diff --git a/openmetadata-ui/src/main/resources/ui/cypress/common/common.js b/openmetadata-ui/src/main/resources/ui/cypress/common/common.js
index 71310e07eda6..1d8cc779bacf 100644
--- a/openmetadata-ui/src/main/resources/ui/cypress/common/common.js
+++ b/openmetadata-ui/src/main/resources/ui/cypress/common/common.js
@@ -623,7 +623,9 @@ export const addNewTagToEntity = (entityObj, term) => {
entityObj.entity
);
cy.wait(500);
- cy.get('[data-testid="entity-tags"] [data-testid="add-tag"]')
+ cy.get(
+ '[data-testid="classification-tags-0"] [data-testid="entity-tags"] [data-testid="add-tag"]'
+ )
.eq(0)
.should('be.visible')
.scrollIntoView()
@@ -640,34 +642,8 @@ export const addNewTagToEntity = (entityObj, term) => {
.scrollIntoView()
.should('be.visible')
.click();
- cy.get('[data-testid="tags-container"] [data-testid="entity-tags"]')
+ cy.get('[data-testid="classification-tags-0"] [data-testid="tags-container"]')
.scrollIntoView()
- .should('be.visible')
- .contains(term);
-
- cy.get('[data-testid="classification-tags-0"] [data-testid="tag-container"]')
- .scrollIntoView()
- .contains('Add')
- .should('be.visible')
- .click();
-
- cy.get('[data-testid="tag-selector"]')
- .scrollIntoView()
- .should('be.visible')
- .type(term);
- cy.wait(500);
- cy.get('.ant-select-item-option-content')
- .contains(term)
- .should('be.visible')
- .click();
- // to close popup
- cy.clickOutside();
-
- cy.get('[data-testid="saveAssociatedTag"]')
- .scrollIntoView()
- .should('be.visible')
- .click();
- cy.get('[data-testid="classification-tags-0"] [data-testid="tag-container"]')
.contains(term)
.should('exist');
};
diff --git a/openmetadata-ui/src/main/resources/ui/cypress/constants/tagsAddRemove.constants.js b/openmetadata-ui/src/main/resources/ui/cypress/constants/tagsAddRemove.constants.js
index 898342bd94ea..26f3e5ffc8d8 100644
--- a/openmetadata-ui/src/main/resources/ui/cypress/constants/tagsAddRemove.constants.js
+++ b/openmetadata-ui/src/main/resources/ui/cypress/constants/tagsAddRemove.constants.js
@@ -18,7 +18,7 @@ export const TAGS_ADD_REMOVE_ENTITIES = [
entity: 'tables',
serviceName: 'sample_data',
fieldName: 'SKU',
- tags: ['PersonalData.Personal', 'PII.Sensitive'],
+ tags: ['Personal', 'Sensitive'],
entityTags: 'Personal',
},
{
@@ -27,7 +27,7 @@ export const TAGS_ADD_REMOVE_ENTITIES = [
entity: 'topics',
serviceName: 'sample_kafka',
fieldName: 'AddressBook',
- tags: ['PersonalData.Personal', 'PII.Sensitive'],
+ tags: ['Personal', 'Sensitive'],
entityTags: 'Personal',
},
{
@@ -37,7 +37,7 @@ export const TAGS_ADD_REMOVE_ENTITIES = [
insideEntity: 'charts',
serviceName: 'sample_superset',
fieldName: 'e3cfd274-44f8-4bf3-b75d-d40cf88869ba',
- tags: ['PersonalData.Personal', 'PII.Sensitive'],
+ tags: ['Personal', 'Sensitive'],
entityTags: 'Personal',
},
{
@@ -46,7 +46,7 @@ export const TAGS_ADD_REMOVE_ENTITIES = [
entity: 'pipelines',
serviceName: 'sample_airflow',
fieldName: 'dim_address_task',
- tags: ['PersonalData.Personal', 'PII.Sensitive'],
+ tags: ['Personal', 'Sensitive'],
entityTags: 'Personal',
},
{
@@ -55,7 +55,7 @@ export const TAGS_ADD_REMOVE_ENTITIES = [
entity: 'mlmodels',
serviceName: 'mlflow_svc',
fieldName: 'sales',
- tags: ['PersonalData.Personal', 'PII.Sensitive'],
+ tags: ['Personal', 'Sensitive'],
entityTags: 'Personal',
},
];
diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/TagsAddRemove.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/TagsAddRemove.spec.js
index 6dc7a497b5fd..0c7da7d6bf33 100644
--- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/TagsAddRemove.spec.js
+++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Flow/TagsAddRemove.spec.js
@@ -18,20 +18,14 @@ import {
} from '../../common/common';
import { TAGS_ADD_REMOVE_ENTITIES } from '../../constants/tagsAddRemove.constants';
-const addTags = (tag, parent) => {
+const addTags = (tag) => {
cy.get('[data-testid="tag-selector"]')
.scrollIntoView()
.should('be.visible')
.click()
.type(tag);
- if (parent) {
- cy.get(`[title="${tag}"]`).should('be.visible').click();
- } else {
- cy.get('.ant-select-item-option-content')
- .should('be.visible')
- .click({ multiple: true });
- }
+ cy.get(`[title="${tag}"]`).should('be.visible').click();
cy.get('[data-testid="tag-selector"] > .ant-select-selector').contains(tag);
};
@@ -40,18 +34,22 @@ const checkTags = (tag, checkForParentEntity) => {
cy.get(
'[data-testid="entity-right-panel"] [data-testid="tags-container"] [data-testid="entity-tags"] '
)
-
.scrollIntoView()
- .should('be.visible')
.contains(tag);
} else {
- cy.get(`[data-testid="tag-${tag}"]`).should('be.visible');
+ cy.get(
+ '[data-testid="classification-tags-0"] [data-testid="tags-container"] [data-testid="entity-tags"] '
+ )
+ .scrollIntoView()
+ .contains(tag);
}
};
const removeTags = (checkForParentEntity) => {
if (checkForParentEntity) {
- cy.get('[data-testid="entity-right-panel"] [data-testid="edit-button"]')
+ cy.get(
+ '[data-testid="entity-right-panel"] [data-testid="tags-container"] [data-testid="edit-button"]'
+ )
.scrollIntoView()
.should('be.visible')
.click();
@@ -93,7 +91,7 @@ describe('Check if tags addition and removal flow working properly from tables',
.should('be.visible')
.click();
- addTags(entityDetails.entityTags, true);
+ addTags(entityDetails.entityTags);
interceptURL('PATCH', `/api/v1/${entityDetails.entity}/*`, 'tagsChange');
@@ -113,9 +111,8 @@ describe('Check if tags addition and removal flow working properly from tables',
.click();
} else {
cy.get(
- `.ant-table-tbody [data-testid="tag-container"] [data-testid="add-tag"]`
+ `.ant-table-tbody [data-testid="classification-tags-0"] [data-testid="tags-container"] [data-testid="entity-tags"]`
)
- .eq(0)
.scrollIntoView()
.should('be.visible')
.click();
diff --git a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Tags.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Tags.spec.js
index aaa5c73a42e0..ec405933cefa 100644
--- a/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Tags.spec.js
+++ b/openmetadata-ui/src/main/resources/ui/cypress/e2e/Pages/Tags.spec.js
@@ -233,7 +233,7 @@ describe('Tags page should work', () => {
});
it('Use newly created tag to any entity should work', () => {
- const entity = SEARCH_ENTITY_TABLE.table_1;
+ const entity = SEARCH_ENTITY_TABLE.table_3;
addNewTagToEntity(entity, `${NEW_TAG.name}`);
});
@@ -251,7 +251,7 @@ describe('Tags page should work', () => {
);
interceptURL('PATCH', '/api/v1/databaseSchemas/*', 'addTags');
- const entity = SEARCH_ENTITY_TABLE.table_2;
+ const entity = SEARCH_ENTITY_TABLE.table_3;
const tag = 'Sensitive';
visitEntityDetailsPage(entity.term, entity.serviceName, entity.entity);
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ContainerDetail/ContainerDataModel/ContainerDataModel.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ContainerDetail/ContainerDataModel/ContainerDataModel.test.tsx
index 875a6190fa72..6baf02ebd071 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/ContainerDetail/ContainerDataModel/ContainerDataModel.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/ContainerDetail/ContainerDataModel/ContainerDataModel.test.tsx
@@ -75,14 +75,14 @@ const props = {
onUpdate: jest.fn(),
};
-jest.mock('../../../utils/TagsUtils', () => ({
- getClassifications: jest.fn().mockReturnValue([]),
- getTaglist: jest.fn().mockReturnValue([]),
+jest.mock('utils/TagsUtils', () => ({
+ getAllTagsList: jest.fn(() => Promise.resolve([])),
+ getTagsHierarchy: jest.fn().mockReturnValue([]),
}));
jest.mock('utils/GlossaryUtils', () => ({
- fetchGlossaryTerms: jest.fn().mockReturnValue([]),
- getGlossaryTermlist: jest.fn().mockReturnValue([]),
+ getGlossaryTermsList: jest.fn(() => Promise.resolve([])),
+ getGlossaryTermHierarchy: jest.fn().mockReturnValue([]),
}));
jest.mock('utils/TableTags/TableTags.utils', () => ({
@@ -122,6 +122,14 @@ jest.mock('components/TableTags/TableTags.component', () =>
))
);
+jest.mock('components/common/error-with-placeholder/ErrorPlaceHolder', () =>
+ jest
+ .fn()
+ .mockImplementation(() => (
+
ErrorPlaceHolder
+ ))
+);
+
describe('ContainerDataModel', () => {
it('Should render the Container data model component', async () => {
render();
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/ContainerDetail/ContainerDataModel/ContainerDataModel.tsx b/openmetadata-ui/src/main/resources/ui/src/components/ContainerDetail/ContainerDataModel/ContainerDataModel.tsx
index 538b51efd332..e7e0be7c78c9 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/ContainerDetail/ContainerDataModel/ContainerDataModel.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/ContainerDetail/ContainerDataModel/ContainerDataModel.tsx
@@ -17,6 +17,10 @@ import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlac
import RichTextEditorPreviewer from 'components/common/rich-text-editor/RichTextEditorPreviewer';
import { ModalWithMarkdownEditor } from 'components/Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
import TableTags from 'components/TableTags/TableTags.component';
+import {
+ GlossaryTermDetailsProps,
+ TagsDetailsProps,
+} from 'components/Tag/TagsContainerV1/TagsContainerV1.interface';
import { Column, TagLabel } from 'generated/entity/data/container';
import { TagSource } from 'generated/type/tagLabel';
import { cloneDeep, isEmpty, isUndefined, map, toLower } from 'lodash';
@@ -28,10 +32,12 @@ import {
updateContainerColumnTags,
} from 'utils/ContainerDetailUtils';
import { getEntityName } from 'utils/EntityUtils';
-import { fetchGlossaryTerms, getGlossaryTermlist } from 'utils/GlossaryUtils';
-import { getFilterTags } from 'utils/TableTags/TableTags.utils';
+import {
+ getGlossaryTermHierarchy,
+ getGlossaryTermsList,
+} from 'utils/GlossaryUtils';
import { getTableExpandableConfig } from 'utils/TableUtils';
-import { getClassifications, getTaglist } from 'utils/TagsUtils';
+import { getAllTagsList, getTagsHierarchy } from 'utils/TagsUtils';
import {
CellRendered,
ContainerDataModelProps,
@@ -52,18 +58,18 @@ const ContainerDataModel: FC = ({
const [isTagLoading, setIsTagLoading] = useState(false);
const [isGlossaryLoading, setIsGlossaryLoading] = useState(false);
const [tagFetchFailed, setTagFetchFailed] = useState(false);
- const [glossaryTags, setGlossaryTags] = useState([]);
- const [classificationTags, setClassificationTags] = useState([]);
+ const [glossaryTags, setGlossaryTags] = useState(
+ []
+ );
+ const [classificationTags, setClassificationTags] = useState<
+ TagsDetailsProps[]
+ >([]);
const fetchGlossaryTags = async () => {
setIsGlossaryLoading(true);
try {
- const res = await fetchGlossaryTerms();
-
- const glossaryTerms: TagOption[] = getGlossaryTermlist(res).map(
- (tag) => ({ fqn: tag, source: TagSource.Glossary })
- );
- setGlossaryTags(glossaryTerms);
+ const glossaryTermList = await getGlossaryTermsList();
+ setGlossaryTags(glossaryTermList);
} catch {
setTagFetchFailed(true);
} finally {
@@ -74,15 +80,8 @@ const ContainerDataModel: FC = ({
const fetchClassificationTags = async () => {
setIsTagLoading(true);
try {
- const res = await getClassifications();
- const tagList = await getTaglist(res.data);
-
- const classificationTag: TagOption[] = map(tagList, (tag) => ({
- fqn: tag,
- source: TagSource.Classification,
- }));
-
- setClassificationTags(classificationTag);
+ const tags = await getAllTagsList();
+ setClassificationTags(tags);
} catch {
setTagFetchFailed(true);
} finally {
@@ -91,15 +90,11 @@ const ContainerDataModel: FC = ({
};
const handleFieldTagsChange = useCallback(
- async (
- selectedTags: EntityTags[],
- editColumnTag: Column,
- otherTags: TagLabel[]
- ) => {
- const newSelectedTags: TagOption[] = map(
- [...selectedTags, ...otherTags],
- (tag) => ({ fqn: tag.tagFQN, source: tag.source })
- );
+ async (selectedTags: EntityTags[], editColumnTag: Column) => {
+ const newSelectedTags: TagOption[] = map(selectedTags, (tag) => ({
+ fqn: tag.tagFQN,
+ source: tag.source,
+ }));
if (newSelectedTags && editColumnTag) {
const containerDataModel = cloneDeep(dataModel);
@@ -233,8 +228,8 @@ const ContainerDataModel: FC = ({
isTagLoading={isTagLoading}
record={record}
tagFetchFailed={tagFetchFailed}
- tagList={classificationTags}
- tags={getFilterTags(tags)}
+ tagList={getTagsHierarchy(classificationTags)}
+ tags={tags}
type={TagSource.Classification}
/>
),
@@ -256,8 +251,8 @@ const ContainerDataModel: FC = ({
isTagLoading={isGlossaryLoading}
record={record}
tagFetchFailed={tagFetchFailed}
- tagList={glossaryTags}
- tags={getFilterTags(tags)}
+ tagList={getGlossaryTermHierarchy(glossaryTags)}
+ tags={tags}
type={TagSource.Glossary}
/>
),
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DashboardDetails/DashboardDetails.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DashboardDetails/DashboardDetails.component.tsx
index 47c9b4432075..2b7ef544489d 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/DashboardDetails/DashboardDetails.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/DashboardDetails/DashboardDetails.component.tsx
@@ -27,6 +27,10 @@ import { EntityName } from 'components/Modals/EntityNameModal/EntityNameModal.in
import TableTags from 'components/TableTags/TableTags.component';
import TabsLabel from 'components/TabsLabel/TabsLabel.component';
import TagsContainerV1 from 'components/Tag/TagsContainerV1/TagsContainerV1';
+import {
+ GlossaryTermDetailsProps,
+ TagsDetailsProps,
+} from 'components/Tag/TagsContainerV1/TagsContainerV1.interface';
import { getDashboardDetailsPath } from 'constants/constants';
import { compare } from 'fast-json-patch';
import { TagSource } from 'generated/type/schema';
@@ -37,7 +41,11 @@ import { useTranslation } from 'react-i18next';
import { useHistory, useParams } from 'react-router-dom';
import { restoreDashboard } from 'rest/dashboardAPI';
import { getEntityName, getEntityThreadLink } from 'utils/EntityUtils';
-import { getFilterTags } from 'utils/TableTags/TableTags.utils';
+import {
+ getGlossaryTermHierarchy,
+ getGlossaryTermsList,
+} from 'utils/GlossaryUtils';
+import { getAllTagsList, getTagsHierarchy } from 'utils/TagsUtils';
import { ReactComponent as ExternalLinkIcon } from '../../assets/svg/external-links.svg';
import { EntityField } from '../../constants/Feeds.constants';
import { EntityTabs, EntityType } from '../../enums/entity.enum';
@@ -46,13 +54,8 @@ import { ThreadType } from '../../generated/entity/feed/thread';
import { LabelType, State, TagLabel } from '../../generated/type/tagLabel';
import { getCurrentUserId, refreshPage } from '../../utils/CommonUtils';
import { getEntityFieldThreadCounts } from '../../utils/FeedUtils';
-import {
- fetchGlossaryTerms,
- getGlossaryTermlist,
-} from '../../utils/GlossaryUtils';
import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils';
import { getTagsWithoutTier, getTierTags } from '../../utils/TableUtils';
-import { getClassifications, getTaglist } from '../../utils/TagsUtils';
import { showErrorToast, showSuccessToast } from '../../utils/ToastUtils';
import ActivityThreadPanel from '../ActivityFeed/ActivityThreadPanel/ActivityThreadPanel';
import { CustomPropertyTable } from '../common/CustomPropertyTable/CustomPropertyTable';
@@ -110,8 +113,12 @@ const DashboardDetails = ({
Array
>([]);
- const [glossaryTags, setGlossaryTags] = useState([]);
- const [classificationTags, setClassificationTags] = useState([]);
+ const [glossaryTags, setGlossaryTags] = useState(
+ []
+ );
+ const [classificationTags, setClassificationTags] = useState<
+ TagsDetailsProps[]
+ >([]);
const {
owner,
@@ -204,12 +211,8 @@ const DashboardDetails = ({
const fetchGlossaryTags = async () => {
setIsGlossaryLoading(true);
try {
- const res = await fetchGlossaryTerms();
-
- const glossaryTerms: TagOption[] = getGlossaryTermlist(res).map(
- (tag) => ({ fqn: tag, source: TagSource.Glossary })
- );
- setGlossaryTags(glossaryTerms);
+ const glossaryTermList = await getGlossaryTermsList();
+ setGlossaryTags(glossaryTermList);
} catch {
setTagFetchFailed(true);
} finally {
@@ -220,15 +223,8 @@ const DashboardDetails = ({
const fetchClassificationTags = async () => {
setIsTagLoading(true);
try {
- const res = await getClassifications();
- const tagList = await getTaglist(res.data);
-
- const classificationTag: TagOption[] = map(tagList, (tag) => ({
- fqn: tag,
- source: TagSource.Classification,
- }));
-
- setClassificationTags(classificationTag);
+ const tags = await getAllTagsList();
+ setClassificationTags(tags);
} catch {
setTagFetchFailed(true);
} finally {
@@ -371,14 +367,13 @@ const DashboardDetails = ({
const handleChartTagSelection = async (
selectedTags: Array,
- editColumnTag: ChartType,
- otherTags: TagLabel[]
+ editColumnTag: ChartType
) => {
if (selectedTags && editColumnTag) {
- const newSelectedTags: TagOption[] = map(
- [...selectedTags, ...otherTags],
- (tag) => ({ fqn: tag.tagFQN, source: tag.source })
- );
+ const newSelectedTags: TagOption[] = map(selectedTags, (tag) => ({
+ fqn: tag.tagFQN,
+ source: tag.source,
+ }));
const prevTags = editColumnTag.tags?.filter((tag) =>
newSelectedTags.some((selectedTag) => selectedTag.fqn === tag.tagFQN)
@@ -546,8 +541,8 @@ const DashboardDetails = ({
isTagLoading={isTagLoading}
record={record}
tagFetchFailed={tagFetchFailed}
- tagList={classificationTags}
- tags={getFilterTags(tags)}
+ tagList={getTagsHierarchy(classificationTags)}
+ tags={tags}
type={TagSource.Classification}
/>
);
@@ -570,8 +565,8 @@ const DashboardDetails = ({
isTagLoading={isGlossaryLoading}
record={record}
tagFetchFailed={tagFetchFailed}
- tagList={glossaryTags}
- tags={getFilterTags(tags)}
+ tagList={getGlossaryTermHierarchy(glossaryTags)}
+ tags={tags}
type={TagSource.Glossary}
/>
),
@@ -651,8 +646,9 @@ const DashboardDetails = ({
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
entityType={EntityType.DASHBOARD}
permission={
- dashboardPermissions.EditAll ||
- dashboardPermissions.EditTags
+ (dashboardPermissions.EditAll ||
+ dashboardPermissions.EditTags) &&
+ !dashboardDetails.deleted
}
selectedTags={dashboardTags}
tagType={TagSource.Classification}
@@ -665,8 +661,9 @@ const DashboardDetails = ({
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
entityType={EntityType.DASHBOARD}
permission={
- dashboardPermissions.EditAll ||
- dashboardPermissions.EditTags
+ (dashboardPermissions.EditAll ||
+ dashboardPermissions.EditTags) &&
+ !dashboardDetails.deleted
}
selectedTags={dashboardTags}
tagType={TagSource.Glossary}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DashboardDetails/DashboardDetails.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DashboardDetails/DashboardDetails.test.tsx
index 7c39b3b5650f..0a734efa37b4 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/DashboardDetails/DashboardDetails.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/DashboardDetails/DashboardDetails.test.tsx
@@ -19,7 +19,6 @@ import {
} from '@testing-library/react';
import { EntityTabs } from 'enums/entity.enum';
import { ChartType } from 'generated/entity/data/chart';
-import { GlossaryTerm } from 'generated/entity/data/glossaryTerm';
import { mockGlossaryList } from 'mocks/Glossary.mock';
import { mockTagList } from 'mocks/Tags.mock';
import React from 'react';
@@ -162,24 +161,14 @@ jest.mock('../../utils/CommonUtils', () => ({
getOwnerValue: jest.fn().mockReturnValue('Owner'),
}));
-jest.mock('../../utils/GlossaryUtils', () => ({
- fetchGlossaryTerms: jest
- .fn()
- .mockImplementation(() => Promise.resolve(mockGlossaryList)),
- getGlossaryTermlist: jest.fn().mockImplementation((terms) => {
- return terms.map((term: GlossaryTerm) => term?.fullyQualifiedName);
- }),
+jest.mock('../../utils/TagsUtils', () => ({
+ getAllTagsList: jest.fn(() => Promise.resolve(mockTagList)),
+ getTagsHierarchy: jest.fn().mockReturnValue([]),
}));
-jest.mock('../../utils/TagsUtils', () => ({
- getClassifications: jest
- .fn()
- .mockImplementation(() => Promise.resolve({ data: mockTagList })),
- getTaglist: jest
- .fn()
- .mockImplementation(() =>
- Promise.resolve(['PersonalData.Personal', 'PersonalData.SpecialCategory'])
- ),
+jest.mock('../../utils/GlossaryUtils', () => ({
+ getGlossaryTermsList: jest.fn(() => Promise.resolve(mockGlossaryList)),
+ getGlossaryTermHierarchy: jest.fn().mockReturnValue([]),
}));
describe.skip('Test DashboardDetails component', () => {
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataModels/DataModelDetails.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataModels/DataModelDetails.component.tsx
index b50b937c075b..b9756f57e32d 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/DataModels/DataModelDetails.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/DataModels/DataModelDetails.component.tsx
@@ -181,7 +181,7 @@ const DataModelDetails = ({
entityFqn={dashboardDataModelFQN}
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
entityType={EntityType.DASHBOARD_DATA_MODEL}
- permission={hasEditTagsPermission}
+ permission={hasEditTagsPermission && !dataModelData.deleted}
selectedTags={tags}
tagType={TagSource.Classification}
onSelectionChange={handleTagSelection}
@@ -191,7 +191,7 @@ const DataModelDetails = ({
entityFqn={dashboardDataModelFQN}
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
entityType={EntityType.DASHBOARD_DATA_MODEL}
- permission={hasEditTagsPermission}
+ permission={hasEditTagsPermission && !dataModelData.deleted}
selectedTags={tags}
tagType={TagSource.Glossary}
onSelectionChange={handleTagSelection}
@@ -202,6 +202,7 @@ const DataModelDetails = ({
);
}, [
+ dataModelData,
description,
dashboardDataModelFQN,
entityFieldThreadCount,
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/DataModels/ModelTab/ModelTab.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/DataModels/ModelTab/ModelTab.component.tsx
index 2940a2ab1de3..94c11275f522 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/DataModels/ModelTab/ModelTab.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/DataModels/ModelTab/ModelTab.component.tsx
@@ -17,6 +17,10 @@ import RichTextEditorPreviewer from 'components/common/rich-text-editor/RichText
import { CellRendered } from 'components/ContainerDetail/ContainerDataModel/ContainerDataModel.interface';
import { ModalWithMarkdownEditor } from 'components/Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
import TableTags from 'components/TableTags/TableTags.component';
+import {
+ GlossaryTermDetailsProps,
+ TagsDetailsProps,
+} from 'components/Tag/TagsContainerV1/TagsContainerV1.interface';
import { Column } from 'generated/entity/data/dashboardDataModel';
import { TagLabel, TagSource } from 'generated/type/tagLabel';
import { cloneDeep, isUndefined, map } from 'lodash';
@@ -28,9 +32,11 @@ import {
updateDataModelColumnTags,
} from 'utils/DataModelsUtils';
import { getEntityName } from 'utils/EntityUtils';
-import { fetchGlossaryTerms, getGlossaryTermlist } from 'utils/GlossaryUtils';
-import { getFilterTags } from 'utils/TableTags/TableTags.utils';
-import { getClassifications, getTaglist } from 'utils/TagsUtils';
+import {
+ getGlossaryTermHierarchy,
+ getGlossaryTermsList,
+} from 'utils/GlossaryUtils';
+import { getAllTagsList, getTagsHierarchy } from 'utils/TagsUtils';
import { ModelTabProps } from './ModelTab.interface';
const ModelTab = ({
@@ -46,18 +52,18 @@ const ModelTab = ({
const [isGlossaryLoading, setIsGlossaryLoading] = useState(false);
const [tagFetchFailed, setTagFetchFailed] = useState(false);
- const [glossaryTags, setGlossaryTags] = useState([]);
- const [classificationTags, setClassificationTags] = useState([]);
+ const [glossaryTags, setGlossaryTags] = useState(
+ []
+ );
+ const [classificationTags, setClassificationTags] = useState<
+ TagsDetailsProps[]
+ >([]);
const fetchGlossaryTags = async () => {
setIsGlossaryLoading(true);
try {
- const res = await fetchGlossaryTerms();
-
- const glossaryTerms: TagOption[] = getGlossaryTermlist(res).map(
- (tag) => ({ fqn: tag, source: TagSource.Glossary })
- );
- setGlossaryTags(glossaryTerms);
+ const glossaryTermList = await getGlossaryTermsList();
+ setGlossaryTags(glossaryTermList);
} catch {
setTagFetchFailed(true);
} finally {
@@ -68,15 +74,8 @@ const ModelTab = ({
const fetchClassificationTags = async () => {
setIsTagLoading(true);
try {
- const res = await getClassifications();
- const tagList = await getTaglist(res.data);
-
- const classificationTag: TagOption[] = map(tagList, (tag) => ({
- fqn: tag,
- source: TagSource.Classification,
- }));
-
- setClassificationTags(classificationTag);
+ const tags = await getAllTagsList();
+ setClassificationTags(tags);
} catch {
setTagFetchFailed(true);
} finally {
@@ -85,15 +84,11 @@ const ModelTab = ({
};
const handleFieldTagsChange = useCallback(
- async (
- selectedTags: EntityTags[],
- editColumnTag: Column,
- otherTags: TagLabel[]
- ) => {
- const newSelectedTags: TagOption[] = map(
- [...selectedTags, ...otherTags],
- (tag) => ({ fqn: tag.tagFQN, source: tag.source })
- );
+ async (selectedTags: EntityTags[], editColumnTag: Column) => {
+ const newSelectedTags: TagOption[] = map(selectedTags, (tag) => ({
+ fqn: tag.tagFQN,
+ source: tag.source,
+ }));
const dataModelData = cloneDeep(data);
@@ -206,8 +201,8 @@ const ModelTab = ({
isTagLoading={isTagLoading}
record={record}
tagFetchFailed={tagFetchFailed}
- tagList={classificationTags}
- tags={getFilterTags(tags)}
+ tagList={getTagsHierarchy(classificationTags)}
+ tags={tags}
type={TagSource.Classification}
/>
),
@@ -229,8 +224,8 @@ const ModelTab = ({
isTagLoading={isGlossaryLoading}
record={record}
tagFetchFailed={tagFetchFailed}
- tagList={glossaryTags}
- tags={getFilterTags(tags)}
+ tagList={getGlossaryTermHierarchy(glossaryTags)}
+ tags={tags}
type={TagSource.Glossary}
/>
),
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.component.tsx
index cbf0590dd1a5..781a0824bcea 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.component.tsx
@@ -16,6 +16,10 @@ import { ColumnsType } from 'antd/lib/table';
import { ReactComponent as IconEdit } from 'assets/svg/edit-new.svg';
import FilterTablePlaceHolder from 'components/common/error-with-placeholder/FilterTablePlaceHolder';
import TableTags from 'components/TableTags/TableTags.component';
+import {
+ GlossaryTermDetailsProps,
+ TagsDetailsProps,
+} from 'components/Tag/TagsContainerV1/TagsContainerV1.interface';
import { LabelType, State, TagSource } from 'generated/type/schema';
import {
cloneDeep,
@@ -31,7 +35,11 @@ import { EntityTags, TagOption } from 'Models';
import React, { Fragment, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useHistory } from 'react-router-dom';
-import { getFilterTags } from 'utils/TableTags/TableTags.utils';
+import {
+ getGlossaryTermHierarchy,
+ getGlossaryTermsList,
+} from 'utils/GlossaryUtils';
+import { getAllTagsList, getTagsHierarchy } from 'utils/TagsUtils';
import { ReactComponent as IconRequest } from '../../assets/svg/request-icon.svg';
import { FQN_SEPARATOR_CHAR } from '../../constants/char.constants';
import { EntityField } from '../../constants/Feeds.constants';
@@ -47,17 +55,12 @@ import {
getFrequentlyJoinedColumns,
} from '../../utils/EntityUtils';
import { getFieldThreadElement } from '../../utils/FeedElementUtils';
-import {
- fetchGlossaryTerms,
- getGlossaryTermlist,
-} from '../../utils/GlossaryUtils';
import {
getDataTypeString,
getTableExpandableConfig,
makeData,
prepareConstraintIcon,
} from '../../utils/TableUtils';
-import { getClassifications, getTaglist } from '../../utils/TagsUtils';
import {
getRequestDescriptionPath,
getRequestTagsPath,
@@ -87,8 +90,12 @@ const EntityTable = ({
const { t } = useTranslation();
const [searchedColumns, setSearchedColumns] = useState([]);
- const [glossaryTags, setGlossaryTags] = useState([]);
- const [classificationTags, setClassificationTags] = useState([]);
+ const [glossaryTags, setGlossaryTags] = useState(
+ []
+ );
+ const [classificationTags, setClassificationTags] = useState<
+ TagsDetailsProps[]
+ >([]);
const sortByOrdinalPosition = useMemo(
() => sortBy(tableColumns, 'ordinalPosition'),
@@ -112,12 +119,8 @@ const EntityTable = ({
const fetchGlossaryTags = async () => {
setIsGlossaryLoading(true);
try {
- const res = await fetchGlossaryTerms();
-
- const glossaryTerms: TagOption[] = getGlossaryTermlist(res).map(
- (tag) => ({ fqn: tag, source: TagSource.Glossary })
- );
- setGlossaryTags(glossaryTerms);
+ const glossaryTermList = await getGlossaryTermsList();
+ setGlossaryTags(glossaryTermList);
} catch {
setTagFetchFailed(true);
} finally {
@@ -128,15 +131,8 @@ const EntityTable = ({
const fetchClassificationTags = async () => {
setIsTagLoading(true);
try {
- const res = await getClassifications();
- const tagList = await getTaglist(res.data);
-
- const classificationTag: TagOption[] = map(tagList, (tag) => ({
- fqn: tag,
- source: TagSource.Classification,
- }));
-
- setClassificationTags(classificationTag);
+ const tags = await getAllTagsList();
+ setClassificationTags(tags);
} catch {
setTagFetchFailed(true);
} finally {
@@ -233,13 +229,12 @@ const EntityTable = ({
const handleTagSelection = async (
selectedTags: EntityTags[],
- editColumnTag: Column,
- otherTags: TagLabel[]
+ editColumnTag: Column
) => {
- const newSelectedTags: TagOption[] = map(
- [...selectedTags, ...otherTags],
- (tag) => ({ fqn: tag.tagFQN, source: tag.source })
- );
+ const newSelectedTags: TagOption[] = map(selectedTags, (tag) => ({
+ fqn: tag.tagFQN,
+ source: tag.source,
+ }));
if (newSelectedTags && editColumnTag) {
const tableCols = cloneDeep(tableColumns);
updateColumnTags(
@@ -543,8 +538,8 @@ const EntityTable = ({
isTagLoading={isTagLoading}
record={record}
tagFetchFailed={tagFetchFailed}
- tagList={classificationTags}
- tags={getFilterTags(tags)}
+ tagList={getTagsHierarchy(classificationTags)}
+ tags={tags}
type={TagSource.Classification}
onRequestTagsHandler={onRequestTagsHandler}
onThreadLinkSelect={onThreadLinkSelect}
@@ -574,8 +569,8 @@ const EntityTable = ({
isTagLoading={isGlossaryLoading}
record={record}
tagFetchFailed={tagFetchFailed}
- tagList={glossaryTags}
- tags={getFilterTags(tags)}
+ tagList={getGlossaryTermHierarchy(glossaryTags)}
+ tags={tags}
type={TagSource.Glossary}
onRequestTagsHandler={onRequestTagsHandler}
onThreadLinkSelect={onThreadLinkSelect}
@@ -598,7 +593,6 @@ const EntityTable = ({
fetchGlossaryTags,
getColumnName,
handleTagSelection,
- getFilterTags,
hasTagEditAccess,
isReadOnly,
tagFetchFailed,
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.interface.ts
index 6e051867e783..dfd2db1b413b 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.interface.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.interface.ts
@@ -21,7 +21,7 @@ export interface EntityTableProps {
joins: Array;
columnName: string;
hasDescriptionEditAccess?: boolean;
- hasTagEditAccess?: boolean;
+ hasTagEditAccess: boolean;
tableConstraints: Table['tableConstraints'];
searchText?: string;
isReadOnly?: boolean;
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.test.tsx
index 0a0ef99f8327..47beed656492 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/EntityTable/EntityTable.test.tsx
@@ -16,7 +16,6 @@ import { TagOption } from 'Models';
import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { Column } from '../../generated/api/data/createTable';
-import { GlossaryTerm } from '../../generated/entity/data/glossaryTerm';
import { Table } from '../../generated/entity/data/table';
import EntityTableV1 from './EntityTable.component';
@@ -112,62 +111,13 @@ const mockEntityTableProp = {
entityFqn: 'bigquery_gcp.ecommerce.shopify.raw_product_catalog',
owner: {} as Table['owner'],
columnName: '',
+ hasTagEditAccess: true,
tableConstraints: mockTableConstraints,
onEntityFieldSelect,
onThreadLinkSelect,
onUpdate,
};
-const mockTagList = [
- {
- id: 'tagCatId1',
- name: 'TagCat1',
- description: '',
- children: [
- {
- id: 'tagId1',
- name: 'Tag1',
- fullyQualifiedName: 'TagCat1.Tag1',
- description: '',
- deprecated: false,
- deleted: false,
- },
- ],
- },
- {
- id: 'tagCatId2',
- name: 'TagCat2',
- description: '',
- children: [
- {
- id: 'tagId2',
- name: 'Tag2',
- fullyQualifiedName: 'TagCat2.Tag2',
- description: '',
- deprecated: false,
- deleted: false,
- },
- ],
- },
-];
-
-const mockGlossaryList = [
- {
- name: 'Tag1',
- displayName: 'Tag1',
- fullyQualifiedName: 'Glossary.Tag1',
- type: 'glossaryTerm',
- id: 'glossaryTagId1',
- },
- {
- name: 'Tag2',
- displayName: 'Tag2',
- fullyQualifiedName: 'Glossary.Tag2',
- type: 'glossaryTerm',
- id: 'glossaryTagId2',
- },
-];
-
jest.mock('../../hooks/authHooks', () => {
return {
useAuth: jest.fn().mockReturnValue({
@@ -205,17 +155,27 @@ jest.mock('components/Tag/Tags/tags', () => {
return jest.fn().mockReturnValue(Tag
);
});
-jest.mock('../../utils/GlossaryUtils', () => ({
- fetchGlossaryTerms: jest.fn(() => Promise.resolve(mockGlossaryList)),
- getGlossaryTermlist: jest.fn((terms) => {
- return terms.map((term: GlossaryTerm) => term?.fullyQualifiedName);
- }),
+jest.mock('../../utils/TagsUtils', () => ({
+ getAllTagsList: jest.fn(() => Promise.resolve([])),
+ getTagsHierarchy: jest.fn().mockReturnValue([]),
}));
-jest.mock('../../utils/TagsUtils', () => ({
- getClassifications: jest.fn(() => Promise.resolve({ data: mockTagList })),
+jest.mock('../../utils/GlossaryUtils', () => ({
+ getGlossaryTermsList: jest.fn(() => Promise.resolve([])),
+ getGlossaryTermHierarchy: jest.fn().mockReturnValue([]),
}));
+jest.mock(
+ 'components/common/error-with-placeholder/FilterTablePlaceHolder',
+ () => {
+ return jest.fn().mockReturnValue(FilterTablePlaceHolder
);
+ }
+);
+
+jest.mock('components/TableTags/TableTags.component', () => {
+ return jest.fn().mockReturnValue(TableTags
);
+});
+
describe('Test EntityTable Component', () => {
it('Initially, Table should load', async () => {
render(, {
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MlModelDetail/MlModelDetail.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MlModelDetail/MlModelDetail.component.tsx
index 57c703e9c9dc..abdd28105ee9 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/MlModelDetail/MlModelDetail.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/MlModelDetail/MlModelDetail.component.tsx
@@ -398,7 +398,9 @@ const MlModelDetail: FC = ({
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
entityType={EntityType.MLMODEL}
permission={
- mlModelPermissions.EditAll || mlModelPermissions.EditTags
+ (mlModelPermissions.EditAll ||
+ mlModelPermissions.EditTags) &&
+ !mlModelDetail.deleted
}
selectedTags={mlModelTags}
tagType={TagSource.Classification}
@@ -411,7 +413,9 @@ const MlModelDetail: FC = ({
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
entityType={EntityType.MLMODEL}
permission={
- mlModelPermissions.EditAll || mlModelPermissions.EditTags
+ (mlModelPermissions.EditAll ||
+ mlModelPermissions.EditTags) &&
+ !mlModelDetail.deleted
}
selectedTags={mlModelTags}
tagType={TagSource.Glossary}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MlModelDetail/MlModelFeaturesList.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MlModelDetail/MlModelFeaturesList.test.tsx
index 442a0eabada3..0b39da5432b1 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/MlModelDetail/MlModelFeaturesList.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/MlModelDetail/MlModelFeaturesList.test.tsx
@@ -122,21 +122,6 @@ jest.mock('../../utils/CommonUtils', () => ({
getHtmlForNonAdminAction: jest.fn().mockReturnValue('admin action'),
}));
-jest.mock('../../utils/GlossaryUtils', () => ({
- fetchGlossaryTerms: jest.fn(),
- getGlossaryTermlist: jest.fn().mockReturnValue([]),
-}));
-
-jest.mock('../../utils/TableUtils', () => ({
- getEntityLink: jest.fn().mockReturnValue('entityLink'),
-}));
-
-jest.mock('../../utils/TagsUtils', () => ({
- getClassifications: jest.fn(),
- getTaglist: jest.fn().mockReturnValue([]),
- getTagDisplay: jest.fn(),
-}));
-
jest.mock('../common/rich-text-editor/RichTextEditorPreviewer', () => {
return jest.fn().mockReturnValue(RichTextEditorPreviewer
);
});
@@ -151,6 +136,16 @@ jest.mock('components/Tag/Tags/tags', () => {
return jest.fn().mockImplementation(({ tag }) => {tag.tagFQN});
});
+jest.mock('utils/TableUtils', () => ({
+ getAllTagsList: jest.fn().mockImplementation(() => Promise.resolve([])),
+ getTagsHierarchy: jest.fn().mockReturnValue([]),
+}));
+
+jest.mock('utils/GlossaryUtils', () => ({
+ getGlossaryTermHierarchy: jest.fn().mockReturnValue([]),
+ getGlossaryTermsList: jest.fn().mockImplementation(() => Promise.resolve([])),
+}));
+
const handleFeaturesUpdate = jest.fn();
const mockProp = {
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/MlModelDetail/MlModelFeaturesList.tsx b/openmetadata-ui/src/main/resources/ui/src/components/MlModelDetail/MlModelFeaturesList.tsx
index 0f7f79c8a2f3..042688980288 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/MlModelDetail/MlModelFeaturesList.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/MlModelDetail/MlModelFeaturesList.tsx
@@ -23,19 +23,22 @@ import {
} from 'antd';
import { ReactComponent as EditIcon } from 'assets/svg/edit-new.svg';
import TableTags from 'components/TableTags/TableTags.component';
-import { TagLabel, TagSource } from 'generated/type/schema';
-import { isEmpty, map } from 'lodash';
-import { EntityTags, TagOption } from 'Models';
+import {
+ GlossaryTermDetailsProps,
+ TagsDetailsProps,
+} from 'components/Tag/TagsContainerV1/TagsContainerV1.interface';
+import { TagSource } from 'generated/type/schema';
+import { isEmpty } from 'lodash';
+import { EntityTags } from 'Models';
import React, { Fragment, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
-import { getFilterTags } from 'utils/TableTags/TableTags.utils';
+import {
+ getGlossaryTermHierarchy,
+ getGlossaryTermsList,
+} from 'utils/GlossaryUtils';
+import { getAllTagsList, getTagsHierarchy } from 'utils/TagsUtils';
import { MlFeature } from '../../generated/entity/data/mlmodel';
import { LabelType, State } from '../../generated/type/tagLabel';
-import {
- fetchGlossaryTerms,
- getGlossaryTermlist,
-} from '../../utils/GlossaryUtils';
-import { getClassifications, getTaglist } from '../../utils/TagsUtils';
import ErrorPlaceHolder from '../common/error-with-placeholder/ErrorPlaceHolder';
import RichTextEditorPreviewer from '../common/rich-text-editor/RichTextEditorPreviewer';
import { ModalWithMarkdownEditor } from '../Modals/ModalWithMarkdownEditor/ModalWithMarkdownEditor';
@@ -57,9 +60,12 @@ const MlModelFeaturesList = ({
const [isGlossaryLoading, setIsGlossaryLoading] = useState(false);
const [tagFetchFailed, setTagFetchFailed] = useState(false);
- const [glossaryTags, setGlossaryTags] = useState([]);
- const [classificationTags, setClassificationTags] = useState([]);
-
+ const [glossaryTags, setGlossaryTags] = useState(
+ []
+ );
+ const [classificationTags, setClassificationTags] = useState<
+ TagsDetailsProps[]
+ >([]);
const hasEditPermission = useMemo(
() => permissions.EditTags || permissions.EditAll,
[permissions]
@@ -89,10 +95,9 @@ const MlModelFeaturesList = ({
const handleTagsChange = async (
selectedTags: EntityTags[],
- targetFeature: MlFeature,
- otherTags: TagLabel[]
+ targetFeature: MlFeature
) => {
- const newSelectedTags = [...selectedTags, ...otherTags].map((tag) => {
+ const newSelectedTags = selectedTags.map((tag) => {
return {
tagFQN: tag.tagFQN,
source: tag.source,
@@ -119,12 +124,8 @@ const MlModelFeaturesList = ({
const fetchGlossaryTags = async () => {
setIsGlossaryLoading(true);
try {
- const res = await fetchGlossaryTerms();
-
- const glossaryTerms: TagOption[] = getGlossaryTermlist(res).map(
- (tag) => ({ fqn: tag, source: TagSource.Glossary })
- );
- setGlossaryTags(glossaryTerms);
+ const glossaryTermList = await getGlossaryTermsList();
+ setGlossaryTags(glossaryTermList);
} catch {
setTagFetchFailed(true);
} finally {
@@ -135,15 +136,8 @@ const MlModelFeaturesList = ({
const fetchClassificationTags = async () => {
setIsTagLoading(true);
try {
- const res = await getClassifications();
- const tagList = await getTaglist(res.data);
-
- const classificationTag: TagOption[] = map(tagList, (tag) => ({
- fqn: tag,
- source: TagSource.Classification,
- }));
-
- setClassificationTags(classificationTag);
+ const tags = await getAllTagsList();
+ setClassificationTags(tags);
} catch {
setTagFetchFailed(true);
} finally {
@@ -219,8 +213,8 @@ const MlModelFeaturesList = ({
isTagLoading={isGlossaryLoading}
record={feature}
tagFetchFailed={tagFetchFailed}
- tagList={glossaryTags}
- tags={getFilterTags(feature.tags ?? [])}
+ tagList={getGlossaryTermHierarchy(glossaryTags)}
+ tags={feature.tags ?? []}
type={TagSource.Glossary}
/>
@@ -246,8 +240,8 @@ const MlModelFeaturesList = ({
isTagLoading={isTagLoading}
record={feature}
tagFetchFailed={tagFetchFailed}
- tagList={classificationTags}
- tags={getFilterTags(feature.tags ?? [])}
+ tagList={getTagsHierarchy(classificationTags)}
+ tags={feature.tags ?? []}
type={TagSource.Classification}
/>
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/PipelineDetails/PipelineDetails.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/PipelineDetails/PipelineDetails.component.tsx
index c62d2dd4f6b0..b9e271e1c300 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/PipelineDetails/PipelineDetails.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/PipelineDetails/PipelineDetails.component.tsx
@@ -30,6 +30,10 @@ import { EntityName } from 'components/Modals/EntityNameModal/EntityNameModal.in
import TableTags from 'components/TableTags/TableTags.component';
import TabsLabel from 'components/TabsLabel/TabsLabel.component';
import TagsContainerV1 from 'components/Tag/TagsContainerV1/TagsContainerV1';
+import {
+ GlossaryTermDetailsProps,
+ TagsDetailsProps,
+} from 'components/Tag/TagsContainerV1/TagsContainerV1.interface';
import TasksDAGView from 'components/TasksDAGView/TasksDAGView';
import { EntityField } from 'constants/Feeds.constants';
import { compare } from 'fast-json-patch';
@@ -41,8 +45,11 @@ import { useTranslation } from 'react-i18next';
import { Link, useHistory, useParams } from 'react-router-dom';
import { postThread } from 'rest/feedsAPI';
import { restorePipeline } from 'rest/pipelineAPI';
-import { fetchGlossaryTerms, getGlossaryTermlist } from 'utils/GlossaryUtils';
-import { getFilterTags } from 'utils/TableTags/TableTags.utils';
+import {
+ getGlossaryTermHierarchy,
+ getGlossaryTermsList,
+} from 'utils/GlossaryUtils';
+import { getAllTagsList, getTagsHierarchy } from 'utils/TagsUtils';
import { ReactComponent as ExternalLinkIcon } from '../../assets/svg/external-links.svg';
import {
getPipelineDetailsPath,
@@ -69,7 +76,6 @@ import { getEntityName, getEntityThreadLink } from '../../utils/EntityUtils';
import { getEntityFieldThreadCounts } from '../../utils/FeedUtils';
import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils';
import { getTagsWithoutTier, getTierTags } from '../../utils/TableUtils';
-import { getClassifications, getTaglist } from '../../utils/TagsUtils';
import { showErrorToast, showSuccessToast } from '../../utils/ToastUtils';
import ActivityThreadPanel from '../ActivityFeed/ActivityThreadPanel/ActivityThreadPanel';
import RichTextEditorPreviewer from '../common/rich-text-editor/RichTextEditorPreviewer';
@@ -147,8 +153,13 @@ const PipelineDetails = ({
const [isTagLoading, setIsTagLoading] = useState(false);
const [isGlossaryLoading, setIsGlossaryLoading] = useState(false);
const [tagFetchFailed, setTagFetchFailed] = useState(false);
- const [glossaryTags, setGlossaryTags] = useState([]);
- const [classificationTags, setClassificationTags] = useState([]);
+
+ const [glossaryTags, setGlossaryTags] = useState(
+ []
+ );
+ const [classificationTags, setClassificationTags] = useState<
+ TagsDetailsProps[]
+ >([]);
const { getEntityPermission } = usePermissionProvider();
@@ -194,12 +205,8 @@ const PipelineDetails = ({
const fetchGlossaryTags = async () => {
setIsGlossaryLoading(true);
try {
- const res = await fetchGlossaryTerms();
-
- const glossaryTerms: TagOption[] = getGlossaryTermlist(res).map(
- (tag) => ({ fqn: tag, source: TagSource.Glossary })
- );
- setGlossaryTags(glossaryTerms);
+ const glossaryTermList = await getGlossaryTermsList();
+ setGlossaryTags(glossaryTermList);
} catch {
setTagFetchFailed(true);
} finally {
@@ -210,15 +217,8 @@ const PipelineDetails = ({
const fetchClassificationTags = async () => {
setIsTagLoading(true);
try {
- const res = await getClassifications();
- const tagList = await getTaglist(res.data);
-
- const classificationTag: TagOption[] = map(tagList, (tag) => ({
- fqn: tag,
- source: TagSource.Classification,
- }));
-
- setClassificationTags(classificationTag);
+ const tags = await getAllTagsList();
+ setClassificationTags(tags);
} catch {
setTagFetchFailed(true);
} finally {
@@ -358,13 +358,12 @@ const PipelineDetails = ({
const handleTableTagSelection = async (
selectedTags: EntityTags[],
- editColumnTag: Task,
- otherTags: TagLabel[]
+ editColumnTag: Task
) => {
- const newSelectedTags: TagOption[] = map(
- [...selectedTags, ...otherTags],
- (tag) => ({ fqn: tag.tagFQN, source: tag.source })
- );
+ const newSelectedTags: TagOption[] = map(selectedTags, (tag) => ({
+ fqn: tag.tagFQN,
+ source: tag.source,
+ }));
const prevTags = editColumnTag.tags?.filter((tag) =>
newSelectedTags.some((selectedTag) => selectedTag.fqn === tag.tagFQN)
@@ -487,8 +486,8 @@ const PipelineDetails = ({
isTagLoading={isTagLoading}
record={record}
tagFetchFailed={tagFetchFailed}
- tagList={classificationTags}
- tags={getFilterTags(tags)}
+ tagList={getTagsHierarchy(classificationTags)}
+ tags={tags}
type={TagSource.Classification}
/>
),
@@ -510,8 +509,8 @@ const PipelineDetails = ({
isTagLoading={isGlossaryLoading}
record={record}
tagFetchFailed={tagFetchFailed}
- tagList={glossaryTags}
- tags={getFilterTags(tags)}
+ tagList={getGlossaryTermHierarchy(glossaryTags)}
+ tags={tags}
type={TagSource.Glossary}
/>
),
@@ -657,7 +656,9 @@ const PipelineDetails = ({
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
entityType={EntityType.PIPELINE}
permission={
- pipelinePermissions.EditAll || pipelinePermissions.EditTags
+ (pipelinePermissions.EditAll ||
+ pipelinePermissions.EditTags) &&
+ !pipelineDetails.deleted
}
selectedTags={tags}
tagType={TagSource.Classification}
@@ -670,7 +671,9 @@ const PipelineDetails = ({
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
entityType={EntityType.PIPELINE}
permission={
- pipelinePermissions.EditAll || pipelinePermissions.EditTags
+ (pipelinePermissions.EditAll ||
+ pipelinePermissions.EditTags) &&
+ !pipelineDetails.deleted
}
selectedTags={tags}
tagType={TagSource.Glossary}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/PipelineDetails/PipelineDetails.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/PipelineDetails/PipelineDetails.test.tsx
index 2607e5a2b9c1..fff2294b42ed 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/PipelineDetails/PipelineDetails.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/PipelineDetails/PipelineDetails.test.tsx
@@ -181,6 +181,16 @@ jest.mock('../../utils/CommonUtils', () => ({
getCountBadge: jest.fn().mockImplementation((count) => {count}
),
}));
+jest.mock('utils/TagsUtils', () => ({
+ getAllTagsList: jest.fn().mockImplementation(() => Promise.resolve([])),
+ getTagsHierarchy: jest.fn().mockReturnValue([]),
+}));
+
+jest.mock('utils/GlossaryUtils', () => ({
+ getGlossaryTermHierarchy: jest.fn().mockReturnValue([]),
+ getGlossaryTermsList: jest.fn().mockImplementation(() => Promise.resolve([])),
+}));
+
jest.mock('../Execution/Execution.component', () => {
return jest.fn().mockImplementation(() => Executions
);
});
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/SchemaTab/SchemaTab.interfaces.ts b/openmetadata-ui/src/main/resources/ui/src/components/SchemaTab/SchemaTab.interfaces.ts
index 3254ce78c889..451913a54e7e 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/SchemaTab/SchemaTab.interfaces.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/components/SchemaTab/SchemaTab.interfaces.ts
@@ -26,7 +26,7 @@ export type Props = {
tableConstraints: Table['tableConstraints'];
sampleData?: TableData;
hasDescriptionEditAccess?: boolean;
- hasTagEditAccess?: boolean;
+ hasTagEditAccess: boolean;
isReadOnly?: boolean;
entityFqn?: string;
entityFieldThreads?: EntityFieldThreads[];
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/TableQueries/TableQueryRightPanel/TableQueryRightPanel.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/TableQueries/TableQueryRightPanel/TableQueryRightPanel.interface.ts
index 47821bc02a66..cb1c33334074 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/TableQueries/TableQueryRightPanel/TableQueryRightPanel.interface.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/components/TableQueries/TableQueryRightPanel/TableQueryRightPanel.interface.ts
@@ -12,8 +12,8 @@
*/
import { OperationPermission } from 'components/PermissionProvider/PermissionProvider.interface';
+import { TagsDetailsProps } from 'components/Tag/TagsContainerV1/TagsContainerV1.interface';
import { Query } from 'generated/entity/data/query';
-import { TagOption } from 'Models';
export interface TableQueryRightPanelProps {
query: Query;
@@ -24,6 +24,6 @@ export interface TableQueryRightPanelProps {
export type TagDetails = {
isLoading: boolean;
- options: TagOption[];
+ options: TagsDetailsProps[];
isError: boolean;
};
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/TableTags/TableTags.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/TableTags/TableTags.component.tsx
index 5d04d0c8af1f..9ac0eef2256f 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/TableTags/TableTags.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/TableTags/TableTags.component.tsx
@@ -14,12 +14,10 @@
import { Button, Popover } from 'antd';
import { ReactComponent as IconEdit } from 'assets/svg/edit-new.svg';
import classNames from 'classnames';
-import TagsContainer from 'components/Tag/TagsContainer/tags-container';
-import TagsViewer from 'components/Tag/TagsViewer/tags-viewer';
+import TagsContainerEntityTable from 'components/Tag/TagsContainerEntityTable/TagsContainerEntityTable.component';
import { EntityField } from 'constants/Feeds.constants';
import { EntityType } from 'enums/entity.enum';
import { ThreadType } from 'generated/entity/feed/thread';
-import { TagSource } from 'generated/type/schema';
import { EntityFieldThreads } from 'interface/feed.interface';
import { isEmpty } from 'lodash';
import React, { useCallback, useMemo, useState } from 'react';
@@ -54,14 +52,9 @@ const TableTags = ({
const { t } = useTranslation();
const [isEdit, setIsEdit] = useState(false);
- const isGlossaryType = useMemo(() => type === TagSource.Glossary, [type]);
-
const showEditTagButton = useMemo(
() =>
- tags[type].length &&
- hasTagEditAccess &&
- !isEdit &&
- !showInlineEditTagButton,
+ tags.length && hasTagEditAccess && !isEdit && !showInlineEditTagButton,
[tags, type, hasTagEditAccess, isEdit, showInlineEditTagButton]
);
@@ -79,26 +72,6 @@ const TableTags = ({
]
);
- const otherTags = useMemo(
- () =>
- isGlossaryType
- ? tags[TagSource.Classification]
- : tags[TagSource.Glossary],
- [tags, isGlossaryType]
- );
-
- const searchPlaceholder = useMemo(
- () =>
- isGlossaryType
- ? t('label.search-entity', {
- entity: t('label.glossary-term-plural'),
- })
- : t('label.search-entity', {
- entity: t('label.tag-plural'),
- }),
- [isGlossaryType]
- );
-
const addButtonHandler = useCallback(() => {
setIsEdit(true);
// Fetch Classification or Glossary only once
@@ -109,14 +82,15 @@ const TableTags = ({
const getRequestTagsElement = useMemo(() => {
const hasTags = !isEmpty(record.tags || []);
- const text = hasTags
- ? t('label.update-request-tag-plural')
- : t('label.request-tag-plural');
return (
@@ -143,35 +117,29 @@ const TableTags = ({
return (
- {isReadOnly ? (
-
- ) : (
-
-
setIsEdit(false)}
- onEditButtonClick={addButtonHandler}
- onSelectionChange={async (selectedTags) => {
- await handleTagSelection(selectedTags, record, otherTags);
- setIsEdit(false);
- }}
- />
+
+
setIsEdit(false)}
+ onSelectionChange={async (selectedTags) => {
+ await handleTagSelection(selectedTags, record);
+ setIsEdit(false);
+ }}
+ />
+ {!isReadOnly && (
{showEditTagButton ? (
-
- )}
+ )}
+
);
};
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/TableTags/TableTags.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/TableTags/TableTags.interface.ts
index b26fa6d3f353..bd0622e478d1 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/TableTags/TableTags.interface.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/components/TableTags/TableTags.interface.ts
@@ -11,6 +11,7 @@
* limitations under the License.
*/
+import { HierarchyTagsProps } from 'components/Tag/TagsContainerV1/TagsContainerV1.interface';
import { MlFeature } from 'generated/entity/data/mlmodel';
import { Task } from 'generated/entity/data/pipeline';
import { Field } from 'generated/entity/data/topic';
@@ -22,19 +23,18 @@ import { Column } from '../../generated/entity/data/table';
import { EntityFieldThreads } from '../../interface/feed.interface';
export interface TableTagsComponentProps {
- tags: TableTagsProps;
- tagList: TagOption[];
+ tags: TagLabel[];
+ tagList: HierarchyTagsProps[];
onUpdateTagsHandler?: (cell: T) => void;
isReadOnly?: boolean;
entityFqn?: string;
record: T;
index: number;
isTagLoading: boolean;
- hasTagEditAccess?: boolean;
+ hasTagEditAccess: boolean;
handleTagSelection: (
- selectedTags: Array,
- editColumnTag: T,
- otherTags: TagLabel[]
+ selectedTags: EntityTags[],
+ editColumnTag: T
) => Promise;
onRequestTagsHandler?: (cell: T) => void;
getColumnName?: (cell: T) => string;
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/TableTags/TableTags.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/TableTags/TableTags.test.tsx
index 5e1ebaa985cb..4242447c4299 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/TableTags/TableTags.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/TableTags/TableTags.test.tsx
@@ -18,10 +18,6 @@ import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import TableTags from './TableTags.component';
-jest.mock('components/Tag/TagsViewer/tags-viewer', () => {
- return jest.fn().mockReturnValue(TagViewer
);
-});
-
jest.mock('utils/FeedElementUtils', () => ({
getFieldThreadElement: jest
.fn()
@@ -68,10 +64,7 @@ const requestUpdateTags = {
const mockProp = {
placeholder: 'Search Tags',
dataTestId: 'tag-container',
- tags: {
- Classification: [],
- Glossary: [],
- },
+ tags: [],
record: {
constraint: Constraint.Null,
dataLength: 1,
@@ -128,10 +121,7 @@ describe('Test EntityTableTags Component', () => {
...mockProp.record,
tags: [...classificationTags, ...glossaryTags],
}}
- tags={{
- Classification: classificationTags,
- Glossary: glossaryTags,
- }}
+ tags={[...classificationTags, ...glossaryTags]}
/>,
{
wrapper: MemoryRouter,
@@ -139,10 +129,8 @@ describe('Test EntityTableTags Component', () => {
);
const tagContainer = await screen.findByTestId('tag-container-0');
- const tagViewer = await screen.findByTestId('tags-viewer');
expect(tagContainer).toBeInTheDocument();
- expect(tagViewer).toBeInTheDocument();
});
it('Tags list should be visible', async () => {
@@ -153,10 +141,7 @@ describe('Test EntityTableTags Component', () => {
...mockProp.record,
tags: [...classificationTags, ...glossaryTags],
}}
- tags={{
- Classification: classificationTags,
- Glossary: glossaryTags,
- }}
+ tags={[...classificationTags, ...glossaryTags]}
/>,
{
wrapper: MemoryRouter,
@@ -178,10 +163,7 @@ describe('Test EntityTableTags Component', () => {
...mockProp.record,
tags: [...classificationTags, ...glossaryTags],
}}
- tags={{
- Classification: classificationTags,
- Glossary: glossaryTags,
- }}
+ tags={[...classificationTags, ...glossaryTags]}
/>,
{
wrapper: MemoryRouter,
@@ -204,10 +186,7 @@ describe('Test EntityTableTags Component', () => {
...mockProp.record,
tags: [...classificationTags, ...glossaryTags],
}}
- tags={{
- Classification: classificationTags,
- Glossary: glossaryTags,
- }}
+ tags={[...classificationTags, ...glossaryTags]}
/>,
{
wrapper: MemoryRouter,
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsContainerEntityTable/TagsContainerEntityTable.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsContainerEntityTable/TagsContainerEntityTable.component.tsx
new file mode 100644
index 000000000000..2d2f6f124228
--- /dev/null
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsContainerEntityTable/TagsContainerEntityTable.component.tsx
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2022 Collate.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Button, Space } from 'antd';
+import { ReactComponent as IconEdit } from 'assets/svg/edit-new.svg';
+import Loader from 'components/Loader/Loader';
+import { TableTagsProps } from 'components/TableTags/TableTags.interface';
+import Tags from 'components/Tag/Tags/tags';
+import { TAG_CONSTANT, TAG_START_WITH } from 'constants/Tag.constants';
+import { TagSource } from 'generated/type/tagLabel';
+import { isEmpty } from 'lodash';
+import { EntityTags } from 'Models';
+import React, { useCallback, useEffect, useMemo, useState } from 'react';
+import { getFilterTags } from 'utils/TableTags/TableTags.utils';
+import { getTagPlaceholder } from 'utils/TagsUtils';
+import TagTree from '../TagsTree/TagsTreeForm.component';
+import TagsViewer from '../TagsViewer/tags-viewer';
+import { TagsContainerEntityTableProps } from './TagsContainerEntityTable.interface';
+
+const TagsContainerEntityTable = ({
+ isLoading,
+ isEditing,
+ permission,
+ selectedTags,
+ showEditButton,
+ tagType,
+ treeData,
+ onCancel,
+ onSelectionChange,
+ onAddButtonClick,
+}: TagsContainerEntityTableProps) => {
+ const [tags, setTags] = useState();
+
+ const isGlossaryType = useMemo(
+ () => tagType === TagSource.Glossary,
+ [tagType]
+ );
+
+ const showAddTagButton = useMemo(
+ () => permission && isEmpty(tags?.[tagType]),
+ [permission, tags?.[tagType]]
+ );
+
+ const selectedTagsInternal = useMemo(
+ () => tags?.[tagType].map(({ tagFQN }) => tagFQN as string),
+ [tags, tagType]
+ );
+
+ const showNoDataPlaceholder = useMemo(
+ () => !showAddTagButton && isEmpty(tags?.[tagType]),
+ [showAddTagButton, tags?.[tagType]]
+ );
+
+ const getUpdatedTags = (selectedTag: string[]): EntityTags[] => {
+ const updatedTags = selectedTag.map((t) => ({
+ tagFQN: t,
+ source: isGlossaryType ? TagSource.Glossary : TagSource.Classification,
+ }));
+
+ return updatedTags;
+ };
+
+ const handleSave = useCallback(
+ (selectedTag: string[]) => {
+ const updatedTags = getUpdatedTags(selectedTag);
+ onSelectionChange([
+ ...updatedTags,
+ ...((isGlossaryType
+ ? tags?.[TagSource.Classification]
+ : tags?.[TagSource.Glossary]) ?? []),
+ ]);
+ },
+ [isGlossaryType, tags, getUpdatedTags]
+ );
+
+ const editTagButton = useMemo(
+ () =>
+ !isEmpty(tags?.[tagType]) && showEditButton ? (
+ }
+ size="small"
+ type="text"
+ onClick={onAddButtonClick}
+ />
+ ) : null,
+ [selectedTags, showEditButton, onAddButtonClick]
+ );
+
+ const addTagButton = useMemo(
+ () =>
+ showAddTagButton ? (
+
+
+
+ ) : null,
+ [showAddTagButton]
+ );
+
+ const renderTags = useMemo(
+ () => (
+
+ ),
+ [showNoDataPlaceholder, tags?.[tagType]]
+ );
+
+ const tagsSelectContainer = useMemo(() => {
+ return isLoading ? (
+
+ ) : (
+
+ );
+ }, [isGlossaryType, selectedTagsInternal, treeData, onCancel, handleSave]);
+
+ useEffect(() => {
+ setTags(getFilterTags(selectedTags));
+ }, [selectedTags]);
+
+ return (
+
+ {!isEditing && (
+
+ {addTagButton}
+ {renderTags}
+ {editTagButton}
+
+ )}
+ {isEditing && tagsSelectContainer}
+
+ );
+};
+
+export default TagsContainerEntityTable;
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsContainerEntityTable/TagsContainerEntityTable.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsContainerEntityTable/TagsContainerEntityTable.interface.ts
new file mode 100644
index 000000000000..cf5a88eafd0f
--- /dev/null
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsContainerEntityTable/TagsContainerEntityTable.interface.ts
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2023 Collate.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { TagSource } from 'generated/type/tagLabel';
+import { EntityTags } from 'Models';
+import { HierarchyTagsProps } from '../TagsContainerV1/TagsContainerV1.interface';
+
+export type TagsContainerEntityTableProps = {
+ isEditing: boolean;
+ isLoading: boolean;
+ permission: boolean;
+ selectedTags: EntityTags;
+ tagType: TagSource;
+ treeData: HierarchyTagsProps[];
+ showEditButton?: boolean;
+ onCancel: () => void;
+ onAddButtonClick: () => void;
+ onSelectionChange: (selectedTags: EntityTags[]) => void;
+};
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsContainerV1/TagsContainerV1.interface.ts b/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsContainerV1/TagsContainerV1.interface.ts
index ab14c2a092a5..330b8e03ff2b 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsContainerV1/TagsContainerV1.interface.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsContainerV1/TagsContainerV1.interface.ts
@@ -28,14 +28,16 @@ export interface HierarchyTagsProps extends TagsTreeProps {
children: TagsTreeProps[];
}
+export interface TagsDetailsProps {
+ name: string;
+ fqn: string;
+ classification: Tag['classification'];
+ source: TagSource;
+}
+
export type TagDetailsProps = {
isLoading: boolean;
- options: {
- name: string;
- fqn: string;
- classification: Tag['classification'];
- source: TagSource;
- }[];
+ options: TagsDetailsProps[];
isError: boolean;
};
@@ -70,4 +72,6 @@ export type TagsTreeComponentProps = {
treeData: HierarchyTagsProps[];
defaultValue: string[];
onChange?: (value: string[]) => void;
+ onSubmit: (tags: string[]) => void;
+ onCancel: () => void;
};
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsContainerV1/TagsContainerV1.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsContainerV1/TagsContainerV1.tsx
index 4b0fff9e8c12..04b91a1ab5de 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsContainerV1/TagsContainerV1.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsContainerV1/TagsContainerV1.tsx
@@ -11,17 +11,7 @@
* limitations under the License.
*/
-import { CheckOutlined, CloseOutlined } from '@ant-design/icons';
-import {
- Button,
- Col,
- Form,
- FormProps,
- Popover,
- Row,
- Space,
- Typography,
-} from 'antd';
+import { Button, Col, Form, Popover, Row, Space, Typography } from 'antd';
import { ReactComponent as EditIcon } from 'assets/svg/edit-new.svg';
import Loader from 'components/Loader/Loader';
import { TableTagsProps } from 'components/TableTags/TableTags.interface';
@@ -43,7 +33,11 @@ import { getGlossariesList, getGlossaryTerms } from 'rest/glossaryAPI';
import { getEntityFeedLink } from 'utils/EntityUtils';
import { getGlossaryTermHierarchy } from 'utils/GlossaryUtils';
import { getFilterTags } from 'utils/TableTags/TableTags.utils';
-import { getAllTagsForOptions, getTagsHierarchy } from 'utils/TagsUtils';
+import {
+ getAllTagsForOptions,
+ getTagPlaceholder,
+ getTagsHierarchy,
+} from 'utils/TagsUtils';
import {
getRequestTagsPath,
getUpdateTagsPath,
@@ -51,6 +45,7 @@ import {
} from 'utils/TasksUtils';
import { ReactComponent as IconComments } from '../../../assets/svg/comment.svg';
import { ReactComponent as IconRequest } from '../../../assets/svg/request-icon.svg';
+import TagTree from '../TagsTree/TagsTreeForm.component';
import TagsViewer from '../TagsViewer/tags-viewer';
import {
GlossaryDetailsProps,
@@ -58,7 +53,6 @@ import {
TagDetailsProps,
TagsContainerV1Props,
} from './TagsContainerV1.interface';
-import TagTree from './TagsTree.component';
const TagsContainerV1 = ({
permission,
@@ -94,18 +88,6 @@ const TagsContainerV1 = ({
[tagType]
);
- const searchPlaceholder = useMemo(
- () =>
- isGlossaryType
- ? t('label.search-entity', {
- entity: t('label.glossary-term-plural'),
- })
- : t('label.search-entity', {
- entity: t('label.tag-plural'),
- }),
- [isGlossaryType]
- );
-
const showAddTagButton = useMemo(
() => permission && isEmpty(tags?.[tagType]),
[permission, tags?.[tagType]]
@@ -116,7 +98,7 @@ const TagsContainerV1 = ({
[tags, tagType]
);
- const getTreeData = useMemo(() => {
+ const treeData = useMemo(() => {
const tags = getTagsHierarchy(tagDetails.options);
const glossary = getGlossaryTermHierarchy(glossaryDetails.options);
@@ -206,8 +188,8 @@ const TagsContainerV1 = ({
return updatedTags;
};
- const handleSave: FormProps['onFinish'] = (data) => {
- const updatedTags = getUpdatedTags(data.tags);
+ const handleSave = (data: string[]) => {
+ const updatedTags = getUpdatedTags(data);
onSelectionChange([
...updatedTags,
...((isGlossaryType
@@ -263,46 +245,20 @@ const TagsContainerV1 = ({
return tagDetails.isLoading || glossaryDetails.isLoading ? (
) : (
-
+
);
}, [
- searchPlaceholder,
+ isGlossaryType,
selectedTagsInternal,
glossaryDetails,
tagDetails,
- getTreeData,
+ treeData,
handleCancel,
handleSave,
]);
@@ -392,7 +348,6 @@ const TagsContainerV1 = ({
}
size="small"
type="text"
@@ -400,10 +355,12 @@ const TagsContainerV1 = ({
/>
)}
-
- {requestTagElement}
- {conversationThreadElement}
-
+ {permission && (
+
+ {requestTagElement}
+ {conversationThreadElement}
+
+ )}
{!isEditTags && (
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsContainerV1/TagsTree.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsContainerV1/TagsTree.component.tsx
deleted file mode 100644
index 59eeeac9238f..000000000000
--- a/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsContainerV1/TagsTree.component.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2023 Collate.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import { CloseOutlined } from '@ant-design/icons';
-import { TreeSelect } from 'antd';
-import classNames from 'classnames';
-import React from 'react';
-import { TagsTreeComponentProps } from './TagsContainerV1.interface';
-
-const TagTree = ({
- defaultValue,
- placeholder,
- treeData,
- onChange,
-}: TagsTreeComponentProps) => {
- return (
-
- }
- showCheckedStrategy={TreeSelect.SHOW_ALL}
- treeData={treeData}
- treeNodeFilterProp="title"
- onChange={onChange}
- />
- );
-};
-
-export default TagTree;
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsTree/TagsTreeForm.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsTree/TagsTreeForm.component.tsx
new file mode 100644
index 000000000000..11de0692a6d5
--- /dev/null
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Tag/TagsTree/TagsTreeForm.component.tsx
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2023 Collate.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { CheckOutlined, CloseOutlined } from '@ant-design/icons';
+import { Button, Col, Form, Row, Space, TreeSelect } from 'antd';
+import { useForm } from 'antd/lib/form/Form';
+import classNames from 'classnames';
+import React from 'react';
+import { TagsTreeComponentProps } from '../TagsContainerV1/TagsContainerV1.interface';
+
+const TagTree = ({
+ defaultValue,
+ placeholder,
+ treeData,
+ onSubmit,
+ onCancel,
+}: TagsTreeComponentProps) => {
+ const [form] = useForm();
+
+ return (
+
+ );
+};
+
+export default TagTree;
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/TagsInput/TagsInput.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/TagsInput/TagsInput.component.tsx
index 5f4ed3cfd1f5..0d59b4f1d5b2 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/TagsInput/TagsInput.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/TagsInput/TagsInput.component.tsx
@@ -13,14 +13,14 @@
import { Button, Typography } from 'antd';
import { ReactComponent as EditIcon } from 'assets/svg/edit-new.svg';
import { TagDetails } from 'components/TableQueries/TableQueryRightPanel/TableQueryRightPanel.interface';
-import TagsContainer from 'components/Tag/TagsContainer/tags-container';
+import TagsContainerEntityTable from 'components/Tag/TagsContainerEntityTable/TagsContainerEntityTable.component';
import { DE_ACTIVE_COLOR } from 'constants/constants';
import { LabelType, State, TagLabel, TagSource } from 'generated/type/tagLabel';
import { t } from 'i18next';
import { isEmpty } from 'lodash';
import { EntityTags } from 'Models';
import React, { useEffect, useState } from 'react';
-import { getAllTagsForOptions } from 'utils/TagsUtils';
+import { getAllTagsList, getTagsHierarchy } from 'utils/TagsUtils';
type Props = {
editable: boolean;
@@ -68,15 +68,10 @@ const TagsInput: React.FC = ({ tags = [], editable, onTagsUpdate }) => {
setTagDetails((pre) => ({ ...pre, isLoading: true }));
try {
- const tags = await getAllTagsForOptions();
+ const tags = await getAllTagsList();
setTagDetails((pre) => ({
...pre,
- options: tags.map((tag) => {
- return {
- fqn: tag.fullyQualifiedName ?? tag.name,
- source: TagSource.Classification,
- };
- }),
+ options: tags,
}));
} catch (_error) {
setTagDetails((pre) => ({ ...pre, isError: true, options: [] }));
@@ -114,15 +109,14 @@ const TagsInput: React.FC = ({ tags = [], editable, onTagsUpdate }) => {
/>
)}
- setIsEditTags(false)}
onSelectionChange={handleTagSelection}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicDetails.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicDetails.component.tsx
index ed1939189196..767350c462ce 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicDetails.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicDetails.component.tsx
@@ -313,7 +313,8 @@ const TopicDetails: React.FC = ({
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
entityType={EntityType.TOPIC}
permission={
- topicPermissions.EditAll || topicPermissions.EditTags
+ (topicPermissions.EditAll || topicPermissions.EditTags) &&
+ !topicDetails.deleted
}
selectedTags={topicTags}
tagType={TagSource.Classification}
@@ -326,7 +327,8 @@ const TopicDetails: React.FC = ({
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
entityType={EntityType.TOPIC}
permission={
- topicPermissions.EditAll || topicPermissions.EditTags
+ (topicPermissions.EditAll || topicPermissions.EditTags) &&
+ !topicDetails.deleted
}
selectedTags={topicTags}
tagType={TagSource.Glossary}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicDetails.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicDetails.test.tsx
index 373212c42701..7d693ce957d0 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicDetails.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicDetails.test.tsx
@@ -91,18 +91,14 @@ jest.mock('../common/rich-text-editor/RichTextEditorPreviewer', () => {
return jest.fn().mockReturnValue(RichTextEditorPreviwer
);
});
-jest.mock('components/Tag/TagsContainer/tags-container', () => {
- return jest.fn().mockReturnValue(Tag Container
);
+jest.mock('components/Tag/TagsContainerV1/TagsContainerV1', () => {
+ return jest.fn().mockReturnValue(TagsContainerV1
);
});
jest.mock('components/Tag/Tags/tags', () => {
return jest.fn().mockReturnValue(Tags
);
});
-jest.mock('../common/entityPageInfo/EntityPageInfo', () => {
- return jest.fn().mockReturnValue(EntityPageInfo
);
-});
-
jest.mock('../FeedEditor/FeedEditor', () => {
return jest.fn().mockReturnValue(FeedEditor
);
});
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicSchema/TopicSchema.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicSchema/TopicSchema.test.tsx
index 5ec3114945c3..b18acdb73149 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicSchema/TopicSchema.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicSchema/TopicSchema.test.tsx
@@ -37,21 +37,14 @@ const mockProps: TopicSchemaFieldsProps = {
hasTagEditAccess: true,
};
-jest.mock('../../../utils/TagsUtils', () => ({
- getClassifications: jest.fn().mockReturnValue([]),
- getTaglist: jest.fn().mockReturnValue([]),
+jest.mock('utils/TagsUtils', () => ({
+ getAllTagsList: jest.fn().mockImplementation(() => Promise.resolve([])),
+ getTagsHierarchy: jest.fn().mockReturnValue([]),
}));
jest.mock('utils/GlossaryUtils', () => ({
- fetchGlossaryTerms: jest.fn().mockReturnValue([]),
- getGlossaryTermlist: jest.fn().mockReturnValue([]),
-}));
-
-jest.mock('utils/TableTags/TableTags.utils', () => ({
- getFilterTags: jest.fn().mockReturnValue({
- Classification: [],
- Glossary: [],
- }),
+ getGlossaryTermHierarchy: jest.fn().mockReturnValue([]),
+ getGlossaryTermsList: jest.fn().mockImplementation(() => Promise.resolve([])),
}));
jest.mock('../../../utils/TopicSchema.utils', () => ({
@@ -84,6 +77,22 @@ jest.mock('components/TableTags/TableTags.component', () =>
))
);
+jest.mock('components/common/error-with-placeholder/ErrorPlaceHolder', () =>
+ jest
+ .fn()
+ .mockImplementation(() => (
+ ErrorPlaceHolder
+ ))
+);
+
+jest.mock('components/schema-editor/SchemaEditor', () =>
+ jest
+ .fn()
+ .mockImplementation(() => (
+ SchemaEditor
+ ))
+);
+
describe('Topic Schema', () => {
it('Should render the schema component', async () => {
render();
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicSchema/TopicSchema.tsx b/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicSchema/TopicSchema.tsx
index a63c30302ca8..1cd0dd9d5253 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicSchema/TopicSchema.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/TopicDetails/TopicSchema/TopicSchema.tsx
@@ -28,6 +28,10 @@ import classNames from 'classnames';
import ErrorPlaceHolder from 'components/common/error-with-placeholder/ErrorPlaceHolder';
import SchemaEditor from 'components/schema-editor/SchemaEditor';
import TableTags from 'components/TableTags/TableTags.component';
+import {
+ GlossaryTermDetailsProps,
+ TagsDetailsProps,
+} from 'components/Tag/TagsContainerV1/TagsContainerV1.interface';
import { CSMode } from 'enums/codemirror.enum';
import { TagLabel, TagSource } from 'generated/type/tagLabel';
import { cloneDeep, isEmpty, isUndefined, map } from 'lodash';
@@ -35,11 +39,13 @@ import { EntityTags, TagOption } from 'Models';
import React, { FC, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { getEntityName } from 'utils/EntityUtils';
-import { fetchGlossaryTerms, getGlossaryTermlist } from 'utils/GlossaryUtils';
-import { getFilterTags } from 'utils/TableTags/TableTags.utils';
+import {
+ getGlossaryTermHierarchy,
+ getGlossaryTermsList,
+} from 'utils/GlossaryUtils';
+import { getAllTagsList, getTagsHierarchy } from 'utils/TagsUtils';
import { DataTypeTopic, Field } from '../../../generated/entity/data/topic';
import { getTableExpandableConfig } from '../../../utils/TableUtils';
-import { getClassifications, getTaglist } from '../../../utils/TagsUtils';
import {
updateFieldDescription,
updateFieldTags,
@@ -69,18 +75,18 @@ const TopicSchemaFields: FC = ({
SchemaViewType.FIELDS
);
- const [glossaryTags, setGlossaryTags] = useState([]);
- const [classificationTags, setClassificationTags] = useState([]);
+ const [glossaryTags, setGlossaryTags] = useState(
+ []
+ );
+ const [classificationTags, setClassificationTags] = useState<
+ TagsDetailsProps[]
+ >([]);
const fetchGlossaryTags = async () => {
setIsGlossaryLoading(true);
try {
- const res = await fetchGlossaryTerms();
-
- const glossaryTerms: TagOption[] = getGlossaryTermlist(res).map(
- (tag) => ({ fqn: tag, source: TagSource.Glossary })
- );
- setGlossaryTags(glossaryTerms);
+ const glossaryTermList = await getGlossaryTermsList();
+ setGlossaryTags(glossaryTermList);
} catch {
setTagFetchFailed(true);
} finally {
@@ -91,15 +97,8 @@ const TopicSchemaFields: FC = ({
const fetchClassificationTags = async () => {
setIsTagLoading(true);
try {
- const res = await getClassifications();
- const tagList = await getTaglist(res.data);
-
- const classificationTag: TagOption[] = map(tagList, (tag) => ({
- fqn: tag,
- source: TagSource.Classification,
- }));
-
- setClassificationTags(classificationTag);
+ const tags = await getAllTagsList();
+ setClassificationTags(tags);
} catch {
setTagFetchFailed(true);
} finally {
@@ -109,13 +108,12 @@ const TopicSchemaFields: FC = ({
const handleFieldTagsChange = async (
selectedTags: EntityTags[],
- editColumnTag: Field,
- otherTags: TagLabel[]
+ editColumnTag: Field
) => {
- const newSelectedTags: TagOption[] = map(
- [...selectedTags, ...otherTags],
- (tag) => ({ fqn: tag.tagFQN, source: tag.source })
- );
+ const newSelectedTags: TagOption[] = map(selectedTags, (tag) => ({
+ fqn: tag.tagFQN,
+ source: tag.source,
+ }));
if (newSelectedTags && editColumnTag) {
const schema = cloneDeep(messageSchema);
@@ -231,8 +229,8 @@ const TopicSchemaFields: FC = ({
isTagLoading={isTagLoading}
record={record}
tagFetchFailed={tagFetchFailed}
- tagList={classificationTags}
- tags={getFilterTags(tags)}
+ tagList={getTagsHierarchy(classificationTags)}
+ tags={tags}
type={TagSource.Classification}
/>
),
@@ -254,8 +252,8 @@ const TopicSchemaFields: FC = ({
isTagLoading={isGlossaryLoading}
record={record}
tagFetchFailed={tagFetchFailed}
- tagList={glossaryTags}
- tags={getFilterTags(tags)}
+ tagList={getGlossaryTermHierarchy(glossaryTags)}
+ tags={tags}
type={TagSource.Glossary}
/>
),
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/ContainerPage/ContainerPage.test.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/ContainerPage/ContainerPage.test.tsx
index 25977d11f8db..df27bf98dba2 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/ContainerPage/ContainerPage.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/ContainerPage/ContainerPage.test.tsx
@@ -60,10 +60,10 @@ jest.mock('components/common/description/Description', () => {
.mockReturnValue(Description
);
});
-jest.mock('components/common/entityPageInfo/EntityPageInfo', () => {
+jest.mock('components/Tag/TagsContainerV1/TagsContainerV1', () => {
return jest
.fn()
- .mockReturnValue(EntityPageInfo
);
+ .mockReturnValue(TagsContainerV1
);
});
jest.mock('components/FeedEditor/FeedEditor', () => {
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/ContainerPage/ContainerPage.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/ContainerPage/ContainerPage.tsx
index be4ec3dc4637..f8cacf433d69 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/ContainerPage/ContainerPage.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/ContainerPage/ContainerPage.tsx
@@ -634,7 +634,9 @@ const ContainerPage = () => {
entityFqn={containerName}
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
entityType={EntityType.CONTAINER}
- permission={hasEditDescriptionPermission}
+ permission={
+ hasEditDescriptionPermission && !containerData?.deleted
+ }
selectedTags={tags}
tagType={TagSource.Classification}
onSelectionChange={handleTagSelection}
@@ -644,7 +646,9 @@ const ContainerPage = () => {
entityFqn={containerName}
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
entityType={EntityType.CONTAINER}
- permission={hasEditDescriptionPermission}
+ permission={
+ hasEditDescriptionPermission && !containerData?.deleted
+ }
selectedTags={tags}
tagType={TagSource.Glossary}
onSelectionChange={handleTagSelection}
@@ -738,6 +742,7 @@ const ContainerPage = () => {
},
],
[
+ containerData,
description,
containerName,
entityName,
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/TableDetailsPageV1/TableDetailsPageV1.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/TableDetailsPageV1/TableDetailsPageV1.tsx
index cba06e4d35b0..ed9b96f070a3 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/TableDetailsPageV1/TableDetailsPageV1.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/TableDetailsPageV1/TableDetailsPageV1.tsx
@@ -453,7 +453,10 @@ const TableDetailsPageV1 = () => {
entityFqn={datasetFQN}
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
entityType={EntityType.TABLE}
- permission={tablePermissions.EditAll || tablePermissions.EditTags}
+ permission={
+ (tablePermissions.EditAll || tablePermissions.EditTags) &&
+ !tableDetails?.deleted
+ }
selectedTags={tableTags}
tagType={TagSource.Classification}
onSelectionChange={handleTagSelection}
@@ -464,7 +467,10 @@ const TableDetailsPageV1 = () => {
entityFqn={datasetFQN}
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
entityType={EntityType.TABLE}
- permission={tablePermissions.EditAll || tablePermissions.EditTags}
+ permission={
+ (tablePermissions.EditAll || tablePermissions.EditTags) &&
+ !tableDetails?.deleted
+ }
selectedTags={tableTags}
tagType={TagSource.Glossary}
onSelectionChange={handleTagSelection}
diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/GlossaryUtils.ts b/openmetadata-ui/src/main/resources/ui/src/utils/GlossaryUtils.ts
index 03cfbf78b49d..192dca739eff 100644
--- a/openmetadata-ui/src/main/resources/ui/src/utils/GlossaryUtils.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/utils/GlossaryUtils.ts
@@ -17,8 +17,14 @@ import {
GlossaryTermDetailsProps,
HierarchyTagsProps,
} from 'components/Tag/TagsContainerV1/TagsContainerV1.interface';
+import { API_RES_MAX_SIZE, PAGE_SIZE_LARGE } from 'constants/constants';
+import { TagSource } from 'generated/type/tagLabel';
import { isUndefined, omit } from 'lodash';
-import { ListGlossaryTermsParams } from 'rest/glossaryAPI';
+import {
+ getGlossariesList,
+ getGlossaryTerms,
+ ListGlossaryTermsParams,
+} from 'rest/glossaryAPI';
import { searchData } from 'rest/miscAPI';
import { WILD_CARD_CHAR } from '../constants/char.constants';
import { SearchIndex } from '../enums/search.enum';
@@ -267,3 +273,40 @@ export const getGlossaryTermHierarchy = (
return tree;
};
+
+export const getGlossaryTermsList = async () => {
+ try {
+ const glossaryTermList: GlossaryTermDetailsProps[] = [];
+ const { data } = await getGlossariesList({
+ limit: PAGE_SIZE_LARGE,
+ });
+
+ const promises = data.map((item) =>
+ getGlossaryTerms({
+ glossary: item.id,
+ limit: API_RES_MAX_SIZE,
+ fields: 'children,parent',
+ })
+ );
+ const response = await Promise.allSettled(promises);
+
+ response.forEach((res) => {
+ if (res.status === 'fulfilled') {
+ glossaryTermList.push(
+ ...res.value.data.map((data) => ({
+ name: data.name,
+ fqn: data.fullyQualifiedName ?? '',
+ children: data.children,
+ parent: data.parent,
+ glossary: data.glossary,
+ source: TagSource.Glossary,
+ }))
+ );
+ }
+ });
+
+ return Promise.resolve(glossaryTermList);
+ } catch (error) {
+ return Promise.reject({ data: (error as AxiosError).response });
+ }
+};
diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/TagsUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/TagsUtils.tsx
index 5788d8055cc0..51a892eae7c1 100644
--- a/openmetadata-ui/src/main/resources/ui/src/utils/TagsUtils.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/utils/TagsUtils.tsx
@@ -19,7 +19,7 @@ import RichTextEditorPreviewer from 'components/common/rich-text-editor/RichText
import Loader from 'components/Loader/Loader';
import {
HierarchyTagsProps,
- TagDetailsProps,
+ TagsDetailsProps,
} from 'components/Tag/TagsContainerV1/TagsContainerV1.interface';
import { FQN_SEPARATOR_CHAR } from 'constants/char.constants';
import { getExplorePath } from 'constants/constants';
@@ -311,7 +311,7 @@ export const getUsageCountLink = (tagFQN: string) => {
};
export const getTagsHierarchy = (
- tags: TagDetailsProps['options']
+ tags: TagsDetailsProps[]
): HierarchyTagsProps[] => {
const filteredTags = tags.filter(
(tag) => !tag.fqn?.startsWith(`Tier${FQN_SEPARATOR_CHAR}Tier`)
@@ -363,3 +363,29 @@ export const getTagsHierarchy = (
return hierarchyTags;
};
+
+export const getAllTagsList = async () => {
+ try {
+ const tags = await getAllTagsForOptions();
+
+ return Promise.resolve(
+ tags.map((tag) => ({
+ name: tag.name,
+ fqn: tag.fullyQualifiedName ?? '',
+ classification: tag.classification,
+ source: TagSource.Classification,
+ }))
+ );
+ } catch (error) {
+ return Promise.reject({ data: (error as AxiosError).response });
+ }
+};
+
+export const getTagPlaceholder = (isGlossaryType: boolean): string =>
+ isGlossaryType
+ ? i18next.t('label.search-entity', {
+ entity: i18next.t('label.glossary-term-plural'),
+ })
+ : i18next.t('label.search-entity', {
+ entity: i18next.t('label.tag-plural'),
+ });