Skip to content

Commit 858f432

Browse files
authored
feat(web_common):add option to toggle node dragging in lineage (#5473)
1 parent 42fbc64 commit 858f432

File tree

3 files changed

+111
-23
lines changed

3 files changed

+111
-23
lines changed

web/common/src/components/Lineage/LineageLayout.tsx

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ import {
22
Background,
33
BackgroundVariant,
44
Controls,
5+
type EdgeChange,
56
type EdgeTypes,
7+
type NodeChange,
68
type NodeTypes,
79
ReactFlow,
810
ReactFlowProvider,
@@ -12,6 +14,8 @@ import {
1214
getOutgoers,
1315
useReactFlow,
1416
useViewport,
17+
applyNodeChanges,
18+
applyEdgeChanges,
1519
} from '@xyflow/react'
1620

1721
import '@xyflow/react/dist/style.css'
@@ -55,6 +59,8 @@ export function LineageLayout<
5559
edgeTypes,
5660
className,
5761
controls,
62+
nodesDraggable,
63+
nodesConnectable,
5864
useLineage,
5965
onNodeClick,
6066
onNodeDoubleClick,
@@ -69,6 +75,8 @@ export function LineageLayout<
6975
nodeTypes?: NodeTypes
7076
edgeTypes?: EdgeTypes
7177
className?: string
78+
nodesDraggable?: boolean
79+
nodesConnectable?: boolean
7280
controls?:
7381
| React.ReactNode
7482
| (({ setCenter }: { setCenter: SetCenter }) => React.ReactNode)
@@ -86,6 +94,8 @@ export function LineageLayout<
8694
<LineageLayoutBase
8795
nodeTypes={nodeTypes}
8896
edgeTypes={edgeTypes}
97+
nodesDraggable={nodesDraggable}
98+
nodesConnectable={nodesConnectable}
8999
className={className}
90100
controls={controls}
91101
useLineage={useLineage}
@@ -107,6 +117,8 @@ function LineageLayoutBase<
107117
edgeTypes,
108118
className,
109119
controls,
120+
nodesDraggable = false,
121+
nodesConnectable = false,
110122
useLineage,
111123
onNodeClick,
112124
onNodeDoubleClick,
@@ -118,6 +130,8 @@ function LineageLayoutBase<
118130
TEdgeID,
119131
TPortID
120132
>
133+
nodesDraggable?: boolean
134+
nodesConnectable?: boolean
121135
nodeTypes?: NodeTypes
122136
edgeTypes?: EdgeTypes
123137
className?: string
@@ -140,8 +154,8 @@ function LineageLayoutBase<
140154
isBuildingLayout,
141155
currentNode,
142156
zoom,
143-
nodes,
144-
edges,
157+
nodes: initialNodes,
158+
edges: initialEdges,
145159
nodesMap,
146160
showOnlySelectedNodes,
147161
selectedNodeId,
@@ -152,6 +166,32 @@ function LineageLayoutBase<
152166
setSelectedEdges,
153167
} = useLineage()
154168

169+
const [nodes, setNodes] = React.useState(initialNodes)
170+
const [edges, setEdges] = React.useState(initialEdges)
171+
172+
const onNodesChange = React.useCallback(
173+
(changes: NodeChange<LineageNode<TNodeData, TNodeID>>[]) => {
174+
setNodes(
175+
applyNodeChanges<LineageNode<TNodeData, TNodeID>>(changes, nodes),
176+
)
177+
},
178+
[nodes, setNodes],
179+
)
180+
181+
const onEdgesChange = React.useCallback(
182+
(
183+
changes: EdgeChange<LineageEdge<TEdgeData, TNodeID, TEdgeID, TPortID>>[],
184+
) => {
185+
setEdges(
186+
applyEdgeChanges<LineageEdge<TEdgeData, TNodeID, TEdgeID, TPortID>>(
187+
changes,
188+
edges,
189+
),
190+
)
191+
},
192+
[edges, setEdges],
193+
)
194+
155195
const updateZoom = React.useMemo(() => debounce(setZoom, 200), [setZoom])
156196

157197
const zoomToCurrentNode = React.useCallback(
@@ -221,6 +261,14 @@ function LineageLayoutBase<
221261
[nodes, edges],
222262
)
223263

264+
React.useEffect(() => {
265+
setNodes(initialNodes)
266+
}, [initialNodes])
267+
268+
React.useEffect(() => {
269+
setEdges(initialEdges)
270+
}, [initialEdges])
271+
224272
React.useEffect(() => {
225273
if (selectedNodeId == null) {
226274
setShowOnlySelectedNodes(false)
@@ -290,8 +338,6 @@ function LineageLayoutBase<
290338
React.useEffect(() => {
291339
if (currentNode?.id) {
292340
setSelectedNodeId(currentNode.id)
293-
} else if (selectedNodeId) {
294-
// setSelectedNodeId(selectedNodeId);
295341
} else {
296342
const node = nodes.length > 0 ? nodes[nodes.length - 1] : null
297343

@@ -332,8 +378,10 @@ function LineageLayoutBase<
332378
edges={edges}
333379
nodeTypes={nodeTypes}
334380
edgeTypes={edgeTypes}
335-
nodesDraggable={false}
336-
nodesConnectable={false}
381+
onNodesChange={onNodesChange}
382+
onEdgesChange={onEdgesChange}
383+
nodesDraggable={nodesDraggable}
384+
nodesConnectable={nodesConnectable}
337385
zoomOnDoubleClick={false}
338386
panOnScroll={true}
339387
zoomOnScroll={true}

web/common/src/components/Lineage/stories/Lineage.stories.tsx

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,33 +17,56 @@ export const LineageModel = () => {
1717
>
1818
<style>{`
1919
:root {
20+
--color-metadata-label: rgba(100, 100, 100, 1);
21+
--color-metadata-value: rgba(10, 10, 10, 1);
2022
21-
--color-lineage-control-button-tooltip-background: rgba(150, 150, 150, 1);
22-
--color-lineage-control-button-tooltip-foreground: rgba(255, 255, 255, 1);
23+
--color-tooltip-background: rgba(150, 150, 150, 1);
24+
--color-tooltip-foreground: rgba(255, 255, 255, 1);
2325
24-
--color-lineage-divider: rgba(0, 0, 0, 0.1);
25-
--color-lineage-background: rgba(255, 255, 255, 1);
26-
--color-lineage-border: rgba(0, 0, 0, 0.1);
26+
--color-filterable-list-counter-background: rgba(200, 0, 0, 1);
27+
--color-filterable-list-counter-foreground: rgba(255, 255, 255, 1);
28+
--color-filterable-list-input-background: rgba(250, 250, 250, 1);
29+
--color-filterable-list-input-foreground: rgba(0, 0, 0, 1);
30+
--color-filterable-list-input-placeholder: rgba(100, 100, 100, 1);
31+
--color-filterable-list-input-border: rgba(100, 100, 100, 1);
2732
2833
--color-lineage-control-background: rgba(250, 250, 250, 1);
2934
--color-lineage-control-background-hover: rgba(245, 245, 245, 1);
3035
--color-lineage-control-icon-background: rgba(0, 0, 0, 1);
3136
--color-lineage-control-icon-foreground: rgba(255, 255, 255, 1);
37+
--color-lineage-control-button-tooltip-background: rgba(150, 150, 150, 1);
38+
--color-lineage-control-button-tooltip-foreground: rgba(255, 255, 255, 1);
3239
33-
--color-lineage-grid-dot: rgba(0, 0, 0, 1);
40+
--color-model-name-grayscale-link-underline: rgba(125, 125, 125, 1);
41+
--color-model-name-grayscale-link-underline-hover: rgba(125, 125, 125, 1);
42+
--color-model-name-link-underline: rgba(0, 0, 0, 1);
43+
--color-model-name-link-underline-hover: rgba(0, 0, 0, 1);
44+
--color-model-name-catalog: rgba(0, 0, 0, 1);
45+
--color-model-name-schema: rgba(0, 0, 0, 1);
46+
--color-model-name-model: rgba(0, 0, 0, 1);
47+
--color-model-name-grayscale-catalog: rgba(100, 100, 100, 1);
48+
--color-model-name-grayscale-schema: rgba(50, 50, 50, 1);
49+
--color-model-name-grayscale-model: rgba(10, 10, 10, 1);
50+
--color-model-name-copy-icon: rgba(100, 100, 100, 1);
51+
--color-model-name-copy-icon-hover: rgba(125, 125, 125, 1);
52+
53+
--color-lineage-background: rgba(255, 255, 255, 1);
54+
--color-lineage-divider: rgba(0, 0, 0, 0.1);
55+
--color-lineage-border: rgba(0, 0, 0, 0.1);
56+
57+
--color-lineage-grid-dot: rgba(0, 0, 0, 0.1);
3458
35-
--color-lineage-node-appendix-background: transparent;
36-
3759
--color-lineage-node-background: rgba(255, 255, 255, 1);
3860
--color-lineage-node-foreground: rgba(0, 0, 0, 0.75);
61+
--color-lineage-node-selected-border: rgba(0, 120, 120, 0.5);
3962
--color-lineage-node-border: rgba(0, 0, 0, 0.1);
4063
--color-lineage-node-border-hover: rgba(0, 0, 0, 0.2);
4164
42-
--color-lineage-node-selected-border: rgba(0, 120, 120, 0.5);
43-
44-
--color-lineage-node-badge-background: rgba(240, 240, 240, 1);
65+
--color-lineage-node-badge-background: rgba(200, 200, 200, 1);
4566
--color-lineage-node-badge-foreground: rgba(0, 0, 0, 1);
4667
68+
--color-lineage-node-appendix-background: transparent;
69+
4770
--color-lineage-node-type-background-sql: rgba(0, 0, 120, 1);
4871
--color-lineage-node-type-foreground-sql: rgba(0, 0, 120, 1);
4972
--color-lineage-node-type-border-sql: rgba(0, 0, 120, 1);
@@ -52,7 +75,18 @@ export const LineageModel = () => {
5275
--color-lineage-node-type-foreground-python: rgba(120, 0, 120, 1);
5376
--color-lineage-node-type-border-python: rgba(120, 0, 120, 1);
5477
78+
--color-lineage-node-type-background-source: rgba(120, 120, 0, 1);
79+
--color-lineage-node-type-foreground-source: rgba(120, 120, 0, 1);
80+
--color-lineage-node-type-border-source: rgba(120, 120, 0, 1);
81+
82+
--color-lineage-node-type-background-cte-subquery: rgba(120, 120, 120, 1);
83+
--color-lineage-node-type-foreground-cte-subquery: rgba(120, 120, 120, 1);
84+
--color-lineage-node-type-border-cte-subquery: rgba(120, 120, 120, 1);
85+
5586
--color-lineage-node-type-handle-icon-background: rgba(255, 255, 255, 1);
87+
--color-lineage-node-type-handle-icon-foreground: rgba(0, 0, 0, 1);
88+
89+
--color-lineage-edge: rgba(0, 0, 0, 0.1);
5690
5791
--color-lineage-node-port-background: rgba(70, 0, 0, 0.05);
5892
--color-lineage-node-port-handle-source: rgba(70, 0, 0, 1);
@@ -61,15 +95,12 @@ export const LineageModel = () => {
6195
--color-lineage-node-port-edge-target: rgba(130, 0, 0, 1);
6296
6397
--color-lineage-model-column-error-background: rgba(255, 0, 0, 1);
64-
--color-lineage-model-column-source-background: rgba(200, 0, 0, 1);
65-
--color-lineage-model-column-expression-background: rgba(100, 0, 0, 1);
98+
--color-lineage-model-column-source-background: rgba(0, 200, 200, 1);
99+
--color-lineage-model-column-expression-background: rgba(0, 10, 100, 1);
66100
--color-lineage-model-column-error-icon: rgba(255, 0, 0, 1);
67101
--color-lineage-model-column-active: rgba(70, 0, 0, 0.1);
68102
--color-lineage-model-column-icon: rgba(0, 0, 0, 1);
69103
--color-lineage-model-column-icon-active: rgba(0, 0, 0, 1);
70-
71-
--color-filterable-list-counter-background: rgba(200, 0, 0, 1);
72-
--color-filterable-list-counter-foreground: rgba(200, 200, 200, 1);
73104
}
74105
`}</style>
75106
<ModelLineage

web/common/src/components/Lineage/stories/ModelLineage.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { debounce } from 'lodash'
2-
import { Focus, Rows2, Rows3 } from 'lucide-react'
2+
import { Focus, LockOpen, Rows2, Rows3, Lock } from 'lucide-react'
33
import React from 'react'
44

55
import { type ColumnLevelLineageAdjacencyList } from '../LineageColumnLevel/ColumnLevelLineageContext'
@@ -74,6 +74,7 @@ export const ModelLineage = ({
7474
}) => {
7575
const [zoom, setZoom] = React.useState(ZOOM_THRESHOLD)
7676
const [isBuildingLayout, setIsBuildingLayout] = React.useState(false)
77+
const [nodesDraggable, setNodesDraggable] = React.useState(false)
7778
const [edges, setEdges] = React.useState<
7879
LineageEdge<EdgeData, ModelNodeId, ModelEdgeId, ModelColumnID>[]
7980
>([])
@@ -388,6 +389,7 @@ export const ModelLineage = ({
388389
nodeTypes={nodeTypes}
389390
edgeTypes={edgeTypes}
390391
className={className}
392+
nodesDraggable={nodesDraggable}
391393
controls={
392394
<>
393395
<LineageControlButton
@@ -408,6 +410,13 @@ export const ModelLineage = ({
408410
>
409411
<LineageControlIcon Icon={Focus} />
410412
</LineageControlButton>
413+
<LineageControlButton
414+
text={nodesDraggable ? 'Lock nodes' : 'Unlock nodes'}
415+
onClick={() => setNodesDraggable(prev => !prev)}
416+
disabled={isBuildingLayout}
417+
>
418+
<LineageControlIcon Icon={nodesDraggable ? Lock : LockOpen} />
419+
</LineageControlButton>
411420
</>
412421
}
413422
/>

0 commit comments

Comments
 (0)