mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-10-18 20:30:48 +00:00
fix(ui):supported separate tags for glossary and tags (#12068)
* supported separate tags for glossary and tags * fix cypress issue * fix cypress issue
This commit is contained in:
parent
5197682921
commit
10ba297961
@ -640,7 +640,7 @@ export const addNewTagToEntity = (entityObj, term) => {
|
|||||||
.scrollIntoView()
|
.scrollIntoView()
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.click();
|
.click();
|
||||||
cy.get('[data-testid="entity-tags"]')
|
cy.get('[data-testid="tags-container"] [data-testid="entity-tags"]')
|
||||||
.scrollIntoView()
|
.scrollIntoView()
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.contains(term);
|
.contains(term);
|
||||||
|
@ -38,8 +38,9 @@ const addTags = (tag, parent) => {
|
|||||||
const checkTags = (tag, checkForParentEntity) => {
|
const checkTags = (tag, checkForParentEntity) => {
|
||||||
if (checkForParentEntity) {
|
if (checkForParentEntity) {
|
||||||
cy.get(
|
cy.get(
|
||||||
'[data-testid="entity-right-panel"] [data-testid="tag-container"] [data-testid="entity-tags"] '
|
'[data-testid="entity-right-panel"] [data-testid="tags-container"] [data-testid="entity-tags"] '
|
||||||
)
|
)
|
||||||
|
|
||||||
.scrollIntoView()
|
.scrollIntoView()
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.contains(tag);
|
.contains(tag);
|
||||||
@ -48,9 +49,9 @@ const checkTags = (tag, checkForParentEntity) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeTags = (checkForParentEntity, separate) => {
|
const removeTags = (checkForParentEntity) => {
|
||||||
if (checkForParentEntity) {
|
if (checkForParentEntity) {
|
||||||
cy.get('[data-testid="entity-right-panel"] [data-testid="edit-button"] ')
|
cy.get('[data-testid="entity-right-panel"] [data-testid="edit-button"]')
|
||||||
.scrollIntoView()
|
.scrollIntoView()
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.click();
|
.click();
|
||||||
@ -86,7 +87,9 @@ describe('Check if tags addition and removal flow working properly from tables',
|
|||||||
entityDetails.entity
|
entityDetails.entity
|
||||||
);
|
);
|
||||||
|
|
||||||
cy.get('[data-testid="entity-right-panel"] [data-testid="add-tag"]')
|
cy.get(
|
||||||
|
'[data-testid="entity-right-panel"] [data-testid="tags-container"] [data-testid="add-tag"]'
|
||||||
|
)
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
|
@ -281,7 +281,7 @@ describe('Tags page should work', () => {
|
|||||||
cy.get('[data-testid="tag-selector"] > .ant-select-selector').contains(tag);
|
cy.get('[data-testid="tag-selector"] > .ant-select-selector').contains(tag);
|
||||||
cy.get('[data-testid="saveAssociatedTag"]').scrollIntoView().click();
|
cy.get('[data-testid="saveAssociatedTag"]').scrollIntoView().click();
|
||||||
verifyResponseStatusCode('@addTags', 200);
|
verifyResponseStatusCode('@addTags', 200);
|
||||||
cy.get('[data-testid="entity-tags"]')
|
cy.get('[data-testid="tag-container"]')
|
||||||
.scrollIntoView()
|
.scrollIntoView()
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.contains(tag);
|
.contains(tag);
|
||||||
|
@ -36,7 +36,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useHistory, useParams } from 'react-router-dom';
|
import { useHistory, useParams } from 'react-router-dom';
|
||||||
import { restoreDashboard } from 'rest/dashboardAPI';
|
import { restoreDashboard } from 'rest/dashboardAPI';
|
||||||
import { getEntityName } from 'utils/EntityUtils';
|
import { getEntityName, getEntityThreadLink } from 'utils/EntityUtils';
|
||||||
import { getFilterTags } from 'utils/TableTags/TableTags.utils';
|
import { getFilterTags } from 'utils/TableTags/TableTags.utils';
|
||||||
import { ReactComponent as ExternalLinkIcon } from '../../assets/svg/external-links.svg';
|
import { ReactComponent as ExternalLinkIcon } from '../../assets/svg/external-links.svg';
|
||||||
import { EntityField } from '../../constants/Feeds.constants';
|
import { EntityField } from '../../constants/Feeds.constants';
|
||||||
@ -645,20 +645,35 @@ const DashboardDetails = ({
|
|||||||
className="entity-tag-right-panel-container"
|
className="entity-tag-right-panel-container"
|
||||||
data-testid="entity-right-panel"
|
data-testid="entity-right-panel"
|
||||||
flex="320px">
|
flex="320px">
|
||||||
<TagsContainerV1
|
<Space className="w-full" direction="vertical" size="large">
|
||||||
editable={
|
<TagsContainerV1
|
||||||
dashboardPermissions.EditAll || dashboardPermissions.EditTags
|
entityFqn={dashboardDetails.fullyQualifiedName}
|
||||||
}
|
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
|
||||||
entityFieldThreads={getEntityFieldThreadCounts(
|
entityType={EntityType.DASHBOARD}
|
||||||
EntityField.TAGS,
|
permission={
|
||||||
entityFieldThreadCount
|
dashboardPermissions.EditAll ||
|
||||||
)}
|
dashboardPermissions.EditTags
|
||||||
entityFqn={dashboardDetails.fullyQualifiedName}
|
}
|
||||||
entityType={EntityType.DASHBOARD}
|
selectedTags={dashboardTags}
|
||||||
selectedTags={dashboardTags}
|
tagType={TagSource.Classification}
|
||||||
onSelectionChange={handleTagSelection}
|
onSelectionChange={handleTagSelection}
|
||||||
onThreadLinkSelect={onThreadLinkSelect}
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<TagsContainerV1
|
||||||
|
entityFqn={dashboardDetails.fullyQualifiedName}
|
||||||
|
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
|
||||||
|
entityType={EntityType.DASHBOARD}
|
||||||
|
permission={
|
||||||
|
dashboardPermissions.EditAll ||
|
||||||
|
dashboardPermissions.EditTags
|
||||||
|
}
|
||||||
|
selectedTags={dashboardTags}
|
||||||
|
tagType={TagSource.Glossary}
|
||||||
|
onSelectionChange={handleTagSelection}
|
||||||
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
),
|
),
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Card, Col, Row, Tabs } from 'antd';
|
import { Card, Col, Row, Space, Tabs } from 'antd';
|
||||||
import ActivityFeedProvider, {
|
import ActivityFeedProvider, {
|
||||||
useActivityFeedProvider,
|
useActivityFeedProvider,
|
||||||
} from 'components/ActivityFeed/ActivityFeedProvider/ActivityFeedProvider';
|
} from 'components/ActivityFeed/ActivityFeedProvider/ActivityFeedProvider';
|
||||||
@ -29,13 +29,13 @@ import { getDataModelDetailsPath, getVersionPath } from 'constants/constants';
|
|||||||
import { EntityField } from 'constants/Feeds.constants';
|
import { EntityField } from 'constants/Feeds.constants';
|
||||||
import { CSMode } from 'enums/codemirror.enum';
|
import { CSMode } from 'enums/codemirror.enum';
|
||||||
import { EntityTabs, EntityType } from 'enums/entity.enum';
|
import { EntityTabs, EntityType } from 'enums/entity.enum';
|
||||||
import { LabelType, State, TagLabel } from 'generated/type/tagLabel';
|
import { LabelType, State, TagLabel, TagSource } from 'generated/type/tagLabel';
|
||||||
import { isUndefined, toString } from 'lodash';
|
import { isUndefined, toString } from 'lodash';
|
||||||
import { EntityTags } from 'Models';
|
import { EntityTags } from 'Models';
|
||||||
import React, { useMemo, useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useHistory, useParams } from 'react-router-dom';
|
import { useHistory, useParams } from 'react-router-dom';
|
||||||
import { getEntityName } from 'utils/EntityUtils';
|
import { getEntityName, getEntityThreadLink } from 'utils/EntityUtils';
|
||||||
import { getEntityFieldThreadCounts } from 'utils/FeedUtils';
|
import { getEntityFieldThreadCounts } from 'utils/FeedUtils';
|
||||||
import { getTagsWithoutTier } from 'utils/TableUtils';
|
import { getTagsWithoutTier } from 'utils/TableUtils';
|
||||||
import { DataModelDetailsProps } from './DataModelDetails.interface';
|
import { DataModelDetailsProps } from './DataModelDetails.interface';
|
||||||
@ -176,18 +176,28 @@ const DataModelDetails = ({
|
|||||||
className="entity-tag-right-panel-container"
|
className="entity-tag-right-panel-container"
|
||||||
data-testid="entity-right-panel"
|
data-testid="entity-right-panel"
|
||||||
flex="320px">
|
flex="320px">
|
||||||
<TagsContainerV1
|
<Space className="w-full" direction="vertical" size="large">
|
||||||
editable={hasEditTagsPermission}
|
<TagsContainerV1
|
||||||
entityFieldThreads={getEntityFieldThreadCounts(
|
entityFqn={dashboardDataModelFQN}
|
||||||
EntityField.TAGS,
|
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
|
||||||
entityFieldThreadCount
|
entityType={EntityType.DASHBOARD_DATA_MODEL}
|
||||||
)}
|
permission={hasEditTagsPermission}
|
||||||
entityFqn={dashboardDataModelFQN}
|
selectedTags={tags}
|
||||||
entityType={EntityType.DASHBOARD_DATA_MODEL}
|
tagType={TagSource.Classification}
|
||||||
selectedTags={tags}
|
onSelectionChange={handleTagSelection}
|
||||||
onSelectionChange={handleTagSelection}
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
onThreadLinkSelect={onThreadLinkSelect}
|
/>
|
||||||
/>
|
<TagsContainerV1
|
||||||
|
entityFqn={dashboardDataModelFQN}
|
||||||
|
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
|
||||||
|
entityType={EntityType.DASHBOARD_DATA_MODEL}
|
||||||
|
permission={hasEditTagsPermission}
|
||||||
|
selectedTags={tags}
|
||||||
|
tagType={TagSource.Glossary}
|
||||||
|
onSelectionChange={handleTagSelection}
|
||||||
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Card, Col, Row, Table, Tabs, Typography } from 'antd';
|
import { Card, Col, Row, Space, Table, Tabs, Typography } from 'antd';
|
||||||
import { ColumnsType } from 'antd/lib/table';
|
import { ColumnsType } from 'antd/lib/table';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import ActivityFeedProvider, {
|
import ActivityFeedProvider, {
|
||||||
@ -24,14 +24,14 @@ import { DataAssetsHeader } from 'components/DataAssets/DataAssetsHeader/DataAss
|
|||||||
import { EntityName } from 'components/Modals/EntityNameModal/EntityNameModal.interface';
|
import { EntityName } from 'components/Modals/EntityNameModal/EntityNameModal.interface';
|
||||||
import TabsLabel from 'components/TabsLabel/TabsLabel.component';
|
import TabsLabel from 'components/TabsLabel/TabsLabel.component';
|
||||||
import TagsContainerV1 from 'components/Tag/TagsContainerV1/TagsContainerV1';
|
import TagsContainerV1 from 'components/Tag/TagsContainerV1/TagsContainerV1';
|
||||||
import { TagLabel } from 'generated/type/schema';
|
import { TagLabel, TagSource } from 'generated/type/schema';
|
||||||
import { isEmpty } from 'lodash';
|
import { isEmpty } from 'lodash';
|
||||||
import { EntityTags } from 'Models';
|
import { EntityTags } from 'Models';
|
||||||
import React, { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useHistory, useParams } from 'react-router-dom';
|
import { useHistory, useParams } from 'react-router-dom';
|
||||||
import { restoreMlmodel } from 'rest/mlModelAPI';
|
import { restoreMlmodel } from 'rest/mlModelAPI';
|
||||||
import { getEntityName } from 'utils/EntityUtils';
|
import { getEntityName, getEntityThreadLink } from 'utils/EntityUtils';
|
||||||
import AppState from '../../AppState';
|
import AppState from '../../AppState';
|
||||||
import { getMlModelDetailsPath } from '../../constants/constants';
|
import { getMlModelDetailsPath } from '../../constants/constants';
|
||||||
import { EntityField } from '../../constants/Feeds.constants';
|
import { EntityField } from '../../constants/Feeds.constants';
|
||||||
@ -392,20 +392,33 @@ const MlModelDetail: FC<MlModelDetailProp> = ({
|
|||||||
className="entity-tag-right-panel-container"
|
className="entity-tag-right-panel-container"
|
||||||
data-testid="entity-right-panel"
|
data-testid="entity-right-panel"
|
||||||
flex="320px">
|
flex="320px">
|
||||||
<TagsContainerV1
|
<Space className="w-full" direction="vertical" size="large">
|
||||||
editable={
|
<TagsContainerV1
|
||||||
mlModelPermissions.EditAll || mlModelPermissions.EditTags
|
entityFqn={mlModelDetail.fullyQualifiedName}
|
||||||
}
|
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
|
||||||
entityFieldThreads={getEntityFieldThreadCounts(
|
entityType={EntityType.MLMODEL}
|
||||||
EntityField.TAGS,
|
permission={
|
||||||
entityFieldThreadCount
|
mlModelPermissions.EditAll || mlModelPermissions.EditTags
|
||||||
)}
|
}
|
||||||
entityFqn={mlModelDetail.fullyQualifiedName}
|
selectedTags={mlModelTags}
|
||||||
entityType={EntityType.MLMODEL}
|
tagType={TagSource.Classification}
|
||||||
selectedTags={mlModelTags}
|
onSelectionChange={handleTagSelection}
|
||||||
onSelectionChange={handleTagSelection}
|
onThreadLinkSelect={handleThreadLinkSelect}
|
||||||
onThreadLinkSelect={handleThreadLinkSelect}
|
/>
|
||||||
/>
|
|
||||||
|
<TagsContainerV1
|
||||||
|
entityFqn={mlModelDetail.fullyQualifiedName}
|
||||||
|
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
|
||||||
|
entityType={EntityType.MLMODEL}
|
||||||
|
permission={
|
||||||
|
mlModelPermissions.EditAll || mlModelPermissions.EditTags
|
||||||
|
}
|
||||||
|
selectedTags={mlModelTags}
|
||||||
|
tagType={TagSource.Glossary}
|
||||||
|
onSelectionChange={handleTagSelection}
|
||||||
|
onThreadLinkSelect={handleThreadLinkSelect}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
),
|
),
|
||||||
|
@ -65,7 +65,7 @@ import {
|
|||||||
getFeedCounts,
|
getFeedCounts,
|
||||||
refreshPage,
|
refreshPage,
|
||||||
} from '../../utils/CommonUtils';
|
} from '../../utils/CommonUtils';
|
||||||
import { getEntityName } from '../../utils/EntityUtils';
|
import { getEntityName, getEntityThreadLink } from '../../utils/EntityUtils';
|
||||||
import { getEntityFieldThreadCounts } from '../../utils/FeedUtils';
|
import { getEntityFieldThreadCounts } from '../../utils/FeedUtils';
|
||||||
import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils';
|
import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils';
|
||||||
import { getTagsWithoutTier, getTierTags } from '../../utils/TableUtils';
|
import { getTagsWithoutTier, getTierTags } from '../../utils/TableUtils';
|
||||||
@ -651,20 +651,33 @@ const PipelineDetails = ({
|
|||||||
className="entity-tag-right-panel-container"
|
className="entity-tag-right-panel-container"
|
||||||
data-testid="entity-right-panel"
|
data-testid="entity-right-panel"
|
||||||
flex="320px">
|
flex="320px">
|
||||||
<TagsContainerV1
|
<Space className="w-full" direction="vertical" size="large">
|
||||||
editable={
|
<TagsContainerV1
|
||||||
pipelinePermissions.EditAll || pipelinePermissions.EditTags
|
entityFqn={pipelineFQN}
|
||||||
}
|
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
|
||||||
entityFieldThreads={getEntityFieldThreadCounts(
|
entityType={EntityType.PIPELINE}
|
||||||
EntityField.TAGS,
|
permission={
|
||||||
entityFieldThreadCount
|
pipelinePermissions.EditAll || pipelinePermissions.EditTags
|
||||||
)}
|
}
|
||||||
entityFqn={pipelineFQN}
|
selectedTags={tags}
|
||||||
entityType={EntityType.TOPIC}
|
tagType={TagSource.Classification}
|
||||||
selectedTags={tags}
|
onSelectionChange={handleTagSelection}
|
||||||
onSelectionChange={handleTagSelection}
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
onThreadLinkSelect={onThreadLinkSelect}
|
/>
|
||||||
/>
|
|
||||||
|
<TagsContainerV1
|
||||||
|
entityFqn={pipelineFQN}
|
||||||
|
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
|
||||||
|
entityType={EntityType.PIPELINE}
|
||||||
|
permission={
|
||||||
|
pipelinePermissions.EditAll || pipelinePermissions.EditTags
|
||||||
|
}
|
||||||
|
selectedTags={tags}
|
||||||
|
tagType={TagSource.Glossary}
|
||||||
|
onSelectionChange={handleTagSelection}
|
||||||
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
),
|
),
|
||||||
|
@ -15,7 +15,6 @@ import { ThreadType } from 'generated/api/feed/createThread';
|
|||||||
import { Tag } from 'generated/entity/classification/tag';
|
import { Tag } from 'generated/entity/classification/tag';
|
||||||
import { GlossaryTerm } from 'generated/entity/data/glossaryTerm';
|
import { GlossaryTerm } from 'generated/entity/data/glossaryTerm';
|
||||||
import { TagSource } from 'generated/type/tagLabel';
|
import { TagSource } from 'generated/type/tagLabel';
|
||||||
import { EntityFieldThreads } from 'interface/feed.interface';
|
|
||||||
import { EntityTags } from 'Models';
|
import { EntityTags } from 'Models';
|
||||||
|
|
||||||
interface TagsTreeProps {
|
interface TagsTreeProps {
|
||||||
@ -29,10 +28,6 @@ export interface HierarchyTagsProps extends TagsTreeProps {
|
|||||||
children: TagsTreeProps[];
|
children: TagsTreeProps[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GlossaryTermNodeProps extends TagsTreeProps {
|
|
||||||
children: TagsTreeProps[] | undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type TagDetailsProps = {
|
export type TagDetailsProps = {
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
options: {
|
options: {
|
||||||
@ -60,13 +55,19 @@ export type GlossaryTermDetailsProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type TagsContainerV1Props = {
|
export type TagsContainerV1Props = {
|
||||||
editable: boolean;
|
permission: boolean;
|
||||||
selectedTags: Array<EntityTags>;
|
selectedTags: Array<EntityTags>;
|
||||||
onSelectionChange: (selectedTags: Array<EntityTags>) => void;
|
onSelectionChange: (selectedTags: Array<EntityTags>) => void;
|
||||||
placeholder?: string;
|
onThreadLinkSelect: (value: string, threadType?: ThreadType) => void;
|
||||||
showLimited?: boolean;
|
|
||||||
onThreadLinkSelect?: (value: string, threadType?: ThreadType) => void;
|
|
||||||
entityType?: string;
|
entityType?: string;
|
||||||
entityFieldThreads?: EntityFieldThreads[];
|
entityThreadLink?: string;
|
||||||
entityFqn?: string;
|
entityFqn?: string;
|
||||||
|
tagType: TagSource;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TagsTreeComponentProps = {
|
||||||
|
placeholder: string;
|
||||||
|
treeData: HierarchyTagsProps[];
|
||||||
|
defaultValue: string[];
|
||||||
|
onChange?: (value: string[]) => void;
|
||||||
};
|
};
|
||||||
|
@ -20,40 +20,37 @@ import {
|
|||||||
Popover,
|
Popover,
|
||||||
Row,
|
Row,
|
||||||
Space,
|
Space,
|
||||||
TreeSelect,
|
|
||||||
Typography,
|
Typography,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import { ReactComponent as EditIcon } from 'assets/svg/edit-new.svg';
|
import { ReactComponent as EditIcon } from 'assets/svg/edit-new.svg';
|
||||||
import classNames from 'classnames';
|
|
||||||
import Loader from 'components/Loader/Loader';
|
import Loader from 'components/Loader/Loader';
|
||||||
|
import { TableTagsProps } from 'components/TableTags/TableTags.interface';
|
||||||
import Tags from 'components/Tag/Tags/tags';
|
import Tags from 'components/Tag/Tags/tags';
|
||||||
import {
|
import {
|
||||||
API_RES_MAX_SIZE,
|
API_RES_MAX_SIZE,
|
||||||
DE_ACTIVE_COLOR,
|
DE_ACTIVE_COLOR,
|
||||||
NO_DATA_PLACEHOLDER,
|
|
||||||
PAGE_SIZE_LARGE,
|
PAGE_SIZE_LARGE,
|
||||||
} from 'constants/constants';
|
} from 'constants/constants';
|
||||||
import { TAG_CONSTANT, TAG_START_WITH } from 'constants/Tag.constants';
|
import { TAG_CONSTANT, TAG_START_WITH } from 'constants/Tag.constants';
|
||||||
import { EntityType } from 'enums/entity.enum';
|
import { EntityType } from 'enums/entity.enum';
|
||||||
import { TagSource } from 'generated/type/tagLabel';
|
import { TagSource } from 'generated/type/tagLabel';
|
||||||
import { isEmpty, isUndefined } from 'lodash';
|
import { isEmpty } from 'lodash';
|
||||||
import { EntityTags } from 'Models';
|
import { EntityTags } from 'Models';
|
||||||
import React, { useCallback, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import { getGlossariesList, getGlossaryTerms } from 'rest/glossaryAPI';
|
import { getGlossariesList, getGlossaryTerms } from 'rest/glossaryAPI';
|
||||||
import { getEntityFeedLink } from 'utils/EntityUtils';
|
import { getEntityFeedLink } from 'utils/EntityUtils';
|
||||||
import { getGlossaryTermHierarchy } from 'utils/GlossaryUtils';
|
import { getGlossaryTermHierarchy } from 'utils/GlossaryUtils';
|
||||||
|
import { getFilterTags } from 'utils/TableTags/TableTags.utils';
|
||||||
import { getAllTagsForOptions, getTagsHierarchy } from 'utils/TagsUtils';
|
import { getAllTagsForOptions, getTagsHierarchy } from 'utils/TagsUtils';
|
||||||
import {
|
import {
|
||||||
getRequestTagsPath,
|
getRequestTagsPath,
|
||||||
getUpdateTagsPath,
|
getUpdateTagsPath,
|
||||||
TASK_ENTITIES,
|
TASK_ENTITIES,
|
||||||
} from 'utils/TasksUtils';
|
} from 'utils/TasksUtils';
|
||||||
import { ReactComponent as IconCommentPlus } from '../../../assets/svg/add-chat.svg';
|
|
||||||
import { ReactComponent as IconComments } from '../../../assets/svg/comment.svg';
|
import { ReactComponent as IconComments } from '../../../assets/svg/comment.svg';
|
||||||
import { ReactComponent as IconRequest } from '../../../assets/svg/request-icon.svg';
|
import { ReactComponent as IconRequest } from '../../../assets/svg/request-icon.svg';
|
||||||
import TagsV1 from '../TagsV1/TagsV1.component';
|
|
||||||
import TagsViewer from '../TagsViewer/tags-viewer';
|
import TagsViewer from '../TagsViewer/tags-viewer';
|
||||||
import {
|
import {
|
||||||
GlossaryDetailsProps,
|
GlossaryDetailsProps,
|
||||||
@ -61,17 +58,17 @@ import {
|
|||||||
TagDetailsProps,
|
TagDetailsProps,
|
||||||
TagsContainerV1Props,
|
TagsContainerV1Props,
|
||||||
} from './TagsContainerV1.interface';
|
} from './TagsContainerV1.interface';
|
||||||
|
import TagTree from './TagsTree.component';
|
||||||
|
|
||||||
const TagsContainerV1 = ({
|
const TagsContainerV1 = ({
|
||||||
editable,
|
permission,
|
||||||
selectedTags,
|
selectedTags,
|
||||||
onSelectionChange,
|
|
||||||
placeholder,
|
|
||||||
showLimited,
|
|
||||||
onThreadLinkSelect,
|
|
||||||
entityType,
|
entityType,
|
||||||
entityFieldThreads,
|
entityThreadLink,
|
||||||
entityFqn,
|
entityFqn,
|
||||||
|
tagType,
|
||||||
|
onSelectionChange,
|
||||||
|
onThreadLinkSelect,
|
||||||
}: TagsContainerV1Props) => {
|
}: TagsContainerV1Props) => {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
@ -90,19 +87,41 @@ const TagsContainerV1 = ({
|
|||||||
options: [],
|
options: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const tagThread = entityFieldThreads?.[0];
|
const [tags, setTags] = useState<TableTagsProps>();
|
||||||
|
|
||||||
const showAddTagButton = useMemo(
|
const isGlossaryType = useMemo(
|
||||||
() => editable && isEmpty(selectedTags),
|
() => tagType === TagSource.Glossary,
|
||||||
[editable, selectedTags]
|
[tagType]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleRequestTags = () => {
|
const searchPlaceholder = useMemo(
|
||||||
history.push(getRequestTagsPath(entityType as string, entityFqn as string));
|
() =>
|
||||||
};
|
isGlossaryType
|
||||||
const handleUpdateTags = () => {
|
? t('label.search-entity', {
|
||||||
history.push(getUpdateTagsPath(entityType as string, entityFqn as string));
|
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]]
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectedTagsInternal = useMemo(
|
||||||
|
() => tags?.[tagType].map(({ tagFQN }) => tagFQN as string),
|
||||||
|
[tags, tagType]
|
||||||
|
);
|
||||||
|
|
||||||
|
const getTreeData = useMemo(() => {
|
||||||
|
const tags = getTagsHierarchy(tagDetails.options);
|
||||||
|
const glossary = getGlossaryTermHierarchy(glossaryDetails.options);
|
||||||
|
|
||||||
|
return [...tags, ...glossary];
|
||||||
|
}, [tagDetails.options, glossaryDetails.options]);
|
||||||
|
|
||||||
const fetchTags = async () => {
|
const fetchTags = async () => {
|
||||||
if (isEmpty(tagDetails.options) || tagDetails.isError) {
|
if (isEmpty(tagDetails.options) || tagDetails.isError) {
|
||||||
@ -172,8 +191,8 @@ const TagsContainerV1 = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const showNoDataPlaceholder = useMemo(
|
const showNoDataPlaceholder = useMemo(
|
||||||
() => !showAddTagButton && selectedTags.length === 0,
|
() => !showAddTagButton && isEmpty(tags?.[tagType]),
|
||||||
[showAddTagButton, selectedTags]
|
[showAddTagButton, tags?.[tagType]]
|
||||||
);
|
);
|
||||||
|
|
||||||
const getUpdatedTags = (selectedTag: string[]): EntityTags[] => {
|
const getUpdatedTags = (selectedTag: string[]): EntityTags[] => {
|
||||||
@ -188,8 +207,13 @@ const TagsContainerV1 = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSave: FormProps['onFinish'] = (data) => {
|
const handleSave: FormProps['onFinish'] = (data) => {
|
||||||
const tags = getUpdatedTags(data.tags);
|
const updatedTags = getUpdatedTags(data.tags);
|
||||||
onSelectionChange(tags);
|
onSelectionChange([
|
||||||
|
...updatedTags,
|
||||||
|
...((isGlossaryType
|
||||||
|
? tags?.[TagSource.Classification]
|
||||||
|
: tags?.[TagSource.Glossary]) ?? []),
|
||||||
|
]);
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
setIsEditTags(false);
|
setIsEditTags(false);
|
||||||
};
|
};
|
||||||
@ -199,15 +223,14 @@ const TagsContainerV1 = ({
|
|||||||
form.resetFields();
|
form.resetFields();
|
||||||
}, [form]);
|
}, [form]);
|
||||||
|
|
||||||
const handleAddClick = () => {
|
const handleAddClick = useCallback(() => {
|
||||||
fetchTags();
|
if (isGlossaryType) {
|
||||||
fetchGlossaryList();
|
fetchGlossaryList();
|
||||||
|
} else {
|
||||||
|
fetchTags();
|
||||||
|
}
|
||||||
setIsEditTags(true);
|
setIsEditTags(true);
|
||||||
};
|
}, [isGlossaryType, fetchGlossaryList, fetchTags]);
|
||||||
|
|
||||||
const getTagsElement = (tag: EntityTags) => (
|
|
||||||
<TagsV1 key={tag.tagFQN} tag={tag} />
|
|
||||||
);
|
|
||||||
|
|
||||||
const addTagButton = useMemo(
|
const addTagButton = useMemo(
|
||||||
() =>
|
() =>
|
||||||
@ -225,47 +248,19 @@ const TagsContainerV1 = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const renderTags = useMemo(
|
const renderTags = useMemo(
|
||||||
() =>
|
() => (
|
||||||
showLimited ? (
|
<TagsViewer
|
||||||
<TagsViewer
|
isTextPlaceholder
|
||||||
isTextPlaceholder
|
showNoDataPlaceholder={showNoDataPlaceholder}
|
||||||
showNoDataPlaceholder={showNoDataPlaceholder}
|
tags={tags?.[tagType] ?? []}
|
||||||
tags={selectedTags}
|
type="border"
|
||||||
type="border"
|
/>
|
||||||
/>
|
),
|
||||||
) : (
|
[showNoDataPlaceholder, tags?.[tagType]]
|
||||||
<>
|
|
||||||
{!showAddTagButton && isEmpty(selectedTags) ? (
|
|
||||||
<Typography.Text data-testid="no-tags">
|
|
||||||
{NO_DATA_PLACEHOLDER}
|
|
||||||
</Typography.Text>
|
|
||||||
) : null}
|
|
||||||
{selectedTags.map(getTagsElement)}
|
|
||||||
</>
|
|
||||||
),
|
|
||||||
[
|
|
||||||
showLimited,
|
|
||||||
showNoDataPlaceholder,
|
|
||||||
selectedTags,
|
|
||||||
getTagsElement,
|
|
||||||
showAddTagButton,
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectedTagsInternal = useMemo(
|
|
||||||
() => selectedTags.map(({ tagFQN }) => tagFQN as string),
|
|
||||||
[selectedTags]
|
|
||||||
);
|
|
||||||
|
|
||||||
const getTreeData = useMemo(() => {
|
|
||||||
const tags = getTagsHierarchy(tagDetails.options);
|
|
||||||
const glossary = getGlossaryTermHierarchy(glossaryDetails.options);
|
|
||||||
|
|
||||||
return [...tags, ...glossary];
|
|
||||||
}, [tagDetails.options, glossaryDetails.options]);
|
|
||||||
|
|
||||||
const tagsSelectContainer = useMemo(() => {
|
const tagsSelectContainer = useMemo(() => {
|
||||||
return tagDetails.isLoading && glossaryDetails.isLoading ? (
|
return tagDetails.isLoading || glossaryDetails.isLoading ? (
|
||||||
<Loader size="small" />
|
<Loader size="small" />
|
||||||
) : (
|
) : (
|
||||||
<Form form={form} name="tagsForm" onFinish={handleSave}>
|
<Form form={form} name="tagsForm" onFinish={handleSave}>
|
||||||
@ -292,32 +287,10 @@ const TagsContainerV1 = ({
|
|||||||
|
|
||||||
<Col className="gutter-row" span={24}>
|
<Col className="gutter-row" span={24}>
|
||||||
<Form.Item noStyle name="tags">
|
<Form.Item noStyle name="tags">
|
||||||
<TreeSelect
|
<TagTree
|
||||||
autoFocus
|
defaultValue={selectedTagsInternal ?? []}
|
||||||
multiple
|
placeholder={searchPlaceholder}
|
||||||
showSearch
|
|
||||||
treeDefaultExpandAll
|
|
||||||
treeLine
|
|
||||||
className={classNames('w-full')}
|
|
||||||
data-testid="tag-selector"
|
|
||||||
defaultValue={selectedTagsInternal}
|
|
||||||
placeholder={
|
|
||||||
placeholder
|
|
||||||
? placeholder
|
|
||||||
: t('label.select-field', {
|
|
||||||
field: t('label.tag-plural'),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
removeIcon={
|
|
||||||
<CloseOutlined
|
|
||||||
data-testid="remove-tags"
|
|
||||||
height={8}
|
|
||||||
width={8}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
showCheckedStrategy={TreeSelect.SHOW_ALL}
|
|
||||||
treeData={getTreeData}
|
treeData={getTreeData}
|
||||||
treeNodeFilterProp="title"
|
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
@ -325,23 +298,26 @@ const TagsContainerV1 = ({
|
|||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
}, [
|
}, [
|
||||||
|
searchPlaceholder,
|
||||||
selectedTagsInternal,
|
selectedTagsInternal,
|
||||||
handleCancel,
|
|
||||||
handleSave,
|
|
||||||
placeholder,
|
|
||||||
glossaryDetails,
|
glossaryDetails,
|
||||||
tagDetails,
|
tagDetails,
|
||||||
getTreeData,
|
getTreeData,
|
||||||
|
handleCancel,
|
||||||
|
handleSave,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const getRequestTagsElements = useCallback(() => {
|
const handleRequestTags = () => {
|
||||||
const hasTags = !isEmpty(selectedTags);
|
history.push(getRequestTagsPath(entityType as string, entityFqn as string));
|
||||||
const text = hasTags
|
};
|
||||||
? t('label.update-request-tag-plural')
|
const handleUpdateTags = () => {
|
||||||
: t('label.request-tag-plural');
|
history.push(getUpdateTagsPath(entityType as string, entityFqn as string));
|
||||||
|
};
|
||||||
|
|
||||||
return onThreadLinkSelect &&
|
const requestTagElement = useMemo(() => {
|
||||||
TASK_ENTITIES.includes(entityType as EntityType) ? (
|
const hasTags = !isEmpty(tags?.[tagType]);
|
||||||
|
|
||||||
|
return TASK_ENTITIES.includes(entityType as EntityType) ? (
|
||||||
<Col>
|
<Col>
|
||||||
<Button
|
<Button
|
||||||
className="p-0 flex-center"
|
className="p-0 flex-center"
|
||||||
@ -351,7 +327,11 @@ const TagsContainerV1 = ({
|
|||||||
onClick={hasTags ? handleUpdateTags : handleRequestTags}>
|
onClick={hasTags ? handleUpdateTags : handleRequestTags}>
|
||||||
<Popover
|
<Popover
|
||||||
destroyTooltipOnHide
|
destroyTooltipOnHide
|
||||||
content={text}
|
content={
|
||||||
|
hasTags
|
||||||
|
? t('label.update-request-tag-plural')
|
||||||
|
: t('label.request-tag-plural')
|
||||||
|
}
|
||||||
overlayClassName="ant-popover-request-description"
|
overlayClassName="ant-popover-request-description"
|
||||||
placement="topLeft"
|
placement="topLeft"
|
||||||
trigger="hover"
|
trigger="hover"
|
||||||
@ -366,57 +346,53 @@ const TagsContainerV1 = ({
|
|||||||
</Button>
|
</Button>
|
||||||
</Col>
|
</Col>
|
||||||
) : null;
|
) : null;
|
||||||
|
}, [tags?.[tagType], handleUpdateTags, handleRequestTags]);
|
||||||
|
|
||||||
|
const conversationThreadElement = useMemo(
|
||||||
|
() => (
|
||||||
|
<Col>
|
||||||
|
<Button
|
||||||
|
className="p-0 flex-center"
|
||||||
|
data-testid="tag-thread"
|
||||||
|
size="small"
|
||||||
|
type="text"
|
||||||
|
onClick={() =>
|
||||||
|
onThreadLinkSelect(
|
||||||
|
entityThreadLink ??
|
||||||
|
getEntityFeedLink(entityType, entityFqn, 'tags')
|
||||||
|
)
|
||||||
|
}>
|
||||||
|
<Space align="center" className="w-full h-full" size={2}>
|
||||||
|
<IconComments height={16} name="comments" width={16} />
|
||||||
|
</Space>
|
||||||
|
</Button>
|
||||||
|
</Col>
|
||||||
|
),
|
||||||
|
[
|
||||||
|
entityType,
|
||||||
|
entityFqn,
|
||||||
|
entityThreadLink,
|
||||||
|
getEntityFeedLink,
|
||||||
|
onThreadLinkSelect,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setTags(getFilterTags(selectedTags));
|
||||||
}, [selectedTags]);
|
}, [selectedTags]);
|
||||||
|
|
||||||
const getThreadElements = () => {
|
|
||||||
if (!isUndefined(entityFieldThreads)) {
|
|
||||||
return !isUndefined(tagThread) ? (
|
|
||||||
<Col>
|
|
||||||
<Button
|
|
||||||
className="p-0 flex-center"
|
|
||||||
data-testid="tag-thread"
|
|
||||||
size="small"
|
|
||||||
type="text"
|
|
||||||
onClick={() => onThreadLinkSelect?.(tagThread.entityLink)}>
|
|
||||||
<Space align="center" className="w-full h-full" size={2}>
|
|
||||||
<IconComments height={16} name="comments" width={16} />
|
|
||||||
<span data-testid="tag-thread-count">{tagThread.count}</span>
|
|
||||||
</Space>
|
|
||||||
</Button>
|
|
||||||
</Col>
|
|
||||||
) : (
|
|
||||||
<Col>
|
|
||||||
<Button
|
|
||||||
className="p-0 flex-center"
|
|
||||||
data-testid="start-tag-thread"
|
|
||||||
icon={<IconCommentPlus height={16} name="comments" width={16} />}
|
|
||||||
size="small"
|
|
||||||
type="text"
|
|
||||||
onClick={() =>
|
|
||||||
onThreadLinkSelect?.(
|
|
||||||
getEntityFeedLink(entityType, entityFqn, 'tags')
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div data-testid="tag-container">
|
<div data-testid={isGlossaryType ? 'glossary-container' : 'tags-container'}>
|
||||||
<div className="d-flex justify-between m-b-xs">
|
<div className="d-flex justify-between m-b-xs">
|
||||||
<div className="d-flex items-center">
|
<div className="d-flex items-center">
|
||||||
<Typography.Text className="right-panel-label">
|
<Typography.Text className="right-panel-label">
|
||||||
{t('label.tag-plural')}
|
{isGlossaryType ? t('label.glossary-term') : t('label.tag-plural')}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
{editable && selectedTags.length > 0 && (
|
{permission && !isEmpty(tags?.[tagType]) && (
|
||||||
<Button
|
<Button
|
||||||
className="cursor-pointer flex-center m-l-xss"
|
className="cursor-pointer flex-center m-l-xss"
|
||||||
data-testid="edit-button"
|
data-testid="edit-button"
|
||||||
disabled={!editable}
|
disabled={!permission}
|
||||||
icon={<EditIcon color={DE_ACTIVE_COLOR} width="14px" />}
|
icon={<EditIcon color={DE_ACTIVE_COLOR} width="14px" />}
|
||||||
size="small"
|
size="small"
|
||||||
type="text"
|
type="text"
|
||||||
@ -425,8 +401,8 @@ const TagsContainerV1 = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Row gutter={8}>
|
<Row gutter={8}>
|
||||||
{getRequestTagsElements()}
|
{requestTagElement}
|
||||||
{getThreadElements()}
|
{conversationThreadElement}
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* 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 (
|
||||||
|
<TreeSelect
|
||||||
|
autoFocus
|
||||||
|
multiple
|
||||||
|
showSearch
|
||||||
|
treeDefaultExpandAll
|
||||||
|
treeLine
|
||||||
|
className={classNames('w-full')}
|
||||||
|
data-testid="tag-selector"
|
||||||
|
defaultValue={defaultValue}
|
||||||
|
placeholder={placeholder}
|
||||||
|
removeIcon={
|
||||||
|
<CloseOutlined data-testid="remove-tags" height={8} width={8} />
|
||||||
|
}
|
||||||
|
showCheckedStrategy={TreeSelect.SHOW_ALL}
|
||||||
|
treeData={treeData}
|
||||||
|
treeNodeFilterProp="title"
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TagTree;
|
@ -11,7 +11,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Card, Col, Row, Tabs } from 'antd';
|
import { Card, Col, Row, Space, Tabs } from 'antd';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import ActivityFeedProvider, {
|
import ActivityFeedProvider, {
|
||||||
useActivityFeedProvider,
|
useActivityFeedProvider,
|
||||||
@ -30,12 +30,12 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useHistory, useParams } from 'react-router-dom';
|
import { useHistory, useParams } from 'react-router-dom';
|
||||||
import { restoreTopic } from 'rest/topicsAPI';
|
import { restoreTopic } from 'rest/topicsAPI';
|
||||||
import { getEntityName } from 'utils/EntityUtils';
|
import { getEntityName, getEntityThreadLink } from 'utils/EntityUtils';
|
||||||
import { EntityField } from '../../constants/Feeds.constants';
|
import { EntityField } from '../../constants/Feeds.constants';
|
||||||
import { EntityTabs, EntityType } from '../../enums/entity.enum';
|
import { EntityTabs, EntityType } from '../../enums/entity.enum';
|
||||||
import { Topic } from '../../generated/entity/data/topic';
|
import { Topic } from '../../generated/entity/data/topic';
|
||||||
import { ThreadType } from '../../generated/entity/feed/thread';
|
import { ThreadType } from '../../generated/entity/feed/thread';
|
||||||
import { LabelType, State } from '../../generated/type/tagLabel';
|
import { LabelType, State, TagSource } from '../../generated/type/tagLabel';
|
||||||
import { getCurrentUserId, refreshPage } from '../../utils/CommonUtils';
|
import { getCurrentUserId, refreshPage } from '../../utils/CommonUtils';
|
||||||
import { getEntityFieldThreadCounts } from '../../utils/FeedUtils';
|
import { getEntityFieldThreadCounts } from '../../utils/FeedUtils';
|
||||||
import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils';
|
import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils';
|
||||||
@ -307,18 +307,33 @@ const TopicDetails: React.FC<TopicDetailsProps> = ({
|
|||||||
className="entity-tag-right-panel-container"
|
className="entity-tag-right-panel-container"
|
||||||
data-testid="entity-right-panel"
|
data-testid="entity-right-panel"
|
||||||
flex="320px">
|
flex="320px">
|
||||||
<TagsContainerV1
|
<Space className="w-full" direction="vertical" size="large">
|
||||||
editable={topicPermissions.EditAll || topicPermissions.EditTags}
|
<TagsContainerV1
|
||||||
entityFieldThreads={getEntityFieldThreadCounts(
|
entityFqn={topicDetails.fullyQualifiedName}
|
||||||
EntityField.TAGS,
|
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
|
||||||
entityFieldThreadCount
|
entityType={EntityType.TOPIC}
|
||||||
)}
|
permission={
|
||||||
entityFqn={topicDetails.fullyQualifiedName}
|
topicPermissions.EditAll || topicPermissions.EditTags
|
||||||
entityType={EntityType.TOPIC}
|
}
|
||||||
selectedTags={topicTags}
|
selectedTags={topicTags}
|
||||||
onSelectionChange={handleTagSelection}
|
tagType={TagSource.Classification}
|
||||||
onThreadLinkSelect={onThreadLinkSelect}
|
onSelectionChange={handleTagSelection}
|
||||||
/>
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<TagsContainerV1
|
||||||
|
entityFqn={topicDetails.fullyQualifiedName}
|
||||||
|
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
|
||||||
|
entityType={EntityType.TOPIC}
|
||||||
|
permission={
|
||||||
|
topicPermissions.EditAll || topicPermissions.EditTags
|
||||||
|
}
|
||||||
|
selectedTags={topicTags}
|
||||||
|
tagType={TagSource.Glossary}
|
||||||
|
onSelectionChange={handleTagSelection}
|
||||||
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
),
|
),
|
||||||
|
@ -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 { Card, Col, Row, Tabs } from 'antd';
|
import { Card, Col, Row, Space, Tabs } from 'antd';
|
||||||
import AppState from 'AppState';
|
import AppState from 'AppState';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import ActivityFeedProvider, {
|
import ActivityFeedProvider, {
|
||||||
@ -77,7 +77,11 @@ import {
|
|||||||
refreshPage,
|
refreshPage,
|
||||||
sortTagsCaseInsensitive,
|
sortTagsCaseInsensitive,
|
||||||
} from 'utils/CommonUtils';
|
} from 'utils/CommonUtils';
|
||||||
import { getEntityLineage, getEntityName } from 'utils/EntityUtils';
|
import {
|
||||||
|
getEntityLineage,
|
||||||
|
getEntityName,
|
||||||
|
getEntityThreadLink,
|
||||||
|
} from 'utils/EntityUtils';
|
||||||
import { getEntityFieldThreadCounts } from 'utils/FeedUtils';
|
import { getEntityFieldThreadCounts } from 'utils/FeedUtils';
|
||||||
import { DEFAULT_ENTITY_PERMISSION } from 'utils/PermissionsUtils';
|
import { DEFAULT_ENTITY_PERMISSION } from 'utils/PermissionsUtils';
|
||||||
import { getLineageViewPath } from 'utils/RouterUtils';
|
import { getLineageViewPath } from 'utils/RouterUtils';
|
||||||
@ -623,18 +627,28 @@ const ContainerPage = () => {
|
|||||||
className="entity-tag-right-panel-container"
|
className="entity-tag-right-panel-container"
|
||||||
data-testid="entity-right-panel"
|
data-testid="entity-right-panel"
|
||||||
flex="320px">
|
flex="320px">
|
||||||
<TagsContainerV1
|
<Space className="w-full" direction="vertical" size="large">
|
||||||
editable={hasEditDescriptionPermission}
|
<TagsContainerV1
|
||||||
entityFieldThreads={getEntityFieldThreadCounts(
|
entityFqn={containerName}
|
||||||
EntityField.TAGS,
|
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
|
||||||
entityFieldThreadCount
|
entityType={EntityType.CONTAINER}
|
||||||
)}
|
permission={hasEditDescriptionPermission}
|
||||||
entityFqn={containerName}
|
selectedTags={tags}
|
||||||
entityType={EntityType.CONTAINER}
|
tagType={TagSource.Classification}
|
||||||
selectedTags={tags}
|
onSelectionChange={handleTagSelection}
|
||||||
onSelectionChange={handleTagSelection}
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
onThreadLinkSelect={onThreadLinkSelect}
|
/>
|
||||||
/>
|
<TagsContainerV1
|
||||||
|
entityFqn={containerName}
|
||||||
|
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
|
||||||
|
entityType={EntityType.CONTAINER}
|
||||||
|
permission={hasEditDescriptionPermission}
|
||||||
|
selectedTags={tags}
|
||||||
|
tagType={TagSource.Glossary}
|
||||||
|
onSelectionChange={handleTagSelection}
|
||||||
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
),
|
),
|
||||||
|
@ -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 { Card, Col, Divider, Row, Tabs } from 'antd';
|
import { Card, Col, Divider, Row, Space, Tabs } from 'antd';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import ActivityFeedProvider, {
|
import ActivityFeedProvider, {
|
||||||
useActivityFeedProvider,
|
useActivityFeedProvider,
|
||||||
@ -46,7 +46,7 @@ import { compare } from 'fast-json-patch';
|
|||||||
import { CreateThread } from 'generated/api/feed/createThread';
|
import { CreateThread } from 'generated/api/feed/createThread';
|
||||||
import { JoinedWith, Table } from 'generated/entity/data/table';
|
import { JoinedWith, Table } from 'generated/entity/data/table';
|
||||||
import { ThreadType } from 'generated/entity/feed/thread';
|
import { ThreadType } from 'generated/entity/feed/thread';
|
||||||
import { LabelType, State, TagLabel } from 'generated/type/tagLabel';
|
import { LabelType, State, TagLabel, TagSource } from 'generated/type/tagLabel';
|
||||||
import { EntityFieldThreadCount } from 'interface/feed.interface';
|
import { EntityFieldThreadCount } from 'interface/feed.interface';
|
||||||
import { isEmpty, isEqual } from 'lodash';
|
import { isEmpty, isEqual } from 'lodash';
|
||||||
import { EntityTags } from 'Models';
|
import { EntityTags } from 'Models';
|
||||||
@ -71,7 +71,7 @@ import {
|
|||||||
sortTagsCaseInsensitive,
|
sortTagsCaseInsensitive,
|
||||||
} from 'utils/CommonUtils';
|
} from 'utils/CommonUtils';
|
||||||
import { defaultFields } from 'utils/DatasetDetailsUtils';
|
import { defaultFields } from 'utils/DatasetDetailsUtils';
|
||||||
import { getEntityName } from 'utils/EntityUtils';
|
import { getEntityName, getEntityThreadLink } from 'utils/EntityUtils';
|
||||||
import { getEntityFieldThreadCounts } from 'utils/FeedUtils';
|
import { getEntityFieldThreadCounts } from 'utils/FeedUtils';
|
||||||
import { DEFAULT_ENTITY_PERMISSION } from 'utils/PermissionsUtils';
|
import { DEFAULT_ENTITY_PERMISSION } from 'utils/PermissionsUtils';
|
||||||
import { createQueryFilter } from 'utils/Query/QueryUtils';
|
import { createQueryFilter } from 'utils/Query/QueryUtils';
|
||||||
@ -448,19 +448,30 @@ const TableDetailsPageV1 = () => {
|
|||||||
<Divider className="m-y-sm" />
|
<Divider className="m-y-sm" />
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
<TagsContainerV1
|
|
||||||
showLimited
|
<Space className="w-full" direction="vertical" size="large">
|
||||||
editable={tablePermissions.EditAll || tablePermissions.EditTags}
|
<TagsContainerV1
|
||||||
entityFieldThreads={getEntityFieldThreadCounts(
|
entityFqn={datasetFQN}
|
||||||
EntityField.TAGS,
|
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
|
||||||
entityFieldThreadCount
|
entityType={EntityType.TABLE}
|
||||||
)}
|
permission={tablePermissions.EditAll || tablePermissions.EditTags}
|
||||||
entityFqn={datasetFQN}
|
selectedTags={tableTags}
|
||||||
entityType={EntityType.TABLE}
|
tagType={TagSource.Classification}
|
||||||
selectedTags={tableTags}
|
onSelectionChange={handleTagSelection}
|
||||||
onSelectionChange={handleTagSelection}
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
onThreadLinkSelect={onThreadLinkSelect}
|
/>
|
||||||
/>
|
|
||||||
|
<TagsContainerV1
|
||||||
|
entityFqn={datasetFQN}
|
||||||
|
entityThreadLink={getEntityThreadLink(entityFieldThreadCount)}
|
||||||
|
entityType={EntityType.TABLE}
|
||||||
|
permission={tablePermissions.EditAll || tablePermissions.EditTags}
|
||||||
|
selectedTags={tableTags}
|
||||||
|
tagType={TagSource.Glossary}
|
||||||
|
onSelectionChange={handleTagSelection}
|
||||||
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
),
|
),
|
||||||
|
@ -27,6 +27,7 @@ import {
|
|||||||
SearchedDataProps,
|
SearchedDataProps,
|
||||||
SourceType,
|
SourceType,
|
||||||
} from 'components/searched-data/SearchedData.interface';
|
} from 'components/searched-data/SearchedData.interface';
|
||||||
|
import { EntityField } from 'constants/Feeds.constants';
|
||||||
import { ExplorePageTabs } from 'enums/Explore.enum';
|
import { ExplorePageTabs } from 'enums/Explore.enum';
|
||||||
import { Container } from 'generated/entity/data/container';
|
import { Container } from 'generated/entity/data/container';
|
||||||
import { DashboardDataModel } from 'generated/entity/data/dashboardDataModel';
|
import { DashboardDataModel } from 'generated/entity/data/dashboardDataModel';
|
||||||
@ -34,6 +35,7 @@ import { GlossaryTerm } from 'generated/entity/data/glossaryTerm';
|
|||||||
import { Mlmodel } from 'generated/entity/data/mlmodel';
|
import { Mlmodel } from 'generated/entity/data/mlmodel';
|
||||||
import { Topic } from 'generated/entity/data/topic';
|
import { Topic } from 'generated/entity/data/topic';
|
||||||
import i18next from 'i18next';
|
import i18next from 'i18next';
|
||||||
|
import { EntityFieldThreadCount } from 'interface/feed.interface';
|
||||||
import { get, isEmpty, isNil, isUndefined, lowerCase, startCase } from 'lodash';
|
import { get, isEmpty, isNil, isUndefined, lowerCase, startCase } from 'lodash';
|
||||||
import { Bucket, EntityDetailUnion } from 'Models';
|
import { Bucket, EntityDetailUnion } from 'Models';
|
||||||
import React, { Fragment } from 'react';
|
import React, { Fragment } from 'react';
|
||||||
@ -74,6 +76,7 @@ import {
|
|||||||
getPartialNameFromTableFQN,
|
getPartialNameFromTableFQN,
|
||||||
getTableFQNFromColumnFQN,
|
getTableFQNFromColumnFQN,
|
||||||
} from './CommonUtils';
|
} from './CommonUtils';
|
||||||
|
import { getEntityFieldThreadCounts } from './FeedUtils';
|
||||||
import Fqn from './Fqn';
|
import Fqn from './Fqn';
|
||||||
import { getGlossaryPath } from './RouterUtils';
|
import { getGlossaryPath } from './RouterUtils';
|
||||||
import {
|
import {
|
||||||
@ -1064,3 +1067,14 @@ export const getEntityLinkFromType = (
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getEntityThreadLink = (
|
||||||
|
entityFieldThreadCount: EntityFieldThreadCount[]
|
||||||
|
) => {
|
||||||
|
const thread = getEntityFieldThreadCounts(
|
||||||
|
EntityField.TAGS,
|
||||||
|
entityFieldThreadCount
|
||||||
|
);
|
||||||
|
|
||||||
|
return thread[0]?.entityLink;
|
||||||
|
};
|
||||||
|
@ -15,7 +15,7 @@ import { AxiosError } from 'axios';
|
|||||||
import { ModifiedGlossaryTerm } from 'components/Glossary/GlossaryTermTab/GlossaryTermTab.interface';
|
import { ModifiedGlossaryTerm } from 'components/Glossary/GlossaryTermTab/GlossaryTermTab.interface';
|
||||||
import {
|
import {
|
||||||
GlossaryTermDetailsProps,
|
GlossaryTermDetailsProps,
|
||||||
GlossaryTermNodeProps,
|
HierarchyTagsProps,
|
||||||
} from 'components/Tag/TagsContainerV1/TagsContainerV1.interface';
|
} from 'components/Tag/TagsContainerV1/TagsContainerV1.interface';
|
||||||
import { isUndefined, omit } from 'lodash';
|
import { isUndefined, omit } from 'lodash';
|
||||||
import { ListGlossaryTermsParams } from 'rest/glossaryAPI';
|
import { ListGlossaryTermsParams } from 'rest/glossaryAPI';
|
||||||
@ -224,9 +224,9 @@ export const formatRelatedTermOptions = (
|
|||||||
|
|
||||||
export const getGlossaryTermHierarchy = (
|
export const getGlossaryTermHierarchy = (
|
||||||
data: GlossaryTermDetailsProps[]
|
data: GlossaryTermDetailsProps[]
|
||||||
): GlossaryTermNodeProps[] => {
|
): HierarchyTagsProps[] => {
|
||||||
const nodes: Record<string, GlossaryTermNodeProps> = {};
|
const nodes: Record<string, HierarchyTagsProps> = {};
|
||||||
const tree: GlossaryTermNodeProps[] = [];
|
const tree: HierarchyTagsProps[] = [];
|
||||||
|
|
||||||
data.forEach((obj) => {
|
data.forEach((obj) => {
|
||||||
if (obj.fqn) {
|
if (obj.fqn) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user