ui: fix permission related bugs (#12160)

* fixed permissions related bugs for entity details pages

* permission related bug fixes for version pages

* changes to revert tab visibility for no permission

* fixed console errors

* fixed unit tests
This commit is contained in:
Aniket Katkar 2023-06-28 11:44:47 +05:30 committed by GitHub
parent d41c08df36
commit 9257065d69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 688 additions and 742 deletions

View File

@ -16,11 +16,13 @@ import classNames from 'classnames';
import { CustomPropertyTable } from 'components/common/CustomPropertyTable/CustomPropertyTable'; import { CustomPropertyTable } from 'components/common/CustomPropertyTable/CustomPropertyTable';
import { CustomPropertyProps } from 'components/common/CustomPropertyTable/CustomPropertyTable.interface'; import { CustomPropertyProps } from 'components/common/CustomPropertyTable/CustomPropertyTable.interface';
import DescriptionV1 from 'components/common/description/DescriptionV1'; import DescriptionV1 from 'components/common/description/DescriptionV1';
import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder';
import DataAssetsVersionHeader from 'components/DataAssets/DataAssetsVersionHeader/DataAssetsVersionHeader'; import DataAssetsVersionHeader from 'components/DataAssets/DataAssetsVersionHeader/DataAssetsVersionHeader';
import TabsLabel from 'components/TabsLabel/TabsLabel.component'; import TabsLabel from 'components/TabsLabel/TabsLabel.component';
import TagsContainerV1 from 'components/Tag/TagsContainerV1/TagsContainerV1'; import TagsContainerV1 from 'components/Tag/TagsContainerV1/TagsContainerV1';
import { getVersionPathWithTab } from 'constants/constants'; import { getVersionPathWithTab } from 'constants/constants';
import { EntityField } from 'constants/Feeds.constants'; import { EntityField } from 'constants/Feeds.constants';
import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum';
import { import {
ChangeDescription, ChangeDescription,
Column, Column,
@ -57,6 +59,7 @@ const ContainerVersion: React.FC<ContainerVersionProp> = ({
deleted = false, deleted = false,
backHandler, backHandler,
versionHandler, versionHandler,
entityPermissions,
}: ContainerVersionProp) => { }: ContainerVersionProp) => {
const { t } = useTranslation(); const { t } = useTranslation();
const history = useHistory(); const history = useHistory();
@ -174,7 +177,9 @@ const ContainerVersion: React.FC<ContainerVersionProp> = ({
name={t('label.custom-property-plural')} name={t('label.custom-property-plural')}
/> />
), ),
children: ( children: !entityPermissions.ViewAll ? (
<ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />
) : (
<CustomPropertyTable <CustomPropertyTable
isVersionView isVersionView
entityDetails={ entityDetails={
@ -186,9 +191,13 @@ const ContainerVersion: React.FC<ContainerVersionProp> = ({
), ),
}, },
], ],
[description, containerFQN, columns, currentVersionData] [description, containerFQN, columns, currentVersionData, entityPermissions]
); );
if (!(entityPermissions.ViewAll || entityPermissions.ViewBasic)) {
return <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />;
}
return ( return (
<> <>
{isVersionLoading ? ( {isVersionLoading ? (

View File

@ -10,6 +10,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { OperationPermission } from 'components/PermissionProvider/PermissionProvider.interface';
import { Container } from 'generated/entity/data/container'; import { Container } from 'generated/entity/data/container';
import { VersionData } from 'pages/EntityVersionPage/EntityVersionPage.component'; import { VersionData } from 'pages/EntityVersionPage/EntityVersionPage.component';
import { EntityHistory } from '../../generated/type/entityHistory'; import { EntityHistory } from '../../generated/type/entityHistory';
@ -28,4 +29,5 @@ export interface ContainerVersionProp {
deleted?: boolean; deleted?: boolean;
backHandler: () => void; backHandler: () => void;
versionHandler: (v: string) => void; versionHandler: (v: string) => void;
entityPermissions: OperationPermission;
} }

View File

@ -18,11 +18,13 @@ import classNames from 'classnames';
import { CustomPropertyTable } from 'components/common/CustomPropertyTable/CustomPropertyTable'; import { CustomPropertyTable } from 'components/common/CustomPropertyTable/CustomPropertyTable';
import { CustomPropertyProps } from 'components/common/CustomPropertyTable/CustomPropertyTable.interface'; import { CustomPropertyProps } from 'components/common/CustomPropertyTable/CustomPropertyTable.interface';
import DescriptionV1 from 'components/common/description/DescriptionV1'; import DescriptionV1 from 'components/common/description/DescriptionV1';
import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder';
import DataAssetsVersionHeader from 'components/DataAssets/DataAssetsVersionHeader/DataAssetsVersionHeader'; import DataAssetsVersionHeader from 'components/DataAssets/DataAssetsVersionHeader/DataAssetsVersionHeader';
import TabsLabel from 'components/TabsLabel/TabsLabel.component'; import TabsLabel from 'components/TabsLabel/TabsLabel.component';
import TagsContainerV1 from 'components/Tag/TagsContainerV1/TagsContainerV1'; import TagsContainerV1 from 'components/Tag/TagsContainerV1/TagsContainerV1';
import { getVersionPathWithTab } from 'constants/constants'; import { getVersionPathWithTab } from 'constants/constants';
import { EntityField } from 'constants/Feeds.constants'; import { EntityField } from 'constants/Feeds.constants';
import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum';
import { EntityTabs, EntityType } from 'enums/entity.enum'; import { EntityTabs, EntityType } from 'enums/entity.enum';
import { TagSource } from 'generated/type/tagLabel'; import { TagSource } from 'generated/type/tagLabel';
import React, { FC, useEffect, useMemo, useState } from 'react'; import React, { FC, useEffect, useMemo, useState } from 'react';
@ -55,6 +57,7 @@ const DashboardVersion: FC<DashboardVersionProp> = ({
deleted = false, deleted = false,
backHandler, backHandler,
versionHandler, versionHandler,
entityPermissions,
}: DashboardVersionProp) => { }: DashboardVersionProp) => {
const { t } = useTranslation(); const { t } = useTranslation();
const history = useHistory(); const history = useHistory();
@ -216,7 +219,9 @@ const DashboardVersion: FC<DashboardVersionProp> = ({
name={t('label.custom-property-plural')} name={t('label.custom-property-plural')}
/> />
), ),
children: ( children: !entityPermissions.ViewAll ? (
<ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />
) : (
<CustomPropertyTable <CustomPropertyTable
isVersionView isVersionView
entityDetails={ entityDetails={
@ -228,9 +233,13 @@ const DashboardVersion: FC<DashboardVersionProp> = ({
), ),
}, },
], ],
[description, tableColumn, currentVersionData] [description, tableColumn, currentVersionData, entityPermissions]
); );
if (!(entityPermissions.ViewAll || entityPermissions.ViewBasic)) {
return <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />;
}
return ( return (
<> <>
<div data-testid="dashboard-version-container"> <div data-testid="dashboard-version-container">

View File

@ -11,6 +11,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { OperationPermission } from 'components/PermissionProvider/PermissionProvider.interface';
import { VersionData } from 'pages/EntityVersionPage/EntityVersionPage.component'; import { VersionData } from 'pages/EntityVersionPage/EntityVersionPage.component';
import { Dashboard } from '../../generated/entity/data/dashboard'; import { Dashboard } from '../../generated/entity/data/dashboard';
import { EntityHistory } from '../../generated/type/entityHistory'; import { EntityHistory } from '../../generated/type/entityHistory';
@ -29,4 +30,5 @@ export interface DashboardVersionProp {
deleted?: boolean; deleted?: boolean;
backHandler: () => void; backHandler: () => void;
versionHandler: (v: string) => void; versionHandler: (v: string) => void;
entityPermissions: OperationPermission;
} }

View File

@ -103,6 +103,7 @@ export const dashboardVersionProps = {
], ],
}, },
deleted: false, deleted: false,
entityPermissions: { ViewAll: true },
} as unknown as DashboardVersionProp; } as unknown as DashboardVersionProp;
export const mockTagChangeVersion = { export const mockTagChangeVersion = {

View File

@ -33,7 +33,6 @@ import EntityHeaderTitle from 'components/Entity/EntityHeaderTitle/EntityHeaderT
import { useTourProvider } from 'components/TourProvider/TourProvider'; import { useTourProvider } from 'components/TourProvider/TourProvider';
import { FQN_SEPARATOR_CHAR } from 'constants/char.constants'; import { FQN_SEPARATOR_CHAR } from 'constants/char.constants';
import { DE_ACTIVE_COLOR, getDashboardDetailsPath } from 'constants/constants'; import { DE_ACTIVE_COLOR, getDashboardDetailsPath } from 'constants/constants';
import { NO_PERMISSION_FOR_ACTION } from 'constants/HelperTextUtil';
import { EntityTabs, EntityType } from 'enums/entity.enum'; import { EntityTabs, EntityType } from 'enums/entity.enum';
import { Container } from 'generated/entity/data/container'; import { Container } from 'generated/entity/data/container';
import { Dashboard } from 'generated/entity/data/dashboard'; import { Dashboard } from 'generated/entity/data/dashboard';
@ -48,9 +47,9 @@ import {
ThreadType, ThreadType,
} from 'generated/entity/feed/thread'; } from 'generated/entity/feed/thread';
import { useClipboard } from 'hooks/useClipBoard'; import { useClipboard } from 'hooks/useClipBoard';
import { t } from 'i18next';
import { isEmpty, isUndefined } from 'lodash'; import { isEmpty, isUndefined } from 'lodash';
import React, { useEffect, useMemo, useState } from 'react'; import React, { useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { getActiveAnnouncement, getFeedCount } from 'rest/feedsAPI'; import { getActiveAnnouncement, getFeedCount } from 'rest/feedsAPI';
import { getCurrentUserId, getEntityDetailLink } from 'utils/CommonUtils'; import { getCurrentUserId, getEntityDetailLink } from 'utils/CommonUtils';
@ -120,6 +119,7 @@ export const DataAssetsHeader = ({
onDisplayNameUpdate, onDisplayNameUpdate,
}: DataAssetsHeaderProps) => { }: DataAssetsHeaderProps) => {
const USERId = getCurrentUserId(); const USERId = getCurrentUserId();
const { t } = useTranslation();
const { isTourPage } = useTourProvider(); const { isTourPage } = useTourProvider();
const { onCopyToClipBoard } = useClipboard(window.location.href); const { onCopyToClipBoard } = useClipboard(window.location.href);
const [taskCount, setTaskCount] = useState(0); const [taskCount, setTaskCount] = useState(0);
@ -182,7 +182,7 @@ export const DataAssetsHeader = ({
}; };
useEffect(() => { useEffect(() => {
if (!isTourPage) { if (dataAsset.fullyQualifiedName && !isTourPage) {
fetchActiveAnnouncement(); fetchActiveAnnouncement();
fetchTaskCount(); fetchTaskCount();
} }
@ -194,46 +194,6 @@ export const DataAssetsHeader = ({
breadcrumbs: [], breadcrumbs: [],
}; };
switch (entityType) { switch (entityType) {
default:
case EntityType.TABLE:
const tableDetails = dataAsset as Table;
returnData.extraInfo = (
<>
{tableDetails.tableType && (
<ExtraInfoLabel
label={t('label.type')}
value={tableDetails.tableType}
/>
)}
{tableDetails?.usageSummary && (
<ExtraInfoLabel
label={t('label.usage')}
value={getUsagePercentile(
tableDetails.usageSummary?.weeklyStats?.percentileRank || 0,
false
)}
/>
)}
{tableDetails?.profile?.columnCount && (
<ExtraInfoLabel
label={t('label.column-plural')}
value={tableDetails.profile?.columnCount}
/>
)}
{tableDetails?.profile?.rowCount && (
<ExtraInfoLabel
label={t('label.row-plural')}
value={tableDetails.profile?.rowCount}
/>
)}
</>
);
returnData.breadcrumbs = getBreadcrumbForTable(tableDetails);
break;
case EntityType.TOPIC: case EntityType.TOPIC:
const topicDetails = dataAsset as Topic; const topicDetails = dataAsset as Topic;
returnData.breadcrumbs = returnData.breadcrumbs =
@ -402,6 +362,46 @@ export const DataAssetsHeader = ({
getBreadcrumbForEntitiesWithServiceOnly(dataModelDetails); getBreadcrumbForEntitiesWithServiceOnly(dataModelDetails);
break; break;
case EntityType.TABLE:
default:
const tableDetails = dataAsset as Table;
returnData.extraInfo = (
<>
{tableDetails.tableType && (
<ExtraInfoLabel
label={t('label.type')}
value={tableDetails.tableType}
/>
)}
{tableDetails?.usageSummary && (
<ExtraInfoLabel
label={t('label.usage')}
value={getUsagePercentile(
tableDetails.usageSummary?.weeklyStats?.percentileRank || 0,
false
)}
/>
)}
{tableDetails?.profile?.columnCount && (
<ExtraInfoLabel
label={t('label.column-plural')}
value={tableDetails.profile?.columnCount}
/>
)}
{tableDetails?.profile?.rowCount && (
<ExtraInfoLabel
label={t('label.row-plural')}
value={tableDetails.profile?.rowCount}
/>
)}
</>
);
returnData.breadcrumbs = getBreadcrumbForTable(tableDetails);
break;
} }
return returnData; return returnData;
@ -467,13 +467,8 @@ export const DataAssetsHeader = ({
})} })}
</span> </span>
)} )}
<Tooltip
placement="topRight" {(permissions.EditAll || permissions.EditTags) && (
title={
permissions.EditAll || permissions.EditTags
? ''
: NO_PERMISSION_FOR_ACTION
}>
<Button <Button
className="flex-center p-0" className="flex-center p-0"
data-testid="edit-tier" data-testid="edit-tier"
@ -484,7 +479,7 @@ export const DataAssetsHeader = ({
size="small" size="small"
type="text" type="text"
/> />
</Tooltip> )}
</Space> </Space>
</TierCard> </TierCard>
{extraInfo} {extraInfo}
@ -565,8 +560,8 @@ export const DataAssetsHeader = ({
{isAnnouncementDrawerOpen && ( {isAnnouncementDrawerOpen && (
<AnnouncementDrawer <AnnouncementDrawer
createPermission={permissions?.EditAll} createPermission={permissions?.EditAll}
entityFQN={dataAsset.fullyQualifiedName || ''} entityFQN={dataAsset.fullyQualifiedName ?? ''}
entityName={entityName || ''} entityName={entityName ?? ''}
entityType={entityType} entityType={entityType}
open={isAnnouncementDrawerOpen} open={isAnnouncementDrawerOpen}
onClose={() => setIsAnnouncementDrawer(false)} onClose={() => setIsAnnouncementDrawer(false)}

View File

@ -14,10 +14,12 @@
import { Col, Row, Space, Tabs, TabsProps } from 'antd'; import { Col, Row, Space, Tabs, TabsProps } from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import DescriptionV1 from 'components/common/description/DescriptionV1'; import DescriptionV1 from 'components/common/description/DescriptionV1';
import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder';
import DataAssetsVersionHeader from 'components/DataAssets/DataAssetsVersionHeader/DataAssetsVersionHeader'; import DataAssetsVersionHeader from 'components/DataAssets/DataAssetsVersionHeader/DataAssetsVersionHeader';
import TabsLabel from 'components/TabsLabel/TabsLabel.component'; import TabsLabel from 'components/TabsLabel/TabsLabel.component';
import TagsContainerV1 from 'components/Tag/TagsContainerV1/TagsContainerV1'; import TagsContainerV1 from 'components/Tag/TagsContainerV1/TagsContainerV1';
import VersionTable from 'components/VersionTable/VersionTable.component'; import VersionTable from 'components/VersionTable/VersionTable.component';
import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum';
import { EntityTabs, EntityType, FqnPart } from 'enums/entity.enum'; import { EntityTabs, EntityType, FqnPart } from 'enums/entity.enum';
import { import {
ChangeDescription, ChangeDescription,
@ -62,6 +64,7 @@ const DataModelVersion: FC<DataModelVersionProp> = ({
backHandler, backHandler,
versionHandler, versionHandler,
dataModelFQN, dataModelFQN,
entityPermissions,
}: DataModelVersionProp) => { }: DataModelVersionProp) => {
const { t } = useTranslation(); const { t } = useTranslation();
const [changeDescription, setChangeDescription] = useState<ChangeDescription>( const [changeDescription, setChangeDescription] = useState<ChangeDescription>(
@ -318,6 +321,10 @@ const DataModelVersion: FC<DataModelVersionProp> = ({
[description, dataModelFQN, columns] [description, dataModelFQN, columns]
); );
if (!(entityPermissions.ViewAll || entityPermissions.ViewBasic)) {
return <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />;
}
return ( return (
<> <>
<div data-testid="data-model-version-container"> <div data-testid="data-model-version-container">

View File

@ -11,6 +11,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { OperationPermission } from 'components/PermissionProvider/PermissionProvider.interface';
import { DashboardDataModel } from 'generated/entity/data/dashboardDataModel'; import { DashboardDataModel } from 'generated/entity/data/dashboardDataModel';
import { VersionData } from 'pages/EntityVersionPage/EntityVersionPage.component'; import { VersionData } from 'pages/EntityVersionPage/EntityVersionPage.component';
import { EntityHistory } from '../../generated/type/entityHistory'; import { EntityHistory } from '../../generated/type/entityHistory';
@ -30,4 +31,5 @@ export interface DataModelVersionProp {
deleted?: boolean; deleted?: boolean;
backHandler: () => void; backHandler: () => void;
versionHandler: (v: string) => void; versionHandler: (v: string) => void;
entityPermissions: OperationPermission;
} }

View File

@ -16,11 +16,13 @@ import classNames from 'classnames';
import { CustomPropertyTable } from 'components/common/CustomPropertyTable/CustomPropertyTable'; import { CustomPropertyTable } from 'components/common/CustomPropertyTable/CustomPropertyTable';
import { CustomPropertyProps } from 'components/common/CustomPropertyTable/CustomPropertyTable.interface'; import { CustomPropertyProps } from 'components/common/CustomPropertyTable/CustomPropertyTable.interface';
import DescriptionV1 from 'components/common/description/DescriptionV1'; import DescriptionV1 from 'components/common/description/DescriptionV1';
import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder';
import DataAssetsVersionHeader from 'components/DataAssets/DataAssetsVersionHeader/DataAssetsVersionHeader'; import DataAssetsVersionHeader from 'components/DataAssets/DataAssetsVersionHeader/DataAssetsVersionHeader';
import TabsLabel from 'components/TabsLabel/TabsLabel.component'; import TabsLabel from 'components/TabsLabel/TabsLabel.component';
import TagsContainerV1 from 'components/Tag/TagsContainerV1/TagsContainerV1'; import TagsContainerV1 from 'components/Tag/TagsContainerV1/TagsContainerV1';
import { getVersionPathWithTab } from 'constants/constants'; import { getVersionPathWithTab } from 'constants/constants';
import { EntityField } from 'constants/Feeds.constants'; import { EntityField } from 'constants/Feeds.constants';
import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum';
import { TagSource } from 'generated/type/tagLabel'; import { TagSource } from 'generated/type/tagLabel';
import { cloneDeep, isUndefined, toString } from 'lodash'; import { cloneDeep, isUndefined, toString } from 'lodash';
import React, { useEffect, useMemo, useState } from 'react'; import React, { useEffect, useMemo, useState } from 'react';
@ -59,6 +61,7 @@ const DatasetVersion: React.FC<DatasetVersionProp> = ({
deleted = false, deleted = false,
backHandler, backHandler,
versionHandler, versionHandler,
entityPermissions,
}: DatasetVersionProp) => { }: DatasetVersionProp) => {
const { t } = useTranslation(); const { t } = useTranslation();
const history = useHistory(); const history = useHistory();
@ -194,7 +197,9 @@ const DatasetVersion: React.FC<DatasetVersionProp> = ({
name={t('label.custom-property-plural')} name={t('label.custom-property-plural')}
/> />
), ),
children: ( children: !entityPermissions.ViewAll ? (
<ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />
) : (
<CustomPropertyTable <CustomPropertyTable
isVersionView isVersionView
entityDetails={ entityDetails={
@ -212,9 +217,14 @@ const DatasetVersion: React.FC<DatasetVersionProp> = ({
columns, columns,
constraintUpdatedColumns, constraintUpdatedColumns,
currentVersionData, currentVersionData,
entityPermissions,
] ]
); );
if (!(entityPermissions.ViewAll || entityPermissions.ViewBasic)) {
return <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />;
}
return ( return (
<> <>
{isVersionLoading ? ( {isVersionLoading ? (

View File

@ -11,6 +11,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { OperationPermission } from 'components/PermissionProvider/PermissionProvider.interface';
import { VersionData } from 'pages/EntityVersionPage/EntityVersionPage.component'; import { VersionData } from 'pages/EntityVersionPage/EntityVersionPage.component';
import { Table } from '../../generated/entity/data/table'; import { Table } from '../../generated/entity/data/table';
import { EntityHistory } from '../../generated/type/entityHistory'; import { EntityHistory } from '../../generated/type/entityHistory';
@ -29,4 +30,5 @@ export interface DatasetVersionProp {
deleted?: boolean; deleted?: boolean;
backHandler: () => void; backHandler: () => void;
versionHandler: (v: string) => void; versionHandler: (v: string) => void;
entityPermissions: OperationPermission;
} }

View File

@ -11,16 +11,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { import { Button, Card, Col, Divider, Row, Space, Typography } from 'antd';
Button,
Card,
Col,
Divider,
Row,
Space,
Tooltip,
Typography,
} from 'antd';
import { ReactComponent as EditIcon } from 'assets/svg/edit-new.svg'; import { ReactComponent as EditIcon } from 'assets/svg/edit-new.svg';
import TableTags from 'components/TableTags/TableTags.component'; import TableTags from 'components/TableTags/TableTags.component';
import { TagSource } from 'generated/type/schema'; import { TagSource } from 'generated/type/schema';
@ -103,7 +94,7 @@ const MlModelFeaturesList = ({
} }
}; };
if (mlFeatures && mlFeatures.length) { if (!isEmpty(mlFeatures)) {
return ( return (
<Fragment> <Fragment>
<Row data-testid="feature-list"> <Row data-testid="feature-list">
@ -216,21 +207,10 @@ const MlModelFeaturesList = ({
})} })}
</Typography.Text> </Typography.Text>
)} )}
<Tooltip {(permissions.EditAll ||
title={ permissions.EditDescription) && (
permissions.EditAll ||
permissions.EditDescription
? t('label.edit')
: t('message.no-permission-for-action')
}>
<Button <Button
className="m-l-xxs no-border p-0 text-primary h-auto" className="m-l-xxs no-border p-0 text-primary h-auto"
disabled={
!(
permissions.EditAll ||
permissions.EditDescription
)
}
icon={<EditIcon width={16} />} icon={<EditIcon width={16} />}
type="text" type="text"
onClick={() => { onClick={() => {
@ -238,7 +218,7 @@ const MlModelFeaturesList = ({
setEditDescription(true); setEditDescription(true);
}} }}
/> />
</Tooltip> )}
</Space> </Space>
</Col> </Col>
</Row> </Row>

View File

@ -33,6 +33,7 @@ import TabsLabel from 'components/TabsLabel/TabsLabel.component';
import TagsContainerV1 from 'components/Tag/TagsContainerV1/TagsContainerV1'; import TagsContainerV1 from 'components/Tag/TagsContainerV1/TagsContainerV1';
import TagsViewer from 'components/Tag/TagsViewer/tags-viewer'; import TagsViewer from 'components/Tag/TagsViewer/tags-viewer';
import { getVersionPathWithTab } from 'constants/constants'; import { getVersionPathWithTab } from 'constants/constants';
import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum';
import { EntityTabs, EntityType } from 'enums/entity.enum'; import { EntityTabs, EntityType } from 'enums/entity.enum';
import { MlFeature, Mlmodel } from 'generated/entity/data/mlmodel'; import { MlFeature, Mlmodel } from 'generated/entity/data/mlmodel';
import { TagSource } from 'generated/type/tagLabel'; import { TagSource } from 'generated/type/tagLabel';
@ -71,6 +72,7 @@ const MlModelVersion: FC<MlModelVersionProp> = ({
deleted = false, deleted = false,
backHandler, backHandler,
versionHandler, versionHandler,
entityPermissions,
}: MlModelVersionProp) => { }: MlModelVersionProp) => {
const { t } = useTranslation(); const { t } = useTranslation();
const history = useHistory(); const history = useHistory();
@ -380,7 +382,9 @@ const MlModelVersion: FC<MlModelVersionProp> = ({
name={t('label.custom-property-plural')} name={t('label.custom-property-plural')}
/> />
), ),
children: ( children: !entityPermissions.ViewAll ? (
<ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />
) : (
<CustomPropertyTable <CustomPropertyTable
isVersionView isVersionView
entityDetails={ entityDetails={
@ -392,9 +396,13 @@ const MlModelVersion: FC<MlModelVersionProp> = ({
), ),
}, },
], ],
[description, mlFeaturesData, currentVersionData] [description, mlFeaturesData, currentVersionData, entityPermissions]
); );
if (!(entityPermissions.ViewAll || entityPermissions.ViewBasic)) {
return <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />;
}
return ( return (
<> <>
{isVersionLoading ? ( {isVersionLoading ? (

View File

@ -11,6 +11,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { OperationPermission } from 'components/PermissionProvider/PermissionProvider.interface';
import { Mlmodel } from 'generated/entity/data/mlmodel'; import { Mlmodel } from 'generated/entity/data/mlmodel';
import { VersionData } from 'pages/EntityVersionPage/EntityVersionPage.component'; import { VersionData } from 'pages/EntityVersionPage/EntityVersionPage.component';
import { EntityHistory } from '../../generated/type/entityHistory'; import { EntityHistory } from '../../generated/type/entityHistory';
@ -29,4 +30,5 @@ export interface MlModelVersionProp {
deleted?: boolean; deleted?: boolean;
backHandler: () => void; backHandler: () => void;
versionHandler: (v: string) => void; versionHandler: (v: string) => void;
entityPermissions: OperationPermission;
} }

View File

@ -18,12 +18,14 @@ import classNames from 'classnames';
import { CustomPropertyTable } from 'components/common/CustomPropertyTable/CustomPropertyTable'; import { CustomPropertyTable } from 'components/common/CustomPropertyTable/CustomPropertyTable';
import { CustomPropertyProps } from 'components/common/CustomPropertyTable/CustomPropertyTable.interface'; import { CustomPropertyProps } from 'components/common/CustomPropertyTable/CustomPropertyTable.interface';
import DescriptionV1 from 'components/common/description/DescriptionV1'; import DescriptionV1 from 'components/common/description/DescriptionV1';
import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder';
import DataAssetsVersionHeader from 'components/DataAssets/DataAssetsVersionHeader/DataAssetsVersionHeader'; import DataAssetsVersionHeader from 'components/DataAssets/DataAssetsVersionHeader/DataAssetsVersionHeader';
import TabsLabel from 'components/TabsLabel/TabsLabel.component'; import TabsLabel from 'components/TabsLabel/TabsLabel.component';
import TagsContainerV1 from 'components/Tag/TagsContainerV1/TagsContainerV1'; import TagsContainerV1 from 'components/Tag/TagsContainerV1/TagsContainerV1';
import TagsViewer from 'components/Tag/TagsViewer/tags-viewer'; import TagsViewer from 'components/Tag/TagsViewer/tags-viewer';
import { getVersionPathWithTab } from 'constants/constants'; import { getVersionPathWithTab } from 'constants/constants';
import { TABLE_SCROLL_VALUE } from 'constants/Table.constants'; import { TABLE_SCROLL_VALUE } from 'constants/Table.constants';
import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum';
import { EntityTabs, EntityType } from 'enums/entity.enum'; import { EntityTabs, EntityType } from 'enums/entity.enum';
import { TagSource } from 'generated/type/schema'; import { TagSource } from 'generated/type/schema';
import { t } from 'i18next'; import { t } from 'i18next';
@ -69,6 +71,7 @@ const PipelineVersion: FC<PipelineVersionProp> = ({
deleted = false, deleted = false,
backHandler, backHandler,
versionHandler, versionHandler,
entityPermissions,
}: PipelineVersionProp) => { }: PipelineVersionProp) => {
const history = useHistory(); const history = useHistory();
const { tab } = useParams<{ tab: EntityTabs }>(); const { tab } = useParams<{ tab: EntityTabs }>();
@ -400,7 +403,9 @@ const PipelineVersion: FC<PipelineVersionProp> = ({
name={t('label.custom-property-plural')} name={t('label.custom-property-plural')}
/> />
), ),
children: ( children: !entityPermissions.ViewAll ? (
<ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />
) : (
<CustomPropertyTable <CustomPropertyTable
isVersionView isVersionView
entityDetails={ entityDetails={
@ -412,9 +417,19 @@ const PipelineVersion: FC<PipelineVersionProp> = ({
), ),
}, },
], ],
[description, tableColumn, pipelineVersionTableData, currentVersionData] [
description,
tableColumn,
pipelineVersionTableData,
currentVersionData,
entityPermissions,
]
); );
if (!(entityPermissions.ViewAll || entityPermissions.ViewBasic)) {
return <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />;
}
return ( return (
<> <>
{isVersionLoading ? ( {isVersionLoading ? (

View File

@ -11,6 +11,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { OperationPermission } from 'components/PermissionProvider/PermissionProvider.interface';
import { VersionData } from 'pages/EntityVersionPage/EntityVersionPage.component'; import { VersionData } from 'pages/EntityVersionPage/EntityVersionPage.component';
import { Pipeline } from '../../generated/entity/data/pipeline'; import { Pipeline } from '../../generated/entity/data/pipeline';
import { EntityHistory } from '../../generated/type/entityHistory'; import { EntityHistory } from '../../generated/type/entityHistory';
@ -29,4 +30,5 @@ export interface PipelineVersionProp {
deleted?: boolean; deleted?: boolean;
backHandler: () => void; backHandler: () => void;
versionHandler: (v: string) => void; versionHandler: (v: string) => void;
entityPermissions: OperationPermission;
} }

View File

@ -18,12 +18,14 @@ import ActivityFeedProvider, {
} from 'components/ActivityFeed/ActivityFeedProvider/ActivityFeedProvider'; } from 'components/ActivityFeed/ActivityFeedProvider/ActivityFeedProvider';
import { ActivityFeedTab } from 'components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.component'; import { ActivityFeedTab } from 'components/ActivityFeed/ActivityFeedTab/ActivityFeedTab.component';
import DescriptionV1 from 'components/common/description/DescriptionV1'; import DescriptionV1 from 'components/common/description/DescriptionV1';
import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder';
import PageLayoutV1 from 'components/containers/PageLayoutV1'; import PageLayoutV1 from 'components/containers/PageLayoutV1';
import { DataAssetsHeader } from 'components/DataAssets/DataAssetsHeader/DataAssetsHeader.component'; import { DataAssetsHeader } from 'components/DataAssets/DataAssetsHeader/DataAssetsHeader.component';
import { EntityName } from 'components/Modals/EntityNameModal/EntityNameModal.interface'; import { EntityName } from 'components/Modals/EntityNameModal/EntityNameModal.interface';
import TabsLabel from 'components/TabsLabel/TabsLabel.component'; import TabsLabel from 'components/TabsLabel/TabsLabel.component';
import TagsContainerV2 from 'components/Tag/TagsContainerV2/TagsContainerV2'; import TagsContainerV2 from 'components/Tag/TagsContainerV2/TagsContainerV2';
import { getTopicDetailsPath } from 'constants/constants'; import { getTopicDetailsPath } from 'constants/constants';
import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum';
import { TagLabel } from 'generated/type/schema'; import { TagLabel } from 'generated/type/schema';
import { EntityFieldThreadCount } from 'interface/feed.interface'; import { EntityFieldThreadCount } from 'interface/feed.interface';
import { EntityTags } from 'Models'; import { EntityTags } from 'Models';
@ -43,18 +45,12 @@ import {
refreshPage, refreshPage,
} from '../../utils/CommonUtils'; } from '../../utils/CommonUtils';
import { getEntityFieldThreadCounts } from '../../utils/FeedUtils'; import { getEntityFieldThreadCounts } from '../../utils/FeedUtils';
import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils';
import { getTagsWithoutTier, getTierTags } from '../../utils/TableUtils'; import { getTagsWithoutTier, getTierTags } from '../../utils/TableUtils';
import { showErrorToast, showSuccessToast } from '../../utils/ToastUtils'; import { showErrorToast, showSuccessToast } from '../../utils/ToastUtils';
import ActivityThreadPanel from '../ActivityFeed/ActivityThreadPanel/ActivityThreadPanel'; import ActivityThreadPanel from '../ActivityFeed/ActivityThreadPanel/ActivityThreadPanel';
import { CustomPropertyTable } from '../common/CustomPropertyTable/CustomPropertyTable'; import { CustomPropertyTable } from '../common/CustomPropertyTable/CustomPropertyTable';
import { CustomPropertyProps } from '../common/CustomPropertyTable/CustomPropertyTable.interface'; import { CustomPropertyProps } from '../common/CustomPropertyTable/CustomPropertyTable.interface';
import EntityLineageComponent from '../EntityLineage/EntityLineage.component'; import EntityLineageComponent from '../EntityLineage/EntityLineage.component';
import { usePermissionProvider } from '../PermissionProvider/PermissionProvider';
import {
OperationPermission,
ResourceEntity,
} from '../PermissionProvider/PermissionProvider.interface';
import SampleDataTopic from '../SampleDataTopic/SampleDataTopic'; import SampleDataTopic from '../SampleDataTopic/SampleDataTopic';
import SchemaEditor from '../schema-editor/SchemaEditor'; import SchemaEditor from '../schema-editor/SchemaEditor';
import { TopicDetailsProps } from './TopicDetails.interface'; import { TopicDetailsProps } from './TopicDetails.interface';
@ -66,8 +62,8 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
unFollowTopicHandler, unFollowTopicHandler,
versionHandler, versionHandler,
createThread, createThread,
onTopicUpdate, onTopicUpdate,
topicPermissions,
}: TopicDetailsProps) => { }: TopicDetailsProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { postFeed, deleteFeed, updateFeed } = useActivityFeedProvider(); const { postFeed, deleteFeed, updateFeed } = useActivityFeedProvider();
@ -88,11 +84,6 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
ThreadType.Conversation ThreadType.Conversation
); );
const [topicPermissions, setTopicPermissions] = useState<OperationPermission>(
DEFAULT_ENTITY_PERMISSION
);
const { getEntityPermission } = usePermissionProvider();
const { const {
owner, owner,
description, description,
@ -116,26 +107,6 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
}; };
}, [followers]); }, [followers]);
const fetchResourcePermission = useCallback(async () => {
try {
const permissions = await getEntityPermission(
ResourceEntity.TOPIC,
topicDetails.id
);
setTopicPermissions(permissions);
} catch (error) {
showErrorToast(
t('server.fetch-entity-permissions-error', { entity: t('label.topic') })
);
}
}, [topicDetails.id, getEntityPermission, setTopicPermissions]);
useEffect(() => {
if (topicDetails.id) {
fetchResourcePermission();
}
}, [topicDetails.id]);
const followTopic = async () => { const followTopic = async () => {
isFollowing ? await unFollowTopicHandler() : await followTopicHandler(); isFollowing ? await unFollowTopicHandler() : await followTopicHandler();
}; };
@ -400,7 +371,13 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
/> />
), ),
key: EntityTabs.SAMPLE_DATA, key: EntityTabs.SAMPLE_DATA,
children: <SampleDataTopic topicId={topicDetails.id} />, children: !(
topicPermissions.ViewAll || topicPermissions.ViewSampleData
) ? (
<ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />
) : (
<SampleDataTopic topicId={topicDetails.id} />
),
}, },
{ {
label: <TabsLabel id={EntityTabs.CONFIG} name={t('label.config')} />, label: <TabsLabel id={EntityTabs.CONFIG} name={t('label.config')} />,
@ -452,6 +429,7 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
), ),
}, },
], ],
[ [
activeTab, activeTab,
feedCount, feedCount,
@ -462,15 +440,10 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
isEdit, isEdit,
entityName, entityName,
topicFQN, topicFQN,
topicPermissions,
] ]
); );
useEffect(() => {
if (topicDetails.id) {
fetchResourcePermission();
}
}, [topicDetails.id]);
return ( return (
<PageLayoutV1 <PageLayoutV1
className="bg-white" className="bg-white"

View File

@ -11,12 +11,14 @@
* limitations under the License. * limitations under the License.
*/ */
import { OperationPermission } from 'components/PermissionProvider/PermissionProvider.interface';
import { CreateThread } from '../../generated/api/feed/createThread'; import { CreateThread } from '../../generated/api/feed/createThread';
import { CleanupPolicy, Topic } from '../../generated/entity/data/topic'; import { CleanupPolicy, Topic } from '../../generated/entity/data/topic';
import { SchemaType } from '../../generated/type/schema'; import { SchemaType } from '../../generated/type/schema';
export interface TopicDetailsProps { export interface TopicDetailsProps {
topicDetails: Topic; topicDetails: Topic;
topicPermissions: OperationPermission;
createThread: (data: CreateThread) => void; createThread: (data: CreateThread) => void;
followTopicHandler: () => Promise<void>; followTopicHandler: () => Promise<void>;
unFollowTopicHandler: () => Promise<void>; unFollowTopicHandler: () => Promise<void>;

View File

@ -20,6 +20,7 @@ import {
import { EntityTabs } from 'enums/entity.enum'; import { EntityTabs } from 'enums/entity.enum';
import React from 'react'; import React from 'react';
import { MemoryRouter } from 'react-router-dom'; import { MemoryRouter } from 'react-router-dom';
import { DEFAULT_ENTITY_PERMISSION } from 'utils/PermissionsUtils';
import TopicDetails from './TopicDetails.component'; import TopicDetails from './TopicDetails.component';
import { TopicDetailsProps } from './TopicDetails.interface'; import { TopicDetailsProps } from './TopicDetails.interface';
import { TOPIC_DETAILS } from './TopicDetails.mock'; import { TOPIC_DETAILS } from './TopicDetails.mock';
@ -55,6 +56,7 @@ const topicDetailsProps: TopicDetailsProps = {
onTopicUpdate: jest.fn(), onTopicUpdate: jest.fn(),
versionHandler: jest.fn(), versionHandler: jest.fn(),
createThread: jest.fn(), createThread: jest.fn(),
topicPermissions: DEFAULT_ENTITY_PERMISSION,
}; };
const mockParams = { const mockParams = {

View File

@ -16,12 +16,14 @@ import classNames from 'classnames';
import { CustomPropertyTable } from 'components/common/CustomPropertyTable/CustomPropertyTable'; import { CustomPropertyTable } from 'components/common/CustomPropertyTable/CustomPropertyTable';
import { CustomPropertyProps } from 'components/common/CustomPropertyTable/CustomPropertyTable.interface'; import { CustomPropertyProps } from 'components/common/CustomPropertyTable/CustomPropertyTable.interface';
import DescriptionV1 from 'components/common/description/DescriptionV1'; import DescriptionV1 from 'components/common/description/DescriptionV1';
import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder';
import DataAssetsVersionHeader from 'components/DataAssets/DataAssetsVersionHeader/DataAssetsVersionHeader'; import DataAssetsVersionHeader from 'components/DataAssets/DataAssetsVersionHeader/DataAssetsVersionHeader';
import TabsLabel from 'components/TabsLabel/TabsLabel.component'; import TabsLabel from 'components/TabsLabel/TabsLabel.component';
import TagsContainerV1 from 'components/Tag/TagsContainerV1/TagsContainerV1'; import TagsContainerV1 from 'components/Tag/TagsContainerV1/TagsContainerV1';
import TopicSchemaFields from 'components/TopicDetails/TopicSchema/TopicSchema'; import TopicSchemaFields from 'components/TopicDetails/TopicSchema/TopicSchema';
import { getVersionPathWithTab } from 'constants/constants'; import { getVersionPathWithTab } from 'constants/constants';
import { EntityField } from 'constants/Feeds.constants'; import { EntityField } from 'constants/Feeds.constants';
import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum';
import { EntityTabs, EntityType } from 'enums/entity.enum'; import { EntityTabs, EntityType } from 'enums/entity.enum';
import { TagSource } from 'generated/type/tagLabel'; import { TagSource } from 'generated/type/tagLabel';
import React, { FC, useEffect, useMemo, useState } from 'react'; import React, { FC, useEffect, useMemo, useState } from 'react';
@ -49,6 +51,7 @@ const TopicVersion: FC<TopicVersionProp> = ({
deleted = false, deleted = false,
backHandler, backHandler,
versionHandler, versionHandler,
entityPermissions,
}: TopicVersionProp) => { }: TopicVersionProp) => {
const { t } = useTranslation(); const { t } = useTranslation();
const history = useHistory(); const history = useHistory();
@ -162,7 +165,9 @@ const TopicVersion: FC<TopicVersionProp> = ({
name={t('label.custom-property-plural')} name={t('label.custom-property-plural')}
/> />
), ),
children: ( children: !entityPermissions.ViewAll ? (
<ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />
) : (
<CustomPropertyTable <CustomPropertyTable
isVersionView isVersionView
entityDetails={ entityDetails={
@ -174,9 +179,13 @@ const TopicVersion: FC<TopicVersionProp> = ({
), ),
}, },
], ],
[description, messageSchemaDiff, currentVersionData] [description, messageSchemaDiff, currentVersionData, entityPermissions]
); );
if (!(entityPermissions.ViewAll || entityPermissions.ViewBasic)) {
return <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />;
}
return ( return (
<> <>
{isVersionLoading ? ( {isVersionLoading ? (

View File

@ -11,6 +11,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { OperationPermission } from 'components/PermissionProvider/PermissionProvider.interface';
import { VersionData } from 'pages/EntityVersionPage/EntityVersionPage.component'; import { VersionData } from 'pages/EntityVersionPage/EntityVersionPage.component';
import { Topic } from '../../generated/entity/data/topic'; import { Topic } from '../../generated/entity/data/topic';
import { EntityHistory } from '../../generated/type/entityHistory'; import { EntityHistory } from '../../generated/type/entityHistory';
@ -29,4 +30,5 @@ export interface TopicVersionProp {
deleted?: boolean; deleted?: boolean;
backHandler: () => void; backHandler: () => void;
versionHandler: (v: string) => void; versionHandler: (v: string) => void;
entityPermissions: OperationPermission;
} }

View File

@ -32,7 +32,7 @@ import {
} from 'rest/dashboardAPI'; } from 'rest/dashboardAPI';
import { postThread } from 'rest/feedsAPI'; import { postThread } from 'rest/feedsAPI';
import { getVersionPath } from '../../constants/constants'; import { getVersionPath } from '../../constants/constants';
import { EntityType } from '../../enums/entity.enum'; import { EntityType, TabSpecificField } from '../../enums/entity.enum';
import { CreateThread } from '../../generated/api/feed/createThread'; import { CreateThread } from '../../generated/api/feed/createThread';
import { Chart } from '../../generated/entity/data/chart'; import { Chart } from '../../generated/entity/data/chart';
import { Dashboard } from '../../generated/entity/data/dashboard'; import { Dashboard } from '../../generated/entity/data/dashboard';
@ -101,6 +101,24 @@ const DashboardDetailsPage = () => {
return patchDashboardDetails(dashboardId, jsonPatch); return patchDashboardDetails(dashboardId, jsonPatch);
}; };
const fetchUsageSummaryDetails = async (dashboardFQN: string) => {
setLoading(true);
try {
const res = await getDashboardByFqn(
dashboardFQN,
TabSpecificField.USAGE_SUMMARY
);
const { usageSummary } = res;
setDashboardDetails((dashboard) => ({ ...dashboard, usageSummary }));
} catch (error) {
// Error here
} finally {
setLoading(false);
}
};
const fetchDashboardDetail = async (dashboardFQN: string) => { const fetchDashboardDetail = async (dashboardFQN: string) => {
setLoading(true); setLoading(true);
@ -276,6 +294,9 @@ const DashboardDetailsPage = () => {
if (dashboardPermissions.ViewAll || dashboardPermissions.ViewBasic) { if (dashboardPermissions.ViewAll || dashboardPermissions.ViewBasic) {
fetchDashboardDetail(dashboardFQN); fetchDashboardDetail(dashboardFQN);
} }
if (dashboardPermissions.ViewUsage) {
fetchUsageSummaryDetails(dashboardFQN);
}
}, [dashboardFQN, dashboardPermissions]); }, [dashboardFQN, dashboardPermissions]);
useEffect(() => { useEffect(() => {

View File

@ -11,7 +11,6 @@
* limitations under the License. * limitations under the License.
*/ */
import { AxiosError } from 'axios';
import { TitleBreadcrumbProps } from 'components/common/title-breadcrumb/title-breadcrumb.interface'; import { TitleBreadcrumbProps } from 'components/common/title-breadcrumb/title-breadcrumb.interface';
import ContainerVersion from 'components/ContainerVersion/ContainerVersion.component'; import ContainerVersion from 'components/ContainerVersion/ContainerVersion.component';
import DashboardVersion from 'components/DashboardVersion/DashboardVersion.component'; import DashboardVersion from 'components/DashboardVersion/DashboardVersion.component';
@ -24,7 +23,12 @@ import TopicVersion from 'components/TopicVersion/TopicVersion.component';
import { Container } from 'generated/entity/data/container'; import { Container } from 'generated/entity/data/container';
import { DashboardDataModel } from 'generated/entity/data/dashboardDataModel'; import { DashboardDataModel } from 'generated/entity/data/dashboardDataModel';
import { Mlmodel } from 'generated/entity/data/mlmodel'; import { Mlmodel } from 'generated/entity/data/mlmodel';
import React, { FunctionComponent, useEffect, useState } from 'react'; import React, {
FunctionComponent,
useCallback,
useEffect,
useState,
} from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { useHistory, useParams } from 'react-router-dom'; import { useHistory, useParams } from 'react-router-dom';
import { import {
@ -95,8 +99,14 @@ import { defaultFields as DataModelFields } from '../../utils/DataModelsUtils';
import { defaultFields as MlModelFields } from '../../utils/MlModelDetailsUtils'; import { defaultFields as MlModelFields } from '../../utils/MlModelDetailsUtils';
import PageLayoutV1 from 'components/containers/PageLayoutV1'; import PageLayoutV1 from 'components/containers/PageLayoutV1';
import { usePermissionProvider } from 'components/PermissionProvider/PermissionProvider';
import {
OperationPermission,
ResourceEntity,
} from 'components/PermissionProvider/PermissionProvider.interface';
import { isEmpty } from 'lodash';
import { DEFAULT_ENTITY_PERMISSION } from 'utils/PermissionsUtils';
import { getTierTags } from '../../utils/TableUtils'; import { getTierTags } from '../../utils/TableUtils';
import { showErrorToast } from '../../utils/ToastUtils';
import './EntityVersionPage.less'; import './EntityVersionPage.less';
export type VersionData = export type VersionData =
@ -123,7 +133,10 @@ const EntityVersionPage: FunctionComponent = () => {
const { entityType, version, entityFQN } = const { entityType, version, entityFQN } =
useParams<{ entityType: string; version: string; entityFQN: string }>(); useParams<{ entityType: string; version: string; entityFQN: string }>();
const [isLoading, setIsloading] = useState<boolean>(false); const { getEntityPermissionByFqn } = usePermissionProvider();
const [entityPermissions, setEntityPermissions] =
useState<OperationPermission>(DEFAULT_ENTITY_PERMISSION);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [versionList, setVersionList] = useState<EntityHistory>( const [versionList, setVersionList] = useState<EntityHistory>(
{} as EntityHistory {} as EntityHistory
); );
@ -193,244 +206,212 @@ const EntityVersionPage: FunctionComponent = () => {
setSlashedEntityName(titleBreadCrumb); setSlashedEntityName(titleBreadCrumb);
}; };
const fetchEntityVersions = async () => { const fetchResourcePermission = useCallback(
setIsloading(true); async (resourceEntity: ResourceEntity) => {
if (!isEmpty(currentVersionData)) {
try {
const permission = await getEntityPermissionByFqn(
resourceEntity,
currentVersionData.id ?? ''
);
setEntityPermissions(permission);
} catch (error) {
//
}
}
},
[currentVersionData.id, getEntityPermissionByFqn, setEntityPermissions]
);
const fetchEntityPermissions = async () => {
setIsLoading(true);
try {
switch (entityType) { switch (entityType) {
case EntityType.TABLE: { case EntityType.TABLE: {
getTableDetailsByFQN( fetchResourcePermission(ResourceEntity.TABLE);
getPartialNameFromTableFQN(
entityFQN,
[FqnPart.Service, FqnPart.Database, FqnPart.Schema, FqnPart.Table],
FQN_SEPARATOR_CHAR
),
['owner', 'tags']
)
.then((res) => {
const { id, owner, tags = [] } = res;
setEntityState(
tags,
owner,
res,
getEntityBreadcrumbs(res, EntityType.TABLE)
);
getTableVersions(id)
.then((vres) => {
setVersionList(vres);
setIsloading(false);
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: '',
})
);
});
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: '',
})
);
});
break; break;
} }
case EntityType.TOPIC: { case EntityType.TOPIC: {
getTopicByFqn( fetchResourcePermission(ResourceEntity.TOPIC);
break;
}
case EntityType.DASHBOARD: {
fetchResourcePermission(ResourceEntity.DASHBOARD);
break;
}
case EntityType.PIPELINE: {
fetchResourcePermission(ResourceEntity.PIPELINE);
break;
}
case EntityType.MLMODEL: {
fetchResourcePermission(ResourceEntity.ML_MODEL);
break;
}
case EntityType.CONTAINER: {
fetchResourcePermission(ResourceEntity.CONTAINER);
break;
}
case EntityType.DASHBOARD_DATA_MODEL: {
fetchResourcePermission(ResourceEntity.DASHBOARD_DATA_MODEL);
break;
}
default: {
break;
}
}
} finally {
setIsLoading(false);
}
};
const fetchEntityVersions = async () => {
setIsLoading(true);
try {
switch (entityType) {
case EntityType.TABLE: {
const response = await getTableDetailsByFQN(
getPartialNameFromTableFQN(
entityFQN,
[
FqnPart.Service,
FqnPart.Database,
FqnPart.Schema,
FqnPart.Table,
],
FQN_SEPARATOR_CHAR
),
['owner', 'tags']
);
const { id, owner, tags = [] } = response;
setEntityState(
tags,
owner,
response,
getEntityBreadcrumbs(response, EntityType.TABLE)
);
const versions = await getTableVersions(id);
setVersionList(versions);
break;
}
case EntityType.TOPIC: {
const response = await getTopicByFqn(
getPartialNameFromFQN( getPartialNameFromFQN(
entityFQN, entityFQN,
['service', 'database'], ['service', 'database'],
FQN_SEPARATOR_CHAR FQN_SEPARATOR_CHAR
), ),
[TabSpecificField.OWNER, TabSpecificField.TAGS] [TabSpecificField.OWNER, TabSpecificField.TAGS]
) );
.then((res) => {
const { id, owner, tags = [] } = res; const { id, owner, tags = [] } = response;
setEntityState( setEntityState(
tags, tags,
owner, owner,
res, response,
getEntityBreadcrumbs(res, EntityType.TOPIC) getEntityBreadcrumbs(response, EntityType.TOPIC)
); );
getTopicVersions(id) const versions = await getTopicVersions(id);
.then((vres) => {
setVersionList(vres); setVersionList(versions);
setIsloading(false);
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: '',
})
);
});
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: '',
})
);
});
break; break;
} }
case EntityType.DASHBOARD: { case EntityType.DASHBOARD: {
getDashboardByFqn( const response = await getDashboardByFqn(
getPartialNameFromFQN( getPartialNameFromFQN(
entityFQN, entityFQN,
['service', 'database'], ['service', 'database'],
FQN_SEPARATOR_CHAR FQN_SEPARATOR_CHAR
), ),
['owner', 'tags', 'charts'] ['owner', 'tags', 'charts']
) );
.then((res) => {
const { id, owner, tags = [] } = res; const { id, owner, tags = [] } = response;
setEntityState( setEntityState(
tags, tags,
owner, owner,
res, response,
getEntityBreadcrumbs(res, EntityType.DASHBOARD) getEntityBreadcrumbs(response, EntityType.DASHBOARD)
); );
getDashboardVersions(id) const versions = await getDashboardVersions(id);
.then((vres) => {
setVersionList(vres); setVersionList(versions);
setIsloading(false);
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: '',
})
);
});
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: '',
})
);
});
break; break;
} }
case EntityType.PIPELINE: { case EntityType.PIPELINE: {
getPipelineByFqn( const response = await getPipelineByFqn(
getPartialNameFromFQN( getPartialNameFromFQN(
entityFQN, entityFQN,
['service', 'database'], ['service', 'database'],
FQN_SEPARATOR_CHAR FQN_SEPARATOR_CHAR
), ),
['owner', 'tags', 'tasks'] ['owner', 'tags', 'tasks']
) );
.then((res) => {
const { id, owner, tags = [] } = res; const { id, owner, tags = [] } = response;
setEntityState( setEntityState(
tags, tags,
owner, owner,
res, response,
getEntityBreadcrumbs(res, EntityType.PIPELINE) getEntityBreadcrumbs(response, EntityType.PIPELINE)
); );
getPipelineVersions(id) const versions = await getPipelineVersions(id);
.then((vres) => {
setVersionList(vres); setVersionList(versions);
setIsloading(false);
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: '',
})
);
});
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: '',
})
);
});
break; break;
} }
case EntityType.MLMODEL: { case EntityType.MLMODEL: {
getMlModelByFQN( const response = await getMlModelByFQN(
getPartialNameFromFQN( getPartialNameFromFQN(
entityFQN, entityFQN,
['service', 'database'], ['service', 'database'],
FQN_SEPARATOR_CHAR FQN_SEPARATOR_CHAR
), ),
MlModelFields MlModelFields
) );
.then((res) => {
const { id, owner, tags = [] } = res; const { id, owner, tags = [] } = response;
setEntityState( setEntityState(
tags, tags,
owner, owner,
res, response,
getEntityBreadcrumbs(res, EntityType.MLMODEL) getEntityBreadcrumbs(response, EntityType.MLMODEL)
); );
getMlModelVersions(id) const versions = await getMlModelVersions(id);
.then((vres) => {
setVersionList(vres);
setIsloading(false);
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: '',
})
);
});
})
.catch((err: AxiosError) => { setVersionList(versions);
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: '',
})
);
});
break; break;
} }
case EntityType.CONTAINER: { case EntityType.CONTAINER: {
try {
const response = await getContainerByName( const response = await getContainerByName(
entityFQN, entityFQN,
@ -446,57 +427,28 @@ const EntityVersionPage: FunctionComponent = () => {
); );
const versions = await getContainerVersions(id); const versions = await getContainerVersions(id);
setVersionList(versions); setVersionList(versions);
} catch (err) {
showErrorToast(
err as AxiosError,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: '',
})
);
} finally {
setIsloading(false);
}
break; break;
} }
case EntityType.DASHBOARD_DATA_MODEL: { case EntityType.DASHBOARD_DATA_MODEL: {
getDataModelDetailsByFQN(entityFQN, DataModelFields) const response = await getDataModelDetailsByFQN(
.then((res) => { entityFQN,
const { id, owner, tags = [] } = res; DataModelFields
);
const { id, owner, tags = [] } = response;
setEntityState( setEntityState(
tags, tags,
owner, owner,
res, response,
getEntityBreadcrumbs(res, EntityType.DASHBOARD_DATA_MODEL) getEntityBreadcrumbs(response, EntityType.DASHBOARD_DATA_MODEL)
); );
getDataModelVersionsList(id ?? '') const versions = await getDataModelVersionsList(id ?? '');
.then((vres) => {
setVersionList(vres);
setIsloading(false);
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: '',
})
);
});
})
.catch((err: AxiosError) => { setVersionList(versions);
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: '',
})
);
});
break; break;
} }
@ -504,238 +456,139 @@ const EntityVersionPage: FunctionComponent = () => {
default: default:
break; break;
} }
} catch (err) {
// Error
} finally {
setIsLoading(false);
}
}; };
const fetchCurrentVersion = async () => { const fetchCurrentVersion = async () => {
setIsVersionLoading(true); setIsVersionLoading(true);
try {
switch (entityType) { switch (entityType) {
case EntityType.TABLE: { case EntityType.TABLE: {
getTableDetailsByFQN( const { id } = await getTableDetailsByFQN(
getPartialNameFromTableFQN( getPartialNameFromTableFQN(
entityFQN, entityFQN,
[FqnPart.Service, FqnPart.Database, FqnPart.Schema, FqnPart.Table], [
FqnPart.Service,
FqnPart.Database,
FqnPart.Schema,
FqnPart.Table,
],
FQN_SEPARATOR_CHAR FQN_SEPARATOR_CHAR
), ),
[] []
) );
.then((res) => {
const { id } = res; const currentVersion = await getTableVersion(id, version);
getTableVersion(id, version)
.then((vRes) => { const { owner, tags = [] } = currentVersion;
const { owner, tags } = vRes;
setEntityState( setEntityState(
tags, tags,
owner, owner,
vRes, currentVersion,
getEntityBreadcrumbs(vRes, EntityType.TABLE) getEntityBreadcrumbs(currentVersion, EntityType.TABLE)
); );
setIsVersionLoading(false);
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: version,
})
);
});
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: version,
})
);
});
break; break;
} }
case EntityType.TOPIC: { case EntityType.TOPIC: {
getTopicByFqn( const { id } = await getTopicByFqn(
getPartialNameFromFQN( getPartialNameFromFQN(
entityFQN, entityFQN,
['service', 'database'], ['service', 'database'],
FQN_SEPARATOR_CHAR FQN_SEPARATOR_CHAR
), ),
[] []
) );
.then((res) => {
const { id } = res; const currentVersion = await getTopicVersion(id, version);
getTopicVersion(id, version)
.then((vRes) => { const { owner, tags = [] } = currentVersion;
const { owner, tags = [] } = vRes;
setEntityState( setEntityState(
tags, tags,
owner, owner,
vRes, currentVersion,
getEntityBreadcrumbs(vRes, EntityType.TOPIC) getEntityBreadcrumbs(currentVersion, EntityType.TOPIC)
); );
setIsVersionLoading(false);
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: version,
})
);
});
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: version,
})
);
});
break; break;
} }
case EntityType.DASHBOARD: { case EntityType.DASHBOARD: {
getDashboardByFqn( const { id } = await getDashboardByFqn(
getPartialNameFromFQN( getPartialNameFromFQN(
entityFQN, entityFQN,
['service', 'database'], ['service', 'database'],
FQN_SEPARATOR_CHAR FQN_SEPARATOR_CHAR
), ),
[] []
) );
.then((res) => {
const { id } = res; const currentVersion = await getDashboardVersion(id, version);
getDashboardVersion(id, version)
.then((vRes) => { const { owner, tags = [] } = currentVersion;
const { owner, tags = [] } = vRes;
setEntityState( setEntityState(
tags, tags,
owner, owner,
vRes, currentVersion,
getEntityBreadcrumbs(vRes, EntityType.DASHBOARD) getEntityBreadcrumbs(currentVersion, EntityType.DASHBOARD)
); );
setIsVersionLoading(false);
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: version,
})
);
});
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: version,
})
);
});
break; break;
} }
case EntityType.PIPELINE: { case EntityType.PIPELINE: {
getPipelineByFqn( const { id } = await getPipelineByFqn(
getPartialNameFromFQN( getPartialNameFromFQN(
entityFQN, entityFQN,
['service', 'database'], ['service', 'database'],
FQN_SEPARATOR_CHAR FQN_SEPARATOR_CHAR
), ),
[] []
) );
.then((res) => {
const { id } = res; const currentVersion = await getPipelineVersion(id, version);
getPipelineVersion(id, version)
.then((vRes) => { const { owner, tags = [] } = currentVersion;
const { owner, tags = [] } = vRes;
setEntityState( setEntityState(
tags, tags,
owner, owner,
vRes, currentVersion,
getEntityBreadcrumbs(vRes, EntityType.PIPELINE) getEntityBreadcrumbs(currentVersion, EntityType.PIPELINE)
); );
setIsVersionLoading(false);
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: version,
})
);
});
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: version,
})
);
});
break; break;
} }
case EntityType.MLMODEL: { case EntityType.MLMODEL: {
getMlModelByFQN( const { id } = await getMlModelByFQN(
getPartialNameFromFQN( getPartialNameFromFQN(
entityFQN, entityFQN,
['service', 'database'], ['service', 'database'],
FQN_SEPARATOR_CHAR FQN_SEPARATOR_CHAR
), ),
MlModelFields MlModelFields
) );
.then((res) => {
const { id } = res; const currentVersion = await getMlModelVersion(id, version);
getMlModelVersion(id, version)
.then((vRes) => { const { owner, tags = [] } = currentVersion;
const { owner, tags = [] } = vRes;
setEntityState( setEntityState(
tags, tags,
owner, owner,
vRes, currentVersion,
getEntityBreadcrumbs(vRes, EntityType.MLMODEL) getEntityBreadcrumbs(currentVersion, EntityType.MLMODEL)
); );
setIsVersionLoading(false);
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: version,
})
);
});
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: version,
})
);
});
break; break;
} }
case EntityType.CONTAINER: { case EntityType.CONTAINER: {
try {
const response = await getContainerByName( const response = await getContainerByName(
entityFQN, entityFQN,
'dataModel,owner,tags' 'dataModel,owner,tags'
@ -750,56 +603,26 @@ const EntityVersionPage: FunctionComponent = () => {
currentVersion, currentVersion,
getEntityBreadcrumbs(currentVersion, EntityType.CONTAINER) getEntityBreadcrumbs(currentVersion, EntityType.CONTAINER)
); );
} catch (err) {
showErrorToast(
err as AxiosError,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: '',
})
);
} finally {
setIsVersionLoading(false);
}
break; break;
} }
case EntityType.DASHBOARD_DATA_MODEL: { case EntityType.DASHBOARD_DATA_MODEL: {
getDataModelDetailsByFQN(entityFQN, []) const { id } = await getDataModelDetailsByFQN(entityFQN, []);
.then((res) => {
const { id } = res; const currentVersion = await getDataModelVersion(id ?? '', version);
getDataModelVersion(id ?? '', version)
.then((vRes) => { const { owner, tags = [] } = currentVersion;
const { owner, tags = [] } = vRes;
setEntityState( setEntityState(
tags, tags,
owner, owner,
vRes, currentVersion,
getEntityBreadcrumbs(vRes, EntityType.DASHBOARD_DATA_MODEL) getEntityBreadcrumbs(
currentVersion,
EntityType.DASHBOARD_DATA_MODEL
)
); );
setIsVersionLoading(false);
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: version,
})
);
});
})
.catch((err: AxiosError) => {
showErrorToast(
err,
t('server.entity-fetch-version-error', {
entity: entityFQN,
version: version,
})
);
});
break; break;
} }
@ -807,6 +630,9 @@ const EntityVersionPage: FunctionComponent = () => {
default: default:
break; break;
} }
} finally {
setIsVersionLoading(false);
}
}; };
const versionComponent = () => { const versionComponent = () => {
@ -818,6 +644,7 @@ const EntityVersionPage: FunctionComponent = () => {
currentVersionData={currentVersionData} currentVersionData={currentVersionData}
datasetFQN={entityFQN} datasetFQN={entityFQN}
deleted={currentVersionData.deleted} deleted={currentVersionData.deleted}
entityPermissions={entityPermissions}
isVersionLoading={isVersionLoading} isVersionLoading={isVersionLoading}
owner={owner} owner={owner}
slashedTableName={slashedEntityName} slashedTableName={slashedEntityName}
@ -834,6 +661,7 @@ const EntityVersionPage: FunctionComponent = () => {
backHandler={backHandler} backHandler={backHandler}
currentVersionData={currentVersionData} currentVersionData={currentVersionData}
deleted={currentVersionData.deleted} deleted={currentVersionData.deleted}
entityPermissions={entityPermissions}
isVersionLoading={isVersionLoading} isVersionLoading={isVersionLoading}
owner={owner} owner={owner}
slashedTopicName={slashedEntityName} slashedTopicName={slashedEntityName}
@ -852,6 +680,7 @@ const EntityVersionPage: FunctionComponent = () => {
backHandler={backHandler} backHandler={backHandler}
currentVersionData={currentVersionData} currentVersionData={currentVersionData}
deleted={currentVersionData.deleted} deleted={currentVersionData.deleted}
entityPermissions={entityPermissions}
isVersionLoading={isVersionLoading} isVersionLoading={isVersionLoading}
owner={owner} owner={owner}
slashedDashboardName={slashedEntityName} slashedDashboardName={slashedEntityName}
@ -870,6 +699,7 @@ const EntityVersionPage: FunctionComponent = () => {
backHandler={backHandler} backHandler={backHandler}
currentVersionData={currentVersionData} currentVersionData={currentVersionData}
deleted={currentVersionData.deleted} deleted={currentVersionData.deleted}
entityPermissions={entityPermissions}
isVersionLoading={isVersionLoading} isVersionLoading={isVersionLoading}
owner={owner} owner={owner}
slashedPipelineName={slashedEntityName} slashedPipelineName={slashedEntityName}
@ -888,6 +718,7 @@ const EntityVersionPage: FunctionComponent = () => {
backHandler={backHandler} backHandler={backHandler}
currentVersionData={currentVersionData} currentVersionData={currentVersionData}
deleted={currentVersionData.deleted} deleted={currentVersionData.deleted}
entityPermissions={entityPermissions}
isVersionLoading={isVersionLoading} isVersionLoading={isVersionLoading}
owner={owner} owner={owner}
slashedMlModelName={slashedEntityName} slashedMlModelName={slashedEntityName}
@ -907,6 +738,7 @@ const EntityVersionPage: FunctionComponent = () => {
containerFQN={entityFQN} containerFQN={entityFQN}
currentVersionData={currentVersionData} currentVersionData={currentVersionData}
deleted={currentVersionData.deleted} deleted={currentVersionData.deleted}
entityPermissions={entityPermissions}
isVersionLoading={isVersionLoading} isVersionLoading={isVersionLoading}
owner={owner} owner={owner}
tier={tier as TagLabel} tier={tier as TagLabel}
@ -924,6 +756,7 @@ const EntityVersionPage: FunctionComponent = () => {
currentVersionData={currentVersionData} currentVersionData={currentVersionData}
dataModelFQN={entityFQN} dataModelFQN={entityFQN}
deleted={currentVersionData.deleted} deleted={currentVersionData.deleted}
entityPermissions={entityPermissions}
isVersionLoading={isVersionLoading} isVersionLoading={isVersionLoading}
owner={owner} owner={owner}
slashedDataModelName={slashedEntityName} slashedDataModelName={slashedEntityName}
@ -941,6 +774,12 @@ const EntityVersionPage: FunctionComponent = () => {
} }
}; };
useEffect(() => {
if (currentVersionData) {
fetchEntityPermissions();
}
}, [currentVersionData]);
useEffect(() => { useEffect(() => {
fetchEntityVersions(); fetchEntityVersions();
}, [entityFQN]); }, [entityFQN]);

View File

@ -51,36 +51,36 @@ jest.mock('components/DataModelVersion/DataModelVersion.component', () => {
}); });
jest.mock('rest/dashboardAPI', () => ({ jest.mock('rest/dashboardAPI', () => ({
getDashboardByFqn: jest.fn().mockImplementation(() => Promise.resolve()), getDashboardByFqn: jest.fn().mockImplementation(() => Promise.resolve({})),
getDashboardVersion: jest.fn().mockImplementation(() => Promise.resolve()), getDashboardVersion: jest.fn().mockImplementation(() => Promise.resolve({})),
getDashboardVersions: jest.fn().mockImplementation(() => Promise.resolve()), getDashboardVersions: jest.fn().mockImplementation(() => Promise.resolve({})),
})); }));
jest.mock('rest/pipelineAPI', () => ({ jest.mock('rest/pipelineAPI', () => ({
getPipelineByFqn: jest.fn().mockImplementation(() => Promise.resolve()), getPipelineByFqn: jest.fn().mockImplementation(() => Promise.resolve({})),
getPipelineVersion: jest.fn().mockImplementation(() => Promise.resolve()), getPipelineVersion: jest.fn().mockImplementation(() => Promise.resolve({})),
getPipelineVersions: jest.fn().mockImplementation(() => Promise.resolve()), getPipelineVersions: jest.fn().mockImplementation(() => Promise.resolve({})),
})); }));
jest.mock('rest/tableAPI', () => ({ jest.mock('rest/tableAPI', () => ({
getTableDetailsByFQN: jest.fn().mockImplementation(() => Promise.resolve()), getTableDetailsByFQN: jest.fn().mockImplementation(() => Promise.resolve({})),
getTableVersion: jest.fn().mockImplementation(() => Promise.resolve()), getTableVersion: jest.fn().mockImplementation(() => Promise.resolve({})),
getTableVersions: jest.fn().mockImplementation(() => Promise.resolve()), getTableVersions: jest.fn().mockImplementation(() => Promise.resolve({})),
})); }));
jest.mock('rest/topicsAPI', () => ({ jest.mock('rest/topicsAPI', () => ({
getTopicByFqn: jest.fn().mockImplementation(() => Promise.resolve()), getTopicByFqn: jest.fn().mockImplementation(() => Promise.resolve({})),
getTopicVersion: jest.fn().mockImplementation(() => Promise.resolve()), getTopicVersion: jest.fn().mockImplementation(() => Promise.resolve({})),
getTopicVersions: jest.fn().mockImplementation(() => Promise.resolve()), getTopicVersions: jest.fn().mockImplementation(() => Promise.resolve({})),
})); }));
jest.mock('rest/mlModelAPI', () => ({ jest.mock('rest/mlModelAPI', () => ({
getMlModelByFQN: jest.fn().mockImplementation(() => Promise.resolve()), getMlModelByFQN: jest.fn().mockImplementation(() => Promise.resolve({})),
getMlModelVersion: jest.fn().mockImplementation(() => Promise.resolve()), getMlModelVersion: jest.fn().mockImplementation(() => Promise.resolve({})),
getMlModelVersions: jest.fn().mockImplementation(() => Promise.resolve()), getMlModelVersions: jest.fn().mockImplementation(() => Promise.resolve({})),
})); }));
jest.mock('rest/storageAPI', () => ({ jest.mock('rest/storageAPI', () => ({
getContainerByName: jest.fn().mockImplementation(() => Promise.resolve()), getContainerByName: jest.fn().mockImplementation(() => Promise.resolve({})),
getContainerVersion: jest.fn().mockImplementation(() => Promise.resolve()), getContainerVersion: jest.fn().mockImplementation(() => Promise.resolve({})),
getContainerVersions: jest.fn().mockImplementation(() => Promise.resolve()), getContainerVersions: jest.fn().mockImplementation(() => Promise.resolve({})),
})); }));
jest.mock('components/containers/PageLayoutV1', () => jest.mock('components/containers/PageLayoutV1', () =>
@ -90,11 +90,11 @@ jest.mock('components/containers/PageLayoutV1', () =>
jest.mock('rest/dataModelsAPI', () => ({ jest.mock('rest/dataModelsAPI', () => ({
getDataModelDetailsByFQN: jest getDataModelDetailsByFQN: jest
.fn() .fn()
.mockImplementation(() => Promise.resolve()), .mockImplementation(() => Promise.resolve({})),
getDataModelVersion: jest.fn().mockImplementation(() => Promise.resolve()), getDataModelVersion: jest.fn().mockImplementation(() => Promise.resolve({})),
getDataModelVersionsList: jest getDataModelVersionsList: jest
.fn() .fn()
.mockImplementation(() => Promise.resolve()), .mockImplementation(() => Promise.resolve({})),
})); }));
describe('Test EntityVersionPage component', () => { describe('Test EntityVersionPage component', () => {

View File

@ -143,7 +143,7 @@ const MlModelPage = () => {
const { oldValue } = res.changeDescription.fieldsDeleted[0]; const { oldValue } = res.changeDescription.fieldsDeleted[0];
setMlModelDetail((preVDetail) => ({ setMlModelDetail((preVDetail) => ({
...preVDetail, ...preVDetail,
followers: (mlModelDetail.followers || []).filter( followers: (mlModelDetail.followers ?? []).filter(
(follower) => follower.id !== oldValue[0].id (follower) => follower.id !== oldValue[0].id
), ),
})); }));
@ -162,7 +162,7 @@ const MlModelPage = () => {
const res = await saveUpdatedMlModelData(updatedMlModel); const res = await saveUpdatedMlModelData(updatedMlModel);
setMlModelDetail((preVDetail) => ({ setMlModelDetail((preVDetail) => ({
...preVDetail, ...preVDetail,
tags: sortTagsCaseInsensitive(res.tags || []), tags: sortTagsCaseInsensitive(res.tags ?? []),
})); }));
setCurrentVersion(res.version?.toString()); setCurrentVersion(res.version?.toString());
} catch (error) { } catch (error) {

View File

@ -44,7 +44,13 @@ import { FQN_SEPARATOR_CHAR } from 'constants/char.constants';
import { getTableTabPath, getVersionPath } from 'constants/constants'; import { getTableTabPath, getVersionPath } from 'constants/constants';
import { EntityField } from 'constants/Feeds.constants'; import { EntityField } from 'constants/Feeds.constants';
import { mockDatasetData } from 'constants/mockTourData.constants'; import { mockDatasetData } from 'constants/mockTourData.constants';
import { EntityTabs, EntityType, FqnPart } from 'enums/entity.enum'; import { ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum';
import {
EntityTabs,
EntityType,
FqnPart,
TabSpecificField,
} from 'enums/entity.enum';
import { compare } from 'fast-json-patch'; import { compare } from 'fast-json-patch';
import { CreateThread } from 'generated/api/feed/createThread'; import { CreateThread } from 'generated/api/feed/createThread';
import { JoinedWith, Table } from 'generated/entity/data/table'; import { JoinedWith, Table } from 'generated/entity/data/table';
@ -120,6 +126,40 @@ const TableDetailsPageV1 = () => {
} }
}; };
const fetchUsageDetails = async () => {
setLoading(true);
try {
const { usageSummary } = await getTableDetailsByFQN(
datasetFQN,
TabSpecificField.USAGE_SUMMARY
);
setTableDetails((table) =>
table ? { ...table, usageSummary } : undefined
);
} catch (error) {
// Error here
} finally {
setLoading(false);
}
};
const fetchTestSuiteDetails = async () => {
setLoading(true);
try {
const { testSuite } = await getTableDetailsByFQN(
datasetFQN,
TabSpecificField.TESTSUITE
);
setTableDetails((table) => (table ? { ...table, testSuite } : undefined));
} catch (error) {
// Error here
} finally {
setLoading(false);
}
};
const fetchQueryCount = async () => { const fetchQueryCount = async () => {
if (!tableDetails?.id) { if (!tableDetails?.id) {
return; return;
@ -531,11 +571,13 @@ const TableDetailsPageV1 = () => {
name={t('label.sample-data')} name={t('label.sample-data')}
/> />
), ),
isHidden: !(
tablePermissions.ViewAll || tablePermissions.ViewSampleData
),
key: EntityTabs.SAMPLE_DATA, key: EntityTabs.SAMPLE_DATA,
children: ( children: !(
tablePermissions.ViewAll || tablePermissions.ViewSampleData
) ? (
<ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />
) : (
<SampleDataTableComponent <SampleDataTableComponent
isTableDeleted={tableDetails?.deleted} isTableDeleted={tableDetails?.deleted}
tableId={tableDetails?.id ?? ''} tableId={tableDetails?.id ?? ''}
@ -551,13 +593,12 @@ const TableDetailsPageV1 = () => {
name={t('label.query-plural')} name={t('label.query-plural')}
/> />
), ),
isHidden: !(
tablePermissions.ViewAll ||
tablePermissions.ViewBasic ||
tablePermissions.ViewQueries
),
key: EntityTabs.TABLE_QUERIES, key: EntityTabs.TABLE_QUERIES,
children: ( children: !(
tablePermissions.ViewAll || tablePermissions.ViewQueries
) ? (
<ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />
) : (
<TableQueries <TableQueries
isTableDeleted={tableDetails?.deleted} isTableDeleted={tableDetails?.deleted}
tableId={tableDetails?.id ?? ''} tableId={tableDetails?.id ?? ''}
@ -571,14 +612,14 @@ const TableDetailsPageV1 = () => {
name={t('label.profiler-amp-data-quality')} name={t('label.profiler-amp-data-quality')}
/> />
), ),
isHidden: !( key: EntityTabs.PROFILER,
children: !(
tablePermissions.ViewAll || tablePermissions.ViewAll ||
tablePermissions.ViewBasic ||
tablePermissions.ViewDataProfile || tablePermissions.ViewDataProfile ||
tablePermissions.ViewTests tablePermissions.ViewTests
), ) ? (
key: EntityTabs.PROFILER, <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />
children: ( ) : (
<TableProfilerV1 <TableProfilerV1
isTableDeleted={tableDetails?.deleted} isTableDeleted={tableDetails?.deleted}
permissions={tablePermissions} permissions={tablePermissions}
@ -651,7 +692,9 @@ const TableDetailsPageV1 = () => {
/> />
), ),
key: EntityTabs.CUSTOM_PROPERTIES, key: EntityTabs.CUSTOM_PROPERTIES,
children: ( children: !tablePermissions.ViewAll ? (
<ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />
) : (
<CustomPropertyTable <CustomPropertyTable
entityDetails={tableDetails as CustomPropertyProps['entityDetails']} entityDetails={tableDetails as CustomPropertyProps['entityDetails']}
entityType={EntityType.TABLE} entityType={EntityType.TABLE}
@ -793,6 +836,12 @@ const TableDetailsPageV1 = () => {
} else { } else {
fetchTableDetails(); fetchTableDetails();
getEntityFeedCount(); getEntityFeedCount();
if (tablePermissions.ViewUsage) {
fetchUsageDetails();
}
if (tablePermissions.ViewTests) {
fetchTestSuiteDetails();
}
} }
}, [datasetFQN, isTourOpen, isTourPage]); }, [datasetFQN, isTourOpen, isTourPage]);
@ -825,6 +874,10 @@ const TableDetailsPageV1 = () => {
return <Loader />; return <Loader />;
} }
if (!(tablePermissions.ViewAll || tablePermissions.ViewBasic)) {
return <ErrorPlaceHolder type={ERROR_PLACEHOLDER_TYPE.PERMISSION} />;
}
if (!tableDetails) { if (!tableDetails) {
return <ErrorPlaceHolder className="m-0" />; return <ErrorPlaceHolder className="m-0" />;
} }

View File

@ -239,6 +239,7 @@ const TopicDetailsPage: FunctionComponent = () => {
createThread={createThread} createThread={createThread}
followTopicHandler={followTopic} followTopicHandler={followTopic}
topicDetails={topicDetails} topicDetails={topicDetails}
topicPermissions={topicPermissions}
unFollowTopicHandler={unFollowTopic} unFollowTopicHandler={unFollowTopic}
versionHandler={versionHandler} versionHandler={versionHandler}
onTopicUpdate={onTopicUpdate} onTopicUpdate={onTopicUpdate}

View File

@ -18,8 +18,7 @@ import { TabSpecificField } from '../enums/entity.enum';
import { Dashboard } from '../generated/entity/data/dashboard'; import { Dashboard } from '../generated/entity/data/dashboard';
import { sortTagsCaseInsensitive } from './CommonUtils'; import { sortTagsCaseInsensitive } from './CommonUtils';
export const defaultFields = `${TabSpecificField.OWNER}, ${TabSpecificField.FOLLOWERS}, ${TabSpecificField.TAGS}, export const defaultFields = `${TabSpecificField.OWNER}, ${TabSpecificField.FOLLOWERS}, ${TabSpecificField.TAGS}, ${TabSpecificField.CHARTS},${TabSpecificField.EXTENSION}`;
${TabSpecificField.USAGE_SUMMARY}, ${TabSpecificField.CHARTS},${TabSpecificField.EXTENSION}`;
export const sortTagsForCharts = (charts: ChartType[]) => { export const sortTagsForCharts = (charts: ChartType[]) => {
return charts.map((chart) => ({ return charts.map((chart) => ({

View File

@ -13,6 +13,6 @@
import { TabSpecificField } from '../enums/entity.enum'; import { TabSpecificField } from '../enums/entity.enum';
export const defaultFields = `${TabSpecificField.COLUMNS}, ${TabSpecificField.USAGE_SUMMARY}, export const defaultFields = `${TabSpecificField.COLUMNS},
${TabSpecificField.FOLLOWERS}, ${TabSpecificField.JOINS}, ${TabSpecificField.TAGS}, ${TabSpecificField.OWNER}, ${TabSpecificField.FOLLOWERS}, ${TabSpecificField.JOINS}, ${TabSpecificField.TAGS}, ${TabSpecificField.OWNER},
${TabSpecificField.DATAMODEL},${TabSpecificField.TABLE_CONSTRAINTS},${TabSpecificField.EXTENSION},${TabSpecificField.TESTSUITE},${TabSpecificField.VIEW_DEFINITION}`; ${TabSpecificField.DATAMODEL},${TabSpecificField.TABLE_CONSTRAINTS},${TabSpecificField.EXTENSION},${TabSpecificField.VIEW_DEFINITION}`;

View File

@ -13,5 +13,4 @@
import { TabSpecificField } from '../enums/entity.enum'; import { TabSpecificField } from '../enums/entity.enum';
export const defaultFields = `${TabSpecificField.USAGE_SUMMARY}, export const defaultFields = `${TabSpecificField.FOLLOWERS}, ${TabSpecificField.TAGS}, ${TabSpecificField.OWNER}, ${TabSpecificField.DASHBOARD} ,${TabSpecificField.EXTENSION}`;
${TabSpecificField.FOLLOWERS}, ${TabSpecificField.TAGS}, ${TabSpecificField.OWNER}, ${TabSpecificField.DASHBOARD} ,${TabSpecificField.EXTENSION}`;

View File

@ -23,7 +23,7 @@ import { sortTagsCaseInsensitive } from './CommonUtils';
import { Icons } from './SvgUtils'; import { Icons } from './SvgUtils';
export const defaultFields = `${TabSpecificField.FOLLOWERS}, ${TabSpecificField.TAGS}, ${TabSpecificField.OWNER}, export const defaultFields = `${TabSpecificField.FOLLOWERS}, ${TabSpecificField.TAGS}, ${TabSpecificField.OWNER},
${TabSpecificField.TASKS}, ${TabSpecificField.PIPELINE_STATUS},${TabSpecificField.EXTENSION}, ${TabSpecificField.SCHEDULE_INTERVAL}`; ${TabSpecificField.TASKS}, ${TabSpecificField.PIPELINE_STATUS},${TabSpecificField.EXTENSION}`;
export const pipelineDetailsTabs = [ export const pipelineDetailsTabs = [
{ {