Skip to content

Commit f441d8a

Browse files
committed
some pr comments
1 parent aab6a8e commit f441d8a

File tree

9 files changed

+291
-395
lines changed

9 files changed

+291
-395
lines changed

pnpm-lock.yaml

Lines changed: 72 additions & 208 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vscode/bus/src/brand.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,26 @@ type Brand<B> = { [__brand]: B }
1717
* userId == userName -> compile error
1818
*/
1919
export type Branded<T, B> = T & Brand<B>
20+
21+
/**
22+
* Constraint that only accepts branded string types
23+
*/
24+
export type BrandedString = string & Brand<string>
25+
26+
/**
27+
* BrandedRecord is a type that creates a branded Record type with strict key checking.
28+
* This ensures that Record<BrandedKey1, V> is NOT assignable to Record<BrandedKey2, V>
29+
*
30+
* @example
31+
* type ModelFQN = Branded<string, 'ModelFQN'>
32+
* type ModelName = Branded<string, 'ModelName'>
33+
*
34+
* type FQNMap = BrandedRecord<ModelFQN, string>
35+
* type NameMap = BrandedRecord<ModelName, string>
36+
*
37+
* const fqnMap: FQNMap = {}
38+
* const nameMap: NameMap = fqnMap // TypeScript error!
39+
*/
40+
export type BrandedRecord<K extends BrandedString, V> = Record<K, V> & {
41+
readonly __recordKeyBrand: K
42+
}

vscode/react/package.json

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,15 @@
1919
"@heroicons/react": "^2.2.0",
2020
"@radix-ui/react-select": "^2.2.5",
2121
"@tanstack/react-query": "^5.83.0",
22-
"@tanstack/react-router": "^1.129.8",
22+
"@tanstack/react-router": "^1.131.26",
2323
"@tanstack/react-router-devtools": "^1.131.26",
2424
"@tanstack/react-virtual": "^3.13.12",
25-
"@tanstack/router-plugin": "^1.129.8",
25+
"@tanstack/router-plugin": "^1.131.26",
2626
"@tobikodata/sqlmesh-common": "file:../../web/common",
2727
"apache-arrow": "^19.0.1",
2828
"clsx": "^2.1.1",
2929
"cronstrue": "3.3.0",
3030
"elkjs": "^0.8.2",
31-
"lodash": "4.17.21",
3231
"lucide-react": "0.542.0",
3332
"orval": "^7.10.0",
3433
"react": "^18.3.1",
@@ -47,12 +46,11 @@
4746
"@storybook/react-vite": "^9.0.18",
4847
"@testing-library/dom": "^10.4.1",
4948
"@testing-library/react": "^16.3.0",
50-
"@types/lodash": "4.17.20",
5149
"@types/react": "^18.3.23",
5250
"@types/react-dom": "^18.3.7",
5351
"@vitejs/plugin-react": "^4.7.0",
54-
"@vitest/browser": "3.2.3",
55-
"@vitest/coverage-v8": "3.2.3",
52+
"@vitest/browser": "3.2.4",
53+
"@vitest/coverage-v8": "3.2.4",
5654
"jsdom": "^26.1.0",
5755
"playwright": "^1.54.1",
5856
"storybook": "^9.0.18",

vscode/react/src/pages/ModelLineage.tsx

Lines changed: 44 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
import React from 'react'
22

