@gadmin2n/schematics 0.0.143 → 0.0.145

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 (279) hide show
  1. package/dist/lib/application/files/gadmin2-game-angle-demo/config/.types.d.ts +10 -0
  2. package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/approval.prisma +2 -0
  3. package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/workflow.prisma +140 -19
  4. package/dist/lib/application/files/gadmin2-game-angle-demo/server/package.json +2 -2
  5. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/data-mngt.seed.ts +0 -2
  6. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-node-types.ts +694 -327
  7. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-outbox.ts +57 -0
  8. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow.seed.ts +35 -5
  9. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflows.ts +224 -59
  10. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/code-executor.spec.ts +23 -0
  11. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/code-executor.ts +16 -5
  12. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/code-runtime.controller.spec.ts +98 -0
  13. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/code-runtime.controller.ts +26 -6
  14. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/code-runtime.dto.ts +17 -2
  15. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-runtime.controller.spec.ts +1 -0
  16. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-runtime.controller.ts +3 -0
  17. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-runtime.dto.ts +0 -2
  18. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-signal-outbox.service.spec.ts +30 -0
  19. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-signal-outbox.service.ts +28 -6
  20. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction.service.spec.ts +63 -0
  21. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction.service.ts +151 -38
  22. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-wait.handler.ts +4 -1
  23. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/human-approval.handler.spec.ts +16 -5
  24. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/human-approval.handler.ts +23 -6
  25. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/httpRequest/http-request-runtime.controller.spec.ts +130 -0
  26. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/httpRequest/http-request-runtime.controller.ts +62 -62
  27. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/httpRequest/http-request-runtime.dto.ts +15 -1
  28. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/httpRequest/http-request-runtime.util.spec.ts +70 -9
  29. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/httpRequest/http-request-runtime.util.ts +31 -7
  30. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/approval-signal-outbox.service.spec.ts +30 -0
  31. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/approval-signal-outbox.service.ts +28 -6
  32. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/approval-subject-source.util.spec.ts +50 -3
  33. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/approval-subject-source.util.ts +26 -3
  34. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.dto.ts +53 -47
  35. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.errors.ts +0 -1
  36. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.service.spec.ts +541 -0
  37. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.service.ts +442 -200
  38. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/outbox-retry.util.ts +1 -0
  39. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/runtime/human-approval-runtime.controller.spec.ts +150 -0
  40. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/runtime/human-approval-runtime.controller.ts +56 -40
  41. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/runtime/human-approval-runtime.dto.ts +16 -60
  42. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/integrationConnection/integration-connection.controller.ts +13 -0
  43. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/integrationConnection/integration-connection.service.spec.ts +44 -0
  44. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/integrationConnection/integration-connection.service.ts +6 -0
  45. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/dsl-validate.util.spec.ts +258 -12
  46. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/dsl-validate.util.ts +127 -14
  47. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/manual-workflow-execution.spec.ts +85 -0
  48. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/manual-workflow-execution.ts +108 -0
  49. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/parameter-binding.ts +5 -5
  50. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/temporal.service.spec.ts +96 -25
  51. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/temporal.service.ts +77 -34
  52. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-callable.spec.ts +23 -34
  53. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-callable.ts +0 -21
  54. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-cancellation.spec.ts +245 -0
  55. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.spec.ts +639 -188
  56. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.ts +408 -235
  57. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.types.ts +1 -3
  58. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-data-edge.util.spec.ts +279 -95
  59. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-data-edge.util.ts +360 -80
  60. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-event-catalog.spec.ts +323 -0
  61. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-execution-idempotency.spec.ts +773 -0
  62. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-execution.dto.ts +7 -13
  63. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-export.dto.ts +0 -16
  64. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-export.service.spec.ts +184 -0
  65. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-export.service.ts +69 -138
  66. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-handle-validator.spec.ts +113 -0
  67. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-handle-validator.ts +59 -13
  68. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-runtime.facade.ts +86 -0
  69. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-switch-config.spec.ts +25 -0
  70. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-switch-config.ts +45 -0
  71. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.spec.ts +78 -43
  72. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.ts +103 -40
  73. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.dto.ts +57 -0
  74. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.module.ts +3 -1
  75. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.spec.ts +1000 -240
  76. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.ts +2184 -317
  77. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/node-config-validator.service.spec.ts +279 -2
  78. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/node-config-validator.service.ts +5 -1
  79. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/subject-config-validator.service.spec.ts +4 -1
  80. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/subject-config-validator.service.ts +5 -1
  81. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/widget-catalog.service.spec.ts +12 -3
  82. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/widget-catalog.service.ts +10 -1
  83. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.service.spec.ts +2 -24
  84. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.service.ts +3 -70
  85. package/dist/lib/application/files/gadmin2-game-angle-demo/web/package.json +3 -1
  86. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/RowActions.tsx +25 -5
  87. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/WorkflowActionButton.test.tsx +71 -0
  88. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/WorkflowActionButton.tsx +89 -0
  89. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/index.ts +1 -0
  90. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/header.tsx +52 -12
  91. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/config/routeRegistry.tsx +12 -0
  92. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/constants/layout.ts +2 -2
  93. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/dev-shell/AddDataModal.tsx +10 -33
  94. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/dev-shell/AddPageModal.tsx +13 -37
  95. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/dev-shell/DevShell.tsx +55 -7
  96. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/dev-shell/style.css +14 -0
  97. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/helpers/http.ts +10 -0
  98. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/helpers/list.tsx +1 -0
  99. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/helpers/workflowAction.ts +19 -0
  100. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/index.ts +1 -0
  101. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/types.ts +3 -1
  102. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useDynamicResources.tsx +1 -6
  103. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useReferenceUpload.ts +95 -0
  104. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/common.json +2 -2
  105. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/workflow.json +672 -110
  106. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/common.json +2 -2
  107. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/workflow.json +676 -114
  108. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/plugins/devShellPlugin.ts +13 -1
  109. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agenda/index.tsx +1 -0
  110. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasEditPage.tsx +38 -4
  111. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasListPage.tsx +276 -376
  112. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/CanvasAiModal.tsx +126 -6
  113. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/human-approval/DecisionModal.test.tsx +50 -0
  114. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/human-approval/DecisionModal.tsx +48 -11
  115. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/human-approval/inbox.tsx +32 -34
  116. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/business-events/RegisterBusinessEventModal.test.tsx +111 -0
  117. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/business-events/RegisterBusinessEventModal.tsx +167 -0
  118. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/business-events/business-events.css +99 -0
  119. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/business-events/detail.test.tsx +106 -0
  120. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/business-events/detail.tsx +324 -0
  121. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/business-events/index.test.tsx +73 -0
  122. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/business-events/index.tsx +359 -0
  123. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/CanvasZoomControls.tsx +46 -0
  124. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/CreateNodeInstanceDrawer.tsx +9 -1
  125. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/CustomNode.test.tsx +105 -4
  126. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/CustomNode.tsx +90 -48
  127. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/DeletableEdge.tsx +3 -2
  128. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/DslView.test.tsx +259 -0
  129. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/DslView.tsx +167 -103
  130. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/EnhancedFlowRenderer.tsx +142 -140
  131. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ExecutionStatusNode.test.tsx +60 -15
  132. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ExecutionStatusNode.tsx +25 -12
  133. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/FlowRenderer.tsx +364 -200
  134. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NewNodeDefaults.test.tsx +220 -52
  135. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodeOutputSummary.test.tsx +260 -0
  136. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodeOutputSummary.tsx +300 -130
  137. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodePropertyPanel.test.tsx +507 -33
  138. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodePropertyPanel.tsx +630 -592
  139. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ParameterBindingEditor.tsx +67 -70
  140. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ReadonlyNodePanel.test.tsx +90 -0
  141. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ReadonlyNodePanel.tsx +325 -0
  142. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/RunWorkflowModal.test.tsx +52 -0
  143. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/RunWorkflowModal.tsx +14 -9
  144. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/StatusCards.tsx +2 -1
  145. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/VersionPanel.tsx +2 -1
  146. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/WorkflowCodeEditor.test.tsx +42 -0
  147. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/WorkflowCodeEditor.tsx +76 -0
  148. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/WorkflowWorkspaceHeader.tsx +56 -0
  149. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/parameter-binding-editor.css +46 -0
  150. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/workflow-code-editor.css +34 -0
  151. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/ConnectionModal.test.tsx +53 -7
  152. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/ConnectionModal.tsx +123 -62
  153. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/connections.css +85 -0
  154. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/connectionsApi.ts +29 -0
  155. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/index.test.tsx +75 -0
  156. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/index.tsx +69 -36
  157. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/editor.test.tsx +494 -0
  158. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/editor.tsx +665 -194
  159. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/hooks/useReferencedNodeInstanceConfigs.test.tsx +92 -0
  160. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/hooks/useReferencedNodeInstanceConfigs.ts +96 -0
  161. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/hooks/useWorkflowAgent.test.tsx +297 -0
  162. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/hooks/useWorkflowAgent.ts +135 -65
  163. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/index.tsx +53 -42
  164. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.tsx +344 -155
  165. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instances.tsx +79 -58
  166. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/components/CreateNodeInstanceModal.tsx +123 -144
  167. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/components/NodeInstanceForm.tsx +169 -98
  168. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/components/node-instance-form.css +91 -0
  169. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/index.tsx +54 -31
  170. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/node-config.css +854 -0
  171. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/SchemaField.tsx +41 -14
  172. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/SchemaForm.test.tsx +75 -0
  173. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/SchemaForm.tsx +3 -0
  174. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/default-widgets.tsx +20 -2
  175. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/widget-registry.tsx +2 -1
  176. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/show.tsx +61 -66
  177. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ApprovalRuleEditor.test.tsx +33 -1
  178. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ApprovalRuleEditor.tsx +47 -15
  179. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/BranchConfigEditors.test.tsx +104 -0
  180. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/CallableInputParametersEditor.tsx +22 -52
  181. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/CodeConfigEditor.test.tsx +72 -0
  182. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/CodeConfigEditor.tsx +78 -70
  183. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/CronTriggerConfigEditor.tsx +569 -0
  184. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/DbExecuteConfigEditor.tsx +130 -0
  185. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/DelayConfigEditor.tsx +100 -0
  186. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/EventTriggerConfigEditor.tsx +620 -0
  187. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ExternalRequestConfigEditor.test.tsx +22 -45
  188. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ExternalRequestConfigEditor.tsx +25 -92
  189. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ExternalWaitConfigEditor.tsx +3 -11
  190. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ForEachConfigEditor.test.tsx +58 -0
  191. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ForEachConfigEditor.tsx +107 -0
  192. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/HttpRequestConfigEditor.test.tsx +212 -31
  193. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/HttpRequestConfigEditor.tsx +214 -304
  194. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/HumanApprovalConfigEditor.test.tsx +175 -40
  195. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/HumanApprovalConfigEditor.tsx +693 -293
  196. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/IfElseConfigEditor.tsx +190 -0
  197. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ManualTriggerConfigEditor.test.tsx +152 -0
  198. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ManualTriggerConfigEditor.tsx +286 -0
  199. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ParallelConfigEditor.tsx +101 -0
  200. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ParameterBindingListEditor.tsx +99 -0
  201. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SimplifiedNodeEditors.test.tsx +495 -0
  202. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SubWorkflowConfigEditor.test.tsx +124 -0
  203. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SubWorkflowConfigEditor.tsx +222 -0
  204. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SubjectPicker.tsx +2 -4
  205. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SwitchConfigEditor.tsx +204 -0
  206. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/UserGroupCreateModal.tsx +3 -1
  207. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/UserGroupEditModal.tsx +9 -6
  208. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/callable-workflow.ts +4 -0
  209. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/code-config.css +96 -0
  210. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/event-catalog.api.ts +117 -0
  211. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/http-request-config.css +242 -0
  212. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/human-approval-config.css +194 -0
  213. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/show.tsx +264 -167
  214. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/temporal-tenant/index.tsx +6 -9
  215. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/types/parameter-binding.ts +19 -16
  216. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/types.ts +28 -4
  217. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/useWorkflowFormValidation.test.tsx +59 -0
  218. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/useWorkflowFormValidation.ts +24 -0
  219. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/forEachConnection.test.ts +311 -0
  220. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/forEachConnection.ts +198 -0
  221. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/mainFlowConnection.test.ts +143 -0
  222. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/mainFlowConnection.ts +19 -0
  223. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/newNodeConfig.ts +103 -5
  224. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/removeWorkflowEdges.test.ts +158 -3
  225. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/removeWorkflowEdges.ts +117 -9
  226. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveEffectiveOutput.test.ts +70 -0
  227. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveEffectiveOutput.ts +48 -0
  228. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveLookupPorts.test.ts +55 -0
  229. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveLookupPorts.ts +95 -22
  230. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveOutputs.test.ts +148 -1
  231. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveOutputs.ts +62 -11
  232. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveWorkflowDisplay.test.ts +19 -0
  233. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveWorkflowDisplay.ts +1 -1
  234. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/subWorkflowChange.test.ts +45 -0
  235. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/subWorkflowChange.ts +26 -0
  236. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/validateWorkflowDsl.test.ts +502 -0
  237. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/validateWorkflowDsl.ts +694 -0
  238. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/workflowDateTime.test.ts +27 -0
  239. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/workflowDateTime.ts +33 -0
  240. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/workflowHistory.test.ts +34 -0
  241. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/workflowHistory.ts +52 -0
  242. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/workflowPublishError.test.ts +99 -0
  243. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/workflowPublishError.ts +91 -0
  244. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/workflowSkillPrompt.test.ts +74 -0
  245. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/workflowSkillPrompt.ts +120 -0
  246. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/workflow-ui.css +481 -0
  247. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/styles/index.css +1 -1
  248. package/package.json +1 -1
  249. package/dist/lib/application/files/gadmin2-game-angle-demo/config/ui/WorkflowEventOutbox.ts +0 -62
  250. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/migrate-human-approval-configs.ts +0 -86
  251. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-event-trigger.ts +0 -60
  252. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.external-decision.spec.ts +0 -183
  253. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/legacy-approval-config-migration.ts +0 -227
  254. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-http-response.spec.ts +0 -82
  255. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-http-response.ts +0 -111
  256. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.controller.spec.ts +0 -54
  257. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.controller.ts +0 -147
  258. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.module.ts +0 -10
  259. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.service.spec.ts +0 -350
  260. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.service.ts +0 -110
  261. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/audit/index.ts +0 -1
  262. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/InstanceRequiredDialog.tsx +0 -106
  263. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/LookupConnectionDialog.test.tsx +0 -45
  264. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/LookupConnectionDialog.tsx +0 -43
  265. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodeTypeBadge.tsx +0 -36
  266. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/hooks/useNodeInstanceLibrary.ts +0 -41
  267. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ApproverSourceEditor.test.tsx +0 -47
  268. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ApproverSourceEditor.tsx +0 -182
  269. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ReturnResultConfigEditor.test.tsx +0 -34
  270. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ReturnResultConfigEditor.tsx +0 -16
  271. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/approver-source.test.ts +0 -25
  272. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/approver-source.ts +0 -42
  273. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/lookupConnection.test.ts +0 -208
  274. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/lookupConnection.ts +0 -246
  275. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/create.tsx +0 -111
  276. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/edit.tsx +0 -127
  277. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/index.tsx +0 -4
  278. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/list.tsx +0 -282
  279. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/show.tsx +0 -74
