@gadmin2n/schematics 0.0.144 → 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
@@ -1,25 +1,317 @@
1
+ import { BadRequestException } from '@nestjs/common';
1
2
  import { hashNodeInstanceConfig } from '../workflowNodeInstance/node-instance-config.util';
2
3
  import { WorkflowCompilerService } from './workflow-compiler.service';
3
4
 
4
5
  describe('WorkflowCompilerService', () => {
5
- it('compiles a webhook function that returns its previous result', async () => {
6
+ it('allows an incomplete manual parameter draft to fail only at publication', async () => {
7
+ const validateOrThrow = jest.fn();
6
8
  const prisma = {
7
9
  workflowNodeType: {
8
10
  findMany: jest.fn().mockResolvedValue([
9
11
  {
10
12
  id: BigInt(1),
11
- type: 'webhook_trigger',
12
- runtimeKey: 'webhook_trigger',
13
+ type: 'manual_trigger',
14
+ runtimeKey: 'manual_trigger',
13
15
  instancePolicy: 'INLINE_ONLY',
14
- schemaVersion: 4,
16
+ schemaVersion: 1,
15
17
  configSchema: { type: 'object' },
16
18
  uiSchema: {},
17
19
  },
20
+ ]),
21
+ },
22
+ workflowNodeInstance: { findMany: jest.fn().mockResolvedValue([]) },
23
+ };
24
+ const service = new WorkflowCompilerService(
25
+ prisma as any,
26
+ { validateOrThrow } as any,
27
+ { assertUiSchemaSupported: jest.fn() } as any,
28
+ { validateSubjects: jest.fn() } as any,
29
+ );
30
+
31
+ await expect(
32
+ service.compile(
33
+ {
34
+ nodes: [
35
+ {
36
+ id: 'manual',
37
+ type: 'manual_trigger',
38
+ label: '手动触发',
39
+ config: {
40
+ inputParameters: [{ key: '', type: 'string' }],
41
+ },
42
+ },
43
+ ],
44
+ edges: [],
45
+ },
46
+ { userId: 'author' },
47
+ ),
48
+ ).rejects.toMatchObject({
49
+ response: {
50
+ message: '启动参数 1 的参数名不能为空',
51
+ nodeLabel: '手动触发',
52
+ nodeId: 'manual',
53
+ },
54
+ });
55
+ expect(validateOrThrow).not.toHaveBeenCalled();
56
+ });
57
+
58
+ it('explains that an approval node needs at least one approver', async () => {
59
+ const validateOrThrow = jest.fn();
60
+ const prisma = {
61
+ workflowNodeType: {
62
+ findMany: jest.fn().mockResolvedValue([
18
63
  {
19
- id: BigInt(2),
20
- type: 'return_result',
21
- runtimeKey: 'return_result',
64
+ id: BigInt(1),
65
+ type: 'approval',
66
+ runtimeKey: 'human_approval',
67
+ instancePolicy: 'INLINE_ONLY',
68
+ schemaVersion: 1,
69
+ configSchema: { type: 'object' },
70
+ uiSchema: {},
71
+ },
72
+ ]),
73
+ },
74
+ workflowNodeInstance: { findMany: jest.fn().mockResolvedValue([]) },
75
+ };
76
+ const service = new WorkflowCompilerService(
77
+ prisma as any,
78
+ { validateOrThrow } as any,
79
+ { assertUiSchemaSupported: jest.fn() } as any,
80
+ { validateSubjects: jest.fn() } as any,
81
+ );
82
+
83
+ await expect(
84
+ service.compile(
85
+ {
86
+ nodes: [
87
+ {
88
+ id: 'approval',
89
+ type: 'approval',
90
+ label: '人工审批',
91
+ config: { subjects: [] },
92
+ },
93
+ ],
94
+ edges: [],
95
+ },
96
+ { userId: 'author' },
97
+ ),
98
+ ).rejects.toMatchObject({
99
+ response: {
100
+ message: '必须至少设置一位固定审批人或动态审批人',
101
+ nodeLabel: '人工审批',
102
+ nodeId: 'approval',
103
+ },
104
+ });
105
+ expect(validateOrThrow).not.toHaveBeenCalled();
106
+ });
107
+
108
+ it('rejects an invalid fixed binding before publication', async () => {
109
+ const prisma = {
110
+ workflowNodeType: {
111
+ findMany: jest.fn().mockResolvedValue([
112
+ {
113
+ id: BigInt(1),
114
+ type: 'http_request',
115
+ runtimeKey: 'http_request',
22
116
  instancePolicy: 'INLINE_ONLY',
117
+ schemaVersion: 1,
118
+ configSchema: { type: 'object' },
119
+ uiSchema: {},
120
+ },
121
+ ]),
122
+ },
123
+ workflowNodeInstance: { findMany: jest.fn().mockResolvedValue([]) },
124
+ integrationConnection: {
125
+ findUnique: jest.fn().mockResolvedValue({ isEnabled: true }),
126
+ },
127
+ };
128
+ const service = new WorkflowCompilerService(
129
+ prisma as any,
130
+ { validateOrThrow: jest.fn() } as any,
131
+ { assertUiSchemaSupported: jest.fn() } as any,
132
+ { validateSubjects: jest.fn() } as any,
133
+ );
134
+
135
+ await expect(
136
+ service.compile(
137
+ {
138
+ nodes: [
139
+ {
140
+ id: 'request',
141
+ type: 'http_request',
142
+ config: {
143
+ connectionRef: 'erp',
144
+ bodyBindings: {
145
+ payload: {
146
+ source: 'FIXED',
147
+ valueType: 'JSON',
148
+ value: '{invalid',
149
+ },
150
+ },
151
+ },
152
+ },
153
+ ],
154
+ edges: [],
155
+ },
156
+ { userId: 'author' },
157
+ ),
158
+ ).rejects.toMatchObject({
159
+ response: {
160
+ message: '参数来源或固定值无效:config.bodyBindings.payload',
161
+ nodeId: 'request',
162
+ },
163
+ });
164
+ });
165
+
166
+ it('reports the node name and every schema error during publication', async () => {
167
+ const errors = [
168
+ {
169
+ path: '/script',
170
+ keyword: 'minLength',
171
+ message: 'must NOT have fewer than 1 characters',
172
+ },
173
+ {
174
+ path: '/',
175
+ keyword: 'required',
176
+ message: "must have required property 'mode'",
177
+ },
178
+ ];
179
+ const prisma = {
180
+ workflowNodeType: {
181
+ findMany: jest.fn().mockResolvedValue([
182
+ {
183
+ id: BigInt(1),
184
+ type: 'code',
185
+ label: '代码处理',
186
+ runtimeKey: 'code',
187
+ instancePolicy: 'INLINE_ONLY',
188
+ schemaVersion: 1,
189
+ configSchema: { type: 'object' },
190
+ uiSchema: {},
191
+ },
192
+ ]),
193
+ },
194
+ workflowNodeInstance: { findMany: jest.fn().mockResolvedValue([]) },
195
+ };
196
+ const service = new WorkflowCompilerService(
197
+ prisma as any,
198
+ {
199
+ validateOrThrow: jest.fn(() => {
200
+ throw new BadRequestException({
201
+ code: 'NODE_CONFIG_INVALID',
202
+ errors,
203
+ });
204
+ }),
205
+ } as any,
206
+ { assertUiSchemaSupported: jest.fn() } as any,
207
+ { validateSubjects: jest.fn() } as any,
208
+ );
209
+
210
+ await expect(
211
+ service.compile(
212
+ {
213
+ nodes: [
214
+ {
215
+ id: 'internal-node-id',
216
+ type: 'code',
217
+ label: '整理发布结果',
218
+ config: {},
219
+ },
220
+ ],
221
+ edges: [],
222
+ },
223
+ { userId: 'author' },
224
+ ),
225
+ ).rejects.toMatchObject({
226
+ response: {
227
+ code: 'NODE_CONFIG_INVALID',
228
+ message: '节点“整理发布结果”的配置不完整或有误',
229
+ nodeLabel: '整理发布结果',
230
+ errors,
231
+ },
232
+ });
233
+ });
234
+
235
+ it('reports every invalid approver with its node name', async () => {
236
+ const prisma = {
237
+ workflowNodeType: {
238
+ findMany: jest.fn().mockResolvedValue([
239
+ {
240
+ id: BigInt(1),
241
+ type: 'approval',
242
+ label: '人工审批',
243
+ runtimeKey: 'human_approval',
244
+ instancePolicy: 'INLINE_ONLY',
245
+ schemaVersion: 1,
246
+ configSchema: { type: 'object' },
247
+ uiSchema: {},
248
+ },
249
+ ]),
250
+ },
251
+ workflowNodeInstance: { findMany: jest.fn().mockResolvedValue([]) },
252
+ };
253
+ const service = new WorkflowCompilerService(
254
+ prisma as any,
255
+ { validateOrThrow: jest.fn() } as any,
256
+ { assertUiSchemaSupported: jest.fn() } as any,
257
+ {
258
+ validateSubjects: jest.fn(() => {
259
+ throw new BadRequestException({
260
+ code: 'SUBJECT_REF_INVALID',
261
+ issues: [
262
+ {
263
+ path: '/subjects/0/refs/0',
264
+ code: 'INVALID_REF',
265
+ message: 'ref must be a nonblank string',
266
+ },
267
+ ],
268
+ });
269
+ }),
270
+ } as any,
271
+ );
272
+
273
+ await expect(
274
+ service.compile(
275
+ {
276
+ nodes: [
277
+ {
278
+ id: 'internal-node-id',
279
+ type: 'approval',
280
+ label: '部门负责人审批',
281
+ config: {
282
+ subjects: [{ source: 'STATIC', provider: 'USER', refs: [' '] }],
283
+ },
284
+ },
285
+ ],
286
+ edges: [],
287
+ },
288
+ { userId: 'author' },
289
+ ),
290
+ ).rejects.toMatchObject({
291
+ response: {
292
+ code: 'SUBJECT_REF_INVALID',
293
+ message: '节点“部门负责人审批”的审批人配置不完整或无效',
294
+ nodeLabel: '部门负责人审批',
295
+ errors: [
296
+ {
297
+ path: '/subjects/0/refs/0',
298
+ keyword: 'INVALID_REF',
299
+ message: 'ref must be a nonblank string',
300
+ },
301
+ ],
302
+ },
303
+ });
304
+ });
305
+
306
+ it('compiles an asynchronous webhook trigger', async () => {
307
+ const prisma = {
308
+ workflowNodeType: {
309
+ findMany: jest.fn().mockResolvedValue([
310
+ {
311
+ id: BigInt(1),
312
+ type: 'webhook_trigger',
313
+ runtimeKey: 'webhook_trigger',
314
+ instancePolicy: 'REQUIRED',
23
315
  schemaVersion: 4,
24
316
  configSchema: { type: 'object' },
25
317
  uiSchema: {},
@@ -47,38 +339,20 @@ describe('WorkflowCompilerService', () => {
47
339
  path: 'create-ticket',
48
340
  method: 'POST',
49
341
  verificationMode: 'NONE',
50
- responseMode: 'WAIT_FOR_RESULT',
51
- responseTimeoutSeconds: 60,
52
342
  },
53
343
  },
54
- {
55
- id: 'return',
56
- type: 'return_result',
57
- config: {},
58
- },
59
- ],
60
- edges: [
61
- {
62
- id: 'webhook-return',
63
- source: 'webhook',
64
- target: 'return',
65
- kind: 'FLOW',
66
- },
67
344
  ],
345
+ edges: [],
68
346
  },
69
347
  { userId: 'author' },
70
348
  );
71
349
 
72
350
  expect(compiled.nodes).toEqual([
73
351
  expect.objectContaining({ type: 'webhook_trigger' }),
74
- expect.objectContaining({
75
- type: 'return_result',
76
- config: {},
77
- }),
78
352
  ]);
79
353
  });
80
354
 
81
- it('rejects a webhook function whose flow can finish without returning', async () => {
355
+ it('accepts a webhook flow that ends at a business node', async () => {
82
356
  const prisma = {
83
357
  workflowNodeType: {
84
358
  findMany: jest.fn().mockResolvedValue([
@@ -123,7 +397,6 @@ describe('WorkflowCompilerService', () => {
123
397
  config: {
124
398
  path: 'create-ticket',
125
399
  method: 'POST',
126
- responseMode: 'WAIT_FOR_RESULT',
127
400
  },
128
401
  },
129
402
  { id: 'code', type: 'code', config: {} },
@@ -139,15 +412,15 @@ describe('WorkflowCompilerService', () => {
139
412
  },
140
413
  { userId: 'author' },
141
414
  ),
142
- ).rejects.toMatchObject({
143
- response: {
144
- message: '等待返回结果时,每个流程分支都必须以“返回调用”结束',
145
- nodeId: 'webhook',
146
- },
415
+ ).resolves.toMatchObject({
416
+ nodes: [
417
+ expect.objectContaining({ type: 'webhook_trigger' }),
418
+ expect.objectContaining({ type: 'code' }),
419
+ ],
147
420
  });
148
421
  });
149
422
 
150
- it('snapshots the current Node Instance config into the compiled workflow', async () => {
423
+ it('snapshots a Node Instance config regardless of the legacy instance policy', async () => {
151
424
  const instance = {
152
425
  id: BigInt(12),
153
426
  code: 'FINANCE_APPROVAL',
@@ -162,7 +435,7 @@ describe('WorkflowCompilerService', () => {
162
435
  id: BigInt(7),
163
436
  type: 'approval',
164
437
  runtimeKey: 'human_approval',
165
- instancePolicy: 'REQUIRED',
438
+ instancePolicy: 'INLINE_ONLY',
166
439
  schemaVersion: 3,
167
440
  configSchema: { type: 'object' },
168
441
  uiSchema: {},
@@ -254,7 +527,12 @@ describe('WorkflowCompilerService', () => {
254
527
  id: 'approval-1',
255
528
  type: 'approval',
256
529
  config: instance.config,
257
- configOverride: { timeoutSeconds: 3600 },
530
+ configOverride: {
531
+ timeoutSeconds: 3600,
532
+ subjects: [
533
+ { source: 'STATIC', provider: 'USER', refs: ['alice'] },
534
+ ],
535
+ },
258
536
  instanceRef: {
259
537
  instanceId: '12',
260
538
  instanceCode: 'FINANCE_APPROVAL',
@@ -266,14 +544,38 @@ describe('WorkflowCompilerService', () => {
266
544
  { userId: 'author' },
267
545
  );
268
546
 
269
- expect(compiled.nodes[0].config).toEqual({ timeoutSeconds: 3600 });
547
+ const expectedOverride = {
548
+ timeoutSeconds: 3600,
549
+ subjects: [{ source: 'STATIC', provider: 'USER', refs: ['alice'] }],
550
+ };
551
+ expect(compiled.nodes[0].config).toEqual(expectedOverride);
270
552
  expect(compiled.nodes[0].source?.configHash).toBe(
271
- hashNodeInstanceConfig({ timeoutSeconds: 3600 }),
553
+ hashNodeInstanceConfig(expectedOverride),
272
554
  );
273
555
  expect(instance.config).toEqual({ timeoutSeconds: 0 });
274
556
  });
275
557
 
276
- it('rejects a Human Approval node that references a disabled Workflow', async () => {
558
+ it('compiles a self-contained Human Approval node without loading another Workflow', async () => {
559
+ const findWorkflow = jest.fn();
560
+ const config = {
561
+ task: {
562
+ title: {
563
+ source: 'FIXED',
564
+ valueType: 'STRING',
565
+ value: '采购申请审批',
566
+ },
567
+ description: {
568
+ source: 'FIXED',
569
+ valueType: 'STRING',
570
+ value: '',
571
+ },
572
+ details: [],
573
+ },
574
+ subjects: [{ source: 'STATIC', provider: 'USER', refs: ['alice'] }],
575
+ approvalRule: { mode: 'ANY' },
576
+ rejectionRule: { mode: 'ANY' },
577
+ timeout: { durationSeconds: 0, action: 'REJECTED' },
578
+ };
277
579
  const prisma = {
278
580
  workflowNodeType: {
279
581
  findMany: jest.fn().mockResolvedValue([
@@ -281,29 +583,144 @@ describe('WorkflowCompilerService', () => {
281
583
  id: BigInt(7),
282
584
  type: 'approval',
283
585
  runtimeKey: 'human_approval',
284
- instancePolicy: 'REQUIRED',
285
- schemaVersion: 4,
586
+ instancePolicy: 'OPTIONAL',
587
+ schemaVersion: 12,
286
588
  configSchema: { type: 'object' },
287
589
  uiSchema: {},
288
590
  },
289
591
  ]),
290
592
  },
291
- workflowNodeInstance: {
593
+ workflowNodeInstance: { findMany: jest.fn().mockResolvedValue([]) },
594
+ workflow: { findUnique: findWorkflow },
595
+ };
596
+ const service = new WorkflowCompilerService(
597
+ prisma as any,
598
+ { validateOrThrow: jest.fn() } as any,
599
+ { assertUiSchemaSupported: jest.fn() } as any,
600
+ { validateSubjects: jest.fn() } as any,
601
+ );
602
+
603
+ await expect(
604
+ service.compile(
605
+ {
606
+ nodes: [{ id: 'approval-1', type: 'approval', config }],
607
+ edges: [],
608
+ },
609
+ { userId: 'author' },
610
+ ),
611
+ ).resolves.toMatchObject({
612
+ nodes: [expect.objectContaining({ type: 'approval', config })],
613
+ });
614
+ expect(findWorkflow).not.toHaveBeenCalled();
615
+ });
616
+
617
+ it('validates the connections embedded in a Human Approval node', async () => {
618
+ const findConnection = jest.fn().mockImplementation(({ where }) =>
619
+ Promise.resolve({
620
+ isEnabled: where.code === 'myoa' || where.code === 'erp',
621
+ }),
622
+ );
623
+ const prisma = {
624
+ workflowNodeType: {
625
+ findMany: jest.fn().mockResolvedValue([
626
+ {
627
+ id: BigInt(7),
628
+ type: 'approval',
629
+ runtimeKey: 'human_approval',
630
+ instancePolicy: 'OPTIONAL',
631
+ schemaVersion: 16,
632
+ configSchema: { type: 'object' },
633
+ uiSchema: {},
634
+ },
635
+ ]),
636
+ },
637
+ workflowNodeInstance: { findMany: jest.fn().mockResolvedValue([]) },
638
+ integrationConnection: { findUnique: findConnection },
639
+ };
640
+ const service = new WorkflowCompilerService(
641
+ prisma as any,
642
+ { validateOrThrow: jest.fn() } as any,
643
+ { assertUiSchemaSupported: jest.fn() } as any,
644
+ { validateSubjects: jest.fn() } as any,
645
+ );
646
+
647
+ await service.compile(
648
+ {
649
+ nodes: [
650
+ {
651
+ id: 'approval-1',
652
+ type: 'approval',
653
+ config: {
654
+ external: { request: { connectionRef: 'myoa' } },
655
+ subjects: [
656
+ {
657
+ source: 'DYNAMIC',
658
+ provider: 'USER',
659
+ inputKey: 'direct_manager',
660
+ label: '查询直属领导',
661
+ lookup: { request: { connectionRef: 'erp' } },
662
+ },
663
+ ],
664
+ },
665
+ },
666
+ ],
667
+ edges: [],
668
+ },
669
+ { userId: 'author' },
670
+ );
671
+
672
+ expect(findConnection).toHaveBeenCalledTimes(2);
673
+ expect(findConnection).toHaveBeenCalledWith({
674
+ where: { code: 'myoa' },
675
+ select: { isEnabled: true },
676
+ });
677
+ expect(findConnection).toHaveBeenCalledWith({
678
+ where: { code: 'erp' },
679
+ select: { isEnabled: true },
680
+ });
681
+ });
682
+
683
+ it('validates required inputs from the selected published version', async () => {
684
+ const findWorkflow = jest.fn().mockResolvedValue({
685
+ status: 'PUBLISHED',
686
+ isEnabled: true,
687
+ versions: [
688
+ {
689
+ dsl: {
690
+ nodes: [
691
+ {
692
+ id: 'input',
693
+ type: 'callable_trigger',
694
+ config: {
695
+ inputParameters: [
696
+ { key: 'orderId', label: '订单 ID', required: true },
697
+ ],
698
+ },
699
+ },
700
+ { id: 'work', type: 'code', config: {} },
701
+ ],
702
+ edges: [{ source: 'input', target: 'work', kind: 'FLOW' }],
703
+ },
704
+ },
705
+ ],
706
+ });
707
+ const prisma = {
708
+ workflowNodeType: {
292
709
  findMany: jest.fn().mockResolvedValue([
293
710
  {
294
- id: BigInt(12),
295
- code: 'FINANCE_APPROVAL',
296
- nodeTypeId: BigInt(7),
297
- isEnabled: true,
298
- config: { approvalWorkflowId: '11' },
711
+ id: BigInt(8),
712
+ type: 'sub_workflow',
713
+ runtimeKey: 'sub_workflow',
714
+ instancePolicy: 'INLINE_ONLY',
715
+ schemaVersion: 2,
716
+ configSchema: { type: 'object' },
717
+ uiSchema: {},
299
718
  },
300
719
  ]),
301
720
  },
721
+ workflowNodeInstance: { findMany: jest.fn().mockResolvedValue([]) },
302
722
  workflow: {
303
- findUnique: jest.fn().mockResolvedValue({
304
- isEnabled: false,
305
- status: 'PUBLISHED',
306
- }),
723
+ findUnique: findWorkflow,
307
724
  },
308
725
  };
309
726
  const service = new WorkflowCompilerService(
@@ -318,11 +735,12 @@ describe('WorkflowCompilerService', () => {
318
735
  {
319
736
  nodes: [
320
737
  {
321
- id: 'approval-1',
322
- type: 'approval',
323
- instanceRef: {
324
- instanceId: '12',
325
- instanceCode: 'FINANCE_APPROVAL',
738
+ id: 'call-1',
739
+ type: 'sub_workflow',
740
+ config: {
741
+ workflowId: '42',
742
+ workflowVersionId: '420',
743
+ inputBindings: {},
326
744
  },
327
745
  },
328
746
  ],
@@ -332,77 +750,60 @@ describe('WorkflowCompilerService', () => {
332
750
  ),
333
751
  ).rejects.toMatchObject({
334
752
  response: {
335
- message: 'Approval Workflow was not found, published, or enabled',
336
- nodeId: 'approval-1',
753
+ message: '调用 Workflow 的参数来源无效:订单 ID',
754
+ nodeId: 'call-1',
337
755
  },
338
756
  });
757
+ expect(findWorkflow).toHaveBeenCalledWith(
758
+ expect.objectContaining({
759
+ where: { id: BigInt(42) },
760
+ select: expect.objectContaining({
761
+ versions: expect.objectContaining({
762
+ where: { id: BigInt(420) },
763
+ }),
764
+ }),
765
+ }),
766
+ );
767
+ expect(findWorkflow.mock.calls[0][0].select).not.toHaveProperty('status');
339
768
  });
340
769
 
341
- it('rejects a Human Approval node missing a required Workflow argument', async () => {
770
+ it('rejects an indirect Workflow invocation cycle', async () => {
342
771
  const prisma = {
343
772
  workflowNodeType: {
344
773
  findMany: jest.fn().mockResolvedValue([
345
774
  {
346
- id: BigInt(7),
347
- type: 'approval',
348
- runtimeKey: 'human_approval',
349
- instancePolicy: 'REQUIRED',
350
- schemaVersion: 6,
775
+ id: BigInt(8),
776
+ type: 'sub_workflow',
777
+ runtimeKey: 'sub_workflow',
778
+ instancePolicy: 'INLINE_ONLY',
779
+ schemaVersion: 4,
351
780
  configSchema: { type: 'object' },
352
781
  uiSchema: {},
353
782
  },
354
783
  ]),
355
784
  },
356
- workflowNodeInstance: {
357
- findMany: jest.fn().mockResolvedValue([
358
- {
359
- id: BigInt(12),
360
- code: 'MYOA_APPROVAL',
361
- nodeTypeId: BigInt(7),
362
- isEnabled: true,
363
- config: {
364
- approvalWorkflowId: '11',
365
- approvalWorkflowInputBindings: {
366
- title: { source: 'WORKFLOW', path: 'requestTitle' },
367
- },
368
- },
369
- },
370
- ]),
371
- },
785
+ workflowNodeInstance: { findMany: jest.fn().mockResolvedValue([]) },
372
786
  workflow: {
373
787
  findUnique: jest.fn().mockResolvedValue({
374
- isEnabled: true,
375
788
  status: 'PUBLISHED',
789
+ isEnabled: true,
376
790
  versions: [
377
791
  {
378
792
  dsl: {
379
793
  nodes: [
794
+ { id: 'input', type: 'callable_trigger', config: {} },
380
795
  {
381
- id: 'input',
382
- type: 'callable_trigger',
796
+ id: 'call-current',
797
+ type: 'sub_workflow',
383
798
  config: {
384
- inputParameters: [
385
- { key: 'title', required: true },
386
- {
387
- key: 'content',
388
- label: '审批内容',
389
- required: true,
390
- },
391
- ],
799
+ workflowId: '7',
800
+ workflowVersionId: '70',
801
+ inputBindings: {},
392
802
  },
393
803
  },
394
- {
395
- id: 'return',
396
- type: 'return_result',
397
- config: {},
398
- },
399
804
  ],
400
805
  edges: [
401
- {
402
- source: 'input',
403
- target: 'return',
404
- kind: 'FLOW',
405
- },
806
+ { source: 'input', target: 'call-current', kind: 'FLOW' },
406
807
  ],
407
808
  },
408
809
  },
@@ -422,72 +823,100 @@ describe('WorkflowCompilerService', () => {
422
823
  {
423
824
  nodes: [
424
825
  {
425
- id: 'approval-1',
426
- type: 'approval',
427
- instanceRef: {
428
- instanceId: '12',
429
- instanceCode: 'MYOA_APPROVAL',
826
+ id: 'call-1',
827
+ type: 'sub_workflow',
828
+ config: {
829
+ workflowId: '42',
830
+ workflowVersionId: '420',
831
+ inputBindings: {},
430
832
  },
431
833
  },
432
834
  ],
433
835
  edges: [],
434
836
  },
435
837
  { userId: 'author' },
838
+ { workflowId: BigInt(7) },
436
839
  ),
437
840
  ).rejects.toMatchObject({
438
841
  response: {
439
- message: '审批 Workflow 缺少必填参数:审批内容',
440
- nodeId: 'approval-1',
842
+ message: '调用 Workflow 的固定版本调用链存在循环',
843
+ nodeId: 'call-1',
441
844
  },
442
845
  });
443
846
  });
444
847
 
445
- it('rejects a Human Approval node that references a disabled automatic approver Workflow', async () => {
848
+ it('allows a new version to call a historical version of the same Workflow when the fixed version graph terminates', async () => {
849
+ const prisma = {
850
+ workflow: {
851
+ findUnique: jest.fn().mockResolvedValue({
852
+ versions: [
853
+ {
854
+ dsl: {
855
+ nodes: [
856
+ { id: 'input', type: 'callable_trigger', config: {} },
857
+ {
858
+ id: 'done',
859
+ type: 'code',
860
+ config: { script: 'return input;' },
861
+ },
862
+ ],
863
+ edges: [
864
+ {
865
+ id: 'input-done',
866
+ source: 'input',
867
+ target: 'done',
868
+ kind: 'FLOW',
869
+ },
870
+ ],
871
+ },
872
+ },
873
+ ],
874
+ }),
875
+ },
876
+ };
877
+ const service = new WorkflowCompilerService(
878
+ prisma as any,
879
+ {} as any,
880
+ {} as any,
881
+ {} as any,
882
+ );
883
+
884
+ await expect(
885
+ (service as any).assertNoInvocationCycle(
886
+ BigInt(42),
887
+ BigInt(420),
888
+ {
889
+ nodes: [
890
+ {
891
+ id: 'call-a-v1',
892
+ type: 'sub_workflow',
893
+ config: { workflowId: '7', workflowVersionId: '70' },
894
+ },
895
+ ],
896
+ edges: [],
897
+ },
898
+ { id: 'call-b-v1' },
899
+ '调用 Workflow',
900
+ ),
901
+ ).resolves.toBeUndefined();
902
+ });
903
+
904
+ it('rejects a data-modifying statement when database writes are disabled', async () => {
446
905
  const prisma = {
447
906
  workflowNodeType: {
448
907
  findMany: jest.fn().mockResolvedValue([
449
908
  {
450
- id: BigInt(7),
451
- type: 'approval',
452
- runtimeKey: 'human_approval',
453
- instancePolicy: 'REQUIRED',
454
- schemaVersion: 4,
909
+ id: BigInt(10),
910
+ type: 'db_execute',
911
+ runtimeKey: 'db_execute',
912
+ instancePolicy: 'INLINE_ONLY',
913
+ schemaVersion: 2,
455
914
  configSchema: { type: 'object' },
456
915
  uiSchema: {},
457
916
  },
458
917
  ]),
459
918
  },
460
- workflowNodeInstance: {
461
- findMany: jest.fn().mockResolvedValue([
462
- {
463
- id: BigInt(12),
464
- code: 'FINANCE_APPROVAL',
465
- nodeTypeId: BigInt(7),
466
- isEnabled: true,
467
- config: {
468
- approverSources: [
469
- {
470
- workflowId: '99',
471
- inputBindings: {
472
- employeeId: {
473
- source: 'WORKFLOW',
474
- path: 'applicantId',
475
- },
476
- },
477
- },
478
- ],
479
- },
480
- },
481
- ]),
482
- },
483
- workflow: {
484
- findUnique: jest.fn().mockResolvedValue({
485
- id: BigInt(99),
486
- status: 'PUBLISHED',
487
- isEnabled: false,
488
- versions: [],
489
- }),
490
- },
919
+ workflowNodeInstance: { findMany: jest.fn().mockResolvedValue([]) },
491
920
  };
492
921
  const service = new WorkflowCompilerService(
493
922
  prisma as any,
@@ -501,11 +930,11 @@ describe('WorkflowCompilerService', () => {
501
930
  {
502
931
  nodes: [
503
932
  {
504
- id: 'approval-1',
505
- type: 'approval',
506
- instanceRef: {
507
- instanceId: '12',
508
- instanceCode: 'FINANCE_APPROVAL',
933
+ id: 'database-1',
934
+ type: 'db_execute',
935
+ config: {
936
+ allowWrite: false,
937
+ sql: 'WITH removed AS (DELETE FROM users RETURNING id) SELECT * FROM removed',
509
938
  },
510
939
  },
511
940
  ],
@@ -515,57 +944,79 @@ describe('WorkflowCompilerService', () => {
515
944
  ),
516
945
  ).rejects.toMatchObject({
517
946
  response: {
518
- message: '自动找审批人的 Workflow 未发布或已停用',
519
- nodeId: 'approval-1',
947
+ message: '当前数据库操作节点只允许单条只读查询',
948
+ nodeId: 'database-1',
520
949
  },
521
950
  });
522
951
  });
523
952
 
524
- it('validates required inputs when calling another Workflow', async () => {
953
+ it('accepts a single data write when database writes are enabled', async () => {
525
954
  const prisma = {
526
955
  workflowNodeType: {
527
956
  findMany: jest.fn().mockResolvedValue([
528
957
  {
529
- id: BigInt(8),
530
- type: 'sub_workflow',
531
- runtimeKey: 'sub_workflow',
958
+ id: BigInt(10),
959
+ type: 'db_execute',
960
+ runtimeKey: 'db_execute',
532
961
  instancePolicy: 'INLINE_ONLY',
533
- schemaVersion: 2,
962
+ schemaVersion: 4,
534
963
  configSchema: { type: 'object' },
535
964
  uiSchema: {},
536
965
  },
537
966
  ]),
538
967
  },
539
968
  workflowNodeInstance: { findMany: jest.fn().mockResolvedValue([]) },
540
- workflow: {
541
- findUnique: jest.fn().mockResolvedValue({
542
- status: 'PUBLISHED',
543
- isEnabled: true,
544
- versions: [
969
+ };
970
+ const service = new WorkflowCompilerService(
971
+ prisma as any,
972
+ { validateOrThrow: jest.fn() } as any,
973
+ { assertUiSchemaSupported: jest.fn() } as any,
974
+ { validateSubjects: jest.fn() } as any,
975
+ );
976
+
977
+ await expect(
978
+ service.compile(
979
+ {
980
+ nodes: [
545
981
  {
546
- dsl: {
547
- nodes: [
548
- {
549
- id: 'input',
550
- type: 'callable_trigger',
551
- config: {
552
- inputParameters: [
553
- { key: 'orderId', label: '订单 ID', required: true },
554
- ],
555
- },
556
- },
557
- { id: 'work', type: 'code', config: {} },
558
- { id: 'return', type: 'return_result', config: {} },
559
- ],
560
- edges: [
561
- { source: 'input', target: 'work', kind: 'FLOW' },
562
- { source: 'work', target: 'return', kind: 'FLOW' },
563
- ],
982
+ id: 'database-1',
983
+ type: 'db_execute',
984
+ config: {
985
+ allowWrite: true,
986
+ sql: 'UPDATE users SET active = $1 WHERE id = $2',
564
987
  },
565
988
  },
566
989
  ],
990
+ edges: [],
991
+ },
992
+ { userId: 'author' },
993
+ ),
994
+ ).resolves.toMatchObject({
995
+ nodes: [
996
+ expect.objectContaining({
997
+ id: 'database-1',
998
+ config: expect.objectContaining({ allowWrite: true }),
567
999
  }),
1000
+ ],
1001
+ });
1002
+ });
1003
+
1004
+ it('accepts one writable CTE when database writes are enabled', async () => {
1005
+ const prisma = {
1006
+ workflowNodeType: {
1007
+ findMany: jest.fn().mockResolvedValue([
1008
+ {
1009
+ id: BigInt(10),
1010
+ type: 'db_execute',
1011
+ runtimeKey: 'db_execute',
1012
+ instancePolicy: 'INLINE_ONLY',
1013
+ schemaVersion: 4,
1014
+ configSchema: { type: 'object' },
1015
+ uiSchema: {},
1016
+ },
1017
+ ]),
568
1018
  },
1019
+ workflowNodeInstance: { findMany: jest.fn().mockResolvedValue([]) },
569
1020
  };
570
1021
  const service = new WorkflowCompilerService(
571
1022
  prisma as any,
@@ -579,20 +1030,20 @@ describe('WorkflowCompilerService', () => {
579
1030
  {
580
1031
  nodes: [
581
1032
  {
582
- id: 'call-1',
583
- type: 'sub_workflow',
584
- config: { workflowId: '42', inputBindings: {} },
1033
+ id: 'database-1',
1034
+ type: 'db_execute',
1035
+ config: {
1036
+ allowWrite: true,
1037
+ sql: 'WITH changed AS (UPDATE requests SET status = $1 RETURNING id) UPDATE assets SET state = $2 WHERE request_id IN (SELECT id FROM changed)',
1038
+ },
585
1039
  },
586
1040
  ],
587
1041
  edges: [],
588
1042
  },
589
1043
  { userId: 'author' },
590
1044
  ),
591
- ).rejects.toMatchObject({
592
- response: {
593
- message: '调用 Workflow 的参数来源无效:订单 ID',
594
- nodeId: 'call-1',
595
- },
1045
+ ).resolves.toMatchObject({
1046
+ nodes: [expect.objectContaining({ id: 'database-1' })],
596
1047
  });
597
1048
  });
598
1049
  });