UI : Add Permission Check on Entity Page (#7303)

* UI : Add Permission Check on Entity Page

* Change dependency
This commit is contained in:
Sachin Chaurasiya 2022-09-07 17:05:54 +05:30 committed by GitHub
parent 1a9a67b087
commit 58c439e900
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 718 additions and 231 deletions

View File

@ -38,6 +38,16 @@ export const getEntityPermissionById = async (
return response.data;
};
export const getEntityPermissionByFqn = async (
resource: ResourceEntity,
entityFqn: string
) => {
const response = await APIClient.get<ResourcePermission>(
`/permissions/${resource}/name/${entityFqn}`
);
return response.data;
};
export const getResourcePermission = async (resource: ResourceEntity) => {
const response = await APIClient.get<ResourcePermission>(

View File

@ -172,7 +172,9 @@ const DatasetDetails: React.FC<DatasetDetailsProps> = ({
}, [tableDetails.id, getEntityPermission, setTablePermissions]);
useEffect(() => {
fetchResourcePermission();
if (tableDetails.id) {
fetchResourcePermission();
}
}, [tableDetails.id]);
const onEntityFieldSelect = (value: string) => {

View File

@ -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(<DatasetDetails {...DatasetDetailsProps} />, {

View File

@ -128,7 +128,9 @@ const MlModelDetail: FC<MlModelDetailProp> = ({
}, [mlModelDetail.id, getEntityPermission, setPipelinePermissions]);
useEffect(() => {
fetchResourcePermission();
if (mlModelDetail.id) {
fetchResourcePermission();
}
}, [mlModelDetail.id]);
const currentUser = useMemo(

View File

@ -65,6 +65,10 @@ export interface PermissionContextType {
resource: ResourceEntity,
entityId: string
) => Promise<OperationPermission>;
getEntityPermissionByFqn: (
resource: ResourceEntity,
entityFqn: string
) => Promise<OperationPermission>;
getResourcePermission: (
resource: ResourceEntity
) => Promise<OperationPermission>;

View File

@ -23,6 +23,7 @@ import React, {
} from 'react';
import AppState from '../../AppState';
import {
getEntityPermissionByFqn,
getEntityPermissionById,
getLoggedInUserPermissions,
getResourcePermission,
@ -105,6 +106,25 @@ const PermissionProvider: FC<PermissionProviderProps> = ({ 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<PermissionProviderProps> = ({ children }) => {
permissions,
getEntityPermission: fetchEntityPermission,
getResourcePermission: fetchResourcePermission,
getEntityPermissionByFqn: fetchEntityPermissionByFqn,
}}>
{children}
</PermissionContext.Provider>

View File

@ -154,7 +154,9 @@ const PipelineDetails = ({
}, [pipelineDetails.id, getEntityPermission, setPipelinePermissions]);
useEffect(() => {
fetchResourcePermission();
if (pipelineDetails.id) {
fetchResourcePermission();
}
}, [pipelineDetails.id]);
const onEntityFieldSelect = (value: string) => {

View File

@ -272,12 +272,14 @@ const TableProfilerV1: FC<TableProfilerProps> = ({
onAddTestClick={onAddTestClick}
/>
<ProfilerSettingsModal
columns={columns}
tableId={table.id}
visible={settingModalVisible}
onVisibilityChange={handleSettingModal}
/>
{settingModalVisible && (
<ProfilerSettingsModal
columns={columns}
tableId={table.id}
visible={settingModalVisible}
onVisibilityChange={handleSettingModal}
/>
)}
</div>
);
};

View File

@ -139,7 +139,9 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
}, [topicDetails.id, getEntityPermission, setTopicPermissions]);
useEffect(() => {
fetchResourcePermission();
if (topicDetails.id) {
fetchResourcePermission();
}
}, [topicDetails.id]);
const onEntityFieldSelect = (value: string) => {

View File

@ -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<string, string>;
const [dashboardDetails, setDashboardDetails] = useState<Dashboard>(
{} as Dashboard
@ -136,6 +141,27 @@ const DashboardDetailsPage = () => {
>([]);
const [paging, setPaging] = useState<Paging>({} 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)}
</ErrorPlaceHolder>
) : (
<DashboardDetails
activeTab={activeTab}
addLineageHandler={addLineageHandler}
chartDescriptionUpdateHandler={onChartUpdate}
chartTagUpdateHandler={handleChartTagSelection}
charts={charts}
createThread={createThread}
dashboardDetails={dashboardDetails}
dashboardFQN={dashboardFQN}
dashboardTags={tags}
dashboardUrl={dashboardUrl}
deletePostHandler={deletePostHandler}
deleted={deleted}
description={description}
descriptionUpdateHandler={descriptionUpdateHandler}
entityFieldTaskCount={entityFieldTaskCount}
entityFieldThreadCount={entityFieldThreadCount}
entityLineage={entityLineage}
entityLineageHandler={entityLineageHandler}
entityName={displayName}
entityThread={entityThread}
feedCount={feedCount}
fetchFeedHandler={getFeedData}
followDashboardHandler={followDashboard}
followers={followers}
isLineageLoading={isLineageLoading}
isNodeLoading={isNodeLoading}
isentityThreadLoading={isentityThreadLoading}
lineageLeafNodes={leafNodes}
loadNodeHandler={loadNodeHandler}
owner={owner as EntityReference}
paging={paging}
postFeedHandler={postFeedHandler}
removeLineageHandler={removeLineageHandler}
serviceType={serviceType}
setActiveTabHandler={activeTabHandler}
settingsUpdateHandler={settingsUpdateHandler}
slashedDashboardName={slashedDashboardName}
tagUpdateHandler={onTagUpdate}
tier={tier as TagLabel}
unfollowDashboardHandler={unfollowDashboard}
updateThreadHandler={updateThreadHandler}
version={currentVersion as string}
versionHandler={versionHandler}
onExtensionUpdate={handleExtentionUpdate}
/>
<>
{dashboardPermissions.ViewAll ? (
<DashboardDetails
activeTab={activeTab}
addLineageHandler={addLineageHandler}
chartDescriptionUpdateHandler={onChartUpdate}
chartTagUpdateHandler={handleChartTagSelection}
charts={charts}
createThread={createThread}
dashboardDetails={dashboardDetails}
dashboardFQN={dashboardFQN}
dashboardTags={tags}
dashboardUrl={dashboardUrl}
deletePostHandler={deletePostHandler}
deleted={deleted}
description={description}
descriptionUpdateHandler={descriptionUpdateHandler}
entityFieldTaskCount={entityFieldTaskCount}
entityFieldThreadCount={entityFieldThreadCount}
entityLineage={entityLineage}
entityLineageHandler={entityLineageHandler}
entityName={displayName}
entityThread={entityThread}
feedCount={feedCount}
fetchFeedHandler={getFeedData}
followDashboardHandler={followDashboard}
followers={followers}
isLineageLoading={isLineageLoading}
isNodeLoading={isNodeLoading}
isentityThreadLoading={isentityThreadLoading}
lineageLeafNodes={leafNodes}
loadNodeHandler={loadNodeHandler}
owner={owner as EntityReference}
paging={paging}
postFeedHandler={postFeedHandler}
removeLineageHandler={removeLineageHandler}
serviceType={serviceType}
setActiveTabHandler={activeTabHandler}
settingsUpdateHandler={settingsUpdateHandler}
slashedDashboardName={slashedDashboardName}
tagUpdateHandler={onTagUpdate}
tier={tier as TagLabel}
unfollowDashboardHandler={unfollowDashboard}
updateThreadHandler={updateThreadHandler}
version={currentVersion as string}
versionHandler={versionHandler}
onExtensionUpdate={handleExtentionUpdate}
/>
) : (
<ErrorPlaceHolder>{NO_PERMISSION_TO_VIEW}</ErrorPlaceHolder>
)}
</>
)}
</>
);

View File

@ -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<boolean>(true);
const [isLineageLoading, setIsLineageLoading] = useState<boolean>(false);
const [isSampleDataLoading, setIsSampleDataLoading] =
@ -174,6 +182,10 @@ const DatasetDetailsPage: FunctionComponent = () => {
EntityFieldThreadCount[]
>([]);
const [tablePermissions, setTablePermissions] = useState<OperationPermission>(
DEFAULT_ENTITY_PERMISSION
);
// Data Quality tab state
const [testMode, setTestMode] = useState<DatasetTestModeType>('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)}
</ErrorPlaceHolder>
) : (
<DatasetDetails
activeTab={activeTab}
addLineageHandler={addLineageHandler}
columns={columns}
columnsUpdateHandler={columnsUpdateHandler}
createThread={createThread}
dataModel={tableDetails.dataModel}
datasetFQN={tableFQN}
deletePostHandler={deletePostHandler}
deleted={deleted}
description={description}
descriptionUpdateHandler={descriptionUpdateHandler}
entityFieldTaskCount={entityFieldTaskCount}
entityFieldThreadCount={entityFieldThreadCount}
entityLineage={entityLineage}
entityLineageHandler={entityLineageHandler}
entityName={name}
entityThread={entityThread}
feedCount={feedCount}
fetchFeedHandler={handleFeedFetchFromFeedList}
followTableHandler={followTable}
followers={followers}
handleAddColumnTestCase={handleAddColumnTestCase}
handleAddTableTestCase={handleAddTableTestCase}
handleExtentionUpdate={handleExtentionUpdate}
handleRemoveColumnTest={handleRemoveColumnTest}
handleRemoveTableTest={handleRemoveTableTest}
handleSelectedColumn={handleSelectedColumn}
handleShowTestForm={handleShowTestForm}
handleTestModeChange={handleTestModeChange}
isLineageLoading={isLineageLoading}
isNodeLoading={isNodeLoading}
isQueriesLoading={isTableQueriesLoading}
isSampleDataLoading={isSampleDataLoading}
isentityThreadLoading={isentityThreadLoading}
joins={joins}
lineageLeafNodes={leafNodes}
loadNodeHandler={loadNodeHandler}
owner={owner as EntityReference}
paging={paging}
postFeedHandler={postFeedHandler}
qualityTestFormHandler={qualityTestFormHandler}
removeLineageHandler={removeLineageHandler}
sampleData={sampleData}
selectedColumn={selectedColumn as string}
setActiveTabHandler={activeTabHandler}
settingsUpdateHandler={settingsUpdateHandler}
showTestForm={showTestForm}
slashedTableName={slashedTableName}
tableDetails={tableDetails}
tableProfile={tableProfile}
tableQueries={tableQueries}
tableTags={tableTags}
tableTestCase={tableTestCase}
tableType={tableType}
tagUpdateHandler={onTagUpdate}
testMode={testMode}
tier={tier as TagLabel}
unfollowTableHandler={unfollowTable}
updateThreadHandler={updateThreadHandler}
usageSummary={usageSummary}
version={currentVersion}
versionHandler={versionHandler}
/>
<>
{tablePermissions.ViewAll ? (
<DatasetDetails
activeTab={activeTab}
addLineageHandler={addLineageHandler}
columns={columns}
columnsUpdateHandler={columnsUpdateHandler}
createThread={createThread}
dataModel={tableDetails.dataModel}
datasetFQN={tableFQN}
deletePostHandler={deletePostHandler}
deleted={deleted}
description={description}
descriptionUpdateHandler={descriptionUpdateHandler}
entityFieldTaskCount={entityFieldTaskCount}
entityFieldThreadCount={entityFieldThreadCount}
entityLineage={entityLineage}
entityLineageHandler={entityLineageHandler}
entityName={name}
entityThread={entityThread}
feedCount={feedCount}
fetchFeedHandler={handleFeedFetchFromFeedList}
followTableHandler={followTable}
followers={followers}
handleAddColumnTestCase={handleAddColumnTestCase}
handleAddTableTestCase={handleAddTableTestCase}
handleExtentionUpdate={handleExtentionUpdate}
handleRemoveColumnTest={handleRemoveColumnTest}
handleRemoveTableTest={handleRemoveTableTest}
handleSelectedColumn={handleSelectedColumn}
handleShowTestForm={handleShowTestForm}
handleTestModeChange={handleTestModeChange}
isLineageLoading={isLineageLoading}
isNodeLoading={isNodeLoading}
isQueriesLoading={isTableQueriesLoading}
isSampleDataLoading={isSampleDataLoading}
isentityThreadLoading={isentityThreadLoading}
joins={joins}
lineageLeafNodes={leafNodes}
loadNodeHandler={loadNodeHandler}
owner={owner as EntityReference}
paging={paging}
postFeedHandler={postFeedHandler}
qualityTestFormHandler={qualityTestFormHandler}
removeLineageHandler={removeLineageHandler}
sampleData={sampleData}
selectedColumn={selectedColumn as string}
setActiveTabHandler={activeTabHandler}
settingsUpdateHandler={settingsUpdateHandler}
showTestForm={showTestForm}
slashedTableName={slashedTableName}
tableDetails={tableDetails}
tableProfile={tableProfile}
tableQueries={tableQueries}
tableTags={tableTags}
tableTestCase={tableTestCase}
tableType={tableType}
tagUpdateHandler={onTagUpdate}
testMode={testMode}
tier={tier as TagLabel}
unfollowTableHandler={unfollowTable}
updateThreadHandler={updateThreadHandler}
usageSummary={usageSummary}
version={currentVersion}
versionHandler={versionHandler}
/>
) : (
<ErrorPlaceHolder>{NO_PERMISSION_TO_VIEW}</ErrorPlaceHolder>
)}
</>
)}
</>
);

View File

@ -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()

View File

@ -153,6 +153,59 @@ jest.mock('../../components/MlModelDetail/MlModelDetail.component', () => {
.mockReturnValue(<div data-testid="mlmodel-details">MlModelDetails</div>);
});
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(<MlModelPageComponent />, {

View File

@ -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<boolean>(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 (
<Fragment>{isDetailLoading ? <Loader /> : getMlModelDetail()}</Fragment>
<Fragment>
{isDetailLoading ? (
<Loader />
) : (
<>
{mlModelPermissions.ViewAll ? (
getMlModelDetail()
) : (
<ErrorPlaceHolder>{NO_PERMISSION_TO_VIEW}</ErrorPlaceHolder>
)}
</>
)}
</Fragment>
);
};

View File

@ -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)}
</ErrorPlaceHolder>
) : (
<PipelineDetails
activeTab={activeTab}
addLineageHandler={addLineageHandler}
createThread={createThread}
deletePostHandler={deletePostHandler}
deleted={deleted}
description={description}
descriptionUpdateHandler={descriptionUpdateHandler}
entityFieldTaskCount={entityFieldTaskCount}
entityFieldThreadCount={entityFieldThreadCount}
entityLineage={entityLineage}
entityLineageHandler={entityLineageHandler}
entityName={displayName}
entityThread={entityThread}
feedCount={feedCount}
fetchFeedHandler={handleFeedFetchFromFeedList}
followPipelineHandler={followPipeline}
followers={followers}
isLineageLoading={isLineageLoading}
isNodeLoading={isNodeLoading}
isentityThreadLoading={isentityThreadLoading}
lineageLeafNodes={leafNodes}
loadNodeHandler={loadNodeHandler}
owner={owner as EntityReference}
paging={paging}
pipelineDetails={pipelineDetails}
pipelineFQN={pipelineFQN}
pipelineStatus={pipeLineStatus}
pipelineTags={tags}
pipelineUrl={pipelineUrl}
postFeedHandler={postFeedHandler}
removeLineageHandler={removeLineageHandler}
serviceType={serviceType}
setActiveTabHandler={activeTabHandler}
settingsUpdateHandler={settingsUpdateHandler}
slashedPipelineName={slashedPipelineName}
tagUpdateHandler={onTagUpdate}
taskUpdateHandler={onTaskUpdate}
tasks={tasks}
tier={tier as TagLabel}
unfollowPipelineHandler={unfollowPipeline}
updateThreadHandler={updateThreadHandler}
version={currentVersion as string}
versionHandler={versionHandler}
onExtensionUpdate={handleExtentionUpdate}
/>
<>
{pipelinePermissions.ViewAll ? (
<PipelineDetails
activeTab={activeTab}
addLineageHandler={addLineageHandler}
createThread={createThread}
deletePostHandler={deletePostHandler}
deleted={deleted}
description={description}
descriptionUpdateHandler={descriptionUpdateHandler}
entityFieldTaskCount={entityFieldTaskCount}
entityFieldThreadCount={entityFieldThreadCount}
entityLineage={entityLineage}
entityLineageHandler={entityLineageHandler}
entityName={displayName}
entityThread={entityThread}
feedCount={feedCount}
fetchFeedHandler={handleFeedFetchFromFeedList}
followPipelineHandler={followPipeline}
followers={followers}
isLineageLoading={isLineageLoading}
isNodeLoading={isNodeLoading}
isentityThreadLoading={isentityThreadLoading}
lineageLeafNodes={leafNodes}
loadNodeHandler={loadNodeHandler}
owner={owner as EntityReference}
paging={paging}
pipelineDetails={pipelineDetails}
pipelineFQN={pipelineFQN}
pipelineStatus={pipeLineStatus}
pipelineTags={tags}
pipelineUrl={pipelineUrl}
postFeedHandler={postFeedHandler}
removeLineageHandler={removeLineageHandler}
serviceType={serviceType}
setActiveTabHandler={activeTabHandler}
settingsUpdateHandler={settingsUpdateHandler}
slashedPipelineName={slashedPipelineName}
tagUpdateHandler={onTagUpdate}
taskUpdateHandler={onTaskUpdate}
tasks={tasks}
tier={tier as TagLabel}
unfollowPipelineHandler={unfollowPipeline}
updateThreadHandler={updateThreadHandler}
version={currentVersion as string}
versionHandler={versionHandler}
onExtensionUpdate={handleExtentionUpdate}
/>
) : (
<ErrorPlaceHolder>{NO_PERMISSION_TO_VIEW}</ErrorPlaceHolder>
)}
</>
)}
</>
);

View File

@ -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(<PipelineDetailsPage />, {

View File

@ -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<string, string>;
const [topicDetails, setTopicDetails] = useState<Topic>({} as Topic);
@ -133,6 +141,10 @@ const TopicDetailsPage: FunctionComponent = () => {
});
const [isLineageLoading, setIsLineageLoading] = useState<boolean>(false);
const [topicPermissions, setTopicPermissions] = useState<OperationPermission>(
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)}
</ErrorPlaceHolder>
) : (
<TopicDetails
activeTab={activeTab}
cleanupPolicies={cleanupPolicies}
createThread={createThread}
deletePostHandler={deletePostHandler}
deleted={deleted}
description={description}
descriptionUpdateHandler={descriptionUpdateHandler}
entityFieldTaskCount={entityFieldTaskCount}
entityFieldThreadCount={entityFieldThreadCount}
entityName={name}
entityThread={entityThread}
feedCount={feedCount}
fetchFeedHandler={handleFeedFetchFromFeedList}
followTopicHandler={followTopic}
followers={followers}
isSampleDataLoading={isSampleDataLoading}
isentityThreadLoading={isentityThreadLoading}
lineageTabData={{
loadNodeHandler,
addLineageHandler,
removeLineageHandler,
entityLineageHandler,
isLineageLoading,
entityLineage,
lineageLeafNodes: leafNodes,
isNodeLoading,
}}
maximumMessageSize={maximumMessageSize}
owner={owner as EntityReference}
paging={paging}
partitions={partitions}
postFeedHandler={postFeedHandler}
replicationFactor={replicationFactor}
retentionSize={retentionSize}
sampleData={sampleData}
schemaText={schemaText}
schemaType={schemaType}
setActiveTabHandler={activeTabHandler}
settingsUpdateHandler={settingsUpdateHandler}
slashedTopicName={slashedTopicName}
tagUpdateHandler={onTagUpdate}
tier={tier as TagLabel}
topicDetails={topicDetails}
topicFQN={topicFQN}
topicTags={tags}
unfollowTopicHandler={unfollowTopic}
updateThreadHandler={updateThreadHandler}
version={currentVersion}
versionHandler={versionHandler}
onExtensionUpdate={handleExtentionUpdate}
/>
<>
{topicPermissions.ViewAll ? (
<TopicDetails
activeTab={activeTab}
cleanupPolicies={cleanupPolicies}
createThread={createThread}
deletePostHandler={deletePostHandler}
deleted={deleted}
description={description}
descriptionUpdateHandler={descriptionUpdateHandler}
entityFieldTaskCount={entityFieldTaskCount}
entityFieldThreadCount={entityFieldThreadCount}
entityName={name}
entityThread={entityThread}
feedCount={feedCount}
fetchFeedHandler={handleFeedFetchFromFeedList}
followTopicHandler={followTopic}
followers={followers}
isSampleDataLoading={isSampleDataLoading}
isentityThreadLoading={isentityThreadLoading}
lineageTabData={{
loadNodeHandler,
addLineageHandler,
removeLineageHandler,
entityLineageHandler,
isLineageLoading,
entityLineage,
lineageLeafNodes: leafNodes,
isNodeLoading,
}}
maximumMessageSize={maximumMessageSize}
owner={owner as EntityReference}
paging={paging}
partitions={partitions}
postFeedHandler={postFeedHandler}
replicationFactor={replicationFactor}
retentionSize={retentionSize}
sampleData={sampleData}
schemaText={schemaText}
schemaType={schemaType}
setActiveTabHandler={activeTabHandler}
settingsUpdateHandler={settingsUpdateHandler}
slashedTopicName={slashedTopicName}
tagUpdateHandler={onTagUpdate}
tier={tier as TagLabel}
topicDetails={topicDetails}
topicFQN={topicFQN}
topicTags={tags}
unfollowTopicHandler={unfollowTopic}
updateThreadHandler={updateThreadHandler}
version={currentVersion}
versionHandler={versionHandler}
onExtensionUpdate={handleExtentionUpdate}
/>
) : (
<ErrorPlaceHolder>{NO_PERMISSION_TO_VIEW}</ErrorPlaceHolder>
)}
</>
)}
</>
);

View File

@ -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(<TopicDetailsPageComponent />, {