@gadmin2n/schematics 0.0.138 → 0.0.140

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 (314) hide show
  1. package/dist/lib/application/files/gadmin2-game-angle-demo/Jenkinsfile +6 -34
  2. package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/approval.prisma +199 -0
  3. package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/system.prisma +9 -0
  4. package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/workflow.prisma +191 -14
  5. package/dist/lib/application/files/gadmin2-game-angle-demo/gitignore +6 -5
  6. package/dist/lib/application/files/gadmin2-game-angle-demo/readme.md +10 -3
  7. package/dist/lib/application/files/gadmin2-game-angle-demo/server/migrate-between-pg-schemas.js +6 -4
  8. package/dist/lib/application/files/gadmin2-game-angle-demo/server/package.json +5 -2
  9. package/dist/lib/application/files/gadmin2-game-angle-demo/server/prisma.config.ts +12 -3
  10. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/migrate-human-approval-configs.ts +86 -0
  11. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-node-types.ts +682 -121
  12. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow.seed.ts +110 -1
  13. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/config/index.ts +28 -0
  14. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/json-body-parser.spec.ts +61 -0
  15. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/json-body-parser.ts +7 -0
  16. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/structured-all-exceptions.filter.spec.ts +54 -0
  17. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/lib/structured-all-exceptions.filter.ts +86 -0
  18. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/main.ts +9 -3
  19. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/approvalChannel/approval-channel.controller.ts +89 -0
  20. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/approvalChannel/approval-channel.dto.ts +68 -0
  21. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/approvalChannel/approval-channel.service.spec.ts +177 -0
  22. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/approvalChannel/approval-channel.service.ts +283 -0
  23. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/approvalChannel/approvalChannel.module.ts +10 -0
  24. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/code-executor.spec.ts +42 -0
  25. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/code-executor.ts +108 -0
  26. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/code-runtime.controller.ts +101 -0
  27. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/code-runtime.dto.ts +29 -0
  28. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/codeRuntime/codeRuntime.module.ts +21 -0
  29. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-handler.registry.ts +30 -0
  30. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-handler.ts +15 -0
  31. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-runtime.controller.spec.ts +105 -0
  32. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-runtime.controller.ts +96 -0
  33. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-runtime.dto.ts +78 -0
  34. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-signal-outbox.service.spec.ts +56 -0
  35. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-signal-outbox.service.ts +111 -0
  36. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-token.spec.ts +23 -0
  37. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction-token.ts +18 -0
  38. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction.service.spec.ts +240 -0
  39. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction.service.ts +339 -0
  40. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-interaction.types.ts +74 -0
  41. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/external-wait.handler.ts +47 -0
  42. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/externalInteraction.module.ts +41 -0
  43. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/human-approval.handler.spec.ts +70 -0
  44. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/human-approval.handler.ts +76 -0
  45. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/workflow-callback-url.controller.ts +12 -0
  46. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/workflow-callback-url.service.spec.ts +227 -0
  47. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/externalInteraction/workflow-callback-url.service.ts +121 -0
  48. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/httpRequest/http-request-runtime.controller.ts +160 -0
  49. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/httpRequest/http-request-runtime.dto.ts +41 -0
  50. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/httpRequest/http-request-runtime.util.spec.ts +171 -0
  51. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/httpRequest/http-request-runtime.util.ts +245 -0
  52. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/httpRequest/httpRequest.module.ts +22 -0
  53. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/approval-rule-evaluator.spec.ts +68 -0
  54. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/approval-rule-evaluator.ts +126 -0
  55. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/approval-rule.types.ts +34 -0
  56. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/approval-signal-outbox.service.ts +115 -0
  57. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/approval-subject-source.util.spec.ts +45 -0
  58. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/approval-subject-source.util.ts +59 -0
  59. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.controller.ts +72 -0
  60. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.dto.ts +144 -0
  61. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.errors.ts +19 -0
  62. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.external-decision.spec.ts +350 -0
  63. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/human-approval.service.ts +774 -0
  64. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/humanApproval.module.ts +46 -0
  65. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/legacy-approval-config-migration.ts +227 -0
  66. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/outbox-retry.util.ts +14 -0
  67. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/runtime/human-approval-runtime.controller.ts +151 -0
  68. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/runtime/human-approval-runtime.dto.ts +88 -0
  69. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/humanApproval/runtime/runtime-token.guard.ts +43 -0
  70. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/index.ts +21 -1
  71. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/integrationConnection/integration-connection.controller.ts +77 -0
  72. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/integrationConnection/integration-connection.dto.ts +98 -0
  73. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/integrationConnection/integration-connection.service.ts +277 -0
  74. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/integrationConnection/integration-secret-cipher.spec.ts +14 -0
  75. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/integrationConnection/integration-secret-cipher.ts +59 -0
  76. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/integrationConnection/integrationConnection.module.ts +10 -0
  77. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/actor-context.util.ts +27 -0
  78. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/providers/user-group.provider.ts +208 -0
  79. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/providers/user.provider.ts +168 -0
  80. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/subject-provider.controller.spec.ts +157 -0
  81. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/subject-provider.controller.ts +176 -0
  82. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/subject-provider.dto.ts +21 -0
  83. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/subject-provider.errors.ts +78 -0
  84. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/subject-provider.registry.spec.ts +100 -0
  85. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/subject-provider.registry.ts +115 -0
  86. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/subject-provider.types.ts +97 -0
  87. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/subjectProvider/subjectProvider.module.ts +34 -0
  88. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/temporalTenantConfig/temporalTenantConfig.controller.spec.ts +89 -1
  89. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/temporalTenantConfig/temporalTenantConfig.controller.ts +4 -0
  90. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/userGroup/user-group.controller.ts +119 -0
  91. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/userGroup/user-group.dto.ts +91 -0
  92. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/userGroup/user-group.errors.ts +34 -0
  93. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/userGroup/user-group.service.spec.ts +161 -0
  94. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/userGroup/user-group.service.ts +390 -0
  95. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/userGroup/userGroup.module.ts +10 -0
  96. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/dsl-validate.util.spec.ts +17 -0
  97. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/dsl-validate.util.ts +8 -2
  98. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/parameter-binding.ts +93 -0
  99. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-callable.spec.ts +158 -0
  100. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-callable.ts +155 -0
  101. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.spec.ts +363 -0
  102. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.service.ts +354 -0
  103. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-compiler.types.ts +43 -0
  104. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-data-edge.util.spec.ts +174 -0
  105. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-data-edge.util.ts +149 -0
  106. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-dsl-comparison.ts +43 -0
  107. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-execution.dto.ts +1 -1
  108. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-export.dto.ts +4 -0
  109. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-export.service.ts +70 -28
  110. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-handle-validator.ts +128 -0
  111. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.ts +12 -1
  112. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.module.ts +18 -3
  113. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.spec.ts +369 -22
  114. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.ts +319 -90
  115. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/node-config-validator.service.spec.ts +79 -0
  116. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/node-config-validator.service.ts +62 -0
  117. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/schema.types.ts +10 -0
  118. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/subject-config-validator.service.spec.ts +124 -0
  119. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/subject-config-validator.service.ts +236 -0
  120. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/widget-catalog.service.spec.ts +49 -0
  121. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/widget-catalog.service.ts +69 -0
  122. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowConfig/workflowConfig.module.ts +20 -0
  123. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/node-instance-config.util.spec.ts +15 -0
  124. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/node-instance-config.util.ts +25 -0
  125. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.controller.ts +103 -11
  126. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.dto.ts +98 -0
  127. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.module.ts +3 -0
  128. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.service.spec.ts +72 -62
  129. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.service.ts +148 -11
  130. package/dist/lib/application/files/gadmin2-game-angle-demo/web/package.json +13 -9
  131. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/App.tsx +5 -2
  132. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/authProvider.ts +2 -2
  133. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/BulkActions.tsx +0 -5
  134. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/SearchBar.tsx +26 -18
  135. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/auditLog/components/eventList/index.tsx +2 -2
  136. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/auditLog/components/logButton/index.tsx +24 -17
  137. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/auditLog/components/logList/index.tsx +7 -18
  138. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/auditLog/components/modalDiffViewer/index.tsx +2 -2
  139. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/contexts/color-mode/index.tsx +288 -33
  140. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/contexts/color-mode/themeStyles.ts +97 -0
  141. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/SettingDrawer.tsx +251 -0
  142. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/header.tsx +47 -19
  143. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/layout.tsx +18 -9
  144. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/menuRenderer.tsx +155 -0
  145. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/sider.tsx +123 -129
  146. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/config/routeRegistry.tsx +16 -0
  147. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/constants/layout.ts +2 -1
  148. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/dev-shell/AddDataModal.tsx +98 -3
  149. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/dev-shell/AddPageModal.tsx +101 -0
  150. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/dev-shell/DevShell.tsx +8 -0
  151. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/dev-shell/style.css +51 -0
  152. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/helpers/form.tsx +1 -1
  153. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/helpers/list.tsx +1 -1
  154. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/helpers/login.ts +40 -1
  155. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/helpers/show.tsx +5 -5
  156. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useDynamicResources.tsx +16 -1
  157. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/hooks/useListPageState.ts +10 -7
  158. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/i18n.ts +4 -2
  159. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/common.json +26 -2
  160. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/workflow.json +556 -0
  161. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/common.json +26 -2
  162. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/workflow.json +556 -0
  163. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/plugins/devShellPlugin.ts +152 -2
  164. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agenda/index.tsx +6 -1
  165. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agenda/show.tsx +41 -9
  166. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agendaJob/edit.tsx +1 -1
  167. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agendaJob/list.tsx +10 -8
  168. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agendaJob/show.tsx +3 -3
  169. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/audit/components/action-cell.css +1 -1
  170. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/audit/edit.tsx +1 -1
  171. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/audit/show.tsx +3 -6
  172. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasCell.css +3 -0
  173. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasCell.tsx +45 -13
  174. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasComponentLibrary.tsx +45 -22
  175. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasListPage.tsx +168 -101
  176. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasPage.tsx +248 -74
  177. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasToolbar.tsx +33 -18
  178. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CodeFloatWindow.tsx +16 -10
  179. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/PublishModal.tsx +1 -1
  180. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/canvasContextMenuRegistry.tsx +31 -0
  181. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/canvasDefaults.ts +15 -0
  182. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/BarChartDataSourceModal.tsx +16 -11
  183. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/CanvasAiModal.tsx +25 -21
  184. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/ExportModal.tsx +6 -1
  185. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/LineChartDataSourceModal.tsx +9 -10
  186. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/MultiChartConfigModal.tsx +4 -7
  187. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/MultiChartDataSourceModal.tsx +23 -9
  188. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/NumCardDataSourceModal.tsx +16 -11
  189. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/PromptModal.tsx +2 -5
  190. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/RadarChartDataSourceModal.tsx +16 -11
  191. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/TableConfigModal.tsx +2 -9
  192. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/TableDataSourceModal.tsx +23 -12
  193. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/canvasModalProps.ts +2 -17
  194. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/sectionCompactor.test.ts +149 -0
  195. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/sectionCompactor.ts +111 -17
  196. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/types.ts +1 -0
  197. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/whiteboardLayout.test.ts +83 -0
  198. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/whiteboardLayout.ts +118 -0
  199. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/whiteboardName.test.ts +26 -0
  200. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas-page/index.tsx +9 -1
  201. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/game/edit.tsx +1 -1
  202. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/game/list.tsx +10 -8
  203. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/game/show.tsx +3 -6
  204. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/human-approval/DecisionModal.tsx +71 -0
  205. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/human-approval/inbox.tsx +216 -0
  206. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/page/Components/AssignRolesModal.tsx +6 -1
  207. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/permissionReadme/index.tsx +8 -8
  208. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/Components/modal.tsx +1 -1
  209. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/resource/list.tsx +5 -5
  210. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/role/Components/modal.tsx +1 -1
  211. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/user/components/show-drawer.tsx +1 -1
  212. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/approval-channels/ApprovalChannelModal.test.tsx +84 -0
  213. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/approval-channels/ApprovalChannelModal.tsx +141 -0
  214. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/approval-channels/approval-channel.types.ts +16 -0
  215. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/approval-channels/index.tsx +208 -0
  216. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/CreateNodeInstanceDrawer.tsx +154 -0
  217. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/CustomNode.tsx +194 -5
  218. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/DeletableEdge.tsx +76 -0
  219. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/DslView.tsx +1 -1
  220. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/EnhancedFlowRenderer.tsx +176 -22
  221. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ExecutionStatusNode.test.tsx +62 -0
  222. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ExecutionStatusNode.tsx +94 -5
  223. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ExportModal.tsx +15 -10
  224. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/FlowRenderer.tsx +251 -70
  225. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ImportModal.tsx +18 -24
  226. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/InstanceRequiredDialog.tsx +106 -0
  227. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/LookupConnectionDialog.test.tsx +45 -0
  228. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/LookupConnectionDialog.tsx +43 -0
  229. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NewNodeDefaults.test.tsx +279 -0
  230. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodeEditModal.tsx +6 -7
  231. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodePropertyPanel.test.tsx +335 -0
  232. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodePropertyPanel.tsx +433 -237
  233. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ParameterBindingEditor.tsx +179 -0
  234. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/RunWorkflowModal.tsx +18 -16
  235. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/StatusCards.tsx +20 -16
  236. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/VersionPanel.tsx +6 -4
  237. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/ConnectionModal.test.tsx +68 -0
  238. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/ConnectionModal.tsx +367 -0
  239. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/connection.types.ts +21 -0
  240. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/connections/index.tsx +171 -0
  241. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/editor.tsx +38 -22
  242. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/hooks/useNodeInstanceLibrary.ts +41 -0
  243. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/hooks/useWorkflowAgent.ts +6 -0
  244. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/index.tsx +27 -20
  245. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.tsx +8 -11
  246. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instances.tsx +6 -1
  247. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/components/NodeInstanceForm.tsx +56 -23
  248. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/create.tsx +21 -6
  249. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/edit.tsx +17 -20
  250. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/index.tsx +6 -1
  251. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/SchemaField.tsx +311 -0
  252. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/SchemaForm.test.tsx +218 -0
  253. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/SchemaForm.tsx +83 -0
  254. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/default-widgets.tsx +135 -0
  255. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/schema-defaults.ts +36 -0
  256. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/schema.types.ts +32 -0
  257. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/widget-registry.test.tsx +23 -0
  258. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/schema-form/widget-registry.tsx +52 -0
  259. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/show.tsx +9 -13
  260. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ApprovalRequestTriggerConfigEditor.tsx +39 -0
  261. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ApprovalRuleEditor.test.tsx +20 -0
  262. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ApprovalRuleEditor.tsx +72 -0
  263. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ApproverSourceEditor.test.tsx +47 -0
  264. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ApproverSourceEditor.tsx +185 -0
  265. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/CallableInputParametersEditor.test.tsx +102 -0
  266. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/CallableInputParametersEditor.tsx +150 -0
  267. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/CodeConfigEditor.tsx +103 -0
  268. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ExternalRequestConfigEditor.test.tsx +93 -0
  269. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ExternalRequestConfigEditor.tsx +196 -0
  270. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ExternalWaitConfigEditor.tsx +303 -0
  271. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/HttpRequestConfigEditor.test.tsx +189 -0
  272. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/HttpRequestConfigEditor.tsx +706 -0
  273. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/HumanApprovalConfigEditor.test.tsx +86 -0
  274. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/HumanApprovalConfigEditor.tsx +458 -0
  275. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ReturnResultConfigEditor.test.tsx +53 -0
  276. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/ReturnResultConfigEditor.tsx +91 -0
  277. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SubjectPicker.test.tsx +61 -0
  278. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SubjectPicker.tsx +266 -0
  279. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SubmitApprovalResultConfigEditor.tsx +104 -0
  280. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/SubmitExternalResultConfigEditor.tsx +98 -0
  281. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/UserGroupCreateModal.tsx +70 -0
  282. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/UserGroupEditModal.tsx +138 -0
  283. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/approver-source.test.ts +25 -0
  284. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/approver-source.ts +42 -0
  285. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/widgets/subject-provider.api.ts +95 -0
  286. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/show.tsx +15 -11
  287. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/temporal-tenant/index.tsx +49 -8
  288. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/types/parameter-binding.ts +49 -0
  289. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/types.ts +31 -2
  290. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/lookupConnection.test.ts +208 -0
  291. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/lookupConnection.ts +246 -0
  292. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/newNodeConfig.ts +73 -0
  293. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/removeWorkflowEdges.test.ts +34 -0
  294. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/removeWorkflowEdges.ts +18 -0
  295. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveLookupPorts.ts +66 -0
  296. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveOutputs.test.ts +39 -0
  297. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveOutputs.ts +48 -0
  298. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveWorkflowDisplay.test.ts +51 -0
  299. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/utils/resolveWorkflowDisplay.ts +32 -0
  300. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/edit.tsx +1 -1
  301. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/list.tsx +10 -8
  302. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/show.tsx +3 -3
  303. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/styles/antd-theme-vars.css +93 -0
  304. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/styles/antd.css +8 -8
  305. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/styles/fc.css +4 -4
  306. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/styles/index.css +20 -5
  307. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/styles/show-drawer.module.css +3 -3
  308. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/styles/show-page.module.css +3 -3
  309. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/styles/theme-styles.css +81 -0
  310. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/test/setup.ts +5 -0
  311. package/dist/lib/application/files/gadmin2-game-angle-demo/web/vite.config.ts +1 -7
  312. package/dist/lib/application/files/gadmin2-game-angle-demo/web/vitest.config.ts +12 -0
  313. package/package.json +1 -1
  314. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/components/DynamicConfigForm.tsx +0 -154