@@ -2,7 +2,7 @@ export type FixedValueType = 'STRING' | 'NUMBER' | 'BOOLEAN' | 'JSON';
2
2
 
3
3
  export type ParameterBinding =
4
4
  | {
5
- source: 'INPUT' | 'WORKFLOW' | 'SYSTEM';
5
+ source: 'INPUT' | 'WORKFLOW' | 'APPROVAL';
6
6
  path: string;
7
7
  }
8
8
  | {
@@ -15,22 +15,25 @@ export function workflowBinding(path: string): ParameterBinding {
15
15
  return { source: 'WORKFLOW', path };
16
16
  }
17
17
 
18
- export function bindingPreview(binding: ParameterBinding): string {
19
- if (binding.source === 'FIXED') return '';
20
- const source =
21
- binding.source === 'INPUT'
22
- ? 'input'
23
- : binding.source === 'WORKFLOW'
24
- ? 'workflow'
25
- : 'system';
26
- return `${source}.${binding.path}`;
27
- }
28
-
29
18
  export function isParameterBindingValid(
30
- binding: ParameterBinding | undefined,
31
- ): boolean {
32
- if (!binding) return false;
33
- if (binding.source !== 'FIXED') return binding.path.trim().length > 0;
19
+ value: unknown,
20
+ ): value is ParameterBinding {
21
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
22
+ const binding = value as Record<string, unknown>;
23
+ if (
24
+ binding.source === 'INPUT' ||
25
+ binding.source === 'WORKFLOW' ||
26
+ binding.source === 'APPROVAL'
27
+ )
28
+ return typeof binding.path === 'string' && binding.path.trim().length > 0;
29
+ if (binding.source !== 'FIXED') return false;
30
+ if (
31
+ !['STRING', 'NUMBER', 'BOOLEAN', 'JSON'].includes(
32
+ String(binding.valueType),
33
+ ) ||
34
+ typeof binding.value !== 'string'
35
+ )
36
+ return false;
34
37
  if (binding.valueType === 'STRING') return true;
35
38
  if (binding.valueType === 'NUMBER') {
36
39
  return (
@@ -24,10 +24,8 @@ export interface WorkflowEdge {
24
24
  source: string;
25
25
  target: string;
26
26
  sourceHandle?: string;
27
- /** Dot path read from the source node output for a DATA edge. */
28
- sourcePath?: string;
29
27
  targetHandle?: string;
30
- kind?: 'FLOW' | 'DATA' | 'CALL' | 'RETURN';
28
+ kind?: 'FLOW' | 'CALL' | 'RETURN';
31
29
  label?: string;
32
30
  /** CALL/RETURN edges belonging to the same callable-node invocation. */
33
31
  pairId?: string;
@@ -47,9 +45,17 @@ export interface AgentOutput {
47
45
 
48
46
  export interface Workflow {
49
47
  id: string;
48
+ code: string;
50
49
  name: string;
51
50
  description: string | null;
52
- status: 'DRAFT' | 'PUBLISHED';
51
+ status: 'DRAFT' | 'PUBLISHED' | 'DELETING';
52
+ hasUnpublishedChanges?: boolean;
53
+ scheduleStatus?:
54
+ | 'ACTIVE'
55
+ | 'PAUSED'
56
+ | 'MISSING'
57
+ | 'UNAVAILABLE'
58
+ | 'NOT_APPLICABLE';
53
59
  isEnabled: boolean;
54
60
  dsl: WorkflowDSL | null;
55
61
  creator: string;
@@ -105,6 +111,24 @@ export interface WorkflowNodeType {
105
111
  instancePolicy: 'REQUIRED' | 'OPTIONAL' | 'INLINE_ONLY';
106
112
  }
107
113
 
114
+ export interface CallableInputParameter {
115
+ key: string;
116
+ label?: string;
117
+ required?: boolean;
118
+ }
119
+
120
+ export interface CallableWorkflowOption {
121
+ id: string;
122
+ name: string;
123
+ description?: string | null;
124
+ latestVersionId: string;
125
+ versions: Array<{
126
+ id: string;
127
+ version: number;
128
+ inputParameters: CallableInputParameter[];
129
+ }>;
130
+ }
131
+
108
132
  export interface WorkflowNodeInstance {
109
133
  id: string;
110
134
  nodeTypeId: string;
@@ -0,0 +1,59 @@
1
+ import { fireEvent, render, screen, waitFor } from '@testing-library/react';
2
+ import { Button, Form, Input } from 'antd';
3
+ import { beforeEach, describe, expect, it } from 'vitest';
4
+ import i18n from '../../i18n';
5
+ import { useWorkflowFormValidation } from './useWorkflowFormValidation';
6
+
7
+ Object.defineProperty(window, 'matchMedia', {
8
+ writable: true,
9
+ value: () => ({
10
+ matches: false,
11
+ addListener: () => undefined,
12
+ removeListener: () => undefined,
13
+ addEventListener: () => undefined,
14
+ removeEventListener: () => undefined,
15
+ dispatchEvent: () => false,
16
+ }),
17
+ });
18
+
19
+ describe('useWorkflowFormValidation', () => {
20
+ beforeEach(async () => {
21
+ await i18n.changeLanguage('zh_CN');
22
+ });
23
+
24
+ it('shows localized required errors only after submission validation', async () => {
25
+ function TestForm() {
26
+ const [form] = Form.useForm();
27
+ const formValidation = useWorkflowFormValidation();
28
+ return (
29
+ <Form form={form} {...formValidation}>
30
+ <Form.Item
31
+ name="operation"
32
+ label="产生事件的变化"
33
+ rules={[{ required: true }]}
34
+ >
35
+ <Input aria-label="产生事件的变化" />
36
+ </Form.Item>
37
+ <Button onClick={() => void form.validateFields().catch(() => {})}>
38
+ 提交
39
+ </Button>
40
+ </Form>
41
+ );
42
+ }
43
+
44
+ render(<TestForm />);
45
+ const input = screen.getByLabelText('产生事件的变化');
46
+ fireEvent.change(input, { target: { value: '更新后' } });
47
+ fireEvent.change(input, { target: { value: '' } });
48
+
49
+ expect(screen.queryByText('请输入或选择 产生事件的变化')).toBeNull();
50
+ expect(screen.queryByText('Please enter 产生事件的变化')).toBeNull();
51
+
52
+ fireEvent.click(screen.getByRole('button', { name: /提\s*交/ }));
53
+ await waitFor(() =>
54
+ expect(
55
+ screen.getByText('请输入或选择 产生事件的变化'),
56
+ ).toBeInTheDocument(),
57
+ );
58
+ });
59
+ });
@@ -0,0 +1,24 @@
1
+ import type { FormProps } from 'antd';
2
+ import { useMemo } from 'react';
3
+ import { useTranslation } from 'react-i18next';
4
+
5
+ export function useWorkflowFormValidation(): Pick<
6
+ FormProps,
7
+ 'validateMessages' | 'validateTrigger'
8
+ > {
9
+ const { t } = useTranslation('workflow');
10
+
11
+ return useMemo(
12
+ () => ({
13
+ validateTrigger: false,
14
+ validateMessages: {
15
+ required: t('validation.required'),
16
+ whitespace: t('validation.required'),
17
+ types: {
18
+ url: t('validation.url'),
19
+ },
20
+ },
21
+ }),
22
+ [t],
23
+ );
24
+ }
@@ -0,0 +1,311 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import {
3
+ appendForEachPipelineEdge,
4
+ createForEachCall,
5
+ resolveForEachCall,
6
+ resolveForEachPipelineConnection,
7
+ } from './forEachConnection';
8
+ import { resolveLookupPorts } from './resolveLookupPorts';
9
+
10
+ vi.stubGlobal('crypto', { randomUUID: () => 'pair-1' });
11
+
12
+ const nodes = [
13
+ {
14
+ id: 'loop',
15
+ type: 'for_each',
16
+ label: '循环处理',
17
+ config: {},
18
+ position: { x: 0, y: 0 },
19
+ },
20
+ {
21
+ id: 'http',
22
+ type: 'http_request',
23
+ label: 'HTTP',
24
+ config: {},
25
+ position: { x: 1, y: 0 },
26
+ },
27
+ {
28
+ id: 'code',
29
+ type: 'code',
30
+ label: 'Code',
31
+ config: {},
32
+ position: { x: 2, y: 0 },
33
+ },
34
+ ];
35
+
36
+ describe('For Each canvas connections', () => {
37
+ it('creates a paired CALL from the item output', () => {
38
+ const resolved = resolveForEachCall(
39
+ { nodes, edges: [] },
40
+ {
41
+ source: 'loop',
42
+ target: 'http',
43
+ sourceHandle: 'start',
44
+ targetHandle: 'request-in',
45
+ },
46
+ );
47
+ expect(resolved).not.toBeNull();
48
+ expect(createForEachCall(resolved!)).toMatchObject({
49
+ kind: 'CALL',
50
+ pairId: 'pair-1',
51
+ source: 'loop',
52
+ target: 'http',
53
+ sourceHandle: 'start',
54
+ });
55
+ });
56
+
57
+ it('extends the same pair and returns the final item result', () => {
58
+ const call = {
59
+ id: 'call',
60
+ kind: 'CALL' as const,
61
+ pairId: 'pair-1',
62
+ source: 'loop',
63
+ target: 'http',
64
+ sourceHandle: 'start',
65
+ };
66
+ const flow = resolveForEachPipelineConnection(
67
+ { nodes, edges: [call] },
68
+ {
69
+ source: 'http',
70
+ target: 'code',
71
+ sourceHandle: 'response-out',
72
+ targetHandle: 'data-in',
73
+ },
74
+ );
75
+ expect(flow).toMatchObject({ kind: 'FLOW', pairId: 'pair-1' });
76
+
77
+ const result = resolveForEachPipelineConnection(
78
+ { nodes, edges: [call, flow!] },
79
+ {
80
+ source: 'code',
81
+ target: 'loop',
82
+ sourceHandle: 'result-out',
83
+ targetHandle: 'end',
84
+ },
85
+ );
86
+ expect(result).toMatchObject({
87
+ kind: 'RETURN',
88
+ pairId: 'pair-1',
89
+ target: 'loop',
90
+ targetHandle: 'end',
91
+ });
92
+ });
93
+
94
+ it('keeps temporarily conflicting pipeline edges in a draft', () => {
95
+ const approval = {
96
+ id: 'approval',
97
+ type: 'approval',
98
+ label: '人工审批',
99
+ config: {},
100
+ position: { x: 3, y: 0 },
101
+ };
102
+ const call = {
103
+ id: 'call',
104
+ kind: 'CALL' as const,
105
+ pairId: 'pair-1',
106
+ source: 'loop',
107
+ target: 'http',
108
+ sourceHandle: 'start',
109
+ };
110
+ const first = resolveForEachPipelineConnection(
111
+ { nodes: [...nodes, approval], edges: [call] },
112
+ {
113
+ source: 'http',
114
+ target: 'code',
115
+ sourceHandle: 'response-out',
116
+ targetHandle: 'data-in',
117
+ },
118
+ )!;
119
+ const second = resolveForEachPipelineConnection(
120
+ { nodes: [...nodes, approval], edges: [call, first] },
121
+ {
122
+ source: 'http',
123
+ target: 'approval',
124
+ sourceHandle: 'response-out',
125
+ targetHandle: null,
126
+ },
127
+ )!;
128
+
129
+ expect(appendForEachPipelineEdge([call, first], second)).toHaveLength(3);
130
+ });
131
+
132
+ it('always exposes the item ports', () => {
133
+ expect(resolveLookupPorts(nodes[0])).toEqual(
134
+ expect.arrayContaining([
135
+ expect.objectContaining({ id: 'start' }),
136
+ expect.objectContaining({ id: 'end' }),
137
+ ]),
138
+ );
139
+ });
140
+
141
+ it('does not expose canvas lookup ports for approval nodes', () => {
142
+ expect(
143
+ resolveLookupPorts({
144
+ id: 'approval',
145
+ type: 'approval',
146
+ label: '人工审核',
147
+ position: { x: 0, y: 0 },
148
+ config: {
149
+ subjects: [
150
+ {
151
+ source: 'DYNAMIC',
152
+ provider: 'USER',
153
+ inputKey: 'direct_manager',
154
+ },
155
+ ],
156
+ },
157
+ }),
158
+ ).toEqual([]);
159
+ });
160
+
161
+ it('allows a Call Workflow node as the loop body', () => {
162
+ const callWorkflow = {
163
+ id: 'call-workflow',
164
+ type: 'sub_workflow',
165
+ label: '调用 Workflow',
166
+ config: {},
167
+ position: { x: 1, y: 1 },
168
+ };
169
+ expect(
170
+ resolveForEachCall(
171
+ { nodes: [...nodes, callWorkflow], edges: [] },
172
+ {
173
+ source: 'loop',
174
+ target: 'call-workflow',
175
+ sourceHandle: 'start',
176
+ targetHandle: null,
177
+ },
178
+ ),
179
+ ).not.toBeNull();
180
+ });
181
+
182
+ it('creates a separate START / END pair for each Parallel branch', () => {
183
+ const parallel = {
184
+ id: 'parallel',
185
+ type: 'parallel',
186
+ label: '并行执行',
187
+ config: {
188
+ branches: [
189
+ { id: 'notify', label: '发送通知' },
190
+ { id: 'sync', label: '同步资产' },
191
+ ],
192
+ },
193
+ position: { x: 0, y: 1 },
194
+ };
195
+ const graph = { nodes: [...nodes, parallel], edges: [] };
196
+ const resolved = resolveForEachCall(graph, {
197
+ source: 'parallel',
198
+ target: 'http',
199
+ sourceHandle: 'notify-start',
200
+ targetHandle: 'request-in',
201
+ });
202
+
203
+ expect(createForEachCall(resolved!)).toMatchObject({
204
+ kind: 'CALL',
205
+ sourceHandle: 'notify-start',
206
+ label: '发送通知',
207
+ });
208
+ expect(resolveLookupPorts(parallel)).toEqual(
209
+ expect.arrayContaining([
210
+ expect.objectContaining({
211
+ id: 'notify-start',
212
+ label: '0 · 发送通知 START',
213
+ }),
214
+ expect.objectContaining({
215
+ id: 'notify-end',
216
+ label: '0 · 发送通知 END',
217
+ }),
218
+ expect.objectContaining({
219
+ id: 'sync-start',
220
+ label: '1 · 同步资产 START',
221
+ }),
222
+ expect.objectContaining({ id: 'sync-end', label: '1 · 同步资产 END' }),
223
+ ]),
224
+ );
225
+ });
226
+
227
+ it.each(['if_else', 'approval'])(
228
+ 'allows a Parallel START to enter a %s node',
229
+ (type) => {
230
+ const parallel = {
231
+ id: 'parallel',
232
+ type: 'parallel',
233
+ label: '并行执行',
234
+ config: { branches: [{ id: 'review', label: '审核' }] },
235
+ position: { x: 0, y: 1 },
236
+ };
237
+ const target = {
238
+ id: type,
239
+ type,
240
+ label: type,
241
+ config: {},
242
+ position: { x: 1, y: 1 },
243
+ };
244
+
245
+ expect(
246
+ resolveForEachCall(
247
+ { nodes: [...nodes, parallel, target], edges: [] },
248
+ {
249
+ source: 'parallel',
250
+ target: type,
251
+ sourceHandle: 'review-start',
252
+ targetHandle: null,
253
+ },
254
+ ),
255
+ ).not.toBeNull();
256
+ },
257
+ );
258
+
259
+ it('keeps separate condition exits in one Parallel branch', () => {
260
+ const parallel = {
261
+ id: 'parallel',
262
+ type: 'parallel',
263
+ label: '并行执行',
264
+ config: { branches: [{ id: 'review', label: '审核' }] },
265
+ position: { x: 0, y: 1 },
266
+ };
267
+ const condition = {
268
+ id: 'condition',
269
+ type: 'if_else',
270
+ label: '条件',
271
+ config: {},
272
+ position: { x: 1, y: 1 },
273
+ };
274
+ const call = {
275
+ id: 'call',
276
+ kind: 'CALL' as const,
277
+ pairId: 'pair-1',
278
+ source: 'parallel',
279
+ target: 'condition',
280
+ sourceHandle: 'review-start',
281
+ };
282
+ const graph = { nodes: [...nodes, parallel, condition], edges: [call] };
283
+ const trueReturn = resolveForEachPipelineConnection(graph, {
284
+ source: 'condition',
285
+ target: 'parallel',
286
+ sourceHandle: 'true',
287
+ targetHandle: 'review-end',
288
+ });
289
+ expect(trueReturn).toMatchObject({ kind: 'RETURN', sourceHandle: 'true' });
290
+
291
+ const falseReturn = resolveForEachPipelineConnection(
292
+ { ...graph, edges: appendForEachPipelineEdge(graph.edges, trueReturn!) },
293
+ {
294
+ source: 'condition',
295
+ target: 'parallel',
296
+ sourceHandle: 'false',
297
+ targetHandle: 'review-end',
298
+ },
299
+ );
300
+ const edges = appendForEachPipelineEdge(
301
+ appendForEachPipelineEdge(graph.edges, trueReturn!),
302
+ falseReturn!,
303
+ );
304
+
305
+ expect(edges.filter((edge) => edge.kind === 'RETURN')).toEqual([
306
+ expect.objectContaining({ sourceHandle: 'true' }),
307
+ expect.objectContaining({ sourceHandle: 'false' }),
308
+ ]);
309
+ expect(new Set(edges.map((edge) => edge.id)).size).toBe(edges.length);
310
+ });
311
+ });
@@ -0,0 +1,198 @@
1
+ import type { Connection } from '@xyflow/react';
2
+ import type { WorkflowDSL, WorkflowEdge, WorkflowNode } from '../types';
3
+
4
+ export interface ResolvedForEachCall {
5
+ forEachNode: WorkflowNode;
6
+ firstNode: WorkflowNode;
7
+ sourceHandle: string;
8
+ targetReturnHandle: string;
9
+ label: string;
10
+ targetHandle?: string;
11
+ }
12
+
13
+ export function resolveForEachCall(
14
+ dsl: WorkflowDSL,
15
+ connection: Connection,
16
+ ): ResolvedForEachCall | null {
17
+ if (!connection.sourceHandle || !connection.source || !connection.target)
18
+ return null;
19
+ const forEachNode = dsl.nodes.find((node) => node.id === connection.source);
20
+ const firstNode = dsl.nodes.find((node) => node.id === connection.target);
21
+ const ownerPorts = pipelineOwnerPorts(
22
+ forEachNode,
23
+ connection.sourceHandle,
24
+ 'start',
25
+ );
26
+ if (!ownerPorts || !firstNode) return null;
27
+ return {
28
+ forEachNode: forEachNode!,
29
+ firstNode,
30
+ sourceHandle: ownerPorts.start,
31
+ targetReturnHandle: ownerPorts.end,
32
+ label: ownerPorts.label,
33
+ targetHandle: connection.targetHandle || undefined,
34
+ };
35
+ }
36
+
37
+ export function createForEachCall(call: ResolvedForEachCall): WorkflowEdge {
38
+ const pairId = crypto.randomUUID();
39
+ return {
40
+ id: `call-${pairId}`,
41
+ kind: 'CALL',
42
+ pairId,
43
+ source: call.forEachNode.id,
44
+ target: call.firstNode.id,
45
+ sourceHandle: call.sourceHandle,
46
+ targetHandle: call.targetHandle,
47
+ label: call.label,
48
+ };
49
+ }
50
+
51
+ export function resolveForEachPipelineConnection(
52
+ dsl: WorkflowDSL,
53
+ connection: Connection,
54
+ ): WorkflowEdge | null {
55
+ if (!connection.source || !connection.target) return null;
56
+
57
+ const targetOwner = dsl.nodes.find((node) => node.id === connection.target);
58
+ if (!targetOwner) return null;
59
+ const ownerPorts = pipelineOwnerPorts(
60
+ targetOwner,
61
+ connection.targetHandle ?? '',
62
+ 'end',
63
+ );
64
+ if (ownerPorts) {
65
+ const call = dsl.edges.find(
66
+ (edge) =>
67
+ edge.kind === 'CALL' &&
68
+ edge.source === targetOwner.id &&
69
+ edge.sourceHandle === ownerPorts.start,
70
+ );
71
+ if (
72
+ !call?.pairId ||
73
+ !nodeBelongsToPair(dsl, connection.source, call.pairId)
74
+ )
75
+ return null;
76
+ return {
77
+ id: `return-${call.pairId}-${connection.source}-${
78
+ connection.sourceHandle || 'output'
79
+ }`,
80
+ kind: 'RETURN',
81
+ pairId: call.pairId,
82
+ source: connection.source,
83
+ target: targetOwner.id,
84
+ sourceHandle: connection.sourceHandle || undefined,
85
+ targetHandle: ownerPorts.end,
86
+ valueType: 'JSON',
87
+ label: `${ownerPorts.label} END`,
88
+ };
89
+ }
90
+
91
+ const ownedPairs = ownedPairIdsForNode(dsl, connection.source);
92
+ if (ownedPairs.length !== 1) return null;
93
+ const pairId = ownedPairs[0];
94
+ const targetNode = dsl.nodes.find((node) => node.id === connection.target);
95
+ if (!targetNode) return null;
96
+ return {
97
+ id: `flow-${pairId}-${crypto.randomUUID()}`,
98
+ kind: 'FLOW',
99
+ pairId,
100
+ source: connection.source,
101
+ target: connection.target,
102
+ sourceHandle: connection.sourceHandle || undefined,
103
+ targetHandle: connection.targetHandle || undefined,
104
+ label: '处理当前项',
105
+ };
106
+ }
107
+
108
+ export function appendForEachPipelineEdge(
109
+ currentEdges: WorkflowEdge[],
110
+ edge: WorkflowEdge,
111
+ ): WorkflowEdge[] {
112
+ return [...currentEdges, edge];
113
+ }
114
+
115
+ export function isForEachReservedConnection(
116
+ dsl: WorkflowDSL,
117
+ connection: Connection,
118
+ ): boolean {
119
+ if (
120
+ pipelineOwnerPorts(
121
+ dsl.nodes.find((node) => node.id === connection.source),
122
+ connection.sourceHandle ?? '',
123
+ 'start',
124
+ ) ||
125
+ pipelineOwnerPorts(
126
+ dsl.nodes.find((node) => node.id === connection.target),
127
+ connection.targetHandle ?? '',
128
+ 'end',
129
+ )
130
+ )
131
+ return true;
132
+ return Boolean(
133
+ connection.source && ownedPairIdsForNode(dsl, connection.source).length,
134
+ );
135
+ }
136
+
137
+ function ownedPairIdsForNode(dsl: WorkflowDSL, nodeId: string): string[] {
138
+ return dsl.edges
139
+ .filter(
140
+ (edge) =>
141
+ edge.kind === 'CALL' &&
142
+ edge.pairId &&
143
+ nodeBelongsToPair(dsl, nodeId, edge.pairId),
144
+ )
145
+ .map((edge) => edge.pairId!);
146
+ }
147
+
148
+ function pipelineOwnerPorts(
149
+ node: WorkflowNode | undefined,
150
+ handle: string,
151
+ direction: 'start' | 'end',
152
+ ): { start: string; end: string; label: string } | null {
153
+ if (node?.type === 'for_each') {
154
+ if (handle !== direction) return null;
155
+ return { start: 'start', end: 'end', label: '循环处理' };
156
+ }
157
+ if (node?.type !== 'parallel') return null;
158
+ const branches = Array.isArray(node.config?.branches)
159
+ ? (node.config.branches as Array<{ id?: string; label?: string }>)
160
+ : [];
161
+ const branch = branches.find(
162
+ (item) => item.id && `${item.id}-${direction}` === handle,
163
+ );
164
+ if (!branch?.id) return null;
165
+ return {
166
+ start: `${branch.id}-start`,
167
+ end: `${branch.id}-end`,
168
+ label: branch.label?.trim() || '并行分支',
169
+ };
170
+ }
171
+
172
+ function nodeBelongsToPair(
173
+ dsl: WorkflowDSL,
174
+ nodeId: string,
175
+ pairId: string,
176
+ ): boolean {
177
+ const call = dsl.edges.find(
178
+ (edge) => edge.kind === 'CALL' && edge.pairId === pairId,
179
+ );
180
+ if (!call) return false;
181
+ const reachable = new Set([call.target]);
182
+ let changed = true;
183
+ while (changed) {
184
+ changed = false;
185
+ for (const edge of dsl.edges) {
186
+ if (
187
+ edge.kind !== 'FLOW' ||
188
+ edge.pairId !== pairId ||
189
+ !reachable.has(edge.source) ||
190
+ reachable.has(edge.target)
191
+ )
192
+ continue;
193
+ reachable.add(edge.target);
194
+ changed = true;
195
+ }
196
+ }
197
+ return reachable.has(nodeId);
198
+ }