@flowgram.ai/free-layout-core 0.1.0-alpha.10 → 0.1.0-alpha.12

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/index.js CHANGED
@@ -59,6 +59,7 @@ __export(src_exports, {
59
59
  WorkflowSelectService: () => WorkflowSelectService,
60
60
  WorkflowSimpleLineContribution: () => WorkflowSimpleLineContribution,
61
61
  bindConfigEntity: () => import_core3.bindConfigEntity,
62
+ buildGroupJSON: () => buildGroupJSON,
62
63
  compose: () => import_utils.compose,
63
64
  composeAsync: () => import_utils.composeAsync,
64
65
  delay: () => import_utils4.delay,
@@ -105,7 +106,7 @@ var import_core25 = require("@flowgram.ai/core");
105
106
  var import_react2 = require("react");
106
107
  var import_reactive = require("@flowgram.ai/reactive");
107
108
  var import_node = require("@flowgram.ai/node");
108
- var import_document12 = require("@flowgram.ai/document");
109
+ var import_document13 = require("@flowgram.ai/document");
109
110
  var import_core21 = require("@flowgram.ai/core");
110
111
 
111
112
  // src/service/workflow-select-service.ts
@@ -117,6 +118,34 @@ var import_utils9 = require("@flowgram.ai/utils");
117
118
  var import_core3 = require("@flowgram.ai/core");
118
119
  var import_utils4 = require("@flowgram.ai/utils");
119
120
 
121
+ // src/utils/build-group-json.ts
122
+ var import_document = require("@flowgram.ai/document");
123
+ var buildGroupJSON = (json) => {
124
+ const { nodes, edges } = json;
125
+ const groupJSONs = nodes.filter(
126
+ (nodeJSON) => nodeJSON.type === import_document.FlowNodeBaseType.GROUP
127
+ );
128
+ const nodeJSONMap = new Map(nodes.map((n) => [n.id, n]));
129
+ const groupNodeJSONs = groupJSONs.map((groupJSON) => {
130
+ const groupBlocks = (groupJSON.data.blockIDs ?? []).map((blockID) => nodeJSONMap.get(blockID)).filter(Boolean);
131
+ const groupEdges = edges?.filter(
132
+ (edge) => groupBlocks.some((block) => block.id === edge.sourceNodeID || block.id === edge.targetNodeID)
133
+ );
134
+ const groupNodeJSON = {
135
+ ...groupJSON,
136
+ blocks: groupBlocks,
137
+ edges: groupEdges
138
+ };
139
+ return groupNodeJSON;
140
+ });
141
+ const groupBlockSet = new Set(groupJSONs.map((groupJSON) => groupJSON.data.blockIDs).flat());
142
+ const processedNodes = nodes.filter((nodeJSON) => !groupBlockSet.has(nodeJSON.id)).concat(groupNodeJSONs);
143
+ return {
144
+ nodes: processedNodes,
145
+ edges
146
+ };
147
+ };
148
+
120
149
  // src/utils/nanoid.ts
121
150
  var import_nanoid = require("nanoid");
122
151
  function nanoid(n) {
@@ -170,8 +199,8 @@ function domReactToBounds(react) {
170
199
  }
171
200
 
172
201
  // src/entities/workflow-node-entity.ts
173
- var import_document = require("@flowgram.ai/document");
174
- var WorkflowNodeEntity = import_document.FlowNodeEntity;
202
+ var import_document2 = require("@flowgram.ai/document");
203
+ var WorkflowNodeEntity = import_document2.FlowNodeEntity;
175
204
 
176
205
  // src/entities/workflow-line-entity.ts
177
206
  var import_lodash_es2 = require("lodash-es");
@@ -180,12 +209,12 @@ var import_core8 = require("@flowgram.ai/core");
180
209
 
181
210
  // src/entity-datas/workflow-node-ports-data.ts
182
211
  var import_lodash_es = require("lodash-es");
183
- var import_document3 = require("@flowgram.ai/document");
212
+ var import_document4 = require("@flowgram.ai/document");
184
213
  var import_core5 = require("@flowgram.ai/core");
185
214
 
186
215
  // src/entities/workflow-port-entity.ts
187
216
  var import_utils5 = require("@flowgram.ai/utils");
188
- var import_document2 = require("@flowgram.ai/document");
217
+ var import_document3 = require("@flowgram.ai/document");
189
218
  var import_core4 = require("@flowgram.ai/core");
190
219
  var PORT_SIZE = 24;
191
220
  var WorkflowPortEntity = class extends import_core4.Entity {
@@ -214,26 +243,27 @@ var WorkflowPortEntity = class extends import_core4.Entity {
214
243
  }
215
244
  // 设置连线的错误态,外部应使用 validate 进行更新
216
245
  set hasError(hasError) {
217
- this._hasError = hasError;
218
- this._onErrorChangedEmitter.fire();
246
+ if (hasError !== this._hasError) {
247
+ this._hasError = hasError;
248
+ this._onErrorChangedEmitter.fire();
249
+ }
219
250
  }
220
251
  validate() {
221
252
  const anyLineHasError = this.allLines.some((line) => {
222
253
  if (line.disposed || line.isHidden) {
223
254
  return false;
224
255
  }
225
- line.validateSelf();
226
256
  return line.hasError;
227
257
  });
228
258
  const isPortHasError = this.node.document.isErrorPort(this);
229
259
  this.hasError = anyLineHasError || isPortHasError;
230
260
  }
231
261
  isErrorPort() {
232
- return this.node.document.isErrorPort(this);
262
+ return this.node.document.isErrorPort(this, this.hasError);
233
263
  }
234
264
  get point() {
235
265
  const { targetElement } = this;
236
- const { bounds } = this.node.getData(import_document2.FlowNodeTransformData);
266
+ const { bounds } = this.node.getData(import_document3.FlowNodeTransformData);
237
267
  if (targetElement) {
238
268
  const pos = domReactToBounds(targetElement.getBoundingClientRect()).center;
239
269
  return this.entityManager.getEntity(import_core4.PlaygroundConfigEntity).getPosFromMouseEvent({
@@ -262,7 +292,7 @@ var WorkflowPortEntity = class extends import_core4.Entity {
262
292
  */
263
293
  get relativePosition() {
264
294
  const { point } = this;
265
- const { bounds } = this.node.getData(import_document2.FlowNodeTransformData);
295
+ const { bounds } = this.node.getData(import_document3.FlowNodeTransformData);
266
296
  return {
267
297
  x: point.x - bounds.x,
268
298
  y: point.y - bounds.y
@@ -372,7 +402,7 @@ var WorkflowNodePortsData = class extends import_core5.EntityData {
372
402
  * 动态计算点位,通过 dom 的 data-port-key
373
403
  */
374
404
  updateDynamicPorts() {
375
- const domNode = this.entity.getData(import_document3.FlowNodeRenderData).node;
405
+ const domNode = this.entity.getData(import_document4.FlowNodeRenderData).node;
376
406
  const elements = domNode.querySelectorAll("[data-port-id]");
377
407
  const staticPorts = this._staticPorts;
378
408
  const dynamicPorts = [];
@@ -416,7 +446,6 @@ var WorkflowNodePortsData = class extends import_core5.EntityData {
416
446
  port.allLines.forEach((line) => {
417
447
  line.validate();
418
448
  });
419
- port.validate();
420
449
  });
421
450
  }
422
451
  /**
@@ -547,6 +576,9 @@ var _WorkflowNodeLinesData = class _WorkflowNodeLinesData extends import_core6.E
547
576
  get outputLines() {
548
577
  return this.data.outputLines;
549
578
  }
579
+ get allLines() {
580
+ return this.data.inputLines.concat(this.data.outputLines);
581
+ }
550
582
  /**
551
583
  * 输入节点
552
584
  */
@@ -733,8 +765,16 @@ var POINT_RADIUS = 10;
733
765
  var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity {
734
766
  constructor(opts) {
735
767
  super(opts);
736
- this._processing = false;
737
- this._hasError = false;
768
+ this._uiState = {
769
+ hasError: false,
770
+ flowing: false,
771
+ disabled: false,
772
+ vertical: false,
773
+ hideArrow: false,
774
+ reverse: false,
775
+ highlightColor: "",
776
+ lockedColor: ""
777
+ };
738
778
  this.stackIndex = 0;
739
779
  /**
740
780
  * 线条数据
@@ -754,6 +794,14 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
754
794
  if (opts.drawingTo) {
755
795
  this.isDrawing = true;
756
796
  }
797
+ this.onEntityChange(() => {
798
+ this.fromPort?.validate();
799
+ this.toPort?.validate();
800
+ });
801
+ this.onDispose(() => {
802
+ this.fromPort?.validate();
803
+ this.toPort?.validate();
804
+ });
757
805
  }
758
806
  /**
759
807
  * 转成线条 id
@@ -763,6 +811,43 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
763
811
  const { from, to, fromPort, toPort } = info;
764
812
  return `${from}_${fromPort || ""}-${to || ""}_${toPort || ""}`;
765
813
  }
814
+ /**
815
+ * 线条的 UI 状态
816
+ */
817
+ get uiState() {
818
+ return this._uiState;
819
+ }
820
+ /**
821
+ * 更新线条的 ui 状态
822
+ * @param newState
823
+ */
824
+ updateUIState(newState) {
825
+ let changed = false;
826
+ Object.keys(newState).forEach((key) => {
827
+ const value = newState[key];
828
+ if (this._uiState[key] !== value) {
829
+ this._uiState[key] = value;
830
+ changed = true;
831
+ }
832
+ });
833
+ if (changed) {
834
+ this.fireChange();
835
+ }
836
+ }
837
+ /**
838
+ * 线条的扩展数据
839
+ */
840
+ get lineData() {
841
+ return this._lineData;
842
+ }
843
+ /**
844
+ * 更新线条扩展数据
845
+ * @param data
846
+ */
847
+ set lineData(data) {
848
+ this._lineData = data;
849
+ this.fireChange();
850
+ }
766
851
  /**
767
852
  * 获取线条的前置节点
768
853
  */
@@ -784,29 +869,30 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
784
869
  }
785
870
  /**
786
871
  * 获取是否 testrun processing
872
+ * @deprecated use `uiState.flowing` instead
787
873
  */
788
874
  get processing() {
789
- return this._processing;
875
+ return this._uiState.flowing;
790
876
  }
791
877
  /**
792
878
  * 设置 testrun processing 状态
879
+ * @deprecated use `uiState.flowing` instead
793
880
  */
794
881
  set processing(status) {
795
- if (this._processing !== status) {
796
- this._processing = status;
882
+ if (this._uiState.flowing !== status) {
883
+ this._uiState.flowing = status;
797
884
  this.fireChange();
798
885
  }
799
886
  }
800
887
  // 获取连线是否为错误态
801
888
  get hasError() {
802
- return this._hasError;
889
+ return this.uiState.hasError;
803
890
  }
804
891
  // 设置连线的错误态
805
892
  set hasError(hasError) {
806
- if (this._hasError !== hasError) {
807
- this._hasError = hasError;
808
- this.fireChange();
809
- }
893
+ this.updateUIState({
894
+ hasError
895
+ });
810
896
  if (this._node) {
811
897
  this._node.dataset.hasError = this.hasError ? "true" : "false";
812
898
  }
@@ -821,6 +907,7 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
821
907
  if (this.toPort === toPort) {
822
908
  return;
823
909
  }
910
+ const prePort = this.toPort;
824
911
  if (toPort && toPort.portType === "input" && this.linesManager.canAddLine(this.fromPort, toPort, true)) {
825
912
  const { node, portID } = toPort;
826
913
  this._to = node;
@@ -833,6 +920,9 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
833
920
  this.info.to = void 0;
834
921
  this.info.toPort = "";
835
922
  }
923
+ if (prePort) {
924
+ prePort.validate();
925
+ }
836
926
  this.fireChange();
837
927
  }
838
928
  /**
@@ -859,13 +949,20 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
859
949
  return this.info.drawingTo;
860
950
  }
861
951
  get highlightColor() {
862
- return this.info.highlightColor || "";
952
+ return this.uiState.highlightColor || "";
863
953
  }
864
- set highlightColor(color) {
865
- if (this.info.highlightColor !== color) {
866
- this.info.highlightColor = color;
867
- this.fireChange();
868
- }
954
+ set highlightColor(highlightColor) {
955
+ this.updateUIState({
956
+ highlightColor
957
+ });
958
+ }
959
+ get lockedColor() {
960
+ return this.uiState.lockedColor;
961
+ }
962
+ set lockedColor(lockedColor) {
963
+ this.updateUIState({
964
+ lockedColor
965
+ });
869
966
  }
870
967
  /**
871
968
  * 获取线条的边框位置大小
@@ -896,23 +993,23 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
896
993
  }
897
994
  /** 是否反转箭头 */
898
995
  get reverse() {
899
- return this.linesManager.isReverseLine(this);
996
+ return this.linesManager.isReverseLine(this, this.uiState.reverse);
900
997
  }
901
998
  /** 是否隐藏箭头 */
902
999
  get hideArrow() {
903
- return this.linesManager.isHideArrowLine(this);
1000
+ return this.linesManager.isHideArrowLine(this, this.uiState.hideArrow);
904
1001
  }
905
1002
  /** 是否流动 */
906
1003
  get flowing() {
907
- return this.linesManager.isFlowingLine(this);
1004
+ return this.linesManager.isFlowingLine(this, this.uiState.flowing);
908
1005
  }
909
1006
  /** 是否禁用 */
910
1007
  get disabled() {
911
- return this.linesManager.isDisabledLine(this);
1008
+ return this.linesManager.isDisabledLine(this, this.uiState.disabled);
912
1009
  }
913
1010
  /** 是否竖向 */
914
1011
  get vertical() {
915
- return this.linesManager.isVerticalLine(this);
1012
+ return this.linesManager.isVerticalLine(this, this.uiState.vertical);
916
1013
  }
917
1014
  /** 获取线条渲染器类型 */
918
1015
  get renderType() {
@@ -939,15 +1036,16 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
939
1036
  }
940
1037
  // 校验连线是否为错误态
941
1038
  validate() {
942
- const { fromPort, toPort } = this;
943
1039
  this.validateSelf();
944
- fromPort?.validate();
945
- toPort?.validate();
946
1040
  }
1041
+ /**
1042
+ * use `validate` instead
1043
+ * @deprecated
1044
+ */
947
1045
  validateSelf() {
948
1046
  const { fromPort, toPort } = this;
949
1047
  if (fromPort) {
950
- this.hasError = this.linesManager.isErrorLine(fromPort, toPort);
1048
+ this.hasError = this.linesManager.isErrorLine(fromPort, toPort, this.uiState.hasError);
951
1049
  }
952
1050
  }
953
1051
  is(line) {
@@ -978,6 +1076,9 @@ var _WorkflowLineEntity = class _WorkflowLineEntity extends import_core8.Entity
978
1076
  sourcePortID: this.info.fromPort,
979
1077
  targetPortID: this.info.toPort
980
1078
  };
1079
+ if (this._lineData !== void 0) {
1080
+ json.data = this._lineData;
1081
+ }
981
1082
  if (!json.sourcePortID) {
982
1083
  delete json.sourcePortID;
983
1084
  }
@@ -1159,20 +1260,20 @@ WorkflowHoverService = __decorateClass([
1159
1260
  var import_nanoid3 = require("nanoid");
1160
1261
  var import_inversify6 = require("inversify");
1161
1262
  var import_utils16 = require("@flowgram.ai/utils");
1162
- var import_document8 = require("@flowgram.ai/document");
1163
1263
  var import_document9 = require("@flowgram.ai/document");
1264
+ var import_document10 = require("@flowgram.ai/document");
1164
1265
  var import_core15 = require("@flowgram.ai/core");
1165
1266
 
1166
1267
  // src/workflow-lines-manager.ts
1167
1268
  var import_lodash_es3 = require("lodash-es");
1168
1269
  var import_inversify3 = require("inversify");
1169
1270
  var import_utils12 = require("@flowgram.ai/utils");
1170
- var import_document5 = require("@flowgram.ai/document");
1271
+ var import_document6 = require("@flowgram.ai/document");
1171
1272
  var import_core12 = require("@flowgram.ai/core");
1172
1273
 
1173
1274
  // src/workflow-document-option.ts
1174
1275
  var import_form_core2 = require("@flowgram.ai/form-core");
1175
- var import_document4 = require("@flowgram.ai/document");
1276
+ var import_document5 = require("@flowgram.ai/document");
1176
1277
  var import_core11 = require("@flowgram.ai/core");
1177
1278
 
1178
1279
  // src/utils/flow-node-form-data.ts
@@ -1264,7 +1365,7 @@ var WorkflowDocumentOptionsDefault = {
1264
1365
  const nodeMeta = node.getNodeMeta();
1265
1366
  const subCanvas = nodeMeta.subCanvas?.(node);
1266
1367
  if (subCanvas?.isCanvas === false) {
1267
- const canvasNodeTransform = subCanvas.canvasNode.getData(import_document4.FlowNodeTransformData);
1368
+ const canvasNodeTransform = subCanvas.canvasNode.getData(import_document5.FlowNodeTransformData);
1268
1369
  const { x, y } = canvasNodeTransform.transform.position;
1269
1370
  metaData.canvasPosition = { x, y };
1270
1371
  }
@@ -1401,7 +1502,6 @@ var WorkflowLinesManager = class {
1401
1502
  }
1402
1503
  fromNode.removeLine(line);
1403
1504
  toNode?.removeLine(line);
1404
- line.validate();
1405
1505
  });
1406
1506
  line.onDispose(() => {
1407
1507
  if (available) {
@@ -1445,41 +1545,41 @@ var WorkflowLinesManager = class {
1445
1545
  get disposed() {
1446
1546
  return this.toDispose.disposed;
1447
1547
  }
1448
- isErrorLine(fromPort, toPort) {
1548
+ isErrorLine(fromPort, toPort, defaultValue) {
1449
1549
  if (this.options.isErrorLine) {
1450
1550
  return this.options.isErrorLine(fromPort, toPort, this);
1451
1551
  }
1452
- return false;
1552
+ return !!defaultValue;
1453
1553
  }
1454
- isReverseLine(line) {
1554
+ isReverseLine(line, defaultValue = false) {
1455
1555
  if (this.options.isReverseLine) {
1456
1556
  return this.options.isReverseLine(line);
1457
1557
  }
1458
- return false;
1558
+ return defaultValue;
1459
1559
  }
1460
- isHideArrowLine(line) {
1560
+ isHideArrowLine(line, defaultValue = false) {
1461
1561
  if (this.options.isHideArrowLine) {
1462
1562
  return this.options.isHideArrowLine(line);
1463
1563
  }
1464
- return false;
1564
+ return defaultValue;
1465
1565
  }
1466
- isFlowingLine(line) {
1566
+ isFlowingLine(line, defaultValue = false) {
1467
1567
  if (this.options.isFlowingLine) {
1468
1568
  return this.options.isFlowingLine(line);
1469
1569
  }
1470
- return false;
1570
+ return defaultValue;
1471
1571
  }
1472
- isDisabledLine(line) {
1572
+ isDisabledLine(line, defaultValue = false) {
1473
1573
  if (this.options.isDisabledLine) {
1474
1574
  return this.options.isDisabledLine(line);
1475
1575
  }
1476
- return false;
1576
+ return defaultValue;
1477
1577
  }
1478
- isVerticalLine(line) {
1578
+ isVerticalLine(line, defaultValue = false) {
1479
1579
  if (this.options.isVerticalLine) {
1480
1580
  return this.options.isVerticalLine(line);
1481
1581
  }
1482
- return false;
1582
+ return defaultValue;
1483
1583
  }
1484
1584
  setLineRenderType(line) {
1485
1585
  if (this.options.setLineRenderType) {
@@ -1497,6 +1597,9 @@ var WorkflowLinesManager = class {
1497
1597
  if (line.isHidden) {
1498
1598
  return this.lineColor.hidden;
1499
1599
  }
1600
+ if (line.lockedColor) {
1601
+ return line.lockedColor;
1602
+ }
1500
1603
  if (line.hasError) {
1501
1604
  return this.lineColor.error;
1502
1605
  }
@@ -1593,7 +1696,7 @@ var WorkflowLinesManager = class {
1593
1696
  const allNodes = this.getSortedNodes();
1594
1697
  const zoom = this.entityManager.getEntity(import_core12.PlaygroundConfigEntity)?.config?.zoom || 1;
1595
1698
  const containNodes = allNodes.map((node) => {
1596
- const { bounds } = node.getData(import_document5.FlowNodeTransformData);
1699
+ const { bounds } = node.getData(import_document6.FlowNodeTransformData);
1597
1700
  if (bounds.clone().pad(4 / zoom).contains(pos.x, pos.y)) {
1598
1701
  return node;
1599
1702
  }
@@ -1601,7 +1704,7 @@ var WorkflowLinesManager = class {
1601
1704
  return containNodes;
1602
1705
  }
1603
1706
  getNodeIndex(node) {
1604
- const nodeRenderData = node.getData(import_document5.FlowNodeRenderData);
1707
+ const nodeRenderData = node.getData(import_document6.FlowNodeRenderData);
1605
1708
  return nodeRenderData.stackIndex;
1606
1709
  }
1607
1710
  };
@@ -1626,13 +1729,13 @@ var import_nanoid2 = require("nanoid");
1626
1729
  var import_inversify5 = require("inversify");
1627
1730
  var import_utils14 = require("@flowgram.ai/utils");
1628
1731
  var import_form_core3 = require("@flowgram.ai/form-core");
1629
- var import_document7 = require("@flowgram.ai/document");
1732
+ var import_document8 = require("@flowgram.ai/document");
1630
1733
  var import_core14 = require("@flowgram.ai/core");
1631
1734
 
1632
1735
  // src/layout/free-layout.ts
1633
1736
  var import_inversify4 = require("inversify");
1634
1737
  var import_utils13 = require("@flowgram.ai/utils");
1635
- var import_document6 = require("@flowgram.ai/document");
1738
+ var import_document7 = require("@flowgram.ai/document");
1636
1739
  var import_core13 = require("@flowgram.ai/core");
1637
1740
  var FREE_LAYOUT_KEY = "free-layout";
1638
1741
  var FreeLayout = class {
@@ -1646,12 +1749,12 @@ var FreeLayout = class {
1646
1749
  * 更新布局
1647
1750
  */
1648
1751
  update() {
1649
- if (this.document.root.getData(import_document6.FlowNodeTransformData)?.localDirty) {
1752
+ if (this.document.root.getData(import_document7.FlowNodeTransformData)?.localDirty) {
1650
1753
  this.document.root.clearMemoGlobal();
1651
1754
  }
1652
1755
  }
1653
1756
  syncTransform(node) {
1654
- const transform = node.getData(import_document6.FlowNodeTransformData);
1757
+ const transform = node.getData(import_document7.FlowNodeTransformData);
1655
1758
  if (!transform.localDirty) {
1656
1759
  return;
1657
1760
  }
@@ -1665,7 +1768,7 @@ var FreeLayout = class {
1665
1768
  }
1666
1769
  node.parent.clearMemoGlobal();
1667
1770
  node.parent.clearMemoLocal();
1668
- const parentTransform = node.parent.getData(import_document6.FlowNodeTransformData);
1771
+ const parentTransform = node.parent.getData(import_document7.FlowNodeTransformData);
1669
1772
  parentTransform.transform.fireChange();
1670
1773
  }
1671
1774
  /**
@@ -1689,7 +1792,7 @@ var FreeLayout = class {
1689
1792
  */
1690
1793
  getPadding(node) {
1691
1794
  const { padding } = node.getNodeMeta();
1692
- const transform = node.getData(import_document6.FlowNodeTransformData);
1795
+ const transform = node.getData(import_document7.FlowNodeTransformData);
1693
1796
  if (padding) {
1694
1797
  return typeof padding === "function" ? padding(transform) : padding;
1695
1798
  }
@@ -1757,7 +1860,7 @@ __decorateClass([
1757
1860
  (0, import_inversify4.inject)(import_core13.PlaygroundConfigEntity)
1758
1861
  ], FreeLayout.prototype, "playgroundConfig", 2);
1759
1862
  __decorateClass([
1760
- (0, import_inversify4.inject)(import_document6.FlowDocumentProvider)
1863
+ (0, import_inversify4.inject)(import_document7.FlowDocumentProvider)
1761
1864
  ], FreeLayout.prototype, "documentProvider", 2);
1762
1865
  FreeLayout = __decorateClass([
1763
1866
  (0, import_inversify4.injectable)()
@@ -1766,7 +1869,7 @@ FreeLayout = __decorateClass([
1766
1869
  // src/workflow-document.ts
1767
1870
  var nanoid2 = (0, import_nanoid2.customAlphabet)("1234567890", 5);
1768
1871
  var WorkflowDocumentProvider = Symbol("WorkflowDocumentProvider");
1769
- var WorkflowDocument = class extends import_document7.FlowDocument {
1872
+ var WorkflowDocument = class extends import_document8.FlowDocument {
1770
1873
  constructor() {
1771
1874
  super(...arguments);
1772
1875
  this._onContentChangeEmitter = new import_utils14.Emitter();
@@ -1863,7 +1966,7 @@ var WorkflowDocument = class extends import_document7.FlowDocument {
1863
1966
  const { formMeta } = registry;
1864
1967
  const meta = node.getNodeMeta();
1865
1968
  const formData = getFlowNodeFormData(node);
1866
- const transform = node.getData(import_document7.FlowNodeTransformData);
1969
+ const transform = node.getData(import_document8.FlowNodeTransformData);
1867
1970
  const freeLayout = this.layout;
1868
1971
  if (!isExistedNode) {
1869
1972
  transform.onDataChange(() => {
@@ -1905,10 +2008,10 @@ var WorkflowDocument = class extends import_document7.FlowDocument {
1905
2008
  toJSON: () => this.toNodeJSON(node)
1906
2009
  });
1907
2010
  node.onDispose(() => {
1908
- if (!node.parent || node.parent.flowNodeType === import_document7.FlowNodeBaseType.ROOT) {
2011
+ if (!node.parent || node.parent.flowNodeType === import_document8.FlowNodeBaseType.ROOT) {
1909
2012
  return;
1910
2013
  }
1911
- const parentTransform = node.parent.getData(import_document7.FlowNodeTransformData);
2014
+ const parentTransform = node.parent.getData(import_document8.FlowNodeTransformData);
1912
2015
  parentTransform.fireChange();
1913
2016
  });
1914
2017
  let lastDeleteNodeData;
@@ -2073,10 +2176,10 @@ var WorkflowDocument = class extends import_document7.FlowDocument {
2073
2176
  );
2074
2177
  }
2075
2178
  getAllNodes() {
2076
- return this.entityManager.getEntities(WorkflowNodeEntity).filter((n) => n.id !== import_document7.FlowNodeBaseType.ROOT);
2179
+ return this.entityManager.getEntities(WorkflowNodeEntity).filter((n) => n.id !== import_document8.FlowNodeBaseType.ROOT);
2077
2180
  }
2078
2181
  getAllPorts() {
2079
- return this.entityManager.getEntities(WorkflowPortEntity).filter((p) => p.node.id !== import_document7.FlowNodeBaseType.ROOT);
2182
+ return this.entityManager.getEntities(WorkflowPortEntity).filter((p) => p.node.id !== import_document8.FlowNodeBaseType.ROOT);
2080
2183
  }
2081
2184
  /**
2082
2185
  * 获取画布中的非游离节点
@@ -2220,21 +2323,22 @@ var WorkflowDocument = class extends import_document7.FlowDocument {
2220
2323
  /**
2221
2324
  * 判断端口是否为错误态
2222
2325
  */
2223
- isErrorPort(port) {
2326
+ isErrorPort(port, defaultValue = false) {
2224
2327
  if (typeof this.options.isErrorPort === "function") {
2225
2328
  return this.options.isErrorPort(port);
2226
2329
  }
2227
- return false;
2330
+ return defaultValue;
2228
2331
  }
2229
2332
  /**
2230
2333
  * 导出数据
2231
2334
  */
2232
2335
  toJSON() {
2233
2336
  const rootJSON = this.toNodeJSON(this.root);
2234
- return {
2337
+ const json = {
2235
2338
  nodes: rootJSON.blocks ?? [],
2236
2339
  edges: rootJSON.edges ?? []
2237
2340
  };
2341
+ return json;
2238
2342
  }
2239
2343
  dispose() {
2240
2344
  super.dispose();
@@ -2246,10 +2350,11 @@ var WorkflowDocument = class extends import_document7.FlowDocument {
2246
2350
  renderJSON(json, options) {
2247
2351
  const { parent = this.root, isClone = false } = options ?? {};
2248
2352
  const containerID = this.getNodeSubCanvas(parent)?.canvasNode.id ?? parent.id;
2249
- const nodes = json.nodes.map(
2353
+ const processedJSON = buildGroupJSON(json);
2354
+ const nodes = processedJSON.nodes.map(
2250
2355
  (nodeJSON) => this.createWorkflowNode(nodeJSON, isClone, containerID)
2251
2356
  );
2252
- const edges = json.edges.map((edge) => this.createWorkflowLine(edge, containerID)).filter(Boolean);
2357
+ const edges = processedJSON.edges.map((edge) => this.createWorkflowLine(edge, containerID)).filter(Boolean);
2253
2358
  return { nodes, edges };
2254
2359
  }
2255
2360
  getNodeSubCanvas(node) {
@@ -2259,13 +2364,19 @@ var WorkflowDocument = class extends import_document7.FlowDocument {
2259
2364
  return subCanvas;
2260
2365
  }
2261
2366
  getNodeChildren(node) {
2262
- if (!node) return [];
2367
+ if (!node || node.flowNodeType === import_document8.FlowNodeBaseType.GROUP) return [];
2263
2368
  const subCanvas = this.getNodeSubCanvas(node);
2264
- const childrenWithCanvas = subCanvas ? subCanvas.canvasNode.collapsedChildren : node.collapsedChildren;
2265
- const children = childrenWithCanvas.filter((child) => {
2369
+ const realChildren = subCanvas ? subCanvas.canvasNode.blocks : node.blocks;
2370
+ const childrenWithoutSubCanvas = realChildren.filter((child) => {
2266
2371
  const childMeta = child.getNodeMeta();
2267
2372
  return !childMeta.subCanvas?.(node)?.isCanvas;
2268
2373
  }).filter(Boolean);
2374
+ const children = childrenWithoutSubCanvas.map((child) => {
2375
+ if (child.flowNodeType === import_document8.FlowNodeBaseType.GROUP) {
2376
+ return [child, ...child.blocks];
2377
+ }
2378
+ return child;
2379
+ }).flat();
2269
2380
  return children;
2270
2381
  }
2271
2382
  toLineJSON(line) {
@@ -2397,7 +2508,7 @@ var WorkflowDragService = class {
2397
2508
  }
2398
2509
  this.isDragging = true;
2399
2510
  const sameParent = this.childrenOfContainer(selectedNodes);
2400
- if (sameParent && sameParent.flowNodeType !== import_document9.FlowNodeBaseType.ROOT) {
2511
+ if (sameParent && sameParent.flowNodeType !== import_document10.FlowNodeBaseType.ROOT) {
2401
2512
  selectedNodes = [sameParent];
2402
2513
  }
2403
2514
  let startPosition = this.getNodesPosition(selectedNodes);
@@ -2567,7 +2678,7 @@ var WorkflowDragService = class {
2567
2678
  if (!mousePos) {
2568
2679
  return { x: 0, y: 0 };
2569
2680
  }
2570
- if (!subNodeType || !containerNode || containerNode.flowNodeType === import_document9.FlowNodeBaseType.ROOT) {
2681
+ if (!subNodeType || !containerNode || containerNode.flowNodeType === import_document10.FlowNodeBaseType.ROOT) {
2571
2682
  return mousePos;
2572
2683
  }
2573
2684
  const isParentEmpty = !containerNode.children || containerNode.children.length === 0;
@@ -2653,7 +2764,7 @@ var WorkflowDragService = class {
2653
2764
  return offset;
2654
2765
  }
2655
2766
  updateDroppableTransforms() {
2656
- this._droppableTransforms = this.document.getRenderDatas(import_document8.FlowNodeTransformData, false).filter((transform) => {
2767
+ this._droppableTransforms = this.document.getRenderDatas(import_document9.FlowNodeTransformData, false).filter((transform) => {
2657
2768
  const { entity } = transform;
2658
2769
  if (entity.originParent) {
2659
2770
  return this.nodeSelectable(entity) && this.nodeSelectable(entity.originParent);
@@ -2670,7 +2781,7 @@ var WorkflowDragService = class {
2670
2781
  */
2671
2782
  getNodesPosition(nodes) {
2672
2783
  const selectedBounds = import_utils16.Rectangle.enlarge(
2673
- nodes.map((n) => n.getData(import_document8.FlowNodeTransformData).bounds)
2784
+ nodes.map((n) => n.getData(import_document9.FlowNodeTransformData).bounds)
2674
2785
  );
2675
2786
  const position = {
2676
2787
  x: selectedBounds.x,
@@ -2778,7 +2889,7 @@ var WorkflowDragService = class {
2778
2889
  return;
2779
2890
  }
2780
2891
  config.updateCursor("grab");
2781
- line.highlightColor = this.linesManager.lineColor.drawing;
2892
+ line.highlightColor = originLine?.lockedColor || this.linesManager.lineColor.drawing;
2782
2893
  this.hoverService.updateHoveredKey("");
2783
2894
  }
2784
2895
  if (!line) {
@@ -2800,7 +2911,7 @@ var WorkflowDragService = class {
2800
2911
  this._onDragLineEventEmitter.fire({
2801
2912
  type: "onDrag"
2802
2913
  });
2803
- this.setLineColor(line, this.linesManager.lineColor.drawing);
2914
+ this.setLineColor(line, originLine?.lockedColor || this.linesManager.lineColor.drawing);
2804
2915
  if (toNode && this.canBuildContainerLine(toNode, dragPos)) {
2805
2916
  toPort = this.getNearestPort(toNode, dragPos);
2806
2917
  const { hasError } = this.handleDragOnNode(toNode, fromPort, line, toPort, originLine);
@@ -2950,7 +3061,7 @@ __decorateClass([
2950
3061
  (0, import_inversify6.inject)(WorkflowSelectService)
2951
3062
  ], WorkflowDragService.prototype, "selectService", 2);
2952
3063
  __decorateClass([
2953
- (0, import_inversify6.inject)(import_document8.FlowOperationBaseService)
3064
+ (0, import_inversify6.inject)(import_document9.FlowOperationBaseService)
2954
3065
  ], WorkflowDragService.prototype, "operationService", 2);
2955
3066
  __decorateClass([
2956
3067
  (0, import_inversify6.inject)(WorkflowDocumentOptions)
@@ -2969,13 +3080,13 @@ var import_core18 = require("@flowgram.ai/core");
2969
3080
  var import_utils17 = require("@flowgram.ai/utils");
2970
3081
 
2971
3082
  // src/utils/layout-to-positions.ts
2972
- var import_document10 = require("@flowgram.ai/document");
3083
+ var import_document11 = require("@flowgram.ai/document");
2973
3084
  var import_core16 = require("@flowgram.ai/core");
2974
3085
  var layoutToPositions = async (nodes, nodePositionMap) => {
2975
3086
  const newNodePositionMap = {};
2976
3087
  nodes.forEach((node) => {
2977
3088
  const transform = node.getData(import_core16.TransformData);
2978
- const nodeTransform = node.getData(import_document10.FlowNodeTransformData);
3089
+ const nodeTransform = node.getData(import_document11.FlowNodeTransformData);
2979
3090
  newNodePositionMap[node.id] = {
2980
3091
  x: transform.position.x,
2981
3092
  y: transform.position.y + nodeTransform.bounds.height / 2
@@ -3071,9 +3182,9 @@ WorkflowResetLayoutService = __decorateClass([
3071
3182
  // src/service/workflow-operation-base-service.ts
3072
3183
  var import_inversify8 = require("inversify");
3073
3184
  var import_utils19 = require("@flowgram.ai/utils");
3074
- var import_document11 = require("@flowgram.ai/document");
3185
+ var import_document12 = require("@flowgram.ai/document");
3075
3186
  var import_core19 = require("@flowgram.ai/core");
3076
- var WorkflowOperationBaseServiceImpl = class extends import_document11.FlowOperationBaseServiceImpl {
3187
+ var WorkflowOperationBaseServiceImpl = class extends import_document12.FlowOperationBaseServiceImpl {
3077
3188
  constructor() {
3078
3189
  super(...arguments);
3079
3190
  this.onNodePostionUpdateEmitter = new import_utils19.Emitter();
@@ -3125,7 +3236,7 @@ function checkTargetDraggable(el) {
3125
3236
  }
3126
3237
  function useNodeRender(nodeFromProps) {
3127
3238
  const node = nodeFromProps || (0, import_react2.useContext)(import_core21.PlaygroundEntityContext);
3128
- const renderData = node.getData(import_document12.FlowNodeRenderData);
3239
+ const renderData = node.getData(import_document13.FlowNodeRenderData);
3129
3240
  const portsData = node.getData(WorkflowNodePortsData);
3130
3241
  const readonly = usePlaygroundReadonlyState();
3131
3242
  const dragService = (0, import_core21.useService)(WorkflowDragService);
@@ -3292,11 +3403,11 @@ function useNodeRender(nodeFromProps) {
3292
3403
  }
3293
3404
 
3294
3405
  // src/hooks/use-current-dom-node.ts
3295
- var import_document13 = require("@flowgram.ai/document");
3406
+ var import_document14 = require("@flowgram.ai/document");
3296
3407
  var import_core22 = require("@flowgram.ai/core");
3297
3408
  function useCurrentDomNode() {
3298
3409
  const entity = (0, import_core22.useEntityFromContext)();
3299
- const renderData = entity.getData(import_document13.FlowNodeRenderData);
3410
+ const renderData = entity.getData(import_document14.FlowNodeRenderData);
3300
3411
  return renderData.node;
3301
3412
  }
3302
3413
 
@@ -3327,16 +3438,16 @@ var InteractiveType = /* @__PURE__ */ ((InteractiveType2) => {
3327
3438
  // src/workflow-document-container-module.ts
3328
3439
  var import_inversify10 = require("inversify");
3329
3440
  var import_utils20 = require("@flowgram.ai/utils");
3330
- var import_document15 = require("@flowgram.ai/document");
3441
+ var import_document16 = require("@flowgram.ai/document");
3331
3442
 
3332
3443
  // src/workflow-document-contribution.ts
3333
3444
  var import_inversify9 = require("inversify");
3334
- var import_document14 = require("@flowgram.ai/document");
3445
+ var import_document15 = require("@flowgram.ai/document");
3335
3446
  var WorkflowDocumentContribution = class {
3336
3447
  registerDocument(document2) {
3337
3448
  document2.registerNodeDatas(
3338
- import_document14.FlowNodeTransformData,
3339
- import_document14.FlowNodeRenderData,
3449
+ import_document15.FlowNodeTransformData,
3450
+ import_document15.FlowNodeRenderData,
3340
3451
  WorkflowNodePortsData,
3341
3452
  WorkflowNodeLinesData
3342
3453
  );
@@ -3371,11 +3482,11 @@ var WorkflowDocumentContainerModule = new import_inversify10.ContainerModule(
3371
3482
  bind(WorkflowResetLayoutService).toSelf().inSingletonScope();
3372
3483
  bind(WorkflowOperationBaseService).to(WorkflowOperationBaseServiceImpl).inSingletonScope();
3373
3484
  bind(URLParams).toDynamicValue(() => getUrlParams()).inSingletonScope();
3374
- (0, import_utils20.bindContributions)(bind, WorkflowDocumentContribution, [import_document15.FlowDocumentContribution]);
3485
+ (0, import_utils20.bindContributions)(bind, WorkflowDocumentContribution, [import_document16.FlowDocumentContribution]);
3375
3486
  bind(WorkflowDocumentOptions).toConstantValue({
3376
3487
  ...WorkflowDocumentOptionsDefault
3377
3488
  });
3378
- rebind(import_document15.FlowDocument).toService(WorkflowDocument);
3489
+ rebind(import_document16.FlowDocument).toService(WorkflowDocument);
3379
3490
  bind(WorkflowDocumentProvider).toDynamicValue((ctx) => () => ctx.container.get(WorkflowDocument)).inSingletonScope();
3380
3491
  }
3381
3492
  );
@@ -3487,6 +3598,7 @@ WorkflowSimpleLineContribution.type = "WorkflowSimpleLineContribution";
3487
3598
  WorkflowSelectService,
3488
3599
  WorkflowSimpleLineContribution,
3489
3600
  bindConfigEntity,
3601
+ buildGroupJSON,
3490
3602
  compose,
3491
3603
  composeAsync,
3492
3604
  delay,