From 87f8bcc4fa057a8bd04a6c930682fc97e64a2c85 Mon Sep 17 00:00:00 2001 From: Shailesh Parmar Date: Fri, 26 Aug 2022 16:08:02 +0530 Subject: [PATCH] Fixed issue: UI: Glossary details page improvements#6834" (#6879) * Fixed issue: UI: Glossary details page improvements#6834" * added data-testid * fixed input box re-render issue * fixed failing cypress for glossary * addressing comments * fixed failing cypress * updated glossary test and cypress * fixed glossary test --- .../integration/Pages/Glossary.spec.js | 24 +- .../ui/src/assets/svg/icon-edit-primary.svg | 4 + .../assets/svg/icon-plus-primary-outlined.svg | 4 + .../src/components/AddWebhook/AddWebhook.tsx | 3 +- .../src/components/Glossary/Glossary.test.tsx | 5 + .../Glossary/GlossaryV1.component.tsx | 5 +- .../GlossaryDetails.component.tsx | 21 +- .../GlossaryTerms/GlossaryTerms.test.tsx | 43 ++- .../GlossaryTermsV1.component.tsx | 357 +++++++++--------- .../components/common/TreeView/treeView.css | 2 +- .../common/description/DescriptionV1.tsx | 51 +-- .../ui/src/styles/components/glossary.less | 52 +++ .../src/main/resources/ui/src/styles/index.js | 1 + .../main/resources/ui/src/utils/SvgUtils.tsx | 12 + 14 files changed, 351 insertions(+), 233 deletions(-) create mode 100644 openmetadata-ui/src/main/resources/ui/src/assets/svg/icon-edit-primary.svg create mode 100644 openmetadata-ui/src/main/resources/ui/src/assets/svg/icon-plus-primary-outlined.svg create mode 100644 openmetadata-ui/src/main/resources/ui/src/styles/components/glossary.less diff --git a/openmetadata-ui/src/main/resources/ui/cypress/integration/Pages/Glossary.spec.js b/openmetadata-ui/src/main/resources/ui/cypress/integration/Pages/Glossary.spec.js index e0b26661db9..20df30b01bf 100644 --- a/openmetadata-ui/src/main/resources/ui/cypress/integration/Pages/Glossary.spec.js +++ b/openmetadata-ui/src/main/resources/ui/cypress/integration/Pages/Glossary.spec.js @@ -201,6 +201,7 @@ describe('Glossary page should work properly', () => { cy.get('@description').type(newDescription); cy.get('[data-testid="save"]').click(); cy.get('.tw-modal-container').should('not.exist'); + cy.wait(1000); cy.get('[data-testid="viewer-container"]') .contains(newDescription) .should('be.visible'); @@ -215,11 +216,11 @@ describe('Glossary page should work properly', () => { cy.wait(500); cy.get('[data-testid="inactive-link"]').contains(term).should('be.visible'); - // updating synonyms - cy.get('[data-testid="edit-synonyms"]') + cy.get('[data-testid="section-synonyms"]') .scrollIntoView() .should('be.visible') .click(); + cy.get('[data-testid="synonyms"]') .scrollIntoView() .should('be.visible') @@ -228,7 +229,7 @@ describe('Glossary page should work properly', () => { cy.get('@synonyms').type(uSynonyms); cy.get('[data-testid="saveAssociatedTag"]').should('be.visible').click(); cy.wait(100); - cy.get('[data-testid="synonyms-card-container"]') + cy.get('[data-testid="synonyms-container"]') .as('synonyms-container') .should('be.visible'); @@ -237,16 +238,17 @@ describe('Glossary page should work properly', () => { }); // updating References - cy.get('[data-testid="edit-referencfe"]').should('exist').click(); + cy.get('[data-testid="section-references"] [data-testid="add-button"]') + .should('exist') + .click(); cy.get('.tw-modal-container').should('be.visible'); - cy.get('[data-testid="references"] > :nth-child(1) > .button-comp') + cy.get('[data-testid="references"] .button-comp') .should('be.visible') .click(); cy.get('#name-1').should('be.visible').type(newRef.name); cy.get('#url-1').should('be.visible').type(newRef.url); cy.get('[data-testid="saveButton"]').should('be.visible').click(); - cy.get('[data-testid="references-card-container"]') - .scrollIntoView() + cy.get('[data-testid="references-container"]') .contains(newRef.name) .should('be.visible') .invoke('attr', 'href') @@ -269,6 +271,7 @@ describe('Glossary page should work properly', () => { .contains('PersonalData.Personal') .should('be.visible'); + cy.wait(1000); // updating description cy.get('[data-testid="edit-description"]').should('be.visible').click(); cy.get('.tw-modal-container').should('be.visible'); @@ -279,6 +282,9 @@ describe('Glossary page should work properly', () => { cy.get('@description').type(newDescription); cy.get('[data-testid="save"]').click(); cy.get('.tw-modal-container').should('not.exist'); + + cy.wait(1000); + cy.get('[data-testid="viewer-container"]') .contains(newDescription) .should('be.visible'); @@ -335,6 +341,7 @@ describe('Glossary page should work properly', () => { const entity = SEARCH_ENTITY_TABLE.table_3.term; // go assets tab goToAssetsTab(term); + cy.wait(1000); cy.get('[data-testid="column"] > :nth-child(1) > a') .contains(entity) .should('be.visible') @@ -354,8 +361,10 @@ describe('Glossary page should work properly', () => { .scrollIntoView() .should('be.visible') .click(); + cy.get('[data-testid="saveAssociatedTag"]').scrollIntoView().click(); + //Remove the added column tag from entity cy.get( ':nth-child(1) > :nth-child(5) > [data-testid="tags-wrapper"] > :nth-child(1) > :nth-child(1) > [data-testid="tag-container"] > div > span.tw-text-primary > [data-testid="tags"]' ) @@ -367,7 +376,6 @@ describe('Glossary page should work properly', () => { .scrollIntoView() .should('be.visible') .click(); - cy.get(':nth-child(1) > .css-xb97g8') .scrollIntoView() .should('be.visible') diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/icon-edit-primary.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/icon-edit-primary.svg new file mode 100644 index 00000000000..516012f93d5 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/icon-edit-primary.svg @@ -0,0 +1,4 @@ + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/assets/svg/icon-plus-primary-outlined.svg b/openmetadata-ui/src/main/resources/ui/src/assets/svg/icon-plus-primary-outlined.svg new file mode 100644 index 00000000000..c706464adb6 --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/assets/svg/icon-plus-primary-outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/openmetadata-ui/src/main/resources/ui/src/components/AddWebhook/AddWebhook.tsx b/openmetadata-ui/src/main/resources/ui/src/components/AddWebhook/AddWebhook.tsx index 9a807e86282..8723e2d05e3 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/AddWebhook/AddWebhook.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/AddWebhook/AddWebhook.tsx @@ -19,8 +19,7 @@ import cryptoRandomString from 'crypto-random-string-with-promisify-polyfill'; import { cloneDeep, isEqual, isNil } from 'lodash'; import { EditorContentRef } from 'Models'; import React, { FunctionComponent, useCallback, useRef, useState } from 'react'; -import { TERM_ALL } from '../../constants/constants'; -import { ROUTES } from '../../constants/constants'; +import { ROUTES, TERM_ALL } from '../../constants/constants'; import { GlobalSettingOptions, GlobalSettingsMenuCategory, diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/Glossary.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/Glossary.test.tsx index e3eef57d975..971245418d6 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/Glossary.test.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/Glossary.test.tsx @@ -49,7 +49,12 @@ jest.mock('../../components/GlossaryTerms/GlossaryTermsV1.component', () => { return jest.fn().mockReturnValue(<>Glossary-Term component); }); +jest.mock('../common/title-breadcrumb/title-breadcrumb.component', () => { + return jest.fn().mockReturnValue(<>TitleBreadcrumb); +}); + jest.mock('antd', () => ({ + Card: jest.fn().mockImplementation(({ children }) =>
{children}
), Col: jest.fn().mockImplementation(({ children }) =>
{children}
), Input: jest.fn().mockImplementation(({ children }) =>
{children}
), Row: jest.fn().mockImplementation(({ children }) =>
{children}
), diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryV1.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryV1.component.tsx index 55ee013286c..570e39261a5 100644 --- a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryV1.component.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryV1.component.tsx @@ -162,8 +162,9 @@ const GlossaryV1 = ({ if (selectedKey !== key) { handleChildLoading(true); handleSelectedData(key); - setIsNameEditing(false); } + + setIsNameEditing(false); }; const onDisplayNameChange = (value: string) => { @@ -349,7 +350,7 @@ const GlossaryV1 = ({ visible={showActions} onVisibleChange={setShowActions}> - - ); - }; - - const editButton = (onClick: () => void) => { - return ( - - + + ); }; @@ -430,46 +424,52 @@ const GlossaryTermsV1 = ({ ); }; - const getSynonyms = (synonyms: string) => { - return !isEmpty(synonyms) ? ( - synonyms - .split(',') - .map((synonym) => ( - - )) + const getSynonyms = (synonymsList: string) => { + return !isEmpty(synonymsList) ? ( + synonymsList.split(',').map((synonym, index) => ( + <> + {index > 0 ? , : null} + {synonym} + + )) ) : ( <> ); }; - const relatedTermActionBtn = () => { - return relatedTerms.length > 0 ? ( - editButton(() => setShowRelatedTermsModal(true)) - ) : ( - <> - ); - }; - - const referenceActionBtn = () => { - return references.length > 0 ? ( - editButton(() => setIsReferencesEditing(true)) - ) : ( - <> - ); - }; - - const summaryTab = () => { + const SummaryDetail = ({ + title, + children, + setShow, + data, + ...props + }: SummaryDetailsProps) => { return ( -
-
-
+ + + {title} +
+ {addButton(() => setShow && setShow(true))} +
+
+ {!isString(data) && !isUndefined(data) && data.length > 0 ? ( +
+ {children} +
+ ) : ( +
{children}
+ )} +
+ ); + }; + + const SummaryTab = () => { + return ( + + + -
- - - {relatedTerms.length > 0 ? ( -
- {relatedTerms.map((d, i) => ( - - {i > 0 && ,} + + + <> + {relatedTerms.map((d, i) => ( + + {i > 0 && ,} + { + onRelatedTermClick?.(d.fullyQualifiedName); + }}> { - onRelatedTermClick?.(d.fullyQualifiedName); - }}> - 32, - })} - title={d?.name as string}> - {d?.name} - + className={classNames('tw-inline-block tw-truncate', { + 'tw-w-52': (d?.name as string).length > 32, + })} + title={d?.name as string}> + {d?.name} - - ))} -
- ) : ( - addButton('Add Related Term', () => - setShowRelatedTermsModal(true) - ) - )} -
-
+ + + ))} + + + - - - {isSynonymsEditing ? ( -
- -
- - -
-
- ) : ( -
- - - - {getSynonyms(synonyms)} -
- )} -
-
+ + <> + {isSynonymsEditing ? ( + + + + + + + + ) : ( + <>{getSynonyms(synonyms)} + )} + + + - - - {references && references.length > 0 ? ( -
- {references.map((d, i) => ( + + <> + {references && + references.length > 0 && + references.map((d, i) => ( - {i > 0 && ,} + {i > 0 && ,} ))} -
- ) : ( - addButton('Add Reference', () => setIsReferencesEditing(true)) - )} -
+ +
-
-
- + + + + Reviewer + + }>
{getReviewerTabData()}
-
-
+ + ); }; @@ -699,7 +684,7 @@ const GlossaryTermsV1 = ({ />
- {activeTab === 1 && summaryTab()} + {activeTab === 1 && } {activeTab === 2 && ( void; onEntityFieldSelect?: (value: string) => void; } - const DescriptionV1 = ({ owner, hasEditAccess, @@ -76,7 +76,12 @@ const DescriptionV1 = ({ className="focus:tw-outline-none tw-text-primary" data-testid="edit-description" onClick={onDescriptionEdit}> - + ) : ( @@ -85,27 +90,25 @@ const DescriptionV1 = ({ }; return ( -
+ + + Description +
{editButton()}
+
- -
- {description?.trim() ? ( - - ) : ( - No description - )} -
-
- + {description?.trim() ? ( + + ) : ( + No description + )} {isEdit && ( ) : null} -
+
); }; diff --git a/openmetadata-ui/src/main/resources/ui/src/styles/components/glossary.less b/openmetadata-ui/src/main/resources/ui/src/styles/components/glossary.less new file mode 100644 index 00000000000..9662b023d2a --- /dev/null +++ b/openmetadata-ui/src/main/resources/ui/src/styles/components/glossary.less @@ -0,0 +1,52 @@ +/* + * Copyright 2022 Collate + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.glossary-card { + box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.12); +} + +.m-r-1 { + margin: 1rem 0; +} +.p-lr-3 { + padding-left: 0.75rem; + padding-right: 0.75rem; +} +.left-panel-card { + border: 1px rgb(221, 227, 234) solid; + border-radius: 4px; + box-shadow: 1px 1px 8px rgb(0 0 0 / 6%); + height: 100%; + .header { + padding: 0.5rem 0.75rem; + } + .ant-card-body { + padding: 0px; + } + .ant-card-head { + border-bottom: none; + margin-bottom: 0.5rem; + + .ant-card-head-title { + font-weight: 600; + font-size: 1rem; + line-height: 1.5rem; + } + } +} + +.right-card { + .ant-card-head-wrapper { + padding: 0.37rem 0.13rem; + } +} diff --git a/openmetadata-ui/src/main/resources/ui/src/styles/index.js b/openmetadata-ui/src/main/resources/ui/src/styles/index.js index c5dfbd5a961..d62429e607c 100644 --- a/openmetadata-ui/src/main/resources/ui/src/styles/index.js +++ b/openmetadata-ui/src/main/resources/ui/src/styles/index.js @@ -14,6 +14,7 @@ import 'tailwindcss/tailwind.css'; import '../fonts/Inter/Inter-VariableFont_slnt,wght.ttf'; import './antd-master.less'; +import './components/glossary.less'; import './components/step.less'; import './fonts.css'; import './myDataDetailsTemp.css'; diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/SvgUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/SvgUtils.tsx index 3e5553d219f..ddc61c01f96 100644 --- a/openmetadata-ui/src/main/resources/ui/src/utils/SvgUtils.tsx +++ b/openmetadata-ui/src/main/resources/ui/src/utils/SvgUtils.tsx @@ -109,9 +109,11 @@ import IconWorkflows from '../assets/svg/ic-workflows.svg'; import IconChevronDown from '../assets/svg/icon-chevron-down.svg'; import IconCopy from '../assets/svg/icon-copy.svg'; import IconDown from '../assets/svg/icon-down.svg'; +import IcEditPrimary from '../assets/svg/icon-edit-primary.svg'; import IconInfoSecondary from '../assets/svg/icon-info.svg'; import IconKey from '../assets/svg/icon-key.svg'; import IconNotNull from '../assets/svg/icon-notnull.svg'; +import IconPlusPrimaryOutlined from '../assets/svg/icon-plus-primary-outlined.svg'; import IconRoleGrey from '../assets/svg/icon-role-grey.svg'; import IconTour from '../assets/svg/icon-tour.svg'; import IconUnique from '../assets/svg/icon-unique.svg'; @@ -271,6 +273,7 @@ export const Icons = { TOUR: 'tour', ICON_PLUS: 'icon-plus', ICON_PLUS_PRIMERY: 'icon-plus-primary', + ICON_PLUS_PRIMARY_OUTLINED: 'icon-plus-primary-outlined', ICON_MINUS: 'icon-minus', TAG: 'icon-tag', TAG_GREY: 'icon-tag-grey', @@ -333,6 +336,7 @@ export const Icons = { POLICIES: 'policies', INFO_SECONDARY: 'info-secondary', ICON_REMOVE: 'icon-remove', + IC_EDIT_PRIMARY: 'ic-edit-primary', }; const SVGIcons: FunctionComponent = ({ @@ -971,6 +975,14 @@ const SVGIcons: FunctionComponent = ({ case Icons.ICON_REMOVE: IconComponent = IconRemove; + break; + case Icons.IC_EDIT_PRIMARY: + IconComponent = IcEditPrimary; + + break; + case Icons.ICON_PLUS_PRIMARY_OUTLINED: + IconComponent = IconPlusPrimaryOutlined; + break; case Icons.INFO_SECONDARY: