@aloudata/ink-lineage 0.0.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +27 -0
- package/src/assets/big/dataSourceTypeIcon.ts +65 -0
- package/src/assets/big/entityType.ts +1 -0
- package/src/assets/big/index.ts +5 -0
- package/src/assets/big/lineageIcon.ts +35 -0
- package/src/assets/big/tableTypeIcon.ts +17 -0
- package/src/assets/big/tipIcon.ts +1 -0
- package/src/assets/index.ts +14 -0
- package/src/components/Edges/DefaultEdge.ts +196 -0
- package/src/components/Edges/FoldEdge.ts +97 -0
- package/src/components/Edges/LineageEdge.ts +24 -0
- package/src/components/Edges/index.ts +3 -0
- package/src/components/Nodes/AssetNode.ts +438 -0
- package/src/components/Nodes/ColumnNode.ts +491 -0
- package/src/components/Nodes/CustomNode.ts +63 -0
- package/src/components/Nodes/DefaultNode.ts +74 -0
- package/src/components/Nodes/DowngradeNode.ts +115 -0
- package/src/components/Nodes/TableNode.ts +534 -0
- package/src/components/Nodes/index.ts +4 -0
- package/src/components/index.ts +2 -0
- package/src/constant/index.ts +1 -0
- package/src/constant/nodeStyle.ts +141 -0
- package/src/index.ts +6 -0
- package/src/manager/BaseManager.ts +20 -0
- package/src/manager/DataProcessor.ts +782 -0
- package/src/manager/ExpandManager.ts +93 -0
- package/src/manager/FoldLineageManager.ts +196 -0
- package/src/manager/GraphEventManager.ts +90 -0
- package/src/manager/LineageManager.ts +680 -0
- package/src/manager/RightKeyMenuManager.ts +114 -0
- package/src/manager/SearchNodeManager.ts +188 -0
- package/src/manager/ToolbarManager.ts +42 -0
- package/src/manager/index.ts +8 -0
- package/src/manager/nodeManager/AssetEventManager.ts +442 -0
- package/src/manager/nodeManager/BaseEventManager.ts +68 -0
- package/src/manager/nodeManager/ColumnEventManager.ts +467 -0
- package/src/manager/nodeManager/CustomEventManager.ts +11 -0
- package/src/manager/nodeManager/TableEventManager.ts +87 -0
- package/src/manager/nodeManager/index.ts +3 -0
- package/src/types/NodeConfig.ts +69 -0
- package/src/types/eventEnum.ts +58 -0
- package/src/types/index.ts +3 -0
- package/src/types/manager.ts +75 -0
- package/src/types/node.ts +246 -0
- package/src/utils/downgradeNode.ts +22 -0
- package/src/utils/foldNode.ts +345 -0
- package/src/utils/getIconByType.ts +104 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/node.ts +294 -0
- package/tsconfig.json +30 -0
|
@@ -0,0 +1,782 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getNodeHeight,
|
|
3
|
+
groupNodesByEdgesAndDirection,
|
|
4
|
+
} from '@aloudata/ink-graph-new';
|
|
5
|
+
import {
|
|
6
|
+
EEntityType,
|
|
7
|
+
EDirection,
|
|
8
|
+
IEntity,
|
|
9
|
+
IBseRelation,
|
|
10
|
+
INodeConfig,
|
|
11
|
+
IColumnConfig,
|
|
12
|
+
IEdgeConfig,
|
|
13
|
+
ILineageData,
|
|
14
|
+
IColResBase,
|
|
15
|
+
TDataBase,
|
|
16
|
+
EDashType,
|
|
17
|
+
} from '../types';
|
|
18
|
+
import _ from 'lodash';
|
|
19
|
+
import { BaseManager } from './BaseManager';
|
|
20
|
+
import {
|
|
21
|
+
COL_HEIGHT,
|
|
22
|
+
CUSTOM_NODE,
|
|
23
|
+
LINEAGE_EDGE,
|
|
24
|
+
NODE_WIDTH,
|
|
25
|
+
TABLE_HEADER_HEIGHT,
|
|
26
|
+
TABLE_NODE,
|
|
27
|
+
} from '../constant';
|
|
28
|
+
import { InkLineageManager } from './LineageManager';
|
|
29
|
+
|
|
30
|
+
export interface IParsedGraphData<
|
|
31
|
+
TData extends TDataBase<TColumn>,
|
|
32
|
+
TColumn extends IColResBase
|
|
33
|
+
> {
|
|
34
|
+
nodes: INodeConfig<TData, TColumn>[];
|
|
35
|
+
edges: IEdgeConfig[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class DataProcessor<
|
|
39
|
+
TData extends TDataBase<TColumn>,
|
|
40
|
+
TColumn extends IColResBase
|
|
41
|
+
> extends BaseManager<TData, TColumn> {
|
|
42
|
+
static startNodes: string[] = [];
|
|
43
|
+
|
|
44
|
+
constructor(lineageManager: InkLineageManager<TData, TColumn>) {
|
|
45
|
+
super(lineageManager);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static parseData<
|
|
49
|
+
TData extends TDataBase<TColumn>,
|
|
50
|
+
TColumn extends IColResBase,
|
|
51
|
+
>(
|
|
52
|
+
data: ILineageData<TData, TColumn>,
|
|
53
|
+
startNodes: string[],
|
|
54
|
+
): IParsedGraphData<TData, TColumn> {
|
|
55
|
+
DataProcessor.startNodes = startNodes;
|
|
56
|
+
// parse data here
|
|
57
|
+
const { entities, relations } = data;
|
|
58
|
+
const nodes = DataProcessor.parseEntities<TData, TColumn>(
|
|
59
|
+
entities,
|
|
60
|
+
startNodes,
|
|
61
|
+
);
|
|
62
|
+
const edges = DataProcessor.parseRelations(relations);
|
|
63
|
+
|
|
64
|
+
const res = {
|
|
65
|
+
nodes,
|
|
66
|
+
edges,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
return res;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
static parseEntities<
|
|
73
|
+
TData extends TDataBase<TColumn>,
|
|
74
|
+
TColumn extends IColResBase,
|
|
75
|
+
>(entities: IEntity<TData>[], startNodes: string[]) {
|
|
76
|
+
const nodesId: string[] = [];
|
|
77
|
+
const nodes: INodeConfig<TData, TColumn>[] = [];
|
|
78
|
+
|
|
79
|
+
entities.forEach((entity) => {
|
|
80
|
+
if (nodesId.includes(entity.guid)) return;
|
|
81
|
+
|
|
82
|
+
const isStartNode = startNodes.includes(entity.guid);
|
|
83
|
+
let node = null;
|
|
84
|
+
|
|
85
|
+
switch (entity.typeCode) {
|
|
86
|
+
case 'Table':
|
|
87
|
+
case 'View':
|
|
88
|
+
node = DataProcessor.parseTableEntity<TData, TColumn>(
|
|
89
|
+
entity,
|
|
90
|
+
isStartNode,
|
|
91
|
+
);
|
|
92
|
+
break;
|
|
93
|
+
default:
|
|
94
|
+
node = DataProcessor.parseCustomEntity<TData, TColumn>(
|
|
95
|
+
entity,
|
|
96
|
+
isStartNode,
|
|
97
|
+
);
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (node) {
|
|
102
|
+
nodes.push(node);
|
|
103
|
+
nodesId.push(node.id);
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
return nodes;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
static parseRelations(relations: IBseRelation[]) {
|
|
111
|
+
const existedEdgesMap = new Map<string, string>();
|
|
112
|
+
const edges: IEdgeConfig[] = [];
|
|
113
|
+
|
|
114
|
+
relations.forEach((relation) => {
|
|
115
|
+
const edgeId = `${relation.srcGuid}___${relation.dstGuid}`;
|
|
116
|
+
|
|
117
|
+
if (existedEdgesMap.has(edgeId)) {
|
|
118
|
+
if (existedEdgesMap.get(edgeId) !== relation.relationTypeCode) {
|
|
119
|
+
const edge = edges.find((e) => e.id === edgeId);
|
|
120
|
+
if (edge) {
|
|
121
|
+
edge.relationType = EDashType.ALL;
|
|
122
|
+
edge.style.strokeDasharray = [0];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const isIndirect = relation.relationTypeCode.includes('Indirect');
|
|
130
|
+
|
|
131
|
+
const edge = {
|
|
132
|
+
id: edgeId,
|
|
133
|
+
type: LINEAGE_EDGE,
|
|
134
|
+
data: {
|
|
135
|
+
...relation,
|
|
136
|
+
},
|
|
137
|
+
source: relation.srcGuid,
|
|
138
|
+
target: relation.dstGuid,
|
|
139
|
+
visible: true,
|
|
140
|
+
isActive: false,
|
|
141
|
+
isFolded: false,
|
|
142
|
+
canBeFold: false,
|
|
143
|
+
relationType: isIndirect ? EDashType.INDIRECT : EDashType.DIRECT,
|
|
144
|
+
style: {
|
|
145
|
+
stroke: '#B1B1B1',
|
|
146
|
+
strokeDasharray: isIndirect ? [2] : [0],
|
|
147
|
+
lineWidth: 1,
|
|
148
|
+
},
|
|
149
|
+
points: [],
|
|
150
|
+
} as IEdgeConfig;
|
|
151
|
+
|
|
152
|
+
edges.push(edge);
|
|
153
|
+
existedEdgesMap.set(edge.id, edge.data.relationTypeCode);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
return edges;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
static parseTableEntity<
|
|
160
|
+
TData extends TDataBase<TColumn>,
|
|
161
|
+
TColumn extends IColResBase
|
|
162
|
+
>(entity: IEntity<TData>, isStartNode: boolean) {
|
|
163
|
+
const cols = Array.isArray(entity.properties?.columns)
|
|
164
|
+
? entity.properties?.columns?.map((col) => {
|
|
165
|
+
return DataProcessor.parseColumn<TColumn>(
|
|
166
|
+
col,
|
|
167
|
+
isStartNode,
|
|
168
|
+
entity.guid,
|
|
169
|
+
entity.properties?.name,
|
|
170
|
+
);
|
|
171
|
+
}) || []
|
|
172
|
+
: [];
|
|
173
|
+
|
|
174
|
+
// 只有起始资产的relatedCols一开始有元素
|
|
175
|
+
const relatedCols = Array.isArray(entity.properties?.columns)
|
|
176
|
+
? entity.properties?.columns?.map((col) => {
|
|
177
|
+
return DataProcessor.parseRelatedColumn<TColumn>(
|
|
178
|
+
col,
|
|
179
|
+
isStartNode,
|
|
180
|
+
entity.guid,
|
|
181
|
+
entity.properties?.name,
|
|
182
|
+
);
|
|
183
|
+
}) || []
|
|
184
|
+
: [];
|
|
185
|
+
|
|
186
|
+
const data = {
|
|
187
|
+
id: entity.guid,
|
|
188
|
+
type: TABLE_NODE,
|
|
189
|
+
data: {
|
|
190
|
+
...entity.properties,
|
|
191
|
+
type: (entity.properties?.type as EEntityType) || EEntityType.TABLE,
|
|
192
|
+
guid: entity.guid,
|
|
193
|
+
typeCode: entity.typeCode,
|
|
194
|
+
},
|
|
195
|
+
style: {
|
|
196
|
+
width: NODE_WIDTH + 2,
|
|
197
|
+
height: TABLE_HEADER_HEIGHT,
|
|
198
|
+
headerHeight: TABLE_HEADER_HEIGHT,
|
|
199
|
+
},
|
|
200
|
+
position: {
|
|
201
|
+
x: 0,
|
|
202
|
+
y: 0,
|
|
203
|
+
},
|
|
204
|
+
isStartNode,
|
|
205
|
+
isOpen: isStartNode,
|
|
206
|
+
visible: true,
|
|
207
|
+
isRelated: false,
|
|
208
|
+
isFolded: false,
|
|
209
|
+
isExpandOutput: false,
|
|
210
|
+
isExpandInput: false,
|
|
211
|
+
canExpandInput: false,
|
|
212
|
+
canExpandOutput: false,
|
|
213
|
+
canFoldInput: false,
|
|
214
|
+
canFoldOutput: false,
|
|
215
|
+
hasMoreInput: true,
|
|
216
|
+
hasMoreOutput: true,
|
|
217
|
+
children: cols,
|
|
218
|
+
pagination: {
|
|
219
|
+
pageNum: 1,
|
|
220
|
+
pageSize: 10,
|
|
221
|
+
total: 0,
|
|
222
|
+
totalPage: 0,
|
|
223
|
+
},
|
|
224
|
+
relatedColumns: relatedCols,
|
|
225
|
+
} as unknown as INodeConfig<TData, TColumn>;
|
|
226
|
+
|
|
227
|
+
data.style.height = getNodeHeight(data);
|
|
228
|
+
|
|
229
|
+
return data;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
static parseColumn<TColumn extends IColResBase>(
|
|
233
|
+
column: TColumn,
|
|
234
|
+
isStartNode: boolean,
|
|
235
|
+
tableId: string,
|
|
236
|
+
tableName: string,
|
|
237
|
+
) {
|
|
238
|
+
return {
|
|
239
|
+
data: {
|
|
240
|
+
...column,
|
|
241
|
+
},
|
|
242
|
+
type: '',
|
|
243
|
+
style: {
|
|
244
|
+
width: NODE_WIDTH + 2,
|
|
245
|
+
height: COL_HEIGHT,
|
|
246
|
+
headerHeight: COL_HEIGHT,
|
|
247
|
+
},
|
|
248
|
+
position: { x: 8, y: 0 },
|
|
249
|
+
id: column.guid,
|
|
250
|
+
tableId,
|
|
251
|
+
tableName: column.tableName || tableName,
|
|
252
|
+
visible: true,
|
|
253
|
+
isFolded: false,
|
|
254
|
+
isStartNode,
|
|
255
|
+
isRelated: false,
|
|
256
|
+
canExpandInput: false,
|
|
257
|
+
canExpandOutput: false,
|
|
258
|
+
canFoldInput: false,
|
|
259
|
+
canFoldOutput: false,
|
|
260
|
+
hasMoreInput: true,
|
|
261
|
+
hasMoreOutput: true,
|
|
262
|
+
} as IColumnConfig<TColumn>;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
static parseRelatedColumn<TColumn extends IColResBase>(
|
|
266
|
+
column: TColumn,
|
|
267
|
+
isStartNode: boolean,
|
|
268
|
+
tableId: string,
|
|
269
|
+
tableName: string,
|
|
270
|
+
) {
|
|
271
|
+
return {
|
|
272
|
+
data: {
|
|
273
|
+
...column,
|
|
274
|
+
},
|
|
275
|
+
type: '',
|
|
276
|
+
style: {
|
|
277
|
+
width: NODE_WIDTH + 2,
|
|
278
|
+
height: COL_HEIGHT,
|
|
279
|
+
headerHeight: COL_HEIGHT,
|
|
280
|
+
},
|
|
281
|
+
position: { x: 0, y: 0 },
|
|
282
|
+
id: column.guid,
|
|
283
|
+
tableId,
|
|
284
|
+
tableName: column.tableName || tableName,
|
|
285
|
+
visible: true,
|
|
286
|
+
isFolded: false,
|
|
287
|
+
isStartNode,
|
|
288
|
+
isRelated: true,
|
|
289
|
+
isRelatedColumn: true,
|
|
290
|
+
canExpandInput: false,
|
|
291
|
+
canExpandOutput: false,
|
|
292
|
+
canFoldInput: false,
|
|
293
|
+
canFoldOutput: false,
|
|
294
|
+
hasMoreInput: true,
|
|
295
|
+
hasMoreOutput: true,
|
|
296
|
+
} as IColumnConfig<TColumn>;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
static parseCustomEntity<
|
|
300
|
+
TData extends TDataBase<TColumn>,
|
|
301
|
+
TColumn extends IColResBase
|
|
302
|
+
>(entity: IEntity<TData>, isStartNode: boolean) {
|
|
303
|
+
const data = {
|
|
304
|
+
id: entity.guid,
|
|
305
|
+
type: CUSTOM_NODE,
|
|
306
|
+
data: {
|
|
307
|
+
...entity.properties,
|
|
308
|
+
type: (entity.properties?.type as EEntityType) || EEntityType.TABLE,
|
|
309
|
+
guid: entity.guid,
|
|
310
|
+
typeCode: entity.typeCode,
|
|
311
|
+
typeCodeName: entity.typeCodeName,
|
|
312
|
+
},
|
|
313
|
+
style: {
|
|
314
|
+
width: NODE_WIDTH + 2,
|
|
315
|
+
height: TABLE_HEADER_HEIGHT,
|
|
316
|
+
headerHeight: TABLE_HEADER_HEIGHT,
|
|
317
|
+
},
|
|
318
|
+
position: {
|
|
319
|
+
x: 0,
|
|
320
|
+
y: 0,
|
|
321
|
+
},
|
|
322
|
+
isStartNode,
|
|
323
|
+
isOpen: isStartNode,
|
|
324
|
+
visible: true,
|
|
325
|
+
isRelated: false,
|
|
326
|
+
canExpandInput: false,
|
|
327
|
+
canExpandOutput: false,
|
|
328
|
+
canFoldInput: false,
|
|
329
|
+
canFoldOutput: false,
|
|
330
|
+
hasMoreInput: true,
|
|
331
|
+
hasMoreOutput: true,
|
|
332
|
+
children: Array.isArray(entity.properties?.columns)
|
|
333
|
+
? entity.properties?.columns?.map((col) => {
|
|
334
|
+
return DataProcessor.parseColumn<TColumn>(
|
|
335
|
+
col,
|
|
336
|
+
isStartNode,
|
|
337
|
+
entity.guid,
|
|
338
|
+
entity.properties?.name,
|
|
339
|
+
);
|
|
340
|
+
}) || []
|
|
341
|
+
: [],
|
|
342
|
+
pagination: {
|
|
343
|
+
pageNum: 1,
|
|
344
|
+
pageSize: 10,
|
|
345
|
+
total: 0,
|
|
346
|
+
totalPage: 0,
|
|
347
|
+
},
|
|
348
|
+
relatedColumns: [],
|
|
349
|
+
} as unknown as INodeConfig<TData, TColumn>;
|
|
350
|
+
|
|
351
|
+
data.style.height = getNodeHeight(data);
|
|
352
|
+
|
|
353
|
+
return data;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
updateSideIconVisible(
|
|
357
|
+
data: IParsedGraphData<TData, TColumn>,
|
|
358
|
+
) {
|
|
359
|
+
if (_.isNil(data)) return;
|
|
360
|
+
|
|
361
|
+
const nodesConfig = data.nodes.filter((cfg) => cfg.visible);
|
|
362
|
+
const edgesConfig = data.edges.filter((cfg) => cfg.visible);
|
|
363
|
+
if (!nodesConfig) return;
|
|
364
|
+
|
|
365
|
+
const startNodeIndex = nodesConfig.findIndex((node) => node.isStartNode);
|
|
366
|
+
if (startNodeIndex < 0) return;
|
|
367
|
+
|
|
368
|
+
const startNodeCfg = nodesConfig[startNodeIndex];
|
|
369
|
+
if (!startNodeCfg) return;
|
|
370
|
+
|
|
371
|
+
const nodesConfigMap = new Map<
|
|
372
|
+
string,
|
|
373
|
+
INodeConfig<TData, TColumn> | IColumnConfig<TColumn>
|
|
374
|
+
>();
|
|
375
|
+
nodesConfig?.forEach((n) => {
|
|
376
|
+
nodesConfigMap.set(n.id, n);
|
|
377
|
+
n.children?.forEach((child) => {
|
|
378
|
+
nodesConfigMap.set(child.id, child);
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
const inputGroupedData = groupNodesByEdgesAndDirection(
|
|
383
|
+
startNodeCfg,
|
|
384
|
+
nodesConfigMap,
|
|
385
|
+
edgesConfig,
|
|
386
|
+
EDirection.INPUT,
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
const outputGroupedData = groupNodesByEdgesAndDirection(
|
|
390
|
+
startNodeCfg,
|
|
391
|
+
nodesConfigMap,
|
|
392
|
+
edgesConfig,
|
|
393
|
+
EDirection.OUTPUT,
|
|
394
|
+
);
|
|
395
|
+
|
|
396
|
+
if (!inputGroupedData && !outputGroupedData) return;
|
|
397
|
+
|
|
398
|
+
const { groupedNodes: inputGroupNodes } = inputGroupedData;
|
|
399
|
+
const { groupedNodes: outputGroupNodes } = outputGroupedData;
|
|
400
|
+
// 两个map合并
|
|
401
|
+
const groupedNodes = new Map();
|
|
402
|
+
if (inputGroupNodes) {
|
|
403
|
+
for (const [key, value] of inputGroupNodes) {
|
|
404
|
+
if (groupedNodes.has(key)) continue;
|
|
405
|
+
groupedNodes.set(key, value);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
if (outputGroupNodes) {
|
|
410
|
+
for (const [key, value] of outputGroupNodes) {
|
|
411
|
+
if (groupedNodes.has(key)) continue;
|
|
412
|
+
groupedNodes.set(key, value);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const dstNodeIds = edgesConfig.map((edge) => edge.target);
|
|
417
|
+
const srcNodeIds = edgesConfig.map((edge) => edge.source);
|
|
418
|
+
|
|
419
|
+
// table
|
|
420
|
+
nodesConfig?.forEach((n) => {
|
|
421
|
+
n.canExpandInput = false;
|
|
422
|
+
n.canExpandOutput = false;
|
|
423
|
+
n.canFoldInput = false;
|
|
424
|
+
n.canFoldOutput = false;
|
|
425
|
+
|
|
426
|
+
const currNodeLevel = groupedNodes.get(n.id);
|
|
427
|
+
|
|
428
|
+
if (_.isNil(currNodeLevel)) {
|
|
429
|
+
console.warn(`get node level error '${n.id}'`);
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
let isInputLeaf = false;
|
|
434
|
+
let isOutputLeaf = false;
|
|
435
|
+
if (currNodeLevel === 0) {
|
|
436
|
+
isInputLeaf = !dstNodeIds.includes(n.id);
|
|
437
|
+
isOutputLeaf = !srcNodeIds.includes(n.id);
|
|
438
|
+
} else if (currNodeLevel < 0) {
|
|
439
|
+
isInputLeaf = !dstNodeIds.includes(n.id);
|
|
440
|
+
} else {
|
|
441
|
+
isOutputLeaf = !srcNodeIds.includes(n.id);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// input node exist & left of start node
|
|
445
|
+
if (currNodeLevel <= 0 && !isInputLeaf) {
|
|
446
|
+
n.canFoldInput = true;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// input node not exist & left of start node
|
|
450
|
+
if (currNodeLevel <= 0 && isInputLeaf && n.hasMoreInput) {
|
|
451
|
+
n.canExpandInput = true;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// output node exist & right of start node
|
|
455
|
+
if (currNodeLevel >= 0 && !isOutputLeaf) {
|
|
456
|
+
n.canFoldOutput = true;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// output node not exist & right of start node
|
|
460
|
+
if (currNodeLevel >= 0 && isOutputLeaf && n.hasMoreOutput) {
|
|
461
|
+
n.canExpandOutput = true;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// column: always true if isStartNode === true
|
|
465
|
+
const columnRefreshList = n.isStartNode
|
|
466
|
+
? [...n.children, ...n.relatedColumns]
|
|
467
|
+
: n.relatedColumns;
|
|
468
|
+
|
|
469
|
+
columnRefreshList?.forEach((col) => {
|
|
470
|
+
col.canExpandInput = false;
|
|
471
|
+
col.canExpandOutput = false;
|
|
472
|
+
col.canFoldInput = false;
|
|
473
|
+
col.canFoldOutput = false;
|
|
474
|
+
|
|
475
|
+
if (!col.isStartNode && !col.isRelatedColumn) return;
|
|
476
|
+
|
|
477
|
+
let isInputLeaf_col = false;
|
|
478
|
+
let isOutputLeaf_col = false;
|
|
479
|
+
if (currNodeLevel === 0) {
|
|
480
|
+
isInputLeaf_col = !dstNodeIds.includes(col.id);
|
|
481
|
+
isOutputLeaf_col = !srcNodeIds.includes(col.id);
|
|
482
|
+
} else if (currNodeLevel < 0) {
|
|
483
|
+
isInputLeaf_col = !dstNodeIds.includes(col.id);
|
|
484
|
+
} else {
|
|
485
|
+
isOutputLeaf_col = !srcNodeIds.includes(col.id);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// input node exist & left of start node
|
|
489
|
+
if (currNodeLevel <= 0 && !isInputLeaf_col) {
|
|
490
|
+
col.canFoldInput = true;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// input node not exist & left of start node
|
|
494
|
+
if (currNodeLevel <= 0 && isInputLeaf_col && col.hasMoreInput) {
|
|
495
|
+
col.canExpandInput = true;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// output node exist & right of start node
|
|
499
|
+
if (currNodeLevel >= 0 && !isOutputLeaf_col) {
|
|
500
|
+
col.canFoldOutput = true;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// output node not exist & right of start node
|
|
504
|
+
if (currNodeLevel >= 0 && isOutputLeaf_col && col.hasMoreOutput) {
|
|
505
|
+
col.canExpandOutput = true;
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
getNodeType(typeCode: string) {
|
|
512
|
+
return typeCode === 'Table' ? TABLE_NODE : CUSTOM_NODE;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
updateNodesVisible(
|
|
516
|
+
data: IParsedGraphData<TData, TColumn>,
|
|
517
|
+
edgeDashVisible: EDashType,
|
|
518
|
+
onlyShowRelated: boolean,
|
|
519
|
+
isFoldChecked: boolean,
|
|
520
|
+
) {
|
|
521
|
+
if (_.isNil(data)) return;
|
|
522
|
+
|
|
523
|
+
data.nodes.forEach((node) => {
|
|
524
|
+
node.visible = this.getNodeVisible(
|
|
525
|
+
node,
|
|
526
|
+
data,
|
|
527
|
+
edgeDashVisible,
|
|
528
|
+
onlyShowRelated,
|
|
529
|
+
isFoldChecked,
|
|
530
|
+
);
|
|
531
|
+
|
|
532
|
+
node.relatedColumns?.forEach((col) => {
|
|
533
|
+
col.visible = this.getRelatedNodeVisible(col, data, edgeDashVisible);
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
node.children?.forEach((child) => {
|
|
537
|
+
child.visible = this.getNodeVisible(
|
|
538
|
+
child,
|
|
539
|
+
data,
|
|
540
|
+
edgeDashVisible,
|
|
541
|
+
onlyShowRelated,
|
|
542
|
+
isFoldChecked,
|
|
543
|
+
);
|
|
544
|
+
});
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
updateEdgesVisible(
|
|
549
|
+
data: IParsedGraphData<TData, TColumn>,
|
|
550
|
+
edgeDashVisible: EDashType,
|
|
551
|
+
onlyShowRelated: boolean,
|
|
552
|
+
isFoldChecked: boolean,
|
|
553
|
+
) {
|
|
554
|
+
if (_.isNil(data)) return;
|
|
555
|
+
|
|
556
|
+
data.edges.forEach((edge) => {
|
|
557
|
+
edge.visible = this.getEdgeVisible(
|
|
558
|
+
edge,
|
|
559
|
+
edgeDashVisible,
|
|
560
|
+
onlyShowRelated,
|
|
561
|
+
isFoldChecked,
|
|
562
|
+
);
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
getNodeVisible(
|
|
567
|
+
nodeConfig: INodeConfig<TData, TColumn> | IColumnConfig<TColumn>,
|
|
568
|
+
data: IParsedGraphData<TData, TColumn>,
|
|
569
|
+
edgeDashVisible: EDashType,
|
|
570
|
+
onlyShowRelated: boolean,
|
|
571
|
+
isFoldChecked: boolean,
|
|
572
|
+
) {
|
|
573
|
+
if (nodeConfig.isStartNode) return true;
|
|
574
|
+
|
|
575
|
+
if (nodeConfig.isFolded) return false;
|
|
576
|
+
|
|
577
|
+
// 只显示相关节点 & 该节点不是相关节点 & 该节点是表,则该节点不可见
|
|
578
|
+
if (onlyShowRelated && !nodeConfig.isRelated && !nodeConfig.tableId)
|
|
579
|
+
return false;
|
|
580
|
+
|
|
581
|
+
if (nodeConfig.canBeFold && isFoldChecked) return false;
|
|
582
|
+
|
|
583
|
+
// 找出所有target、source为该节点的边
|
|
584
|
+
const relatedEdges = data.edges.filter((edge) => {
|
|
585
|
+
return (
|
|
586
|
+
// 上游表-当前表、当前表-下游表
|
|
587
|
+
edge.target === nodeConfig.id ||
|
|
588
|
+
edge.source === nodeConfig.id ||
|
|
589
|
+
// 上游列-当前列、当前列-下游列
|
|
590
|
+
(nodeConfig as INodeConfig<TData, TColumn>)?.relatedColumns?.some(
|
|
591
|
+
(col) => {
|
|
592
|
+
return edge.target === col.id || edge.source === col.id;
|
|
593
|
+
},
|
|
594
|
+
)
|
|
595
|
+
);
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
if (!relatedEdges.length) return false;
|
|
599
|
+
|
|
600
|
+
const allRelatedNodeInvisible = relatedEdges.every((edgeCfg) => {
|
|
601
|
+
const srcNode = data.nodes.find((node) => node.id === edgeCfg.source);
|
|
602
|
+
const tgtNode = data.nodes.find((node) => node.id === edgeCfg.target);
|
|
603
|
+
|
|
604
|
+
if ((srcNode?.canBeFold || tgtNode?.canBeFold) && isFoldChecked)
|
|
605
|
+
return true;
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
if (allRelatedNodeInvisible) return false;
|
|
609
|
+
|
|
610
|
+
const isAllIndirectEdges = relatedEdges.every(
|
|
611
|
+
(edge) => edge.relationType === EDashType.INDIRECT,
|
|
612
|
+
);
|
|
613
|
+
|
|
614
|
+
// 开关只有true false,直接、间接
|
|
615
|
+
if (edgeDashVisible === EDashType.INDIRECT) {
|
|
616
|
+
return true;
|
|
617
|
+
} else {
|
|
618
|
+
// 如果边都是间接边,那么该节点就隐藏
|
|
619
|
+
if (isAllIndirectEdges) return false;
|
|
620
|
+
|
|
621
|
+
return true;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
getRelatedNodeVisible(
|
|
626
|
+
nodeConfig: INodeConfig<TData, TColumn> | IColumnConfig<TColumn>,
|
|
627
|
+
data: IParsedGraphData<TData, TColumn>,
|
|
628
|
+
edgeDashVisible: EDashType,
|
|
629
|
+
) {
|
|
630
|
+
// 仅相关开启的情况下,如果高亮链路是表链路,隐藏非相关的列
|
|
631
|
+
if (this.lineageManager?.rightKeyMenuManager?.onlyShowRelated) {
|
|
632
|
+
if (!this.lineageManager?.activeNodes?.[0]?.tableName) {
|
|
633
|
+
if (!_.some(this.lineageManager?.relatedNodes, { id: nodeConfig.id }))
|
|
634
|
+
return false;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// 找出所有target、source为该节点的边
|
|
639
|
+
const relatedEdges = data.edges.filter(
|
|
640
|
+
(edge) =>
|
|
641
|
+
(edge.target === nodeConfig.id || edge.source === nodeConfig.id) &&
|
|
642
|
+
edge.visible,
|
|
643
|
+
);
|
|
644
|
+
|
|
645
|
+
if (!relatedEdges.length) return false;
|
|
646
|
+
|
|
647
|
+
const isAllIndirectEdges = relatedEdges.every(
|
|
648
|
+
(edge) => edge.relationType === EDashType.INDIRECT,
|
|
649
|
+
);
|
|
650
|
+
|
|
651
|
+
// 开关只有true false,直接、间接
|
|
652
|
+
if (edgeDashVisible === EDashType.INDIRECT) {
|
|
653
|
+
return true;
|
|
654
|
+
} else {
|
|
655
|
+
// 如果边都是间接边,那么该节点就隐藏
|
|
656
|
+
if (isAllIndirectEdges) return false;
|
|
657
|
+
|
|
658
|
+
return true;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
getEdgeVisible(
|
|
663
|
+
edgeCfg: IEdgeConfig,
|
|
664
|
+
edgeDashVisible: EDashType,
|
|
665
|
+
onlyShowRelated: boolean,
|
|
666
|
+
isFoldChecked: boolean,
|
|
667
|
+
) {
|
|
668
|
+
// 如果边被折叠了,那么该边就隐藏
|
|
669
|
+
if (edgeCfg.isFolded) return false;
|
|
670
|
+
|
|
671
|
+
let visible = false;
|
|
672
|
+
|
|
673
|
+
if (isFoldChecked) {
|
|
674
|
+
const foldStatus =
|
|
675
|
+
this.lineageManager?.foldLineageManager?.foldStatusMap?.get(
|
|
676
|
+
edgeCfg.foldTableId,
|
|
677
|
+
);
|
|
678
|
+
|
|
679
|
+
if (foldStatus) {
|
|
680
|
+
visible = !!edgeCfg.isExtraFoldEdge;
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
switch (edgeDashVisible) {
|
|
685
|
+
case EDashType.DIRECT:
|
|
686
|
+
visible =
|
|
687
|
+
edgeCfg.relationType === EDashType.DIRECT ||
|
|
688
|
+
edgeCfg.relationType === EDashType.ALL;
|
|
689
|
+
break;
|
|
690
|
+
case EDashType.INDIRECT:
|
|
691
|
+
visible = true;
|
|
692
|
+
break;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
return visible;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
updateNodesAndEdgesVisible(
|
|
699
|
+
data: IParsedGraphData<TData, TColumn>,
|
|
700
|
+
edgeDashVisible: EDashType,
|
|
701
|
+
onlyShowRelated: boolean,
|
|
702
|
+
isFoldChecked: boolean,
|
|
703
|
+
) {
|
|
704
|
+
this.updateEdgesVisible(
|
|
705
|
+
data,
|
|
706
|
+
edgeDashVisible,
|
|
707
|
+
onlyShowRelated,
|
|
708
|
+
isFoldChecked,
|
|
709
|
+
);
|
|
710
|
+
|
|
711
|
+
// 更新节点本身、列、节点children的可见性
|
|
712
|
+
this.updateNodesVisible(
|
|
713
|
+
data,
|
|
714
|
+
edgeDashVisible,
|
|
715
|
+
onlyShowRelated,
|
|
716
|
+
isFoldChecked,
|
|
717
|
+
);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
refreshRelatedNodesAndEdges(
|
|
721
|
+
relatedNodes: (INodeConfig<TData, TColumn> | IColumnConfig<TColumn>)[],
|
|
722
|
+
relatedEdges: IEdgeConfig[],
|
|
723
|
+
) {
|
|
724
|
+
relatedNodes.forEach((n) => {
|
|
725
|
+
if (!n) return;
|
|
726
|
+
|
|
727
|
+
const nodeConfig = this.lineageManager.getNodeConfigById(n.id);
|
|
728
|
+
if (!nodeConfig) return;
|
|
729
|
+
|
|
730
|
+
nodeConfig.isRelated = true;
|
|
731
|
+
|
|
732
|
+
nodeConfig.style.stroke = '#3271C9';
|
|
733
|
+
|
|
734
|
+
if (!nodeConfig.isActive) {
|
|
735
|
+
nodeConfig.style.fill = '#E4EFFF';
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
nodeConfig.style.zIndex = 3;
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
relatedEdges.forEach((e) => {
|
|
742
|
+
if (!e) return;
|
|
743
|
+
|
|
744
|
+
const edge = this.lineageManager.getEdgeConfigById(e.id);
|
|
745
|
+
if (!edge) return;
|
|
746
|
+
if (
|
|
747
|
+
(edge.inFoldLink &&
|
|
748
|
+
this.lineageManager.foldLineageManager.isFoldChecked) ||
|
|
749
|
+
edge.isExtraFoldEdge
|
|
750
|
+
)
|
|
751
|
+
return;
|
|
752
|
+
|
|
753
|
+
edge.style.stroke = '#3271C9';
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
updateNodeHeight(data: IParsedGraphData<TData, TColumn>) {
|
|
758
|
+
data.nodes.forEach((node) => {
|
|
759
|
+
node.style.height = this.calcNodeHeight(node);
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
updateColumnPosition(data: IParsedGraphData<TData, TColumn>) {
|
|
764
|
+
data.nodes.forEach((node) => {
|
|
765
|
+
const visibleRelatedColumns = node.relatedColumns?.filter(
|
|
766
|
+
(col) => col.visible,
|
|
767
|
+
);
|
|
768
|
+
visibleRelatedColumns?.forEach((col, i) => {
|
|
769
|
+
col.position.y = i * COL_HEIGHT;
|
|
770
|
+
});
|
|
771
|
+
|
|
772
|
+
const visibleColumns = node.children?.filter((col) => col.visible);
|
|
773
|
+
visibleColumns?.forEach((col, i) => {
|
|
774
|
+
col.position.y = node.position.y + COL_HEIGHT * i;
|
|
775
|
+
});
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
calcNodeHeight(node: INodeConfig<TData, TColumn>) {
|
|
780
|
+
return getNodeHeight(node);
|
|
781
|
+
}
|
|
782
|
+
}
|