mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-09-25 08:50:18 +00:00
fix: glossary feedbacks (#13594)
* fix: glossary feedbacks * fix: localization keys * fix: encoding issues in glossary * fix: glossary approval reload * fix: minor glossary issues * fix: update position of custom attrs in settings page * fix: sync permission and domain provider calls
This commit is contained in:
parent
53576b0a7a
commit
4ecfc2ac5d
@ -200,12 +200,10 @@ export const ActivityFeedTab = ({
|
||||
}, [fqn]);
|
||||
|
||||
const { feedFilter, threadType } = useMemo(() => {
|
||||
let filter;
|
||||
if (!isUserEntity) {
|
||||
filter = currentUser?.isAdmin
|
||||
? FeedFilter.ALL
|
||||
: FeedFilter.OWNER_OR_FOLLOWS;
|
||||
}
|
||||
const currentFilter = currentUser?.isAdmin
|
||||
? FeedFilter.ALL
|
||||
: FeedFilter.OWNER_OR_FOLLOWS;
|
||||
const filter = isUserEntity ? currentFilter : undefined;
|
||||
|
||||
return {
|
||||
threadType:
|
||||
|
@ -12,6 +12,7 @@
|
||||
*/
|
||||
import { ItemType, MenuItemType } from 'antd/lib/menu/hooks/useItems';
|
||||
import { AxiosError } from 'axios';
|
||||
import { isEmpty } from 'lodash';
|
||||
import React, {
|
||||
FC,
|
||||
ReactNode,
|
||||
@ -29,7 +30,7 @@ import {
|
||||
import { Domain } from '../../../generated/entity/domains/domain';
|
||||
import { getDomainList } from '../../../rest/domainAPI';
|
||||
import { showErrorToast } from '../../../utils/ToastUtils';
|
||||
import { useAuthContext } from '../../authentication/auth-provider/AuthProvider';
|
||||
import { usePermissionProvider } from '../../PermissionProvider/PermissionProvider';
|
||||
import { DomainContextType } from './DomainProvider.interface';
|
||||
|
||||
export const DomainContext = React.createContext({} as DomainContextType);
|
||||
@ -42,7 +43,7 @@ const DomainProvider: FC<Props> = ({ children }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const [domains, setDomains] = useState<Domain[]>([]);
|
||||
const [domainLoading, setDomainLoading] = useState(false);
|
||||
const { isAuthenticated } = useAuthContext();
|
||||
const { permissions } = usePermissionProvider();
|
||||
const localStorageData =
|
||||
localStorage.getItem(ACTIVE_DOMAIN_STORAGE_KEY) ?? DEFAULT_DOMAIN_VALUE;
|
||||
|
||||
@ -121,10 +122,10 @@ const DomainProvider: FC<Props> = ({ children }: Props) => {
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isAuthenticated) {
|
||||
if (!isEmpty(permissions)) {
|
||||
fetchDomainList();
|
||||
}
|
||||
}, [isAuthenticated]);
|
||||
}, [permissions]);
|
||||
|
||||
return (
|
||||
<DomainContext.Provider value={domainContextObj}>
|
||||
|
@ -22,7 +22,6 @@ import { EntityType } from '../../../enums/entity.enum';
|
||||
import { ChangeDescription } from '../../../generated/entity/type';
|
||||
import { getFeedCounts } from '../../../utils/CommonUtils';
|
||||
import { getEntityVersionByField } from '../../../utils/EntityVersionUtils';
|
||||
import { getEncodedFqn } from '../../../utils/StringsUtils';
|
||||
import { ActivityFeedTab } from '../../ActivityFeed/ActivityFeedTab/ActivityFeedTab.component';
|
||||
import DescriptionV1 from '../../common/description/DescriptionV1';
|
||||
import TabsLabel from '../../TabsLabel/TabsLabel.component';
|
||||
@ -110,7 +109,7 @@ const GlossaryDetails = ({
|
||||
const getEntityFeedCount = () => {
|
||||
getFeedCounts(
|
||||
EntityType.GLOSSARY,
|
||||
getEncodedFqn(glossary.fullyQualifiedName ?? ''),
|
||||
glossary.fullyQualifiedName ?? '',
|
||||
setFeedCount
|
||||
);
|
||||
};
|
||||
|
@ -137,6 +137,14 @@ const GlossaryHeader = ({
|
||||
}
|
||||
};
|
||||
|
||||
const glossaryTermStatus: Status | null = useMemo(() => {
|
||||
if (!isGlossary) {
|
||||
return (selectedData as GlossaryTerm).status ?? Status.Approved;
|
||||
}
|
||||
|
||||
return null;
|
||||
}, [isGlossary, selectedData]);
|
||||
|
||||
const editDisplayNamePermission = useMemo(() => {
|
||||
return permissions.EditAll || permissions.EditDisplayName;
|
||||
}, [permissions]);
|
||||
@ -419,25 +427,29 @@ const GlossaryHeader = ({
|
||||
{t('label.add-entity', { entity: t('label.term-lowercase') })}
|
||||
</Button>
|
||||
) : (
|
||||
<Dropdown
|
||||
className="m-l-xs"
|
||||
menu={{
|
||||
items: addButtonContent,
|
||||
}}
|
||||
placement="bottomRight"
|
||||
trigger={['click']}>
|
||||
<Button type="primary">
|
||||
<Space>
|
||||
{t('label.add')}
|
||||
<DownOutlined />
|
||||
</Space>
|
||||
</Button>
|
||||
</Dropdown>
|
||||
<>
|
||||
{glossaryTermStatus && glossaryTermStatus === Status.Approved && (
|
||||
<Dropdown
|
||||
className="m-l-xs"
|
||||
menu={{
|
||||
items: addButtonContent,
|
||||
}}
|
||||
placement="bottomRight"
|
||||
trigger={['click']}>
|
||||
<Button type="primary">
|
||||
<Space>
|
||||
{t('label.add')}
|
||||
<DownOutlined />
|
||||
</Space>
|
||||
</Button>
|
||||
</Dropdown>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}, [isGlossary, permissions, addButtonContent]);
|
||||
}, [isGlossary, permissions, addButtonContent, glossaryTermStatus]);
|
||||
|
||||
/**
|
||||
* To create breadcrumb from the fqn
|
||||
@ -529,7 +541,7 @@ const GlossaryHeader = ({
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{!isVersionView && (
|
||||
{!isVersionView && manageButtonContent.length > 0 && (
|
||||
<Dropdown
|
||||
align={{ targetOffset: [-12, 0] }}
|
||||
className="m-l-xs"
|
||||
|
@ -95,6 +95,14 @@ const GlossaryTermTab = ({
|
||||
const [isTableLoading, setIsTableLoading] = useState(false);
|
||||
const [isTableHovered, setIsTableHovered] = useState(false);
|
||||
|
||||
const glossaryTermStatus: Status | null = useMemo(() => {
|
||||
if (!isGlossary) {
|
||||
return (selectedData as GlossaryTerm).status ?? Status.Approved;
|
||||
}
|
||||
|
||||
return null;
|
||||
}, [isGlossary, selectedData]);
|
||||
|
||||
const columns = useMemo(() => {
|
||||
const data: ColumnsType<ModifiedGlossaryTerm> = [
|
||||
{
|
||||
@ -171,38 +179,48 @@ const GlossaryTermTab = ({
|
||||
title: t('label.action-plural'),
|
||||
key: 'new-term',
|
||||
width: 80,
|
||||
render: (_, record) => (
|
||||
<div className="d-flex items-center">
|
||||
<Tooltip
|
||||
title={t('label.add-entity', {
|
||||
entity: t('label.glossary-term'),
|
||||
})}>
|
||||
<Button
|
||||
className="add-new-term-btn text-grey-muted flex-center"
|
||||
data-testid="add-classification"
|
||||
icon={<PlusOutlinedIcon color={DE_ACTIVE_COLOR} width="14px" />}
|
||||
size="small"
|
||||
type="text"
|
||||
onClick={() => {
|
||||
onAddGlossaryTerm(record as GlossaryTerm);
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip
|
||||
title={t('label.edit-entity', {
|
||||
entity: t('label.glossary-term'),
|
||||
})}>
|
||||
<Button
|
||||
className="cursor-pointer flex-center"
|
||||
data-testid="edit-button"
|
||||
icon={<EditIcon color={DE_ACTIVE_COLOR} width="14px" />}
|
||||
size="small"
|
||||
type="text"
|
||||
onClick={() => onEditGlossaryTerm(record as GlossaryTerm)}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
),
|
||||
render: (_, record) => {
|
||||
const status = record.status ?? Status.Approved;
|
||||
const allowAddTerm = status === Status.Approved;
|
||||
|
||||
return (
|
||||
<div className="d-flex items-center">
|
||||
{allowAddTerm && (
|
||||
<Tooltip
|
||||
title={t('label.add-entity', {
|
||||
entity: t('label.glossary-term'),
|
||||
})}>
|
||||
<Button
|
||||
className="add-new-term-btn text-grey-muted flex-center"
|
||||
data-testid="add-classification"
|
||||
icon={
|
||||
<PlusOutlinedIcon color={DE_ACTIVE_COLOR} width="14px" />
|
||||
}
|
||||
size="small"
|
||||
type="text"
|
||||
onClick={() => {
|
||||
onAddGlossaryTerm(record as GlossaryTerm);
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
<Tooltip
|
||||
title={t('label.edit-entity', {
|
||||
entity: t('label.glossary-term'),
|
||||
})}>
|
||||
<Button
|
||||
className="cursor-pointer flex-center"
|
||||
data-testid="edit-button"
|
||||
icon={<EditIcon color={DE_ACTIVE_COLOR} width="14px" />}
|
||||
size="small"
|
||||
type="text"
|
||||
onClick={() => onEditGlossaryTerm(record as GlossaryTerm)}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ -332,7 +350,7 @@ const GlossaryTermTab = ({
|
||||
heading={t('label.glossary-term')}
|
||||
permission={permissions.Create}
|
||||
type={
|
||||
permissions.Create
|
||||
permissions.Create && glossaryTermStatus === Status.Approved
|
||||
? ERROR_PLACEHOLDER_TYPE.CREATE
|
||||
: ERROR_PLACEHOLDER_TYPE.NO_DATA
|
||||
}
|
||||
|
@ -107,7 +107,7 @@ describe('Test GlossaryTermTab component', () => {
|
||||
|
||||
expect(getAllByText(container, 'OwnerLabel')).toHaveLength(2);
|
||||
|
||||
expect(getAllByTestId(container, 'add-classification')).toHaveLength(2);
|
||||
expect(getAllByTestId(container, 'add-classification')).toHaveLength(1);
|
||||
expect(getAllByTestId(container, 'edit-button')).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
|
@ -13,51 +13,35 @@
|
||||
|
||||
import { Col, Row, Tabs } from 'antd';
|
||||
import { t } from 'i18next';
|
||||
import { noop } from 'lodash';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useHistory, useParams } from 'react-router-dom';
|
||||
import { getGlossaryTermDetailsPath } from '../../../constants/constants';
|
||||
import { EntityField } from '../../../constants/Feeds.constants';
|
||||
import { myDataSearchIndex } from '../../../constants/Mydata.constants';
|
||||
import { EntityTabs, EntityType } from '../../../enums/entity.enum';
|
||||
import { GlossaryTerm } from '../../../generated/entity/data/glossaryTerm';
|
||||
import {
|
||||
GlossaryTerm,
|
||||
Status,
|
||||
} from '../../../generated/entity/data/glossaryTerm';
|
||||
import { ChangeDescription } from '../../../generated/entity/type';
|
||||
import { MOCK_GLOSSARY_NO_PERMISSIONS } from '../../../mocks/Glossary.mock';
|
||||
import { searchData } from '../../../rest/miscAPI';
|
||||
import { getCountBadge, getFeedCounts } from '../../../utils/CommonUtils';
|
||||
import { getEntityVersionByField } from '../../../utils/EntityVersionUtils';
|
||||
import { getQueryFilterToExcludeTerm } from '../../../utils/GlossaryUtils';
|
||||
import { getGlossaryTermsVersionsPath } from '../../../utils/RouterUtils';
|
||||
import { getEncodedFqn } from '../../../utils/StringsUtils';
|
||||
import { ActivityFeedTab } from '../../ActivityFeed/ActivityFeedTab/ActivityFeedTab.component';
|
||||
import { AssetSelectionModal } from '../../Assets/AssetsSelectionModal/AssetSelectionModal';
|
||||
import { CustomPropertyTable } from '../../common/CustomPropertyTable/CustomPropertyTable';
|
||||
import { EntityDetailsObjectInterface } from '../../Explore/explore.interface';
|
||||
import { OperationPermission } from '../../PermissionProvider/PermissionProvider.interface';
|
||||
import TabsLabel from '../../TabsLabel/TabsLabel.component';
|
||||
import { VotingDataProps } from '../../Voting/voting.interface';
|
||||
import { GlossaryTabs } from '../GlossaryDetails/GlossaryDetails.interface';
|
||||
import GlossaryHeader from '../GlossaryHeader/GlossaryHeader.component';
|
||||
import GlossaryTermTab from '../GlossaryTermTab/GlossaryTermTab.component';
|
||||
import { GlossaryTermsV1Props } from './GlossaryTermsV1.interface';
|
||||
import AssetsTabs, { AssetsTabRef } from './tabs/AssetsTabs.component';
|
||||
import { AssetsOfEntity } from './tabs/AssetsTabs.interface';
|
||||
import GlossaryOverviewTab from './tabs/GlossaryOverviewTab.component';
|
||||
|
||||
type Props = {
|
||||
isVersionView?: boolean;
|
||||
permissions: OperationPermission;
|
||||
glossaryTerm: GlossaryTerm;
|
||||
childGlossaryTerms: GlossaryTerm[];
|
||||
handleGlossaryTermUpdate: (data: GlossaryTerm) => Promise<void>;
|
||||
handleGlossaryTermDelete: (id: string) => void;
|
||||
refreshGlossaryTerms: () => void;
|
||||
onAssetClick?: (asset?: EntityDetailsObjectInterface) => void;
|
||||
isSummaryPanelOpen: boolean;
|
||||
termsLoading: boolean;
|
||||
onAddGlossaryTerm: (glossaryTerm: GlossaryTerm | undefined) => void;
|
||||
onEditGlossaryTerm: (glossaryTerm: GlossaryTerm) => void;
|
||||
updateVote?: (data: VotingDataProps) => Promise<void>;
|
||||
};
|
||||
|
||||
const GlossaryTermsV1 = ({
|
||||
glossaryTerm,
|
||||
childGlossaryTerms,
|
||||
@ -71,8 +55,9 @@ const GlossaryTermsV1 = ({
|
||||
onAddGlossaryTerm,
|
||||
onEditGlossaryTerm,
|
||||
updateVote,
|
||||
refreshActiveGlossaryTerm,
|
||||
isVersionView,
|
||||
}: Props) => {
|
||||
}: GlossaryTermsV1Props) => {
|
||||
const {
|
||||
fqn: glossaryFqn,
|
||||
tab,
|
||||
@ -84,6 +69,14 @@ const GlossaryTermsV1 = ({
|
||||
const [feedCount, setFeedCount] = useState<number>(0);
|
||||
const [assetCount, setAssetCount] = useState<number>(0);
|
||||
|
||||
const assetPermissions = useMemo(() => {
|
||||
const glossaryTermStatus = glossaryTerm.status ?? Status.Approved;
|
||||
|
||||
return glossaryTermStatus === Status.Approved
|
||||
? permissions
|
||||
: MOCK_GLOSSARY_NO_PERMISSIONS;
|
||||
}, [glossaryTerm, permissions]);
|
||||
|
||||
const activeTab = useMemo(() => {
|
||||
return tab ?? 'overview';
|
||||
}, [tab]);
|
||||
@ -99,7 +92,7 @@ const GlossaryTermsV1 = ({
|
||||
const getEntityFeedCount = () => {
|
||||
getFeedCounts(
|
||||
EntityType.GLOSSARY_TERM,
|
||||
getEncodedFqn(glossaryTerm.fullyQualifiedName ?? ''),
|
||||
glossaryTerm.fullyQualifiedName ?? '',
|
||||
setFeedCount
|
||||
);
|
||||
};
|
||||
@ -170,7 +163,7 @@ const GlossaryTermsV1 = ({
|
||||
<AssetsTabs
|
||||
assetCount={assetCount}
|
||||
isSummaryPanelOpen={isSummaryPanelOpen}
|
||||
permissions={permissions}
|
||||
permissions={assetPermissions}
|
||||
ref={assetTabRef}
|
||||
onAddAsset={() => setAssetModelVisible(true)}
|
||||
onAssetClick={onAssetClick}
|
||||
@ -192,34 +185,34 @@ const GlossaryTermsV1 = ({
|
||||
entityType={EntityType.GLOSSARY_TERM}
|
||||
fqn={glossaryTerm.fullyQualifiedName ?? ''}
|
||||
onFeedUpdate={getEntityFeedCount}
|
||||
onUpdateEntityDetails={noop}
|
||||
onUpdateEntityDetails={refreshActiveGlossaryTerm}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
label: (
|
||||
<TabsLabel
|
||||
id={EntityTabs.CUSTOM_PROPERTIES}
|
||||
name={t('label.custom-property-plural')}
|
||||
/>
|
||||
),
|
||||
key: EntityTabs.CUSTOM_PROPERTIES,
|
||||
children: (
|
||||
<CustomPropertyTable
|
||||
entityDetails={isVersionView ? glossaryTerm : undefined}
|
||||
entityType={EntityType.GLOSSARY_TERM}
|
||||
handleExtensionUpdate={onExtensionUpdate}
|
||||
hasEditAccess={
|
||||
!isVersionView &&
|
||||
(permissions.EditAll || permissions.EditCustomFields)
|
||||
}
|
||||
hasPermission={permissions.ViewAll}
|
||||
isVersionView={isVersionView}
|
||||
/>
|
||||
),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
label: (
|
||||
<TabsLabel
|
||||
id={EntityTabs.CUSTOM_PROPERTIES}
|
||||
name={t('label.custom-property-plural')}
|
||||
/>
|
||||
),
|
||||
key: EntityTabs.CUSTOM_PROPERTIES,
|
||||
children: (
|
||||
<CustomPropertyTable
|
||||
entityDetails={isVersionView ? glossaryTerm : undefined}
|
||||
entityType={EntityType.GLOSSARY_TERM}
|
||||
handleExtensionUpdate={onExtensionUpdate}
|
||||
hasEditAccess={
|
||||
!isVersionView &&
|
||||
(permissions.EditAll || permissions.EditCustomFields)
|
||||
}
|
||||
hasPermission={permissions.ViewAll}
|
||||
isVersionView={isVersionView}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return items;
|
||||
@ -232,6 +225,7 @@ const GlossaryTermsV1 = ({
|
||||
feedCount,
|
||||
isSummaryPanelOpen,
|
||||
isVersionView,
|
||||
assetPermissions,
|
||||
]);
|
||||
|
||||
const fetchGlossaryTermAssets = async () => {
|
||||
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2023 Collate.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { GlossaryTerm } from '../../../generated/entity/data/glossaryTerm';
|
||||
import { EntityDetailsObjectInterface } from '../../Explore/explore.interface';
|
||||
import { OperationPermission } from '../../PermissionProvider/PermissionProvider.interface';
|
||||
import { VotingDataProps } from '../../Voting/voting.interface';
|
||||
|
||||
export interface GlossaryTermsV1Props {
|
||||
isVersionView?: boolean;
|
||||
permissions: OperationPermission;
|
||||
glossaryTerm: GlossaryTerm;
|
||||
childGlossaryTerms: GlossaryTerm[];
|
||||
handleGlossaryTermUpdate: (data: GlossaryTerm) => Promise<void>;
|
||||
handleGlossaryTermDelete: (id: string) => void;
|
||||
refreshGlossaryTerms: () => void;
|
||||
onAssetClick?: (asset?: EntityDetailsObjectInterface) => void;
|
||||
isSummaryPanelOpen: boolean;
|
||||
termsLoading: boolean;
|
||||
onAddGlossaryTerm: (glossaryTerm: GlossaryTerm | undefined) => void;
|
||||
onEditGlossaryTerm: (glossaryTerm: GlossaryTerm) => void;
|
||||
updateVote?: (data: VotingDataProps) => Promise<void>;
|
||||
refreshActiveGlossaryTerm?: () => void;
|
||||
}
|
@ -80,6 +80,7 @@ const mockProps = {
|
||||
onRelatedTermClick: jest.fn(),
|
||||
handleGlossaryTermDelete: jest.fn(),
|
||||
refreshGlossaryTerms: jest.fn(),
|
||||
refreshActiveGlossaryTerm: jest.fn(),
|
||||
onAddGlossaryTerm: jest.fn(),
|
||||
onEditGlossaryTerm: jest.fn(),
|
||||
};
|
||||
|
@ -446,7 +446,11 @@ const AssetsTabs = forwardRef(
|
||||
doc={GLOSSARIES_DOCS}
|
||||
heading={t('label.asset')}
|
||||
permission={permissions.Create}
|
||||
type={ERROR_PLACEHOLDER_TYPE.CREATE}
|
||||
type={
|
||||
permissions.Create
|
||||
? ERROR_PLACEHOLDER_TYPE.CREATE
|
||||
: ERROR_PLACEHOLDER_TYPE.NO_DATA
|
||||
}
|
||||
onClick={onAddAsset}
|
||||
/>
|
||||
)}
|
||||
|
@ -63,6 +63,7 @@ const GlossaryV1 = ({
|
||||
isVersionsView,
|
||||
onAssetClick,
|
||||
isSummaryPanelOpen,
|
||||
refreshActiveGlossaryTerm,
|
||||
}: GlossaryV1Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { action, tab } =
|
||||
@ -338,6 +339,7 @@ const GlossaryV1 = ({
|
||||
isSummaryPanelOpen={isSummaryPanelOpen}
|
||||
isVersionView={isVersionsView}
|
||||
permissions={glossaryTermPermission}
|
||||
refreshActiveGlossaryTerm={refreshActiveGlossaryTerm}
|
||||
refreshGlossaryTerms={() => loadGlossaryTerms(true)}
|
||||
termsLoading={isTermsLoading}
|
||||
updateVote={updateVote}
|
||||
|
@ -29,4 +29,5 @@ export type GlossaryV1Props = {
|
||||
onAssetClick?: (asset?: EntityDetailsObjectInterface) => void;
|
||||
isSummaryPanelOpen: boolean;
|
||||
updateVote?: (data: VotingDataProps) => Promise<void>;
|
||||
refreshActiveGlossaryTerm?: () => void;
|
||||
};
|
||||
|
@ -13,7 +13,6 @@
|
||||
|
||||
import { CookieStorage } from 'cookie-storage';
|
||||
import { isEmpty } from 'lodash';
|
||||
import { observer } from 'mobx-react';
|
||||
import React, {
|
||||
createContext,
|
||||
FC,
|
||||
@ -32,10 +31,7 @@ import {
|
||||
getLoggedInUserPermissions,
|
||||
getResourcePermission,
|
||||
} from '../../rest/permissionAPI';
|
||||
import {
|
||||
getUrlPathnameExpiryAfterRoute,
|
||||
isProtectedRoute,
|
||||
} from '../../utils/AuthProvider.util';
|
||||
import { getUrlPathnameExpiryAfterRoute } from '../../utils/AuthProvider.util';
|
||||
import {
|
||||
getOperationPermissions,
|
||||
getUIPermission,
|
||||
@ -177,7 +173,7 @@ const PermissionProvider: FC<PermissionProviderProps> = ({ children }) => {
|
||||
/**
|
||||
* Only fetch permissions if current user is present
|
||||
*/
|
||||
if (isProtectedRoute(location.pathname) && !isEmpty(currentUser)) {
|
||||
if (!isEmpty(currentUser)) {
|
||||
fetchLoggedInUserPermissions();
|
||||
}
|
||||
if (isEmpty(currentUser)) {
|
||||
@ -209,4 +205,4 @@ const PermissionProvider: FC<PermissionProviderProps> = ({ children }) => {
|
||||
|
||||
export const usePermissionProvider = () => useContext(PermissionContext);
|
||||
|
||||
export default observer(PermissionProvider);
|
||||
export default PermissionProvider;
|
||||
|
@ -19,6 +19,7 @@ import {
|
||||
MenuProps,
|
||||
Row,
|
||||
Space,
|
||||
Tooltip,
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import { useForm } from 'antd/lib/form/Form';
|
||||
@ -165,6 +166,10 @@ export const TaskTab = ({
|
||||
.then(() => {
|
||||
showSuccessToast(t('server.task-resolved-successfully'));
|
||||
rest.onAfterClose?.();
|
||||
|
||||
if (isTaskGlossaryApproval) {
|
||||
rest.onUpdateEntityDetails?.();
|
||||
}
|
||||
})
|
||||
.catch((err: AxiosError) => showErrorToast(err));
|
||||
};
|
||||
@ -255,34 +260,53 @@ export const TaskTab = ({
|
||||
.then(() => {
|
||||
showSuccessToast(t('server.task-closed-successfully'));
|
||||
rest.onAfterClose?.();
|
||||
|
||||
if (isTaskGlossaryApproval) {
|
||||
rest.onUpdateEntityDetails?.();
|
||||
}
|
||||
})
|
||||
.catch((err: AxiosError) => showErrorToast(err));
|
||||
};
|
||||
|
||||
const approvalWorkflowActions = useMemo(() => {
|
||||
const hasApprovalAccess = isAssignee || Boolean(isPartOfAssigneeTeam);
|
||||
|
||||
return (
|
||||
<Space
|
||||
className="m-t-sm items-end w-full"
|
||||
data-testid="task-cta-buttons"
|
||||
size="small">
|
||||
{(isCreator || hasEditAccess) && (
|
||||
<>
|
||||
<Button data-testid="reject-task" onClick={onTaskReject}>
|
||||
{t('label.reject')}
|
||||
</Button>
|
||||
{hasEditAccess && (
|
||||
<Button
|
||||
data-testid="approve-task"
|
||||
type="primary"
|
||||
onClick={onTaskResolve}>
|
||||
{t('label.approve')}
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<Tooltip
|
||||
title={
|
||||
!hasApprovalAccess
|
||||
? t('message.only-reviewers-can-approve-or-reject')
|
||||
: ''
|
||||
}>
|
||||
<Button
|
||||
data-testid="reject-task"
|
||||
disabled={!hasApprovalAccess}
|
||||
onClick={onTaskReject}>
|
||||
{t('label.reject')}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
<Tooltip
|
||||
title={
|
||||
!hasApprovalAccess
|
||||
? t('message.only-reviewers-can-approve-or-reject')
|
||||
: ''
|
||||
}>
|
||||
<Button
|
||||
data-testid="approve-task"
|
||||
disabled={!hasApprovalAccess}
|
||||
type="primary"
|
||||
onClick={onTaskResolve}>
|
||||
{t('label.approve')}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
);
|
||||
}, [taskDetails, onTaskResolve, hasEditAccess, isCreator]);
|
||||
}, [taskDetails, onTaskResolve, isAssignee, isPartOfAssigneeTeam]);
|
||||
|
||||
const actionButtons = useMemo(() => {
|
||||
if (isTaskClosed) {
|
||||
|
@ -1419,6 +1419,7 @@
|
||||
"onboarding-claim-ownership-description": "Daten funktionieren am besten, wenn sie einen Eigentümer haben. Sieh dir die Datenvermögenswerte an, die du besitzt, und beanspruche ihren Besitz.",
|
||||
"onboarding-explore-data-description": "Schau dir die beliebten Datenvermögenswerte in deiner Organisation an.",
|
||||
"onboarding-stay-up-to-date-description": "Folge den Datensätzen, die du häufig verwendest, um über sie informiert zu bleiben.",
|
||||
"only-reviewers-can-approve-or-reject": "Only Reviewers can Approve or Reject",
|
||||
"optional-configuration-update-description-dbt": "Optionale Konfiguration, um die Beschreibung von dbt zu aktualisieren oder nicht.",
|
||||
"page-is-not-available": "Die von dir gesuchte Seite ist nicht verfügbar",
|
||||
"page-sub-header-for-activity-feed": "Aktivitäts-Feed, der es dir ermöglicht, eine Zusammenfassung der Ereignisse zur Datenänderung anzuzeigen.",
|
||||
|
@ -1419,6 +1419,7 @@
|
||||
"onboarding-claim-ownership-description": "Data works well when it is owned. Take a look at the data assets that you own and claim ownership.",
|
||||
"onboarding-explore-data-description": "Look at the popular data assets in your organization.",
|
||||
"onboarding-stay-up-to-date-description": "Follow the datasets that you frequently use to stay informed about it.",
|
||||
"only-reviewers-can-approve-or-reject": "Only Reviewers can Approve or Reject",
|
||||
"optional-configuration-update-description-dbt": "Optional configuration to update the description from dbt or not",
|
||||
"page-is-not-available": "The page you are looking for is not available",
|
||||
"page-sub-header-for-activity-feed": "Activity feed that enables you view a summary of data change events.",
|
||||
|
@ -1419,6 +1419,7 @@
|
||||
"onboarding-claim-ownership-description": "Los datos funcionan bien cuando están tienen propietario. Revisa los activos de datos que posees y reclama su propiedad.",
|
||||
"onboarding-explore-data-description": "Sigue los activos de datos populares en tu organización.",
|
||||
"onboarding-stay-up-to-date-description": "Sigue los conjuntos de datos que usas con frecuencia para mantenerte informado acerca de ellos.",
|
||||
"only-reviewers-can-approve-or-reject": "Only Reviewers can Approve or Reject",
|
||||
"optional-configuration-update-description-dbt": "Configuración opcional para actualizar la descripción de dbt",
|
||||
"page-is-not-available": "La página que estás buscando no está disponible",
|
||||
"page-sub-header-for-activity-feed": "Activity feed that enables you view a summary of data change events.",
|
||||
|
@ -1419,6 +1419,7 @@
|
||||
"onboarding-claim-ownership-description": "Les données fonctionnent mieux lorsqu'elles sont possédées. Revoyez les ressources de données que vous possédez et revendiquez la propriété.",
|
||||
"onboarding-explore-data-description": "Découvrez les ressources de données populaires dans votre organisation.",
|
||||
"onboarding-stay-up-to-date-description": "Suivez les ressources de données que vous utilisez fréquemment pour rester informé à leur sujet.",
|
||||
"only-reviewers-can-approve-or-reject": "Only Reviewers can Approve or Reject",
|
||||
"optional-configuration-update-description-dbt": "Configuration optionnelle pour mettre à jour la description à partir de dbt ou non",
|
||||
"page-is-not-available": "La page que vous recherchez n'est pas disponible",
|
||||
"page-sub-header-for-activity-feed": "Fil d'activité qui vous permet de voir un résumé des événements de modification des données.",
|
||||
|
@ -1419,6 +1419,7 @@
|
||||
"onboarding-claim-ownership-description": "Data works well when it is owned. Take a look at the data assets that you own and claim ownership.",
|
||||
"onboarding-explore-data-description": "あなたの組織で人気のデータアセットを見る。",
|
||||
"onboarding-stay-up-to-date-description": "よく使うデータセットをフォローして、情報が通知されるようにする",
|
||||
"only-reviewers-can-approve-or-reject": "Only Reviewers can Approve or Reject",
|
||||
"optional-configuration-update-description-dbt": "Optional configuration to update the description from dbt or not",
|
||||
"page-is-not-available": "お探しのページはご利用いただけません",
|
||||
"page-sub-header-for-activity-feed": "Activity feed that enables you view a summary of data change events.",
|
||||
|
@ -1419,6 +1419,7 @@
|
||||
"onboarding-claim-ownership-description": "Dados funcionam bem quando possuem um dono. Dê uma olhada nos ativos de dados que você é responsável e reivindique a propriedade.",
|
||||
"onboarding-explore-data-description": "Olhe para os ativos de dados populares na sua organização.",
|
||||
"onboarding-stay-up-to-date-description": "Siga os conjuntos de dados que você usa com frequência para se manter informado sobre eles.",
|
||||
"only-reviewers-can-approve-or-reject": "Only Reviewers can Approve or Reject",
|
||||
"optional-configuration-update-description-dbt": "Configuração opcional para atualizar ou não a descrição do dbt",
|
||||
"page-is-not-available": "A página que você está procurando não está disponível",
|
||||
"page-sub-header-for-activity-feed": "Activity feed that enables you view a summary of data change events.",
|
||||
|
@ -1419,6 +1419,7 @@
|
||||
"onboarding-claim-ownership-description": "Данные работают хорошо, когда ими владеют. Взгляните на объекты данных, которыми вы владеете, и заявите о праве собственности.",
|
||||
"onboarding-explore-data-description": "Посмотрите на популярные объекты данных в вашей организации.",
|
||||
"onboarding-stay-up-to-date-description": "Следите за наборами данных, которые вы часто используете, чтобы быть в курсе.",
|
||||
"only-reviewers-can-approve-or-reject": "Only Reviewers can Approve or Reject",
|
||||
"optional-configuration-update-description-dbt": "Необязательная конфигурация для обновления описания из dbt или нет",
|
||||
"page-is-not-available": "Страница, которую вы ищете, недоступна",
|
||||
"page-sub-header-for-activity-feed": "Лента активности позволяет просматривать сводку событий изменения данных.",
|
||||
|
@ -1419,6 +1419,7 @@
|
||||
"onboarding-claim-ownership-description": "查看数据资产并声明所有权,以更好的维护数据",
|
||||
"onboarding-explore-data-description": "查看组织中热门的数据资产",
|
||||
"onboarding-stay-up-to-date-description": "关注您经常使用的数据集以获取最新信息",
|
||||
"only-reviewers-can-approve-or-reject": "Only Reviewers can Approve or Reject",
|
||||
"optional-configuration-update-description-dbt": "可选配置,选择是否从 dbt 更新描述",
|
||||
"page-is-not-available": "您要查找的页面不可用",
|
||||
"page-sub-header-for-activity-feed": "活动信息流可用于查看数据的修改事件概览",
|
||||
|
@ -45,7 +45,7 @@ export const mockedGlossaryTerms = [
|
||||
updatedBy: 'anonymous',
|
||||
reviewers: [],
|
||||
tags: [],
|
||||
status: 'Draft' as Status,
|
||||
status: Status.Draft,
|
||||
deleted: false,
|
||||
},
|
||||
{
|
||||
@ -71,7 +71,7 @@ export const mockedGlossaryTerms = [
|
||||
updatedBy: 'anonymous',
|
||||
reviewers: [],
|
||||
tags: [],
|
||||
status: 'Draft' as Status,
|
||||
status: Status.Approved,
|
||||
deleted: false,
|
||||
},
|
||||
];
|
||||
@ -431,6 +431,13 @@ export const MOCK_PERMISSIONS = {
|
||||
ViewUsage: true,
|
||||
} as OperationPermission;
|
||||
|
||||
export const MOCK_GLOSSARY_NO_PERMISSIONS = {
|
||||
Create: false,
|
||||
Delete: false,
|
||||
EditAll: false,
|
||||
ViewAll: true,
|
||||
} as OperationPermission;
|
||||
|
||||
export const MOCKED_GLOSSARY_TERMS = [
|
||||
{
|
||||
id: 'a735e9c0-a98f-43aa-8c15-490a55198f3c',
|
||||
|
@ -356,6 +356,7 @@ const GlossaryPage = () => {
|
||||
isGlossaryActive={isGlossaryActive}
|
||||
isSummaryPanelOpen={Boolean(previewAsset)}
|
||||
isVersionsView={false}
|
||||
refreshActiveGlossaryTerm={fetchGlossaryTermDetails}
|
||||
selectedData={selectedData as Glossary}
|
||||
updateGlossary={updateGlossary}
|
||||
updateVote={updateVote}
|
||||
|
@ -249,6 +249,30 @@ export const getGlobalSettingsMenuWithPermission = (
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
category: i18next.t('label.open-metadata'),
|
||||
key: 'openMetadata',
|
||||
items: [
|
||||
{
|
||||
label: i18next.t('label.customize-landing-page'),
|
||||
isProtected: Boolean(isAdminUser),
|
||||
key: 'openMetadata.customizeLandingPage',
|
||||
icon: <CustomDashboardLogoIcon className="w-4 side-panel-icons" />,
|
||||
},
|
||||
{
|
||||
label: i18next.t('label.email'),
|
||||
isProtected: Boolean(isAdminUser),
|
||||
key: 'openMetadata.email',
|
||||
icon: <EmailSettingsIcon className="w-4 side-panel-icons" />,
|
||||
},
|
||||
{
|
||||
label: i18next.t('label.custom-logo'),
|
||||
isProtected: Boolean(isAdminUser),
|
||||
key: 'openMetadata.customLogo',
|
||||
icon: <CustomLogoIcon className="w-4 side-panel-icons" />,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
category: i18next.t('label.custom-attribute-plural'),
|
||||
key: 'customAttributes',
|
||||
@ -321,30 +345,6 @@ export const getGlobalSettingsMenuWithPermission = (
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
category: i18next.t('label.open-metadata'),
|
||||
key: 'openMetadata',
|
||||
items: [
|
||||
{
|
||||
label: i18next.t('label.customize-landing-page'),
|
||||
isProtected: Boolean(isAdminUser),
|
||||
key: 'openMetadata.customizeLandingPage',
|
||||
icon: <CustomDashboardLogoIcon className="w-4 side-panel-icons" />,
|
||||
},
|
||||
{
|
||||
label: i18next.t('label.email'),
|
||||
isProtected: Boolean(isAdminUser),
|
||||
key: 'openMetadata.email',
|
||||
icon: <EmailSettingsIcon className="w-4 side-panel-icons" />,
|
||||
},
|
||||
{
|
||||
label: i18next.t('label.custom-logo'),
|
||||
isProtected: Boolean(isAdminUser),
|
||||
key: 'openMetadata.customLogo',
|
||||
icon: <CustomLogoIcon className="w-4 side-panel-icons" />,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
|
@ -228,7 +228,9 @@ export const StatusClass = {
|
||||
[Status.Deprecated]: StatusType.Warning,
|
||||
};
|
||||
|
||||
export const StatusFilters = Object.values(Status).map((status) => ({
|
||||
text: status,
|
||||
value: status,
|
||||
}));
|
||||
export const StatusFilters = Object.values(Status)
|
||||
.filter((status) => status !== Status.Deprecated) // Deprecated not in use for this release
|
||||
.map((status) => ({
|
||||
text: status,
|
||||
value: status,
|
||||
}));
|
||||
|
Loading…
x
Reference in New Issue
Block a user