mirror of
				https://github.com/open-metadata/OpenMetadata.git
				synced 2025-10-26 00:04:52 +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
	 karanh37
						karanh37