@gadmin2n/schematics 0.0.144 → 0.0.146

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 (280) 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 +49 -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/src/modules/agenda/agenda.service.ts +14 -24
  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/seed/workflows.ts +0 -698
  253. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.external-decision.spec.ts +0 -183
  254. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/legacy-approval-config-migration.ts +0 -227
  255. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-http-response.spec.ts +0 -82
  256. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-http-response.ts +0 -111
  257. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.controller.spec.ts +0 -54
  258. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.controller.ts +0 -147
  259. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.module.ts +0 -10
  260. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.service.spec.ts +0 -350
  261. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.service.ts +0 -110
  262. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/audit/index.ts +0 -1
  263. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/InstanceRequiredDialog.tsx +0 -106
  264. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/LookupConnectionDialog.test.tsx +0 -45
  265. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/LookupConnectionDialog.tsx +0 -43
  266. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodeTypeBadge.tsx +0 -36
  267. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/hooks/useNodeInstanceLibrary.ts +0 -41
  268. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ApproverSourceEditor.test.tsx +0 -47
  269. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ApproverSourceEditor.tsx +0 -182
  270. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ReturnResultConfigEditor.test.tsx +0 -34
  271. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ReturnResultConfigEditor.tsx +0 -16
  272. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/approver-source.test.ts +0 -25
  273. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/approver-source.ts +0 -42
  274. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/lookupConnection.test.ts +0 -208
  275. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/lookupConnection.ts +0 -246
  276. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/create.tsx +0 -111
  277. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/edit.tsx +0 -127
  278. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/index.tsx +0 -4
  279. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/list.tsx +0 -282
  280. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/show.tsx +0 -74
@@ -1,54 +1,78 @@
1
- import React, { useEffect, useMemo, useState } from 'react';
2
1
  import {
3
- Alert,
2
+ DeleteOutlined,
3
+ PlusOutlined,
4
+ UserAddOutlined,
5
+ UsergroupAddOutlined,
6
+ } from '@ant-design/icons';
7
+ import {
4
8
  Button,
5
- Card,
6
- Divider,
9
+ Collapse,
10
+ Input,
7
11
  InputNumber,
8
12
  Radio,
9
13
  Select,
10
14
  Space,
11
- Tag,
15
+ Switch,
12
16
  Typography,
13
17
  } from 'antd';
14
- import { ApiOutlined, DeleteOutlined, TeamOutlined } from '@ant-design/icons';
15
- import type { WidgetProps } from '../schema-form/widget-registry';
18
+ import { useMemo, useState } from 'react';
16
19
  import { useTranslation } from 'react-i18next';
17
- import { customRequest } from 'helpers/http';
18
- import { ApprovalRuleEditor } from './ApprovalRuleEditor';
19
- import { SubjectPicker, type SubjectSelection } from './SubjectPicker';
20
- import { ApproverSourceEditor } from './ApproverSourceEditor';
21
- import type { ApproverSourceConfig } from './approver-source';
22
20
  import { ParameterBindingEditor } from '../../components/ParameterBindingEditor';
23
21
  import type { ParameterBinding } from '../../types/parameter-binding';
22
+ import type { WidgetProps } from '../schema-form/widget-registry';
23
+ import { ApprovalRuleEditor } from './ApprovalRuleEditor';
24
+ import { CodeConfigEditor } from './CodeConfigEditor';
25
+ import { HttpRequestConfigEditor } from './HttpRequestConfigEditor';
26
+ import { SubjectPicker, type SubjectSelection } from './SubjectPicker';
27
+ import './human-approval-config.css';
24
28
 
25
29
  type Provider = 'USER' | 'USER_GROUP';
30
+ type EmbeddedCodeConfig = {
31
+ script: string;
32
+ mode: 'runOnceForAll';
33
+ timeout: number;
34
+ };
26
35
  type SubjectSource =
27
36
  | { source: 'STATIC'; provider: Provider; refs: string[] }
28
- | { source: 'DYNAMIC'; provider: Provider; inputKey: string };
37
+ | {
38
+ source: 'DYNAMIC';
39
+ provider: Provider;
40
+ inputKey: string;
41
+ label: string;
42
+ lookup: {
43
+ request: Record<string, unknown>;
44
+ result: EmbeddedCodeConfig;
45
+ };
46
+ };
29
47
  type Rule = {
30
48
  mode: 'ANY' | 'ALL' | 'COUNT' | 'PERCENTAGE';
31
- count?: number;
32
- percentage?: number;
49
+ count?: number | null;
50
+ percentage?: number | null;
51
+ };
52
+ type TaskDetail = {
53
+ key: string;
54
+ label: string;
55
+ value: ParameterBinding;
33
56
  };
