@flowgram.ai/free-node-panel-plugin 0.1.18 → 0.1.22
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/dist/esm/index.js +365 -266
- package/dist/esm/index.js.map +1 -1
- package/dist/index.d.mts +92 -23
- package/dist/index.d.ts +92 -23
- package/dist/index.js +370 -269
- package/dist/index.js.map +1 -1
- package/package.json +10 -9
package/dist/esm/index.js
CHANGED
|
@@ -10,26 +10,135 @@ var __decorateClass = (decorators, target, key, kind) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
// src/create-plugin.ts
|
|
13
|
-
import {
|
|
14
|
-
definePluginCreator
|
|
15
|
-
} from "@flowgram.ai/core";
|
|
13
|
+
import { definePluginCreator } from "@flowgram.ai/core";
|
|
16
14
|
|
|
17
15
|
// src/service.ts
|
|
18
16
|
import { inject, injectable } from "inversify";
|
|
19
|
-
import {
|
|
17
|
+
import { DisposableCollection } from "@flowgram.ai/utils";
|
|
20
18
|
import {
|
|
21
19
|
WorkflowDocument,
|
|
22
20
|
WorkflowDragService,
|
|
23
|
-
WorkflowLinesManager
|
|
24
|
-
WorkflowNodePortsData
|
|
21
|
+
WorkflowLinesManager as WorkflowLinesManager2
|
|
25
22
|
} from "@flowgram.ai/free-layout-core";
|
|
26
23
|
import { WorkflowSelectService } from "@flowgram.ai/free-layout-core";
|
|
27
|
-
import {
|
|
28
|
-
import { FlowNodeTransformData } from "@flowgram.ai/document";
|
|
24
|
+
import { HistoryService as HistoryService2 } from "@flowgram.ai/free-history-plugin";
|
|
29
25
|
import { PlaygroundConfigEntity } from "@flowgram.ai/core";
|
|
26
|
+
|
|
27
|
+
// src/utils/wait-node-render.ts
|
|
28
|
+
import { delay } from "@flowgram.ai/free-layout-core";
|
|
29
|
+
var waitNodeRender = async () => {
|
|
30
|
+
await delay(20);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// src/utils/update-sub-nodes-position.ts
|
|
34
|
+
import { FreeOperationType } from "@flowgram.ai/free-history-plugin";
|
|
30
35
|
import { TransformData } from "@flowgram.ai/core";
|
|
31
36
|
|
|
32
|
-
// src/utils.ts
|
|
37
|
+
// src/utils/get-port-box.ts
|
|
38
|
+
import { Rectangle } from "@flowgram.ai/utils";
|
|
39
|
+
import { FlowNodeTransformData } from "@flowgram.ai/document";
|
|
40
|
+
|
|
41
|
+
// src/utils/is-container.ts
|
|
42
|
+
var isContainer = (node) => node?.getNodeMeta().isContainer ?? false;
|
|
43
|
+
|
|
44
|
+
// src/utils/get-port-box.ts
|
|
45
|
+
var getPortBox = (port, offset = { x: 0, y: 0 }) => {
|
|
46
|
+
const node = port.node;
|
|
47
|
+
if (isContainer(node)) {
|
|
48
|
+
const { point } = port;
|
|
49
|
+
if (port.portType === "input") {
|
|
50
|
+
return new Rectangle(point.x + offset.x, point.y - 50 + offset.y, 300, 100);
|
|
51
|
+
}
|
|
52
|
+
return new Rectangle(point.x - 300, point.y - 50, 300, 100);
|
|
53
|
+
}
|
|
54
|
+
const box = node.getData(FlowNodeTransformData).bounds;
|
|
55
|
+
return box;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// src/utils/update-sub-nodes-position.ts
|
|
59
|
+
var updateSubSequentNodesPosition = (params) => {
|
|
60
|
+
const {
|
|
61
|
+
node,
|
|
62
|
+
subsequentNodes,
|
|
63
|
+
fromPort,
|
|
64
|
+
toPort,
|
|
65
|
+
containerNode,
|
|
66
|
+
offset,
|
|
67
|
+
historyService,
|
|
68
|
+
dragService
|
|
69
|
+
} = params;
|
|
70
|
+
if (!offset || !toPort) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const subsequentNodesPositions = subsequentNodes.map((node2) => {
|
|
74
|
+
const nodeTrans2 = node2.getData(TransformData);
|
|
75
|
+
return {
|
|
76
|
+
x: nodeTrans2.position.x,
|
|
77
|
+
y: nodeTrans2.position.y
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
historyService.pushOperation({
|
|
81
|
+
type: FreeOperationType.dragNodes,
|
|
82
|
+
value: {
|
|
83
|
+
ids: subsequentNodes.map((node2) => node2.id),
|
|
84
|
+
value: subsequentNodesPositions.map((position) => ({
|
|
85
|
+
x: position.x + offset.x,
|
|
86
|
+
y: position.y + offset.y
|
|
87
|
+
})),
|
|
88
|
+
oldValue: subsequentNodesPositions
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
const fromBox = getPortBox(fromPort);
|
|
92
|
+
const toBox = getPortBox(toPort, offset);
|
|
93
|
+
const nodeTrans = node.getData(TransformData);
|
|
94
|
+
let nodePos = {
|
|
95
|
+
x: (fromBox.center.x + toBox.center.x) / 2,
|
|
96
|
+
y: (fromBox.y + toBox.y) / 2
|
|
97
|
+
};
|
|
98
|
+
if (containerNode) {
|
|
99
|
+
nodePos = dragService.adjustSubNodePosition(
|
|
100
|
+
node.flowNodeType,
|
|
101
|
+
containerNode,
|
|
102
|
+
nodePos
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
historyService.pushOperation({
|
|
106
|
+
type: FreeOperationType.dragNodes,
|
|
107
|
+
value: {
|
|
108
|
+
ids: [node.id],
|
|
109
|
+
value: [nodePos],
|
|
110
|
+
oldValue: [
|
|
111
|
+
{
|
|
112
|
+
x: nodeTrans.position.x,
|
|
113
|
+
y: nodeTrans.position.y
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
// src/utils/sub-position-offset.ts
|
|
121
|
+
import { Rectangle as Rectangle3 } from "@flowgram.ai/utils";
|
|
122
|
+
import { FlowNodeTransformData as FlowNodeTransformData2 } from "@flowgram.ai/document";
|
|
123
|
+
|
|
124
|
+
// src/utils/rect-distance.ts
|
|
125
|
+
import { Rectangle as Rectangle2 } from "@flowgram.ai/utils";
|
|
126
|
+
var rectDistance = (rectA, rectB) => {
|
|
127
|
+
const distanceX = Math.abs(Math.min(rectA.right, rectB.right) - Math.max(rectA.left, rectB.left));
|
|
128
|
+
const distanceY = Math.abs(Math.min(rectA.bottom, rectB.bottom) - Math.max(rectA.top, rectB.top));
|
|
129
|
+
if (Rectangle2.intersects(rectA, rectB)) {
|
|
130
|
+
return {
|
|
131
|
+
x: -distanceX,
|
|
132
|
+
y: -distanceY
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
x: distanceX,
|
|
137
|
+
y: distanceY
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// src/utils/greater-or-less.ts
|
|
33
142
|
var isGreaterThan = (a, b) => {
|
|
34
143
|
if (a === void 0 || b === void 0) {
|
|
35
144
|
return false;
|
|
@@ -45,6 +154,213 @@ var isLessThan = (a, b) => {
|
|
|
45
154
|
return b - a > EPSILON;
|
|
46
155
|
};
|
|
47
156
|
|
|
157
|
+
// src/utils/sub-position-offset.ts
|
|
158
|
+
var subPositionOffset = (params) => {
|
|
159
|
+
const { node, fromPort, toPort, padding } = params;
|
|
160
|
+
const fromBox = getPortBox(fromPort);
|
|
161
|
+
const toBox = getPortBox(toPort);
|
|
162
|
+
const nodeTrans = node.getData(FlowNodeTransformData2);
|
|
163
|
+
const nodeSize = node.getNodeMeta()?.size ?? {
|
|
164
|
+
width: nodeTrans.bounds.width,
|
|
165
|
+
height: nodeTrans.bounds.height
|
|
166
|
+
};
|
|
167
|
+
const minDistance = {
|
|
168
|
+
x: nodeSize.width + padding.x,
|
|
169
|
+
y: nodeSize.height + padding.y
|
|
170
|
+
};
|
|
171
|
+
const boxDistance = rectDistance(fromBox, toBox);
|
|
172
|
+
const neededOffset = {
|
|
173
|
+
x: isGreaterThan(boxDistance.x, minDistance.x) ? 0 : minDistance.x - boxDistance.x,
|
|
174
|
+
y: isGreaterThan(boxDistance.y, minDistance.y) ? 0 : minDistance.y - boxDistance.y
|
|
175
|
+
};
|
|
176
|
+
if (neededOffset.x === 0 || neededOffset.y === 0) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const intersection = {
|
|
180
|
+
// 这里没有写反,Rectangle内置的算法是反的
|
|
181
|
+
vertical: Rectangle3.intersects(fromBox, toBox, "horizontal"),
|
|
182
|
+
horizontal: Rectangle3.intersects(fromBox, toBox, "vertical")
|
|
183
|
+
};
|
|
184
|
+
let offsetX = 0;
|
|
185
|
+
let offsetY = 0;
|
|
186
|
+
if (!intersection.horizontal) {
|
|
187
|
+
if (isGreaterThan(toBox.center.y, fromBox.center.y)) {
|
|
188
|
+
offsetY = neededOffset.y;
|
|
189
|
+
} else if (isLessThan(toBox.center.y, fromBox.center.y)) {
|
|
190
|
+
offsetY = -neededOffset.y;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (!intersection.vertical) {
|
|
194
|
+
if (isGreaterThan(toBox.center.x, fromBox.center.x)) {
|
|
195
|
+
offsetX = neededOffset.x;
|
|
196
|
+
} else if (isLessThan(toBox.center.x, fromBox.center.x)) {
|
|
197
|
+
offsetX = -neededOffset.x;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
x: offsetX,
|
|
202
|
+
y: offsetY
|
|
203
|
+
};
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// src/utils/get-sub-nodes.ts
|
|
207
|
+
var getSubsequentNodes = (params) => {
|
|
208
|
+
const { node, linesManager } = params;
|
|
209
|
+
if (isContainer(node)) {
|
|
210
|
+
return [];
|
|
211
|
+
}
|
|
212
|
+
const brothers = node.parent?.blocks ?? [];
|
|
213
|
+
const linkedBrothers = /* @__PURE__ */ new Set();
|
|
214
|
+
const linesMap = /* @__PURE__ */ new Map();
|
|
215
|
+
linesManager.getAllLines().forEach((line) => {
|
|
216
|
+
if (!linesMap.has(line.from.id)) {
|
|
217
|
+
linesMap.set(line.from.id, []);
|
|
218
|
+
}
|
|
219
|
+
if (!line.to?.id || isContainer(line.to)) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
linesMap.get(line.from.id)?.push(line.to.id);
|
|
223
|
+
});
|
|
224
|
+
const bfs = (nodeId) => {
|
|
225
|
+
if (linkedBrothers.has(nodeId)) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
linkedBrothers.add(nodeId);
|
|
229
|
+
const nextNodes = linesMap.get(nodeId) ?? [];
|
|
230
|
+
nextNodes.forEach(bfs);
|
|
231
|
+
};
|
|
232
|
+
bfs(node.id);
|
|
233
|
+
const subsequentNodes = brothers.filter((node2) => linkedBrothers.has(node2.id));
|
|
234
|
+
return subsequentNodes;
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
// src/utils/sub-nodes-auto-offset.ts
|
|
238
|
+
var subNodesAutoOffset = (params) => {
|
|
239
|
+
const {
|
|
240
|
+
node,
|
|
241
|
+
fromPort,
|
|
242
|
+
toPort,
|
|
243
|
+
linesManager,
|
|
244
|
+
historyService,
|
|
245
|
+
dragService,
|
|
246
|
+
containerNode,
|
|
247
|
+
padding = {
|
|
248
|
+
x: 100,
|
|
249
|
+
y: 100
|
|
250
|
+
}
|
|
251
|
+
} = params;
|
|
252
|
+
const subOffset = subPositionOffset({
|
|
253
|
+
node,
|
|
254
|
+
fromPort,
|
|
255
|
+
toPort,
|
|
256
|
+
padding
|
|
257
|
+
});
|
|
258
|
+
const subsequentNodes = getSubsequentNodes({
|
|
259
|
+
node: toPort.node,
|
|
260
|
+
linesManager
|
|
261
|
+
});
|
|
262
|
+
updateSubSequentNodesPosition({
|
|
263
|
+
node,
|
|
264
|
+
subsequentNodes,
|
|
265
|
+
fromPort,
|
|
266
|
+
toPort,
|
|
267
|
+
containerNode,
|
|
268
|
+
offset: subOffset,
|
|
269
|
+
historyService,
|
|
270
|
+
dragService
|
|
271
|
+
});
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
// src/utils/get-container-node.ts
|
|
275
|
+
var getContainerNode = (params) => {
|
|
276
|
+
const { fromPort, containerNode } = params;
|
|
277
|
+
if (containerNode) {
|
|
278
|
+
return containerNode;
|
|
279
|
+
}
|
|
280
|
+
const fromNode = fromPort?.node;
|
|
281
|
+
const fromContainer = fromNode?.parent;
|
|
282
|
+
if (isContainer(fromNode)) {
|
|
283
|
+
return fromNode;
|
|
284
|
+
}
|
|
285
|
+
return fromContainer;
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
// src/utils/build-line.ts
|
|
289
|
+
import {
|
|
290
|
+
WorkflowNodePortsData
|
|
291
|
+
} from "@flowgram.ai/free-layout-core";
|
|
292
|
+
var buildLine = (params) => {
|
|
293
|
+
const { fromPort, node, toPort, linesManager } = params;
|
|
294
|
+
const portsData = node.getData(WorkflowNodePortsData);
|
|
295
|
+
if (!portsData) {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const shouldBuildFromLine = portsData.inputPorts?.length > 0;
|
|
299
|
+
if (fromPort && shouldBuildFromLine) {
|
|
300
|
+
const toTargetPort = portsData.inputPorts[0];
|
|
301
|
+
const isSingleInput = portsData.inputPorts.length === 1;
|
|
302
|
+
linesManager.createLine({
|
|
303
|
+
from: fromPort.node.id,
|
|
304
|
+
fromPort: fromPort.portID,
|
|
305
|
+
to: node.id,
|
|
306
|
+
toPort: isSingleInput ? void 0 : toTargetPort.id
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
const shouldBuildToLine = portsData.outputPorts?.length > 0;
|
|
310
|
+
if (toPort && shouldBuildToLine) {
|
|
311
|
+
const fromTargetPort = portsData.outputPorts[0];
|
|
312
|
+
linesManager.createLine({
|
|
313
|
+
from: node.id,
|
|
314
|
+
fromPort: fromTargetPort.portID,
|
|
315
|
+
to: toPort.node.id,
|
|
316
|
+
toPort: toPort.portID
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
// src/utils/adjust-node-position.ts
|
|
322
|
+
var adjustNodePosition = (params) => {
|
|
323
|
+
const { nodeType, position, fromPort, toPort, containerNode, document, dragService } = params;
|
|
324
|
+
const register = document.getNodeRegistry(nodeType);
|
|
325
|
+
const size = register?.meta?.size;
|
|
326
|
+
let adjustedPosition = position;
|
|
327
|
+
if (!size) {
|
|
328
|
+
adjustedPosition = position;
|
|
329
|
+
} else if (fromPort && toPort) {
|
|
330
|
+
adjustedPosition = {
|
|
331
|
+
x: position.x,
|
|
332
|
+
y: position.y - size.height / 2
|
|
333
|
+
};
|
|
334
|
+
} else if (fromPort && !toPort) {
|
|
335
|
+
adjustedPosition = {
|
|
336
|
+
x: position.x + size.width / 2,
|
|
337
|
+
y: position.y - size.height / 2
|
|
338
|
+
};
|
|
339
|
+
} else if (!fromPort && toPort) {
|
|
340
|
+
adjustedPosition = {
|
|
341
|
+
x: position.x - size.width / 2,
|
|
342
|
+
y: position.y - size.height / 2
|
|
343
|
+
};
|
|
344
|
+
} else {
|
|
345
|
+
adjustedPosition = position;
|
|
346
|
+
}
|
|
347
|
+
return dragService.adjustSubNodePosition(nodeType, containerNode, adjustedPosition);
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
// src/utils/index.ts
|
|
351
|
+
var WorkflowNodePanelUtils = {
|
|
352
|
+
adjustNodePosition,
|
|
353
|
+
buildLine,
|
|
354
|
+
getPortBox,
|
|
355
|
+
getSubsequentNodes,
|
|
356
|
+
getContainerNode,
|
|
357
|
+
rectDistance,
|
|
358
|
+
subNodesAutoOffset,
|
|
359
|
+
subPositionOffset,
|
|
360
|
+
updateSubSequentNodesPosition,
|
|
361
|
+
waitNodeRender
|
|
362
|
+
};
|
|
363
|
+
|
|
48
364
|
// src/service.ts
|
|
49
365
|
var WorkflowNodePanelService = class {
|
|
50
366
|
constructor() {
|
|
@@ -77,7 +393,7 @@ var WorkflowNodePanelService = class {
|
|
|
77
393
|
position: panelPosition,
|
|
78
394
|
enableMultiAdd,
|
|
79
395
|
panelProps,
|
|
80
|
-
containerNode:
|
|
396
|
+
containerNode: WorkflowNodePanelUtils.getContainerNode({
|
|
81
397
|
fromPort,
|
|
82
398
|
containerNode
|
|
83
399
|
}),
|
|
@@ -96,6 +412,23 @@ var WorkflowNodePanelService = class {
|
|
|
96
412
|
});
|
|
97
413
|
});
|
|
98
414
|
}
|
|
415
|
+
/**
|
|
416
|
+
* 唤起单选面板
|
|
417
|
+
*/
|
|
418
|
+
async singleSelectNodePanel(params) {
|
|
419
|
+
return new Promise((resolve) => {
|
|
420
|
+
this.callNodePanel({
|
|
421
|
+
...params,
|
|
422
|
+
enableMultiAdd: false,
|
|
423
|
+
onSelect: async (panelParams) => {
|
|
424
|
+
resolve(panelParams);
|
|
425
|
+
},
|
|
426
|
+
onClose: () => {
|
|
427
|
+
resolve(void 0);
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
});
|
|
431
|
+
}
|
|
99
432
|
/** 添加节点 */
|
|
100
433
|
async addNode(callParams, panelParams) {
|
|
101
434
|
const {
|
|
@@ -116,7 +449,7 @@ var WorkflowNodePanelService = class {
|
|
|
116
449
|
return;
|
|
117
450
|
}
|
|
118
451
|
const { nodeType, selectEvent, nodeJSON } = panelParams;
|
|
119
|
-
const containerNode =
|
|
452
|
+
const containerNode = WorkflowNodePanelUtils.getContainerNode({
|
|
120
453
|
fromPort,
|
|
121
454
|
containerNode: callParams.containerNode
|
|
122
455
|
});
|
|
@@ -127,14 +460,16 @@ var WorkflowNodePanelService = class {
|
|
|
127
460
|
}
|
|
128
461
|
}
|
|
129
462
|
const selectPosition = this.playgroundConfig.getPosFromMouseEvent(selectEvent);
|
|
130
|
-
const nodePosition = callParams.customPosition ? callParams.customPosition({ nodeType, selectPosition }) :
|
|
463
|
+
const nodePosition = callParams.customPosition ? callParams.customPosition({ nodeType, selectPosition }) : WorkflowNodePanelUtils.adjustNodePosition({
|
|
131
464
|
nodeType,
|
|
132
465
|
position: enableSelectPosition ? selectPosition : panelPosition,
|
|
133
466
|
fromPort,
|
|
134
467
|
toPort,
|
|
135
|
-
containerNode
|
|
468
|
+
containerNode,
|
|
469
|
+
document: this.document,
|
|
470
|
+
dragService: this.dragService
|
|
136
471
|
});
|
|
137
|
-
const node =
|
|
472
|
+
const node = this.document.createWorkflowNodeByType(
|
|
138
473
|
nodeType,
|
|
139
474
|
nodePosition,
|
|
140
475
|
nodeJSON ?? {},
|
|
@@ -144,31 +479,27 @@ var WorkflowNodePanelService = class {
|
|
|
144
479
|
return;
|
|
145
480
|
}
|
|
146
481
|
if (enableAutoOffset && fromPort && toPort) {
|
|
147
|
-
|
|
482
|
+
WorkflowNodePanelUtils.subNodesAutoOffset({
|
|
148
483
|
node,
|
|
149
484
|
fromPort,
|
|
150
485
|
toPort,
|
|
151
|
-
padding: autoOffsetPadding
|
|
152
|
-
});
|
|
153
|
-
const subsequentNodes = this.getSubsequentNodes(toPort.node);
|
|
154
|
-
this.updateSubSequentNodesPosition({
|
|
155
|
-
node,
|
|
156
|
-
subsequentNodes,
|
|
157
|
-
fromPort,
|
|
158
|
-
toPort,
|
|
486
|
+
padding: autoOffsetPadding,
|
|
159
487
|
containerNode,
|
|
160
|
-
|
|
488
|
+
historyService: this.historyService,
|
|
489
|
+
dragService: this.dragService,
|
|
490
|
+
linesManager: this.linesManager
|
|
161
491
|
});
|
|
162
492
|
}
|
|
163
493
|
if (!enableBuildLine && !enableDragNode) {
|
|
164
494
|
return node;
|
|
165
495
|
}
|
|
166
|
-
await
|
|
496
|
+
await WorkflowNodePanelUtils.waitNodeRender();
|
|
167
497
|
if (enableBuildLine) {
|
|
168
|
-
|
|
498
|
+
WorkflowNodePanelUtils.buildLine({
|
|
169
499
|
fromPort,
|
|
170
500
|
node,
|
|
171
|
-
toPort
|
|
501
|
+
toPort,
|
|
502
|
+
linesManager: this.linesManager
|
|
172
503
|
});
|
|
173
504
|
}
|
|
174
505
|
if (enableDragNode) {
|
|
@@ -177,240 +508,6 @@ var WorkflowNodePanelService = class {
|
|
|
177
508
|
}
|
|
178
509
|
return node;
|
|
179
510
|
}
|
|
180
|
-
/** 建立连线 */
|
|
181
|
-
buildLine(params) {
|
|
182
|
-
const { fromPort, node, toPort } = params;
|
|
183
|
-
const portsData = node.getData(WorkflowNodePortsData);
|
|
184
|
-
if (!portsData) {
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
const shouldBuildFromLine = portsData.inputPorts?.length > 0;
|
|
188
|
-
if (fromPort && shouldBuildFromLine) {
|
|
189
|
-
const toTargetPort = portsData.inputPorts[0];
|
|
190
|
-
const isSingleInput = portsData.inputPorts.length === 1;
|
|
191
|
-
this.linesManager.createLine({
|
|
192
|
-
from: fromPort.node.id,
|
|
193
|
-
fromPort: fromPort.portID,
|
|
194
|
-
to: node.id,
|
|
195
|
-
toPort: isSingleInput ? void 0 : toTargetPort.id
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
const shouldBuildToLine = portsData.outputPorts?.length > 0;
|
|
199
|
-
if (toPort && shouldBuildToLine) {
|
|
200
|
-
const fromTargetPort = portsData.outputPorts[0];
|
|
201
|
-
this.linesManager.createLine({
|
|
202
|
-
from: node.id,
|
|
203
|
-
fromPort: fromTargetPort.portID,
|
|
204
|
-
to: toPort.node.id,
|
|
205
|
-
toPort: toPort.portID
|
|
206
|
-
});
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
/** 调整节点坐标 */
|
|
210
|
-
adjustNodePosition(params) {
|
|
211
|
-
const { nodeType, position, fromPort, toPort, containerNode } = params;
|
|
212
|
-
const register = this.document.getNodeRegistry(nodeType);
|
|
213
|
-
const size = register?.meta?.size;
|
|
214
|
-
let adjustedPosition = position;
|
|
215
|
-
if (!size) {
|
|
216
|
-
adjustedPosition = position;
|
|
217
|
-
} else if (fromPort && toPort) {
|
|
218
|
-
adjustedPosition = {
|
|
219
|
-
x: position.x,
|
|
220
|
-
y: position.y - size.height / 2
|
|
221
|
-
};
|
|
222
|
-
} else if (fromPort && !toPort) {
|
|
223
|
-
adjustedPosition = {
|
|
224
|
-
x: position.x + size.width / 2,
|
|
225
|
-
y: position.y - size.height / 2
|
|
226
|
-
};
|
|
227
|
-
} else if (!fromPort && toPort) {
|
|
228
|
-
adjustedPosition = {
|
|
229
|
-
x: position.x - size.width / 2,
|
|
230
|
-
y: position.y - size.height / 2
|
|
231
|
-
};
|
|
232
|
-
} else {
|
|
233
|
-
adjustedPosition = position;
|
|
234
|
-
}
|
|
235
|
-
return this.dragService.adjustSubNodePosition(nodeType, containerNode, adjustedPosition);
|
|
236
|
-
}
|
|
237
|
-
getContainerNode(params) {
|
|
238
|
-
const { fromPort, containerNode } = params;
|
|
239
|
-
if (containerNode) {
|
|
240
|
-
return containerNode;
|
|
241
|
-
}
|
|
242
|
-
const fromNode = fromPort?.node;
|
|
243
|
-
const fromContainer = fromNode?.parent;
|
|
244
|
-
if (this.isContainer(fromNode)) {
|
|
245
|
-
return fromNode;
|
|
246
|
-
}
|
|
247
|
-
return fromContainer;
|
|
248
|
-
}
|
|
249
|
-
/** 获取端口矩形 */
|
|
250
|
-
getPortBox(port, offset = { x: 0, y: 0 }) {
|
|
251
|
-
const node = port.node;
|
|
252
|
-
if (this.isContainer(node)) {
|
|
253
|
-
const { point } = port;
|
|
254
|
-
if (port.portType === "input") {
|
|
255
|
-
return new Rectangle(point.x + offset.x, point.y - 50 + offset.y, 300, 100);
|
|
256
|
-
}
|
|
257
|
-
return new Rectangle(point.x - 300, point.y - 50, 300, 100);
|
|
258
|
-
}
|
|
259
|
-
const box = node.getData(FlowNodeTransformData).bounds;
|
|
260
|
-
return box;
|
|
261
|
-
}
|
|
262
|
-
/** 后续节点位置偏移 */
|
|
263
|
-
subPositionOffset(params) {
|
|
264
|
-
const { node, fromPort, toPort, padding } = params;
|
|
265
|
-
const fromBox = this.getPortBox(fromPort);
|
|
266
|
-
const toBox = this.getPortBox(toPort);
|
|
267
|
-
const nodeTrans = node.getData(FlowNodeTransformData);
|
|
268
|
-
const nodeSize = node.getNodeMeta()?.size ?? {
|
|
269
|
-
width: nodeTrans.bounds.width,
|
|
270
|
-
height: nodeTrans.bounds.height
|
|
271
|
-
};
|
|
272
|
-
const minDistance = {
|
|
273
|
-
x: nodeSize.width + padding.x,
|
|
274
|
-
y: nodeSize.height + padding.y
|
|
275
|
-
};
|
|
276
|
-
const boxDistance = this.rectDistance(fromBox, toBox);
|
|
277
|
-
const neededOffset = {
|
|
278
|
-
x: isGreaterThan(boxDistance.x, minDistance.x) ? 0 : minDistance.x - boxDistance.x,
|
|
279
|
-
y: isGreaterThan(boxDistance.y, minDistance.y) ? 0 : minDistance.y - boxDistance.y
|
|
280
|
-
};
|
|
281
|
-
if (neededOffset.x === 0 || neededOffset.y === 0) {
|
|
282
|
-
return;
|
|
283
|
-
}
|
|
284
|
-
const intersection = {
|
|
285
|
-
// 这里没有写反,Rectangle内置的算法是反的
|
|
286
|
-
vertical: Rectangle.intersects(fromBox, toBox, "horizontal"),
|
|
287
|
-
horizontal: Rectangle.intersects(fromBox, toBox, "vertical")
|
|
288
|
-
};
|
|
289
|
-
let offsetX = 0;
|
|
290
|
-
let offsetY = 0;
|
|
291
|
-
if (!intersection.horizontal) {
|
|
292
|
-
if (isGreaterThan(toBox.center.y, fromBox.center.y)) {
|
|
293
|
-
offsetY = neededOffset.y;
|
|
294
|
-
} else if (isLessThan(toBox.center.y, fromBox.center.y)) {
|
|
295
|
-
offsetY = -neededOffset.y;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
if (!intersection.vertical) {
|
|
299
|
-
if (isGreaterThan(toBox.center.x, fromBox.center.x)) {
|
|
300
|
-
offsetX = neededOffset.x;
|
|
301
|
-
} else if (isLessThan(toBox.center.x, fromBox.center.x)) {
|
|
302
|
-
offsetX = -neededOffset.x;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
return {
|
|
306
|
-
x: offsetX,
|
|
307
|
-
y: offsetY
|
|
308
|
-
};
|
|
309
|
-
}
|
|
310
|
-
/** 矩形间距 */
|
|
311
|
-
rectDistance(rectA, rectB) {
|
|
312
|
-
const distanceX = Math.abs(
|
|
313
|
-
Math.min(rectA.right, rectB.right) - Math.max(rectA.left, rectB.left)
|
|
314
|
-
);
|
|
315
|
-
const distanceY = Math.abs(
|
|
316
|
-
Math.min(rectA.bottom, rectB.bottom) - Math.max(rectA.top, rectB.top)
|
|
317
|
-
);
|
|
318
|
-
if (Rectangle.intersects(rectA, rectB)) {
|
|
319
|
-
return {
|
|
320
|
-
x: -distanceX,
|
|
321
|
-
y: -distanceY
|
|
322
|
-
};
|
|
323
|
-
}
|
|
324
|
-
return {
|
|
325
|
-
x: distanceX,
|
|
326
|
-
y: distanceY
|
|
327
|
-
};
|
|
328
|
-
}
|
|
329
|
-
/** 获取后续节点 */
|
|
330
|
-
getSubsequentNodes(node) {
|
|
331
|
-
if (this.isContainer(node)) {
|
|
332
|
-
return [];
|
|
333
|
-
}
|
|
334
|
-
const brothers = node.parent?.collapsedChildren ?? [];
|
|
335
|
-
const linkedBrothers = /* @__PURE__ */ new Set();
|
|
336
|
-
const linesMap = /* @__PURE__ */ new Map();
|
|
337
|
-
this.linesManager.getAllLines().forEach((line) => {
|
|
338
|
-
if (!linesMap.has(line.from.id)) {
|
|
339
|
-
linesMap.set(line.from.id, []);
|
|
340
|
-
}
|
|
341
|
-
if (!line.to?.id || this.isContainer(line.to)) {
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
linesMap.get(line.from.id)?.push(line.to.id);
|
|
345
|
-
});
|
|
346
|
-
const bfs = (nodeId) => {
|
|
347
|
-
if (linkedBrothers.has(nodeId)) {
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
|
-
linkedBrothers.add(nodeId);
|
|
351
|
-
const nextNodes = linesMap.get(nodeId) ?? [];
|
|
352
|
-
nextNodes.forEach(bfs);
|
|
353
|
-
};
|
|
354
|
-
bfs(node.id);
|
|
355
|
-
const subsequentNodes = brothers.filter((node2) => linkedBrothers.has(node2.id));
|
|
356
|
-
return subsequentNodes;
|
|
357
|
-
}
|
|
358
|
-
/** 更新后续节点位置 */
|
|
359
|
-
updateSubSequentNodesPosition(params) {
|
|
360
|
-
const { node, subsequentNodes, fromPort, toPort, containerNode, offset } = params;
|
|
361
|
-
if (!offset || !toPort) {
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
-
const subsequentNodesPositions = subsequentNodes.map((node2) => {
|
|
365
|
-
const nodeTrans2 = node2.getData(TransformData);
|
|
366
|
-
return {
|
|
367
|
-
x: nodeTrans2.position.x,
|
|
368
|
-
y: nodeTrans2.position.y
|
|
369
|
-
};
|
|
370
|
-
});
|
|
371
|
-
this.historyService.pushOperation({
|
|
372
|
-
type: FreeOperationType.dragNodes,
|
|
373
|
-
value: {
|
|
374
|
-
ids: subsequentNodes.map((node2) => node2.id),
|
|
375
|
-
value: subsequentNodesPositions.map((position) => ({
|
|
376
|
-
x: position.x + offset.x,
|
|
377
|
-
y: position.y + offset.y
|
|
378
|
-
})),
|
|
379
|
-
oldValue: subsequentNodesPositions
|
|
380
|
-
}
|
|
381
|
-
});
|
|
382
|
-
const fromBox = this.getPortBox(fromPort);
|
|
383
|
-
const toBox = this.getPortBox(toPort, offset);
|
|
384
|
-
const nodeTrans = node.getData(TransformData);
|
|
385
|
-
let nodePos = {
|
|
386
|
-
x: (fromBox.center.x + toBox.center.x) / 2,
|
|
387
|
-
y: (fromBox.y + toBox.y) / 2
|
|
388
|
-
};
|
|
389
|
-
if (containerNode) {
|
|
390
|
-
nodePos = this.dragService.adjustSubNodePosition(
|
|
391
|
-
node.flowNodeType,
|
|
392
|
-
containerNode,
|
|
393
|
-
nodePos
|
|
394
|
-
);
|
|
395
|
-
}
|
|
396
|
-
this.historyService.pushOperation({
|
|
397
|
-
type: FreeOperationType.dragNodes,
|
|
398
|
-
value: {
|
|
399
|
-
ids: [node.id],
|
|
400
|
-
value: [nodePos],
|
|
401
|
-
oldValue: [
|
|
402
|
-
{
|
|
403
|
-
x: nodeTrans.position.x,
|
|
404
|
-
y: nodeTrans.position.y
|
|
405
|
-
}
|
|
406
|
-
]
|
|
407
|
-
}
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
/** 是否容器节点 */
|
|
411
|
-
isContainer(node) {
|
|
412
|
-
return node?.getNodeMeta().isContainer ?? false;
|
|
413
|
-
}
|
|
414
511
|
};
|
|
415
512
|
__decorateClass([
|
|
416
513
|
inject(WorkflowDocument)
|
|
@@ -422,13 +519,13 @@ __decorateClass([
|
|
|
422
519
|
inject(WorkflowSelectService)
|
|
423
520
|
], WorkflowNodePanelService.prototype, "selectService", 2);
|
|
424
521
|
__decorateClass([
|
|
425
|
-
inject(
|
|
522
|
+
inject(WorkflowLinesManager2)
|
|
426
523
|
], WorkflowNodePanelService.prototype, "linesManager", 2);
|
|
427
524
|
__decorateClass([
|
|
428
525
|
inject(PlaygroundConfigEntity)
|
|
429
526
|
], WorkflowNodePanelService.prototype, "playgroundConfig", 2);
|
|
430
527
|
__decorateClass([
|
|
431
|
-
inject(
|
|
528
|
+
inject(HistoryService2)
|
|
432
529
|
], WorkflowNodePanelService.prototype, "historyService", 2);
|
|
433
530
|
WorkflowNodePanelService = __decorateClass([
|
|
434
531
|
injectable()
|
|
@@ -437,9 +534,9 @@ WorkflowNodePanelService = __decorateClass([
|
|
|
437
534
|
// src/layer.tsx
|
|
438
535
|
import React from "react";
|
|
439
536
|
import { inject as inject2 } from "inversify";
|
|
440
|
-
import { Layer } from "@flowgram.ai/core";
|
|
441
|
-
import { nanoid } from "@flowgram.ai/free-layout-core";
|
|
442
537
|
import { domUtils } from "@flowgram.ai/utils";
|
|
538
|
+
import { nanoid } from "@flowgram.ai/free-layout-core";
|
|
539
|
+
import { Layer } from "@flowgram.ai/core";
|
|
443
540
|
var WorkflowNodePanelLayer = class extends Layer {
|
|
444
541
|
constructor() {
|
|
445
542
|
super();
|
|
@@ -462,7 +559,7 @@ var WorkflowNodePanelLayer = class extends Layer {
|
|
|
462
559
|
}
|
|
463
560
|
async call(params) {
|
|
464
561
|
const taskId = nanoid();
|
|
465
|
-
const {
|
|
562
|
+
const { onSelect, onClose, enableMultiAdd = false, panelProps = {} } = params;
|
|
466
563
|
return new Promise((resolve) => {
|
|
467
564
|
const unmount = () => {
|
|
468
565
|
this.renderList.delete(taskId);
|
|
@@ -481,6 +578,7 @@ var WorkflowNodePanelLayer = class extends Layer {
|
|
|
481
578
|
};
|
|
482
579
|
const renderProps = {
|
|
483
580
|
...params,
|
|
581
|
+
panelProps,
|
|
484
582
|
onSelect: handleSelect,
|
|
485
583
|
onClose: handleClose
|
|
486
584
|
};
|
|
@@ -511,6 +609,7 @@ var createFreeNodePanelPlugin = definePluginCreator({
|
|
|
511
609
|
});
|
|
512
610
|
export {
|
|
513
611
|
WorkflowNodePanelService,
|
|
612
|
+
WorkflowNodePanelUtils,
|
|
514
613
|
createFreeNodePanelPlugin
|
|
515
614
|
};
|
|
516
615
|
//# sourceMappingURL=index.js.map
|