mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-30 20:06:19 +00:00
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:
parent
11ba94e4ea
commit
41262ecb59
@ -13,8 +13,10 @@
|
||||
|
||||
import { CloseOutlined } from '@ant-design/icons';
|
||||
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 React, { useEffect, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Node } from 'reactflow';
|
||||
@ -23,7 +25,6 @@ import { getEncodedFqn } from 'utils/StringsUtils';
|
||||
import { CSMode } from '../../../enums/codemirror.enum';
|
||||
import { getNameFromFQN } from '../../../utils/CommonUtils';
|
||||
import { getEntityLink } from '../../../utils/TableUtils';
|
||||
import RichTextEditorPreviewer from '../../common/rich-text-editor/RichTextEditorPreviewer';
|
||||
import Loader from '../../Loader/Loader';
|
||||
import SchemaEditor from '../../schema-editor/SchemaEditor';
|
||||
import {
|
||||
@ -37,12 +38,21 @@ const EdgeInfoDrawer = ({
|
||||
visible,
|
||||
onClose,
|
||||
nodes,
|
||||
hasEditAccess,
|
||||
onEdgeDescriptionUpdate,
|
||||
}: EdgeInfoDrawerInfo) => {
|
||||
const [edgeData, setEdgeData] = useState<EdgeInformationType>();
|
||||
const [mysqlQuery, setMysqlQuery] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [isDescriptionEditable, setIsDescriptionEditable] =
|
||||
useState<boolean>(false);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const edgeEntity = useMemo(() => {
|
||||
return edge.data.edge;
|
||||
}, [edge]);
|
||||
|
||||
const getEdgeInfo = () => {
|
||||
const { source, target, data, sourceHandle, targetHandle } = edge;
|
||||
let sourceData: Node | undefined, targetData: Node | undefined;
|
||||
@ -101,6 +111,39 @@ const EdgeInfoDrawer = ({
|
||||
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(() => {
|
||||
setIsLoading(true);
|
||||
getEdgeInfo();
|
||||
@ -145,20 +188,17 @@ const EdgeInfoDrawer = ({
|
||||
)}
|
||||
<Col span={24}>
|
||||
<Divider />
|
||||
<Typography.Paragraph className="summary-panel-section-title">
|
||||
{`${t('label.description')}:`}
|
||||
</Typography.Paragraph>
|
||||
{edge?.data.edge?.description?.trim() ? (
|
||||
<RichTextEditorPreviewer
|
||||
markdown={edge?.data.edge?.description}
|
||||
/>
|
||||
) : (
|
||||
<Typography.Paragraph className=" m-b-0">
|
||||
{t('label.no-entity', {
|
||||
entity: t('label.description'),
|
||||
})}
|
||||
</Typography.Paragraph>
|
||||
)}
|
||||
<DescriptionV1
|
||||
description={edgeDescription}
|
||||
entityName="Edge"
|
||||
entityType={EntityType.GLOSSARY}
|
||||
hasEditAccess={hasEditAccess}
|
||||
isEdit={isDescriptionEditable}
|
||||
showCommentsIcon={false}
|
||||
onCancel={() => setIsDescriptionEditable(false)}
|
||||
onDescriptionEdit={() => setIsDescriptionEditable(true)}
|
||||
onDescriptionUpdate={onDescriptionUpdate}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Divider />
|
||||
|
@ -11,6 +11,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AddLineage } from 'generated/api/lineage/addLineage';
|
||||
import { Edge, Node } from 'reactflow';
|
||||
import { SelectedNode } from '../EntityLineage/EntityLineage.interface';
|
||||
|
||||
@ -25,7 +26,9 @@ export interface EdgeInfoDrawerInfo {
|
||||
edge: Edge;
|
||||
nodes: Node[];
|
||||
visible: boolean;
|
||||
hasEditAccess: boolean;
|
||||
onClose: () => void;
|
||||
onEdgeDescriptionUpdate: (updatedEdgeDetails: AddLineage) => Promise<void>;
|
||||
}
|
||||
type InfoType = {
|
||||
key: string;
|
||||
|
@ -65,7 +65,7 @@ import ReactFlow, {
|
||||
useNodesState,
|
||||
} from 'reactflow';
|
||||
import { getDataModelDetails } from 'rest/dataModelsAPI';
|
||||
import { getLineageByFQN } from 'rest/lineageAPI';
|
||||
import { getLineageByFQN, updateLineageEdge } from 'rest/lineageAPI';
|
||||
import { searchData } from 'rest/miscAPI';
|
||||
import { getTableDetails } from 'rest/tableAPI';
|
||||
import {
|
||||
@ -106,6 +106,7 @@ import {
|
||||
onNodeMouseLeave,
|
||||
onNodeMouseMove,
|
||||
removeLineageHandler,
|
||||
updateEdgesWithLineageDetails,
|
||||
} from 'utils/EntityLineageUtils';
|
||||
import {
|
||||
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
|
||||
* Change newly added node label based on entity:EntityReference
|
||||
@ -1681,12 +1732,14 @@ const EntityLineageComponent: FunctionComponent<EntityLineageProp> = ({
|
||||
(selectedEdgeInfo ? (
|
||||
<EdgeInfoDrawer
|
||||
edge={selectedEdgeInfo}
|
||||
hasEditAccess={hasEditAccess}
|
||||
nodes={nodes}
|
||||
visible={isDrawerOpen}
|
||||
onClose={() => {
|
||||
setIsDrawerOpen(false);
|
||||
setSelectedEdgeInfo(undefined);
|
||||
}}
|
||||
onEdgeDescriptionUpdate={onEdgeDescriptionUpdate}
|
||||
/>
|
||||
) : (
|
||||
<EntityInfoDrawer
|
||||
|
@ -32,7 +32,7 @@ export interface SelectedNode {
|
||||
export interface EntityLineageProp {
|
||||
entityType: EntityType;
|
||||
deleted?: boolean;
|
||||
hasEditAccess?: boolean;
|
||||
hasEditAccess: boolean;
|
||||
isFullScreen?: boolean;
|
||||
entity?: SourceType;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AddLineage } from 'generated/api/lineage/addLineage';
|
||||
import { EntityLineage } from '../generated/type/entityLineage';
|
||||
import APIClient from './index';
|
||||
|
||||
@ -26,3 +27,9 @@ export const getLineageByFQN = async (
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const updateLineageEdge = async (edge: AddLineage) => {
|
||||
const response = await APIClient.put<AddLineage>(`/lineage`, edge);
|
||||
|
||||
return response.data;
|
||||
};
|
||||
|
@ -1372,3 +1372,16 @@ export const getSearchIndexFromNodeType = (entityType: string) => {
|
||||
|
||||
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
|
||||
);
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user