@@ -0,0 +1,79 @@
1
+ import { BadRequestException } from '@nestjs/common';
2
+ import { NodeConfigValidatorService } from './node-config-validator.service';
3
+
4
+ describe('NodeConfigValidatorService', () => {
5
+ const schema = {
6
+ type: 'object',
7
+ required: ['count', 'name'],
8
+ properties: {
9
+ count: { type: 'integer', minimum: 1 },
10
+ name: { type: 'string', minLength: 1 },
11
+ },
12
+ additionalProperties: false,
13
+ };
14
+
15
+ let service: NodeConfigValidatorService;
16
+
17
+ beforeEach(() => {
18
+ service = new NodeConfigValidatorService();
19
+ });
20
+
21
+ it('accepts an object that matches the JSON schema', () => {
22
+ expect(() =>
23
+ service.validateOrThrow('12:3', schema, { count: 2, name: 'Review' }),
24
+ ).not.toThrow();
25
+ });
26
+
27
+ it('returns stable paths, keywords and all AJV errors', () => {
28
+ try {
29
+ service.validateOrThrow('12:3', schema, { count: 0, name: '' });
30
+ fail('expected validation to fail');
31
+ } catch (error) {
32
+ expect(error).toBeInstanceOf(BadRequestException);
33
+ expect((error as BadRequestException).getResponse()).toEqual({
34
+ code: 'NODE_CONFIG_INVALID',
35
+ errors: expect.arrayContaining([
36
+ { path: '/count', keyword: 'minimum', message: 'must be >= 1' },
37
+ {
38
+ path: '/name',
39
+ keyword: 'minLength',
40
+ message: 'must NOT have fewer than 1 characters',
41
+ },
42
+ ]),
43
+ });
44
+ expect(
45
+ ((error as BadRequestException).getResponse() as { errors: unknown[] })
46
+ .errors,
47
+ ).toHaveLength(2);
48
+ }
49
+ });
50
+
51
+ it.each([null, [], 'value', 1, true])(
52
+ 'rejects a non-object config: %p',
53
+ (config) => {
54
+ expect(() => service.validateOrThrow('12:3', schema, config)).toThrow(
55
+ expect.objectContaining({
56
+ response: {
57
+ code: 'NODE_CONFIG_INVALID',
58
+ errors: [
59
+ {
60
+ path: '/',
61
+ keyword: 'type',
62
+ message: 'must be object',
63
+ },
64
+ ],
65
+ },
66
+ }),
67
+ );
68
+ },
69
+ );
70
+
71
+ it('compiles a schema only once for the same caller-provided key', () => {
72
+ const compile = jest.spyOn((service as any).ajv, 'compile');
73
+
74
+ service.validateOrThrow('12:3', schema, { count: 1, name: 'A' });
75
+ service.validateOrThrow('12:3', schema, { count: 2, name: 'B' });
76
+
77
+ expect(compile).toHaveBeenCalledTimes(1);
78
+ });
79
+ });
@@ -0,0 +1,62 @@
1
+ import { BadRequestException, Injectable } from '@nestjs/common';
2
+ import Ajv, { ErrorObject, ValidateFunction } from 'ajv';
3
+ import addFormats from 'ajv-formats';
4
+ import { JsonSchema } from './schema.types';
5
+
6
+ export interface NodeConfigValidationError {
7
+ path: string;
8
+ keyword: string;
9
+ message: string;
10
+ }
11
+
12
+ @Injectable()
13
+ export class NodeConfigValidatorService {
14
+ private readonly ajv: Ajv;
15
+ private readonly cache = new Map<string, ValidateFunction>();
16
+
17
+ constructor() {
18
+ this.ajv = new Ajv({ allErrors: true, strict: false });
19
+ addFormats(this.ajv);
20
+ }
21
+
22
+ validateOrThrow(
23
+ schemaKey: string,
24
+ schema: JsonSchema,
25
+ config: unknown,
26
+ ): void {
27
+ if (
28
+ config === null ||
29
+ typeof config !== 'object' ||
30
+ Array.isArray(config)
31
+ ) {
32
+ this.throwInvalid([
33
+ { path: '/', keyword: 'type', message: 'must be object' },
34
+ ]);
35
+ }
36
+
37
+ const validate =
38
+ this.cache.get(schemaKey) ?? this.compile(schemaKey, schema);
39
+
40
+ if (!validate(config)) {
41
+ this.throwInvalid((validate.errors ?? []).map(this.formatError));
42
+ }
43
+ }
44
+
45
+ private compile(schemaKey: string, schema: JsonSchema): ValidateFunction {
46
+ const validate = this.ajv.compile(schema);
47
+ this.cache.set(schemaKey, validate);
48
+ return validate;
49
+ }
50
+
51
+ private readonly formatError = (
52
+ error: ErrorObject,
53
+ ): NodeConfigValidationError => ({
54
+ path: error.instancePath || '/',
55
+ keyword: error.keyword,
56
+ message: error.message ?? 'is invalid',
57
+ });
58
+
59
+ private throwInvalid(errors: NodeConfigValidationError[]): never {
60
+ throw new BadRequestException({ code: 'NODE_CONFIG_INVALID', errors });
61
+ }
62
+ }
@@ -0,0 +1,10 @@
1
+ export type JsonPrimitive = string | number | boolean | null;
2
+
3
+ export type JsonValue =
4
+ | JsonPrimitive
5
+ | JsonValue[]
6
+ | { [key: string]: JsonValue };
7
+
8
+ export type JsonSchema = Record<string, JsonValue>;
9
+
10
+ export type UiSchema = Record<string, JsonValue>;
@@ -0,0 +1,124 @@
1
+ import { BadRequestException } from '@nestjs/common';
2
+ import { SubjectProviderError } from '../subjectProvider/subject-provider.errors';
3
+ import { SubjectProviderRegistry } from '../subjectProvider/subject-provider.registry';
4
+ import {
5
+ ActorContext,
6
+ SubjectProvider,
7
+ } from '../subjectProvider/subject-provider.types';
8
+ import { SubjectConfigValidatorService } from './subject-config-validator.service';
9
+
10
+ const actor: ActorContext = {
11
+ userId: 'user-1',
12
+ username: 'alice',
13
+ roles: ['EDITOR'],
14
+ };
15
+
16
+ const schema = {
17
+ type: 'object',
18
+ properties: {
19
+ approval: {
20
+ type: 'object',
21
+ properties: {
22
+ subjects: {
23
+ type: 'array',
24
+ 'x-gadmin-capability': 'subject-references',
25
+ },
26
+ },
27
+ },
28
+ },
29
+ };
30
+
31
+ function provider(): jest.Mocked<SubjectProvider> {
32
+ return {
33
+ key: 'USER_GROUP',
34
+ descriptor: jest.fn(),
35
+ search: jest.fn(),
36
+ create: jest.fn(),
37
+ validate: jest.fn().mockResolvedValue({ valid: true }),
38
+ preview: jest.fn(),
39
+ resolve: jest.fn(),
40
+ };
41
+ }
42
+
43
+ describe('SubjectConfigValidatorService', () => {
44
+ let registry: SubjectProviderRegistry;
45
+ let subjectProvider: jest.Mocked<SubjectProvider>;
46
+ let service: SubjectConfigValidatorService;
47
+
48
+ beforeEach(() => {
49
+ registry = new SubjectProviderRegistry();
50
+ subjectProvider = provider();
51
+ registry.register(subjectProvider);
52
+ service = new SubjectConfigValidatorService(registry);
53
+ });
54
+
55
+ it('finds annotated nested fields and validates grouped provider refs', async () => {
56
+ await service.validateSubjects(
57
+ schema,
58
+ {
59
+ approval: {
60
+ subjects: [
61
+ { provider: 'USER_GROUP', refs: ['group:ops'] },
62
+ { provider: 'USER_GROUP', refs: ['group:security'] },
63
+ ],
64
+ },
65
+ },
66
+ actor,
67
+ );
68
+
69
+ expect(subjectProvider.validate).toHaveBeenCalledWith(
70
+ ['group:ops', 'group:security'],
71
+ actor,
72
+ );
73
+ });
74
+
75
+ it('rejects malformed, duplicate, and provider-invalid references', async () => {
76
+ subjectProvider.validate.mockResolvedValue({
77
+ valid: false,
78
+ issues: [{ ref: 'group:missing', code: 'NOT_FOUND', message: 'Missing' }],
79
+ });
80
+
81
+ await expect(
82
+ service.validateSubjects(
83
+ schema,
84
+ {
85
+ approval: {
86
+ subjects: [{ provider: 'USER_GROUP', refs: ['group:missing'] }],
87
+ },
88
+ },
89
+ actor,
90
+ ),
91
+ ).rejects.toMatchObject({
92
+ response: { code: 'SUBJECT_REF_INVALID' },
93
+ });
94
+ });
95
+
96
+ it('preserves registry errors and sanitizes unexpected provider failures', async () => {
97
+ await expect(
98
+ service.validateSubjects(
99
+ schema,
100
+ {
101
+ approval: {
102
+ subjects: [{ provider: 'MISSING', refs: ['value'] }],
103
+ },
104
+ },
105
+ actor,
106
+ ),
107
+ ).rejects.toBeInstanceOf(SubjectProviderError);
108
+
109
+ subjectProvider.validate.mockRejectedValueOnce(
110
+ new BadRequestException({ code: 'PROVIDER_LEAK', secret: 'secret DSN' }),
111
+ );
112
+ await expect(
113
+ service.validateSubjects(
114
+ schema,
115
+ {
116
+ approval: {
117
+ subjects: [{ provider: 'USER_GROUP', refs: ['group:ops'] }],
118
+ },
119
+ },
120
+ actor,
121
+ ),
122
+ ).rejects.toMatchObject({ code: 'SUBJECT_PROVIDER_UNAVAILABLE' });
123
+ });
124
+ });
@@ -0,0 +1,236 @@
1
+ import { BadRequestException, Injectable } from '@nestjs/common';
2
+ import {
3
+ SubjectProviderError,
4
+ SubjectProviderUnavailableError,
5
+ } from '../subjectProvider/subject-provider.errors';
6
+ import { SubjectProviderRegistry } from '../subjectProvider/subject-provider.registry';
7
+ import {
8
+ ActorContext,
9
+ ProviderValidationResult,
10
+ } from '../subjectProvider/subject-provider.types';
11
+ import { JsonSchema } from './schema.types';
12
+
13
+ interface SubjectValidationIssue {
14
+ path: string;
15
+ code: string;
16
+ message: string;
17
+ provider?: string;
18
+ ref?: string;
19
+ }
20
+
21
+ @Injectable()
22
+ export class SubjectConfigValidatorService {
23
+ constructor(private readonly registry: SubjectProviderRegistry) {}
24
+
25
+ async validateSubjects(
26
+ schema: JsonSchema,
27
+ config: unknown,
28
+ actor: ActorContext,
29
+ ): Promise<void> {
30
+ const annotatedValues = this.findAnnotatedValues(schema, config);
31
+ const grouped = new Map<string, string[]>();
32
+ const providerPaths = new Map<string, string>();
33
+ const seen = new Set<string>();
34
+ const seenDynamicInputs = new Set<string>();
35
+ const issues: SubjectValidationIssue[] = [];
36
+
37
+ for (const { path, value } of annotatedValues) {
38
+ if (value === undefined || value === null) continue;
39
+ this.parseAndGroup(
40
+ path,
41
+ value,
42
+ grouped,
43
+ providerPaths,
44
+ seen,
45
+ seenDynamicInputs,
46
+ issues,
47
+ );
48
+ }
49
+ if (issues.length > 0) this.throwInvalid(issues);
50
+
51
+ for (const [providerKey, refs] of grouped) {
52
+ const provider = this.registry.get(providerKey);
53
+ let result: ProviderValidationResult;
54
+ try {
55
+ result = await provider.validate(refs, actor);
56
+ } catch (error) {
57
+ if (error instanceof SubjectProviderError) throw error;
58
+ throw new SubjectProviderUnavailableError(providerKey);
59
+ }
60
+
61
+ if (!result.valid) {
62
+ this.throwInvalid(
63
+ (result.issues ?? []).map((issue) => ({
64
+ path: providerPaths.get(providerKey) ?? '/',
65
+ provider: providerKey,
66
+ ...(issue.ref !== undefined && { ref: issue.ref }),
67
+ code: issue.code,
68
+ message: issue.message,
69
+ })),
70
+ );
71
+ }
72
+ }
73
+ }
74
+
75
+ private findAnnotatedValues(
76
+ schema: unknown,
77
+ config: unknown,
78
+ propertyPath: readonly string[] = [],
79
+ ): { path: string; value: unknown }[] {
80
+ if (!isRecord(schema)) return [];
81
+
82
+ const current = this.valueAt(config, propertyPath);
83
+ const results =
84
+ schema['x-gadmin-capability'] === 'subject-references'
85
+ ? [{ path: toJsonPointer(propertyPath), value: current }]
86
+ : [];
87
+
88
+ const properties = schema.properties;
89
+ if (!isRecord(properties)) return results;
90
+
91
+ for (const [property, childSchema] of Object.entries(properties)) {
92
+ results.push(
93
+ ...this.findAnnotatedValues(childSchema, config, [
94
+ ...propertyPath,
95
+ property,
96
+ ]),
97
+ );
98
+ }
99
+ return results;
100
+ }
101
+
102
+ private valueAt(value: unknown, path: readonly string[]): unknown {
103
+ let current = value;
104
+ for (const segment of path) {
105
+ if (!isRecord(current)) return undefined;
106
+ current = current[segment];
107
+ }
108
+ return current;
109
+ }
110
+
111
+ private parseAndGroup(
112
+ path: string,
113
+ value: unknown,
114
+ grouped: Map<string, string[]>,
115
+ providerPaths: Map<string, string>,
116
+ seen: Set<string>,
117
+ seenDynamicInputs: Set<string>,
118
+ issues: SubjectValidationIssue[],
119
+ ): void {
120
+ if (!Array.isArray(value)) {
121
+ issues.push({
122
+ path,
123
+ code: 'INVALID_SUBJECTS',
124
+ message: 'subject references must be an array',
125
+ });
126
+ return;
127
+ }
128
+
129
+ value.forEach((entry, index) => {
130
+ const entryPath = `${path}/${index}`;
131
+ if (!isRecord(entry)) {
132
+ issues.push({
133
+ path: entryPath,
134
+ code: 'INVALID_SUBJECT',
135
+ message: 'subject reference must be an object',
136
+ });
137
+ return;
138
+ }
139
+
140
+ const provider = validNonBlankString(entry.provider);
141
+ const source = entry.source ?? 'STATIC';
142
+ const rawRefs = entry.refs;
143
+ if (!provider) {
144
+ issues.push({
145
+ path: `${entryPath}/provider`,
146
+ code: 'INVALID_PROVIDER',
147
+ message: 'provider must be a nonblank string',
148
+ });
149
+ }
150
+ if (source === 'DYNAMIC') {
151
+ const inputKey = validNonBlankString(entry.inputKey);
152
+ if (!inputKey) {
153
+ issues.push({
154
+ path: `${entryPath}/inputKey`,
155
+ code: 'INVALID_DYNAMIC_INPUT',
156
+ message: 'inputKey must be a nonblank string',
157
+ });
158
+ } else if (seenDynamicInputs.has(inputKey)) {
159
+ issues.push({
160
+ path: `${entryPath}/inputKey`,
161
+ code: 'DUPLICATE_DYNAMIC_INPUT',
162
+ message: 'dynamic input keys must be unique',
163
+ });
164
+ } else {
165
+ seenDynamicInputs.add(inputKey);
166
+ }
167
+ if (provider) {
168
+ grouped.set(provider, grouped.get(provider) ?? []);
169
+ if (!providerPaths.has(provider))
170
+ providerPaths.set(provider, entryPath);
171
+ }
172
+ return;
173
+ }
174
+ if (!Array.isArray(rawRefs) || rawRefs.length === 0) {
175
+ issues.push({
176
+ path: `${entryPath}/refs`,
177
+ code: 'INVALID_REFS',
178
+ message: 'refs must be a non-empty array',
179
+ });
180
+ return;
181
+ }
182
+
183
+ rawRefs.forEach((rawRef, refIndex) => {
184
+ const ref = validNonBlankString(rawRef);
185
+ if (!ref) {
186
+ issues.push({
187
+ path: `${entryPath}/refs/${refIndex}`,
188
+ code: 'INVALID_REF',
189
+ message: 'ref must be a nonblank string',
190
+ });
191
+ return;
192
+ }
193
+ if (!provider) return;
194
+
195
+ const duplicateKey = `${provider}\0${ref}`;
196
+ if (seen.has(duplicateKey)) {
197
+ issues.push({
198
+ path: `${entryPath}/refs/${refIndex}`,
199
+ provider,
200
+ ref,
201
+ code: 'DUPLICATE_REF',
202
+ message: 'duplicate ref for provider',
203
+ });
204
+ return;
205
+ }
206
+
207
+ seen.add(duplicateKey);
208
+ grouped.set(provider, [...(grouped.get(provider) ?? []), ref]);
209
+ if (!providerPaths.has(provider)) providerPaths.set(provider, path);
210
+ });
211
+ });
212
+ }
213
+
214
+ private throwInvalid(issues: SubjectValidationIssue[]): never {
215
+ throw new BadRequestException({ code: 'SUBJECT_REF_INVALID', issues });
216
+ }
217
+ }
218
+
219
+ function isRecord(value: unknown): value is Record<string, unknown> {
220
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
221
+ }
222
+
223
+ function validNonBlankString(value: unknown): string | undefined {
224
+ return typeof value === 'string' && value.trim().length > 0
225
+ ? value.trim() === value
226
+ ? value
227
+ : undefined
228
+ : undefined;
229
+ }
230
+
231
+ function toJsonPointer(path: readonly string[]): string {
232
+ if (path.length === 0) return '/';
233
+ return `/${path
234
+ .map((segment) => segment.replace(/~/g, '~0').replace(/\//g, '~1'))
235
+ .join('/')}`;
236
+ }
@@ -0,0 +1,49 @@
1
+ import { WidgetCatalogService } from './widget-catalog.service';
2
+
3
+ describe('WidgetCatalogService', () => {
4
+ it('accepts the built-in workflow widgets used by seeded node types', () => {
5
+ const catalog = new WidgetCatalogService();
6
+
7
+ expect(() =>
8
+ catalog.assertUiSchemaSupported({
9
+ webhook: { widget: 'external-request-config' },
10
+ approvalResult: { widget: 'submit-approval-result-config' },
11
+ externalResult: { widget: 'submit-external-result-config' },
12
+ externalWait: { widget: 'external-wait-config' },
13
+ callableInputs: { widget: 'callable-input-parameters' },
14
+ approvalRequest: { widget: 'approval-request-trigger-config' },
15
+ returnResult: { widget: 'return-result-config' },
16
+ }),
17
+ ).not.toThrow();
18
+ });
19
+
20
+ it('accepts primitive widgets and newly registered generic widgets', () => {
21
+ const catalog = new WidgetCatalogService();
22
+ catalog.register('custom-picker');
23
+
24
+ expect(() =>
25
+ catalog.assertUiSchemaSupported({
26
+ name: { widget: 'text' },
27
+ nested: [{ field: { widget: 'custom-picker' } }],
28
+ }),
29
+ ).not.toThrow();
30
+ });
31
+
32
+ it('rejects an unregistered widget with its nested path', () => {
33
+ const catalog = new WidgetCatalogService();
34
+
35
+ expect(() =>
36
+ catalog.assertUiSchemaSupported({
37
+ approval: { subjects: { widget: 'missing-widget' } },
38
+ }),
39
+ ).toThrow(
40
+ expect.objectContaining({
41
+ response: {
42
+ code: 'NODE_WIDGET_NOT_REGISTERED',
43
+ widget: 'missing-widget',
44
+ path: '/approval/subjects/widget',
45
+ },
46
+ }),
47
+ );
48
+ });
49
+ });
@@ -0,0 +1,69 @@
1
+ import { BadRequestException, Injectable } from '@nestjs/common';
2
+
3
+ const PRIMITIVE_WIDGETS = [
4
+ 'text',
5
+ 'textarea',
6
+ 'number',
7
+ 'boolean',
8
+ 'select',
9
+ 'object',
10
+ 'array',
11
+ ] as const;
12
+
13
+ const WORKFLOW_WIDGETS = [
14
+ 'callable-input-parameters',
15
+ 'approval-request-trigger-config',
16
+ 'return-result-config',
17
+ 'external-request-config',
18
+ 'submit-approval-result-config',
19
+ 'submit-external-result-config',
20
+ 'external-wait-config',
21
+ ] as const;
22
+
23
+ @Injectable()
24
+ export class WidgetCatalogService {
25
+ private readonly widgets = new Set<string>([
26
+ ...PRIMITIVE_WIDGETS,
27
+ ...WORKFLOW_WIDGETS,
28
+ ]);
29
+
30
+ register(widget: string): void {
31
+ if (typeof widget !== 'string' || widget.trim().length === 0) {
32
+ throw new BadRequestException('widget name must be a nonblank string');
33
+ }
34
+ this.widgets.add(widget);
35
+ }
36
+
37
+ assertUiSchemaSupported(uiSchema: unknown): void {
38
+ this.walk(uiSchema, []);
39
+ }
40
+
41
+ private walk(value: unknown, path: readonly (string | number)[]): void {
42
+ if (Array.isArray(value)) {
43
+ value.forEach((item, index) => this.walk(item, [...path, index]));
44
+ return;
45
+ }
46
+ if (value === null || typeof value !== 'object') return;
47
+
48
+ for (const [key, child] of Object.entries(value)) {
49
+ const childPath = [...path, key];
50
+ if (key === 'widget' && typeof child === 'string') {
51
+ if (!this.widgets.has(child)) {
52
+ throw new BadRequestException({
53
+ code: 'NODE_WIDGET_NOT_REGISTERED',
54
+ widget: child,
55
+ path: toJsonPointer(childPath),
56
+ });
57
+ }
58
+ } else {
59
+ this.walk(child, childPath);
60
+ }
61
+ }
62
+ }
63
+ }
64
+
65
+ function toJsonPointer(path: readonly (string | number)[]): string {
66
+ return `/${path
67
+ .map((segment) => String(segment).replace(/~/g, '~0').replace(/\//g, '~1'))
68
+ .join('/')}`;
69
+ }
@@ -0,0 +1,20 @@
1
+ import { Module } from '@nestjs/common';
2
+ import { SubjectProviderModule } from '../subjectProvider/subjectProvider.module';
3
+ import { NodeConfigValidatorService } from './node-config-validator.service';
4
+ import { SubjectConfigValidatorService } from './subject-config-validator.service';
5
+ import { WidgetCatalogService } from './widget-catalog.service';
6
+
7
+ @Module({
8
+ imports: [SubjectProviderModule],
9
+ providers: [
10
+ NodeConfigValidatorService,
11
+ SubjectConfigValidatorService,
12
+ WidgetCatalogService,
13
+ ],
14
+ exports: [
15
+ NodeConfigValidatorService,
16
+ SubjectConfigValidatorService,
17
+ WidgetCatalogService,
18
+ ],
19
+ })
20
+ export class WorkflowConfigModule {}
@@ -0,0 +1,15 @@
1
+ import { hashNodeInstanceConfig } from './node-instance-config.util';
2
+
3
+ describe('node-instance-config.util', () => {
4
+ it('hashes objects independently of key insertion order', () => {
5
+ expect(hashNodeInstanceConfig({ a: 1, b: { x: true, y: null } })).toBe(
6
+ hashNodeInstanceConfig({ b: { y: null, x: true }, a: 1 }),
7
+ );
8
+ });
9
+
10
+ it('preserves array order', () => {
11
+ expect(hashNodeInstanceConfig({ refs: ['a', 'b'] })).not.toBe(
12
+ hashNodeInstanceConfig({ refs: ['b', 'a'] }),
13
+ );
14
+ });
15
+ });
@@ -0,0 +1,25 @@
1
+ import { Prisma } from '@prisma/client';
2
+ import { createHash } from 'node:crypto';
3
+
4
+ function sortJson(value: Prisma.JsonValue): Prisma.JsonValue {
5
+ if (Array.isArray(value)) return value.map(sortJson);
6
+
7
+ if (value && typeof value === 'object') {
8
+ return Object.fromEntries(
9
+ Object.entries(value)
10
+ .sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))
11
+ .map(([key, nestedValue]) => [
12
+ key,
13
+ nestedValue === undefined ? nestedValue : sortJson(nestedValue),
14
+ ]),
15
+ );
16
+ }
17
+
18
+ return value;
19
+ }
20
+
21
+ export const canonicalizeConfig = (config: Prisma.JsonValue): string =>
22
+ JSON.stringify(sortJson(config));
23
+
24
+ export const hashNodeInstanceConfig = (config: Prisma.JsonValue): string =>
25
+ createHash('sha256').update(canonicalizeConfig(config)).digest('hex');