Fix(#5914) glossary & glossaryTerm displayName (#6922)

* Fix(#5914) glossary & glossaryTerm displayName

* Minor change to show glossary displayname in the tree
This commit is contained in:
Sachin Chaurasiya 2022-08-25 16:19:29 +05:30 committed by GitHub
parent f23357ba68
commit c5ebfdc7e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 153 additions and 36 deletions

View File

@ -49,6 +49,18 @@ jest.mock('../../components/GlossaryTerms/GlossaryTermsV1.component', () => {
return jest.fn().mockReturnValue(<>Glossary-Term component</>);
});
jest.mock('antd', () => ({
Col: jest.fn().mockImplementation(({ children }) => <div>{children}</div>),
Input: jest.fn().mockImplementation(({ children }) => <div>{children}</div>),
Row: jest.fn().mockImplementation(({ children }) => <div>{children}</div>),
Space: jest.fn().mockImplementation(({ children }) => <div>{children}</div>),
Typography: {
Title: jest
.fn()
.mockImplementation(({ children }) => <div>{children}</div>),
},
}));
const mockProps = {
assetData: mockedAssetData,
currentPage: 1,

View File

@ -12,8 +12,9 @@
*/
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Col, Input, Row, Space, Typography } from 'antd';
import classNames from 'classnames';
import { isEmpty } from 'lodash';
import { cloneDeep, isEmpty } from 'lodash';
import { GlossaryTermAssets, LoadingState } from 'Models';
import RcTree from 'rc-tree';
import { DataNode, EventDataNode } from 'rc-tree/lib/interface';
@ -27,7 +28,7 @@ import { GlossaryTerm } from '../../generated/entity/data/glossaryTerm';
import { useAuth } from '../../hooks/authHooks';
import { useAfterMount } from '../../hooks/useAfterMount';
import { ModifiedGlossaryData } from '../../pages/GlossaryPage/GlossaryPageV1.component';
import { getEntityDeleteMessage } from '../../utils/CommonUtils';
import { getEntityDeleteMessage, getEntityName } from '../../utils/CommonUtils';
import { generateTreeData } from '../../utils/GlossaryUtils';
import { getGlossaryPath } from '../../utils/RouterUtils';
import SVGIcons, { Icons } from '../../utils/SvgUtils';
@ -43,6 +44,8 @@ import GlossaryDetails from '../GlossaryDetails/GlossaryDetails.component';
import GlossaryTermsV1 from '../GlossaryTerms/GlossaryTermsV1.component';
import Loader from '../Loader/Loader';
import EntityDeleteModal from '../Modals/EntityDeleteModal/EntityDeleteModal';
import './GlossaryV1.style.less';
const { Title } = Typography;
type Props = {
assetData: GlossaryTermAssets;
@ -120,12 +123,13 @@ const GlossaryV1 = ({
const [leftPanelWidth, setLeftPanelWidth] = useState(
document.getElementById('glossary-left-panel')?.offsetWidth || 0
);
const [isNameEditing, setIsNameEditing] = useState(false);
const [displayName, setDisplayName] = useState<string>();
/**
* To create breadcrumb from the fqn
* @param fqn fqn of glossary or glossary term
*/
const handleBreadcrum = (fqn: string) => {
const handleBreadcrumb = (fqn: string) => {
const arr = fqn.split(FQN_SEPARATOR_CHAR);
const dataFQN: Array<string> = [];
const newData = arr.map((d, i) => {
@ -159,9 +163,36 @@ const GlossaryV1 = ({
if (selectedKey !== key) {
handleChildLoading(true);
handleSelectedData(key);
setIsNameEditing(false);
}
};
const onDisplayNameChange = (value: string) => {
if (selectedData.displayName !== value) {
setDisplayName(value);
}
};
const onDisplayNameSave = () => {
let updatedDetails = cloneDeep(selectedData);
updatedDetails = {
...selectedData,
displayName: displayName,
};
if (
(updatedDetails as GlossaryTerm)?.glossary ||
(updatedDetails as GlossaryTerm)?.parent
) {
handleGlossaryTermUpdate(updatedDetails as GlossaryTerm);
} else {
updateGlossary(updatedDetails as Glossary);
}
setIsNameEditing(false);
};
useEffect(() => {
if (glossaryList.length) {
const generatedData = generateTreeData(glossaryList);
@ -170,7 +201,7 @@ const GlossaryV1 = ({
}, [glossaryList]);
useEffect(() => {
handleBreadcrum(selectedKey);
handleBreadcrumb(selectedKey);
}, [selectedKey]);
useAfterMount(() => {
@ -270,14 +301,16 @@ const GlossaryV1 = ({
);
};
useEffect(() => {
setDisplayName(selectedData?.displayName);
}, [selectedData]);
return glossaryList.length ? (
<PageLayout classes="tw-h-full tw-px-6" leftPanel={fetchLeftPanel()}>
<div
className="tw-flex tw-justify-between tw-items-center"
data-testid="header">
<div
className="tw-heading tw-text-link tw-text-base"
data-testid="category-name">
<div className="tw-text-link tw-text-base" data-testid="category-name">
<TitleBreadcrumb
titleLinks={breadcrumb}
widthDeductions={
@ -329,26 +362,81 @@ const GlossaryV1 = ({
{isChildLoading ? (
<Loader />
) : (
!isEmpty(selectedData) &&
(isGlossaryActive ? (
<GlossaryDetails
glossary={selectedData as Glossary}
handleUserRedirection={handleUserRedirection}
isHasAccess={isHasAccess}
updateGlossary={updateGlossary}
/>
) : (
<GlossaryTermsV1
assetData={assetData}
currentPage={currentPage}
glossaryTerm={selectedData as GlossaryTerm}
handleGlossaryTermUpdate={handleGlossaryTermUpdate}
handleUserRedirection={handleUserRedirection}
isHasAccess={isHasAccess}
onAssetPaginate={onAssetPaginate}
onRelatedTermClick={onRelatedTermClick}
/>
))
<>
<div className="edit-input">
{isNameEditing ? (
<Row align="middle" gutter={8}>
<Col>
<Input
className="input-width"
data-testid="displayName"
name="displayName"
value={displayName}
onChange={(e) => onDisplayNameChange(e.target.value)}
/>
</Col>
<Col>
<Button
className="icon-buttons"
data-testid="cancelAssociatedTag"
size="custom"
theme="primary"
variant="contained"
onMouseDown={() => setIsNameEditing(false)}>
<FontAwesomeIcon
className="tw-w-3.5 tw-h-3.5"
icon="times"
/>
</Button>
<Button
className="icon-buttons"
data-testid="saveAssociatedTag"
size="custom"
theme="primary"
variant="contained"
onMouseDown={onDisplayNameSave}>
<FontAwesomeIcon
className="tw-w-3.5 tw-h-3.5"
icon="check"
/>
</Button>
</Col>
</Row>
) : (
<Space className="display-name">
<Title level={4}>{getEntityName(selectedData)}</Title>
<button onClick={() => setIsNameEditing(true)}>
<SVGIcons
alt="icon-tag"
className="tw-mx-1"
icon={Icons.EDIT}
width="16"
/>
</button>
</Space>
)}
</div>
{!isEmpty(selectedData) &&
(isGlossaryActive ? (
<GlossaryDetails
glossary={selectedData as Glossary}
handleUserRedirection={handleUserRedirection}
isHasAccess={isHasAccess}
updateGlossary={updateGlossary}
/>
) : (
<GlossaryTermsV1
assetData={assetData}
currentPage={currentPage}
glossaryTerm={selectedData as GlossaryTerm}
handleGlossaryTermUpdate={handleGlossaryTermUpdate}
handleUserRedirection={handleUserRedirection}
isHasAccess={isHasAccess}
onAssetPaginate={onAssetPaginate}
onRelatedTermClick={onRelatedTermClick}
/>
))}
</>
)}
{selectedData && isDelete && (
<EntityDeleteModal

View File

@ -0,0 +1,19 @@
.display-name {
.ant-typography {
margin-bottom: 0;
}
}
.input-width {
width: 100%;
}
.edit-input {
padding: 1rem 0;
}
.icon-buttons {
padding: 0.2rem 0.2rem;
border-radius: 0.2rem;
margin-right: 0.3rem;
}

View File

@ -30,7 +30,6 @@ import {
GlossaryTerm,
TermReference,
} from '../../generated/entity/data/glossaryTerm';
import { EntityReference } from '../../generated/entity/type';
import { LabelType, State, TagSource } from '../../generated/type/tagLabel';
import jsonData from '../../jsons/en';
import { getEntityName } from '../../utils/CommonUtils';
@ -623,16 +622,13 @@ const GlossaryTermsV1 = ({
<div
className="tw-w-full tw-h-full tw-flex tw-flex-col"
data-testid="glossary-term">
<p className="tw-text-lg tw-font-medium tw--mt-3">
{getEntityName(glossaryTerm as unknown as EntityReference)}
</p>
{/* TODO: Add this stat when supporting status updation */}
{/* <div className="tw-flex tw-gap-11 tw-mb-2">
<div className="tw-font-medium">Status</div>
<div>{glossaryTerm.status}</div>
</div> */}
<div className="tw-flex tw-flex-wrap tw-group tw-mt-3" data-testid="tags">
<div className="tw-flex tw-flex-wrap tw-group" data-testid="tags">
{!isTagEditable && (
<>
{glossaryTerm?.tags && glossaryTerm.tags.length > 0 && (

View File

@ -42,6 +42,7 @@ import { EntityType, FqnPart, TabSpecificField } from '../enums/entity.enum';
import { Ownership } from '../enums/mydata.enum';
import { Dashboard } from '../generated/entity/data/dashboard';
import { Database } from '../generated/entity/data/database';
import { GlossaryTerm } from '../generated/entity/data/glossaryTerm';
import { Pipeline } from '../generated/entity/data/pipeline';
import { Table } from '../generated/entity/data/table';
import { Topic } from '../generated/entity/data/topic';
@ -628,6 +629,7 @@ export const getEntityName = (
| Team
| Policy
| Role
| GlossaryTerm
) => {
return entity?.displayName || entity?.name || '';
};

View File

@ -35,7 +35,7 @@ import { GlossaryTerm } from '../generated/entity/data/glossaryTerm';
import { ModifiedGlossaryData } from '../pages/GlossaryPage/GlossaryPageV1.component';
import { FileIcon, FolderIcon } from '../utils/svgconstant';
import { formatSearchGlossaryTermResponse } from './APIUtils';
import { getNameFromFQN } from './CommonUtils';
import { getEntityName } from './CommonUtils';
export interface GlossaryTermTreeNode {
children?: GlossaryTermTreeNode[];
@ -104,7 +104,7 @@ export const generateTreeData = (data: ModifiedGlossaryData[]): DataNode[] => {
return d.children?.length
? {
key: (d as GlossaryTerm)?.fullyQualifiedName || d.name,
title: getNameFromFQN(d.name),
title: getEntityName(d),
children: generateTreeData(d.children as ModifiedGlossaryData[]),
data: d,
icon: ({ selected }) =>
@ -112,7 +112,7 @@ export const generateTreeData = (data: ModifiedGlossaryData[]): DataNode[] => {
}
: {
key: (d as GlossaryTerm)?.fullyQualifiedName || d.name,
title: getNameFromFQN(d.name),
title: getEntityName(d),
data: d,
icon: ({ selected }) =>
FileIcon(selected ? PRIMERY_COLOR : TEXT_BODY_COLOR),