@nocobase/plugin-graph-collection-manager 0.11.1-alpha.5 → 0.12.0-alpha.2

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 (100) hide show
  1. package/client.d.ts +2 -3
  2. package/client.js +1 -1
  3. package/dist/client/index.js +65917 -0
  4. package/{lib → dist}/client/utils.d.ts +4 -3
  5. package/{lib → dist}/index.d.ts +1 -0
  6. package/dist/index.js +18 -0
  7. package/dist/locale/en-US.js +19 -0
  8. package/dist/locale/es-ES.js +19 -0
  9. package/dist/locale/fr-FR.js +19 -0
  10. package/dist/locale/ja-JP.js +17 -0
  11. package/dist/locale/pt-BR.js +19 -0
  12. package/dist/locale/zh-CN.js +20 -0
  13. package/dist/server/collections/graphPositions.js +26 -0
  14. package/dist/server/index.js +23 -0
  15. package/package.json +17 -28
  16. package/server.d.ts +2 -3
  17. package/server.js +1 -1
  18. package/lib/client/GraphCollectionProvider.js +0 -51
  19. package/lib/client/GraphCollectionShortcut.js +0 -169
  20. package/lib/client/GraphDrawPage.js +0 -1546
  21. package/lib/client/action-hooks.js +0 -318
  22. package/lib/client/components/AddCollectionAction.js +0 -58
  23. package/lib/client/components/AddFieldAction.js +0 -69
  24. package/lib/client/components/CollectionNodeProvder.js +0 -34
  25. package/lib/client/components/EditCollectionAction.js +0 -47
  26. package/lib/client/components/EditFieldAction.js +0 -63
  27. package/lib/client/components/Entity.js +0 -529
  28. package/lib/client/components/FieldSummary.js +0 -69
  29. package/lib/client/components/OverrideFieldAction.js +0 -64
  30. package/lib/client/components/ViewFieldAction.js +0 -45
  31. package/lib/client/components/ViewNode.js +0 -33
  32. package/lib/client/index.js +0 -27
  33. package/lib/client/locale/index.js +0 -4
  34. package/lib/client/style.js +0 -233
  35. package/lib/client/utils.js +0 -540
  36. package/lib/index.js +0 -13
  37. package/lib/locale/en-US.js +0 -22
  38. package/lib/locale/es-ES.js +0 -22
  39. package/lib/locale/fr-FR.js +0 -22
  40. package/lib/locale/ja-JP.js +0 -20
  41. package/lib/locale/pt-BR.js +0 -22
  42. package/lib/locale/zh-CN.js +0 -23
  43. package/lib/server/collections/graphPositions.js +0 -30
  44. package/lib/server/index.js +0 -37
  45. package/src/client/GraphCollectionProvider.tsx +0 -33
  46. package/src/client/GraphCollectionShortcut.tsx +0 -141
  47. package/src/client/GraphDrawPage.tsx +0 -1382
  48. package/src/client/action-hooks.tsx +0 -237
  49. package/src/client/components/AddCollectionAction.tsx +0 -28
  50. package/src/client/components/AddFieldAction.tsx +0 -37
  51. package/src/client/components/CollectionNodeProvder.tsx +0 -28
  52. package/src/client/components/EditCollectionAction.tsx +0 -21
  53. package/src/client/components/EditFieldAction.tsx +0 -30
  54. package/src/client/components/Entity.tsx +0 -495
  55. package/src/client/components/FieldSummary.tsx +0 -42
  56. package/src/client/components/OverrideFieldAction.tsx +0 -30
  57. package/src/client/components/ViewFieldAction.tsx +0 -12
  58. package/src/client/components/ViewNode.tsx +0 -22
  59. package/src/client/index.tsx +0 -10
  60. package/src/client/locale/index.ts +0 -3
  61. package/src/client/style.tsx +0 -227
  62. package/src/client/utils.tsx +0 -548
  63. package/src/index.ts +0 -1
  64. package/src/locale/en-US.ts +0 -15
  65. package/src/locale/es-ES.ts +0 -15
  66. package/src/locale/fr-FR.ts +0 -15
  67. package/src/locale/ja-JP.ts +0 -13
  68. package/src/locale/pt-BR.ts +0 -15
  69. package/src/locale/zh-CN.ts +0 -16
  70. package/src/server/actions/.gitkeep +0 -0
  71. package/src/server/collections/.gitkeep +0 -0
  72. package/src/server/collections/graphPositions.ts +0 -22
  73. package/src/server/index.ts +0 -13
  74. package/src/server/models/.gitkeep +0 -0
  75. package/src/server/repositories/.gitkeep +0 -0
  76. /package/{lib → dist}/client/GraphCollectionProvider.d.ts +0 -0
  77. /package/{lib → dist}/client/GraphCollectionShortcut.d.ts +0 -0
  78. /package/{lib → dist}/client/GraphDrawPage.d.ts +0 -0
  79. /package/{lib → dist}/client/action-hooks.d.ts +0 -0
  80. /package/{lib → dist}/client/components/AddCollectionAction.d.ts +0 -0
  81. /package/{lib → dist}/client/components/AddFieldAction.d.ts +0 -0
  82. /package/{lib → dist}/client/components/CollectionNodeProvder.d.ts +0 -0
  83. /package/{lib → dist}/client/components/EditCollectionAction.d.ts +0 -0
  84. /package/{lib → dist}/client/components/EditFieldAction.d.ts +0 -0
  85. /package/{lib → dist}/client/components/Entity.d.ts +0 -0
  86. /package/{lib → dist}/client/components/FieldSummary.d.ts +0 -0
  87. /package/{lib → dist}/client/components/OverrideFieldAction.d.ts +0 -0
  88. /package/{lib → dist}/client/components/ViewFieldAction.d.ts +0 -0
  89. /package/{lib → dist}/client/components/ViewNode.d.ts +0 -0
  90. /package/{lib → dist}/client/index.d.ts +0 -0
  91. /package/{lib → dist}/client/locale/index.d.ts +0 -0
  92. /package/{lib → dist}/client/style.d.ts +0 -0
  93. /package/{lib → dist}/locale/en-US.d.ts +0 -0
  94. /package/{lib → dist}/locale/es-ES.d.ts +0 -0
  95. /package/{lib → dist}/locale/fr-FR.d.ts +0 -0
  96. /package/{lib → dist}/locale/ja-JP.d.ts +0 -0
  97. /package/{lib → dist}/locale/pt-BR.d.ts +0 -0
  98. /package/{lib → dist}/locale/zh-CN.d.ts +0 -0
  99. /package/{lib → dist}/server/collections/graphPositions.d.ts +0 -0
  100. /package/{lib → dist}/server/index.d.ts +0 -0
