Minor: fix glossary term, reviewer and cypress (#16125)

* Minor: fix glossary term, reviewer and cypress

* added "Governance" tag for glossary spec

* fixed add glossary term issue

* cypress fixes

* fixed cypress
This commit is contained in:
Shailesh Parmar 2024-05-07 10:59:19 +05:30 committed by GitHub
parent 23a526db4c
commit 8427b8b509
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 171 additions and 160 deletions

View File

@ -264,7 +264,7 @@ export const signupAndLogin = (
cy.url().should('eq', `${BASE_URL}/my-data`); cy.url().should('eq', `${BASE_URL}/my-data`);
// Verify user profile // Verify user profile
cy.get('[data-testid="avatar"]').first().trigger('mouseover').click(); cy.get('[data-testid="dropdown-profile"]').click();
cy.get('[data-testid="user-name"]') cy.get('[data-testid="user-name"]')
.should('be.visible') .should('be.visible')
.invoke('text') .invoke('text')

View File

@ -14,9 +14,7 @@
import { import {
descriptionBox, descriptionBox,
interceptURL, interceptURL,
signupAndLogin,
toastNotification, toastNotification,
uuid,
verifyMultipleResponseStatusCode, verifyMultipleResponseStatusCode,
verifyResponseStatusCode, verifyResponseStatusCode,
} from '../../common/common'; } from '../../common/common';
@ -25,7 +23,11 @@ import { dragAndDropElement } from '../../common/Utils/DragAndDrop';
import { visitEntityDetailsPage } from '../../common/Utils/Entity'; import { visitEntityDetailsPage } from '../../common/Utils/Entity';
import { confirmationDragAndDropGlossary } from '../../common/Utils/Glossary'; import { confirmationDragAndDropGlossary } from '../../common/Utils/Glossary';
import { getToken } from '../../common/Utils/LocalStorage'; import { getToken } from '../../common/Utils/LocalStorage';
import { addOwner, removeOwner } from '../../common/Utils/Owner'; import {
addOwner,
generateRandomUser,
removeOwner,
} from '../../common/Utils/Owner';
import { import {
COLUMN_NAME_FOR_APPLY_GLOSSARY_TERM, COLUMN_NAME_FOR_APPLY_GLOSSARY_TERM,
CYPRESS_ASSETS_GLOSSARY, CYPRESS_ASSETS_GLOSSARY,
@ -45,19 +47,16 @@ import {
import { SidebarItem } from '../../constants/Entity.interface'; import { SidebarItem } from '../../constants/Entity.interface';
import { GLOSSARY_OWNER_LINK_TEST_ID } from '../../constants/glossary.constant'; import { GLOSSARY_OWNER_LINK_TEST_ID } from '../../constants/glossary.constant';
const userName = `test_dataconsumer${uuid()}`; const CREDENTIALS = generateRandomUser();
const userName = `${CREDENTIALS.firstName}${CREDENTIALS.lastName}`;
const CREDENTIALS = {
firstName: 'Cypress',
lastName: 'UserDC',
email: `${userName}@openmetadata.org`,
password: 'User@OMD123',
username: 'CypressUserDC',
};
let createdUserId = ''; let createdUserId = '';
const visitGlossaryTermPage = (termName, fqn, fetchPermission) => { const visitGlossaryTermPage = (
termName: string,
fqn: string,
fetchPermission?: boolean
) => {
interceptURL( interceptURL(
'GET', 'GET',
`/api/v1/search/query?q=*&from=0&size=*&index=glossary_term_search_index`, `/api/v1/search/query?q=*&from=0&size=*&index=glossary_term_search_index`,
@ -77,7 +76,7 @@ const visitGlossaryTermPage = (termName, fqn, fetchPermission) => {
.click(); .click();
verifyResponseStatusCode('@getGlossaryTerms', 200); verifyResponseStatusCode('@getGlossaryTerms', 200);
// verifyResponseStatusCode('@glossaryAPI', 200);
if (fetchPermission) { if (fetchPermission) {
verifyResponseStatusCode('@waitForTermPermission', 200); verifyResponseStatusCode('@waitForTermPermission', 200);
} }
@ -140,8 +139,8 @@ const createGlossary = (glossaryData) => {
if (glossaryData.addReviewer) { if (glossaryData.addReviewer) {
// Add reviewer // Add reviewer
cy.get('[data-testid="add-reviewers"]').scrollIntoView().click(); cy.get('[data-testid="add-reviewers"]').scrollIntoView().click();
cy.get('[data-testid="searchbar"]').type(CREDENTIALS.username); cy.get('[data-testid="searchbar"]').type(userName);
cy.get(`[title="${CREDENTIALS.username}"]`) cy.get(`[title="${userName}"]`)
.scrollIntoView() .scrollIntoView()
.should('be.visible') .should('be.visible')
.click(); .click();
@ -356,7 +355,7 @@ const createGlossaryTerm = (term, glossary, status, isMutually = false) => {
cy.get('[data-testid="glossary-reviewer-name"]') cy.get('[data-testid="glossary-reviewer-name"]')
.scrollIntoView() .scrollIntoView()
.contains(CREDENTIALS.username) .contains(userName)
.should('be.visible'); .should('be.visible');
cy.get(':nth-child(2) > .link-title').click(); cy.get(':nth-child(2) > .link-title').click();
} }
@ -396,7 +395,11 @@ const deleteGlossaryTerm = ({ name, fullyQualifiedName }) => {
.should('not.contain', name); .should('not.contain', name);
}; };
const goToAssetsTab = (name, fqn, fetchPermission) => { const goToAssetsTab = (
name: string,
fqn: string,
fetchPermission?: boolean
) => {
visitGlossaryTermPage(name, fqn, fetchPermission); visitGlossaryTermPage(name, fqn, fetchPermission);
cy.get('[data-testid="assets"]').should('be.visible').click(); cy.get('[data-testid="assets"]').should('be.visible').click();
@ -437,7 +440,7 @@ const updateSynonyms = (uSynonyms) => {
}); });
}; };
const updateTags = (inTerm) => { const updateTags = (inTerm: boolean) => {
// visit glossary page // visit glossary page
interceptURL( interceptURL(
'GET', 'GET',
@ -453,8 +456,6 @@ const updateTags = (inTerm) => {
.should('be.visible') .should('be.visible')
.type('personal'); .type('personal');
cy.get('[data-testid="tag-PersonalData.Personal"]').click(); cy.get('[data-testid="tag-PersonalData.Personal"]').click();
// to close popup
cy.clickOutside();
cy.get('[data-testid="saveAssociatedTag"]').scrollIntoView().click(); cy.get('[data-testid="saveAssociatedTag"]').scrollIntoView().click();
const container = inTerm const container = inTerm
@ -464,10 +465,10 @@ const updateTags = (inTerm) => {
cy.get(container).scrollIntoView().contains('Personal').should('be.visible'); cy.get(container).scrollIntoView().contains('Personal').should('be.visible');
}; };
const updateTerms = (newTerm) => { const updateTerms = (newTerm: string) => {
interceptURL( interceptURL(
'GET', 'GET',
'/api/v1/search/query?q=**&from=0&size=10&index=glossary_search_index', '/api/v1/search/query?q=*&index=glossary_term_search_index*',
'getGlossaryTerm' 'getGlossaryTerm'
); );
cy.get('[data-testid="related-term-container"]') cy.get('[data-testid="related-term-container"]')
@ -481,17 +482,19 @@ const updateTerms = (newTerm) => {
.should('be.visible') .should('be.visible')
.click() .click()
.type(newTerm); .type(newTerm);
verifyResponseStatusCode('@getGlossaryTerm', 200); verifyResponseStatusCode('@getGlossaryTerm', 200, { requestTimeout: 10000 });
cy.get('.ant-select-item-option-content').contains(newTerm).click(); cy.get('.ant-select-dropdown').filter(':visible').contains(newTerm).click();
cy.get('[data-testid="saveAssociatedTag"]').scrollIntoView().click(); cy.get('[data-testid="saveAssociatedTag"]').click();
verifyResponseStatusCode('@saveGlossaryTermData', 200); verifyResponseStatusCode('@saveGlossaryTermData', 200, {
requestTimeout: 10000,
});
cy.get('[data-testid="related-term-container"]') cy.get('[data-testid="related-term-container"]')
.contains(newTerm) .contains(newTerm)
.should('be.visible'); .should('be.visible');
}; };
const updateReferences = (newRef) => { const updateReferences = (newRef: { name: string; url: string }) => {
cy.get('[data-testid="section-References"]') cy.get('[data-testid="section-References"]')
.find('[data-testid="edit-button"]') .find('[data-testid="edit-button"]')
.scrollIntoView() .scrollIntoView()
@ -533,7 +536,7 @@ const updateDescription = (newDescription, isGlossary) => {
.should('be.visible'); .should('be.visible');
}; };
const upVoting = (api) => { const upVoting = (api: string) => {
cy.get('[data-testid="up-vote-btn"]').click(); cy.get('[data-testid="up-vote-btn"]').click();
cy.wait(api).then(({ request, response }) => { cy.wait(api).then(({ request, response }) => {
@ -545,7 +548,7 @@ const upVoting = (api) => {
cy.get('[data-testid="up-vote-count"]').contains(1); cy.get('[data-testid="up-vote-count"]').contains(1);
}; };
const downVoting = (api) => { const downVoting = (api: string) => {
cy.get('[data-testid="down-vote-btn"]').click(); cy.get('[data-testid="down-vote-btn"]').click();
cy.wait(api).then(({ request, response }) => { cy.wait(api).then(({ request, response }) => {
@ -561,7 +564,7 @@ const downVoting = (api) => {
}; };
// goes to initial stage after down voting glossary or glossary term // goes to initial stage after down voting glossary or glossary term
const initialVoting = (api) => { const initialVoting = (api: string) => {
cy.get('[data-testid="down-vote-btn"]').click(); cy.get('[data-testid="down-vote-btn"]').click();
cy.wait(api).then(({ request, response }) => { cy.wait(api).then(({ request, response }) => {
@ -574,7 +577,7 @@ const initialVoting = (api) => {
cy.get('[data-testid="down-vote-count"]').contains(0); cy.get('[data-testid="down-vote-count"]').contains(0);
}; };
const voteGlossary = (isGlossary) => { const voteGlossary = (isGlossary?: boolean) => {
if (isGlossary) { if (isGlossary) {
interceptURL('PUT', '/api/v1/glossaries/*/vote', 'voteGlossary'); interceptURL('PUT', '/api/v1/glossaries/*/vote', 'voteGlossary');
} else { } else {
@ -700,16 +703,22 @@ const deleteUser = () => {
}); });
}; };
describe('Glossary page should work properly', { tags: 'Glossary' }, () => { describe('Glossary page should work properly', { tags: 'Governance' }, () => {
before(() => { before(() => {
// Prerequisites - Create a user with data consumer role // Prerequisites - Create a user with data consumer role
signupAndLogin( cy.login();
CREDENTIALS.email, cy.getAllLocalStorage().then((data) => {
CREDENTIALS.password, const token = getToken(data);
CREDENTIALS.firstName,
CREDENTIALS.lastName // Create a new user
).then((id) => { cy.request({
createdUserId = id; method: 'POST',
url: `/api/v1/users/signup`,
headers: { Authorization: `Bearer ${token}` },
body: CREDENTIALS,
}).then((response) => {
createdUserId = response.body.id;
});
}); });
}); });
@ -735,7 +744,7 @@ describe('Glossary page should work properly', { tags: 'Glossary' }, () => {
.click(); .click();
checkDisplayName(NEW_GLOSSARY.name); checkDisplayName(NEW_GLOSSARY.name);
addOwner(CREDENTIALS.username, GLOSSARY_OWNER_LINK_TEST_ID); addOwner(userName, GLOSSARY_OWNER_LINK_TEST_ID);
}); });
it('Update Owner', () => { it('Update Owner', () => {
@ -795,7 +804,7 @@ describe('Glossary page should work properly', { tags: 'Glossary' }, () => {
cy.get(`[data-testid="glossary-reviewer-name"]`) cy.get(`[data-testid="glossary-reviewer-name"]`)
.invoke('text') .invoke('text')
.then((text) => { .then((text) => {
expect(text).to.contain(CREDENTIALS.username); expect(text).to.contain(userName);
}); });
// Verify Product glossary details // Verify Product glossary details
@ -857,7 +866,7 @@ describe('Glossary page should work properly', { tags: 'Glossary' }, () => {
checkDisplayName(NEW_GLOSSARY.name); checkDisplayName(NEW_GLOSSARY.name);
// Updating owner // Updating owner
addOwner(CREDENTIALS.username, GLOSSARY_OWNER_LINK_TEST_ID); addOwner(userName, GLOSSARY_OWNER_LINK_TEST_ID);
// updating tags // updating tags
updateTags(false); updateTags(false);
@ -875,7 +884,11 @@ describe('Glossary page should work properly', { tags: 'Glossary' }, () => {
const { name, fullyQualifiedName } = NEW_GLOSSARY_1_TERMS.term_1; const { name, fullyQualifiedName } = NEW_GLOSSARY_1_TERMS.term_1;
// visit glossary page // visit glossary page
interceptURL('GET', `/api/v1/glossaryTerms?glossary=*`, 'glossaryTerm'); interceptURL(
'GET',
`/api/v1/glossaryTerms?directChildrenOf=*`,
'glossaryTerm'
);
interceptURL('GET', `/api/v1/permissions/glossary/*`, 'permissions'); interceptURL('GET', `/api/v1/permissions/glossary/*`, 'permissions');
cy.get('.ant-menu-item').contains(NEW_GLOSSARY_1.name).click(); cy.get('.ant-menu-item').contains(NEW_GLOSSARY_1.name).click();
@ -1112,80 +1125,6 @@ describe('Glossary page should work properly', { tags: 'Glossary' }, () => {
}); });
}); });
it('Change glossary term hierarchy using menu options', () => {
interceptURL('PATCH', '/api/v1/glossaryTerms/*', 'saveGlossaryTermData');
interceptURL(
'GET',
'/api/v1/glossaryTerms/name/*',
'fetchGlossaryTermData'
);
const parentTerm = CYPRESS_ASSETS_GLOSSARY_TERMS.term_1;
const childTerm = CYPRESS_ASSETS_GLOSSARY_TERMS.term_3;
visitGlossaryTermPage(childTerm.name, childTerm.fullyQualifiedName, true);
cy.get('[data-testid="manage-button"]').click();
cy.get('[data-testid="change-parent-button"]').should('be.visible').click();
cy.get(
'[data-testid="change-parent-select"] > .ant-select-selector'
).click();
cy.get(`[title="${parentTerm.name}"]`).click();
// Submit the select parent
cy.get('.ant-modal-footer > .ant-btn-primary').click();
verifyResponseStatusCode('@saveGlossaryTermData', 200);
verifyResponseStatusCode('@fetchGlossaryTermData', 200);
/**
* Todo: Enable this once this asset issue is resolve https://github.com/open-metadata/OpenMetadata/issues/15809
*/
// cy.get('[data-testid="assets"] [data-testid="filter-count"]')
// .should('be.visible')
// .contains('3');
// checking the breadcrumb, if the change parent term is updated and displayed
cy.get('[data-testid="breadcrumb-link"]')
.should('be.visible')
.contains(`${parentTerm.name}`)
.click();
verifyResponseStatusCode('@fetchGlossaryTermData', 200);
// checking the child term is updated and displayed under the parent term
cy.get('[data-testid="terms"] [data-testid="filter-count"]')
.should('be.visible')
.contains('1')
.click();
cy.get(`[data-testid="${childTerm.name}"]`).should('be.visible');
goToGlossaryPage();
const newTermHierarchy = `${Cypress.$.escapeSelector(
CYPRESS_ASSETS_GLOSSARY.name
)}.${parentTerm.name}."${childTerm.name}"`;
// verify the term is moved under the parent term
cy.get(`.ant-table-row-level-1[data-row-key='${newTermHierarchy}']`).should(
'be.visible'
);
// re-dropping the term to the root level
dragAndDropElement(
`${CYPRESS_ASSETS_GLOSSARY.name}.${parentTerm.name}."${childTerm.name}"`,
'.ant-table-thead > tr',
true
);
confirmationDragAndDropGlossary(
childTerm.name,
CYPRESS_ASSETS_GLOSSARY.name,
true
);
});
it('Remove asset from glossary term using asset modal', () => { it('Remove asset from glossary term using asset modal', () => {
const terms = Object.values(CYPRESS_ASSETS_GLOSSARY_TERMS); const terms = Object.values(CYPRESS_ASSETS_GLOSSARY_TERMS);
terms.forEach((term) => { terms.forEach((term) => {
@ -1296,6 +1235,78 @@ describe('Glossary page should work properly', { tags: 'Glossary' }, () => {
}); });
}); });
it('Change glossary term hierarchy using menu options', () => {
interceptURL('PATCH', '/api/v1/glossaryTerms/*', 'saveGlossaryTermData');
interceptURL(
'GET',
'/api/v1/glossaryTerms/name/*',
'fetchGlossaryTermData'
);
const parentTerm = CYPRESS_ASSETS_GLOSSARY_TERMS.term_1;
const childTerm = CYPRESS_ASSETS_GLOSSARY_TERMS.term_2;
cy.get('[data-testid="expand-collapse-all-button"]').click();
visitGlossaryTermPage(childTerm.name, childTerm.fullyQualifiedName, true);
cy.get('[data-testid="manage-button"]').click();
cy.get('[data-testid="change-parent-button"]').should('be.visible').click();
cy.get(
'[data-testid="change-parent-select"] > .ant-select-selector'
).click();
cy.get(`[title="${parentTerm.name}"]`).click();
// Submit the select parent
cy.get('.ant-modal-footer > .ant-btn-primary').click();
verifyResponseStatusCode('@saveGlossaryTermData', 200);
verifyResponseStatusCode('@fetchGlossaryTermData', 200);
/**
* Todo: Enable this once this asset issue is resolve https://github.com/open-metadata/OpenMetadata/issues/15809
*/
// cy.get('[data-testid="assets"] [data-testid="filter-count"]')
// .should('be.visible')
// .contains('3');
// checking the breadcrumb, if the change parent term is updated and displayed
cy.get('[data-testid="breadcrumb-link"]')
.should('be.visible')
.contains(`${parentTerm.name}`)
.click();
verifyResponseStatusCode('@fetchGlossaryTermData', 200);
// checking the child term is updated and displayed under the parent term
cy.get('[data-testid="terms"] [data-testid="filter-count"]')
.should('be.visible')
.contains('1')
.click();
cy.get(`[data-testid="${childTerm.name}"]`).should('be.visible');
goToGlossaryPage();
const newTermHierarchy = `${Cypress.$.escapeSelector(
CYPRESS_ASSETS_GLOSSARY.name
)}.${parentTerm.name}.${childTerm.name}`;
cy.get('[data-testid="expand-collapse-all-button"]').click();
// verify the term is moved under the parent term
cy.get(`[data-row-key='${newTermHierarchy}']`).should('be.visible');
// re-dropping the term to the root level
dragAndDropElement(
`${CYPRESS_ASSETS_GLOSSARY.name}.${parentTerm.name}.${childTerm.name}`,
'.ant-table-thead > tr',
true
);
confirmationDragAndDropGlossary(
childTerm.name,
CYPRESS_ASSETS_GLOSSARY.name,
true
);
});
it('Drag and Drop should work properly for glossary term', () => { it('Drag and Drop should work properly for glossary term', () => {
selectActiveGlossary(NEW_GLOSSARY.name); selectActiveGlossary(NEW_GLOSSARY.name);
@ -1308,8 +1319,8 @@ describe('Glossary page should work properly', { tags: 'Glossary' }, () => {
NEW_GLOSSARY_TERMS.term_2.name, NEW_GLOSSARY_TERMS.term_2.name,
NEW_GLOSSARY_TERMS.term_1.name NEW_GLOSSARY_TERMS.term_1.name
); );
// verify the term is moved under the parent term // verify the term is moved under the parent term
cy.get('[data-testid="expand-collapse-all-button"]').click();
cy.get( cy.get(
`.ant-table-row-level-1[data-row-key="${Cypress.$.escapeSelector( `.ant-table-row-level-1[data-row-key="${Cypress.$.escapeSelector(
NEW_GLOSSARY_TERMS.term_1.fullyQualifiedName NEW_GLOSSARY_TERMS.term_1.fullyQualifiedName
@ -1319,7 +1330,7 @@ describe('Glossary page should work properly', { tags: 'Glossary' }, () => {
it('Drag and Drop should work properly for glossary term at table level', () => { it('Drag and Drop should work properly for glossary term at table level', () => {
selectActiveGlossary(NEW_GLOSSARY.name); selectActiveGlossary(NEW_GLOSSARY.name);
cy.get('[data-testid="expand-collapse-all-button"]').click();
dragAndDropElement( dragAndDropElement(
`${NEW_GLOSSARY_TERMS.term_1.fullyQualifiedName}.${NEW_GLOSSARY_TERMS.term_2.name}`, `${NEW_GLOSSARY_TERMS.term_1.fullyQualifiedName}.${NEW_GLOSSARY_TERMS.term_2.name}`,
'.ant-table-thead > tr', '.ant-table-thead > tr',
@ -1333,6 +1344,7 @@ describe('Glossary page should work properly', { tags: 'Glossary' }, () => {
); );
// verify the term is moved under the parent term // verify the term is moved under the parent term
cy.get('[data-testid="expand-collapse-all-button"]').click();
cy.get( cy.get(
`.ant-table-row-level-0[data-row-key="${Cypress.$.escapeSelector( `.ant-table-row-level-0[data-row-key="${Cypress.$.escapeSelector(
NEW_GLOSSARY_TERMS.term_2.fullyQualifiedName NEW_GLOSSARY_TERMS.term_2.fullyQualifiedName

View File

@ -216,7 +216,10 @@ describe(
cy.get('[data-testid="version-button"]').contains('0.2'); cy.get('[data-testid="version-button"]').contains('0.2');
addOwner(data.user.displayName, GLOSSARY_OWNER_LINK_TEST_ID); addOwner(data.user.displayName, GLOSSARY_OWNER_LINK_TEST_ID);
// Adding manual wait as the backend is now performing batch operations,
// which causes a delay in reflecting changes
cy.wait(1000);
cy.reload();
interceptURL('GET', `/api/v1/glossaries/*/versions`, 'getVersionsList'); interceptURL('GET', `/api/v1/glossaries/*/versions`, 'getVersionsList');
interceptURL( interceptURL(
'GET', 'GET',
@ -244,6 +247,11 @@ describe(
addReviewer(data.reviewer.displayName, 'glossaries'); addReviewer(data.reviewer.displayName, 'glossaries');
// Adding manual wait as the backend is now performing batch operations,
// which causes a delay in reflecting changes
cy.wait(1000);
cy.reload();
interceptURL( interceptURL(
'GET', 'GET',
`/api/v1/glossaries/*/versions/0.2`, `/api/v1/glossaries/*/versions/0.2`,
@ -279,12 +287,12 @@ describe(
); );
interceptURL( interceptURL(
'GET', 'GET',
`/api/v1/glossaryTerms?parent=*&limit=*&fields=*`, `/api/v1/glossaryTerms?directChildrenOf=*&fields=*&limit=*`,
'getGlossaryTermParents' 'getGlossaryTermParents'
); );
interceptURL( interceptURL(
'GET', 'GET',
`/api/v1/glossaryTerms?parent=*&limit=*`, `/api/v1/glossaryTerms?directChildrenOf=*&limit=*`,
'getChildGlossaryTerms' 'getChildGlossaryTerms'
); );
@ -335,12 +343,12 @@ describe(
); );
interceptURL( interceptURL(
'GET', 'GET',
`/api/v1/glossaryTerms?parent=*&limit=*&fields=*`, `/api/v1/glossaryTerms?directChildrenOf=*&fields=*&limit=*`,
'getGlossaryTermParents' 'getGlossaryTermParents'
); );
interceptURL( interceptURL(
'GET', 'GET',
`/api/v1/glossaryTerms?parent=*&limit=*`, `/api/v1/glossaryTerms?directChildrenOf=*&limit=*`,
'getChildGlossaryTerms' 'getChildGlossaryTerms'
); );

View File

@ -35,13 +35,13 @@ import ErrorPlaceHolder from '../../../components/common/ErrorWithPlaceholder/Er
import { OwnerLabel } from '../../../components/common/OwnerLabel/OwnerLabel.component'; import { OwnerLabel } from '../../../components/common/OwnerLabel/OwnerLabel.component';
import RichTextEditorPreviewer from '../../../components/common/RichTextEditor/RichTextEditorPreviewer'; import RichTextEditorPreviewer from '../../../components/common/RichTextEditor/RichTextEditorPreviewer';
import StatusBadge from '../../../components/common/StatusBadge/StatusBadge.component'; import StatusBadge from '../../../components/common/StatusBadge/StatusBadge.component';
import { TABLE_CONSTANTS } from '../../../constants/Teams.constants';
import { import {
API_RES_MAX_SIZE, API_RES_MAX_SIZE,
DE_ACTIVE_COLOR, DE_ACTIVE_COLOR,
TEXT_BODY_COLOR, TEXT_BODY_COLOR,
} from '../../../constants/constants'; } from '../../../constants/constants';
import { GLOSSARIES_DOCS } from '../../../constants/docs.constants'; import { GLOSSARIES_DOCS } from '../../../constants/docs.constants';
import { TABLE_CONSTANTS } from '../../../constants/Teams.constants';
import { ERROR_PLACEHOLDER_TYPE } from '../../../enums/common.enum'; import { ERROR_PLACEHOLDER_TYPE } from '../../../enums/common.enum';
import { import {
EntityReference, EntityReference,
@ -50,20 +50,20 @@ import {
} from '../../../generated/entity/data/glossaryTerm'; } from '../../../generated/entity/data/glossaryTerm';
import { useApplicationStore } from '../../../hooks/useApplicationStore'; import { useApplicationStore } from '../../../hooks/useApplicationStore';
import { import {
GlossaryTermWithChildren,
getFirstLevelGlossaryTerms, getFirstLevelGlossaryTerms,
getGlossaryTerms, getGlossaryTerms,
GlossaryTermWithChildren,
patchGlossaryTerm, patchGlossaryTerm,
} from '../../../rest/glossaryAPI'; } from '../../../rest/glossaryAPI';
import { Transi18next } from '../../../utils/CommonUtils'; import { Transi18next } from '../../../utils/CommonUtils';
import { getEntityName } from '../../../utils/EntityUtils'; import { getEntityName } from '../../../utils/EntityUtils';
import Fqn from '../../../utils/Fqn'; import Fqn from '../../../utils/Fqn';
import { import {
StatusClass,
StatusFilters,
buildTree, buildTree,
findExpandableKeysForArray, findExpandableKeysForArray,
findGlossaryTermByFqn, findGlossaryTermByFqn,
StatusClass,
StatusFilters,
} from '../../../utils/GlossaryUtils'; } from '../../../utils/GlossaryUtils';
import { getGlossaryPath } from '../../../utils/RouterUtils'; import { getGlossaryPath } from '../../../utils/RouterUtils';
import { showErrorToast } from '../../../utils/ToastUtils'; import { showErrorToast } from '../../../utils/ToastUtils';
@ -449,6 +449,7 @@ const GlossaryTermTab = ({
<div className="d-flex justify-end"> <div className="d-flex justify-end">
<Button <Button
className="text-primary m-b-sm" className="text-primary m-b-sm"
data-testid="expand-collapse-all-button"
size="small" size="small"
type="text" type="text"
onClick={toggleExpandAll}> onClick={toggleExpandAll}>

View File

@ -14,7 +14,7 @@
import { Button, Tooltip, Typography } from 'antd'; import { Button, Tooltip, Typography } from 'antd';
import { DefaultOptionType } from 'antd/lib/select'; import { DefaultOptionType } from 'antd/lib/select';
import { t } from 'i18next'; import { t } from 'i18next';
import { cloneDeep, includes, isArray, isEmpty, uniqWith } from 'lodash'; import { isArray, isEmpty, isUndefined } from 'lodash';
import React, { useCallback, useEffect, useMemo, useState } from 'react'; import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { ReactComponent as IconTerm } from '../../../../assets/svg/book.svg'; import { ReactComponent as IconTerm } from '../../../../assets/svg/book.svg';
@ -29,6 +29,7 @@ import {
import { EntityField } from '../../../../constants/Feeds.constants'; import { EntityField } from '../../../../constants/Feeds.constants';
import { NO_PERMISSION_FOR_ACTION } from '../../../../constants/HelperTextUtil'; import { NO_PERMISSION_FOR_ACTION } from '../../../../constants/HelperTextUtil';
import { OperationPermission } from '../../../../context/PermissionProvider/PermissionProvider.interface'; import { OperationPermission } from '../../../../context/PermissionProvider/PermissionProvider.interface';
import { EntityType } from '../../../../enums/entity.enum';
import { SearchIndex } from '../../../../enums/search.enum'; import { SearchIndex } from '../../../../enums/search.enum';
import { GlossaryTerm } from '../../../../generated/entity/data/glossaryTerm'; import { GlossaryTerm } from '../../../../generated/entity/data/glossaryTerm';
import { import {
@ -38,7 +39,10 @@ import {
import { Paging } from '../../../../generated/type/paging'; import { Paging } from '../../../../generated/type/paging';
import { searchData } from '../../../../rest/miscAPI'; import { searchData } from '../../../../rest/miscAPI';
import { formatSearchGlossaryTermResponse } from '../../../../utils/APIUtils'; import { formatSearchGlossaryTermResponse } from '../../../../utils/APIUtils';
import { getEntityName } from '../../../../utils/EntityUtils'; import {
getEntityName,
getEntityReferenceFromEntity,
} from '../../../../utils/EntityUtils';
import { import {
getChangedEntityNewValue, getChangedEntityNewValue,
getChangedEntityOldValue, getChangedEntityOldValue,
@ -64,7 +68,6 @@ const RelatedTerms = ({
}: RelatedTermsProps) => { }: RelatedTermsProps) => {
const history = useHistory(); const history = useHistory();
const [isIconVisible, setIsIconVisible] = useState<boolean>(true); const [isIconVisible, setIsIconVisible] = useState<boolean>(true);
const [options, setOptions] = useState<EntityReference[]>([]);
const [selectedOption, setSelectedOption] = useState<EntityReference[]>([]); const [selectedOption, setSelectedOption] = useState<EntityReference[]>([]);
const handleRelatedTermClick = (fqn: string) => { const handleRelatedTermClick = (fqn: string) => {
@ -78,32 +81,20 @@ const RelatedTerms = ({
return; return;
} }
const newOptions = uniqWith( const newOptions = selectedData.map((value) =>
options, getEntityReferenceFromEntity(
(arrVal, othVal) => arrVal.id === othVal.id isUndefined(value.data)
).filter((item) => ? glossaryTerm.relatedTerms?.find(
selectedData.find((data) => (term) => term.fullyQualifiedName === value.value
typeof data === 'string' )
? data === item.fullyQualifiedName : value.data,
: data.value === item.fullyQualifiedName EntityType.GLOSSARY_TERM
) )
); );
let updatedGlossaryTerm = cloneDeep(glossaryTerm); const updatedGlossaryTerm = {
const oldTerms = newOptions.filter((d) => ...glossaryTerm,
includes(glossaryTerm.relatedTerms, d) relatedTerms: newOptions,
);
const newTerms = newOptions
.filter((d) => !includes(glossaryTerm.relatedTerms, d))
.map((d) => ({
id: d.id,
type: d.type,
displayName: d.displayName,
name: d.name,
}));
updatedGlossaryTerm = {
...updatedGlossaryTerm,
relatedTerms: [...oldTerms, ...newTerms],
}; };
await onGlossaryTermUpdate(updatedGlossaryTerm); await onGlossaryTermUpdate(updatedGlossaryTerm);
@ -137,10 +128,10 @@ const RelatedTerms = ({
); );
const results = termResult.map(getEntityReferenceFromGlossary); const results = termResult.map(getEntityReferenceFromGlossary);
setOptions((prev) => [...prev, ...results]);
return { return {
data: results.map((item) => ({ data: results.map((item) => ({
data: item,
label: item.fullyQualifiedName ?? '', label: item.fullyQualifiedName ?? '',
value: item.fullyQualifiedName ?? '', value: item.fullyQualifiedName ?? '',
})), })),
@ -165,7 +156,6 @@ const RelatedTerms = ({
useEffect(() => { useEffect(() => {
if (glossaryTerm) { if (glossaryTerm) {
setOptions(glossaryTerm.relatedTerms ?? []);
setSelectedOption(formatOptions(glossaryTerm.relatedTerms ?? [])); setSelectedOption(formatOptions(glossaryTerm.relatedTerms ?? []));
} }
}, [glossaryTerm]); }, [glossaryTerm]);

View File

@ -174,7 +174,7 @@ const TreeAsyncSelectList: FC<Omit<AsyncSelectListProps, 'fetchOptions'>> = ({
const handleChange: TreeSelectProps['onChange'] = (values: string[]) => { const handleChange: TreeSelectProps['onChange'] = (values: string[]) => {
const selectedValues = values.map((value) => { const selectedValues = values.map((value) => {
const initialData = findGlossaryTermByFqn( const initialData = findGlossaryTermByFqn(
glossaries as ModifiedGlossaryTerm[], [...glossaries, ...searchOptions] as ModifiedGlossaryTerm[],
value value
); );

View File

@ -187,7 +187,7 @@ const GlossaryPage = () => {
jsonPatch jsonPatch
); );
updateActiveGlossary(response); updateActiveGlossary({ ...updatedData, ...response });
if (activeGlossary?.name !== updatedData.name) { if (activeGlossary?.name !== updatedData.name) {
history.push(getGlossaryPath(response.fullyQualifiedName)); history.push(getGlossaryPath(response.fullyQualifiedName));