3-
import { debounce } from 'lodash'
43
import { Focus, Rows2, Rows3 } from 'lucide-react'
54
import {
65
FactoryEdgeWithGradient,
76
EdgeWithGradient,
8-
type LineageAdjacencyList,
9-
type LineageDetails,
107
ZOOM_THRESHOLD,
118
type LineageEdge,
129
type LineageNodesMap,
@@ -34,20 +31,21 @@ import {
3431
} from '@tobikodata/sqlmesh-common/lineage'
3532

3633
import {
34+
type BrandedLineageAdjacencyList,
35+
type BrandedLineageDetails,
3736
type ColumnName,
3837
type EdgeData,
3938
type ModelColumnID,
4039
type ModelEdgeId,
4140
type ModelLineageNodeDetails,
4241
type ModelNodeId,
4342
type NodeData,
44-
type NodeType,
4543
ModelLineageContext,
4644
} from './ModelLineageContext'
4745
import { ModelNode } from './ModelNode'
4846
import { useModelLineage } from './ModelLineageContext'
49-
import type { ModelName } from '@/domain/models'
50-
import { getNodeTypeColorVar } from './help'
47+
import type { ModelFQN } from '@/domain/models'
48+
import { NODE_TYPE_COLOR_VAR } from './help'
5149

5250
const nodeTypes = {
5351
node: ModelNode,
@@ -64,9 +62,9 @@ export const ModelLineage = ({
6462
className,
6563
onNodeClick,
6664
}: {
67-
adjacencyList: LineageAdjacencyList<ModelName>
68-
lineageDetails: LineageDetails<ModelName, ModelLineageNodeDetails>
69-
selectedModelName?: ModelName
65+
adjacencyList: BrandedLineageAdjacencyList<ModelFQN>
66+
lineageDetails: BrandedLineageDetails<ModelFQN, ModelLineageNodeDetails>
67+
selectedModelName?: ModelFQN
7068
className?: string
7169
onNodeClick?: (
7270
event: React.MouseEvent<Element, MouseEvent>,
@@ -98,7 +96,7 @@ export const ModelLineage = ({
9896

9997
const [showColumns, setShowColumns] = React.useState(false)
10098
const [columnLevelLineage, setColumnLevelLineage] = React.useState<
101-
Map<ModelColumnID, ColumnLevelLineageAdjacencyList<ModelName, ColumnName>>
99+
Map<ModelColumnID, ColumnLevelLineageAdjacencyList<ModelFQN, ColumnName>>
102100
>(new Map())
103101
const [fetchingColumns, setFetchingColumns] = React.useState<
104102
Set<ModelColumnID>
@@ -108,17 +106,17 @@ export const ModelLineage = ({
108106
adjacencyListColumnLevel,
109107
selectedColumns,
110108
adjacencyListKeysColumnLevel,
111-
} = useColumnLevelLineage<ModelName, ColumnName, ModelColumnID>(
109+
} = useColumnLevelLineage<ModelFQN, ColumnName, ModelColumnID>(
112110
columnLevelLineage,
113111
)
114112

115113
const adjacencyListKeys = React.useMemo(() => {
116-
let keys: ModelName[] = []
114+
let keys: ModelFQN[] = []
117115

118116
if (adjacencyListKeysColumnLevel.length > 0) {
119117
keys = adjacencyListKeysColumnLevel
120118
} else {
121-
keys = Object.keys(adjacencyList) as ModelName[]
119+
keys = Object.keys(adjacencyList) as ModelFQN[]
122120
}
123121

124122
return keys
@@ -131,7 +129,7 @@ export const ModelLineage = ({
131129
const node = createNode('node', nodeId, {
132130
name: detail.name,
133131
displayName: detail.display_name,
134-
model_type: detail.model_type as NodeType,
132+
model_type: detail.model_type,
135133
identifier: detail.identifier,
136134
kind: detail.kind,
137135
cron: detail.cron,
@@ -177,7 +175,7 @@ export const ModelLineage = ({
177175

178176
const transformedNodesMap = React.useMemo(() => {
179177
return getTransformedNodes<
180-
ModelName,
178+
ModelFQN,
181179
ModelLineageNodeDetails,
182180
NodeData,
183181
ModelNodeId
@@ -201,19 +199,15 @@ export const ModelLineage = ({
201199
data.startColor = 'var(--color-lineage-node-port-edge-source)'
202200
} else {
203201
if (sourceNode?.data?.model_type) {
204-
data.startColor = getNodeTypeColorVar(
205-
sourceNode.data.model_type as NodeType,
206-
)
202+
data.startColor = NODE_TYPE_COLOR_VAR[sourceNode.data.model_type]
207203
}
208204
}
209205

210206
if (targetHandleId) {
211207
data.endColor = 'var(--color-lineage-node-port-edge-target)'
212208
} else {
213209
if (targetNode?.data?.model_type) {
214-
data.endColor = getNodeTypeColorVar(
215-
targetNode.data.model_type as NodeType,
216-
)
210+
data.endColor = NODE_TYPE_COLOR_VAR[targetNode.data.model_type]
217211
}
218212
}
219213

@@ -237,7 +231,7 @@ export const ModelLineage = ({
237231
const edgesColumnLevel = React.useMemo(
238232
() =>
239233
getEdgesFromColumnLineage<
240-
ModelName,
234+
ModelFQN,
241235
ColumnName,
242236
EdgeData,
243237
ModelEdgeId,
@@ -254,34 +248,32 @@ export const ModelLineage = ({
254248
return edgesColumnLevel.length > 0
255249
? edgesColumnLevel
256250
: getTransformedModelEdgesTargetSources<
257-
ModelName,
251+
ModelFQN,
258252
EdgeData,
259253
ModelNodeId,
260254
ModelEdgeId,
261255
ModelColumnID
262256
>(adjacencyListKeys, adjacencyList, transformEdge)
263257
}, [adjacencyListKeys, adjacencyList, transformEdge, edgesColumnLevel])
264258

265-
const calculateLayout = React.useMemo(() => {
266-
return debounce(
267-
(
268-
eds: LineageEdge<EdgeData, ModelNodeId, ModelEdgeId, ModelColumnID>[],
269-
nds: LineageNodesMap<NodeData>,
270-
) => {
271-
const { edges, nodesMap } = buildLayout<
272-
NodeData,
273-
EdgeData,
274-
ModelNodeId,
275-
ModelEdgeId,
276-
ModelColumnID
277-
>({ edges: eds, nodesMap: nds })
278-
setEdges(edges)
279-
setNodesMap(nodesMap)
280-
setIsBuildingLayout(false)
281-
},
282-
200,
283-
)
284-
}, [])
259+
const calculateLayout = React.useCallback(
260+
(
261+
eds: LineageEdge<EdgeData, ModelNodeId, ModelEdgeId, ModelColumnID>[],
262+
nds: LineageNodesMap<NodeData>,
263+
) => {
264+
const { edges, nodesMap } = buildLayout<
265+
NodeData,
266+
EdgeData,
267+
ModelNodeId,
268+
ModelEdgeId,
269+
ModelColumnID
270+
>({ edges: eds, nodesMap: nds })
271+
setEdges(edges)
272+
setNodesMap(nodesMap)
273+
setIsBuildingLayout(false)
274+
},
275+
[edges, nodesMap, setEdges, setNodesMap, setIsBuildingLayout],
276+
)
285277

286278
const nodes = React.useMemo(() => {
287279
return Object.values(nodesMap)
@@ -317,27 +309,25 @@ export const ModelLineage = ({
317309
} else {
318310
calculateLayout(transformedEdges, transformedNodesMap)
319311
}
320-
}, [
321-
calculateLayout,
322-
showOnlySelectedNodes,
323-
transformedEdges,
324-
transformedNodesMap,
325-
])
312+
}, [showOnlySelectedNodes, transformedEdges, transformedNodesMap])
326313

314+
// currentNodeId is passed from the parent component
315+
// we it change we need to reset the selectedNodeId
327316
React.useEffect(() => {
328317
if (currentNodeId) {
329318
setSelectedNodeId(currentNodeId)
330319
}
331320
}, [currentNodeId])
332321

322+
// When the selectedColumns is empty it measn we dont have any selected columns
323+
// so we need to set the selectedNodeId back to the currentNode.id
324+
// where currentNode derived from currentNodeId if present in nodesMap
325+
// if the currentNode is null we need to set the selectedNodeId to null
333326
React.useEffect(() => {
334-
if (
335-
(selectedColumns.size === 0 && currentNode?.id !== selectedNodeId) ||
336-
selectedNodeId == null
337-
) {
327+
if (selectedColumns.size === 0 && selectedNodeId != currentNode?.id) {
338328
setSelectedNodeId(currentNode?.id || null)
339329
}
340-
}, [selectedColumns, currentNode?.id, selectedNodeId])
330+
}, [selectedColumns, currentNode?.id])
341331

342332
function toggleColumns() {
343333
setShowColumns(prev => !prev)

vscode/react/src/pages/ModelLineageContext.ts

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,52 @@
1-
import type { ModelName } from '@/domain/models'
2-
import type { Branded } from '@tobikodata/sqlmesh-common'
1+
import type { ModelType } from '@/api/client'
2+
import type { ModelFQN, ModelName } from '@/domain/models'
3+
import type { Branded, BrandedString } from '@bus/brand'
34
import {
45
type Column,
5-
type ColumnLevelLineageAdjacencyList,
66
type ColumnLevelLineageContextValue,
77
type LineageContextValue,
88
type PathType,
99
getInitial as getLineageContextInitial,
1010
getColumnLevelLineageContextInitial,
1111
createLineageContext,
12+
type LineageAdjacencyList,
13+
type LineageDetails,
14+
type ColumnLevelLineageAdjacencyList,
1215
} from '@tobikodata/sqlmesh-common/lineage'
1316

17+
export type BrandedLineageAdjacencyList<K extends BrandedString> =
18+
LineageAdjacencyList<K> & {
19+
readonly __adjacencyListKeyBrand: K
20+
}
21+
22+
export type BrandedLineageDetails<K extends BrandedString, V> = LineageDetails<
23+
K,
24+
V
25+
> & {
26+
readonly __lineageDetailsKeyBrand: K
27+
}
28+
29+
export type BrandedColumnLevelLineageAdjacencyList<
30+
K extends BrandedString,
31+
V extends BrandedString,
32+
> = ColumnLevelLineageAdjacencyList<K, V> & {
33+
readonly __columnLevelLineageAdjacencyListKeyBrand: K
34+
readonly __columnLevelLineageAdjacencyListColumnKeyBrand: V
35+
}
36+
1437
export type ColumnName = Branded<string, 'ColumnName'>
1538
export type ModelColumnID = Branded<string, 'ModelColumnID'>
1639
export type ModelNodeId = Branded<string, 'ModelNodeId'>
1740
export type ModelEdgeId = Branded<string, 'ModelEdgeId'>
1841
export type ModelColumn = Column & {
1942
id: ModelColumnID
2043
name: ColumnName
21-
columnLineageData?: ColumnLevelLineageAdjacencyList<ModelName, ColumnName>
2244
}
2345

24-
export type NodeType = 'sql' | 'python'
2546
export type ModelLineageNodeDetails = {
26-
name: ModelName
27-
display_name: string
28-
model_type: string
47+
name: ModelFQN
48+
display_name: ModelName
49+
model_type: ModelType
2950
identifier?: string | null
3051
version?: string | null
3152
dialect?: string | null
@@ -37,9 +58,9 @@ export type ModelLineageNodeDetails = {
3758
}
3859

3960
export type NodeData = {
40-
name: ModelName
41-
displayName: string
42-
model_type: NodeType
61+
name: ModelFQN
62+
displayName: ModelName
63+
model_type: ModelType
4364
identifier?: string | null
4465
version?: string | null
4566
kind?: string | null
@@ -58,7 +79,7 @@ export type EdgeData = {
5879
}
5980

6081
export type ModelLineageContextValue = ColumnLevelLineageContextValue<
61-
ModelName,
82+
ModelFQN,
6283
ColumnName,
6384
ModelColumnID
6485
> &
@@ -72,11 +93,7 @@ export type ModelLineageContextValue = ColumnLevelLineageContextValue<
7293

7394
export const initial = {
7495
...getLineageContextInitial<ModelNodeId, ModelEdgeId>(),
75-
...getColumnLevelLineageContextInitial<
76-
ModelName,
77-
ColumnName,
78-
ModelColumnID
79-
>(),
96+
...getColumnLevelLineageContextInitial<ModelFQN, ColumnName, ModelColumnID>(),
8097
}
8198

8299
export const { Provider, useLineage } = createLineageContext<

0 commit comments

Comments
 (0)