mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-20 05:15:08 +00:00
fix: allow removing assets from assets page (#13936)
* fix: allow removing assets from assets tab * fix: localization * fix: glossary trim issue and permission fix * fix: asset removal on domain and glossary term
This commit is contained in:
parent
2c72245342
commit
fcdeb1b9e8
@ -365,7 +365,7 @@ const AppDetails = () => {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
...tabConfiguration,
|
...tabConfiguration,
|
||||||
...(appData?.appType === AppType.Internal && !appData?.deleted
|
...(!appData?.deleted
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
label: (
|
label: (
|
||||||
|
@ -212,21 +212,25 @@ const AppRunsHistory = forwardRef(
|
|||||||
|
|
||||||
if (isExternalApp) {
|
if (isExternalApp) {
|
||||||
const currentTime = Date.now();
|
const currentTime = Date.now();
|
||||||
const oneDayAgo = getEpochMillisForPastDays(1);
|
// past 30 days
|
||||||
|
const startDay = getEpochMillisForPastDays(30);
|
||||||
|
|
||||||
const { data } = await getApplicationRuns(fqn, {
|
const { data } = await getApplicationRuns(fqn, {
|
||||||
startTs: oneDayAgo,
|
startTs: startDay,
|
||||||
endTs: currentTime,
|
endTs: currentTime,
|
||||||
});
|
});
|
||||||
|
|
||||||
setAppRunsHistoryData(
|
setAppRunsHistoryData(
|
||||||
data.map((item) => ({
|
data
|
||||||
...item,
|
.map((item) => ({
|
||||||
status: getStatusFromPipelineState(
|
...item,
|
||||||
(item as PipelineStatus).pipelineState ?? PipelineState.Failed
|
status: getStatusFromPipelineState(
|
||||||
),
|
(item as PipelineStatus).pipelineState ??
|
||||||
id: (item as PipelineStatus).runId ?? '',
|
PipelineState.Failed
|
||||||
}))
|
),
|
||||||
|
id: (item as PipelineStatus).runId ?? '',
|
||||||
|
}))
|
||||||
|
.slice(0, maxRecords)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const { data, paging } = await getApplicationRuns(fqn, {
|
const { data, paging } = await getApplicationRuns(fqn, {
|
||||||
@ -248,7 +252,7 @@ const AppRunsHistory = forwardRef(
|
|||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[fqn, pageSize, maxRecords]
|
[fqn, pageSize, maxRecords, appData]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleAppHistoryPageChange = ({
|
const handleAppHistoryPageChange = ({
|
||||||
|
@ -411,12 +411,14 @@ const DataProductsDetailsPage = ({
|
|||||||
rightPanelWidth={400}>
|
rightPanelWidth={400}>
|
||||||
<AssetsTabs
|
<AssetsTabs
|
||||||
assetCount={assetCount}
|
assetCount={assetCount}
|
||||||
|
entityFqn={dataProduct.fullyQualifiedName}
|
||||||
isSummaryPanelOpen={false}
|
isSummaryPanelOpen={false}
|
||||||
permissions={dataProductPermission}
|
permissions={dataProductPermission}
|
||||||
ref={assetTabRef}
|
ref={assetTabRef}
|
||||||
type={AssetsOfEntity.DATA_PRODUCT}
|
type={AssetsOfEntity.DATA_PRODUCT}
|
||||||
onAddAsset={() => setAssetModelVisible(true)}
|
onAddAsset={() => setAssetModelVisible(true)}
|
||||||
onAssetClick={handleAssetClick}
|
onAssetClick={handleAssetClick}
|
||||||
|
onRemoveAsset={handleAssetSave}
|
||||||
/>
|
/>
|
||||||
</PageLayoutV1>
|
</PageLayoutV1>
|
||||||
),
|
),
|
||||||
@ -429,6 +431,7 @@ const DataProductsDetailsPage = ({
|
|||||||
previewAsset,
|
previewAsset,
|
||||||
dataProduct,
|
dataProduct,
|
||||||
isVersionsView,
|
isVersionsView,
|
||||||
|
handleAssetSave,
|
||||||
assetCount,
|
assetCount,
|
||||||
activeTab,
|
activeTab,
|
||||||
]);
|
]);
|
||||||
@ -571,7 +574,8 @@ const DataProductsDetailsPage = ({
|
|||||||
entityFqn={dataProductFqn}
|
entityFqn={dataProductFqn}
|
||||||
open={assetModalVisible}
|
open={assetModalVisible}
|
||||||
queryFilter={getQueryFilterToIncludeDomain(
|
queryFilter={getQueryFilterToIncludeDomain(
|
||||||
dataProduct.domain?.fullyQualifiedName ?? ''
|
dataProduct.domain?.fullyQualifiedName ?? '',
|
||||||
|
dataProduct.fullyQualifiedName ?? ''
|
||||||
)}
|
)}
|
||||||
type={AssetsOfEntity.DATA_PRODUCT}
|
type={AssetsOfEntity.DATA_PRODUCT}
|
||||||
onCancel={() => setAssetModelVisible(false)}
|
onCancel={() => setAssetModelVisible(false)}
|
||||||
|
@ -24,7 +24,8 @@
|
|||||||
margin-left: 24px;
|
margin-left: 24px;
|
||||||
}
|
}
|
||||||
.assets-data-container {
|
.assets-data-container {
|
||||||
padding: 12px 18px;
|
padding-left: 18px;
|
||||||
|
padding-right: 18px;
|
||||||
}
|
}
|
||||||
.page-layout-v1-vertical-scroll,
|
.page-layout-v1-vertical-scroll,
|
||||||
.page-layout-leftpanel {
|
.page-layout-leftpanel {
|
||||||
|
@ -71,6 +71,7 @@ import { Style } from '../../../generated/type/tagLabel';
|
|||||||
import { addDataProducts } from '../../../rest/dataProductAPI';
|
import { addDataProducts } from '../../../rest/dataProductAPI';
|
||||||
import { searchData } from '../../../rest/miscAPI';
|
import { searchData } from '../../../rest/miscAPI';
|
||||||
import { getIsErrorMatch } from '../../../utils/CommonUtils';
|
import { getIsErrorMatch } from '../../../utils/CommonUtils';
|
||||||
|
import { getQueryFilterToExcludeDomainTerms } from '../../../utils/DomainUtils';
|
||||||
import { getEntityVersionByField } from '../../../utils/EntityVersionUtils';
|
import { getEntityVersionByField } from '../../../utils/EntityVersionUtils';
|
||||||
import Fqn from '../../../utils/Fqn';
|
import Fqn from '../../../utils/Fqn';
|
||||||
import { DEFAULT_ENTITY_PERMISSION } from '../../../utils/PermissionsUtils';
|
import { DEFAULT_ENTITY_PERMISSION } from '../../../utils/PermissionsUtils';
|
||||||
@ -472,12 +473,14 @@ const DomainDetailsPage = ({
|
|||||||
rightPanelWidth={400}>
|
rightPanelWidth={400}>
|
||||||
<AssetsTabs
|
<AssetsTabs
|
||||||
assetCount={assetCount}
|
assetCount={assetCount}
|
||||||
|
entityFqn={domainFqn}
|
||||||
isSummaryPanelOpen={false}
|
isSummaryPanelOpen={false}
|
||||||
permissions={domainPermission}
|
permissions={domainPermission}
|
||||||
ref={assetTabRef}
|
ref={assetTabRef}
|
||||||
type={AssetsOfEntity.DOMAIN}
|
type={AssetsOfEntity.DOMAIN}
|
||||||
onAddAsset={() => setAssetModelVisible(true)}
|
onAddAsset={() => setAssetModelVisible(true)}
|
||||||
onAssetClick={handleAssetClick}
|
onAssetClick={handleAssetClick}
|
||||||
|
onRemoveAsset={handleAssetSave}
|
||||||
/>
|
/>
|
||||||
</PageLayoutV1>
|
</PageLayoutV1>
|
||||||
),
|
),
|
||||||
@ -490,6 +493,7 @@ const DomainDetailsPage = ({
|
|||||||
domainPermission,
|
domainPermission,
|
||||||
previewAsset,
|
previewAsset,
|
||||||
handleAssetClick,
|
handleAssetClick,
|
||||||
|
handleAssetSave,
|
||||||
assetCount,
|
assetCount,
|
||||||
dataProductsCount,
|
dataProductsCount,
|
||||||
activeTab,
|
activeTab,
|
||||||
@ -627,6 +631,7 @@ const DomainDetailsPage = ({
|
|||||||
<AssetSelectionModal
|
<AssetSelectionModal
|
||||||
entityFqn={domainFqn}
|
entityFqn={domainFqn}
|
||||||
open={assetModalVisible}
|
open={assetModalVisible}
|
||||||
|
queryFilter={getQueryFilterToExcludeDomainTerms(domainFqn)}
|
||||||
type={AssetsOfEntity.DOMAIN}
|
type={AssetsOfEntity.DOMAIN}
|
||||||
onCancel={() => setAssetModelVisible(false)}
|
onCancel={() => setAssetModelVisible(false)}
|
||||||
onSave={handleAssetSave}
|
onSave={handleAssetSave}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Col, Divider, Row, Space, Typography } from 'antd';
|
import { Col, Divider, Row, Space, Typography } from 'antd';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { SummaryEntityType } from '../../../../enums/EntitySummary.enum';
|
import { SummaryEntityType } from '../../../../enums/EntitySummary.enum';
|
||||||
@ -48,7 +49,10 @@ function GlossaryTermSummary({
|
|||||||
[selectedData]
|
[selectedData]
|
||||||
);
|
);
|
||||||
|
|
||||||
const synonyms = useMemo(() => entityDetails.synonyms ?? [], [selectedData]);
|
const synonyms = useMemo(
|
||||||
|
() => entityDetails.synonyms?.filter((item) => !isEmpty(item)) ?? [],
|
||||||
|
[selectedData]
|
||||||
|
);
|
||||||
|
|
||||||
const fetchGlossaryTermDetails = useCallback(async () => {
|
const fetchGlossaryTermDetails = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
|
@ -31,4 +31,5 @@ export interface ExploreSearchCardProps {
|
|||||||
showTags?: boolean;
|
showTags?: boolean;
|
||||||
openEntityInNewPage?: boolean;
|
openEntityInNewPage?: boolean;
|
||||||
hideBreadcrumbs?: boolean;
|
hideBreadcrumbs?: boolean;
|
||||||
|
actionPopoverContent?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
@ -10,7 +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 { Button, Col, Row, Typography } from 'antd';
|
import { Button, Col, Row, Space, Typography } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { isString, startCase, uniqueId } from 'lodash';
|
import { isString, startCase, uniqueId } from 'lodash';
|
||||||
import { ExtraInfo } from 'Models';
|
import { ExtraInfo } from 'Models';
|
||||||
@ -58,6 +58,7 @@ const ExploreSearchCard: React.FC<ExploreSearchCardProps> = forwardRef<
|
|||||||
showTags = true,
|
showTags = true,
|
||||||
openEntityInNewPage,
|
openEntityInNewPage,
|
||||||
hideBreadcrumbs = false,
|
hideBreadcrumbs = false,
|
||||||
|
actionPopoverContent,
|
||||||
},
|
},
|
||||||
ref
|
ref
|
||||||
) => {
|
) => {
|
||||||
@ -245,6 +246,9 @@ const ExploreSearchCard: React.FC<ExploreSearchCardProps> = forwardRef<
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
{actionPopoverContent && (
|
||||||
|
<Space className="explore-card-actions">{actionPopoverContent}</Space>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
.explore-search-card {
|
.explore-search-card {
|
||||||
background-color: @white;
|
background-color: @white;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
position: relative;
|
||||||
&.highlight-card {
|
&.highlight-card {
|
||||||
border-left: 4px solid @info-color;
|
border-left: 4px solid @info-color;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
@ -22,4 +23,22 @@
|
|||||||
.entity-summary-details {
|
.entity-summary-details {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
.explore-card-actions {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: -12px;
|
||||||
|
transition: width 0.3s;
|
||||||
|
background: @white;
|
||||||
|
border: @global-border;
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 6px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: @grey-1;
|
||||||
|
.explore-card-actions {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,13 @@
|
|||||||
|
|
||||||
import { Col, Row, Tabs } from 'antd';
|
import { Col, Row, Tabs } from 'antd';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
import React, {
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
import { useHistory, useParams } from 'react-router-dom';
|
import { useHistory, useParams } from 'react-router-dom';
|
||||||
import { getGlossaryTermDetailsPath } from '../../../constants/constants';
|
import { getGlossaryTermDetailsPath } from '../../../constants/constants';
|
||||||
import { EntityField } from '../../../constants/Feeds.constants';
|
import { EntityField } from '../../../constants/Feeds.constants';
|
||||||
@ -97,6 +103,12 @@ const GlossaryTermsV1 = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleAssetSave = useCallback(() => {
|
||||||
|
fetchGlossaryTermAssets();
|
||||||
|
assetTabRef.current?.refreshAssets();
|
||||||
|
tab !== 'assets' && activeTabHandler('assets');
|
||||||
|
}, [assetTabRef, tab]);
|
||||||
|
|
||||||
const onExtensionUpdate = async (updatedTable: GlossaryTerm) => {
|
const onExtensionUpdate = async (updatedTable: GlossaryTerm) => {
|
||||||
await handleGlossaryTermUpdate({
|
await handleGlossaryTermUpdate({
|
||||||
...glossaryTerm,
|
...glossaryTerm,
|
||||||
@ -162,11 +174,13 @@ const GlossaryTermsV1 = ({
|
|||||||
children: (
|
children: (
|
||||||
<AssetsTabs
|
<AssetsTabs
|
||||||
assetCount={assetCount}
|
assetCount={assetCount}
|
||||||
|
entityFqn={glossaryTerm.fullyQualifiedName ?? ''}
|
||||||
isSummaryPanelOpen={isSummaryPanelOpen}
|
isSummaryPanelOpen={isSummaryPanelOpen}
|
||||||
permissions={assetPermissions}
|
permissions={assetPermissions}
|
||||||
ref={assetTabRef}
|
ref={assetTabRef}
|
||||||
onAddAsset={() => setAssetModelVisible(true)}
|
onAddAsset={() => setAssetModelVisible(true)}
|
||||||
onAssetClick={onAssetClick}
|
onAssetClick={onAssetClick}
|
||||||
|
onRemoveAsset={handleAssetSave}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -226,6 +240,7 @@ const GlossaryTermsV1 = ({
|
|||||||
isSummaryPanelOpen,
|
isSummaryPanelOpen,
|
||||||
isVersionView,
|
isVersionView,
|
||||||
assetPermissions,
|
assetPermissions,
|
||||||
|
handleAssetSave,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const fetchGlossaryTermAssets = async () => {
|
const fetchGlossaryTermAssets = async () => {
|
||||||
@ -253,12 +268,6 @@ const GlossaryTermsV1 = ({
|
|||||||
getEntityFeedCount();
|
getEntityFeedCount();
|
||||||
}, [glossaryFqn]);
|
}, [glossaryFqn]);
|
||||||
|
|
||||||
const handleAssetSave = () => {
|
|
||||||
fetchGlossaryTermAssets();
|
|
||||||
assetTabRef.current?.refreshAssets();
|
|
||||||
tab !== 'assets' && activeTabHandler('assets');
|
|
||||||
};
|
|
||||||
|
|
||||||
const name = useMemo(
|
const name = useMemo(
|
||||||
() =>
|
() =>
|
||||||
isVersionView
|
isVersionView
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable no-case-declarations */
|
||||||
/*
|
/*
|
||||||
* Copyright 2022 Collate.
|
* Copyright 2022 Collate.
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -28,6 +29,7 @@ import {
|
|||||||
} from 'antd';
|
} from 'antd';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
import { compare } from 'fast-json-patch';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
import { isEmpty, isObject } from 'lodash';
|
import { isEmpty, isObject } from 'lodash';
|
||||||
import React, {
|
import React, {
|
||||||
@ -40,18 +42,34 @@ import React, {
|
|||||||
} from 'react';
|
} from 'react';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useParams } from 'react-router-dom';
|
||||||
import { ReactComponent as AddPlaceHolderIcon } from '../../../../assets/svg/add-placeholder.svg';
|
import { ReactComponent as AddPlaceHolderIcon } from '../../../../assets/svg/add-placeholder.svg';
|
||||||
|
import { ReactComponent as DeleteIcon } from '../../../../assets/svg/ic-delete.svg';
|
||||||
import {
|
import {
|
||||||
AssetsFilterOptions,
|
AssetsFilterOptions,
|
||||||
ASSET_MENU_KEYS,
|
ASSET_MENU_KEYS,
|
||||||
ASSET_SUB_MENU_FILTER,
|
ASSET_SUB_MENU_FILTER,
|
||||||
} from '../../../../constants/Assets.constants';
|
} from '../../../../constants/Assets.constants';
|
||||||
|
import { ES_UPDATE_DELAY } from '../../../../constants/constants';
|
||||||
import { GLOSSARIES_DOCS } from '../../../../constants/docs.constants';
|
import { GLOSSARIES_DOCS } from '../../../../constants/docs.constants';
|
||||||
import { ERROR_PLACEHOLDER_TYPE } from '../../../../enums/common.enum';
|
import { ERROR_PLACEHOLDER_TYPE } from '../../../../enums/common.enum';
|
||||||
import { EntityType } from '../../../../enums/entity.enum';
|
import { EntityType } from '../../../../enums/entity.enum';
|
||||||
import { SearchIndex } from '../../../../enums/search.enum';
|
import { SearchIndex } from '../../../../enums/search.enum';
|
||||||
|
import { GlossaryTerm } from '../../../../generated/entity/data/glossaryTerm';
|
||||||
|
import { DataProduct } from '../../../../generated/entity/domains/dataProduct';
|
||||||
|
import { Domain } from '../../../../generated/entity/domains/domain';
|
||||||
import { usePaging } from '../../../../hooks/paging/usePaging';
|
import { usePaging } from '../../../../hooks/paging/usePaging';
|
||||||
|
import {
|
||||||
|
getDataProductByName,
|
||||||
|
patchDataProduct,
|
||||||
|
} from '../../../../rest/dataProductAPI';
|
||||||
|
import { getDomainByName } from '../../../../rest/domainAPI';
|
||||||
|
import { getGlossaryTermByFQN } from '../../../../rest/glossaryAPI';
|
||||||
import { searchData } from '../../../../rest/miscAPI';
|
import { searchData } from '../../../../rest/miscAPI';
|
||||||
|
import {
|
||||||
|
removeGlossaryTermAssets,
|
||||||
|
updateDomainAssets,
|
||||||
|
} from '../../../../utils/Assets/AssetsUtils';
|
||||||
import { getCountBadge, Transi18next } from '../../../../utils/CommonUtils';
|
import { getCountBadge, Transi18next } from '../../../../utils/CommonUtils';
|
||||||
|
import { getEntityName } from '../../../../utils/EntityUtils';
|
||||||
import { getEntityTypeFromSearchIndex } from '../../../../utils/SearchUtils';
|
import { getEntityTypeFromSearchIndex } from '../../../../utils/SearchUtils';
|
||||||
import { getEntityIcon } from '../../../../utils/TableUtils';
|
import { getEntityIcon } from '../../../../utils/TableUtils';
|
||||||
import { showErrorToast } from '../../../../utils/ToastUtils';
|
import { showErrorToast } from '../../../../utils/ToastUtils';
|
||||||
@ -59,6 +77,7 @@ import ErrorPlaceHolder from '../../../common/ErrorWithPlaceholder/ErrorPlaceHol
|
|||||||
import NextPrevious from '../../../common/NextPrevious/NextPrevious';
|
import NextPrevious from '../../../common/NextPrevious/NextPrevious';
|
||||||
import { PagingHandlerParams } from '../../../common/NextPrevious/NextPrevious.interface';
|
import { PagingHandlerParams } from '../../../common/NextPrevious/NextPrevious.interface';
|
||||||
import ExploreSearchCard from '../../../ExploreV1/ExploreSearchCard/ExploreSearchCard';
|
import ExploreSearchCard from '../../../ExploreV1/ExploreSearchCard/ExploreSearchCard';
|
||||||
|
import ConfirmationModal from '../../../Modals/ConfirmationModal/ConfirmationModal';
|
||||||
import {
|
import {
|
||||||
SearchedDataProps,
|
SearchedDataProps,
|
||||||
SourceType,
|
SourceType,
|
||||||
@ -78,11 +97,13 @@ const AssetsTabs = forwardRef(
|
|||||||
onAssetClick,
|
onAssetClick,
|
||||||
isSummaryPanelOpen,
|
isSummaryPanelOpen,
|
||||||
onAddAsset,
|
onAddAsset,
|
||||||
|
onRemoveAsset,
|
||||||
assetCount,
|
assetCount,
|
||||||
queryFilter,
|
queryFilter,
|
||||||
isEntityDeleted = false,
|
isEntityDeleted = false,
|
||||||
type = AssetsOfEntity.GLOSSARY,
|
type = AssetsOfEntity.GLOSSARY,
|
||||||
noDataPlaceholder,
|
noDataPlaceholder,
|
||||||
|
entityFqn,
|
||||||
}: AssetsTabsProps,
|
}: AssetsTabsProps,
|
||||||
ref
|
ref
|
||||||
) => {
|
) => {
|
||||||
@ -104,10 +125,25 @@ const AssetsTabs = forwardRef(
|
|||||||
showPagination,
|
showPagination,
|
||||||
} = usePaging();
|
} = usePaging();
|
||||||
|
|
||||||
|
const isRemovable = useMemo(
|
||||||
|
() =>
|
||||||
|
[
|
||||||
|
AssetsOfEntity.DATA_PRODUCT,
|
||||||
|
AssetsOfEntity.DOMAIN,
|
||||||
|
AssetsOfEntity.GLOSSARY,
|
||||||
|
].includes(type),
|
||||||
|
[type]
|
||||||
|
);
|
||||||
|
|
||||||
const [selectedCard, setSelectedCard] = useState<SourceType>();
|
const [selectedCard, setSelectedCard] = useState<SourceType>();
|
||||||
const [visible, setVisible] = useState<boolean>(false);
|
const [visible, setVisible] = useState<boolean>(false);
|
||||||
const [openKeys, setOpenKeys] = useState<EntityType[]>([]);
|
const [openKeys, setOpenKeys] = useState<EntityType[]>([]);
|
||||||
const [isCountLoading, setIsCountLoading] = useState<boolean>(true);
|
const [isCountLoading, setIsCountLoading] = useState<boolean>(true);
|
||||||
|
const [showDeleteModal, setShowDeleteModal] = useState(false);
|
||||||
|
const [assetToDelete, setAssetToDelete] = useState<SourceType>();
|
||||||
|
const [activeEntity, setActiveEntity] = useState<
|
||||||
|
Domain | DataProduct | GlossaryTerm
|
||||||
|
>();
|
||||||
|
|
||||||
const queryParam = useMemo(() => {
|
const queryParam = useMemo(() => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
@ -199,6 +235,29 @@ const AssetsTabs = forwardRef(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fetchCurrentEntity = useCallback(async () => {
|
||||||
|
let data;
|
||||||
|
const fqn = encodeURIComponent(entityFqn ?? '');
|
||||||
|
switch (type) {
|
||||||
|
case AssetsOfEntity.DOMAIN:
|
||||||
|
data = await getDomainByName(fqn, '');
|
||||||
|
|
||||||
|
break;
|
||||||
|
case AssetsOfEntity.DATA_PRODUCT:
|
||||||
|
data = await getDataProductByName(fqn, 'domain,assets');
|
||||||
|
|
||||||
|
break;
|
||||||
|
case AssetsOfEntity.GLOSSARY:
|
||||||
|
data = await getGlossaryTermByFQN(fqn);
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
setActiveEntity(data);
|
||||||
|
}, [type, entityFqn]);
|
||||||
|
|
||||||
const tabs = useMemo(() => {
|
const tabs = useMemo(() => {
|
||||||
return AssetsFilterOptions.map((option) => {
|
return AssetsFilterOptions.map((option) => {
|
||||||
return {
|
return {
|
||||||
@ -288,6 +347,11 @@ const AssetsTabs = forwardRef(
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const onExploreCardDelete = useCallback((source: SourceType) => {
|
||||||
|
setAssetToDelete(source);
|
||||||
|
setShowDeleteModal(true);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const filteredAssetMenus = useMemo(() => {
|
const filteredAssetMenus = useMemo(() => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case AssetsOfEntity.DOMAIN:
|
case AssetsOfEntity.DOMAIN:
|
||||||
@ -351,6 +415,12 @@ const AssetsTabs = forwardRef(
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (entityFqn) {
|
||||||
|
fetchCurrentEntity();
|
||||||
|
}
|
||||||
|
}, [entityFqn]);
|
||||||
|
|
||||||
const assetErrorPlaceHolder = useMemo(() => {
|
const assetErrorPlaceHolder = useMemo(() => {
|
||||||
if (!isEmpty(activeFilter)) {
|
if (!isEmpty(activeFilter)) {
|
||||||
return (
|
return (
|
||||||
@ -426,17 +496,35 @@ const AssetsTabs = forwardRef(
|
|||||||
const assetListing = useMemo(
|
const assetListing = useMemo(
|
||||||
() =>
|
() =>
|
||||||
data.length ? (
|
data.length ? (
|
||||||
<div className="assets-data-container">
|
<div className="assets-data-container p-t-sm">
|
||||||
{data.map(({ _source, _id = '' }, index) => (
|
{data.map(({ _source, _id = '' }) => (
|
||||||
<ExploreSearchCard
|
<ExploreSearchCard
|
||||||
showEntityIcon
|
showEntityIcon
|
||||||
|
actionPopoverContent={
|
||||||
|
isRemovable && permissions.EditAll ? (
|
||||||
|
<Button
|
||||||
|
className="p-0 flex-center"
|
||||||
|
data-testid="delete-tag"
|
||||||
|
icon={
|
||||||
|
<DeleteIcon
|
||||||
|
data-testid="delete-icon"
|
||||||
|
name="Delete"
|
||||||
|
width={16}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
size="small"
|
||||||
|
type="text"
|
||||||
|
onClick={() => onExploreCardDelete(_source)}
|
||||||
|
/>
|
||||||
|
) : null
|
||||||
|
}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
'm-b-sm cursor-pointer',
|
'm-b-sm cursor-pointer',
|
||||||
selectedCard?.id === _source.id ? 'highlight-card' : ''
|
selectedCard?.id === _source.id ? 'highlight-card' : ''
|
||||||
)}
|
)}
|
||||||
handleSummaryPanelDisplay={setSelectedCard}
|
handleSummaryPanelDisplay={setSelectedCard}
|
||||||
id={_id}
|
id={_id}
|
||||||
key={index}
|
key={'assets_' + _id}
|
||||||
showTags={false}
|
showTags={false}
|
||||||
source={_source}
|
source={_source}
|
||||||
/>
|
/>
|
||||||
@ -458,7 +546,9 @@ const AssetsTabs = forwardRef(
|
|||||||
<div className="m-t-xlg">{assetErrorPlaceHolder}</div>
|
<div className="m-t-xlg">{assetErrorPlaceHolder}</div>
|
||||||
),
|
),
|
||||||
[
|
[
|
||||||
|
type,
|
||||||
data,
|
data,
|
||||||
|
permissions,
|
||||||
paging,
|
paging,
|
||||||
currentPage,
|
currentPage,
|
||||||
selectedCard,
|
selectedCard,
|
||||||
@ -539,6 +629,65 @@ const AssetsTabs = forwardRef(
|
|||||||
);
|
);
|
||||||
}, [assetsHeader, assetListing, selectedCard]);
|
}, [assetsHeader, assetListing, selectedCard]);
|
||||||
|
|
||||||
|
const onAssetRemove = useCallback(async () => {
|
||||||
|
if (!activeEntity) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
let updatedEntity;
|
||||||
|
switch (type) {
|
||||||
|
case AssetsOfEntity.DATA_PRODUCT:
|
||||||
|
const updatedAssets = (
|
||||||
|
(activeEntity as DataProduct)?.assets ?? []
|
||||||
|
).filter((asset) => asset.id !== assetToDelete?.id);
|
||||||
|
updatedEntity = {
|
||||||
|
...activeEntity,
|
||||||
|
assets: updatedAssets,
|
||||||
|
};
|
||||||
|
const jsonPatch = compare(activeEntity, updatedEntity);
|
||||||
|
const res = await patchDataProduct(
|
||||||
|
(activeEntity as DataProduct).id,
|
||||||
|
jsonPatch
|
||||||
|
);
|
||||||
|
setActiveEntity(res);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AssetsOfEntity.DOMAIN:
|
||||||
|
case AssetsOfEntity.GLOSSARY:
|
||||||
|
const selectedItemMap = new Map();
|
||||||
|
selectedItemMap.set(assetToDelete?.id, assetToDelete);
|
||||||
|
|
||||||
|
if (type === AssetsOfEntity.DOMAIN) {
|
||||||
|
await updateDomainAssets(undefined, type, selectedItemMap);
|
||||||
|
} else if (type === AssetsOfEntity.GLOSSARY) {
|
||||||
|
await removeGlossaryTermAssets(
|
||||||
|
entityFqn ?? '',
|
||||||
|
type,
|
||||||
|
selectedItemMap
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Handle other entity types here
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
await new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve('');
|
||||||
|
}, ES_UPDATE_DELAY);
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
showErrorToast(err as AxiosError);
|
||||||
|
} finally {
|
||||||
|
setShowDeleteModal(false);
|
||||||
|
onRemoveAsset?.();
|
||||||
|
}
|
||||||
|
}, [type, activeEntity, assetToDelete, entityFqn]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchAssets({
|
fetchAssets({
|
||||||
index: isEmpty(activeFilter) ? [SearchIndex.ALL] : activeFilter,
|
index: isEmpty(activeFilter) ? [SearchIndex.ALL] : activeFilter,
|
||||||
@ -589,6 +738,20 @@ const AssetsTabs = forwardRef(
|
|||||||
className={classNames('assets-tab-container p-md')}
|
className={classNames('assets-tab-container p-md')}
|
||||||
data-testid="table-container">
|
data-testid="table-container">
|
||||||
{layout}
|
{layout}
|
||||||
|
<ConfirmationModal
|
||||||
|
bodyText={t('message.are-you-sure-action-property', {
|
||||||
|
propertyName: getEntityName(assetToDelete),
|
||||||
|
action: t('label.remove-lowecase'),
|
||||||
|
})}
|
||||||
|
cancelText={t('label.cancel')}
|
||||||
|
confirmText={t('label.delete')}
|
||||||
|
header={t('label.remove-entity', {
|
||||||
|
entity: getEntityName(assetToDelete) + '?',
|
||||||
|
})}
|
||||||
|
visible={showDeleteModal}
|
||||||
|
onCancel={() => setShowDeleteModal(false)}
|
||||||
|
onConfirm={onAssetRemove}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@ export enum AssetsOfEntity {
|
|||||||
|
|
||||||
export interface AssetsTabsProps {
|
export interface AssetsTabsProps {
|
||||||
onAddAsset: () => void;
|
onAddAsset: () => void;
|
||||||
|
onRemoveAsset?: () => void;
|
||||||
|
entityFqn?: string;
|
||||||
permissions: OperationPermission;
|
permissions: OperationPermission;
|
||||||
assetCount: number;
|
assetCount: number;
|
||||||
onAssetClick?: (asset?: EntityDetailsObjectInterface) => void;
|
onAssetClick?: (asset?: EntityDetailsObjectInterface) => void;
|
||||||
|
@ -119,6 +119,8 @@ export const pagingObject = { after: '', before: '', total: 0 };
|
|||||||
|
|
||||||
export const ONLY_NUMBER_REGEX = /^[0-9\b]+$/;
|
export const ONLY_NUMBER_REGEX = /^[0-9\b]+$/;
|
||||||
|
|
||||||
|
export const ES_UPDATE_DELAY = 500;
|
||||||
|
|
||||||
export const globalSearchOptions = [
|
export const globalSearchOptions = [
|
||||||
{ value: '', label: t('label.all') },
|
{ value: '', label: t('label.all') },
|
||||||
{ value: SearchIndex.TABLE, label: t('label.table') },
|
{ value: SearchIndex.TABLE, label: t('label.table') },
|
||||||
|
@ -818,6 +818,7 @@
|
|||||||
"relevance": "Relevanz",
|
"relevance": "Relevanz",
|
||||||
"remove": "Entfernen",
|
"remove": "Entfernen",
|
||||||
"remove-entity": "{{entity}} entfernen",
|
"remove-entity": "{{entity}} entfernen",
|
||||||
|
"remove-lowecase": "remove",
|
||||||
"removed": "Entfernt",
|
"removed": "Entfernt",
|
||||||
"removing-user": "Benutzer entfernen",
|
"removing-user": "Benutzer entfernen",
|
||||||
"rename": "Umbenennen",
|
"rename": "Umbenennen",
|
||||||
|
@ -818,6 +818,7 @@
|
|||||||
"relevance": "Relevance",
|
"relevance": "Relevance",
|
||||||
"remove": "Remove",
|
"remove": "Remove",
|
||||||
"remove-entity": "Remove {{entity}}",
|
"remove-entity": "Remove {{entity}}",
|
||||||
|
"remove-lowecase": "remove",
|
||||||
"removed": "Removed",
|
"removed": "Removed",
|
||||||
"removing-user": "Removing User",
|
"removing-user": "Removing User",
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
|
@ -818,6 +818,7 @@
|
|||||||
"relevance": "Relevancia",
|
"relevance": "Relevancia",
|
||||||
"remove": "Eliminar",
|
"remove": "Eliminar",
|
||||||
"remove-entity": "Eliminar {{entity}}",
|
"remove-entity": "Eliminar {{entity}}",
|
||||||
|
"remove-lowecase": "remove",
|
||||||
"removed": "Eliminado",
|
"removed": "Eliminado",
|
||||||
"removing-user": "Eliminando usuario",
|
"removing-user": "Eliminando usuario",
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
|
@ -818,6 +818,7 @@
|
|||||||
"relevance": "Pertinence",
|
"relevance": "Pertinence",
|
||||||
"remove": "Retirer",
|
"remove": "Retirer",
|
||||||
"remove-entity": "Retirer un·e {{entity}}",
|
"remove-entity": "Retirer un·e {{entity}}",
|
||||||
|
"remove-lowecase": "remove",
|
||||||
"removed": "Retiré",
|
"removed": "Retiré",
|
||||||
"removing-user": "Retirer un Utilisateur",
|
"removing-user": "Retirer un Utilisateur",
|
||||||
"rename": "Renommer",
|
"rename": "Renommer",
|
||||||
|
@ -818,6 +818,7 @@
|
|||||||
"relevance": "Relevance",
|
"relevance": "Relevance",
|
||||||
"remove": "除外",
|
"remove": "除外",
|
||||||
"remove-entity": "{{entity}}を除外",
|
"remove-entity": "{{entity}}を除外",
|
||||||
|
"remove-lowecase": "remove",
|
||||||
"removed": "除外",
|
"removed": "除外",
|
||||||
"removing-user": "ユーザを除外する",
|
"removing-user": "ユーザを除外する",
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
|
@ -818,6 +818,7 @@
|
|||||||
"relevance": "Relevância",
|
"relevance": "Relevância",
|
||||||
"remove": "Remover",
|
"remove": "Remover",
|
||||||
"remove-entity": "Remover {{entity}}",
|
"remove-entity": "Remover {{entity}}",
|
||||||
|
"remove-lowecase": "remove",
|
||||||
"removed": "Removido",
|
"removed": "Removido",
|
||||||
"removing-user": "Removendo usuário",
|
"removing-user": "Removendo usuário",
|
||||||
"rename": "Rename",
|
"rename": "Rename",
|
||||||
|
@ -818,6 +818,7 @@
|
|||||||
"relevance": "Актуальность",
|
"relevance": "Актуальность",
|
||||||
"remove": "Удалить",
|
"remove": "Удалить",
|
||||||
"remove-entity": "Удалить {{entity}}",
|
"remove-entity": "Удалить {{entity}}",
|
||||||
|
"remove-lowecase": "remove",
|
||||||
"removed": "Удаленный",
|
"removed": "Удаленный",
|
||||||
"removing-user": "Удаление пользователя",
|
"removing-user": "Удаление пользователя",
|
||||||
"rename": "Переименовать",
|
"rename": "Переименовать",
|
||||||
|
@ -818,6 +818,7 @@
|
|||||||
"relevance": "相关性",
|
"relevance": "相关性",
|
||||||
"remove": "删除",
|
"remove": "删除",
|
||||||
"remove-entity": "删除{{entity}}",
|
"remove-entity": "删除{{entity}}",
|
||||||
|
"remove-lowecase": "remove",
|
||||||
"removed": "已删除",
|
"removed": "已删除",
|
||||||
"removing-user": "正在删除用户",
|
"removing-user": "正在删除用户",
|
||||||
"rename": "重命名",
|
"rename": "重命名",
|
||||||
|
@ -10,11 +10,15 @@
|
|||||||
* 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 { Operation } from 'fast-json-patch';
|
import { AxiosError } from 'axios';
|
||||||
|
import { compare, Operation } from 'fast-json-patch';
|
||||||
|
import { EntityDetailUnion } from 'Models';
|
||||||
import { MapPatchAPIResponse } from '../../components/Assets/AssetsSelectionModal/AssetSelectionModal.interface';
|
import { MapPatchAPIResponse } from '../../components/Assets/AssetsSelectionModal/AssetSelectionModal.interface';
|
||||||
import { AssetsOfEntity } from '../../components/Glossary/GlossaryTerms/tabs/AssetsTabs.interface';
|
import { AssetsOfEntity } from '../../components/Glossary/GlossaryTerms/tabs/AssetsTabs.interface';
|
||||||
import { EntityType } from '../../enums/entity.enum';
|
import { EntityType } from '../../enums/entity.enum';
|
||||||
import { SearchIndex } from '../../enums/search.enum';
|
import { SearchIndex } from '../../enums/search.enum';
|
||||||
|
import { Table } from '../../generated/entity/data/table';
|
||||||
|
import { Domain } from '../../generated/entity/domains/domain';
|
||||||
import {
|
import {
|
||||||
getDashboardByFqn,
|
getDashboardByFqn,
|
||||||
patchDashboardDetails,
|
patchDashboardDetails,
|
||||||
@ -57,6 +61,7 @@ import { getTableDetailsByFQN, patchTableDetails } from '../../rest/tableAPI';
|
|||||||
import { getTeamByName, patchTeamDetail } from '../../rest/teamsAPI';
|
import { getTeamByName, patchTeamDetail } from '../../rest/teamsAPI';
|
||||||
import { getTopicByFqn, patchTopicDetails } from '../../rest/topicsAPI';
|
import { getTopicByFqn, patchTopicDetails } from '../../rest/topicsAPI';
|
||||||
import { getServiceCategoryFromEntityType } from '../../utils/ServiceUtils';
|
import { getServiceCategoryFromEntityType } from '../../utils/ServiceUtils';
|
||||||
|
import { showErrorToast } from '../ToastUtils';
|
||||||
|
|
||||||
export const getAPIfromSource = (
|
export const getAPIfromSource = (
|
||||||
source: keyof MapPatchAPIResponse
|
source: keyof MapPatchAPIResponse
|
||||||
@ -198,3 +203,114 @@ export const getAssetsFields = (source: AssetsOfEntity) => {
|
|||||||
return 'dataProducts';
|
return 'dataProducts';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getJsonPatchObject = (entity: Table, activeEntity: Domain) => {
|
||||||
|
let patchObj;
|
||||||
|
if (activeEntity) {
|
||||||
|
const { id, description, fullyQualifiedName, name, displayName } =
|
||||||
|
activeEntity;
|
||||||
|
patchObj = {
|
||||||
|
id,
|
||||||
|
description,
|
||||||
|
fullyQualifiedName,
|
||||||
|
name,
|
||||||
|
displayName,
|
||||||
|
type: 'domain',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const jsonPatch = compare(entity, {
|
||||||
|
...entity,
|
||||||
|
domain: patchObj,
|
||||||
|
});
|
||||||
|
|
||||||
|
return jsonPatch;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateDomainAssets = async (
|
||||||
|
activeEntity: EntityDetailUnion | undefined,
|
||||||
|
type: AssetsOfEntity,
|
||||||
|
selectedItems: Map<string, EntityDetailUnion>
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const entityDetails = [...(selectedItems?.values() ?? [])].map((item) =>
|
||||||
|
getEntityAPIfromSource(item.entityType)(
|
||||||
|
item.fullyQualifiedName,
|
||||||
|
getAssetsFields(type)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const entityDetailsResponse = await Promise.allSettled(entityDetails);
|
||||||
|
const map = new Map();
|
||||||
|
|
||||||
|
entityDetailsResponse.forEach((response) => {
|
||||||
|
if (response.status === 'fulfilled') {
|
||||||
|
const entity = response.value;
|
||||||
|
entity && map.set(entity.fullyQualifiedName, entity);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const patchAPIPromises = [...(selectedItems?.values() ?? [])]
|
||||||
|
.map((item) => {
|
||||||
|
if (map.has(item.fullyQualifiedName)) {
|
||||||
|
const entity = map.get(item.fullyQualifiedName);
|
||||||
|
const jsonPatch = getJsonPatchObject(entity, activeEntity as Domain);
|
||||||
|
const api = getAPIfromSource(item.entityType);
|
||||||
|
|
||||||
|
return api(item.id, jsonPatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
await Promise.all(patchAPIPromises);
|
||||||
|
} catch (err) {
|
||||||
|
showErrorToast(err as AxiosError);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const removeGlossaryTermAssets = async (
|
||||||
|
entityFqn: string,
|
||||||
|
type: AssetsOfEntity,
|
||||||
|
selectedItems: Map<string, EntityDetailUnion>
|
||||||
|
) => {
|
||||||
|
const entityDetails = [...(selectedItems?.values() ?? [])].map((item) =>
|
||||||
|
getEntityAPIfromSource(item.entityType)(
|
||||||
|
item.fullyQualifiedName,
|
||||||
|
getAssetsFields(type)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const entityDetailsResponse = await Promise.allSettled(entityDetails);
|
||||||
|
const map = new Map();
|
||||||
|
entityDetailsResponse.forEach((response) => {
|
||||||
|
if (response.status === 'fulfilled') {
|
||||||
|
const entity = response.value;
|
||||||
|
entity && map.set(entity.fullyQualifiedName, (entity as Table).tags);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const patchAPIPromises = [...(selectedItems?.values() ?? [])]
|
||||||
|
.map((item) => {
|
||||||
|
if (map.has(item.fullyQualifiedName)) {
|
||||||
|
const jsonPatch = compare(
|
||||||
|
{ tags: map.get(item.fullyQualifiedName) },
|
||||||
|
{
|
||||||
|
tags: (item.tags ?? []).filter(
|
||||||
|
(tag: EntityDetailUnion) => tag.tagFQN !== entityFqn
|
||||||
|
),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const api = getAPIfromSource(item.entityType);
|
||||||
|
|
||||||
|
return api(item.id, jsonPatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
|
await Promise.all(patchAPIPromises);
|
||||||
|
} catch (err) {
|
||||||
|
showErrorToast(err as AxiosError);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -113,7 +113,35 @@ export const getUserNames = (
|
|||||||
return getOwner(hasPermission, getEntityName(entity.owner), entity.owner);
|
return getOwner(hasPermission, getEntityName(entity.owner), entity.owner);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getQueryFilterToIncludeDomain = (fqn: string) => ({
|
export const getQueryFilterToIncludeDomain = (
|
||||||
|
domainFqn: string,
|
||||||
|
dataProductFqn: string
|
||||||
|
) => ({
|
||||||
|
query: {
|
||||||
|
bool: {
|
||||||
|
must: [
|
||||||
|
{
|
||||||
|
term: {
|
||||||
|
'domain.fullyQualifiedName': domainFqn,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
bool: {
|
||||||
|
must_not: [
|
||||||
|
{
|
||||||
|
term: {
|
||||||
|
'dataProducts.fullyQualifiedName': dataProductFqn,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getQueryFilterToExcludeDomainTerms = (fqn: string) => ({
|
||||||
query: {
|
query: {
|
||||||
bool: {
|
bool: {
|
||||||
must: [
|
must: [
|
||||||
@ -121,8 +149,12 @@ export const getQueryFilterToIncludeDomain = (fqn: string) => ({
|
|||||||
bool: {
|
bool: {
|
||||||
must: [
|
must: [
|
||||||
{
|
{
|
||||||
term: {
|
bool: {
|
||||||
'domain.fullyQualifiedName': fqn,
|
must_not: {
|
||||||
|
term: {
|
||||||
|
'domain.fullyQualifiedName': fqn,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user