34
57
  type ApprovalConfig = {
35
- approvalWorkflowId?: string;
36
- approvalWorkflowInputBindings?: Record<string, ParameterBinding>;
37
- approverSources?: ApproverSourceConfig[];
58
+ external?: {
59
+ request: Record<string, unknown>;
60
+ creationResult: EmbeddedCodeConfig;
61
+ callbackResult: EmbeddedCodeConfig;
62
+ };
63
+ task: {
64
+ title: ParameterBinding;
65
+ description: ParameterBinding;
66
+ details: TaskDetail[];
67
+ };
38
68
  subjects: SubjectSource[];
39
69
  approvalRule: Rule;
40
70
  rejectionRule: Rule;
41
- timeout: { durationSeconds: number; action: 'APPROVED' | 'REJECTED' };
42
- };
43
-
44
- type ApprovalWorkflowOption = {
45
- id: string;
46
- name: string;
47
- inputParameters: Array<{
48
- key: string;
49
- label?: string;
50
- required?: boolean;
51
- }>;
71
+ blockCancellationOnResolved: boolean;
72
+ timeout: {
73
+ durationSeconds: number | null;
74
+ action: 'APPROVED' | 'REJECTED';
75
+ };
52
76
  };
53
77
 
54
78
  const RULE_SCHEMA = {
@@ -56,6 +80,82 @@ const RULE_SCHEMA = {
56
80
  default: { mode: 'ANY' },
57
81
  };
58
82
 
83
+ const DEFAULT_TITLE: ParameterBinding = {
84
+ source: 'FIXED',
85
+ valueType: 'STRING',
86
+ value: '请处理审批任务',
87
+ };
88
+
89
+ const DEFAULT_DESCRIPTION: ParameterBinding = {
90
+ source: 'FIXED',
91
+ valueType: 'STRING',
92
+ value: '',
93
+ };
94
+
95
+ const DEFAULT_EXTERNAL_CONFIG: NonNullable<ApprovalConfig['external']> = {
96
+ request: {
97
+ method: 'POST',
98
+ path: '/',
99
+ queryBindings: {},
100
+ headerBindings: {},
101
+ bodyMode: 'JSON',
102
+ bodyBindings: {},
103
+ body: {},
104
+ timeoutSeconds: 30,
105
+ },
106
+ creationResult: {
107
+ mode: 'runOnceForAll',
108
+ timeout: 5000,
109
+ script: `// response 是发起外部审批后的 HTTP 响应。
110
+ // 接口返回业务错误时在这里抛出异常;返回值不会展示到画布。
111
+ return response;`,
112
+ },
113
+ callbackResult: {
114
+ mode: 'runOnceForAll',
115
+ timeout: 5000,
116
+ script: `// callback 是已通过 callbackToken 验证的外部回调。
117
+ // 请按外部系统格式转换为统一审批结果。
118
+ const body = callback?.body;
119
+ return {
120
+ result: body?.result,
121
+ eventId: callback?.eventId,
122
+ operatorId: body?.operatorId,
123
+ comment: body?.comment,
124
+ data: { callback: body },
125
+ };`,
126
+ },
127
+ };
128
+
129
+ function defaultDynamicLookup(provider: Provider): {
130
+ request: Record<string, unknown>;
131
+ result: EmbeddedCodeConfig;
132
+ } {
133
+ return {
134
+ request: {
135
+ method: 'GET',
136
+ path: '/',
137
+ queryBindings: {},
138
+ headerBindings: {},
139
+ bodyMode: 'FIELDS',
140
+ bodyBindings: {},
141
+ timeoutSeconds: 30,
142
+ },
143
+ result: {
144
+ mode: 'runOnceForAll',
145
+ timeout: 5000,
146
+ script: `// response 是查询接口返回的 { status, data, headers }。
147
+ // 从响应中提取审批人 ID,并返回统一格式。
148
+ const refs = response?.data?.refs;
149
+ if (!Array.isArray(refs) || refs.length === 0) {
150
+ throw new Error('未查询到有效的审批人');
151
+ }
152
+ return {
153
+ subjects: [{ provider: '${provider}', refs }],
154
+ };`,
155
+ },
156
+ };
157
+ }
158
+
59
159
  export function HumanApprovalConfigEditor({
60
160
  value,
61
161
  onChange,
@@ -63,23 +163,19 @@ export function HumanApprovalConfigEditor({
63
163
  schema,
64
164
  }: WidgetProps<ApprovalConfig | undefined>) {
65
165
  const { t } = useTranslation('workflow');
66
- const [approvalWorkflows, setApprovalWorkflows] = useState<
67
- ApprovalWorkflowOption[]
68
- >([]);
69
166
  const config: ApprovalConfig = {
70
- approvalWorkflowId: value?.approvalWorkflowId,
71
- approvalWorkflowInputBindings: value?.approvalWorkflowInputBindings ?? {},
72
- approverSources: value?.approverSources ?? [],
167
+ ...(value?.external && { external: value.external }),
168
+ task: {
169
+ title: value?.task?.title ?? DEFAULT_TITLE,
170
+ description: value?.task?.description ?? DEFAULT_DESCRIPTION,
171
+ details: value?.task?.details ?? [],
172
+ },
73
173
  subjects: value?.subjects ?? [],
74
174
  approvalRule: value?.approvalRule ?? { mode: 'ANY' },
75
175
  rejectionRule: value?.rejectionRule ?? { mode: 'ANY' },
176
+ blockCancellationOnResolved: value?.blockCancellationOnResolved ?? false,
76
177
  timeout: value?.timeout ?? { durationSeconds: 0, action: 'REJECTED' },
77
178
  };
78
- useEffect(() => {
79
- customRequest<ApprovalWorkflowOption[]>('workflow/callable', 'GET')
80
- .then(setApprovalWorkflows)
81
- .catch(() => setApprovalWorkflows([]));
82
- }, []);
83
179
  const staticSelections = useMemo<SubjectSelection[]>(() => {
84
180
  const grouped = new Map<string, string[]>();
85
181
  for (const subject of config.subjects) {
@@ -94,14 +190,35 @@ export function HumanApprovalConfigEditor({
94
190
  (subject): subject is Extract<SubjectSource, { source: 'DYNAMIC' }> =>
95
191
  subject.source === 'DYNAMIC',
96
192
  );
97
- const selectedApprovalWorkflow = approvalWorkflows.find(
98
- (workflow) => workflow.id === config.approvalWorkflowId,
99
- );
100
193
 
101
194
  function update(patch: Partial<ApprovalConfig>) {
102
195
  onChange({ ...config, ...patch });
103
196
  }
104
197
 
198
+ function updateTask(patch: Partial<ApprovalConfig['task']>) {
199
+ update({ task: { ...config.task, ...patch } });
200
+ }
201
+
202
+ function updateExternal(
203
+ patch: Partial<NonNullable<ApprovalConfig['external']>>,
204
+ ) {
205
+ update({
206
+ external: {
207
+ ...(config.external ?? DEFAULT_EXTERNAL_CONFIG),
208
+ ...patch,
209
+ },
210
+ });
211
+ }
212
+
213
+ function toggleExternal(enabled: boolean) {
214
+ if (enabled) {
215
+ update({ external: config.external ?? DEFAULT_EXTERNAL_CONFIG });
216
+ return;
217
+ }
218
+ const { external: _external, ...gadminOnlyConfig } = config;
219
+ onChange(gadminOnlyConfig);
220
+ }
221
+
105
222
  function updateStatic(next: SubjectSelection[]) {
106
223
  update({
107
224
  subjects: [
@@ -115,251 +232,538 @@ export function HumanApprovalConfigEditor({
115
232
  });
116
233
  }
117
234
 
118
- function removeDynamic(inputKey: string) {
235
+ function updateDetail(index: number, patch: Partial<TaskDetail>) {
236
+ updateTask({
237
+ details: config.task.details.map((detail, current) =>
238
+ current === index ? { ...detail, ...patch } : detail,
239
+ ),
240
+ });
241
+ }
242
+
243
+ function updateDynamic(
244
+ inputKey: string,
245
+ patch: Partial<Extract<SubjectSource, { source: 'DYNAMIC' }>>,
246
+ ) {
119
247
  update({
120
- subjects: config.subjects.filter(
121
- (subject) =>
122
- subject.source !== 'DYNAMIC' || subject.inputKey !== inputKey,
248
+ subjects: config.subjects.map((subject) =>
249
+ subject.source === 'DYNAMIC' && subject.inputKey === inputKey
250
+ ? { ...subject, ...patch }
251
+ : subject,
123
252
  ),
124
253
  });
125
254
  }
126
255
 
256
+ function addDynamic(provider: Provider) {
257
+ const base = provider === 'USER' ? 'dynamic_users' : 'dynamic_user_groups';
258
+ const existing = new Set(dynamicSources.map((source) => source.inputKey));
259
+ let inputKey = base;
260
+ let suffix = 2;
261
+ while (existing.has(inputKey)) inputKey = `${base}_${suffix++}`;
262
+ update({
263
+ subjects: [
264
+ ...config.subjects,
265
+ {
266
+ source: 'DYNAMIC',
267
+ provider,
268
+ inputKey,
269
+ label:
270
+ provider === 'USER'
271
+ ? t('approval.dynamicUserDefaultName')
272
+ : t('approval.dynamicGroupDefaultName'),
273
+ lookup: defaultDynamicLookup(provider),
274
+ },
275
+ ],
276
+ });
277
+ }
278
+
279
+ const subjectSchema = (schema.properties?.subjects as any)?.items;
280
+ const dynamicLookupSchema = subjectSchema?.properties?.lookup;
281
+
127
282
  return (
128
- <Space direction="vertical" size={12} style={{ width: '100%' }}>
129
- <Card
130
- size="small"
131
- title={
132
- <Space>
133
- <TeamOutlined />
134
- <span>{t('approval.whoCanApprove')}</span>
135
- </Space>
136
- }
137
- >
138
- <Typography.Paragraph type="secondary">
139
- {t('approval.description')}
140
- </Typography.Paragraph>
141
- <Typography.Text strong>{t('approval.fixedApprovers')}</Typography.Text>
142
- <div style={{ marginTop: 8 }}>
143
- <SubjectPicker
144
- value={staticSelections}
145
- onChange={updateStatic}
283
+ <div className="human-approval-config">
284
+ <section className="human-approval-config__section">
285
+ <Typography.Title
286
+ level={5}
287
+ className="human-approval-config__section-title"
288
+ >
289
+ {t('approval.taskSection')}
290
+ </Typography.Title>
291
+ <div className="human-approval-config__field">
292
+ <Typography.Text strong>{t('approval.taskTitle')}</Typography.Text>
293
+ <ParameterBindingEditor
294
+ name={t('approval.taskTitle')}
295
+ defaultPath="title"
296
+ value={config.task.title}
146
297
  disabled={disabled}
147
- schema={schema}
298
+ onChange={(title) => updateTask({ title })}
148
299
  />
149
300
  </div>
301
+ <div className="human-approval-config__field">
302
+ <div className="human-approval-config__field-heading">
303
+ <Typography.Text strong>
304
+ {t('approval.taskDescription')}
305
+ </Typography.Text>
306
+ <Typography.Text type="secondary">
307
+ {t('approval.optional')}
308
+ </Typography.Text>
309
+ </div>
310
+ <ParameterBindingEditor
311
+ name={t('approval.taskDescription')}
312
+ defaultPath="description"
313
+ value={config.task.description}
314
+ disabled={disabled}
315
+ onChange={(description) => updateTask({ description })}
316
+ />
317
+ </div>
318
+ <div className="human-approval-config__details">
319
+ <div className="human-approval-config__field-heading">
320
+ <div>
321
+ <Typography.Text strong>
322
+ {t('approval.taskDetails')}
323
+ </Typography.Text>
324
+ <Typography.Text
325
+ type="secondary"
326
+ className="human-approval-config__hint"
327
+ >
328
+ {t('approval.taskDetailsDescription')}
329
+ </Typography.Text>
330
+ </div>
331
+ <Button
332
+ size="small"
333
+ className="workflow-panel-action"
334
+ icon={<PlusOutlined />}
335
+ disabled={disabled}
336
+ onClick={() =>
337
+ updateTask({
338
+ details: [
339
+ ...config.task.details,
340
+ {
341
+ key: `detail-${crypto.randomUUID()}`,
342
+ label: '',
343
+ value: { source: 'INPUT', path: '' },
344
+ },
345
+ ],
346
+ })
347
+ }
348
+ >
349
+ {t('approval.addTaskDetail')}
350
+ </Button>
351
+ </div>
352
+ {config.task.details.length === 0 ? (
353
+ <div className="human-approval-config__empty">
354
+ {t('approval.noTaskDetails')}
355
+ </div>
356
+ ) : (
357
+ config.task.details.map((detail, index) => (
358
+ <div className="human-approval-config__detail" key={detail.key}>
359
+ <div className="human-approval-config__detail-head">
360
+ <Input
361
+ aria-label={t('approval.taskDetailLabel', {
362
+ number: index + 1,
363
+ })}
364
+ value={detail.label}
365
+ disabled={disabled}
366
+ placeholder={t('approval.taskDetailPlaceholder')}
367
+ onChange={(event) =>
368
+ updateDetail(index, { label: event.target.value })
369
+ }
370
+ />
371
+ <Button
372
+ type="text"
373
+ danger
374
+ icon={<DeleteOutlined />}
375
+ aria-label={t('approval.removeTaskDetail', {
376
+ number: index + 1,
377
+ })}
378
+ disabled={disabled}
379
+ onClick={() =>
380
+ updateTask({
381
+ details: config.task.details.filter(
382
+ (_, current) => current !== index,
383
+ ),
384
+ })
385
+ }
386
+ />
387
+ </div>
388
+ <ParameterBindingEditor
389
+ name={detail.label || t('approval.taskDetailValue')}
390
+ defaultPath={detail.label || 'value'}
391
+ value={detail.value}
392
+ disabled={disabled}
393
+ onChange={(next) => updateDetail(index, { value: next })}
394
+ />
395
+ </div>
396
+ ))
397
+ )}
398
+ </div>
399
+ </section>
150
400
 
151
- {dynamicSources.length > 0 && (
152
- <Space direction="vertical" size={8} style={{ width: '100%' }}>
153
- <Divider />
154
- <Alert
155
- type="info"
156
- showIcon
157
- message={t('approval.directLookup')}
158
- description={t('approval.directLookupHint')}
159
- />
160
- {dynamicSources.map((source) => {
161
- const isUser = source.provider === 'USER';
162
- return (
163
- <div
164
- key={source.inputKey}
165
- style={{
166
- display: 'flex',
167
- alignItems: 'center',
168
- justifyContent: 'space-between',
169
- gap: 12,
170
- padding: '10px 12px',
171
- border: '1px solid #91caff',
172
- borderRadius: 8,
173
- background: '#f5faff',
174
- }}
175
- >
176
- <Space>
177
- <ApiOutlined style={{ color: '#1677ff' }} />
178
- <div>
179
- <Typography.Text strong>
180
- {isUser
181
- ? t('approval.userIds')
182
- : t('approval.groupIds')}
183
- </Typography.Text>
184
- <Typography.Text
185
- type="secondary"
186
- style={{ display: 'block', fontSize: 12 }}
187
- >
188
- {t('approval.lookupDescription')}
189
- </Typography.Text>
190
- </div>
191
- </Space>
192
- <Space>
193
- <Tag color="blue">
194
- {t('approval.lookup')}: {source.inputKey}
195
- </Tag>
196
- <Button
197
- type="text"
198
- danger
199
- aria-label={t('approval.remove', {
200
- name: source.inputKey,
201
- })}
202
- icon={<DeleteOutlined />}
401
+ <section className="human-approval-config__section">
402
+ <Typography.Title
403
+ level={5}
404
+ className="human-approval-config__section-title"
405
+ >
406
+ {t('approval.cancellationPolicy')}
407
+ </Typography.Title>
408
+ <Typography.Paragraph
409
+ type="secondary"
410
+ className="human-approval-config__section-description"
411
+ >
412
+ {t('approval.cancellationPolicyDescription')}
413
+ </Typography.Paragraph>
414
+ <Space>
415
+ <Switch
416
+ aria-label={t('approval.blockCancellationOnResolved')}
417
+ checked={config.blockCancellationOnResolved}
418
+ disabled={disabled}
419
+ onChange={(blockCancellationOnResolved) =>
420
+ update({ blockCancellationOnResolved })
421
+ }
422
+ />
423
+ <Typography.Text>
424
+ {t('approval.blockCancellationOnResolved')}
425
+ </Typography.Text>
426
+ </Space>
427
+ </section>
428
+
429
+ <section className="human-approval-config__section">
430
+ <Typography.Title
431
+ level={5}
432
+ className="human-approval-config__section-title"
433
+ >
434
+ {t('approval.externalSection')}
435
+ </Typography.Title>
436
+ <Typography.Paragraph
437
+ type="secondary"
438
+ className="human-approval-config__section-description"
439
+ >
440
+ {t('approval.externalSectionDescription')}
441
+ </Typography.Paragraph>
442
+ <div className="human-approval-config__external-toggle">
443
+ <div>
444
+ <Typography.Text strong>
445
+ {t('approval.enableExternal')}
446
+ </Typography.Text>
447
+ <Typography.Text
448
+ type="secondary"
449
+ className="human-approval-config__hint"
450
+ >
451
+ {config.external
452
+ ? t('approval.externalEnabledHint')
453
+ : t('approval.gadminOnlyHint')}
454
+ </Typography.Text>
455
+ </div>
456
+ <Switch
457
+ aria-label={t('approval.enableExternal')}
458
+ checked={Boolean(config.external)}
459
+ disabled={disabled}
460
+ onChange={toggleExternal}
461
+ />
462
+ </div>
463
+ {config.external ? (
464
+ <div className="human-approval-config__external">
465
+ <Collapse
466
+ bordered={false}
467
+ defaultActiveKey={['request']}
468
+ items={[
469
+ {
470
+ key: 'request',
471
+ label: t('approval.externalRequest'),
472
+ children: (
473
+ <HttpRequestConfigEditor
474
+ value={config.external.request}
203
475
  disabled={disabled}
204
- onClick={() => removeDynamic(source.inputKey)}
476
+ uiOptions={{
477
+ embedded: true,
478
+ variableContext: 'approvalExternal',
479
+ bindingSources: [
480
+ 'INPUT',
481
+ 'WORKFLOW',
482
+ 'APPROVAL',
483
+ 'FIXED',
484
+ ],
485
+ requestDataDescriptionKey:
486
+ 'httpRequest.approvalExternalRequestDataDescription',
487
+ }}
488
+ schema={
489
+ (schema.properties?.external as any)?.properties
490
+ ?.request ?? { type: 'object' }
491
+ }
492
+ onChange={(request) => updateExternal({ request })}
205
493
  />
206
- </Space>
207
- </div>
208
- );
209
- })}
210
- </Space>
211
- )}
212
-
213
- <Divider />
494
+ ),
495
+ },
496
+ {
497
+ key: 'creationResult',
498
+ label: t('approval.creationResult'),
499
+ children: (
500
+ <CodeConfigEditor
501
+ value={config.external.creationResult}
502
+ disabled={disabled}
503
+ context="approvalCreation"
504
+ embedded
505
+ schema={
506
+ (schema.properties?.external as any)?.properties
507
+ ?.creationResult ?? { type: 'object' }
508
+ }
509
+ onChange={(creationResult) =>
510
+ updateExternal({
511
+ creationResult: creationResult as any,
512
+ })
513
+ }
514
+ />
515
+ ),
516
+ },
517
+ {
518
+ key: 'callbackResult',
519
+ label: t('approval.callbackResult'),
520
+ children: (
521
+ <CodeConfigEditor
522
+ value={config.external.callbackResult}
523
+ disabled={disabled}
524
+ context="approvalCallback"
525
+ embedded
526
+ schema={
527
+ (schema.properties?.external as any)?.properties
528
+ ?.callbackResult ?? { type: 'object' }
529
+ }
530
+ onChange={(callbackResult) =>
531
+ updateExternal({
532
+ callbackResult: callbackResult as any,
533
+ })
534
+ }
535
+ />
536
+ ),
537
+ },
538
+ ]}
539
+ />
540
+ </div>
541
+ ) : null}
542
+ </section>
214
543
 
215
- <ApproverSourceEditor
216
- value={config.approverSources ?? []}
544
+ <section className="human-approval-config__section">
545
+ <Typography.Title
546
+ level={5}
547
+ className="human-approval-config__section-title"
548
+ >
549
+ {t('approval.whoCanApprove')}
550
+ </Typography.Title>
551
+ <Typography.Paragraph
552
+ type="secondary"
553
+ className="human-approval-config__section-description"
554
+ >
555
+ {t('approval.description')}
556
+ </Typography.Paragraph>
557
+ <Typography.Text strong>{t('approval.fixedApprovers')}</Typography.Text>
558
+ <SubjectPicker
559
+ value={staticSelections}
560
+ onChange={updateStatic}
217
561
  disabled={disabled}
218
- onChange={(approverSources) => update({ approverSources })}
562
+ schema={schema}
219
563
  />
220
- </Card>
221
-
222
- <Card size="small" title={t('approval.decisionRules')}>
223
- <Space direction="vertical" size={14} style={{ width: '100%' }}>
564
+ <div className="human-approval-config__dynamic-heading">
224
565
  <div>
225
566
  <Typography.Text strong>
226
- {t('approval.approveWhen')}
567
+ {t('approval.dynamicApprovers')}
227
568
  </Typography.Text>
228
- <div style={{ marginTop: 6 }}>
229
- <ApprovalRuleEditor
230
- value={config.approvalRule}
231
- onChange={(approvalRule) => update({ approvalRule })}
569
+ </div>
570
+ <Space wrap size={8}>
571
+ <Button
572
+ size="small"
573
+ className="workflow-panel-action"
574
+ icon={<UserAddOutlined />}
575
+ aria-label={t('approval.addUsers')}
576
+ disabled={disabled}
577
+ onClick={() => addDynamic('USER')}
578
+ >
579
+ {t('approval.addUsers')}
580
+ </Button>
581
+ <Button
582
+ size="small"
583
+ className="workflow-panel-action"
584
+ icon={<UsergroupAddOutlined />}
585
+ aria-label={t('approval.addGroups')}
586
+ disabled={disabled}
587
+ onClick={() => addDynamic('USER_GROUP')}
588
+ >
589
+ {t('approval.addGroups')}
590
+ </Button>
591
+ </Space>
592
+ </div>
593
+ {dynamicSources.length === 0 ? (
594
+ <div className="human-approval-config__empty">
595
+ {t('approval.noDynamicInputs')}
596
+ </div>
597
+ ) : null}
598
+ {dynamicSources.map((source) => (
599
+ <div
600
+ className="human-approval-config__dynamic-source"
601
+ key={source.inputKey}
602
+ >
603
+ <div className="human-approval-config__dynamic-source-header">
604
+ <div>
605
+ <Typography.Text strong>
606
+ {source.provider === 'USER'
607
+ ? t('approval.dynamicUsers')
608
+ : t('approval.dynamicGroups')}
609
+ </Typography.Text>
610
+ <Typography.Text
611
+ type="secondary"
612
+ className="human-approval-config__hint"
613
+ >
614
+ {t('approval.lookupDescription')}
615
+ </Typography.Text>
616
+ </div>
617
+ <Button
618
+ type="text"
619
+ danger
620
+ icon={<DeleteOutlined />}
232
621
  disabled={disabled}
233
- schema={RULE_SCHEMA}
622
+ aria-label={t('approval.remove', { name: source.label })}
623
+ onClick={() =>
624
+ update({
625
+ subjects: config.subjects.filter(
626
+ (subject) =>
627
+ subject.source !== 'DYNAMIC' ||
628
+ subject.inputKey !== source.inputKey,
629
+ ),
630
+ })
631
+ }
234
632
  />
235
633
  </div>
634
+ <Input
635
+ aria-label={t('approval.dynamicLookupName')}
636
+ value={source.label}
637
+ disabled={disabled}
638
+ placeholder={t('approval.dynamicLookupNamePlaceholder')}
639
+ onChange={(event) =>
640
+ updateDynamic(source.inputKey, { label: event.target.value })
641
+ }
642
+ />
643
+ <Collapse
644
+ bordered={false}
645
+ items={[
646
+ {
647
+ key: 'request',
648
+ label: t('approval.lookupRequest'),
649
+ children: (
650
+ <HttpRequestConfigEditor
651
+ value={source.lookup.request}
652
+ disabled={disabled}
653
+ uiOptions={{
654
+ embedded: true,
655
+ requestDataDescriptionKey:
656
+ 'httpRequest.approvalLookupRequestDataDescription',
657
+ }}
658
+ schema={
659
+ dynamicLookupSchema?.properties?.request ?? {
660
+ type: 'object',
661
+ }
662
+ }
663
+ onChange={(request) =>
664
+ updateDynamic(source.inputKey, {
665
+ lookup: { ...source.lookup, request: request ?? {} },
666
+ })
667
+ }
668
+ />
669
+ ),
670
+ },
671
+ {
672
+ key: 'result',
673
+ label: t('approval.lookupResult'),
674
+ children: (
675
+ <CodeConfigEditor
676
+ value={source.lookup.result}
677
+ disabled={disabled}
678
+ context="approverLookup"
679
+ embedded
680
+ schema={
681
+ dynamicLookupSchema?.properties?.result ?? {
682
+ type: 'object',
683
+ }
684
+ }
685
+ onChange={(result) =>
686
+ updateDynamic(source.inputKey, {
687
+ lookup: {
688
+ ...source.lookup,
689
+ result: result as EmbeddedCodeConfig,
690
+ },
691
+ })
692
+ }
693
+ />
694
+ ),
695
+ },
696
+ ]}
697
+ />
236
698
  </div>
237
- <div>
699
+ ))}
700
+ </section>
701
+
702
+ <section className="human-approval-config__section">
703
+ <Typography.Title
704
+ level={5}
705
+ className="human-approval-config__section-title"
706
+ >
707
+ {t('approval.decisionRules')}
708
+ </Typography.Title>
709
+ <Typography.Paragraph
710
+ type="secondary"
711
+ className="human-approval-config__section-description"
712
+ >
713
+ {t('approval.decisionRulesDescription')}
714
+ </Typography.Paragraph>
715
+ <div className="human-approval-config__rule-grid">
716
+ <div className="human-approval-config__rule">
717
+ <Typography.Text strong>
718
+ {t('approval.approveWhen')}
719
+ </Typography.Text>
720
+ <ApprovalRuleEditor
721
+ value={config.approvalRule}
722
+ onChange={(approvalRule) => update({ approvalRule })}
723
+ disabled={disabled}
724
+ schema={RULE_SCHEMA}
725
+ decision="APPROVE"
726
+ />
727
+ </div>
728
+ <div className="human-approval-config__rule human-approval-config__rule--reject">
238
729
  <Typography.Text strong>{t('approval.rejectWhen')}</Typography.Text>
239
- <div style={{ marginTop: 6 }}>
240
- <ApprovalRuleEditor
241
- value={config.rejectionRule}
242
- onChange={(rejectionRule) => update({ rejectionRule })}
243
- disabled={disabled}
244
- schema={RULE_SCHEMA}
245
- />
246
- </div>
730
+ <ApprovalRuleEditor
731
+ value={config.rejectionRule}
732
+ onChange={(rejectionRule) => update({ rejectionRule })}
733
+ disabled={disabled}
734
+ schema={RULE_SCHEMA}
735
+ decision="REJECT"
736
+ />
247
737
  </div>
248
- </Space>
249
- </Card>
738
+ </div>
739
+ </section>
250
740
 
251
- <Card
252
- size="small"
253
- title={
254
- <Space>
255
- <ApiOutlined />
256
- <span>{t('approval.workflow')}</span>
257
- </Space>
258
- }
259
- >
260
- <Typography.Paragraph type="secondary">
261
- {t('approval.workflowDescription')}
741
+ <section className="human-approval-config__section">
742
+ <Typography.Title
743
+ level={5}
744
+ className="human-approval-config__section-title"
745
+ >
746
+ {t('approval.timeout')}
747
+ </Typography.Title>
748
+ <Typography.Paragraph
749
+ type="secondary"
750
+ className="human-approval-config__section-description"
751
+ >
752
+ {t('approval.timeoutDescription')}
262
753
  </Typography.Paragraph>
263
- <Select
264
- allowClear
265
- showSearch
266
- optionFilterProp="label"
754
+ <TimeoutEditor
755
+ value={config.timeout}
267
756
  disabled={disabled}
268
- value={config.approvalWorkflowId}
269
- placeholder={t('approval.builtInInbox')}
270
- options={approvalWorkflows.map((workflow) => ({
271
- value: workflow.id,
272
- label: workflow.name,
273
- }))}
274
- onChange={(approvalWorkflowId) => {
275
- const workflow = approvalWorkflows.find(
276
- (item) => item.id === approvalWorkflowId,
277
- );
278
- update({
279
- approvalWorkflowId,
280
- approvalWorkflowInputBindings: workflow
281
- ? Object.fromEntries(
282
- workflow.inputParameters.map((parameter) => [
283
- parameter.key,
284
- config.approvalWorkflowInputBindings?.[parameter.key] ?? {
285
- source: 'WORKFLOW',
286
- path: parameter.key,
287
- },
288
- ]),
289
- )
290
- : {},
291
- });
292
- }}
293
- style={{ width: '100%' }}
757
+ onChange={(timeout) => update({ timeout })}
294
758
  />
295
- <Typography.Text
296
- type="secondary"
297
- style={{ display: 'block', fontSize: 12, marginTop: 8 }}
298
- >
299
- {config.approvalWorkflowId
300
- ? t('approval.workflowHint')
301
- : t('approval.builtInInboxHint')}
302
- </Typography.Text>
303
- {selectedApprovalWorkflow &&
304
- selectedApprovalWorkflow.inputParameters.length > 0 && (
305
- <>
306
- <Divider />
307
- <Typography.Text strong>
308
- {t('approval.workflowInputs')}
309
- </Typography.Text>
310
- <Typography.Paragraph
311
- type="secondary"
312
- style={{ marginTop: 4, marginBottom: 12 }}
313
- >
314
- {t('approval.workflowInputsDescription')}
315
- </Typography.Paragraph>
316
- <Space direction="vertical" size={14} style={{ width: '100%' }}>
317
- {selectedApprovalWorkflow.inputParameters.map((parameter) => {
318
- const name = parameter.label?.trim() || parameter.key;
319
- return (
320
- <div key={parameter.key}>
321
- <Space size={6} style={{ marginBottom: 6 }}>
322
- <Typography.Text strong>{name}</Typography.Text>
323
- {parameter.required && (
324
- <Tag color="blue">{t('approval.required')}</Tag>
325
- )}
326
- </Space>
327
- <ParameterBindingEditor
328
- name={name}
329
- defaultPath={parameter.key}
330
- value={
331
- config.approvalWorkflowInputBindings?.[parameter.key]
332
- }
333
- disabled={disabled}
334
- onChange={(binding) =>
335
- update({
336
- approvalWorkflowInputBindings: {
337
- ...config.approvalWorkflowInputBindings,
338
- [parameter.key]: binding,
339
- },
340
- })
341
- }
342
- />
343
- </div>
344
- );
345
- })}
346
- </Space>
347
- </>
348
- )}
349
- </Card>
350
-
351
- <TimeoutSection
352
- value={config.timeout}
353
- disabled={disabled}
354
- onChange={(timeout) => update({ timeout })}
355
- />
356
- </Space>
759
+ </section>
760
+ </div>
357
761
  );
358
762
  }
359
763
 
360
764
  type TimeoutUnit = 'MINUTES' | 'HOURS' | 'DAYS';
361
765
 
362
- function TimeoutSection({
766
+ function TimeoutEditor({
363
767
  value,
364
768
  disabled,
365
769
  onChange,
@@ -372,10 +776,13 @@ function TimeoutSection({
372
776
  const [unit, setUnit] = useState<TimeoutUnit>(() => preferredUnit(value));
373
777
  const never = value.durationSeconds === 0;
374
778
  const factor = unit === 'DAYS' ? 86400 : unit === 'HOURS' ? 3600 : 60;
375
- const amount = never ? 1 : Math.max(1, value.durationSeconds / factor);
779
+ const amount =
780
+ never || value.durationSeconds === null
781
+ ? value.durationSeconds
782
+ : value.durationSeconds / factor;
376
783
 
377
784
  return (
378
- <Card size="small" title={t('approval.timeout')}>
785
+ <Space direction="vertical" size={14} style={{ width: '100%' }}>
379
786
  <Radio.Group
380
787
  value={never ? 'NEVER' : 'AFTER'}
381
788
  disabled={disabled}
@@ -389,24 +796,18 @@ function TimeoutSection({
389
796
  <Radio value="NEVER">{t('approval.neverTimeout')}</Radio>
390
797
  <Radio value="AFTER">{t('approval.timeoutAfter')}</Radio>
391
798
  </Radio.Group>
392
-
393
- {!never && (
394
- <Space
395
- direction="vertical"
396
- size={12}
397
- style={{ width: '100%', marginTop: 16 }}
398
- >
799
+ {!never ? (
800
+ <>
399
801
  <Space.Compact style={{ width: '100%' }}>
400
802
  <InputNumber
401
803
  aria-label={t('approval.timeoutAmount')}
402
- min={1}
403
804
  precision={0}
404
805
  value={amount}
405
806
  disabled={disabled}
406
807
  onChange={(next) =>
407
808
  onChange({
408
809
  ...value,
409
- durationSeconds: Math.max(1, next ?? 1) * factor,
810
+ durationSeconds: next === null ? null : next * factor,
410
811
  })
411
812
  }
412
813
  style={{ width: '100%' }}
@@ -422,43 +823,42 @@ function TimeoutSection({
422
823
  ]}
423
824
  onChange={(next: TimeoutUnit) => {
424
825
  setUnit(next);
826
+ const nextFactor =
827
+ next === 'DAYS' ? 86400 : next === 'HOURS' ? 3600 : 60;
828
+ onChange({
829
+ ...value,
830
+ durationSeconds: (amount ?? 1) * nextFactor,
831
+ });
425
832
  }}
426
833
  style={{ width: 130 }}
427
834
  />
428
835
  </Space.Compact>
429
- <div>
430
- <Typography.Text strong>
431
- {t('approval.whenTimeRunsOut')}
432
- </Typography.Text>
433
- <Select
434
- aria-label={t('approval.timeoutAction')}
435
- value={value.action}
436
- disabled={disabled}
437
- options={[
438
- { label: t('approval.autoReject'), value: 'REJECTED' },
439
- { label: t('approval.autoApprove'), value: 'APPROVED' },
440
- ]}
441
- onChange={(action) => onChange({ ...value, action })}
442
- style={{ width: '100%', marginTop: 6 }}
443
- />
444
- </div>
445
- </Space>
446
- )}
447
- {never && (
448
- <Typography.Paragraph
449
- type="secondary"
450
- style={{ marginTop: 12, marginBottom: 0 }}
451
- >
836
+ <Select
837
+ aria-label={t('approval.timeoutAction')}
838
+ value={value.action}
839
+ disabled={disabled}
840
+ options={[
841
+ { label: t('approval.autoReject'), value: 'REJECTED' },
842
+ { label: t('approval.autoApprove'), value: 'APPROVED' },
843
+ ]}
844
+ onChange={(action) => onChange({ ...value, action })}
845
+ style={{ width: '100%' }}
846
+ />
847
+ </>
848
+ ) : (
849
+ <Typography.Text type="secondary">
452
850
  {t('approval.waitHint')}
453
- </Typography.Paragraph>
851
+ </Typography.Text>
454
852
  )}
455
- </Card>
853
+ </Space>
456
854
  );
457
855
  }
458
856
 
459
857
  function preferredUnit(timeout: ApprovalConfig['timeout']): TimeoutUnit {
460
858
  const seconds = timeout.durationSeconds;
461
- if (seconds > 0 && seconds % 86400 === 0) return 'DAYS';
462
- if (seconds > 0 && seconds % 3600 === 0) return 'HOURS';
859
+ if (typeof seconds === 'number' && seconds > 0 && seconds % 86400 === 0)
860
+ return 'DAYS';
861
+ if (typeof seconds === 'number' && seconds > 0 && seconds % 3600 === 0)
862
+ return 'HOURS';
463
863
  return 'MINUTES';
464
864
  }