diff --git a/openmetadata-ui/src/main/resources/ui/src/axiosAPIs/permissionAPI.ts b/openmetadata-ui/src/main/resources/ui/src/axiosAPIs/permissionAPI.ts index 98868c634db..543ab3fa884 100644 --- a/openmetadata-ui/src/main/resources/ui/src/axiosAPIs/permissionAPI.ts +++ b/openmetadata-ui/src/main/resources/ui/src/axiosAPIs/permissionAPI.ts @@ -38,6 +38,16 @@ export const getEntityPermissionById = async ( return response.data; }; +export const getEntityPermissionByFqn = async ( + resource: ResourceEntity, + entityFqn: string +) => { + const response = await APIClient.get( + `/permissions/${resource}/name/${entityFqn}` + ); + + return response.data; +}; export const getResourcePermission = async (resource: ResourceEntity) => { const response = await APIClient.get( diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.component.tsx index d9f6e67bcd9..141a04131b4 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.component.tsx @@ -172,7 +172,9 @@ const DatasetDetails: React.FC = ({ }, [tableDetails.id, getEntityPermission, setTablePermissions]); useEffect(() => { - fetchResourcePermission(); + if (tableDetails.id) { + fetchResourcePermission(); + } }, [tableDetails.id]); const onEntityFieldSelect = (value: string) => { diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.test.tsx index 2486b37b2dc..9a80723d3ef 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/DatasetDetails/DatasetDetails.test.tsx @@ -269,6 +269,31 @@ jest.mock('../PermissionProvider/PermissionProvider', () => ({ })), })); +jest.mock('../../utils/PermissionsUtils', () => ({ + DEFAULT_ENTITY_PERMISSION: { + Create: true, + Delete: true, + EditAll: true, + EditCustomFields: true, + EditDataProfile: true, + EditDescription: true, + EditDisplayName: true, + EditLineage: true, + EditOwner: true, + EditQueries: true, + EditSampleData: true, + EditTags: true, + EditTests: true, + EditTier: true, + ViewAll: true, + ViewDataProfile: true, + ViewQueries: true, + ViewSampleData: true, + ViewTests: true, + ViewUsage: true, + }, +})); + describe('Test MyDataDetailsPage page', () => { it('Checks if the page has all the proper components rendered', async () => { const { container } = render(, { diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MlModelDetail/MlModelDetail.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MlModelDetail/MlModelDetail.component.tsx index 8a5cc9fba2e..1bb8e6e274f 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/MlModelDetail/MlModelDetail.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/MlModelDetail/MlModelDetail.component.tsx @@ -128,7 +128,9 @@ const MlModelDetail: FC = ({ }, [mlModelDetail.id, getEntityPermission, setPipelinePermissions]); useEffect(() => { - fetchResourcePermission(); + if (mlModelDetail.id) { + fetchResourcePermission(); + } }, [mlModelDetail.id]); const currentUser = useMemo( diff --git a/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.interface.ts index 10f33f9cfa3..659b3fcd55a 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.interface.ts +++ b/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.interface.ts @@ -65,6 +65,10 @@ export interface PermissionContextType { resource: ResourceEntity, entityId: string ) => Promise; + getEntityPermissionByFqn: ( + resource: ResourceEntity, + entityFqn: string + ) => Promise; getResourcePermission: ( resource: ResourceEntity ) => Promise; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.tsx b/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.tsx index 9a4d8a12e81..72f3b582ddf 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.tsx @@ -23,6 +23,7 @@ import React, { } from 'react'; import AppState from '../../AppState'; import { + getEntityPermissionByFqn, getEntityPermissionById, getLoggedInUserPermissions, getResourcePermission, @@ -105,6 +106,25 @@ const PermissionProvider: FC = ({ children }) => { } }; + const fetchEntityPermissionByFqn = async ( + resource: ResourceEntity, + entityFqn: string + ) => { + const entityPermission = entitiesPermission[entityFqn]; + if (entityPermission) { + return entityPermission; + } else { + const response = await getEntityPermissionByFqn(resource, entityFqn); + const operationPermission = getOperationPermissions(response); + setEntitiesPermission((prev) => ({ + ...prev, + [entityFqn]: operationPermission, + })); + + return operationPermission; + } + }; + const fetchResourcePermission = async (resource: ResourceEntity) => { const resourcePermission = resourcesPermission[resource]; if (resourcePermission) { @@ -134,6 +154,7 @@ const PermissionProvider: FC = ({ children }) => { permissions, getEntityPermission: fetchEntityPermission, getResourcePermission: fetchResourcePermission, + getEntityPermissionByFqn: fetchEntityPermissionByFqn, }}> {children} diff --git a/openmetadata-ui/src/main/resources/ui/src/components/PipelineDetails/PipelineDetails.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/PipelineDetails/PipelineDetails.component.tsx index e45a6b46f52..bae60547f49 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/PipelineDetails/PipelineDetails.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/PipelineDetails/PipelineDetails.component.tsx @@ -154,7 +154,9 @@ const PipelineDetails = ({ }, [pipelineDetails.id, getEntityPermission, setPipelinePermissions]); useEffect(() => { - fetchResourcePermission(); + if (pipelineDetails.id) { + fetchResourcePermission(); + } }, [pipelineDetails.id]); const onEntityFieldSelect = (value: string) => { diff --git a/openmetadata-ui/src/main/resources/ui/src/components/TableProfiler/TableProfilerV1.tsx b/openmetadata-ui/src/main/resources/ui/src/components/TableProfiler/TableProfilerV1.tsx index 39bfe9f8042..4b5a582c59d 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/TableProfiler/TableProfilerV1.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/TableProfiler/TableProfilerV1.tsx @@ -272,12 +272,14 @@ const TableProfilerV1: FC = ({ onAddTestClick={onAddTestClick} /> - + {settingModalVisible && ( + + )} ); }; diff --git a/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicDetails.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicDetails.component.tsx index 82d7c4afd95..4edf2b2bba5 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicDetails.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicDetails.component.tsx @@ -139,7 +139,9 @@ const TopicDetails: React.FC = ({ }, [topicDetails.id, getEntityPermission, setTopicPermissions]); useEffect(() => { - fetchResourcePermission(); + if (topicDetails.id) { + fetchResourcePermission(); + } }, [topicDetails.id]); const onEntityFieldSelect = (value: string) => { diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/DashboardDetailsPage/DashboardDetailsPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/DashboardDetailsPage/DashboardDetailsPage.component.tsx index 06449709838..037f7a7ea2e 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/DashboardDetailsPage/DashboardDetailsPage.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/DashboardDetailsPage/DashboardDetailsPage.component.tsx @@ -47,11 +47,14 @@ import { EdgeData, } from '../../components/EntityLineage/EntityLineage.interface'; import Loader from '../../components/Loader/Loader'; +import { usePermissionProvider } from '../../components/PermissionProvider/PermissionProvider'; +import { ResourceEntity } from '../../components/PermissionProvider/PermissionProvider.interface'; import { getDashboardDetailsPath, getServiceDetailsPath, getVersionPath, } from '../../constants/constants'; +import { NO_PERMISSION_TO_VIEW } from '../../constants/HelperTextUtil'; import { EntityType, TabSpecificField } from '../../enums/entity.enum'; import { FeedFilter } from '../../enums/mydata.enum'; import { ServiceCategory } from '../../enums/service.enum'; @@ -79,6 +82,7 @@ import { } from '../../utils/DashboardDetailsUtils'; import { getEntityFeedLink, getEntityLineage } from '../../utils/EntityUtils'; import { deletePost, updateThreadData } from '../../utils/FeedUtils'; +import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils'; import { serviceTypeLogo } from '../../utils/ServiceUtils'; import { getTagsWithoutTier, getTierTags } from '../../utils/TableUtils'; import { showErrorToast } from '../../utils/ToastUtils'; @@ -90,6 +94,7 @@ export type ChartType = { const DashboardDetailsPage = () => { const USERId = getCurrentUserId(); const history = useHistory(); + const { getEntityPermissionByFqn } = usePermissionProvider(); const { dashboardFQN, tab } = useParams() as Record; const [dashboardDetails, setDashboardDetails] = useState( {} as Dashboard @@ -136,6 +141,27 @@ const DashboardDetailsPage = () => { >([]); const [paging, setPaging] = useState({} as Paging); + const [dashboardPermissions, setDashboardPermissions] = useState( + DEFAULT_ENTITY_PERMISSION + ); + + const fetchResourcePermission = async (entityFqn: string) => { + setLoading(true); + try { + const entityPermission = await getEntityPermissionByFqn( + ResourceEntity.DASHBOARD, + entityFqn + ); + setDashboardPermissions(entityPermission); + } catch (error) { + showErrorToast( + jsonData['api-error-messages']['fetch-entity-permissions-error'] + ); + } finally { + setLoading(false); + } + }; + const activeTabHandler = (tabValue: number) => { const currentTabIndex = tabValue - 1; if (dashboardDetailsTabs[currentTabIndex].path !== tab) { @@ -727,9 +753,15 @@ const DashboardDetailsPage = () => { }, [activeTab]); useEffect(() => { - fetchDashboardDetail(dashboardFQN); - setEntityLineage({} as EntityLineage); - getEntityFeedCount(); + if (dashboardPermissions.ViewAll) { + fetchDashboardDetail(dashboardFQN); + setEntityLineage({} as EntityLineage); + getEntityFeedCount(); + } + }, [dashboardFQN, dashboardPermissions]); + + useEffect(() => { + fetchResourcePermission(dashboardFQN); }, [dashboardFQN]); useEffect(() => { @@ -748,52 +780,58 @@ const DashboardDetailsPage = () => { {getEntityMissingError('dashboard', dashboardFQN)} ) : ( - + <> + {dashboardPermissions.ViewAll ? ( + + ) : ( + {NO_PERMISSION_TO_VIEW} + )} + )} ); diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/DatasetDetailsPage/DatasetDetailsPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/DatasetDetailsPage/DatasetDetailsPage.component.tsx index 82ff551eaa6..7e9622002dd 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/DatasetDetailsPage/DatasetDetailsPage.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/DatasetDetailsPage/DatasetDetailsPage.component.tsx @@ -50,6 +50,11 @@ import { EdgeData, } from '../../components/EntityLineage/EntityLineage.interface'; import Loader from '../../components/Loader/Loader'; +import { usePermissionProvider } from '../../components/PermissionProvider/PermissionProvider'; +import { + OperationPermission, + ResourceEntity, +} from '../../components/PermissionProvider/PermissionProvider.interface'; import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants'; import { getDatabaseDetailsPath, @@ -58,6 +63,7 @@ import { getTableTabPath, getVersionPath, } from '../../constants/constants'; +import { NO_PERMISSION_TO_VIEW } from '../../constants/HelperTextUtil'; import { EntityType, FqnPart, TabSpecificField } from '../../enums/entity.enum'; import { FeedFilter } from '../../enums/mydata.enum'; import { ServiceCategory } from '../../enums/service.enum'; @@ -100,12 +106,14 @@ import { } from '../../utils/DatasetDetailsUtils'; import { getEntityFeedLink, getEntityLineage } from '../../utils/EntityUtils'; import { deletePost, updateThreadData } from '../../utils/FeedUtils'; +import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils'; import { serviceTypeLogo } from '../../utils/ServiceUtils'; import { getTagsWithoutTier, getTierTags } from '../../utils/TableUtils'; import { showErrorToast, showSuccessToast } from '../../utils/ToastUtils'; const DatasetDetailsPage: FunctionComponent = () => { const history = useHistory(); + const { getEntityPermissionByFqn } = usePermissionProvider(); const [isLoading, setIsLoading] = useState(true); const [isLineageLoading, setIsLineageLoading] = useState(false); const [isSampleDataLoading, setIsSampleDataLoading] = @@ -174,6 +182,10 @@ const DatasetDetailsPage: FunctionComponent = () => { EntityFieldThreadCount[] >([]); + const [tablePermissions, setTablePermissions] = useState( + DEFAULT_ENTITY_PERMISSION + ); + // Data Quality tab state const [testMode, setTestMode] = useState('table'); const [showTestForm, setShowTestForm] = useState(false); @@ -289,6 +301,24 @@ const DatasetDetailsPage: FunctionComponent = () => { getFeedData(after, feedType, threadType); }; + const fetchResourcePermission = async (entityFqn: string) => { + setIsLoading(true); + try { + const tablePermission = await getEntityPermissionByFqn( + ResourceEntity.TABLE, + entityFqn + ); + + setTablePermissions(tablePermission); + } catch (error) { + showErrorToast( + jsonData['api-error-messages']['fetch-entity-permissions-error'] + ); + } finally { + setIsLoading(false); + } + }; + const fetchTableDetail = () => { setIsLoading(true); getTableDetailsByFQN( @@ -945,9 +975,15 @@ const DatasetDetailsPage: FunctionComponent = () => { }; useEffect(() => { - fetchTableDetail(); - setActiveTab(getCurrentDatasetTab(tab)); - getEntityFeedCount(); + if (tablePermissions.ViewAll) { + fetchTableDetail(); + setActiveTab(getCurrentDatasetTab(tab)); + getEntityFeedCount(); + } + }, [tablePermissions]); + + useEffect(() => { + fetchResourcePermission(tableFQN); }, [tableFQN]); useEffect(() => { @@ -970,70 +1006,76 @@ const DatasetDetailsPage: FunctionComponent = () => { {getEntityMissingError('table', tableFQN)} ) : ( - + <> + {tablePermissions.ViewAll ? ( + + ) : ( + {NO_PERMISSION_TO_VIEW} + )} + )} ); diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/DatasetDetailsPage/DatasetDetailsPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/DatasetDetailsPage/DatasetDetailsPage.test.tsx index 25aafc43a44..179202897a6 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/DatasetDetailsPage/DatasetDetailsPage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/DatasetDetailsPage/DatasetDetailsPage.test.tsx @@ -70,6 +70,59 @@ jest.mock('../../AppState', () => ({ ], })); +jest.mock('../../components/PermissionProvider/PermissionProvider', () => ({ + usePermissionProvider: jest.fn().mockImplementation(() => ({ + permissions: {}, + getEntityPermission: jest.fn().mockResolvedValue({ + Create: true, + Delete: true, + EditAll: true, + EditCustomFields: true, + EditDataProfile: true, + EditDescription: true, + EditDisplayName: true, + EditLineage: true, + EditOwner: true, + EditQueries: true, + EditSampleData: true, + EditTags: true, + EditTests: true, + EditTier: true, + ViewAll: true, + ViewDataProfile: true, + ViewQueries: true, + ViewSampleData: true, + ViewTests: true, + ViewUsage: true, + }), + })), +})); + +jest.mock('../../utils/PermissionsUtils', () => ({ + DEFAULT_ENTITY_PERMISSION: { + Create: true, + Delete: true, + EditAll: true, + EditCustomFields: true, + EditDataProfile: true, + EditDescription: true, + EditDisplayName: true, + EditLineage: true, + EditOwner: true, + EditQueries: true, + EditSampleData: true, + EditTags: true, + EditTests: true, + EditTier: true, + ViewAll: true, + ViewDataProfile: true, + ViewQueries: true, + ViewSampleData: true, + ViewTests: true, + ViewUsage: true, + }, +})); + jest.mock('../../components/DatasetDetails/DatasetDetails.component', () => { return jest .fn() diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/MlModelPage/MlModelPage.component.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/MlModelPage/MlModelPage.component.test.tsx index bea8c1ea54e..a982caff66f 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/MlModelPage/MlModelPage.component.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/MlModelPage/MlModelPage.component.test.tsx @@ -153,6 +153,59 @@ jest.mock('../../components/MlModelDetail/MlModelDetail.component', () => { .mockReturnValue(
MlModelDetails
); }); +jest.mock('../../components/PermissionProvider/PermissionProvider', () => ({ + usePermissionProvider: jest.fn().mockImplementation(() => ({ + permissions: {}, + getEntityPermission: jest.fn().mockResolvedValue({ + Create: true, + Delete: true, + EditAll: true, + EditCustomFields: true, + EditDataProfile: true, + EditDescription: true, + EditDisplayName: true, + EditLineage: true, + EditOwner: true, + EditQueries: true, + EditSampleData: true, + EditTags: true, + EditTests: true, + EditTier: true, + ViewAll: true, + ViewDataProfile: true, + ViewQueries: true, + ViewSampleData: true, + ViewTests: true, + ViewUsage: true, + }), + })), +})); + +jest.mock('../../utils/PermissionsUtils', () => ({ + DEFAULT_ENTITY_PERMISSION: { + Create: true, + Delete: true, + EditAll: true, + EditCustomFields: true, + EditDataProfile: true, + EditDescription: true, + EditDisplayName: true, + EditLineage: true, + EditOwner: true, + EditQueries: true, + EditSampleData: true, + EditTags: true, + EditTests: true, + EditTier: true, + ViewAll: true, + ViewDataProfile: true, + ViewQueries: true, + ViewSampleData: true, + ViewTests: true, + ViewUsage: true, + }, +})); + describe('Test MlModel Entity Page', () => { it('Should render component', async () => { const { container } = render(, { diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/MlModelPage/MlModelPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/MlModelPage/MlModelPage.component.tsx index 9c168d7a15e..2894ccff8aa 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/MlModelPage/MlModelPage.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/MlModelPage/MlModelPage.component.tsx @@ -33,7 +33,10 @@ import { } from '../../components/EntityLineage/EntityLineage.interface'; import Loader from '../../components/Loader/Loader'; import MlModelDetailComponent from '../../components/MlModelDetail/MlModelDetail.component'; +import { usePermissionProvider } from '../../components/PermissionProvider/PermissionProvider'; +import { ResourceEntity } from '../../components/PermissionProvider/PermissionProvider.interface'; import { getMlModelPath } from '../../constants/constants'; +import { NO_PERMISSION_TO_VIEW } from '../../constants/HelperTextUtil'; import { EntityType, TabSpecificField } from '../../enums/entity.enum'; import { Mlmodel } from '../../generated/entity/data/mlmodel'; import { @@ -51,6 +54,7 @@ import { getCurrentMlModelTab, mlModelTabs, } from '../../utils/MlModelDetailsUtils'; +import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils'; import { showErrorToast } from '../../utils/ToastUtils'; const MlModelPage = () => { @@ -71,6 +75,29 @@ const MlModelPage = () => { }); const [isLineageLoading, setIsLineageLoading] = useState(false); + const [mlModelPermissions, setPipelinePermissions] = useState( + DEFAULT_ENTITY_PERMISSION + ); + + const { getEntityPermissionByFqn } = usePermissionProvider(); + + const fetchResourcePermission = async (entityFqn: string) => { + setIsDetailLoading(true); + try { + const entityPermission = await getEntityPermissionByFqn( + ResourceEntity.ML_MODEL, + entityFqn + ); + setPipelinePermissions(entityPermission); + } catch (error) { + showErrorToast( + jsonData['api-error-messages']['fetch-entity-permissions-error'] + ); + } finally { + setIsDetailLoading(false); + } + }; + const getLineageData = () => { setIsLineageLoading(true); getLineageByFQN(mlModelDetail.fullyQualifiedName ?? '', EntityType.MLMODEL) @@ -404,11 +431,29 @@ const MlModelPage = () => { }, [activeTab, mlModelDetail]); useEffect(() => { - fetchMlModelDetails(mlModelFqn); + if (mlModelPermissions.ViewAll) { + fetchMlModelDetails(mlModelFqn); + } + }, [mlModelPermissions, mlModelFqn]); + + useEffect(() => { + fetchResourcePermission(mlModelFqn); }, [mlModelFqn]); return ( - {isDetailLoading ? : getMlModelDetail()} + + {isDetailLoading ? ( + + ) : ( + <> + {mlModelPermissions.ViewAll ? ( + getMlModelDetail() + ) : ( + {NO_PERMISSION_TO_VIEW} + )} + + )} + ); }; diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/PipelineDetails/PipelineDetailsPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/PipelineDetails/PipelineDetailsPage.component.tsx index c79fc159d10..75fc5ee227e 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/PipelineDetails/PipelineDetailsPage.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/PipelineDetails/PipelineDetailsPage.component.tsx @@ -46,12 +46,15 @@ import { EdgeData, } from '../../components/EntityLineage/EntityLineage.interface'; import Loader from '../../components/Loader/Loader'; +import { usePermissionProvider } from '../../components/PermissionProvider/PermissionProvider'; +import { ResourceEntity } from '../../components/PermissionProvider/PermissionProvider.interface'; import PipelineDetails from '../../components/PipelineDetails/PipelineDetails.component'; import { getPipelineDetailsPath, getServiceDetailsPath, getVersionPath, } from '../../constants/constants'; +import { NO_PERMISSION_TO_VIEW } from '../../constants/HelperTextUtil'; import { EntityType, TabSpecificField } from '../../enums/entity.enum'; import { FeedFilter } from '../../enums/mydata.enum'; import { ServiceCategory } from '../../enums/service.enum'; @@ -73,6 +76,7 @@ import { } from '../../utils/CommonUtils'; import { getEntityFeedLink, getEntityLineage } from '../../utils/EntityUtils'; import { deletePost, updateThreadData } from '../../utils/FeedUtils'; +import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils'; import { defaultFields, getCurrentPipelineTab, @@ -137,6 +141,29 @@ const PipelineDetailsPage = () => { EntityFieldThreadCount[] >([]); + const [pipelinePermissions, setPipelinePermissions] = useState( + DEFAULT_ENTITY_PERMISSION + ); + + const { getEntityPermissionByFqn } = usePermissionProvider(); + + const fetchResourcePermission = async (entityFqn: string) => { + setLoading(true); + try { + const entityPermission = await getEntityPermissionByFqn( + ResourceEntity.PIPELINE, + entityFqn + ); + setPipelinePermissions(entityPermission); + } catch (error) { + showErrorToast( + jsonData['api-error-messages']['fetch-entity-permissions-error'] + ); + } finally { + setLoading(false); + } + }; + const activeTabHandler = (tabValue: number) => { const currentTabIndex = tabValue - 1; if (pipelineDetailsTabs[currentTabIndex].path !== tab) { @@ -668,9 +695,15 @@ const PipelineDetailsPage = () => { }, [activeTab]); useEffect(() => { - fetchPipelineDetail(pipelineFQN); - setEntityLineage({} as EntityLineage); - getEntityFeedCount(); + if (pipelinePermissions.ViewAll) { + fetchPipelineDetail(pipelineFQN); + setEntityLineage({} as EntityLineage); + getEntityFeedCount(); + } + }, [pipelinePermissions, pipelineFQN]); + + useEffect(() => { + fetchResourcePermission(pipelineFQN); }, [pipelineFQN]); useEffect(() => { @@ -689,52 +722,58 @@ const PipelineDetailsPage = () => { {getEntityMissingError('pipeline', pipelineFQN)} ) : ( - + <> + {pipelinePermissions.ViewAll ? ( + + ) : ( + {NO_PERMISSION_TO_VIEW} + )} + )} ); diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/PipelineDetails/PipelineDetailsPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/PipelineDetails/PipelineDetailsPage.test.tsx index e878ce7050e..e7d93ecf4c4 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/PipelineDetails/PipelineDetailsPage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/PipelineDetails/PipelineDetailsPage.test.tsx @@ -38,6 +38,59 @@ jest.mock( } ); +jest.mock('../../components/PermissionProvider/PermissionProvider', () => ({ + usePermissionProvider: jest.fn().mockImplementation(() => ({ + permissions: {}, + getEntityPermission: jest.fn().mockResolvedValue({ + Create: true, + Delete: true, + EditAll: true, + EditCustomFields: true, + EditDataProfile: true, + EditDescription: true, + EditDisplayName: true, + EditLineage: true, + EditOwner: true, + EditQueries: true, + EditSampleData: true, + EditTags: true, + EditTests: true, + EditTier: true, + ViewAll: true, + ViewDataProfile: true, + ViewQueries: true, + ViewSampleData: true, + ViewTests: true, + ViewUsage: true, + }), + })), +})); + +jest.mock('../../utils/PermissionsUtils', () => ({ + DEFAULT_ENTITY_PERMISSION: { + Create: true, + Delete: true, + EditAll: true, + EditCustomFields: true, + EditDataProfile: true, + EditDescription: true, + EditDisplayName: true, + EditLineage: true, + EditOwner: true, + EditQueries: true, + EditSampleData: true, + EditTags: true, + EditTests: true, + EditTier: true, + ViewAll: true, + ViewDataProfile: true, + ViewQueries: true, + ViewSampleData: true, + ViewTests: true, + ViewUsage: true, + }, +})); + describe('Test PipelineDetailsPage component', () => { it('PipelineDetailsPage component should render properly', async () => { const { container } = render(, { diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TopicDetails/TopicDetailsPage.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TopicDetails/TopicDetailsPage.component.tsx index 314e0a4505b..485f017c1df 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/TopicDetails/TopicDetailsPage.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/TopicDetails/TopicDetailsPage.component.tsx @@ -45,12 +45,18 @@ import { EdgeData, } from '../../components/EntityLineage/EntityLineage.interface'; import Loader from '../../components/Loader/Loader'; +import { usePermissionProvider } from '../../components/PermissionProvider/PermissionProvider'; +import { + OperationPermission, + ResourceEntity, +} from '../../components/PermissionProvider/PermissionProvider.interface'; import TopicDetails from '../../components/TopicDetails/TopicDetails.component'; import { getServiceDetailsPath, getTopicDetailsPath, getVersionPath, } from '../../constants/constants'; +import { NO_PERMISSION_TO_VIEW } from '../../constants/HelperTextUtil'; import { EntityType, TabSpecificField } from '../../enums/entity.enum'; import { FeedFilter } from '../../enums/mydata.enum'; import { ServiceCategory } from '../../enums/service.enum'; @@ -71,6 +77,7 @@ import { } from '../../utils/CommonUtils'; import { getEntityFeedLink, getEntityLineage } from '../../utils/EntityUtils'; import { deletePost, updateThreadData } from '../../utils/FeedUtils'; +import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils'; import { serviceTypeLogo } from '../../utils/ServiceUtils'; import { getTagsWithoutTier, getTierTags } from '../../utils/TableUtils'; import { showErrorToast } from '../../utils/ToastUtils'; @@ -82,6 +89,7 @@ import { const TopicDetailsPage: FunctionComponent = () => { const USERId = getCurrentUserId(); const history = useHistory(); + const { getEntityPermissionByFqn } = usePermissionProvider(); const { topicFQN, tab } = useParams() as Record; const [topicDetails, setTopicDetails] = useState({} as Topic); @@ -133,6 +141,10 @@ const TopicDetailsPage: FunctionComponent = () => { }); const [isLineageLoading, setIsLineageLoading] = useState(false); + const [topicPermissions, setTopicPermissions] = useState( + DEFAULT_ENTITY_PERMISSION + ); + const getLineageData = () => { setIsLineageLoading(true); getLineageByFQN(topicFQN, EntityType.TOPIC) @@ -352,6 +364,23 @@ const TopicDetailsPage: FunctionComponent = () => { return patchTopicDetails(topicId, jsonPatch); }; + const fetchResourcePermission = async (entityFqn: string) => { + setLoading(true); + try { + const permissions = await getEntityPermissionByFqn( + ResourceEntity.TOPIC, + entityFqn + ); + setTopicPermissions(permissions); + } catch (error) { + showErrorToast( + jsonData['api-error-messages']['fetch-entity-permissions-error'] + ); + } finally { + setLoading(false); + } + }; + const fetchTopicDetail = (topicFQN: string) => { setLoading(true); getTopicByFqn(topicFQN, [ @@ -662,10 +691,16 @@ const TopicDetailsPage: FunctionComponent = () => { }, [activeTab]); useEffect(() => { - fetchTopicDetail(topicFQN); - getEntityFeedCount(); + fetchResourcePermission(topicFQN); }, [topicFQN]); + useEffect(() => { + if (topicPermissions.ViewAll) { + fetchTopicDetail(topicFQN); + getEntityFeedCount(); + } + }, [topicPermissions, topicFQN]); + return ( <> {isLoading ? ( @@ -675,58 +710,64 @@ const TopicDetailsPage: FunctionComponent = () => { {getEntityMissingError('topic', topicFQN)} ) : ( - + <> + {topicPermissions.ViewAll ? ( + + ) : ( + {NO_PERMISSION_TO_VIEW} + )} + )} ); diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TopicDetails/TopicDetailsPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TopicDetails/TopicDetailsPage.test.tsx index 777dc28bf9d..3f81428fa30 100644 --- a/openmetadata-ui/src/main/resources/ui/src/pages/TopicDetails/TopicDetailsPage.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/pages/TopicDetails/TopicDetailsPage.test.tsx @@ -21,6 +21,59 @@ jest.mock('react-router-dom', () => ({ useHistory: jest.fn(), })); +jest.mock('../../components/PermissionProvider/PermissionProvider', () => ({ + usePermissionProvider: jest.fn().mockImplementation(() => ({ + permissions: {}, + getEntityPermission: jest.fn().mockResolvedValue({ + Create: true, + Delete: true, + EditAll: true, + EditCustomFields: true, + EditDataProfile: true, + EditDescription: true, + EditDisplayName: true, + EditLineage: true, + EditOwner: true, + EditQueries: true, + EditSampleData: true, + EditTags: true, + EditTests: true, + EditTier: true, + ViewAll: true, + ViewDataProfile: true, + ViewQueries: true, + ViewSampleData: true, + ViewTests: true, + ViewUsage: true, + }), + })), +})); + +jest.mock('../../utils/PermissionsUtils', () => ({ + DEFAULT_ENTITY_PERMISSION: { + Create: true, + Delete: true, + EditAll: true, + EditCustomFields: true, + EditDataProfile: true, + EditDescription: true, + EditDisplayName: true, + EditLineage: true, + EditOwner: true, + EditQueries: true, + EditSampleData: true, + EditTags: true, + EditTests: true, + EditTier: true, + ViewAll: true, + ViewDataProfile: true, + ViewQueries: true, + ViewSampleData: true, + ViewTests: true, + ViewUsage: true, + }, +})); + describe('Test TopicDetailsPage component', () => { it('TopicDetailsPage component should render properly', async () => { const { container } = render(, {