@@ -1,1382 +0,0 @@
1
- import {
2
- ApartmentOutlined,
3
- FullscreenExitOutlined,
4
- FullscreenOutlined,
5
- LineHeightOutlined,
6
- MenuOutlined,
7
- ShareAltOutlined,
8
- } from '@ant-design/icons';
9
- import { Graph } from '@antv/x6';
10
- import '@antv/x6-react-shape';
11
- import { SchemaOptionsContext } from '@formily/react';
12
- import {
13
- APIClientProvider,
14
- CollectionCategroriesContext,
15
- CollectionCategroriesProvider,
16
- CollectionManagerContext,
17
- CollectionManagerProvider,
18
- CurrentAppInfoContext,
19
- SchemaComponent,
20
- SchemaComponentOptions,
21
- Select,
22
- collection,
23
- css,
24
- cx,
25
- useAPIClient,
26
- useCollectionManager,
27
- useCompile,
28
- useCurrentAppInfo,
29
- useGlobalTheme,
30
- } from '@nocobase/client';
31
- import { lodash } from '@nocobase/utils/client';
32
- import { useFullscreen } from 'ahooks';
33
- import { Button, ConfigProvider, Input, Layout, Menu, Popover, Switch, Tooltip } from 'antd';
34
- import dagre from 'dagre';
35
- import React, { createContext, forwardRef, useContext, useEffect, useLayoutEffect, useState } from 'react';
36
- import { useAsyncDataSource, useCreateActionAndRefreshCM } from './action-hooks';
37
- import { AddCollectionAction } from './components/AddCollectionAction';
38
- import Entity from './components/Entity';
39
- import { SimpleNodeView } from './components/ViewNode';
40
- import useStyles from './style';
41
- import {
42
- formatData,
43
- getChildrenCollections,
44
- getDiffEdge,
45
- getDiffNode,
46
- getInheritCollections,
47
- getPopupContainer,
48
- useGCMTranslation,
49
- } from './utils';
50
-
51
- const { drop, groupBy, last, maxBy, minBy, take } = lodash;
52
-
53
- const LINE_HEIGHT = 40;
54
- const NODE_WIDTH = 250;
55
- let targetGraph;
56
- let targetNode;
57
- const dir = 'TB'; // LR RL TB BT 横排
58
-
59
- export enum DirectionType {
60
- Both = 'both',
61
- Target = 'target',
62
- Source = 'source',
63
- }
64
-
65
- export enum ConnectionType {
66
- Both = 'both',
67
- Inherit = 'inherited',
68
- Entity = 'entity',
69
- }
70
- const getGridData = (num, arr) => {
71
- const newArr = [];
72
- while (arr.length > 0 && num) {
73
- newArr.push(arr.splice(0, num));
74
- }
75
- return newArr;
76
- };
77
-
78
- //初始布局
79
- async function layout(createPositions) {
80
- const { positions } = targetGraph;
81
- let graphPositions = [];
82
- const nodes: any[] = targetGraph.getNodes();
83
- const edges = targetGraph.getEdges();
84
- const g: any = new dagre.graphlib.Graph();
85
- g.setGraph({ rankdir: dir, nodesep: 50, edgesep: 50, rankSep: 50, align: 'DL', controlPoints: true });
86
- g.setDefaultEdgeLabel(() => ({}));
87
- nodes.forEach((node, i) => {
88
- const width = NODE_WIDTH;
89
- const height = node.getPorts().length * 32 + 30;
90
- g.setNode(node.id, { width, height });
91
- });
92
- dagre.layout(g);
93
- targetGraph.freeze();
94
- const dNodes = getGridData(15, g.nodes());
95
- dNodes.forEach((arr, row) => {
96
- arr.forEach((id, index) => {
97
- const node = targetGraph.getCell(id);
98
- const col = index % 15;
99
- if (node) {
100
- const targetPosition =
101
- (positions &&
102
- positions.find((v) => {
103
- return v.collectionName === node.store.data.name;
104
- })) ||
105
- {};
106
- const calculatedPosition = { x: col * 325 + 50, y: row * 400 + 60 };
107
- node.position(targetPosition.x || calculatedPosition.x, targetPosition.y || calculatedPosition.y);
108
- if (positions && !positions.find((v) => v.collectionName === node.store.data.name)) {
109
- // 位置表中没有的表都自动保存
110
- graphPositions.push({
111
- collectionName: node.store.data.name,
112
- x: calculatedPosition.x,
113
- y: calculatedPosition.y,
114
- });
115
- }
116
- }
117
- });
118
- });
119
- edges.forEach((edge) => {
120
- optimizeEdge(edge);
121
- });
122
- targetGraph.unfreeze();
123
- if (targetNode) {
124
- typeof targetNode === 'string'
125
- ? targetGraph.positionCell(last(nodes), 'top', { padding: 100 })
126
- : targetGraph.positionCell(targetNode, 'top', { padding: 100 });
127
- } else {
128
- targetGraph.positionCell(nodes[0], 'top-left', { padding: 100 });
129
- }
130
- if (graphPositions.length > 0) {
131
- await createPositions(graphPositions);
132
- graphPositions = [];
133
- }
134
- }
135
-
136
- function optimizeEdge(edge) {
137
- const {
138
- store: {
139
- data: { connectionType },
140
- },
141
- } = edge;
142
- const source = edge.getSource();
143
- const target = edge.getTarget();
144
- const sorceNodeX = targetGraph.getCell(source.cell).position().x;
145
- const targeNodeX = targetGraph.getCell(target.cell).position().x;
146
- const leftAnchor = connectionType
147
- ? {
148
- name: 'topLeft',
149
- args: {
150
- dy: -20,
151
- },
152
- }
153
- : {
154
- name: 'left',
155
- };
156
- const rightAnchor = connectionType
157
- ? {
158
- name: 'topRight',
159
- args: {
160
- dy: -20,
161
- },
162
- }
163
- : 'right';
164
- const router = connectionType ? 'normal' : 'er';
165
- const vertices = edge.getVertices();
166
- vertices.forEach(() => {
167
- return edge.removeVertexAt(0);
168
- });
169
- if (sorceNodeX - 100 > targeNodeX) {
170
- edge.setSource({
171
- cell: source.cell,
172
- port: source.port,
173
- anchor: leftAnchor,
174
- });
175
- edge.setTarget({
176
- cell: target.cell,
177
- port: target.port,
178
- anchor: rightAnchor,
179
- });
180
- edge.setRouter(router, {
181
- direction: 'H',
182
- });
183
- } else if (Math.abs(sorceNodeX - targeNodeX) < 100) {
184
- const sourceCell = targetGraph.getCell(source.cell);
185
- const targetCell = targetGraph.getCell(target.cell);
186
- edge.setSource({
187
- cell: source.cell,
188
- port: source.port,
189
- anchor: leftAnchor,
190
- });
191
- edge.setTarget({
192
- cell: target.cell,
193
- port: target.port,
194
- anchor: leftAnchor,
195
- });
196
- if (connectionType) {
197
- edge.setVertices([
198
- { x: sourceCell.position().x - 30, y: sourceCell.position().y + 20 },
199
- { x: targetCell.position().x - 30, y: targetCell.position().y + 20 },
200
- ]);
201
- edge.setRouter('normal');
202
- } else {
203
- edge.setRouter('oneSide', { side: 'left' });
204
- }
205
- } else {
206
- edge.setSource({
207
- cell: source.cell,
208
- port: source.port,
209
- anchor: rightAnchor,
210
- });
211
- edge.setTarget({
212
- cell: target.cell,
213
- port: target.port,
214
- anchor: leftAnchor,
215
- });
216
- edge.setRouter(router, {
217
- direction: 'H',
218
- });
219
- }
220
- }
221
-
222
- function getNodes(nodes) {
223
- targetGraph.addNodes(nodes);
224
- }
225
-
226
- function getEdges(edges) {
227
- edges.forEach((item) => {
228
- if (item.source && item.target) {
229
- targetGraph.addEdge({
230
- ...item,
231
- connector: {
232
- name: 'normal',
233
- zIndex: 1000,
234
- },
235
- });
236
- }
237
- });
238
- }
239
-
240
- const CollapsedContext = createContext<any>({});
241
- const formatNodeData = () => {
242
- const layoutNodes = [];
243
- const edges = targetGraph.getEdges();
244
- const nodes = targetGraph.getNodes();
245
- edges.forEach((edge) => {
246
- layoutNodes.push(edge.getSourceCellId());
247
- layoutNodes.push(edge.getTargetCellId());
248
- });
249
- const nodeGroup = groupBy(nodes, (v) => {
250
- if (layoutNodes.includes(v.id)) {
251
- return 'linkNodes';
252
- } else {
253
- return 'rawNodes';
254
- }
255
- });
256
- return nodeGroup;
257
- };
258
- //自动布局
259
- const handelResetLayout = () => {
260
- const { linkNodes = [], rawNodes } = formatNodeData();
261
- const { positions } = targetGraph;
262
- const nodes = linkNodes.concat(rawNodes);
263
- const edges = targetGraph.getEdges();
264
- const g = new dagre.graphlib.Graph();
265
- let alternateNum;
266
- let rawEntity;
267
- let num;
268
- let minX;
269
- let maxY;
270
- const updatePositionData = [];
271
- g.setGraph({ rankdir: 'TB', nodesep: 50, edgesep: 50, rankSep: 50, align: 'DL', controlPoints: true });
272
- const width = 250;
273
- const height = 400;
274
- nodes.forEach((node) => {
275
- g.setNode(node.id, { width, height });
276
- });
277
- edges.forEach((edge) => {
278
- const source = edge.getSource();
279
- const target = edge.getTarget();
280
- g.setEdge(source.cell, target.cell, {});
281
- });
282
- dagre.layout(g);
283
- targetGraph.freeze();
284
- const gNodes = g.nodes();
285
- const nodeWithEdges = take(gNodes, linkNodes.length);
286
- const nodeWithoutEdges = drop(gNodes, linkNodes.length);
287
- nodeWithEdges.forEach((id) => {
288
- const node = targetGraph.getCell(id);
289
- const positionId = positions.find((v) => v.collectionName === node.id)?.id;
290
- if (node) {
291
- const pos = g.node(id);
292
- updatePositionData.push({ id: positionId, x: pos.x, y: pos.y });
293
- node.position(pos?.x, pos?.y);
294
- }
295
- });
296
- if (nodeWithEdges.length) {
297
- maxY = targetGraph
298
- .getCellById(
299
- maxBy(nodeWithEdges, (k) => {
300
- return targetGraph.getCellById(k).position().y;
301
- }),
302
- )
303
- .position().y;
304
- minX = targetGraph
305
- .getCellById(
306
- minBy(nodeWithEdges, (k) => {
307
- return targetGraph.getCellById(k).position().x;
308
- }),
309
- )
310
- .position().x;
311
- const maxX = targetGraph
312
- .getCellById(
313
- maxBy(nodeWithEdges, (k) => {
314
- return targetGraph.getCellById(k).position().x;
315
- }),
316
- )
317
- .position().x;
318
- const yNodes = nodeWithEdges.filter((v) => {
319
- return Math.abs(targetGraph.getCellById(v).position().y - maxY) < 50;
320
- });
321
- const referenceNode: any = targetGraph
322
- .getCell(maxBy(yNodes, (k) => targetGraph.getCellById(k).position().x))
323
- ?.position();
324
- num = Math.round(maxX / 320) || 1;
325
- alternateNum = Math.floor((4500 - (maxX + 100 - referenceNode.x)) / 280);
326
- rawEntity = getGridData(num, rawNodes);
327
- if (alternateNum >= 1) {
328
- const alternateNodes = take(nodeWithoutEdges, alternateNum);
329
- rawEntity = getGridData(num, drop(nodeWithoutEdges, alternateNum));
330
- alternateNodes.forEach((id, index) => {
331
- const node = targetGraph.getCell(id);
332
- if (node) {
333
- const calculatedPosition = { x: referenceNode.x + 320 * index + 280, y: referenceNode.y };
334
- node.position(calculatedPosition.x, calculatedPosition.y);
335
- const positionId = positions.find((v) => v.collectionName === node.id)?.id;
336
- updatePositionData.push({ id: positionId, x: calculatedPosition.x, y: calculatedPosition.y });
337
- }
338
- });
339
- }
340
- } else {
341
- num = 15;
342
- alternateNum = 0;
343
- rawEntity = getGridData(15, rawNodes);
344
- minX = 50;
345
- maxY = 50;
346
- }
347
- rawEntity.forEach((arr, row) => {
348
- arr.forEach((id, index) => {
349
- const node = targetGraph.getCell(id);
350
- const col = index % num;
351
- if (node) {
352
- const calculatedPosition = { x: col * 325 + minX, y: row * 300 + maxY + 300 };
353
- node.position(calculatedPosition.x, calculatedPosition.y);
354
- const positionId = positions.find((v) => v.collectionName === node.id)?.id;
355
- updatePositionData.push({ id: positionId, x: calculatedPosition.x, y: calculatedPosition.y });
356
- }
357
- });
358
- });
359
- edges.forEach((edge) => {
360
- optimizeEdge(edge);
361
- });
362
- targetGraph.unfreeze();
363
- targetGraph.positionCell(nodes[0], 'top-left', { padding: 100 });
364
- targetGraph.updatePositionAction(updatePositionData, true);
365
- };
366
-
367
- export const GraphDrawPage = React.memo(() => {
368
- const { theme } = useGlobalTheme();
369
- const { styles } = useStyles();
370
- const options = useContext(SchemaOptionsContext);
371
- const ctx = useContext(CollectionManagerContext);
372
- const api = useAPIClient();
373
- const compile = useCompile();
374
- const { t } = useGCMTranslation();
375
- const [collectionData, setCollectionData] = useState<any>([]);
376
- const [collectionList, setCollectionList] = useState<any>([]);
377
- const { refreshCM } = useCollectionManager();
378
- const {
379
- data: { database },
380
- } = useCurrentAppInfo();
381
- const categoryCtx = useContext(CollectionCategroriesContext);
382
- const scope = { ...options?.scope };
383
- const components = { ...options?.components };
384
- const useSaveGraphPositionAction = async (data) => {
385
- await api.resource('graphPositions').create({ values: data });
386
- await refreshPositions();
387
- };
388
- const useUpdatePositionAction = async (data, isbatch = false) => {
389
- if (isbatch) {
390
- await api.resource('graphPositions').update({
391
- values: data,
392
- });
393
- } else {
394
- await api.resource('graphPositions').update({
395
- filter: { collectionName: data.collectionName },
396
- values: { ...data },
397
- });
398
- }
399
- await refreshPositions();
400
- };
401
- const refreshPositions = async () => {
402
- const { data } = await api.resource('graphPositions').list({ paginate: false });
403
- targetGraph.positions = data.data;
404
- return Promise.resolve();
405
- };
406
- const setTargetNode = (node) => {
407
- targetNode = node;
408
- if (node === 'destory') {
409
- refreshPositions();
410
- }
411
- };
412
- const refreshGM = async () => {
413
- const data = await refreshCM();
414
- targetGraph.collections = data;
415
- targetGraph.updatePositionAction = useUpdatePositionAction;
416
- const currentNodes = targetGraph.getNodes();
417
- setCollectionData(data);
418
- setCollectionList(data);
419
- if (!currentNodes.length) {
420
- renderInitGraphCollection(data);
421
- } else {
422
- renderDiffGraphCollection(data);
423
- }
424
- };
425
- const initGraphCollections = () => {
426
- targetGraph = new Graph({
427
- container: document.getElementById('container')!,
428
- moveThreshold: 0,
429
- scroller: {
430
- enabled: true,
431
- pannable: true,
432
- padding: { top: 0, left: 500, right: 300, bottom: 400 },
433
- },
434
- selecting: {
435
- enabled: false,
436
- multiple: true,
437
- rubberband: true,
438
- movable: true,
439
- className: 'node-selecting',
440
- modifiers: 'shift',
441
- },
442
- minimap: {
443
- enabled: true,
444
- container: document.getElementById('graph-minimap'),
445
- width: 300,
446
- height: 250,
447
- padding: 10,
448
- graphOptions: {
449
- async: true,
450
- getCellView(cell) {
451
- if (cell.isNode()) {
452
- return SimpleNodeView;
453
- }
454
- },
455
- createCellView(cell) {
456
- if (cell.isEdge()) {
457
- return null;
458
- }
459
- },
460
- },
461
- },
462
- connecting: {
463
- anchor: {
464
- name: 'midSide',
465
- },
466
- },
467
- mousewheel: {
468
- enabled: true,
469
- modifiers: ['ctrl', 'meta'],
470
- },
471
- snapline: {
472
- enabled: !0,
473
- },
474
- keyboard: {
475
- enabled: false,
476
- },
477
- clipboard: {
478
- enabled: false,
479
- },
480
- interacting: {
481
- magnetConnectable: false,
482
- },
483
- async: true,
484
- preventDefaultBlankAction: true,
485
- });
486
- targetGraph.connectionType = ConnectionType.Both;
487
- targetGraph.direction = DirectionType.Target;
488
- targetGraph.cacheCollection = {};
489
- Graph.registerPortLayout(
490
- 'erPortPosition',
491
- (portsPositionArgs) => {
492
- return portsPositionArgs.map((_, index) => {
493
- return {
494
- position: {
495
- x: 0,
496
- y: (index + 1) * LINE_HEIGHT,
497
- },
498
- angle: 0,
499
- };
500
- });
501
- },
502
- true,
503
- );
504
- Graph.registerNode(
505
- 'er-rect',
506
- {
507
- inherit: 'react-shape',
508
- component: (node) => (
509
- <CurrentAppInfoContext.Provider value={database}>
510
- <APIClientProvider apiClient={api}>
511
- <SchemaComponentOptions inherit scope={scope} components={components}>
512
- <CollectionCategroriesProvider {...categoryCtx}>
513
- <CollectionManagerProvider
514
- collections={targetGraph?.collections}
515
- refreshCM={refreshGM}
516
- interfaces={ctx.interfaces}
517
- >
518
- {/* TODO: 因为画布中的卡片是一次性注册进 Graph 的,这里的 theme 是存在闭包里的,因此当主题动态变更时,并不会触发卡片的重新渲染 */}
519
- <ConfigProvider theme={theme}>
520
- <div style={{ height: 'auto' }}>
521
- <Entity node={node} setTargetNode={setTargetNode} targetGraph={targetGraph} />
522
- </div>
523
- </ConfigProvider>
524
- </CollectionManagerProvider>
525
- </CollectionCategroriesProvider>
526
- </SchemaComponentOptions>
527
- </APIClientProvider>
528
- </CurrentAppInfoContext.Provider>
529
- ),
530
- ports: {
531
- groups: {
532
- list: {
533
- markup: [
534
- {
535
- tagName: 'rect',
536
- selector: 'portBody',
537
- },
538
- ],
539
- attrs: {
540
- portBody: {
541
- width: NODE_WIDTH,
542
- height: LINE_HEIGHT,
543
- strokeWidth: 1,
544
- // magnet: true,
545
- visibility: 'hidden',
546
- },
547
- },
548
- position: 'erPortPosition',
549
- },
550
- },
551
- },
552
- body: {
553
- refWidth: 100,
554
- refHeight: 100,
555
- },
556
- },
557
- true,
558
- );
559
- targetGraph.on('edge:mouseleave', ({ e, edge: targetEdge }) => {
560
- e.stopPropagation();
561
- handleEdgeUnActive(targetEdge);
562
- });
563
- targetGraph.on('node:moved', ({ e, node }) => {
564
- e.stopPropagation();
565
- const connectEdges = targetGraph.getConnectedEdges(node);
566
- const currentPosition = node.position();
567
- const oldPosition = targetGraph.positions.find((v) => v.collectionName === node.store.data.name);
568
- if (oldPosition) {
569
- (oldPosition.x !== currentPosition.x || oldPosition.y !== currentPosition.y) &&
570
- useUpdatePositionAction({
571
- collectionName: node.store.data.name,
572
- ...currentPosition,
573
- });
574
- } else {
575
- useSaveGraphPositionAction({
576
- collectionName: node.store.data.name,
577
- ...currentPosition,
578
- });
579
- }
580
- connectEdges.forEach((edge) => {
581
- optimizeEdge(edge);
582
- });
583
- });
584
- targetGraph.on('cell:mouseenter', ({ e, cell, edge }) => {
585
- e.stopPropagation();
586
- cell.toFront();
587
- if (edge) {
588
- handleEdgeActive(edge);
589
- }
590
- });
591
- targetGraph.on('blank:click', (e) => {
592
- if (targetGraph?.activeEdge) {
593
- handleEdgeUnActive(targetGraph?.activeEdge);
594
- }
595
- targetGraph.collapseNodes?.map((v) => {
596
- const node = targetGraph.getCell(Object.keys(v)[0]);
597
- Object.values(v)[0] && node.setData({ collapse: false });
598
- });
599
- targetGraph.cleanSelection();
600
- });
601
- targetGraph.on('node:selected', ({ e, node }) => {
602
- node.setProp({ select: true });
603
- });
604
- targetGraph.on('node:unselected', ({ e, node }) => {
605
- node.setProp({ select: false });
606
- });
607
- };
608
-
609
- const handleEdgeUnActive = (targetEdge) => {
610
- targetGraph.activeEdge = null;
611
- const { m2m, connectionType } = targetEdge.store?.data;
612
- const m2mLineId = m2m?.find((v) => v !== targetEdge.id);
613
- const m2mEdge = targetGraph.getCellById(m2mLineId);
614
- const lightsOut = (edge) => {
615
- const targeNode = targetGraph.getCellById(edge.store.data.target.cell);
616
- const sourceNode = targetGraph.getCellById(edge.store.data.source.cell);
617
- targeNode.setProp({ targetPort: false, associated: null });
618
- sourceNode.setProp({ sourcePort: false, associated: null });
619
- edge.setAttrs({
620
- line: {
621
- stroke: '#ddd',
622
- targetMarker: connectionType === ConnectionType.Inherit ? { name: 'classic', fill: '#ddd' } : null,
623
- },
624
- });
625
- edge.setLabels(
626
- edge.getLabels().map((v) => {
627
- return {
628
- ...v,
629
- attrs: {
630
- labelText: {
631
- ...v.attrs.labelText,
632
- fill: 'rgba(0, 0, 0, 0.3)',
633
- },
634
- labelBody: {
635
- ...v.attrs.labelBody,
636
- stroke: '#ddd',
637
- },
638
- },
639
- };
640
- }),
641
- );
642
- };
643
- lightsOut(targetEdge);
644
- m2mEdge && lightsOut(m2mEdge);
645
- };
646
- const handleEdgeActive = (targetEdge) => {
647
- targetGraph.activeEdge = targetEdge;
648
- const { associated, m2m, connectionType } = targetEdge.store?.data;
649
- const m2mLineId = m2m?.find((v) => v !== targetEdge.id);
650
- const m2mEdge = targetGraph.getCellById(m2mLineId);
651
- const lightUp = (edge) => {
652
- edge.toFront();
653
- edge.setAttrs({
654
- line: {
655
- stroke: '#1890ff',
656
- strokeWidth: 1,
657
- textAnchor: 'middle',
658
- textVerticalAnchor: 'middle',
659
- sourceMarker: null,
660
- targetMarker: connectionType === ConnectionType.Inherit ? { name: 'classic', fill: '#1890ff' } : null,
661
- },
662
- });
663
- edge.setLabels(
664
- edge.getLabels().map((v) => {
665
- return {
666
- ...v,
667
- attrs: {
668
- labelText: {
669
- ...v.attrs.labelText,
670
- fill: '#1890ff',
671
- },
672
- labelBody: {
673
- ...v.attrs.labelBody,
674
-
675
- stroke: '#1890ff',
676
- },
677
- },
678
- };
679
- }),
680
- );
681
- const targeNode = targetGraph.getCellById(edge.store.data.target.cell);
682
- const sourceNode = targetGraph.getCellById(edge.store.data.source.cell);
683
- targeNode.toFront();
684
- sourceNode.toFront();
685
- targeNode.setProp({
686
- targetPort: edge.store.data.target.port,
687
- associated,
688
- });
689
- sourceNode.setProp({
690
- sourcePort: edge.store.data.source.port,
691
- associated,
692
- });
693
- };
694
- lightUp(targetEdge);
695
- m2mEdge && lightUp(m2mEdge);
696
- };
697
- // 首次渲染
698
- const renderInitGraphCollection = (rawData) => {
699
- const { nodesData, edgesData, inheritEdges } = formatData(rawData);
700
- targetGraph.data = { nodes: nodesData, edges: edgesData };
701
- getNodes(nodesData);
702
- getEdges(edgesData);
703
- getEdges(inheritEdges);
704
- layout(useSaveGraphPositionAction);
705
- };
706
-
707
- // 增量渲染
708
- const renderDiffGraphCollection = (rawData) => {
709
- const { positions }: { positions: { x: number; y: number }[] } = targetGraph;
710
- const { nodesData, edgesData, inheritEdges } = formatData(rawData);
711
- const currentNodes = targetGraph.getNodes().map((v) => v.store.data);
712
- const totalEdges = targetGraph.getEdges().map((v) => v.store.data);
713
- const currentEdgesGroup = groupBy(totalEdges, (v) => {
714
- if (v.connectionType) {
715
- return 'currentInheritEdges';
716
- } else {
717
- return 'currentRelateEdges';
718
- }
719
- });
720
- const diffNodes = getDiffNode(nodesData, currentNodes);
721
- const diffEdges = getDiffEdge(edgesData, currentEdgesGroup.currentRelateEdges || []);
722
- const diffInheritEdge = getDiffEdge(inheritEdges, currentEdgesGroup.currentInheritEdges || []);
723
- diffNodes.forEach(({ status, node, port }) => {
724
- const updateNode = targetGraph.getCellById(node.id);
725
- switch (status) {
726
- case 'add':
727
- const maxY = maxBy(positions, 'y').y;
728
- const yNodes = positions.filter((v) => {
729
- return Math.abs(v.y - maxY) < 100;
730
- });
731
- let referenceNode: any = maxBy(yNodes, 'x');
732
- let position;
733
- if (referenceNode.x > 4500) {
734
- const minX = minBy(positions, 'x').x;
735
- referenceNode = minBy(yNodes, 'x');
736
- position = { x: minX, y: referenceNode.y + 400 };
737
- } else {
738
- position = { x: referenceNode.x + 350, y: referenceNode.y };
739
- }
740
- targetNode = targetGraph.addNode({
741
- ...node,
742
- position,
743
- });
744
- useSaveGraphPositionAction({
745
- collectionName: node.name,
746
- ...position,
747
- });
748
- targetGraph && targetGraph.positionCell(targetNode, 'top', { padding: 200 });
749
- break;
750
- case 'insertPort':
751
- updateNode.insertPort(port.index, port.port);
752
- break;
753
- case 'deletePort':
754
- updateNode.removePort(port.id);
755
- break;
756
- case 'updateNode':
757
- updateNode.setProp({ title: node.title });
758
- break;
759
- case 'delete':
760
- targetGraph.removeCell(node.id);
761
- default:
762
- return null;
763
- }
764
- });
765
- const renderDiffEdges = (data) => {
766
- data.forEach(({ status, edge }) => {
767
- switch (status) {
768
- case 'add':
769
- const newEdge = targetGraph.addEdge({
770
- ...edge,
771
- });
772
- optimizeEdge(newEdge);
773
- break;
774
- case 'delete':
775
- targetGraph.removeCell(edge.id);
776
- break;
777
- default:
778
- return null;
779
- }
780
- });
781
- };
782
- setTimeout(() => {
783
- renderDiffEdges(diffEdges.concat(diffInheritEdge));
784
- });
785
- };
786
-
787
- const handleSearchCollection = (e) => {
788
- const value = e.target.value.toLowerCase();
789
- if (value) {
790
- const targetCollections = collectionData.filter((v) => {
791
- const collectionTitle = compile(v.title).toLowerCase();
792
- return collectionTitle.includes(value);
793
- });
794
- setCollectionList(targetCollections);
795
- } else {
796
- setCollectionList(collectionData);
797
- }
798
- };
799
-
800
- // 处理不同方向的继承关系表
801
- const hanleHighlightInheritedNode = (key, direction) => {
802
- if (direction === DirectionType.Target) {
803
- const INodes = getInheritCollections(targetGraph.collections, key);
804
- INodes.forEach((v) => {
805
- targetGraph.getCellById(v)?.setAttrs({
806
- hightLight: true,
807
- direction,
808
- connectionType: ConnectionType.Inherit,
809
- });
810
- });
811
- } else {
812
- const INodes = getChildrenCollections(targetGraph.collections, key);
813
- INodes.forEach((v) => {
814
- targetGraph.getCellById(v.name)?.setAttrs({
815
- hightLight: true,
816
- direction,
817
- connectionType: ConnectionType.Inherit,
818
- });
819
- });
820
- }
821
- };
822
-
823
- // target index entity relation
824
- const handelTargetIndexEntity: any = (key) => {
825
- const node = targetGraph.getCellById(key);
826
- targetGraph.cacheCollection[key] = true;
827
- const connectedEdges = targetGraph.getConnectedEdges(node);
828
- const visibleEdges = connectedEdges.filter((v) => !v.store.data?.connectionType && v.getTargetCellId() === key);
829
- visibleEdges.forEach((v) => {
830
- if (v.store.data.m2m) {
831
- v.store.data.m2m.forEach((i) => {
832
- const m2mEdge = targetGraph.getCellById(i);
833
- if (m2mEdge.getTargetCellId() === key) {
834
- const sourceId = m2mEdge.getSourceCellId();
835
- const node = targetGraph.getCellById(sourceId);
836
- if (!node.store.data.attrs?.hightLight) {
837
- node.setAttrs({
838
- hightLight: true,
839
- direction: DirectionType.Target,
840
- connectionType: ConnectionType.Entity,
841
- });
842
- handelTargetIndexEntity(sourceId);
843
- }
844
- }
845
- });
846
- }
847
- const sourceId = v.getSourceCellId();
848
- const node = targetGraph.getCellById(sourceId);
849
- if (!node.store.data.attrs?.hightLight) {
850
- node.setAttrs({
851
- hightLight: true,
852
- direction: DirectionType.Target,
853
- connectionType: ConnectionType.Entity,
854
- });
855
- handelTargetIndexEntity(sourceId);
856
- }
857
- });
858
- };
859
-
860
- // source index entity relation
861
- const handelSourceIndexEntity: any = (key) => {
862
- const node = targetGraph.getCellById(key);
863
- const connectedEdges = targetGraph.getConnectedEdges(node);
864
- const visibleEdges = connectedEdges.filter((v) => !v.store.data?.connectionType && v.getSourceCellId() === key);
865
- visibleEdges.forEach((v) => {
866
- if (v.store.data.m2m) {
867
- v.store.data.m2m.forEach((i) => {
868
- const m2mEdge = targetGraph.getCellById(i);
869
- if (m2mEdge.getSourceCellId() === key) {
870
- const targetId = m2mEdge.getTargetCellId();
871
- const node = targetGraph.getCellById(targetId);
872
- if (!node.store.data.attrs?.hightLight) {
873
- node.setAttrs({
874
- hightLight: true,
875
- direction: DirectionType.Source,
876
- connectionType: ConnectionType.Entity,
877
- });
878
- handelSourceIndexEntity(targetId);
879
- }
880
- }
881
- });
882
- }
883
- const targetId = v.getTargetCellId();
884
- const node = targetGraph.getCellById(targetId);
885
- if (!node.store.data.attrs?.hightLight) {
886
- node.setAttrs({
887
- hightLight: true,
888
- direction: DirectionType.Source,
889
- connectionType: ConnectionType.Entity,
890
- });
891
- handelSourceIndexEntity(targetId);
892
- }
893
- });
894
- };
895
-
896
- // 处理不同方向的实体关系表
897
- const handleHighlightRelationNodes = (nodekey, direction) => {
898
- if (direction === DirectionType.Target) {
899
- handelTargetIndexEntity(nodekey);
900
- } else {
901
- handelSourceIndexEntity(nodekey);
902
- }
903
- };
904
- const handleCleanHighlight = (key?, currentDirection?, currentConnectionType?) => {
905
- const nodes = targetGraph.getNodes().filter((v) => v.store.data.attrs?.hightLight);
906
- const length = nodes.length;
907
- for (let i = 0; i < length; i++) {
908
- const { direction, connectionType } = nodes[i].getAttrs();
909
- const filterFlag = nodes[i].id !== key;
910
- const directionFlag = key && targetGraph.filterConfig?.key === key ? direction !== currentDirection : true;
911
- const renltionshipFlag =
912
- key && targetGraph.filterConfig?.key === key ? connectionType !== currentConnectionType : true;
913
- if (nodes[i].id !== key) {
914
- setTimeout(() => {
915
- filterFlag &&
916
- (directionFlag || renltionshipFlag) &&
917
- nodes[i].setAttrs({
918
- hightLight: false,
919
- });
920
- }, 0);
921
- }
922
- }
923
- };
924
-
925
- const handleFiterCollections = (value) => {
926
- const { connectionType, direction, filterConfig } = targetGraph;
927
- const directionBothFlag1 = value === filterConfig?.key && direction === DirectionType.Both;
928
- const relationshipBothFlag =
929
- value === filterConfig?.key &&
930
- (connectionType === ConnectionType.Both || connectionType === filterConfig.connectionType);
931
- if (value) {
932
- (!directionBothFlag1 || !relationshipBothFlag) && handleCleanHighlight(value, direction, connectionType);
933
- targetNode = targetGraph.getCellById(value);
934
- targetGraph.positionCell(targetNode, 'center', { padding: 0 });
935
- targetNode.setAttrs({
936
- hightLight: true,
937
- connectionType: connectionType,
938
- });
939
- setTimeout(() => {
940
- if ([ConnectionType.Entity, ConnectionType.Both].includes(connectionType)) {
941
- if (direction === DirectionType.Both) {
942
- handleHighlightRelationNodes(value, DirectionType.Target);
943
- handleHighlightRelationNodes(value, DirectionType.Source);
944
- } else {
945
- direction === DirectionType.Target && handleHighlightRelationNodes(value, direction);
946
- direction === DirectionType.Source && handleHighlightRelationNodes(value, direction);
947
- }
948
- }
949
- if ([ConnectionType.Inherit, ConnectionType.Both].includes(connectionType)) {
950
- if (direction === DirectionType.Both) {
951
- hanleHighlightInheritedNode(value, DirectionType.Target);
952
- hanleHighlightInheritedNode(value, DirectionType.Source);
953
- } else {
954
- hanleHighlightInheritedNode(value, direction);
955
- }
956
- }
957
- targetGraph.filterConfig = {
958
- key: value,
959
- direction: direction,
960
- connectionType,
961
- };
962
- }, 0);
963
- } else {
964
- handleCleanHighlight();
965
- }
966
- };
967
-
968
- const handleSetRelationshipType = (type) => {
969
- handleSetEdgeVisible(type);
970
- };
971
-
972
- const handleSetEdgeVisible = (type) => {
973
- targetNode = null;
974
- const edges = targetGraph.getEdges();
975
- edges.forEach((v) => {
976
- const {
977
- store: {
978
- data: { connectionType },
979
- },
980
- } = v;
981
- if (type === ConnectionType.Entity) {
982
- if (connectionType) {
983
- v.setVisible(false);
984
- } else {
985
- v.setVisible(true);
986
- }
987
- } else if (type === ConnectionType.Inherit) {
988
- if (!connectionType) {
989
- v.setVisible(false);
990
- } else {
991
- v.setVisible(true);
992
- }
993
- } else {
994
- v.setVisible(true);
995
- }
996
- });
997
- };
998
-
999
- useLayoutEffect(() => {
1000
- initGraphCollections();
1001
- return () => {
1002
- targetGraph.off('cell:mouseenter');
1003
- targetGraph.off('edge:mouseleave');
1004
- targetGraph.off('node:moved');
1005
- targetGraph.off('blank:click');
1006
- targetGraph = null;
1007
- targetNode = null;
1008
- };
1009
- }, []);
1010
-
1011
- useEffect(() => {
1012
- refreshPositions().then(() => {
1013
- refreshGM();
1014
- });
1015
- }, []);
1016
- const loadCollections = async () => {
1017
- return targetGraph.collections?.map((collection: any) => ({
1018
- label: compile(collection.title),
1019
- value: collection.name,
1020
- }));
1021
- };
1022
- return (
1023
- <Layout>
1024
- <div className={styles.graphCollectionContainerClass}>
1025
- <CollectionManagerProvider collections={targetGraph?.collections} refreshCM={refreshGM}>
1026
- <CollapsedContext.Provider value={{ collectionList, handleSearchCollection }}>
1027
- <div className={cx(styles.collectionListClass)}>
1028
- <SchemaComponent
1029
- components={{
1030
- Select: (props) => (
1031
- <Select popupMatchSelectWidth={false} {...props} getPopupContainer={getPopupContainer} />
1032
- ),
1033
- AddCollectionAction,
1034
- }}
1035
- schema={{
1036
- type: 'void',
1037
- properties: {
1038
- block1: {
1039
- type: 'void',
1040
- 'x-collection': 'collections',
1041
- 'x-decorator': 'ResourceActionProvider',
1042
- 'x-decorator-props': {
1043
- collection,
1044
- request: {
1045
- resource: 'collections',
1046
- action: 'list',
1047
- params: {
1048
- pageSize: 50,
1049
- filter: {
1050
- inherit: false,
1051
- },
1052
- sort: ['sort'],
1053
- appends: [],
1054
- },
1055
- },
1056
- },
1057
- properties: {
1058
- actions: {
1059
- type: 'void',
1060
- 'x-component': 'ActionBar',
1061
- 'x-component-props': {
1062
- style: {
1063
- fontSize: 16,
1064
- },
1065
- },
1066
- properties: {
1067
- create: {
1068
- type: 'void',
1069
- title: '{{ t("Create collection") }}',
1070
- 'x-component': 'AddCollectionAction',
1071
- 'x-component-props': {
1072
- type: 'primary',
1073
- },
1074
- },
1075
- fullScreen: {
1076
- type: 'void',
1077
- 'x-component': 'Action',
1078
- 'x-component-props': {
1079
- component: forwardRef(() => {
1080
- const [isFullscreen, { toggleFullscreen }] = useFullscreen(
1081
- document.getElementById('graph_container'),
1082
- );
1083
- return (
1084
- <Tooltip title={t('Full Screen')} getPopupContainer={getPopupContainer}>
1085
- <Button
1086
- onClick={() => {
1087
- toggleFullscreen();
1088
- }}
1089
- >
1090
- {isFullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
1091
- </Button>
1092
- </Tooltip>
1093
- );
1094
- }),
1095
- useAction: () => {
1096
- return {
1097
- run() {},
1098
- };
1099
- },
1100
- },
1101
- },
1102
- collectionList: {
1103
- type: 'void',
1104
- 'x-component': function Com() {
1105
- const { handleSearchCollection, collectionList } = useContext(CollapsedContext);
1106
- const [selectedKeys, setSelectKey] = useState([]);
1107
- const content = (
1108
- <div>
1109
- <Input
1110
- style={{ margin: '4px 0' }}
1111
- bordered={false}
1112
- placeholder={t('Collection Search')}
1113
- onChange={handleSearchCollection}
1114
- />
1115
- <Menu
1116
- selectedKeys={selectedKeys}
1117
- selectable={true}
1118
- className={css`
1119
- .ant-menu-item {
1120
- height: 32px;
1121
- line-height: 32px;
1122
- }
1123
- `}
1124
- style={{ maxHeight: '70vh', overflowY: 'auto', border: 'none' }}
1125
- items={[
1126
- { type: 'divider' },
1127
- ...collectionList.map((v) => {
1128
- return {
1129
- key: v.name,
1130
- label: compile(v.title),
1131
- onClick: (e: any) => {
1132
- if (e.key !== selectedKeys[0]) {
1133
- setSelectKey([e.key]);
1134
- handleFiterCollections(e.key);
1135
- } else {
1136
- targetGraph.filterConfig = null;
1137
- handleFiterCollections(false);
1138
- setSelectKey([]);
1139
- }
1140
- },
1141
- };
1142
- }),
1143
- ]}
1144
- />
1145
- </div>
1146
- );
1147
- return (
1148
- <Popover
1149
- content={content}
1150
- autoAdjustOverflow
1151
- placement="bottomRight"
1152
- trigger={['click']}
1153
- getPopupContainer={getPopupContainer}
1154
- overlayClassName={css`
1155
- .ant-popover-inner-content {
1156
- padding: 0;
1157
- }
1158
- `}
1159
- >
1160
- <Button>
1161
- <MenuOutlined />
1162
- </Button>
1163
- </Popover>
1164
- );
1165
- },
1166
- 'x-component-props': {
1167
- icon: 'MenuOutlined',
1168
- useAction: () => {
1169
- return {
1170
- run() {},
1171
- };
1172
- },
1173
- },
1174
- },
1175
- autoLayout: {
1176
- type: 'void',
1177
- 'x-component': 'Action',
1178
- 'x-component-props': {
1179
- component: forwardRef(() => {
1180
- return (
1181
- <Tooltip title={t('Auto layout')} getPopupContainer={getPopupContainer}>
1182
- <Button
1183
- onClick={() => {
1184
- handelResetLayout();
1185
- }}
1186
- >
1187
- <ApartmentOutlined />
1188
- </Button>
1189
- </Tooltip>
1190
- );
1191
- }),
1192
- useAction: () => {
1193
- return {
1194
- run() {},
1195
- };
1196
- },
1197
- },
1198
- },
1199
- connectionType: {
1200
- type: 'void',
1201
- 'x-component': () => {
1202
- const menuItems = [
1203
- {
1204
- key: ConnectionType.Both,
1205
- label: 'All relationships',
1206
- },
1207
- {
1208
- key: ConnectionType.Entity,
1209
- label: 'Entity relationship only',
1210
- },
1211
- {
1212
- key: ConnectionType.Inherit,
1213
- label: 'Inheritance relationship only',
1214
- },
1215
- ];
1216
- const content = (
1217
- <div>
1218
- <Menu
1219
- defaultSelectedKeys={[ConnectionType.Both]}
1220
- selectable={true}
1221
- className={css`
1222
- .ant-menu-item {
1223
- height: 32px;
1224
- line-height: 32px;
1225
- }
1226
- `}
1227
- style={{ maxHeight: '70vh', overflowY: 'auto', border: 'none' }}
1228
- items={[
1229
- { type: 'divider' },
1230
- ...menuItems.map((v) => {
1231
- return {
1232
- key: v.key,
1233
- label: t(v.label),
1234
- onClick: (e: any) => {
1235
- targetGraph.connectionType = v.key;
1236
- const { filterConfig } = targetGraph;
1237
- filterConfig && handleFiterCollections(filterConfig.key);
1238
- handleSetRelationshipType(v.key);
1239
- },
1240
- };
1241
- }),
1242
- ]}
1243
- />
1244
- </div>
1245
- );
1246
- return (
1247
- <Popover
1248
- content={content}
1249
- autoAdjustOverflow
1250
- placement="bottomRight"
1251
- trigger={['click']}
1252
- getPopupContainer={getPopupContainer}
1253
- overlayClassName={css`
1254
- .ant-popover-inner-content {
1255
- padding: 0;
1256
- }
1257
- `}
1258
- >
1259
- <Button>
1260
- <ShareAltOutlined />
1261
- </Button>
1262
- </Popover>
1263
- );
1264
- },
1265
- 'x-component-props': {
1266
- icon: 'MenuOutlined',
1267
- useAction: () => {
1268
- return {
1269
- run() {},
1270
- };
1271
- },
1272
- },
1273
- },
1274
- direction: {
1275
- type: 'void',
1276
- 'x-component': () => {
1277
- const menuItems = [
1278
- {
1279
- key: DirectionType.Both,
1280
- label: 'All directions',
1281
- },
1282
- {
1283
- key: DirectionType.Target,
1284
- label: 'Target index',
1285
- },
1286
- {
1287
- key: DirectionType.Source,
1288
- label: 'Source index',
1289
- },
1290
- ];
1291
- const content = (
1292
- <div>
1293
- <Menu
1294
- defaultSelectedKeys={[DirectionType.Target]}
1295
- selectable={true}
1296
- className={css`
1297
- .ant-menu-item {
1298
- height: 32px;
1299
- line-height: 32px;
1300
- }
1301
- `}
1302
- style={{ maxHeight: '70vh', overflowY: 'auto', border: 'none' }}
1303
- items={[
1304
- { type: 'divider' },
1305
- ...menuItems.map((v) => {
1306
- return {
1307
- key: v.key,
1308
- label: t(v.label),
1309
- onClick: (e: any) => {
1310
- targetGraph.direction = v.key;
1311
- const { filterConfig } = targetGraph;
1312
- if (filterConfig) {
1313
- handleFiterCollections(filterConfig.key);
1314
- }
1315
- },
1316
- };
1317
- }),
1318
- ]}
1319
- />
1320
- </div>
1321
- );
1322
- return (
1323
- <Popover
1324
- content={content}
1325
- autoAdjustOverflow
1326
- placement="bottomRight"
1327
- trigger={['click']}
1328
- getPopupContainer={getPopupContainer}
1329
- overlayClassName={css`
1330
- .ant-popover-inner-content {
1331
- padding: 0;
1332
- }
1333
- `}
1334
- >
1335
- <Button>
1336
- <LineHeightOutlined />
1337
- </Button>
1338
- </Popover>
1339
- );
1340
- },
1341
- },
1342
- selectMode: {
1343
- type: 'void',
1344
- 'x-component': () => {
1345
- return (
1346
- <Tooltip title={t('Selection')}>
1347
- <Switch
1348
- onChange={(value) => {
1349
- targetGraph.toggleSelection();
1350
- }}
1351
- />
1352
- </Tooltip>
1353
- );
1354
- },
1355
- },
1356
- },
1357
- },
1358
- },
1359
- },
1360
- },
1361
- }}
1362
- scope={{
1363
- useAsyncDataSource,
1364
- loadCollections,
1365
- useCreateActionAndRefreshCM: () => useCreateActionAndRefreshCM(setTargetNode),
1366
- enableInherits: database?.dialect === 'postgres',
1367
- }}
1368
- />
1369
- </div>
1370
- </CollapsedContext.Provider>
1371
- </CollectionManagerProvider>
1372
- <div id="container" style={{ width: '100vw', height: '100vh' }}></div>
1373
- <div
1374
- id="graph-minimap"
1375
- className={styles.graphMinimap}
1376
- style={{ width: '300px', height: '250px', right: '10px', bottom: '20px', position: 'fixed' }}
1377
- ></div>
1378
- </div>
1379
- </Layout>
1380
- );
1381
- });
1382
- GraphDrawPage.displayName = 'GraphDrawPage';