diff --git a/web/common/src/components/Lineage/LineageColumnLevel/FactoryColumn.tsx b/web/common/src/components/Lineage/LineageColumnLevel/FactoryColumn.tsx index 294d3ca462..3b83288615 100644 --- a/web/common/src/components/Lineage/LineageColumnLevel/FactoryColumn.tsx +++ b/web/common/src/components/Lineage/LineageColumnLevel/FactoryColumn.tsx @@ -233,7 +233,7 @@ export function FactoryColumn< {type} } className={cn( - 'FactoryColumn__Metadata relative overflow-visible group', + 'FactoryColumn__Metadata relative overflow-visible', isDisabledColumn && 'cursor-not-allowed', className, )} diff --git a/web/common/src/components/Lineage/LineageColumnLevel/help.ts b/web/common/src/components/Lineage/LineageColumnLevel/help.ts index fe75ed162a..0966308a72 100644 --- a/web/common/src/components/Lineage/LineageColumnLevel/help.ts +++ b/web/common/src/components/Lineage/LineageColumnLevel/help.ts @@ -236,9 +236,9 @@ export function calculateColumnsHeight({ const hasColumns = columnsCount > 0 const columnHeight = 24 // tailwind h-6 const columnsTopSeparator = 1 - const columnSeparator = 1 + const columnSeparator = 0 const columnsContainerPadding = 4 - const columnsPadding = 4 + const columnsPadding = 0 const columnsFilterHeight = hasColumnsFilter && hasColumns ? columnHeight : 0 const columnsSeparators = columnsCount > 1 ? columnsCount - 1 : 0 diff --git a/web/common/src/components/Lineage/LineageContext.ts b/web/common/src/components/Lineage/LineageContext.ts index 7c76c2cfd4..10ed0a1e1a 100644 --- a/web/common/src/components/Lineage/LineageContext.ts +++ b/web/common/src/components/Lineage/LineageContext.ts @@ -64,7 +64,6 @@ export interface LineageContextValue< > currentNodeId: TNodeID | null selectedNode: LineageNode | null - currentNode: LineageNode | null } export function getInitial< @@ -89,7 +88,6 @@ export function getInitial< selectedNodeId: null, selectedNode: null, currentNodeId: null, - currentNode: null, } } diff --git a/web/common/src/components/Lineage/LineageLayout.tsx b/web/common/src/components/Lineage/LineageLayout.tsx index e19046780a..32cb989d31 100644 --- a/web/common/src/components/Lineage/LineageLayout.tsx +++ b/web/common/src/components/Lineage/LineageLayout.tsx @@ -35,14 +35,11 @@ export function LineageLayout< edgeTypes, className, controls, - nodesDraggable, - nodesConnectable, isBuildingLayout, useLineage, onNodeClick, onNodeDoubleClick, showControlOnlySelectedNodes, - showControlZoomToCurrentNode, showControlZoomToSelectedNode, }: { useLineage: LineageContextHook< @@ -59,10 +56,7 @@ export function LineageLayout< nodeTypes?: NodeTypes edgeTypes?: EdgeTypes className?: string - nodesDraggable?: boolean - nodesConnectable?: boolean showControlOnlySelectedNodes?: boolean - showControlZoomToCurrentNode?: boolean showControlZoomToSelectedNode?: boolean controls?: | React.ReactNode @@ -85,14 +79,11 @@ export function LineageLayout< diff --git a/web/common/src/components/Lineage/LineageLayoutBase.tsx b/web/common/src/components/Lineage/LineageLayoutBase.tsx index 93a55858bb..45c4db8116 100644 --- a/web/common/src/components/Lineage/LineageLayoutBase.tsx +++ b/web/common/src/components/Lineage/LineageLayoutBase.tsx @@ -2,9 +2,7 @@ import { Background, BackgroundVariant, Controls, - type EdgeChange, type EdgeTypes, - type NodeChange, type NodeTypes, ReactFlow, type SetCenter, @@ -13,14 +11,12 @@ import { getOutgoers, useReactFlow, useViewport, - applyNodeChanges, - applyEdgeChanges, } from '@xyflow/react' import '@xyflow/react/dist/style.css' import './Lineage.css' -import { CircuitBoard, Crosshair, LocateFixed, RotateCcw } from 'lucide-react' +import { CircuitBoard, LocateFixed, RotateCcw } from 'lucide-react' import React from 'react' import { type LineageContextHook } from './LineageContext' @@ -60,13 +56,10 @@ export function LineageLayoutBase< edgeTypes, className, controls, - nodesDraggable = false, - nodesConnectable = false, useLineage, onNodeClick, onNodeDoubleClick, showControlOnlySelectedNodes = true, - showControlZoomToCurrentNode = true, showControlZoomToSelectedNode = true, }: { useLineage: LineageContextHook< @@ -79,13 +72,10 @@ export function LineageLayoutBase< TSourceHandleID, TTargetHandleID > - nodesDraggable?: boolean - nodesConnectable?: boolean nodeTypes?: NodeTypes edgeTypes?: EdgeTypes className?: string showControlOnlySelectedNodes?: boolean - showControlZoomToCurrentNode?: boolean showControlZoomToSelectedNode?: boolean controls?: | React.ReactNode @@ -103,74 +93,20 @@ export function LineageLayoutBase< const { setCenter } = useReactFlow() const { - currentNode, zoom, - nodes: initialNodes, + nodes, edges, - setEdges, selectedNode, showOnlySelectedNodes, selectedNodeId, setZoom, - setSelectedNodeId, setShowOnlySelectedNodes, setSelectedNodes, setSelectedEdges, } = useLineage() - const [nodes, setNodes] = - React.useState[]>(initialNodes) - - const onNodesChange = React.useCallback( - (changes: NodeChange>[]) => { - setNodes(applyNodeChanges(changes, nodes)) - }, - [nodes], - ) - - const onEdgesChange = React.useCallback( - ( - changes: EdgeChange< - LineageEdge< - TEdgeData, - TEdgeID, - TSourceID, - TTargetID, - TSourceHandleID, - TTargetHandleID - > - >[], - ) => { - setEdges( - applyEdgeChanges< - LineageEdge< - TEdgeData, - TEdgeID, - TSourceID, - TTargetID, - TSourceHandleID, - TTargetHandleID - > - >(changes, edges), - ) - }, - [edges], - ) - const updateZoom = React.useMemo(() => debounce(setZoom, 200), [setZoom]) - const zoomToCurrentNode = React.useCallback( - (zoom: number = DEFAULT_ZOOM) => { - if (currentNode) { - setCenter(currentNode.position.x, currentNode.position.y, { - zoom, - duration: 0, - }) - } - }, - [currentNode?.position.x, currentNode?.position.y], - ) - const zoomToSelectedNode = React.useCallback( (zoom: number = DEFAULT_ZOOM) => { if (selectedNode) { @@ -195,13 +131,13 @@ export function LineageLayoutBase< return Array.from( new Set>([ node, - ...getIncomers(node, initialNodes, edges) + ...getIncomers(node, nodes, edges) .map(n => getAllIncomers(n, visited)) .flat(), ]), ) }, - [initialNodes, edges], + [nodes, edges], ) const getAllOutgoers = React.useCallback( @@ -216,13 +152,13 @@ export function LineageLayoutBase< return Array.from( new Set>([ node, - ...getOutgoers(node, initialNodes, edges) + ...getOutgoers(node, nodes, edges) .map(n => getAllOutgoers(n, visited)) .flat(), ]), ) }, - [initialNodes, edges], + [nodes, edges], ) const connectedNodes = React.useMemo(() => { @@ -233,12 +169,8 @@ export function LineageLayoutBase< ...getAllOutgoers(selectedNode), ] - if (currentNode) { - all.push(currentNode) - } - return all - }, [selectedNode, currentNode, getAllIncomers, getAllOutgoers]) + }, [selectedNode, getAllIncomers, getAllOutgoers]) const connectedEdges = React.useMemo(() => { return getConnectedEdges< @@ -254,19 +186,11 @@ export function LineageLayoutBase< >(connectedNodes, edges) }, [connectedNodes, edges]) - React.useEffect(() => { - setNodes(initialNodes) - }, [initialNodes]) - React.useEffect(() => { if (selectedNodeId == null) { setShowOnlySelectedNodes(false) setSelectedNodes(new Set()) setSelectedEdges(new Set()) - } else { - if (selectedNode == null) { - setSelectedNodeId(null) - } } }, [selectedNodeId, selectedNode]) @@ -317,17 +241,12 @@ export function LineageLayoutBase< edges={edges} nodeTypes={nodeTypes} edgeTypes={edgeTypes} - onNodesChange={onNodesChange} - onEdgesChange={onEdgesChange} - nodesDraggable={nodesDraggable} - nodesConnectable={nodesConnectable} zoomOnDoubleClick={false} panOnScroll={true} zoomOnScroll={true} minZoom={nodes.length > NODES_TRESHOLD ? NODES_TRESHOLD_ZOOM : MIN_ZOOM} maxZoom={MAX_ZOOM} fitView={false} - nodeOrigin={[0.5, 0.5]} onlyRenderVisibleElements onNodeClick={onNodeClick} onNodeDoubleClick={onNodeDoubleClick} @@ -346,14 +265,6 @@ export function LineageLayoutBase< position="top-right" className="m-1 border-2 border-lineage-control-border rounded-sm overflow-hidden" > - {currentNode && showControlZoomToCurrentNode && ( - zoomToCurrentNode(DEFAULT_ZOOM)} - > - - - )} {selectedNodeId && ( <> {showControlOnlySelectedNodes && ( diff --git a/web/common/src/components/Lineage/help.ts b/web/common/src/components/Lineage/help.ts index e8041d9f56..63a7c049c5 100644 --- a/web/common/src/components/Lineage/help.ts +++ b/web/common/src/components/Lineage/help.ts @@ -41,17 +41,17 @@ export function getTransformedNodes< adjacencyListKeys: TAdjacencyListKey[], lineageDetails: LineageDetails, transformNode: TransformNodeFn, + allNodesMap?: LineageNodesMap, ): LineageNodesMap { const nodesCount = adjacencyListKeys.length const nodesMap: LineageNodesMap = Object.create(null) for (let i = 0; i < nodesCount; i++) { const adjacencyListKey = adjacencyListKeys[i] - const encodedNodeId = toNodeID(adjacencyListKey) - nodesMap[encodedNodeId] = transformNode( - encodedNodeId, - lineageDetails[adjacencyListKey], - ) + const nodeId = toNodeID(adjacencyListKey) + nodesMap[nodeId] = + allNodesMap?.[nodeId] || + transformNode(nodeId, lineageDetails[adjacencyListKey]) } return nodesMap diff --git a/web/common/src/components/Lineage/layout/dagreLayout.ts b/web/common/src/components/Lineage/layout/dagreLayout.ts index d7a5c01e2e..16f59f495a 100644 --- a/web/common/src/components/Lineage/layout/dagreLayout.ts +++ b/web/common/src/components/Lineage/layout/dagreLayout.ts @@ -21,6 +21,7 @@ export function buildLayout< >({ edges, nodesMap, + shouldReuseExistingPosition = true, }: { edges: LineageEdge< TEdgeData, @@ -31,6 +32,7 @@ export function buildLayout< TTargetHandleID >[] nodesMap: LineageNodesMap + shouldReuseExistingPosition?: boolean }) { const nodes = Object.values(nodesMap) const nodeCount = nodes.length @@ -46,7 +48,7 @@ export function buildLayout< g.setGraph({ rankdir: 'LR', - nodesep: 0, + nodesep: 12, ranksep: 48, edgesep: 0, ranker: 'longest-path', @@ -78,12 +80,19 @@ export function buildLayout< const nodeWithPosition = g.node(nodeId) const halfWidth = width / 2 const halfHeight = height / 2 + const isDefaultPosition = node.position.x === 0 && node.position.y === 0 nodesMap[nodeId] = { ...node, position: { - x: nodeWithPosition.x - halfWidth, - y: nodeWithPosition.y - halfHeight, + x: + shouldReuseExistingPosition && isDefaultPosition + ? nodeWithPosition.x - halfWidth + : node.position.x, + y: + shouldReuseExistingPosition && isDefaultPosition + ? nodeWithPosition.y - halfHeight + : node.position.y, }, } } diff --git a/web/common/src/components/Lineage/node/useNodeMetadata.tsx b/web/common/src/components/Lineage/node/useNodeMetadata.tsx index 3601b752fd..72a8be90ba 100644 --- a/web/common/src/components/Lineage/node/useNodeMetadata.tsx +++ b/web/common/src/components/Lineage/node/useNodeMetadata.tsx @@ -4,17 +4,14 @@ import { useNodeConnections, } from '@xyflow/react' -import { type LineageNode, type LineageNodeData, type NodeId } from '../utils' +import { type LineageNodeData, type NodeId } from '../utils' export type NodeProps = ReactFlowNodeProps> -export function useNodeMetadata< - TNodeData extends LineageNodeData = LineageNodeData, - TNodeID extends string = NodeId, ->( +export function useNodeMetadata( nodeId: TNodeID, - currentNode: LineageNode | null, + currentNodeId: TNodeID | null, selectedNodeId: TNodeID | null, selectedNodes: Set, ) { @@ -29,7 +26,7 @@ export function useNodeMetadata< const leftId = targets.length > 0 ? nodeId : undefined const rightId = sources.length > 0 ? nodeId : undefined - const isCurrent = currentNode?.id === nodeId + const isCurrent = currentNodeId === nodeId const isSelected = selectedNodeId === nodeId const isActive = selectedNodes.has(nodeId) diff --git a/web/common/src/components/Lineage/stories/Lineage.stories.tsx b/web/common/src/components/Lineage/stories/Lineage.stories.tsx index 76c4229250..87a757bbc4 100644 --- a/web/common/src/components/Lineage/stories/Lineage.stories.tsx +++ b/web/common/src/components/Lineage/stories/Lineage.stories.tsx @@ -1,5 +1,3 @@ -import type { LineageAdjacencyList, LineageDetails } from '../utils' - import { ModelLineage } from './ModelLineage' import type { BrandedLineageAdjacencyList, diff --git a/web/common/src/components/Lineage/stories/ModelLineage.tsx b/web/common/src/components/Lineage/stories/ModelLineage.tsx index 215ebb1f84..b4a65fd71e 100644 --- a/web/common/src/components/Lineage/stories/ModelLineage.tsx +++ b/web/common/src/components/Lineage/stories/ModelLineage.tsx @@ -1,4 +1,4 @@ -import { Focus, LockOpen, Rows2, Rows3, Lock } from 'lucide-react' +import { Focus, Rows2, Rows3 } from 'lucide-react' import React from 'react' import { @@ -82,7 +82,6 @@ export const ModelLineage = ({ const [zoom, setZoom] = React.useState(ZOOM_THRESHOLD) const [isBuildingLayout, setIsBuildingLayout] = React.useState(false) - const [nodesDraggable, setNodesDraggable] = React.useState(false) const [edges, setEdges] = React.useState< LineageEdge< EdgeData, @@ -311,6 +310,7 @@ export const ModelLineage = ({ }) .catch(error => { console.error('Layout processing failed:', error) + setEdges([]) setNodesMap({}) }) @@ -324,7 +324,6 @@ export const ModelLineage = ({ return Object.values(nodesMap) }, [nodesMap]) - const currentNode = currentNodeId ? nodesMap[currentNodeId] : null const selectedNode = selectedNodeId ? nodesMap[selectedNodeId] : null const handleReset = React.useCallback(() => { @@ -384,7 +383,6 @@ export const ModelLineage = ({ edges, nodes, nodesMap, - currentNode, setFetchingColumns, setColumnLevelLineage, setShowColumns, @@ -412,7 +410,6 @@ export const ModelLineage = ({ nodeTypes={nodeTypes} edgeTypes={edgeTypes} className={className} - nodesDraggable={nodesDraggable} controls={ <> - setNodesDraggable(prev => !prev)} - disabled={isBuildingLayout} - > - - } /> diff --git a/web/common/src/components/Lineage/stories/ModelNode.tsx b/web/common/src/components/Lineage/stories/ModelNode.tsx index 8dbcc5fc19..4af804aad2 100644 --- a/web/common/src/components/Lineage/stories/ModelNode.tsx +++ b/web/common/src/components/Lineage/stories/ModelNode.tsx @@ -51,7 +51,7 @@ export const ModelNode = React.memo(function ModelNode({ const { selectedColumns, zoom, - currentNode, + currentNodeId, selectedNodeId, selectedNodes, showColumns, @@ -70,7 +70,7 @@ export const ModelNode = React.memo(function ModelNode({ isCurrent, isSelected, // if selected from inside the lineage and node is selcted isActive, // if selected from inside the lineage and node is not selected but in path - } = useNodeMetadata(nodeId, currentNode, selectedNodeId, selectedNodes) + } = useNodeMetadata(nodeId, currentNodeId, selectedNodeId, selectedNodes) const { columns, @@ -132,7 +132,7 @@ export const ModelNode = React.memo(function ModelNode({ ({ )}