From 503873a0a45f2f6c0f04ddfb6e1d704a2cc9616e Mon Sep 17 00:00:00 2001 From: Sachin Chaurasiya Date: Wed, 31 Aug 2022 01:46:33 +0530 Subject: [PATCH] Update Glossary with new roles and policy (#7067) * Update Glossary with new roles and policy * Fix unit tests * Fix tests * Fix tests --- .../src/components/Glossary/Glossary.test.tsx | 56 ++++- .../Glossary/GlossaryV1.component.tsx | 213 +++++++++++++----- .../GlossaryDetails.component.tsx | 202 ++++++++--------- .../GlossaryDetails/GlossaryDetails.test.tsx | 11 +- .../GlossaryTerms/GlossaryTerms.test.tsx | 65 ++++-- .../GlossaryTermsV1.component.tsx | 184 ++++++--------- .../GlossaryTerms/SummaryDetail.tsx | 57 +++++ .../common/description/DescriptionV1.tsx | 17 +- .../GlossaryPage/GlossaryPageV1.component.tsx | 5 - .../ui/src/router/AuthenticatedAppRouter.tsx | 63 +++++- 10 files changed, 535 insertions(+), 338 deletions(-) create mode 100644 openmetadata-ui/src/main/resources/ui/src/components/GlossaryTerms/SummaryDetail.tsx diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/Glossary.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/Glossary.test.tsx index 563352c5f97..a602e90e3b2 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/Glossary.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/Glossary.test.tsx @@ -22,6 +22,44 @@ import React from 'react'; import { mockedAssetData, mockedGlossaries } from '../../mocks/Glossary.mock'; import GlossaryV1 from './GlossaryV1.component'; +jest.mock('../PermissionProvider/PermissionProvider', () => ({ + usePermissionProvider: jest.fn().mockReturnValue({ + getEntityPermission: jest.fn().mockReturnValue({ + Create: true, + Delete: true, + ViewAll: true, + EditAll: true, + EditDescription: true, + EditDisplayName: true, + EditCustomFields: true, + }), + permissions: { + glossaryTerm: { + Create: true, + Delete: true, + ViewAll: true, + EditAll: true, + EditDescription: true, + EditDisplayName: true, + EditCustomFields: true, + }, + glossary: { + Create: true, + Delete: true, + ViewAll: true, + EditAll: true, + EditDescription: true, + EditDisplayName: true, + EditCustomFields: true, + }, + }, + }), +})); + +jest.mock('../../utils/PermissionsUtils', () => ({ + checkPermission: jest.fn().mockReturnValue(true), +})); + jest.mock('react-router-dom', () => ({ useHistory: jest.fn(), useParams: jest.fn().mockReturnValue({ @@ -29,18 +67,6 @@ jest.mock('react-router-dom', () => ({ }), })); -jest.mock('../../authentication/auth-provider/AuthProvider', () => { - return { - useAuthContext: jest.fn(() => ({ - isAuthDisabled: false, - isAuthenticated: true, - isProtectedRoute: jest.fn().mockReturnValue(true), - isTourRoute: jest.fn().mockReturnValue(false), - onLogoutHandler: jest.fn(), - })), - }; -}); - jest.mock('../../components/GlossaryDetails/GlossaryDetails.component', () => { return jest.fn().mockReturnValue(<>Glossary-Details component); }); @@ -77,6 +103,12 @@ jest.mock('antd', () => ({ })} )), + Button: jest + .fn() + .mockImplementation(({ children }) => ), + Tooltip: jest + .fn() + .mockImplementation(({ children }) => {children}), })); jest.mock('../common/title-breadcrumb/title-breadcrumb.component', () => diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryV1.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryV1.component.tsx index 570e39261a5..d4e592388be 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryV1.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryV1.component.tsx @@ -12,28 +12,38 @@ */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Col, Dropdown, Input, Menu, Row, Space, Typography } from 'antd'; -import classNames from 'classnames'; +import { + Button as ButtonAntd, + Col, + Dropdown, + Input, + Menu, + Row, + Space, + Tooltip, + Typography, +} from 'antd'; +import { AxiosError } from 'axios'; import { cloneDeep, isEmpty } from 'lodash'; import { GlossaryTermAssets, LoadingState } from 'Models'; import RcTree from 'rc-tree'; import { DataNode, EventDataNode } from 'rc-tree/lib/interface'; -import React, { Fragment, useEffect, useRef, useState } from 'react'; -import { useAuthContext } from '../../authentication/auth-provider/AuthProvider'; +import React, { Fragment, useEffect, useMemo, useRef, useState } from 'react'; import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants'; -import { TITLE_FOR_NON_ADMIN_ACTION } from '../../constants/constants'; +import { NO_PERMISSION_FOR_ACTION } from '../../constants/HelperTextUtil'; import { Glossary } from '../../generated/entity/data/glossary'; import { GlossaryTerm } from '../../generated/entity/data/glossaryTerm'; -import { useAuth } from '../../hooks/authHooks'; +import { Operation } from '../../generated/entity/policies/policy'; import { useAfterMount } from '../../hooks/useAfterMount'; import { ModifiedGlossaryData } from '../../pages/GlossaryPage/GlossaryPageV1.component'; import { getEntityDeleteMessage, getEntityName } from '../../utils/CommonUtils'; import { generateTreeData } from '../../utils/GlossaryUtils'; +import { checkPermission } from '../../utils/PermissionsUtils'; import { getGlossaryPath } from '../../utils/RouterUtils'; import SVGIcons, { Icons } from '../../utils/SvgUtils'; +import { showErrorToast } from '../../utils/ToastUtils'; import { Button } from '../buttons/Button/Button'; import ErrorPlaceHolder from '../common/error-with-placeholder/ErrorPlaceHolder'; -import NonAdminAction from '../common/non-admin-action/NonAdminAction'; import Searchbar from '../common/searchbar/Searchbar'; import TitleBreadcrumb from '../common/title-breadcrumb/title-breadcrumb.component'; import { TitleBreadcrumbProps } from '../common/title-breadcrumb/title-breadcrumb.interface'; @@ -43,6 +53,11 @@ import GlossaryDetails from '../GlossaryDetails/GlossaryDetails.component'; import GlossaryTermsV1 from '../GlossaryTerms/GlossaryTermsV1.component'; import Loader from '../Loader/Loader'; import EntityDeleteModal from '../Modals/EntityDeleteModal/EntityDeleteModal'; +import { usePermissionProvider } from '../PermissionProvider/PermissionProvider'; +import { + OperationPermission, + ResourceEntity, +} from '../PermissionProvider/PermissionProvider.interface'; import './GlossaryV1.style.less'; const { Title } = Typography; @@ -50,7 +65,6 @@ type Props = { assetData: GlossaryTermAssets; deleteStatus: LoadingState; isSearchResultEmpty: boolean; - isHasAccess: boolean; glossaryList: ModifiedGlossaryData[]; selectedKey: string; expandedKey: string[]; @@ -80,7 +94,6 @@ const GlossaryV1 = ({ assetData, deleteStatus = 'initial', isSearchResultEmpty, - isHasAccess, glossaryList, selectedKey, expandedKey, @@ -104,8 +117,7 @@ const GlossaryV1 = ({ onRelatedTermClick, currentPage, }: Props) => { - const { isAdminUser } = useAuth(); - const { isAuthDisabled } = useAuthContext(); + const { getEntityPermission, permissions } = usePermissionProvider(); const treeRef = useRef>(null); const [treeData, setTreeData] = useState([]); const [breadcrumb, setBreadcrumb] = useState< @@ -124,6 +136,59 @@ const GlossaryV1 = ({ ); const [isNameEditing, setIsNameEditing] = useState(false); const [displayName, setDisplayName] = useState(); + + const [glossaryPermission, setGlossaryPermission] = + useState({} as OperationPermission); + + const [glossaryTermPermission, setGlossaryTermPermission] = + useState({} as OperationPermission); + + const fetchGlossaryPermission = async () => { + try { + const response = await getEntityPermission( + ResourceEntity.GLOSSARY, + selectedData?.id as string + ); + setGlossaryPermission(response); + } catch (error) { + showErrorToast(error as AxiosError); + } + }; + + const fetchGlossaryTermPermission = async () => { + try { + const response = await getEntityPermission( + ResourceEntity.GLOSSARY_TERM, + selectedData?.id as string + ); + setGlossaryTermPermission(response); + } catch (error) { + showErrorToast(error as AxiosError); + } + }; + + const createGlossaryPermission = useMemo( + () => + checkPermission(Operation.Create, ResourceEntity.GLOSSARY, permissions), + [permissions] + ); + + const createGlossaryTermPermission = useMemo( + () => + checkPermission( + Operation.Create, + ResourceEntity.GLOSSARY_TERM, + permissions + ), + [permissions] + ); + + const editDisplayNamePermission = useMemo(() => { + return isGlossaryActive + ? glossaryPermission.EditDisplayName + : glossaryTermPermission.EditDisplayName; + }, [glossaryPermission, glossaryTermPermission]); + /** * To create breadcrumb from the fqn * @param fqn fqn of glossary or glossary term @@ -269,16 +334,20 @@ const GlossaryV1 = ({ typingInterval={500} onSearch={handleSearchText} /> - + - + {isSearchResultEmpty ? (

@@ -311,6 +380,10 @@ const GlossaryV1 = ({ useEffect(() => { setDisplayName(selectedData?.displayName); + if (selectedData) { + fetchGlossaryPermission(); + fetchGlossaryTermPermission(); + } }, [selectedData]); return glossaryList.length ? ( @@ -327,32 +400,45 @@ const GlossaryV1 = ({ />

- - - - - + + + + + - - + +
{isChildLoading ? ( @@ -411,14 +497,24 @@ const GlossaryV1 = ({ ) : ( {getEntityName(selectedData)} - + + setIsNameEditing(true)}> + + + )} @@ -427,7 +523,7 @@ const GlossaryV1 = ({ ) : ( @@ -437,7 +533,7 @@ const GlossaryV1 = ({ glossaryTerm={selectedData as GlossaryTerm} handleGlossaryTermUpdate={handleGlossaryTermUpdate} handleUserRedirection={handleUserRedirection} - isHasAccess={isHasAccess} + permissions={glossaryTermPermission} onAssetPaginate={onAssetPaginate} onRelatedTermClick={onRelatedTermClick} /> @@ -460,19 +556,16 @@ const GlossaryV1 = ({

No glossaries found

- - - +

diff --git a/openmetadata-ui/src/main/resources/ui/src/components/GlossaryDetails/GlossaryDetails.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/GlossaryDetails/GlossaryDetails.component.tsx index cd589083be9..4bf2478c1d8 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/GlossaryDetails/GlossaryDetails.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/GlossaryDetails/GlossaryDetails.component.tsx @@ -12,29 +12,20 @@ */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Card as AntdCard } from 'antd'; +import { Button as ButtonAntd, Card as AntdCard, Tooltip } from 'antd'; import { AxiosError } from 'axios'; import classNames from 'classnames'; import { cloneDeep, debounce, includes, isEqual } from 'lodash'; import { EntityTags, FormattedUsersData } from 'Models'; import React, { useCallback, useEffect, useState } from 'react'; -import { useAuthContext } from '../../authentication/auth-provider/AuthProvider'; import { WILD_CARD_CHAR } from '../../constants/char.constants'; -import { - TITLE_FOR_NON_ADMIN_ACTION, - TITLE_FOR_NON_OWNER_ACTION, - TITLE_FOR_UPDATE_OWNER, -} from '../../constants/constants'; -import { EntityType } from '../../enums/entity.enum'; +import { NO_PERMISSION_FOR_ACTION } from '../../constants/HelperTextUtil'; import { Glossary } from '../../generated/entity/data/glossary'; -import { Operation } from '../../generated/entity/policies/policy'; import { EntityReference } from '../../generated/type/entityReference'; import { LabelType, State, TagSource } from '../../generated/type/tagLabel'; -import { useAuth } from '../../hooks/authHooks'; import jsonData from '../../jsons/en'; -import { getEntityName, hasEditAccess } from '../../utils/CommonUtils'; +import { getEntityName } from '../../utils/CommonUtils'; import { getOwnerList } from '../../utils/ManageUtils'; -import { hasPemission } from '../../utils/PermissionsUtils'; import SVGIcons, { Icons } from '../../utils/SvgUtils'; import { getTagCategories, @@ -47,27 +38,24 @@ import { searchFormattedUsersAndTeams, suggestFormattedUsersAndTeams, } from '../../utils/UserDataUtils'; -import { Button } from '../buttons/Button/Button'; import Card from '../common/Card/Card'; import DescriptionV1 from '../common/description/DescriptionV1'; -import NonAdminAction from '../common/non-admin-action/NonAdminAction'; import ProfilePicture from '../common/ProfilePicture/ProfilePicture'; import DropDownList from '../dropdown/DropDownList'; import ReviewerModal from '../Modals/ReviewerModal/ReviewerModal.component'; +import { OperationPermission } from '../PermissionProvider/PermissionProvider.interface'; import TagsContainer from '../tags-container/tags-container'; import TagsViewer from '../tags-viewer/tags-viewer'; import Tags from '../tags/tags'; type props = { - isHasAccess: boolean; + permissions: OperationPermission; glossary: Glossary; updateGlossary: (value: Glossary) => void; handleUserRedirection?: (name: string) => void; }; -const GlossaryDetails = ({ isHasAccess, glossary, updateGlossary }: props) => { - const { userPermissions } = useAuth(); - const { isAuthDisabled } = useAuthContext(); +const GlossaryDetails = ({ permissions, glossary, updateGlossary }: props) => { const [isDescriptionEditable, setIsDescriptionEditable] = useState(false); const [isTagEditable, setIsTagEditable] = useState(false); const [tagList, setTagList] = useState>([]); @@ -264,13 +252,6 @@ const GlossaryDetails = ({ isHasAccess, glossary, updateGlossary }: props) => { setListVisible(false); }; - const isOwner = () => { - return hasEditAccess( - glossary?.owner?.type || '', - glossary?.owner?.id || '' - ); - }; - const handleTagContainerClick = () => { if (!isTagEditable) { fetchTags(); @@ -293,44 +274,39 @@ const GlossaryDetails = ({ isHasAccess, glossary, updateGlossary }: props) => { const AddReviewerButton = () => { return ( - - - + + ); }; const ownerAction = () => { return ( - {TITLE_FOR_UPDATE_OWNER}

} - isOwner={isOwner()} - permission={Operation.EditOwner} - position="left"> - -
+ + {listVisible && ( { {getEntityName(term)} - {TITLE_FOR_NON_OWNER_ACTION}

} - isOwner={isOwner()} - position="bottom"> - handleRemoveReviewer(term.id)}> - - -
+ + + handleRemoveReviewer(term.id)}> + + + +
))} @@ -426,52 +406,51 @@ const GlossaryDetails = ({ isHasAccess, glossary, updateGlossary }: props) => { )} )} - -
- { - handleTagSelection(); - }} - onSelectionChange={(tags) => { - handleTagSelection(tags); - }}> - {glossary?.tags && glossary?.tags.length ? ( - - ) : ( - - - - )} - -
-
+ +
+ { + handleTagSelection(); + }} + onSelectionChange={(tags) => { + handleTagSelection(tags); + }}> + {glossary?.tags && glossary?.tags.length ? ( + + ) : ( + + + + )} + +
@@ -481,6 +460,7 @@ const GlossaryDetails = ({ isHasAccess, glossary, updateGlossary }: props) => { removeBlur description={glossary?.description} entityName={glossary?.displayName ?? glossary?.name} + hasEditAccess={permissions.EditDescription} isEdit={isDescriptionEditable} onCancel={onCancel} onDescriptionEdit={onDescriptionEdit} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/GlossaryDetails/GlossaryDetails.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/GlossaryDetails/GlossaryDetails.test.tsx index 08199eda6b9..44d65dbf0e7 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/GlossaryDetails/GlossaryDetails.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/GlossaryDetails/GlossaryDetails.test.tsx @@ -14,6 +14,7 @@ import { findByText, getByTestId, render } from '@testing-library/react'; import React from 'react'; import { mockedGlossaries } from '../../mocks/Glossary.mock'; +import { OperationPermission } from '../PermissionProvider/PermissionProvider.interface'; import GlossaryDetails from './GlossaryDetails.component'; jest.mock('react-router-dom', () => ({ @@ -61,7 +62,15 @@ jest.mock('../common/ProfilePicture/ProfilePicture', () => { const mockProps = { glossary: mockedGlossaries[0], - isHasAccess: true, + permissions: { + Create: true, + Delete: true, + ViewAll: true, + EditAll: true, + EditDescription: true, + EditDisplayName: true, + EditCustomFields: true, + } as OperationPermission, updateGlossary: jest.fn(), }; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/GlossaryTerms/GlossaryTerms.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/GlossaryTerms/GlossaryTerms.test.tsx index 2229b88dfe4..9a8cac86fca 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/GlossaryTerms/GlossaryTerms.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/GlossaryTerms/GlossaryTerms.test.tsx @@ -17,8 +17,47 @@ import { mockedAssetData, mockedGlossaryTerms, } from '../../mocks/Glossary.mock'; +import { OperationPermission } from '../PermissionProvider/PermissionProvider.interface'; import GlossaryTerms from './GlossaryTermsV1.component'; +jest.mock('../PermissionProvider/PermissionProvider', () => ({ + usePermissionProvider: jest.fn().mockReturnValue({ + getEntityPermission: jest.fn().mockReturnValue({ + Create: true, + Delete: true, + ViewAll: true, + EditAll: true, + EditDescription: true, + EditDisplayName: true, + EditCustomFields: true, + }), + permissions: { + glossaryTerm: { + Create: true, + Delete: true, + ViewAll: true, + EditAll: true, + EditDescription: true, + EditDisplayName: true, + EditCustomFields: true, + }, + glossary: { + Create: true, + Delete: true, + ViewAll: true, + EditAll: true, + EditDescription: true, + EditDisplayName: true, + EditCustomFields: true, + }, + }, + }), +})); + +jest.mock('../../utils/PermissionsUtils', () => ({ + checkPermission: jest.fn().mockReturnValue(true), +})); + jest.mock('react-router-dom', () => ({ useHistory: jest.fn(), useParams: jest.fn().mockReturnValue({ @@ -26,18 +65,6 @@ jest.mock('react-router-dom', () => ({ }), })); -jest.mock('../../authentication/auth-provider/AuthProvider', () => { - return { - useAuthContext: jest.fn(() => ({ - isAuthDisabled: false, - isAuthenticated: true, - isProtectedRoute: jest.fn().mockReturnValue(true), - isTourRoute: jest.fn().mockReturnValue(false), - onLogoutHandler: jest.fn(), - })), - }; -}); - jest.mock('../../components/tags-container/tags-container', () => { return jest.fn().mockReturnValue(<>Tags-container component); }); @@ -99,10 +126,22 @@ jest.mock('antd', () => ({ )), })); +jest.mock('./SummaryDetail', () => + jest.fn().mockReturnValue(
SummaryDetails
) +); + const mockProps = { assetData: mockedAssetData, currentPage: 1, - isHasAccess: true, + permissions: { + Create: true, + Delete: true, + ViewAll: true, + EditAll: true, + EditDescription: true, + EditDisplayName: true, + EditCustomFields: true, + } as OperationPermission, glossaryTerm: mockedGlossaryTerms[0], handleGlossaryTermUpdate: jest.fn(), onAssetPaginate: jest.fn(), diff --git a/openmetadata-ui/src/main/resources/ui/src/components/GlossaryTerms/GlossaryTermsV1.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/GlossaryTerms/GlossaryTermsV1.component.tsx index 533e0f9763f..62e5db74550 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/GlossaryTerms/GlossaryTermsV1.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/GlossaryTerms/GlossaryTermsV1.component.tsx @@ -20,19 +20,12 @@ import { Input, Row, Space, + Tooltip, Typography, } from 'antd'; import { AxiosError } from 'axios'; import classNames from 'classnames'; -import { - cloneDeep, - includes, - isEmpty, - isEqual, - isString, - isUndefined, - kebabCase, -} from 'lodash'; +import { cloneDeep, includes, isEmpty, isEqual } from 'lodash'; import { EntityTags, FormattedGlossaryTermData, @@ -40,10 +33,7 @@ import { GlossaryTermAssets, } from 'Models'; import React, { Fragment, useEffect, useState } from 'react'; -import { - TITLE_FOR_NON_ADMIN_ACTION, - TITLE_FOR_NON_OWNER_ACTION, -} from '../../constants/constants'; +import { NO_PERMISSION_FOR_ACTION } from '../../constants/HelperTextUtil'; import { GlossaryTerm, TermReference, @@ -59,21 +49,22 @@ import { } from '../../utils/TagsUtils'; import { showErrorToast } from '../../utils/ToastUtils'; import DescriptionV1 from '../common/description/DescriptionV1'; -import NonAdminAction from '../common/non-admin-action/NonAdminAction'; import ProfilePicture from '../common/ProfilePicture/ProfilePicture'; import TabsPane from '../common/TabsPane/TabsPane'; import GlossaryReferenceModal from '../Modals/GlossaryReferenceModal/GlossaryReferenceModal'; import RelatedTermsModal from '../Modals/RelatedTermsModal/RelatedTermsModal'; import ReviewerModal from '../Modals/ReviewerModal/ReviewerModal.component'; +import { OperationPermission } from '../PermissionProvider/PermissionProvider.interface'; import TagsContainer from '../tags-container/tags-container'; import TagsViewer from '../tags-viewer/tags-viewer'; import Tags from '../tags/tags'; +import SummaryDetail from './SummaryDetail'; import AssetsTabs from './tabs/AssetsTabs.component'; const { Text } = Typography; type Props = { assetData: GlossaryTermAssets; - isHasAccess: boolean; + permissions: OperationPermission; glossaryTerm: GlossaryTerm; currentPage: number; handleGlossaryTermUpdate: (data: GlossaryTerm) => void; @@ -82,21 +73,14 @@ type Props = { handleUserRedirection?: (name: string) => void; }; -type SummaryDetailsProps = { - title: string; - children: React.ReactElement; - setShow?: (value: React.SetStateAction) => void; - data?: FormattedGlossaryTermData[] | TermReference[] | string; -}; - const GlossaryTermsV1 = ({ assetData, - isHasAccess, glossaryTerm, handleGlossaryTermUpdate, onAssetPaginate, onRelatedTermClick, currentPage, + permissions, }: Props) => { const [isTagEditable, setIsTagEditable] = useState(false); const [tagList, setTagList] = useState>([]); @@ -301,7 +285,7 @@ const GlossaryTermsV1 = ({ const handleValidation = ( event: React.ChangeEvent ) => { - if (isHasAccess) { + if (permissions.EditAll) { return; } const value = event.target.value; @@ -344,28 +328,18 @@ const GlossaryTermsV1 = ({ const addReviewerButton = () => { return ( - - - - ); - }; - - const addButton = (onClick: () => void) => { - return ( - - - - - + + ); }; @@ -398,9 +372,7 @@ const GlossaryTermsV1 = ({ {getEntityName(term)}
- {TITLE_FOR_NON_OWNER_ACTION}

} - position="bottom"> +
))} @@ -437,34 +409,6 @@ const GlossaryTermsV1 = ({ ); }; - const SummaryDetail = ({ - title, - children, - setShow, - data, - ...props - }: SummaryDetailsProps) => { - return ( - - - {title} -
- {addButton(() => setShow && setShow(true))} -
-
- {!isString(data) && !isUndefined(data) && data.length > 0 ? ( -
- {children} -
- ) : ( -
{children}
- )} -
- ); - }; - const SummaryTab = () => { return ( @@ -482,6 +426,7 @@ const GlossaryTermsV1 = ({ @@ -510,6 +455,7 @@ const GlossaryTermsV1 = ({ @@ -558,6 +504,7 @@ const GlossaryTermsV1 = ({ @@ -629,50 +576,49 @@ const GlossaryTermsV1 = ({ )} )} - -
- { - handleTagSelection(); - }} - onSelectionChange={(tags) => { - handleTagSelection(tags); - }}> - {glossaryTerm?.tags && glossaryTerm?.tags.length ? ( - - ) : ( - - - - )} - -
-
+ +
+ { + handleTagSelection(); + }} + onSelectionChange={(tags) => { + handleTagSelection(tags); + }}> + {glossaryTerm?.tags && glossaryTerm?.tags.length ? ( + + ) : ( + + )} + +
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/GlossaryTerms/SummaryDetail.tsx b/openmetadata-ui/src/main/resources/ui/src/components/GlossaryTerms/SummaryDetail.tsx new file mode 100644 index 00000000000..83933e8f64f --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/components/GlossaryTerms/SummaryDetail.tsx @@ -0,0 +1,57 @@ +import { Button, Space, Tooltip, Typography } from 'antd'; +import { isString, isUndefined, kebabCase } from 'lodash'; +import { FormattedGlossaryTermData } from 'Models'; +import React from 'react'; +import { NO_PERMISSION_FOR_ACTION } from '../../constants/HelperTextUtil'; +import { TermReference } from '../../generated/entity/data/glossaryTerm'; +import SVGIcons from '../../utils/SvgUtils'; + +interface SummaryDetailsProps { + title: string; + children: React.ReactElement; + hasAccess: boolean; + setShow?: (value: React.SetStateAction) => void; + data?: FormattedGlossaryTermData[] | TermReference[] | string; +} + +const SummaryDetail = ({ + title, + children, + setShow, + data, + hasAccess, + ...props +}: SummaryDetailsProps) => { + return ( + + + {title} +
+ + + +
+
+ {!isString(data) && !isUndefined(data) && data.length > 0 ? ( +
+ {children} +
+ ) : ( +
{children}
+ )} +
+ ); +}; + +export default SummaryDetail; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/description/DescriptionV1.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/description/DescriptionV1.tsx index 342c4f07376..7dc508b5b64 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/common/description/DescriptionV1.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/common/description/DescriptionV1.tsx @@ -11,19 +11,17 @@ * limitations under the License. */ -import { Space, Typography } from 'antd'; +import { Space, Tooltip, Typography } from 'antd'; import classNames from 'classnames'; import { isUndefined } from 'lodash'; import { EntityFieldThreads } from 'Models'; import React, { Fragment } from 'react'; import { EntityField } from '../../../constants/feed.constants'; +import { NO_PERMISSION_FOR_ACTION } from '../../../constants/HelperTextUtil'; import { Table } from '../../../generated/entity/data/table'; -import { Operation } from '../../../generated/entity/policies/accessControl/rule'; -import { getHtmlForNonAdminAction } from '../../../utils/CommonUtils'; import { getEntityFeedLink } from '../../../utils/EntityUtils'; import SVGIcons, { Icons } from '../../../utils/SvgUtils'; import { ModalWithMarkdownEditor } from '../../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor'; -import NonAdminAction from '../non-admin-action/NonAdminAction'; import PopOver from '../popover/PopOver'; import RichTextEditorPreviewer from '../rich-text-editor/RichTextEditorPreviewer'; const { Text } = Typography; @@ -47,7 +45,6 @@ interface Props { onEntityFieldSelect?: (value: string) => void; } const DescriptionV1 = ({ - owner, hasEditAccess, onDescriptionEdit, description = '', @@ -67,14 +64,12 @@ const DescriptionV1 = ({ const editButton = () => { return !isReadOnly ? ( - + - + ) : ( <> ); diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/GlossaryPage/GlossaryPageV1.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/GlossaryPage/GlossaryPageV1.component.tsx index b48a1393b30..69442ded4dd 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/GlossaryPage/GlossaryPageV1.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/GlossaryPage/GlossaryPageV1.component.tsx @@ -23,7 +23,6 @@ import { } from 'Models'; import React, { useCallback, useEffect, useState } from 'react'; import { useHistory, useParams } from 'react-router-dom'; -import { useAuthContext } from '../../authentication/auth-provider/AuthProvider'; import { deleteGlossary, deleteGlossaryTerm, @@ -42,7 +41,6 @@ import { myDataSearchIndex } from '../../constants/Mydata.constants'; import { SearchIndex } from '../../enums/search.enum'; import { Glossary } from '../../generated/entity/data/glossary'; import { GlossaryTerm } from '../../generated/entity/data/glossaryTerm'; -import { useAuth } from '../../hooks/authHooks'; import jsonData from '../../jsons/en'; import { formatDataResponse } from '../../utils/APIUtils'; import { @@ -66,8 +64,6 @@ export type ModifiedGlossaryData = Glossary & { const GlossaryPageV1 = () => { const { glossaryName } = useParams>(); - const { isAdminUser } = useAuth(); - const { isAuthDisabled } = useAuthContext(); const history = useHistory(); const [isLoading, setIsLoading] = useState(true); const [isChildLoading, setIsChildLoading] = useState(true); @@ -724,7 +720,6 @@ const GlossaryPageV1 = () => { handleUserRedirection={handleUserRedirection} isChildLoading={isChildLoading} isGlossaryActive={isGlossaryActive} - isHasAccess={!isAdminUser && !isAuthDisabled} isSearchResultEmpty={isSearchResultEmpty} loadingKey={loadingKey} searchText={searchText} diff --git a/openmetadata-ui/src/main/resources/ui/src/router/AuthenticatedAppRouter.tsx b/openmetadata-ui/src/main/resources/ui/src/router/AuthenticatedAppRouter.tsx index e5f7fda85c8..56a2d416be8 100644 --- a/openmetadata-ui/src/main/resources/ui/src/router/AuthenticatedAppRouter.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/router/AuthenticatedAppRouter.tsx @@ -12,7 +12,7 @@ */ import { isEmpty } from 'lodash'; -import React, { FunctionComponent } from 'react'; +import React, { FunctionComponent, useMemo } from 'react'; import { Redirect, Route, Switch } from 'react-router-dom'; import AppState from '../AppState'; import { usePermissionProvider } from '../components/PermissionProvider/PermissionProvider'; @@ -212,6 +212,32 @@ const EditRulePage = withSuspenseFallback( const AuthenticatedAppRouter: FunctionComponent = () => { const { permissions } = usePermissionProvider(); + const glossaryPermission = useMemo( + () => + checkPermission(Operation.ViewAll, ResourceEntity.GLOSSARY, permissions), + [permissions] + ); + + const glossaryTermPermission = useMemo( + () => + checkPermission( + Operation.ViewAll, + ResourceEntity.GLOSSARY_TERM, + permissions + ), + [permissions] + ); + + const tagCategoryPermission = useMemo( + () => + checkPermission( + Operation.ViewAll, + ResourceEntity.TAG_CATEGORY, + permissions + ), + [permissions] + ); + return ( @@ -251,8 +277,18 @@ const AuthenticatedAppRouter: FunctionComponent = () => { {!isEmpty(AppState.userDetails) && } - - + + { /> - - - + + +