@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.
Files changed (50) hide show
  1. package/package.json +27 -0
  2. package/src/assets/big/dataSourceTypeIcon.ts +65 -0
  3. package/src/assets/big/entityType.ts +1 -0
  4. package/src/assets/big/index.ts +5 -0
  5. package/src/assets/big/lineageIcon.ts +35 -0
  6. package/src/assets/big/tableTypeIcon.ts +17 -0
  7. package/src/assets/big/tipIcon.ts +1 -0
  8. package/src/assets/index.ts +14 -0
  9. package/src/components/Edges/DefaultEdge.ts +196 -0
  10. package/src/components/Edges/FoldEdge.ts +97 -0
  11. package/src/components/Edges/LineageEdge.ts +24 -0
  12. package/src/components/Edges/index.ts +3 -0
  13. package/src/components/Nodes/AssetNode.ts +438 -0
  14. package/src/components/Nodes/ColumnNode.ts +491 -0
  15. package/src/components/Nodes/CustomNode.ts +63 -0
  16. package/src/components/Nodes/DefaultNode.ts +74 -0
  17. package/src/components/Nodes/DowngradeNode.ts +115 -0
  18. package/src/components/Nodes/TableNode.ts +534 -0
  19. package/src/components/Nodes/index.ts +4 -0
  20. package/src/components/index.ts +2 -0
  21. package/src/constant/index.ts +1 -0
  22. package/src/constant/nodeStyle.ts +141 -0
  23. package/src/index.ts +6 -0
  24. package/src/manager/BaseManager.ts +20 -0
  25. package/src/manager/DataProcessor.ts +782 -0
  26. package/src/manager/ExpandManager.ts +93 -0
  27. package/src/manager/FoldLineageManager.ts +196 -0
  28. package/src/manager/GraphEventManager.ts +90 -0
  29. package/src/manager/LineageManager.ts +680 -0
  30. package/src/manager/RightKeyMenuManager.ts +114 -0
  31. package/src/manager/SearchNodeManager.ts +188 -0
  32. package/src/manager/ToolbarManager.ts +42 -0
  33. package/src/manager/index.ts +8 -0
  34. package/src/manager/nodeManager/AssetEventManager.ts +442 -0
  35. package/src/manager/nodeManager/BaseEventManager.ts +68 -0
  36. package/src/manager/nodeManager/ColumnEventManager.ts +467 -0
  37. package/src/manager/nodeManager/CustomEventManager.ts +11 -0
  38. package/src/manager/nodeManager/TableEventManager.ts +87 -0
  39. package/src/manager/nodeManager/index.ts +3 -0
  40. package/src/types/NodeConfig.ts +69 -0
  41. package/src/types/eventEnum.ts +58 -0
  42. package/src/types/index.ts +3 -0
  43. package/src/types/manager.ts +75 -0
  44. package/src/types/node.ts +246 -0
  45. package/src/utils/downgradeNode.ts +22 -0
  46. package/src/utils/foldNode.ts +345 -0
  47. package/src/utils/getIconByType.ts +104 -0
  48. package/src/utils/index.ts +3 -0
  49. package/src/utils/node.ts +294 -0
  50. package/tsconfig.json +30 -0
