Issue 10516 (#13297)

* fix: add description component for lineage

* fix: update lineage data

* fix: code smells

---------

Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com>
This commit is contained in:
karanh37 2023-09-22 12:59:05 +05:30 committed by GitHub
parent 11ba94e4ea
commit 41262ecb59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 134 additions and 18 deletions

View File

@ -13,8 +13,10 @@
import { CloseOutlined } from '@ant-design/icons'; import { CloseOutlined } from '@ant-design/icons';
import { Col, Divider, Drawer, Row, Typography } from 'antd'; import { Col, Divider, Drawer, Row, Typography } from 'antd';
import DescriptionV1 from 'components/common/description/DescriptionV1';
import { EntityType } from 'enums/entity.enum';
import { isUndefined } from 'lodash'; import { isUndefined } from 'lodash';
import React, { useEffect, useState } from 'react'; import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Node } from 'reactflow'; import { Node } from 'reactflow';
@ -23,7 +25,6 @@ import { getEncodedFqn } from 'utils/StringsUtils';
import { CSMode } from '../../../enums/codemirror.enum'; import { CSMode } from '../../../enums/codemirror.enum';
import { getNameFromFQN } from '../../../utils/CommonUtils'; import { getNameFromFQN } from '../../../utils/CommonUtils';
import { getEntityLink } from '../../../utils/TableUtils'; import { getEntityLink } from '../../../utils/TableUtils';
import RichTextEditorPreviewer from '../../common/rich-text-editor/RichTextEditorPreviewer';
import Loader from '../../Loader/Loader'; import Loader from '../../Loader/Loader';
import SchemaEditor from '../../schema-editor/SchemaEditor'; import SchemaEditor from '../../schema-editor/SchemaEditor';
import { import {
@ -37,12 +38,21 @@ const EdgeInfoDrawer = ({
visible, visible,
onClose, onClose,
nodes, nodes,
hasEditAccess,
onEdgeDescriptionUpdate,
}: EdgeInfoDrawerInfo) => { }: EdgeInfoDrawerInfo) => {
const [edgeData, setEdgeData] = useState<EdgeInformationType>(); const [edgeData, setEdgeData] = useState<EdgeInformationType>();
const [mysqlQuery, setMysqlQuery] = useState(''); const [mysqlQuery, setMysqlQuery] = useState('');
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [isDescriptionEditable, setIsDescriptionEditable] =
useState<boolean>(false);
const { t } = useTranslation(); const { t } = useTranslation();
const edgeEntity = useMemo(() => {
return edge.data.edge;
}, [edge]);
const getEdgeInfo = () => { const getEdgeInfo = () => {
const { source, target, data, sourceHandle, targetHandle } = edge; const { source, target, data, sourceHandle, targetHandle } = edge;
let sourceData: Node | undefined, targetData: Node | undefined; let sourceData: Node | undefined, targetData: Node | undefined;
@ -101,6 +111,39 @@ const EdgeInfoDrawer = ({
setIsLoading(false); setIsLoading(false);
}; };
const edgeDescription = useMemo(() => {
return edgeEntity?.lineageDetails?.description ?? '';
}, [edgeEntity]);
const onDescriptionUpdate = useCallback(
async (updatedHTML: string) => {
if (edgeDescription !== updatedHTML && edgeEntity) {
const lineageDetails = {
...edgeEntity.lineageDetails,
description: updatedHTML,
};
const updatedEdgeDetails = {
edge: {
fromEntity: {
id: edgeEntity.fromEntity,
type: edge.data.sourceType,
},
toEntity: {
id: edgeEntity.toEntity,
type: edge.data.sourceType,
},
lineageDetails,
},
};
await onEdgeDescriptionUpdate(updatedEdgeDetails);
setIsDescriptionEditable(false);
} else {
setIsDescriptionEditable(false);
}
},
[edgeDescription, edgeEntity, edge.data]
);
useEffect(() => { useEffect(() => {
setIsLoading(true); setIsLoading(true);
getEdgeInfo(); getEdgeInfo();
@ -145,20 +188,17 @@ const EdgeInfoDrawer = ({
)} )}
<Col span={24}> <Col span={24}>
<Divider /> <Divider />
<Typography.Paragraph className="summary-panel-section-title"> <DescriptionV1
{`${t('label.description')}:`} description={edgeDescription}
</Typography.Paragraph> entityName="Edge"
{edge?.data.edge?.description?.trim() ? ( entityType={EntityType.GLOSSARY}
<RichTextEditorPreviewer hasEditAccess={hasEditAccess}
markdown={edge?.data.edge?.description} isEdit={isDescriptionEditable}
/> showCommentsIcon={false}
) : ( onCancel={() => setIsDescriptionEditable(false)}
<Typography.Paragraph className=" m-b-0"> onDescriptionEdit={() => setIsDescriptionEditable(true)}
{t('label.no-entity', { onDescriptionUpdate={onDescriptionUpdate}
entity: t('label.description'), />
})}
</Typography.Paragraph>
)}
</Col> </Col>
<Col span={24}> <Col span={24}>
<Divider /> <Divider />

View File

@ -11,6 +11,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { AddLineage } from 'generated/api/lineage/addLineage';
import { Edge, Node } from 'reactflow'; import { Edge, Node } from 'reactflow';
import { SelectedNode } from '../EntityLineage/EntityLineage.interface'; import { SelectedNode } from '../EntityLineage/EntityLineage.interface';
@ -25,7 +26,9 @@ export interface EdgeInfoDrawerInfo {
edge: Edge; edge: Edge;
nodes: Node[]; nodes: Node[];
visible: boolean; visible: boolean;
hasEditAccess: boolean;
onClose: () => void; onClose: () => void;
onEdgeDescriptionUpdate: (updatedEdgeDetails: AddLineage) => Promise<void>;
} }
type InfoType = { type InfoType = {
key: string; key: string;

View File

@ -65,7 +65,7 @@ import ReactFlow, {
useNodesState, useNodesState,
} from 'reactflow'; } from 'reactflow';
import { getDataModelDetails } from 'rest/dataModelsAPI'; import { getDataModelDetails } from 'rest/dataModelsAPI';
import { getLineageByFQN } from 'rest/lineageAPI'; import { getLineageByFQN, updateLineageEdge } from 'rest/lineageAPI';
import { searchData } from 'rest/miscAPI'; import { searchData } from 'rest/miscAPI';
import { getTableDetails } from 'rest/tableAPI'; import { getTableDetails } from 'rest/tableAPI';
import { import {
@ -106,6 +106,7 @@ import {
onNodeMouseLeave, onNodeMouseLeave,
onNodeMouseMove, onNodeMouseMove,
removeLineageHandler, removeLineageHandler,
updateEdgesWithLineageDetails,
} from 'utils/EntityLineageUtils'; } from 'utils/EntityLineageUtils';
import { import {
getEntityBreadcrumbs, getEntityBreadcrumbs,
@ -1482,6 +1483,56 @@ const EntityLineageComponent: FunctionComponent<EntityLineageProp> = ({
} }
}; };
const onEdgeDescriptionUpdate = useCallback(
async (updatedEdgeDetails: AddLineage) => {
try {
await updateLineageEdge(updatedEdgeDetails);
if (selectedEdgeInfo) {
const updatedSelectedEdgeInfo = {
...selectedEdgeInfo,
data: {
...selectedEdgeInfo.data,
edge: {
...selectedEdgeInfo.data.edge,
lineageDetails: updatedEdgeDetails.edge.lineageDetails,
},
},
};
const updatedEdges = edges.map((edge) =>
edge.id === selectedEdgeInfo.id ? updatedSelectedEdgeInfo : edge
);
setEdges(updatedEdges);
setSelectedEdgeInfo(updatedSelectedEdgeInfo);
setUpdatedLineageData((pre) => {
if (!pre) {
return;
}
const newData = {
...pre,
downstreamEdges: updateEdgesWithLineageDetails(
pre.downstreamEdges ?? [],
updatedEdgeDetails
),
upstreamEdges: updateEdgesWithLineageDetails(
pre.upstreamEdges ?? [],
updatedEdgeDetails
),
};
return newData;
});
}
} catch (err) {
showErrorToast(err as AxiosError);
}
},
[edges, selectedEdgeInfo, updatedLineageData, setUpdatedLineageData]
);
/** /**
* Handle updated lineage nodes * Handle updated lineage nodes
* Change newly added node label based on entity:EntityReference * Change newly added node label based on entity:EntityReference
@ -1681,12 +1732,14 @@ const EntityLineageComponent: FunctionComponent<EntityLineageProp> = ({
(selectedEdgeInfo ? ( (selectedEdgeInfo ? (
<EdgeInfoDrawer <EdgeInfoDrawer
edge={selectedEdgeInfo} edge={selectedEdgeInfo}
hasEditAccess={hasEditAccess}
nodes={nodes} nodes={nodes}
visible={isDrawerOpen} visible={isDrawerOpen}
onClose={() => { onClose={() => {
setIsDrawerOpen(false); setIsDrawerOpen(false);
setSelectedEdgeInfo(undefined); setSelectedEdgeInfo(undefined);
}} }}
onEdgeDescriptionUpdate={onEdgeDescriptionUpdate}
/> />
) : ( ) : (
<EntityInfoDrawer <EntityInfoDrawer

View File

@ -32,7 +32,7 @@ export interface SelectedNode {
export interface EntityLineageProp { export interface EntityLineageProp {
entityType: EntityType; entityType: EntityType;
deleted?: boolean; deleted?: boolean;
hasEditAccess?: boolean; hasEditAccess: boolean;
isFullScreen?: boolean; isFullScreen?: boolean;
entity?: SourceType; entity?: SourceType;
} }

View File

@ -11,6 +11,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { AddLineage } from 'generated/api/lineage/addLineage';
import { EntityLineage } from '../generated/type/entityLineage'; import { EntityLineage } from '../generated/type/entityLineage';
import APIClient from './index'; import APIClient from './index';
@ -26,3 +27,9 @@ export const getLineageByFQN = async (
return response.data; return response.data;
}; };
export const updateLineageEdge = async (edge: AddLineage) => {
const response = await APIClient.put<AddLineage>(`/lineage`, edge);
return response.data;
};

View File

@ -1372,3 +1372,16 @@ export const getSearchIndexFromNodeType = (entityType: string) => {
return SearchIndex[searchIndexKey] as ExploreSearchIndex; return SearchIndex[searchIndexKey] as ExploreSearchIndex;
}; };
export const updateEdgesWithLineageDetails = (
edgesArray: EntityLineageEdge[],
updatedEdgeDetails: AddLineage
) => {
const { fromEntity, toEntity, lineageDetails } = updatedEdgeDetails.edge;
return edgesArray.map((item) =>
item.toEntity === toEntity.id && item.fromEntity === fromEntity.id
? { ...item, lineageDetails: lineageDetails }
: item
);
};