mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-12-16 18:15:17 +00:00
fix: add request tags and desc for glossary and terms (#14071)
* fix: add request tags and desc for glossary and terms * fix: breadcrumbs * fix: add request tags cypress
This commit is contained in:
parent
631145d090
commit
312b038b2b
@ -39,10 +39,12 @@ import {
|
|||||||
SEARCH_ENTITY_TABLE,
|
SEARCH_ENTITY_TABLE,
|
||||||
} from '../../constants/constants';
|
} from '../../constants/constants';
|
||||||
|
|
||||||
|
const name = `test_dataconsumer${uuid()}`;
|
||||||
|
|
||||||
const CREDENTIALS = {
|
const CREDENTIALS = {
|
||||||
firstName: 'Cypress',
|
firstName: 'Cypress',
|
||||||
lastName: 'UserDC',
|
lastName: 'UserDC',
|
||||||
email: `test_dataconsumer${uuid()}@openmetadata.org`,
|
email: `${name}@openmetadata.org`,
|
||||||
password: 'User@OMD123',
|
password: 'User@OMD123',
|
||||||
username: 'CypressUserDC',
|
username: 'CypressUserDC',
|
||||||
};
|
};
|
||||||
@ -278,9 +280,7 @@ const updateTags = (inTerm) => {
|
|||||||
'/api/v1/search/query?q=*&index=tag_search_index&from=0&size=*&query_filter=*',
|
'/api/v1/search/query?q=*&index=tag_search_index&from=0&size=*&query_filter=*',
|
||||||
'tags'
|
'tags'
|
||||||
);
|
);
|
||||||
cy.get(
|
cy.get('[data-testid="tags-container"] [data-testid="add-tag"]').click();
|
||||||
'[data-testid="tags-input-container"] [data-testid="add-tag"]'
|
|
||||||
).click();
|
|
||||||
|
|
||||||
verifyResponseStatusCode('@tags', 200);
|
verifyResponseStatusCode('@tags', 200);
|
||||||
|
|
||||||
@ -294,7 +294,7 @@ const updateTags = (inTerm) => {
|
|||||||
|
|
||||||
cy.get('[data-testid="saveAssociatedTag"]').scrollIntoView().click();
|
cy.get('[data-testid="saveAssociatedTag"]').scrollIntoView().click();
|
||||||
const container = inTerm
|
const container = inTerm
|
||||||
? '[data-testid="tags-input-container"]'
|
? '[data-testid="tags-container"]'
|
||||||
: '[data-testid="glossary-details"]';
|
: '[data-testid="glossary-details"]';
|
||||||
cy.wait(1000);
|
cy.wait(1000);
|
||||||
cy.get(container).scrollIntoView().contains('Personal').should('be.visible');
|
cy.get(container).scrollIntoView().contains('Personal').should('be.visible');
|
||||||
@ -636,7 +636,7 @@ describe('Glossary page should work properly', () => {
|
|||||||
|
|
||||||
// Remove Tag
|
// Remove Tag
|
||||||
cy.get(
|
cy.get(
|
||||||
'[data-testid="tags-input-container"] [data-testid="edit-button"]'
|
'[data-testid="tags-container"] [data-testid="edit-button"]'
|
||||||
).click();
|
).click();
|
||||||
|
|
||||||
cy.get('[data-testid="remove-tags"]').should('be.visible').click();
|
cy.get('[data-testid="remove-tags"]').should('be.visible').click();
|
||||||
@ -768,6 +768,64 @@ describe('Glossary page should work properly', () => {
|
|||||||
voteGlossary();
|
voteGlossary();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Request Tags workflow for Glossary', function () {
|
||||||
|
cy.get('[data-testid="glossary-left-panel"]')
|
||||||
|
.contains(NEW_GLOSSARY_1.name)
|
||||||
|
.click();
|
||||||
|
|
||||||
|
interceptURL(
|
||||||
|
'GET',
|
||||||
|
`/api/v1/search/query?q=*%20AND%20disabled:false&index=tag_search_index*`,
|
||||||
|
'suggestTag'
|
||||||
|
);
|
||||||
|
interceptURL('POST', '/api/v1/feed', 'taskCreated');
|
||||||
|
interceptURL('PUT', '/api/v1/feed/tasks/*/resolve', 'taskResolve');
|
||||||
|
|
||||||
|
cy.get('[data-testid="request-entity-tags"]').should('exist').click();
|
||||||
|
|
||||||
|
// set assignees for task
|
||||||
|
cy.get(
|
||||||
|
'[data-testid="select-assignee"] > .ant-select-selector > .ant-select-selection-overflow'
|
||||||
|
)
|
||||||
|
.click()
|
||||||
|
.type(name);
|
||||||
|
cy.get(`[data-testid="assignee-option-${name}"]`).click();
|
||||||
|
cy.clickOutside();
|
||||||
|
|
||||||
|
cy.get('[data-testid="tag-selector"]')
|
||||||
|
.click()
|
||||||
|
.type('{backspace}')
|
||||||
|
.type('{backspace}')
|
||||||
|
.type('Personal');
|
||||||
|
|
||||||
|
verifyResponseStatusCode('@suggestTag', 200);
|
||||||
|
cy.get(
|
||||||
|
'.ant-select-dropdown [data-testid="tag-PersonalData.Personal"]'
|
||||||
|
).click();
|
||||||
|
cy.clickOutside();
|
||||||
|
|
||||||
|
cy.get('[data-testid="submit-tag-request"]').click();
|
||||||
|
verifyResponseStatusCode('@taskCreated', 201);
|
||||||
|
|
||||||
|
// Accept the tag suggestion which is created
|
||||||
|
cy.get('.ant-btn-compact-first-item').contains('Accept Suggestion').click();
|
||||||
|
|
||||||
|
verifyResponseStatusCode('@taskResolve', 200);
|
||||||
|
|
||||||
|
cy.reload();
|
||||||
|
|
||||||
|
cy.get('[data-testid="glossary-left-panel"]')
|
||||||
|
.contains(NEW_GLOSSARY_1.name)
|
||||||
|
.click();
|
||||||
|
|
||||||
|
checkDisplayName(NEW_GLOSSARY_1.name);
|
||||||
|
|
||||||
|
// Verify Tags which is added at the time of creating glossary
|
||||||
|
cy.get('[data-testid="tags-container"]')
|
||||||
|
.contains('Personal')
|
||||||
|
.should('be.visible');
|
||||||
|
});
|
||||||
|
|
||||||
it('Assets Tab should work properly', () => {
|
it('Assets Tab should work properly', () => {
|
||||||
selectActiveGlossary(NEW_GLOSSARY.name);
|
selectActiveGlossary(NEW_GLOSSARY.name);
|
||||||
const glossary = NEW_GLOSSARY.name;
|
const glossary = NEW_GLOSSARY.name;
|
||||||
|
|||||||
@ -46,6 +46,7 @@ const GlossaryDetails = ({
|
|||||||
onAddGlossaryTerm,
|
onAddGlossaryTerm,
|
||||||
onEditGlossaryTerm,
|
onEditGlossaryTerm,
|
||||||
isVersionView,
|
isVersionView,
|
||||||
|
onThreadLinkSelect,
|
||||||
}: GlossaryDetailsProps) => {
|
}: GlossaryDetailsProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
@ -131,15 +132,19 @@ const GlossaryDetails = ({
|
|||||||
<Space className="w-full" direction="vertical" size={24}>
|
<Space className="w-full" direction="vertical" size={24}>
|
||||||
<DescriptionV1
|
<DescriptionV1
|
||||||
description={description}
|
description={description}
|
||||||
|
entityFqn={glossary.fullyQualifiedName}
|
||||||
entityName={glossary.displayName ?? glossary.name}
|
entityName={glossary.displayName ?? glossary.name}
|
||||||
entityType={EntityType.GLOSSARY}
|
entityType={EntityType.GLOSSARY}
|
||||||
hasEditAccess={permissions.EditDescription || permissions.EditAll}
|
hasEditAccess={permissions.EditDescription || permissions.EditAll}
|
||||||
isEdit={isDescriptionEditable}
|
isEdit={isDescriptionEditable}
|
||||||
showCommentsIcon={false}
|
owner={glossary?.owner}
|
||||||
|
showActions={!glossary.deleted}
|
||||||
onCancel={() => setIsDescriptionEditable(false)}
|
onCancel={() => setIsDescriptionEditable(false)}
|
||||||
onDescriptionEdit={() => setIsDescriptionEditable(true)}
|
onDescriptionEdit={() => setIsDescriptionEditable(true)}
|
||||||
onDescriptionUpdate={onDescriptionUpdate}
|
onDescriptionUpdate={onDescriptionUpdate}
|
||||||
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<GlossaryTermTab
|
<GlossaryTermTab
|
||||||
isGlossary
|
isGlossary
|
||||||
childGlossaryTerms={glossaryTerms}
|
childGlossaryTerms={glossaryTerms}
|
||||||
@ -158,6 +163,7 @@ const GlossaryDetails = ({
|
|||||||
isVersionView={isVersionView}
|
isVersionView={isVersionView}
|
||||||
permissions={permissions}
|
permissions={permissions}
|
||||||
selectedData={glossary}
|
selectedData={glossary}
|
||||||
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
onUpdate={updateGlossary}
|
onUpdate={updateGlossary}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
|
|||||||
@ -33,4 +33,5 @@ export type GlossaryDetailsProps = {
|
|||||||
refreshGlossaryTerms: () => void;
|
refreshGlossaryTerms: () => void;
|
||||||
onAddGlossaryTerm: (glossaryTerm: GlossaryTerm | undefined) => void;
|
onAddGlossaryTerm: (glossaryTerm: GlossaryTerm | undefined) => void;
|
||||||
onEditGlossaryTerm: (glossaryTerm: GlossaryTerm) => void;
|
onEditGlossaryTerm: (glossaryTerm: GlossaryTerm) => void;
|
||||||
|
onThreadLinkSelect: (value: string) => void;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -65,6 +65,7 @@ const mockProps = {
|
|||||||
onAddGlossaryTerm: jest.fn(),
|
onAddGlossaryTerm: jest.fn(),
|
||||||
onEditGlossaryTerm: jest.fn(),
|
onEditGlossaryTerm: jest.fn(),
|
||||||
updateVote: jest.fn(),
|
updateVote: jest.fn(),
|
||||||
|
onThreadLinkSelect: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('Test Glossary-details component', () => {
|
describe('Test Glossary-details component', () => {
|
||||||
|
|||||||
@ -22,7 +22,6 @@ import { UserSelectableList } from '../../../components/common/UserSelectableLis
|
|||||||
import { UserTeamSelectableList } from '../../../components/common/UserTeamSelectableList/UserTeamSelectableList.component';
|
import { UserTeamSelectableList } from '../../../components/common/UserTeamSelectableList/UserTeamSelectableList.component';
|
||||||
import { OperationPermission } from '../../../components/PermissionProvider/PermissionProvider.interface';
|
import { OperationPermission } from '../../../components/PermissionProvider/PermissionProvider.interface';
|
||||||
import TagButton from '../../../components/TagButton/TagButton.component';
|
import TagButton from '../../../components/TagButton/TagButton.component';
|
||||||
import TagsInput from '../../../components/TagsInput/TagsInput.component';
|
|
||||||
import {
|
import {
|
||||||
DE_ACTIVE_COLOR,
|
DE_ACTIVE_COLOR,
|
||||||
getTeamAndUserDetailsPath,
|
getTeamAndUserDetailsPath,
|
||||||
@ -31,7 +30,7 @@ import {
|
|||||||
} from '../../../constants/constants';
|
} from '../../../constants/constants';
|
||||||
import { EntityField } from '../../../constants/Feeds.constants';
|
import { EntityField } from '../../../constants/Feeds.constants';
|
||||||
import { EntityType } from '../../../enums/entity.enum';
|
import { EntityType } from '../../../enums/entity.enum';
|
||||||
import { Glossary } from '../../../generated/entity/data/glossary';
|
import { Glossary, TagSource } from '../../../generated/entity/data/glossary';
|
||||||
import {
|
import {
|
||||||
GlossaryTerm,
|
GlossaryTerm,
|
||||||
TagLabel,
|
TagLabel,
|
||||||
@ -47,6 +46,8 @@ import {
|
|||||||
getEntityVersionTags,
|
getEntityVersionTags,
|
||||||
} from '../../../utils/EntityVersionUtils';
|
} from '../../../utils/EntityVersionUtils';
|
||||||
import { DomainLabel } from '../../common/DomainLabel/DomainLabel.component';
|
import { DomainLabel } from '../../common/DomainLabel/DomainLabel.component';
|
||||||
|
import TagsContainerV2 from '../../Tag/TagsContainerV2/TagsContainerV2';
|
||||||
|
import { DisplayType } from '../../Tag/TagsViewer/TagsViewer.interface';
|
||||||
import GlossaryReviewers from './GlossaryReviewers';
|
import GlossaryReviewers from './GlossaryReviewers';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -55,6 +56,7 @@ type Props = {
|
|||||||
selectedData: Glossary | GlossaryTerm;
|
selectedData: Glossary | GlossaryTerm;
|
||||||
isGlossary: boolean;
|
isGlossary: boolean;
|
||||||
onUpdate: (data: GlossaryTerm | Glossary) => void;
|
onUpdate: (data: GlossaryTerm | Glossary) => void;
|
||||||
|
onThreadLinkSelect: (value: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const GlossaryDetailsRightPanel = ({
|
const GlossaryDetailsRightPanel = ({
|
||||||
@ -63,6 +65,7 @@ const GlossaryDetailsRightPanel = ({
|
|||||||
isGlossary,
|
isGlossary,
|
||||||
onUpdate,
|
onUpdate,
|
||||||
isVersionView,
|
isVersionView,
|
||||||
|
onThreadLinkSelect,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const hasEditReviewerAccess = useMemo(() => {
|
const hasEditReviewerAccess = useMemo(() => {
|
||||||
return permissions.EditAll || permissions.EditReviewers;
|
return permissions.EditAll || permissions.EditReviewers;
|
||||||
@ -307,11 +310,15 @@ const GlossaryDetailsRightPanel = ({
|
|||||||
<Col span="24">
|
<Col span="24">
|
||||||
<div data-testid="glossary-tags-name">
|
<div data-testid="glossary-tags-name">
|
||||||
{isGlossary && (
|
{isGlossary && (
|
||||||
<TagsInput
|
<TagsContainerV2
|
||||||
editable={permissions.EditAll || permissions.EditTags}
|
displayType={DisplayType.READ_MORE}
|
||||||
isVersionView={isVersionView}
|
entityFqn={selectedData.fullyQualifiedName}
|
||||||
tags={tags}
|
entityType={EntityType.GLOSSARY}
|
||||||
onTagsUpdate={handleTagsUpdate}
|
permission={permissions.EditAll || permissions.EditTags}
|
||||||
|
selectedTags={tags ?? []}
|
||||||
|
tagType={TagSource.Classification}
|
||||||
|
onSelectionChange={handleTagsUpdate}
|
||||||
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -48,6 +48,7 @@ describe('GlossaryDetailsRightPanel', () => {
|
|||||||
isGlossary
|
isGlossary
|
||||||
permissions={mockPermissions}
|
permissions={mockPermissions}
|
||||||
selectedData={mockedGlossaries[0]}
|
selectedData={mockedGlossaries[0]}
|
||||||
|
onThreadLinkSelect={jest.fn()}
|
||||||
onUpdate={jest.fn()}
|
onUpdate={jest.fn()}
|
||||||
/>
|
/>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
|
|||||||
@ -63,6 +63,7 @@ const GlossaryTermsV1 = ({
|
|||||||
updateVote,
|
updateVote,
|
||||||
refreshActiveGlossaryTerm,
|
refreshActiveGlossaryTerm,
|
||||||
isVersionView,
|
isVersionView,
|
||||||
|
onThreadLinkSelect,
|
||||||
}: GlossaryTermsV1Props) => {
|
}: GlossaryTermsV1Props) => {
|
||||||
const {
|
const {
|
||||||
fqn: glossaryFqn,
|
fqn: glossaryFqn,
|
||||||
@ -130,6 +131,7 @@ const GlossaryTermsV1 = ({
|
|||||||
isVersionView={isVersionView}
|
isVersionView={isVersionView}
|
||||||
permissions={permissions}
|
permissions={permissions}
|
||||||
selectedData={glossaryTerm}
|
selectedData={glossaryTerm}
|
||||||
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
onUpdate={(data) => handleGlossaryTermUpdate(data as GlossaryTerm)}
|
onUpdate={(data) => handleGlossaryTermUpdate(data as GlossaryTerm)}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
|
|||||||
@ -30,4 +30,5 @@ export interface GlossaryTermsV1Props {
|
|||||||
onEditGlossaryTerm: (glossaryTerm: GlossaryTerm) => void;
|
onEditGlossaryTerm: (glossaryTerm: GlossaryTerm) => void;
|
||||||
updateVote?: (data: VotingDataProps) => Promise<void>;
|
updateVote?: (data: VotingDataProps) => Promise<void>;
|
||||||
refreshActiveGlossaryTerm?: () => void;
|
refreshActiveGlossaryTerm?: () => void;
|
||||||
|
onThreadLinkSelect: (value: string) => void;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -83,6 +83,7 @@ const mockProps = {
|
|||||||
refreshActiveGlossaryTerm: jest.fn(),
|
refreshActiveGlossaryTerm: jest.fn(),
|
||||||
onAddGlossaryTerm: jest.fn(),
|
onAddGlossaryTerm: jest.fn(),
|
||||||
onEditGlossaryTerm: jest.fn(),
|
onEditGlossaryTerm: jest.fn(),
|
||||||
|
onThreadLinkSelect: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('Test Glossary-term component', () => {
|
describe('Test Glossary-term component', () => {
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import { EntityType } from '../../../../enums/entity.enum';
|
|||||||
import { Glossary } from '../../../../generated/entity/data/glossary';
|
import { Glossary } from '../../../../generated/entity/data/glossary';
|
||||||
import { GlossaryTerm } from '../../../../generated/entity/data/glossaryTerm';
|
import { GlossaryTerm } from '../../../../generated/entity/data/glossaryTerm';
|
||||||
import { ChangeDescription } from '../../../../generated/entity/type';
|
import { ChangeDescription } from '../../../../generated/entity/type';
|
||||||
import { TagLabel } from '../../../../generated/type/tagLabel';
|
import { TagLabel, TagSource } from '../../../../generated/type/tagLabel';
|
||||||
import { getEntityName } from '../../../../utils/EntityUtils';
|
import { getEntityName } from '../../../../utils/EntityUtils';
|
||||||
import {
|
import {
|
||||||
getEntityVersionByField,
|
getEntityVersionByField,
|
||||||
@ -25,7 +25,8 @@ import {
|
|||||||
} from '../../../../utils/EntityVersionUtils';
|
} from '../../../../utils/EntityVersionUtils';
|
||||||
import DescriptionV1 from '../../../common/EntityDescription/DescriptionV1';
|
import DescriptionV1 from '../../../common/EntityDescription/DescriptionV1';
|
||||||
import { OperationPermission } from '../../../PermissionProvider/PermissionProvider.interface';
|
import { OperationPermission } from '../../../PermissionProvider/PermissionProvider.interface';
|
||||||
import TagsInput from '../../../TagsInput/TagsInput.component';
|
import TagsContainerV2 from '../../../Tag/TagsContainerV2/TagsContainerV2';
|
||||||
|
import { DisplayType } from '../../../Tag/TagsViewer/TagsViewer.interface';
|
||||||
import GlossaryDetailsRightPanel from '../../GlossaryDetailsRightPanel/GlossaryDetailsRightPanel.component';
|
import GlossaryDetailsRightPanel from '../../GlossaryDetailsRightPanel/GlossaryDetailsRightPanel.component';
|
||||||
import GlossaryTermReferences from './GlossaryTermReferences';
|
import GlossaryTermReferences from './GlossaryTermReferences';
|
||||||
import GlossaryTermSynonyms from './GlossaryTermSynonyms';
|
import GlossaryTermSynonyms from './GlossaryTermSynonyms';
|
||||||
@ -37,6 +38,7 @@ type Props = {
|
|||||||
onUpdate: (data: GlossaryTerm | Glossary) => Promise<void>;
|
onUpdate: (data: GlossaryTerm | Glossary) => Promise<void>;
|
||||||
isGlossary: boolean;
|
isGlossary: boolean;
|
||||||
isVersionView?: boolean;
|
isVersionView?: boolean;
|
||||||
|
onThreadLinkSelect: (value: string) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const GlossaryOverviewTab = ({
|
const GlossaryOverviewTab = ({
|
||||||
@ -45,6 +47,7 @@ const GlossaryOverviewTab = ({
|
|||||||
onUpdate,
|
onUpdate,
|
||||||
isGlossary,
|
isGlossary,
|
||||||
isVersionView,
|
isVersionView,
|
||||||
|
onThreadLinkSelect,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const [isDescriptionEditable, setIsDescriptionEditable] =
|
const [isDescriptionEditable, setIsDescriptionEditable] =
|
||||||
useState<boolean>(false);
|
useState<boolean>(false);
|
||||||
@ -110,14 +113,17 @@ const GlossaryOverviewTab = ({
|
|||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
<DescriptionV1
|
<DescriptionV1
|
||||||
description={glossaryDescription}
|
description={glossaryDescription}
|
||||||
|
entityFqn={selectedData.fullyQualifiedName}
|
||||||
entityName={getEntityName(selectedData)}
|
entityName={getEntityName(selectedData)}
|
||||||
entityType={EntityType.GLOSSARY}
|
entityType={EntityType.GLOSSARY_TERM}
|
||||||
hasEditAccess={permissions.EditDescription || permissions.EditAll}
|
hasEditAccess={permissions.EditDescription || permissions.EditAll}
|
||||||
isEdit={isDescriptionEditable}
|
isEdit={isDescriptionEditable}
|
||||||
showCommentsIcon={false}
|
owner={selectedData?.owner}
|
||||||
|
showActions={!selectedData.deleted}
|
||||||
onCancel={() => setIsDescriptionEditable(false)}
|
onCancel={() => setIsDescriptionEditable(false)}
|
||||||
onDescriptionEdit={() => setIsDescriptionEditable(true)}
|
onDescriptionEdit={() => setIsDescriptionEditable(true)}
|
||||||
onDescriptionUpdate={onDescriptionUpdate}
|
onDescriptionUpdate={onDescriptionUpdate}
|
||||||
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
@ -153,11 +159,15 @@ const GlossaryOverviewTab = ({
|
|||||||
|
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Space className="w-full" direction="vertical">
|
<Space className="w-full" direction="vertical">
|
||||||
<TagsInput
|
<TagsContainerV2
|
||||||
editable={hasEditTagsPermissions}
|
displayType={DisplayType.READ_MORE}
|
||||||
isVersionView={isVersionView}
|
entityFqn={selectedData.fullyQualifiedName}
|
||||||
tags={tags}
|
entityType={EntityType.GLOSSARY_TERM}
|
||||||
onTagsUpdate={handleTagsUpdate}
|
permission={hasEditTagsPermissions}
|
||||||
|
selectedTags={tags ?? []}
|
||||||
|
tagType={TagSource.Classification}
|
||||||
|
onSelectionChange={handleTagsUpdate}
|
||||||
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</Col>
|
</Col>
|
||||||
@ -171,6 +181,7 @@ const GlossaryOverviewTab = ({
|
|||||||
isVersionView={isVersionView}
|
isVersionView={isVersionView}
|
||||||
permissions={permissions}
|
permissions={permissions}
|
||||||
selectedData={selectedData}
|
selectedData={selectedData}
|
||||||
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
onUpdate={onUpdate}
|
onUpdate={onUpdate}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
|
|||||||
@ -50,6 +50,7 @@ describe('GlossaryOverviewTab', () => {
|
|||||||
isGlossary={isGlossary}
|
isGlossary={isGlossary}
|
||||||
permissions={permissions}
|
permissions={permissions}
|
||||||
selectedData={selectedData}
|
selectedData={selectedData}
|
||||||
|
onThreadLinkSelect={jest.fn()}
|
||||||
onUpdate={onUpdate}
|
onUpdate={onUpdate}
|
||||||
/>
|
/>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
|
|||||||
@ -25,9 +25,14 @@ import {
|
|||||||
getGlossaryTermDetailsPath,
|
getGlossaryTermDetailsPath,
|
||||||
} from '../../constants/constants';
|
} from '../../constants/constants';
|
||||||
import { EntityAction } from '../../enums/entity.enum';
|
import { EntityAction } from '../../enums/entity.enum';
|
||||||
|
import {
|
||||||
|
CreateThread,
|
||||||
|
ThreadType,
|
||||||
|
} from '../../generated/api/feed/createThread';
|
||||||
import { Glossary } from '../../generated/entity/data/glossary';
|
import { Glossary } from '../../generated/entity/data/glossary';
|
||||||
import { GlossaryTerm } from '../../generated/entity/data/glossaryTerm';
|
import { GlossaryTerm } from '../../generated/entity/data/glossaryTerm';
|
||||||
import { VERSION_VIEW_GLOSSARY_PERMISSION } from '../../mocks/Glossary.mock';
|
import { VERSION_VIEW_GLOSSARY_PERMISSION } from '../../mocks/Glossary.mock';
|
||||||
|
import { postThread } from '../../rest/feedsAPI';
|
||||||
import {
|
import {
|
||||||
addGlossaryTerm,
|
addGlossaryTerm,
|
||||||
getGlossaryTerms,
|
getGlossaryTerms,
|
||||||
@ -37,6 +42,8 @@ import {
|
|||||||
import { getEntityDeleteMessage } from '../../utils/CommonUtils';
|
import { getEntityDeleteMessage } from '../../utils/CommonUtils';
|
||||||
import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils';
|
import { DEFAULT_ENTITY_PERMISSION } from '../../utils/PermissionsUtils';
|
||||||
import { showErrorToast } from '../../utils/ToastUtils';
|
import { showErrorToast } from '../../utils/ToastUtils';
|
||||||
|
import { useActivityFeedProvider } from '../ActivityFeed/ActivityFeedProvider/ActivityFeedProvider';
|
||||||
|
import ActivityThreadPanel from '../ActivityFeed/ActivityThreadPanel/ActivityThreadPanel';
|
||||||
import EntityDeleteModal from '../Modals/EntityDeleteModal/EntityDeleteModal';
|
import EntityDeleteModal from '../Modals/EntityDeleteModal/EntityDeleteModal';
|
||||||
import { usePermissionProvider } from '../PermissionProvider/PermissionProvider';
|
import { usePermissionProvider } from '../PermissionProvider/PermissionProvider';
|
||||||
import {
|
import {
|
||||||
@ -69,6 +76,11 @@ const GlossaryV1 = ({
|
|||||||
const { action, tab } =
|
const { action, tab } =
|
||||||
useParams<{ action: EntityAction; glossaryName: string; tab: string }>();
|
useParams<{ action: EntityAction; glossaryName: string; tab: string }>();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
const [threadLink, setThreadLink] = useState<string>('');
|
||||||
|
const [threadType, setThreadType] = useState<ThreadType>(
|
||||||
|
ThreadType.Conversation
|
||||||
|
);
|
||||||
|
const { postFeed, deleteFeed, updateFeed } = useActivityFeedProvider();
|
||||||
|
|
||||||
const { getEntityPermission } = usePermissionProvider();
|
const { getEntityPermission } = usePermissionProvider();
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
@ -96,6 +108,17 @@ const GlossaryV1 = ({
|
|||||||
[action]
|
[action]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const onThreadPanelClose = () => {
|
||||||
|
setThreadLink('');
|
||||||
|
};
|
||||||
|
|
||||||
|
const onThreadLinkSelect = (link: string, threadType?: ThreadType) => {
|
||||||
|
setThreadLink(link);
|
||||||
|
if (threadType) {
|
||||||
|
setThreadType(threadType);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const fetchGlossaryTerm = async (
|
const fetchGlossaryTerm = async (
|
||||||
params?: ListGlossaryTermsParams,
|
params?: ListGlossaryTermsParams,
|
||||||
refresh?: boolean
|
refresh?: boolean
|
||||||
@ -139,6 +162,19 @@ const GlossaryV1 = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const createThread = async (data: CreateThread) => {
|
||||||
|
try {
|
||||||
|
await postThread(data);
|
||||||
|
} catch (error) {
|
||||||
|
showErrorToast(
|
||||||
|
error as AxiosError,
|
||||||
|
t('server.create-entity-error', {
|
||||||
|
entity: t('label.conversation'),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleDelete = () => {
|
const handleDelete = () => {
|
||||||
const { id } = selectedData;
|
const { id } = selectedData;
|
||||||
if (isGlossaryActive) {
|
if (isGlossaryActive) {
|
||||||
@ -329,6 +365,7 @@ const GlossaryV1 = ({
|
|||||||
onEditGlossaryTerm={(term) =>
|
onEditGlossaryTerm={(term) =>
|
||||||
handleGlossaryTermModalAction(true, term)
|
handleGlossaryTermModalAction(true, term)
|
||||||
}
|
}
|
||||||
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<GlossaryTermsV1
|
<GlossaryTermsV1
|
||||||
@ -350,6 +387,7 @@ const GlossaryV1 = ({
|
|||||||
onEditGlossaryTerm={(term) =>
|
onEditGlossaryTerm={(term) =>
|
||||||
handleGlossaryTermModalAction(true, term)
|
handleGlossaryTermModalAction(true, term)
|
||||||
}
|
}
|
||||||
|
onThreadLinkSelect={onThreadLinkSelect}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
@ -376,6 +414,19 @@ const GlossaryV1 = ({
|
|||||||
onSave={handleGlossaryTermSave}
|
onSave={handleGlossaryTermSave}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{threadLink ? (
|
||||||
|
<ActivityThreadPanel
|
||||||
|
createThread={createThread}
|
||||||
|
deletePostHandler={deleteFeed}
|
||||||
|
open={Boolean(threadLink)}
|
||||||
|
postFeedHandler={postFeed}
|
||||||
|
threadLink={threadLink}
|
||||||
|
threadType={threadType}
|
||||||
|
updateThreadHandler={updateFeed}
|
||||||
|
onCancel={onThreadPanelClose}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -342,6 +342,7 @@ export const TaskTab = ({
|
|||||||
</Button>
|
</Button>
|
||||||
) : (
|
) : (
|
||||||
<Dropdown.Button
|
<Dropdown.Button
|
||||||
|
data-testid="edit-accept-task-dropdown"
|
||||||
icon={<DownOutlined />}
|
icon={<DownOutlined />}
|
||||||
menu={{
|
menu={{
|
||||||
items: TASK_ACTION_LIST,
|
items: TASK_ACTION_LIST,
|
||||||
|
|||||||
@ -16,6 +16,8 @@ import { Dashboard } from '../../generated/entity/data/dashboard';
|
|||||||
import { DashboardDataModel } from '../../generated/entity/data/dashboardDataModel';
|
import { DashboardDataModel } from '../../generated/entity/data/dashboardDataModel';
|
||||||
import { Database } from '../../generated/entity/data/database';
|
import { Database } from '../../generated/entity/data/database';
|
||||||
import { DatabaseSchema } from '../../generated/entity/data/databaseSchema';
|
import { DatabaseSchema } from '../../generated/entity/data/databaseSchema';
|
||||||
|
import { Glossary } from '../../generated/entity/data/glossary';
|
||||||
|
import { GlossaryTerm } from '../../generated/entity/data/glossaryTerm';
|
||||||
import { Mlmodel } from '../../generated/entity/data/mlmodel';
|
import { Mlmodel } from '../../generated/entity/data/mlmodel';
|
||||||
import { Pipeline } from '../../generated/entity/data/pipeline';
|
import { Pipeline } from '../../generated/entity/data/pipeline';
|
||||||
import { SearchIndex } from '../../generated/entity/data/searchIndex';
|
import { SearchIndex } from '../../generated/entity/data/searchIndex';
|
||||||
@ -34,7 +36,9 @@ export type EntityData =
|
|||||||
| Database
|
| Database
|
||||||
| DatabaseSchema
|
| DatabaseSchema
|
||||||
| DashboardDataModel
|
| DashboardDataModel
|
||||||
| SearchIndex;
|
| SearchIndex
|
||||||
|
| Glossary
|
||||||
|
| GlossaryTerm;
|
||||||
|
|
||||||
export interface Option {
|
export interface Option {
|
||||||
label: string;
|
label: string;
|
||||||
|
|||||||
@ -15,7 +15,10 @@ import { AxiosError } from 'axios';
|
|||||||
import { isUndefined, omit } from 'lodash';
|
import { isUndefined, omit } from 'lodash';
|
||||||
import { StatusType } from '../components/common/StatusBadge/StatusBadge.interface';
|
import { StatusType } from '../components/common/StatusBadge/StatusBadge.interface';
|
||||||
import { ModifiedGlossaryTerm } from '../components/Glossary/GlossaryTermTab/GlossaryTermTab.interface';
|
import { ModifiedGlossaryTerm } from '../components/Glossary/GlossaryTermTab/GlossaryTermTab.interface';
|
||||||
import { WILD_CARD_CHAR } from '../constants/char.constants';
|
import {
|
||||||
|
FQN_SEPARATOR_CHAR,
|
||||||
|
WILD_CARD_CHAR,
|
||||||
|
} from '../constants/char.constants';
|
||||||
import { SearchIndex } from '../enums/search.enum';
|
import { SearchIndex } from '../enums/search.enum';
|
||||||
import { Glossary } from '../generated/entity/data/glossary';
|
import { Glossary } from '../generated/entity/data/glossary';
|
||||||
import { GlossaryTerm, Status } from '../generated/entity/data/glossaryTerm';
|
import { GlossaryTerm, Status } from '../generated/entity/data/glossaryTerm';
|
||||||
@ -24,6 +27,8 @@ import { SearchResponse } from '../interface/search.interface';
|
|||||||
import { ListGlossaryTermsParams } from '../rest/glossaryAPI';
|
import { ListGlossaryTermsParams } from '../rest/glossaryAPI';
|
||||||
import { searchData } from '../rest/miscAPI';
|
import { searchData } from '../rest/miscAPI';
|
||||||
import { formatSearchGlossaryTermResponse } from './APIUtils';
|
import { formatSearchGlossaryTermResponse } from './APIUtils';
|
||||||
|
import Fqn from './Fqn';
|
||||||
|
import { getGlossaryPath } from './RouterUtils';
|
||||||
|
|
||||||
export interface GlossaryTermTreeNode {
|
export interface GlossaryTermTreeNode {
|
||||||
children?: GlossaryTermTreeNode[];
|
children?: GlossaryTermTreeNode[];
|
||||||
@ -234,3 +239,26 @@ export const StatusFilters = Object.values(Status)
|
|||||||
text: status,
|
text: status,
|
||||||
value: status,
|
value: status,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
export const getGlossaryBreadcrumbs = (fqn: string) => {
|
||||||
|
const arr = Fqn.split(fqn);
|
||||||
|
const dataFQN: Array<string> = [];
|
||||||
|
const breadcrumbList = [
|
||||||
|
{
|
||||||
|
name: 'Glossaries',
|
||||||
|
url: getGlossaryPath(''),
|
||||||
|
activeTitle: false,
|
||||||
|
},
|
||||||
|
...arr.map((d) => {
|
||||||
|
dataFQN.push(d);
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: d,
|
||||||
|
url: getGlossaryPath(dataFQN.join(FQN_SEPARATOR_CHAR)),
|
||||||
|
activeTitle: false,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
return breadcrumbList;
|
||||||
|
};
|
||||||
|
|||||||
@ -53,6 +53,7 @@ import {
|
|||||||
getDatabaseSchemaDetailsByFQN,
|
getDatabaseSchemaDetailsByFQN,
|
||||||
} from '../rest/databaseAPI';
|
} from '../rest/databaseAPI';
|
||||||
import { getDataModelDetailsByFQN } from '../rest/dataModelsAPI';
|
import { getDataModelDetailsByFQN } from '../rest/dataModelsAPI';
|
||||||
|
import { getGlossariesByName, getGlossaryTermByFQN } from '../rest/glossaryAPI';
|
||||||
import { getUserSuggestions } from '../rest/miscAPI';
|
import { getUserSuggestions } from '../rest/miscAPI';
|
||||||
import { getMlModelByFQN } from '../rest/mlModelAPI';
|
import { getMlModelByFQN } from '../rest/mlModelAPI';
|
||||||
import { getPipelineByFqn } from '../rest/pipelineAPI';
|
import { getPipelineByFqn } from '../rest/pipelineAPI';
|
||||||
@ -73,11 +74,12 @@ import { defaultFields as DataModelFields } from './DataModelsUtils';
|
|||||||
import { defaultFields as TableFields } from './DatasetDetailsUtils';
|
import { defaultFields as TableFields } from './DatasetDetailsUtils';
|
||||||
import { getEntityName } from './EntityUtils';
|
import { getEntityName } from './EntityUtils';
|
||||||
import { getEntityFQN, getEntityType } from './FeedUtils';
|
import { getEntityFQN, getEntityType } from './FeedUtils';
|
||||||
|
import { getGlossaryBreadcrumbs } from './GlossaryUtils';
|
||||||
import { defaultFields as MlModelFields } from './MlModelDetailsUtils';
|
import { defaultFields as MlModelFields } from './MlModelDetailsUtils';
|
||||||
import { defaultFields as PipelineFields } from './PipelineDetailsUtils';
|
import { defaultFields as PipelineFields } from './PipelineDetailsUtils';
|
||||||
import serviceUtilClassBase from './ServiceUtilClassBase';
|
import serviceUtilClassBase from './ServiceUtilClassBase';
|
||||||
import { STORED_PROCEDURE_DEFAULT_FIELDS } from './StoredProceduresUtils';
|
import { STORED_PROCEDURE_DEFAULT_FIELDS } from './StoredProceduresUtils';
|
||||||
import { getEncodedFqn } from './StringsUtils';
|
import { getDecodedFqn, getEncodedFqn } from './StringsUtils';
|
||||||
import { getEntityLink } from './TableUtils';
|
import { getEntityLink } from './TableUtils';
|
||||||
import { showErrorToast } from './ToastUtils';
|
import { showErrorToast } from './ToastUtils';
|
||||||
|
|
||||||
@ -275,6 +277,8 @@ export const TASK_ENTITIES = [
|
|||||||
EntityType.DASHBOARD_DATA_MODEL,
|
EntityType.DASHBOARD_DATA_MODEL,
|
||||||
EntityType.STORED_PROCEDURE,
|
EntityType.STORED_PROCEDURE,
|
||||||
EntityType.SEARCH_INDEX,
|
EntityType.SEARCH_INDEX,
|
||||||
|
EntityType.GLOSSARY,
|
||||||
|
EntityType.GLOSSARY_TERM,
|
||||||
];
|
];
|
||||||
|
|
||||||
export const getBreadCrumbList = (
|
export const getBreadCrumbList = (
|
||||||
@ -308,12 +312,17 @@ export const getBreadCrumbList = (
|
|||||||
|
|
||||||
const service = (serviceCategory: ServiceCategory) => {
|
const service = (serviceCategory: ServiceCategory) => {
|
||||||
return {
|
return {
|
||||||
name: getEntityName(entityData.service),
|
name: getEntityName((entityData as Table).service),
|
||||||
url: getEntityName(entityData.service)
|
url: getEntityName((entityData as Table).service)
|
||||||
? getServiceDetailsPath(entityData.service?.name || '', serviceCategory)
|
? getServiceDetailsPath(
|
||||||
|
(entityData as Table).service?.name ?? '',
|
||||||
|
serviceCategory
|
||||||
|
)
|
||||||
: '',
|
: '',
|
||||||
imgSrc: entityData.serviceType
|
imgSrc: (entityData as Table).serviceType
|
||||||
? serviceUtilClassBase.getServiceTypeLogo(entityData.serviceType)
|
? serviceUtilClassBase.getServiceTypeLogo(
|
||||||
|
(entityData as Table).serviceType as string
|
||||||
|
)
|
||||||
: undefined,
|
: undefined,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -372,6 +381,11 @@ export const getBreadCrumbList = (
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case EntityType.GLOSSARY:
|
||||||
|
case EntityType.GLOSSARY_TERM: {
|
||||||
|
return getGlossaryBreadcrumbs(entityData.fullyQualifiedName ?? '');
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
@ -485,6 +499,22 @@ export const fetchEntityDetail = (
|
|||||||
.catch((err: AxiosError) => showErrorToast(err));
|
.catch((err: AxiosError) => showErrorToast(err));
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
case EntityType.GLOSSARY:
|
||||||
|
getGlossariesByName(entityFQN, TabSpecificField.TAGS)
|
||||||
|
.then((res) => {
|
||||||
|
setEntityData(res);
|
||||||
|
})
|
||||||
|
.catch((err: AxiosError) => showErrorToast(err));
|
||||||
|
|
||||||
|
break;
|
||||||
|
case EntityType.GLOSSARY_TERM:
|
||||||
|
getGlossaryTermByFQN(getDecodedFqn(entityFQN), TabSpecificField.TAGS)
|
||||||
|
.then((res) => {
|
||||||
|
setEntityData(res);
|
||||||
|
})
|
||||||
|
.catch((err: AxiosError) => showErrorToast(err));
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user