@@ -0,0 +1,438 @@
1
+ import { Group, Rect, Text, Image, Graph } from '@aloudata/ink-graph-new';
2
+ import { DefaultNode } from './DefaultNode';
3
+ import {
4
+ colorVar,
5
+ NODE_WIDTH,
6
+ RECT_LINE_WIDTH,
7
+ SIDE_ICON_SIZE,
8
+ TABLE_HEADER_HEIGHT,
9
+ TABLE_HEADER_NAME_WRAP_WIDTH,
10
+ TABLE_RECT_BORDER_RADIUS,
11
+ TABLE_TAG_HEIGHT,
12
+ } from '../../constant';
13
+ import {
14
+ AssetEventType,
15
+ EDashType,
16
+ EDirection,
17
+ EEntityType,
18
+ EEventEnum,
19
+ EExpandType,
20
+ IColResBase,
21
+ INodeConfig,
22
+ TDataBase,
23
+ } from '../../types';
24
+ import { hotspot } from '../../assets';
25
+ import _ from 'lodash';
26
+
27
+ export class AssetNode extends DefaultNode {
28
+ headerGroup: Rect;
29
+
30
+ headerName: Text;
31
+
32
+ isHoverColumn: boolean = false;
33
+
34
+ declare eventType: AssetEventType;
35
+
36
+ declare config: INodeConfig<TDataBase<IColResBase>, IColResBase>;
37
+
38
+ constructor(
39
+ graph: Graph,
40
+ config: INodeConfig<TDataBase<IColResBase>, IColResBase>,
41
+ ) {
42
+ super(graph, config);
43
+ }
44
+
45
+ renderAssetNode() {
46
+ const { isStartNode, visible, position } = this.config;
47
+
48
+ this.container.setPosition(position.x, position.y);
49
+
50
+ if (visible === false) return;
51
+
52
+ if (isStartNode) {
53
+ // render start node tag
54
+ this.renderStartNodeTag();
55
+ }
56
+
57
+ // render table header
58
+ this.renderHeader();
59
+
60
+ // init events
61
+ this.initEvents();
62
+ }
63
+
64
+ renderStartNodeTag() {
65
+ const { data } = this.config;
66
+ const tagGroup = new Group({
67
+ name: 'tag',
68
+ });
69
+
70
+ const color = data.type === EEntityType.CUSTOM ? '#475569' : '#14B8A6';
71
+ const tagRect = new Rect({
72
+ style: {
73
+ x: -1,
74
+ y: -TABLE_TAG_HEIGHT,
75
+ width: NODE_WIDTH + 2,
76
+ height: TABLE_TAG_HEIGHT,
77
+ stroke: color,
78
+ fill: color,
79
+ lineWidth: 1,
80
+ radius: [4, 4, 0, 0], // 0
81
+ },
82
+ });
83
+
84
+ const tagText = new Text({
85
+ style: {
86
+ x: 8,
87
+ y: -17,
88
+ lineHeight: 16,
89
+ text: '起始资产',
90
+ fontSize: 12,
91
+ fontWeight: 400,
92
+ fontFamily: 'PingFang SC',
93
+ textBaseline: 'top',
94
+ fill: '#FFF',
95
+ },
96
+ });
97
+
98
+ tagGroup.appendChild(tagRect);
99
+ tagGroup.appendChild(tagText);
100
+
101
+ this.container.appendChild(tagGroup);
102
+ }
103
+
104
+ renderHeader() {
105
+ const { data, isStartNode } = this.config;
106
+ const { name, typeCodeName } = data;
107
+
108
+ // table 整体
109
+ this.headerGroup = new Rect({
110
+ name: 'table-header-group',
111
+ style: {
112
+ x: -1,
113
+ y: 1,
114
+ width: NODE_WIDTH + 2,
115
+ height: TABLE_HEADER_HEIGHT,
116
+ stroke: this.config.style.stroke || colorVar.headerGroupBorderDefault,
117
+ zIndex: this.config.style.zIndex || 2,
118
+ lineWidth: RECT_LINE_WIDTH,
119
+ radius: isStartNode
120
+ ? [0, 0, TABLE_RECT_BORDER_RADIUS, TABLE_RECT_BORDER_RADIUS]
121
+ : TABLE_RECT_BORDER_RADIUS,
122
+ },
123
+ });
124
+
125
+ (this.headerGroup as any).node = this;
126
+
127
+ this.headerGroup.addEventListener('click', () => {
128
+ this.lineageManager.emit(this.eventType.HEADER_CLICK, this);
129
+ });
130
+
131
+ this.headerGroup.addEventListener('contextmenu', (e) => {
132
+ e.preventDefault();
133
+
134
+ this.contextmenuClick();
135
+ });
136
+
137
+ // header部分
138
+ this.bgRect = new Rect({
139
+ style: {
140
+ x: 1,
141
+ y: 1,
142
+ fill: this.config.style.fill || '#FFFFFF',
143
+ width: NODE_WIDTH,
144
+ height: TABLE_HEADER_HEIGHT,
145
+ radius: isStartNode
146
+ ? 0
147
+ : [TABLE_RECT_BORDER_RADIUS, TABLE_RECT_BORDER_RADIUS, 0, 0],
148
+ },
149
+ });
150
+
151
+ this.headerName = new Text({
152
+ style: {
153
+ x: 36,
154
+ y: 22,
155
+ text: name,
156
+ fontSize: 12,
157
+ fontWeight: 500,
158
+ lineHeight: 14,
159
+ fontFamily: 'PingFang SC',
160
+ textBaseline: 'middle',
161
+ wordWrap: true,
162
+ wordWrapWidth: TABLE_HEADER_NAME_WRAP_WIDTH,
163
+ maxLines: 2,
164
+ textOverflow: 'ellipsis',
165
+ fill: '#171717',
166
+ },
167
+ });
168
+
169
+ // 用于hover到sideIcon区域时也能显示sideIcon
170
+ const bgHideRect = new Rect({
171
+ name: 'column-bgRect-hide',
172
+ style: {
173
+ x: -20,
174
+ fill: '#0000',
175
+ stroke: '#0000',
176
+ width: NODE_WIDTH + 40,
177
+ height: TABLE_HEADER_HEIGHT,
178
+ zIndex: 9,
179
+ },
180
+ });
181
+
182
+ if (this.config.data.isHotspot) {
183
+ const hotspotIcon = new Image({
184
+ style: {
185
+ x: 270,
186
+ y: 14,
187
+ width: 20,
188
+ height: 20,
189
+ img: hotspot,
190
+ cursor: 'pointer',
191
+ zIndex: 99,
192
+ },
193
+ });
194
+
195
+ hotspotIcon?.addEventListener('mouseenter', () => {
196
+ const { x, y } = hotspotIcon.getBBox();
197
+ this.lineageManager.rightKeyMenuManager.updateHotspotTipState({
198
+ visible: true,
199
+ id: this.config.id,
200
+ data: this.config.data,
201
+ x,
202
+ y,
203
+ });
204
+ });
205
+
206
+ hotspotIcon?.addEventListener('mouseout', () => {
207
+ this.lineageManager.rightKeyMenuManager.updateHotspotTipState({
208
+ visible: false,
209
+ id: '',
210
+ data: {},
211
+ x: -999,
212
+ y: -999,
213
+ });
214
+ });
215
+
216
+ this.headerGroup.appendChild(hotspotIcon);
217
+ }
218
+
219
+ this.leftIcon = new Image({
220
+ name: `sideIcon-img-left`,
221
+ style: {
222
+ x: -SIDE_ICON_SIZE - 4,
223
+ y: TABLE_HEADER_HEIGHT / 2 - SIDE_ICON_SIZE / 2,
224
+ width: SIDE_ICON_SIZE,
225
+ height: SIDE_ICON_SIZE,
226
+ cursor: 'pointer',
227
+ zIndex: 99,
228
+ visibility: 'visible',
229
+ },
230
+ });
231
+
232
+ this.leftIcon.addEventListener('click', () => {
233
+ this.leftIconClick();
234
+ });
235
+
236
+ this.rightIcon = new Image({
237
+ name: `sideIcon-img-right`,
238
+ style: {
239
+ x: NODE_WIDTH + 6,
240
+ y: TABLE_HEADER_HEIGHT / 2 - SIDE_ICON_SIZE / 2,
241
+ width: SIDE_ICON_SIZE,
242
+ height: SIDE_ICON_SIZE,
243
+ cursor: 'pointer',
244
+ zIndex: 99,
245
+ visibility: 'visible',
246
+ },
247
+ });
248
+
249
+ this.rightIcon.addEventListener('click', () => {
250
+ this.rightIconClick();
251
+ });
252
+
253
+ this.headerGroup.appendChild(this.bgRect);
254
+ this.headerGroup.appendChild(this.headerName);
255
+ this.headerGroup.appendChild(bgHideRect);
256
+ this.headerGroup.appendChild(this.leftIcon);
257
+ this.headerGroup.appendChild(this.rightIcon);
258
+
259
+ this.container.appendChild(this.headerGroup);
260
+ }
261
+
262
+ updateNodeHeight() {
263
+ const tagHeight = this.config.isStartNode ? TABLE_TAG_HEIGHT : -1;
264
+ this.headerGroup.style.height = this.container.getBBox().height - tagHeight;
265
+ }
266
+
267
+ onHover() {
268
+ if (!this.config) return;
269
+ if (this.config.style.stroke === '#3271C9') return;
270
+ if (this.isHoverColumn) return;
271
+
272
+ this.headerGroup.setAttribute('stroke', '#3271C9');
273
+ this.container.setAttribute('zIndex', 3);
274
+ }
275
+
276
+ onLeave() {
277
+ if (!this.config) return;
278
+ if (this.config.style.stroke === '#3271C9') return;
279
+ if (this.isHoverColumn) return;
280
+
281
+ this.headerGroup.setAttribute('stroke', '#B1B1B1');
282
+ this.container.setAttribute('zIndex', 2);
283
+ }
284
+
285
+ onMouseLeave = () => {
286
+ this.onLeave();
287
+ // hide side icon
288
+ this.hideSideIcon();
289
+ };
290
+
291
+ onMouseEnter = () => {
292
+ this.onHover();
293
+ // show side icon
294
+ this.showSideIcon();
295
+ };
296
+
297
+ initEvents() {
298
+ this.container.addEventListener('mouseover', (e) => {
299
+ const target = e.target as any;
300
+ if (!target) return;
301
+
302
+ const targetParent = target.parentElement as any;
303
+ if (targetParent && targetParent.name === 'table-header-group') {
304
+ const targetNode = targetParent.node as any;
305
+ if (!targetNode) return;
306
+
307
+ targetNode.onMouseEnter();
308
+
309
+ const handleMouseLeave = () => {
310
+ targetNode.onMouseLeave();
311
+ targetNode.headerGroup.removeEventListener(
312
+ 'mouseleave',
313
+ handleMouseLeave,
314
+ );
315
+ };
316
+
317
+ targetNode.headerGroup.addEventListener('mouseleave', handleMouseLeave);
318
+ }
319
+ });
320
+
321
+ this.container.addEventListener('mouseenter', () => {
322
+ this.onHover();
323
+ });
324
+
325
+ this.container.addEventListener('mouseleave', () => {
326
+ this.onLeave();
327
+ });
328
+ }
329
+
330
+ showSideIcon = () => {
331
+ const { config } = this;
332
+
333
+ const onlyShowRelated =
334
+ !!this.lineageManager?.rightKeyMenuManager?.onlyShowRelated;
335
+
336
+ const isColumnRelatedList =
337
+ !!this.lineageManager.activeNodes?.[0]?.tableName;
338
+ const inRelatedAndInColumnList = onlyShowRelated && isColumnRelatedList;
339
+
340
+ // check left
341
+ // show expand left side icon
342
+ if (config.canExpandInput && !inRelatedAndInColumnList)
343
+ // show left icon if not in column related list
344
+ this.showLeftIcon(EExpandType.EXPAND);
345
+ // show close left side icon
346
+ if (config.canFoldInput && !onlyShowRelated)
347
+ this.showLeftIcon(EExpandType.FOLD);
348
+
349
+ // check right
350
+ // show expand right side icon
351
+ if (config.canExpandOutput && !inRelatedAndInColumnList) {
352
+ // show right icon if not in column related list
353
+ this.showRightIcon(EExpandType.EXPAND);
354
+ }
355
+
356
+ // show close right side icon
357
+ if (config.canFoldOutput && !onlyShowRelated)
358
+ this.showRightIcon(EExpandType.FOLD);
359
+ };
360
+
361
+ handleHotspotExpand(data: { resData; params }) {
362
+ const { resData: parsedData, params } = data;
363
+
364
+ if (!parsedData) return;
365
+
366
+ // reset related nodes
367
+ this.lineageManager?.resetRelatedNodes();
368
+
369
+ const { nodes, edges } = parsedData;
370
+
371
+ // show no more linage
372
+ if (edges.length <= 0) {
373
+ this.lineageManager.emit(EEventEnum.INDIRECT_TIPS, {
374
+ message: `该节点无${
375
+ params.direction === EDirection.INPUT ? '上游' : '下游'
376
+ }血缘`,
377
+ });
378
+ } else {
379
+ // show indirect warning
380
+ if (
381
+ edges
382
+ .filter((e) =>
383
+ params.direction === EDirection.INPUT
384
+ ? e.target === params.guid
385
+ : e.source === params.guid,
386
+ )
387
+ .every((e) => e.relationType === EDashType.INDIRECT)
388
+ ) {
389
+ this.lineageManager.emit(EEventEnum.INDIRECT_TIPS, {
390
+ message: '当前字段只有间接血缘,请打开间接血缘开关后查看',
391
+ });
392
+ }
393
+
394
+ const prevNodesConfig = this.lineageManager.parsedData.nodes;
395
+ const prevEdgesConfig = this.lineageManager.parsedData.edges;
396
+
397
+ const newNodesConfig = _.unionBy([...prevNodesConfig, ...nodes], 'id');
398
+ const newEdgesConfig = _.unionBy([...prevEdgesConfig, ...edges], 'id');
399
+
400
+ // prevNodesConfig中和nodes中同id的node,如果node的isHotspot为true,则将prevNodesConfig中同id的node的isHotspot设置为node的isHotspot,hotspots设置为node的hotspots
401
+ nodes.forEach((node) => {
402
+ const newNode = newNodesConfig.find((n) => n.id === node.id);
403
+ if (newNode) {
404
+ newNode.data.isHotspot =
405
+ newNode.data.isHotspot || node.data.isHotspot;
406
+ newNode.data.hotspots = node.data.hotspots || newNode.data.hotspots;
407
+ }
408
+ });
409
+
410
+ this.lineageManager.setData({
411
+ nodes: newNodesConfig,
412
+ edges: newEdgesConfig,
413
+ });
414
+
415
+ const onlyShowRelated =
416
+ !!this.lineageManager?.rightKeyMenuManager?.onlyShowRelated;
417
+
418
+ if (!onlyShowRelated) {
419
+ // highlight curr node flow
420
+ this.lineageManager?.updateActiveNodes([this.config]);
421
+ // set related nodes & edges
422
+ this.lineageManager?.setRelatedNodesAndEdges(this.config);
423
+ } else {
424
+ // highlight curr node flow
425
+ this.lineageManager?.updateActiveNodes([
426
+ this.lineageManager.cachedRelatedNodeConfig,
427
+ ]);
428
+ // set related nodes & edges
429
+ this.lineageManager?.setRelatedNodesAndEdges(
430
+ this.lineageManager.cachedRelatedNodeConfig,
431
+ );
432
+ }
433
+
434
+ // update
435
+ this.lineageManager.update();
436
+ }
437
+ }
438
+ }