@gadmin2n/schematics 0.0.139 → 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 +4 -1
  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,161 @@
1
+ import { UserGroupService } from './user-group.service';
2
+
3
+ const group = {
4
+ id: BigInt(1),
5
+ code: 'finance',
6
+ name: 'Finance',
7
+ description: null,
8
+ revision: 4,
9
+ isActive: true,
10
+ creator: 'admin',
11
+ createdAt: new Date(),
12
+ updatedAt: new Date(),
13
+ };
14
+ const actor = { userId: 'admin' };
15
+
16
+ function createHarness() {
17
+ const tx = {
18
+ userGroup: {
19
+ findUnique: jest.fn().mockResolvedValue(group),
20
+ findMany: jest.fn(),
21
+ create: jest.fn(),
22
+ updateMany: jest.fn().mockResolvedValue({ count: 1 }),
23
+ },
24
+ user: { findMany: jest.fn() },
25
+ userGroupUser: {
26
+ findMany: jest.fn().mockResolvedValue([]),
27
+ deleteMany: jest.fn().mockResolvedValue({ count: 0 }),
28
+ createMany: jest.fn().mockResolvedValue({ count: 1 }),
29
+ },
30
+ userGroupChild: {
31
+ findMany: jest.fn().mockResolvedValue([]),
32
+ deleteMany: jest.fn().mockResolvedValue({ count: 0 }),
33
+ createMany: jest.fn().mockResolvedValue({ count: 1 }),
34
+ },
35
+ };
36
+ const prisma = {
37
+ ...tx,
38
+ $transaction: jest.fn((fn) => fn(tx)),
39
+ };
40
+ return {
41
+ tx,
42
+ service: new UserGroupService(prisma as never),
43
+ };
44
+ }
45
+
46
+ describe('UserGroupService', () => {
47
+ it('returns direct users and child groups for editing', async () => {
48
+ const { service, tx } = createHarness();
49
+ tx.userGroup.findUnique
50
+ .mockResolvedValueOnce({
51
+ ...group,
52
+ users: [{ userId: 'alice' }],
53
+ children: [{ childGroup: { code: 'finance-child' } }],
54
+ })
55
+ .mockResolvedValueOnce({ id: group.id, isActive: true });
56
+ tx.userGroup.findMany.mockResolvedValueOnce([]);
57
+
58
+ await expect(service.preview('finance')).resolves.toMatchObject({
59
+ directUserIds: ['alice'],
60
+ childGroupCodes: ['finance-child'],
61
+ });
62
+ });
63
+
64
+ it('replaces members and bumps revision', async () => {
65
+ const { service, tx } = createHarness();
66
+ tx.user.findMany.mockResolvedValue([{ userid: 'u1' }]);
67
+ tx.userGroup.findMany
68
+ .mockResolvedValueOnce([{ id: BigInt(2), code: 'child' }])
69
+ .mockResolvedValueOnce([{ id: BigInt(1) }, { id: BigInt(2) }]);
70
+
71
+ await service.replaceMembers(
72
+ 'finance',
73
+ {
74
+ expectedRevision: 4,
75
+ userIds: ['u1', 'u1'],
76
+ childGroupCodes: ['child'],
77
+ },
78
+ actor,
79
+ );
80
+
81
+ expect(tx.userGroup.updateMany).toHaveBeenCalledWith({
82
+ where: { id: BigInt(1), revision: 4 },
83
+ data: { revision: 5 },
84
+ });
85
+ });
86
+
87
+ it('does not bump revision or emit when normalized members are unchanged', async () => {
88
+ const { service, tx } = createHarness();
89
+ tx.user.findMany.mockResolvedValue([{ userid: 'u1' }]);
90
+ tx.userGroup.findMany.mockResolvedValue([{ id: BigInt(2), code: 'child' }]);
91
+ tx.userGroupUser.findMany.mockResolvedValue([{ userId: 'u1' }]);
92
+ tx.userGroupChild.findMany.mockResolvedValue([
93
+ { childGroup: { code: 'child' } },
94
+ ]);
95
+
96
+ await service.replaceMembers(
97
+ 'finance',
98
+ {
99
+ expectedRevision: 4,
100
+ userIds: ['u1', 'u1'],
101
+ childGroupCodes: ['child', 'child'],
102
+ },
103
+ actor,
104
+ );
105
+
106
+ expect(tx.userGroup.updateMany).not.toHaveBeenCalled();
107
+ });
108
+
109
+ it('rejects a direct or indirect cycle', async () => {
110
+ const { service, tx } = createHarness();
111
+ tx.user.findMany.mockResolvedValue([]);
112
+ tx.userGroup.findMany
113
+ .mockResolvedValueOnce([{ id: BigInt(1), code: 'finance' }])
114
+ .mockResolvedValueOnce([{ id: BigInt(1) }]);
115
+
116
+ await expect(
117
+ service.replaceMembers(
118
+ 'finance',
119
+ {
120
+ expectedRevision: 4,
121
+ userIds: [],
122
+ childGroupCodes: ['finance'],
123
+ },
124
+ actor,
125
+ ),
126
+ ).rejects.toMatchObject({
127
+ response: { code: 'USER_GROUP_CYCLE' },
128
+ });
129
+ });
130
+
131
+ it('rejects inactive or missing direct users', async () => {
132
+ const { service, tx } = createHarness();
133
+ tx.user.findMany.mockResolvedValue([]);
134
+ tx.userGroup.findMany.mockResolvedValue([]);
135
+
136
+ await expect(
137
+ service.replaceMembers(
138
+ 'finance',
139
+ {
140
+ expectedRevision: 4,
141
+ userIds: ['inactive'],
142
+ childGroupCodes: [],
143
+ },
144
+ actor,
145
+ ),
146
+ ).rejects.toMatchObject({
147
+ response: { code: 'USER_GROUP_MEMBER_INVALID' },
148
+ });
149
+ });
150
+
151
+ it('returns 409 when expectedRevision is stale', async () => {
152
+ const { service } = createHarness();
153
+ await expect(
154
+ service.updateGroup(
155
+ 'finance',
156
+ { expectedRevision: 3, name: 'Finance 2' },
157
+ actor,
158
+ ),
159
+ ).rejects.toMatchObject({ status: 409 });
160
+ });
161
+ });
@@ -0,0 +1,390 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ import { Prisma } from '@prisma/client';
3
+ import { PrismaService } from 'nestjs-prisma';
4
+ import { ActorContext } from '../subjectProvider/subject-provider.types';
5
+ import {
6
+ CreateUserGroupDto,
7
+ ReplaceUserGroupMembersDto,
8
+ SetUserGroupActiveDto,
9
+ UpdateUserGroupDto,
10
+ } from './user-group.dto';
11
+ import {
12
+ UserGroupDomainError,
13
+ userGroupNotFound,
14
+ userGroupRevisionConflict,
15
+ } from './user-group.errors';
16
+
17
+ export const MAX_GROUP_DEPTH = 20;
18
+
19
+ type Transaction = Prisma.TransactionClient;
20
+
21
+ @Injectable()
22
+ export class UserGroupService {
23
+ constructor(private readonly prisma: PrismaService) {}
24
+
25
+ createGroup(input: CreateUserGroupDto, actor: ActorContext) {
26
+ const userIds = this.normalize(input.userIds ?? []);
27
+ const childCodes = this.normalize(input.childGroupCodes ?? []);
28
+ const creator = this.creatorFrom(actor);
29
+
30
+ return this.prisma.$transaction(async (tx) => {
31
+ const [users, children] = await Promise.all([
32
+ this.requireActiveUsers(tx, userIds),
33
+ this.requireActiveGroups(tx, childCodes),
34
+ ]);
35
+ const group = await tx.userGroup.create({
36
+ data: {
37
+ ...(input.code && { code: input.code.trim() }),
38
+ name: input.name.trim(),
39
+ description: input.description?.trim(),
40
+ creator,
41
+ },
42
+ });
43
+ await this.validateGraphReplacement(tx, group.id, children);
44
+ await this.insertMembers(tx, group.id, users, children, creator);
45
+ return group;
46
+ });
47
+ }
48
+
49
+ updateGroup(code: string, input: UpdateUserGroupDto, actor: ActorContext) {
50
+ return this.prisma.$transaction(async (tx) => {
51
+ const group = await this.findGroup(tx, code);
52
+ this.assertRevision(group.revision, input.expectedRevision);
53
+ const data = {
54
+ ...(input.name !== undefined && { name: input.name.trim() }),
55
+ ...(input.description !== undefined && {
56
+ description: input.description?.trim() ?? null,
57
+ }),
58
+ };
59
+ const changedFields = Object.keys(data).filter(
60
+ (field) => group[field as 'name' | 'description'] !== data[field],
61
+ );
62
+ if (changedFields.length === 0) return group;
63
+
64
+ const revision = group.revision + 1;
65
+ await this.optimisticUpdate(tx, group.id, group.revision, {
66
+ ...data,
67
+ revision,
68
+ });
69
+ return { ...group, ...data, revision };
70
+ });
71
+ }
72
+
73
+ replaceMembers(
74
+ code: string,
75
+ input: ReplaceUserGroupMembersDto,
76
+ actor: ActorContext,
77
+ ) {
78
+ const userIds = this.normalize(input.userIds);
79
+ const childCodes = this.normalize(input.childGroupCodes);
80
+ const creator = this.creatorFrom(actor);
81
+
82
+ return this.prisma.$transaction(async (tx) => {
83
+ const group = await this.findGroup(tx, code);
84
+ this.assertRevision(group.revision, input.expectedRevision);
85
+ const [users, children, currentUsers, currentChildren] =
86
+ await Promise.all([
87
+ this.requireActiveUsers(tx, userIds),
88
+ this.requireActiveGroups(tx, childCodes),
89
+ tx.userGroupUser.findMany({
90
+ where: { groupId: group.id },
91
+ select: { userId: true },
92
+ }),
93
+ tx.userGroupChild.findMany({
94
+ where: { parentGroupId: group.id },
95
+ select: { childGroup: { select: { code: true } } },
96
+ }),
97
+ ]);
98
+
99
+ if (
100
+ this.same(
101
+ userIds,
102
+ currentUsers.map((item) => item.userId),
103
+ ) &&
104
+ this.same(
105
+ childCodes,
106
+ currentChildren.map((item) => item.childGroup.code),
107
+ )
108
+ ) {
109
+ return group;
110
+ }
111
+
112
+ await this.validateGraphReplacement(tx, group.id, children);
113
+ const revision = group.revision + 1;
114
+ await this.optimisticUpdate(tx, group.id, group.revision, { revision });
115
+ await Promise.all([
116
+ tx.userGroupUser.deleteMany({ where: { groupId: group.id } }),
117
+ tx.userGroupChild.deleteMany({
118
+ where: { parentGroupId: group.id },
119
+ }),
120
+ ]);
121
+ await this.insertMembers(tx, group.id, users, children, creator);
122
+ return { ...group, revision };
123
+ });
124
+ }
125
+
126
+ setActive(code: string, input: SetUserGroupActiveDto, actor: ActorContext) {
127
+ return this.prisma.$transaction(async (tx) => {
128
+ const group = await this.findGroup(tx, code);
129
+ this.assertRevision(group.revision, input.expectedRevision);
130
+ if (group.isActive === input.isActive) return group;
131
+
132
+ const revision = group.revision + 1;
133
+ await this.optimisticUpdate(tx, group.id, group.revision, {
134
+ isActive: input.isActive,
135
+ revision,
136
+ });
137
+ return { ...group, isActive: input.isActive, revision };
138
+ });
139
+ }
140
+
141
+ search(query: string) {
142
+ const q = query.trim();
143
+ return this.prisma.userGroup.findMany({
144
+ where: {
145
+ isActive: true,
146
+ ...(q && {
147
+ OR: [
148
+ { code: { contains: q, mode: 'insensitive' } },
149
+ { name: { contains: q, mode: 'insensitive' } },
150
+ ],
151
+ }),
152
+ },
153
+ orderBy: [{ name: 'asc' }, { code: 'asc' }],
154
+ select: {
155
+ code: true,
156
+ name: true,
157
+ description: true,
158
+ revision: true,
159
+ },
160
+ take: 50,
161
+ });
162
+ }
163
+
164
+ async preview(code: string) {
165
+ const group = await this.prisma.userGroup.findUnique({
166
+ where: { code },
167
+ select: {
168
+ code: true,
169
+ name: true,
170
+ description: true,
171
+ revision: true,
172
+ isActive: true,
173
+ users: {
174
+ select: { userId: true },
175
+ orderBy: { userId: 'asc' },
176
+ },
177
+ children: {
178
+ select: { childGroup: { select: { code: true } } },
179
+ },
180
+ },
181
+ });
182
+ if (!group) throw userGroupNotFound(code);
183
+ const users = await this.resolveUsers(code);
184
+ return {
185
+ code: group.code,
186
+ name: group.name,
187
+ description: group.description,
188
+ revision: group.revision,
189
+ isActive: group.isActive,
190
+ directUserIds: group.users.map((item) => item.userId),
191
+ childGroupCodes: group.children
192
+ .map((item) => item.childGroup.code)
193
+ .sort(),
194
+ resolvedUserCount: users.length,
195
+ users,
196
+ };
197
+ }
198
+
199
+ async resolveUsers(code: string) {
200
+ const root = await this.prisma.userGroup.findUnique({
201
+ where: { code },
202
+ select: { id: true, isActive: true },
203
+ });
204
+ if (!root) throw userGroupNotFound(code);
205
+ if (!root.isActive) return [];
206
+
207
+ const visited = new Set<bigint>();
208
+ const users = new Map<
209
+ string,
210
+ { userid: string; username: string | null }
211
+ >();
212
+ let level = [root.id];
213
+ let depth = 0;
214
+ while (level.length > 0) {
215
+ if (depth > MAX_GROUP_DEPTH) this.throwDepth();
216
+ const ids = level.filter((id) => !visited.has(id));
217
+ ids.forEach((id) => visited.add(id));
218
+ if (ids.length === 0) break;
219
+ const groups = await this.prisma.userGroup.findMany({
220
+ where: { id: { in: ids }, isActive: true },
221
+ select: {
222
+ users: {
223
+ where: { user: { isActive: true } },
224
+ select: {
225
+ user: { select: { userid: true, username: true } },
226
+ },
227
+ },
228
+ children: {
229
+ where: { childGroup: { isActive: true } },
230
+ select: { childGroupId: true },
231
+ },
232
+ },
233
+ });
234
+ level = [];
235
+ for (const group of groups) {
236
+ group.users.forEach(({ user }) => users.set(user.userid, user));
237
+ level.push(...group.children.map((child) => child.childGroupId));
238
+ }
239
+ depth += 1;
240
+ }
241
+ return [...users.values()].sort((a, b) => a.userid.localeCompare(b.userid));
242
+ }
243
+
244
+ private async findGroup(tx: Transaction, code: string) {
245
+ const group = await tx.userGroup.findUnique({ where: { code } });
246
+ if (!group) throw userGroupNotFound(code);
247
+ return group;
248
+ }
249
+
250
+ private assertRevision(actual: number, expected: number): void {
251
+ if (actual !== expected) throw userGroupRevisionConflict();
252
+ }
253
+
254
+ private async optimisticUpdate(
255
+ tx: Transaction,
256
+ id: bigint,
257
+ revision: number,
258
+ data: Prisma.UserGroupUpdateManyMutationInput,
259
+ ) {
260
+ const result = await tx.userGroup.updateMany({
261
+ where: { id, revision },
262
+ data,
263
+ });
264
+ if (result.count !== 1) throw userGroupRevisionConflict();
265
+ }
266
+
267
+ private async requireActiveUsers(tx: Transaction, userIds: string[]) {
268
+ if (userIds.length === 0) return [];
269
+ const users = await tx.user.findMany({
270
+ where: { userid: { in: userIds }, isActive: true },
271
+ select: { userid: true },
272
+ });
273
+ if (users.length !== userIds.length) {
274
+ throw new UserGroupDomainError(
275
+ 'USER_GROUP_MEMBER_INVALID',
276
+ 'Every direct user must exist and be active',
277
+ );
278
+ }
279
+ return users;
280
+ }
281
+
282
+ private async requireActiveGroups(tx: Transaction, codes: string[]) {
283
+ if (codes.length === 0) return [];
284
+ const groups = await tx.userGroup.findMany({
285
+ where: { code: { in: codes }, isActive: true },
286
+ select: { id: true, code: true },
287
+ });
288
+ if (groups.length !== codes.length) {
289
+ throw new UserGroupDomainError(
290
+ 'USER_GROUP_MEMBER_INVALID',
291
+ 'Every child group must exist and be active',
292
+ );
293
+ }
294
+ return groups;
295
+ }
296
+
297
+ private async validateGraphReplacement(
298
+ tx: Transaction,
299
+ parentId: bigint,
300
+ children: { id: bigint }[],
301
+ ) {
302
+ const [groups, edges] = await Promise.all([
303
+ tx.userGroup.findMany({
304
+ where: { isActive: true },
305
+ select: { id: true },
306
+ }),
307
+ tx.userGroupChild.findMany({
308
+ where: {
309
+ parentGroup: { isActive: true },
310
+ childGroup: { isActive: true },
311
+ },
312
+ select: { parentGroupId: true, childGroupId: true },
313
+ }),
314
+ ]);
315
+ const graph = new Map<bigint, bigint[]>();
316
+ groups.forEach((group) => graph.set(group.id, []));
317
+ edges.forEach((edge) => {
318
+ if (edge.parentGroupId !== parentId) {
319
+ graph.get(edge.parentGroupId)?.push(edge.childGroupId);
320
+ }
321
+ });
322
+ graph.set(
323
+ parentId,
324
+ children.map((child) => child.id),
325
+ );
326
+
327
+ const visit = (id: bigint, path: Set<bigint>, depth: number): void => {
328
+ if (path.has(id)) {
329
+ throw new UserGroupDomainError(
330
+ 'USER_GROUP_CYCLE',
331
+ 'Nested user groups cannot contain a cycle',
332
+ );
333
+ }
334
+ if (depth > MAX_GROUP_DEPTH) this.throwDepth();
335
+ const nextPath = new Set(path).add(id);
336
+ for (const child of graph.get(id) ?? []) {
337
+ visit(child, nextPath, depth + 1);
338
+ }
339
+ };
340
+ groups.forEach((group) => visit(group.id, new Set(), 0));
341
+ }
342
+
343
+ private throwDepth(): never {
344
+ throw new UserGroupDomainError(
345
+ 'USER_GROUP_DEPTH_EXCEEDED',
346
+ `User group nesting cannot exceed ${MAX_GROUP_DEPTH}`,
347
+ );
348
+ }
349
+
350
+ private async insertMembers(
351
+ tx: Transaction,
352
+ groupId: bigint,
353
+ users: { userid: string }[],
354
+ children: { id: bigint }[],
355
+ creator: string,
356
+ ) {
357
+ if (users.length > 0) {
358
+ await tx.userGroupUser.createMany({
359
+ data: users.map((user) => ({ groupId, userId: user.userid, creator })),
360
+ });
361
+ }
362
+ if (children.length > 0) {
363
+ await tx.userGroupChild.createMany({
364
+ data: children.map((child) => ({
365
+ parentGroupId: groupId,
366
+ childGroupId: child.id,
367
+ creator,
368
+ })),
369
+ });
370
+ }
371
+ }
372
+
373
+ private creatorFrom(actor: ActorContext): string {
374
+ return actor.username ?? actor.userId;
375
+ }
376
+
377
+ private normalize(values: string[]): string[] {
378
+ return [
379
+ ...new Set(values.map((value) => value.trim()).filter(Boolean)),
380
+ ].sort();
381
+ }
382
+
383
+ private same(left: string[], right: string[]): boolean {
384
+ const sortedRight = [...right].sort();
385
+ return (
386
+ left.length === sortedRight.length &&
387
+ left.every((value, index) => value === sortedRight[index])
388
+ );
389
+ }
390
+ }
@@ -0,0 +1,10 @@
1
+ import { Module } from '@nestjs/common';
2
+ import { UserGroupController } from './user-group.controller';
3
+ import { UserGroupService } from './user-group.service';
4
+
5
+ @Module({
6
+ controllers: [UserGroupController],
7
+ providers: [UserGroupService],
8
+ exports: [UserGroupService],
9
+ })
10
+ export class UserGroupModule {}
@@ -202,4 +202,21 @@ describe('validateDslGraph', () => {
202
202
  }
203
203
  });
204
204
  });
205
+
206
+ it('does not treat a CALL/RETURN pair as a main-flow cycle', () => {
207
+ expect(() =>
208
+ validateDslGraph({
209
+ nodes: [
210
+ { id: 'trigger', type: 'manual_trigger' },
211
+ { id: 'approval', type: 'human_approval' },
212
+ { id: 'lookup', type: 'http_request' },
213
+ ],
214
+ edges: [
215
+ { source: 'trigger', target: 'approval', kind: 'FLOW' },
216
+ { source: 'approval', target: 'lookup', kind: 'CALL' },
217
+ { source: 'lookup', target: 'approval', kind: 'RETURN' },
218
+ ],
219
+ }),
220
+ ).not.toThrow();
221
+ });
205
222
  });
@@ -18,7 +18,11 @@
18
18
  */
19
19
  export interface DslGraphLike {
20
20
  nodes?: Array<{ id?: string; type?: string }>;
21
- edges?: Array<{ source?: string; target?: string }>;
21
+ edges?: Array<{
22
+ source?: string;
23
+ target?: string;
24
+ kind?: 'FLOW' | 'DATA' | 'CALL' | 'RETURN';
25
+ }>;
22
26
  }
23
27
 
24
28
  export function validateDslGraph(dsl: unknown): void {
@@ -82,7 +86,9 @@ export function validateDslGraph(dsl: unknown): void {
82
86
  indegree.set(id, 0);
83
87
  adj.set(id, []);
84
88
  }
85
- for (const e of g.edges) {
89
+ for (const e of g.edges.filter(
90
+ (edge) => !edge.kind || edge.kind === 'FLOW',
91
+ )) {
86
92
  indegree.set(e.target!, indegree.get(e.target!)! + 1);
87
93
  adj.get(e.source!)!.push(e.target!);
88
94
  }
@@ -0,0 +1,93 @@
1
+ export type ParameterBinding =
2
+ | {
3
+ source: 'INPUT' | 'WORKFLOW' | 'SYSTEM';
4
+ path: string;
5
+ }
6
+ | {
7
+ source: 'FIXED';
8
+ valueType: 'STRING' | 'NUMBER' | 'BOOLEAN' | 'JSON';
9
+ value: string;
10
+ };
11
+
12
+ export function validateParameterBinding(
13
+ value: unknown,
14
+ ): value is ParameterBinding {
15
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
16
+ const binding = value as Record<string, unknown>;
17
+ if (
18
+ binding.source === 'INPUT' ||
19
+ binding.source === 'WORKFLOW' ||
20
+ binding.source === 'SYSTEM'
21
+ )
22
+ return typeof binding.path === 'string' && Boolean(binding.path.trim());
23
+ if (binding.source !== 'FIXED') return false;
24
+ if (
25
+ !['STRING', 'NUMBER', 'BOOLEAN', 'JSON'].includes(
26
+ String(binding.valueType),
27
+ ) ||
28
+ typeof binding.value !== 'string'
29
+ )
30
+ return false;
31
+ if (binding.valueType === 'NUMBER')
32
+ return (
33
+ binding.value.trim() !== '' && Number.isFinite(Number(binding.value))
34
+ );
35
+ if (binding.valueType === 'BOOLEAN')
36
+ return binding.value === 'true' || binding.value === 'false';
37
+ if (binding.valueType === 'JSON') {
38
+ try {
39
+ JSON.parse(binding.value);
40
+ return true;
41
+ } catch {
42
+ return false;
43
+ }
44
+ }
45
+ return true;
46
+ }
47
+
48
+ export function resolveParameterBinding(
49
+ binding: ParameterBinding,
50
+ input: unknown,
51
+ workflow: Record<string, unknown>,
52
+ system: Record<string, unknown> = {},
53
+ ): unknown {
54
+ if (binding.source === 'FIXED') {
55
+ if (binding.valueType === 'STRING') return binding.value;
56
+ if (binding.valueType === 'NUMBER') return Number(binding.value);
57
+ if (binding.valueType === 'BOOLEAN') return binding.value === 'true';
58
+ return JSON.parse(binding.value);
59
+ }
60
+
61
+ const sourceName =
62
+ binding.source === 'INPUT'
63
+ ? 'input'
64
+ : binding.source === 'WORKFLOW'
65
+ ? 'workflow'
66
+ : 'system';
67
+ const root =
68
+ binding.source === 'INPUT'
69
+ ? input
70
+ : binding.source === 'WORKFLOW'
71
+ ? workflow
72
+ : system;
73
+ const value = readPath(root, binding.path);
74
+ if (value === undefined)
75
+ throw new Error(
76
+ `HTTP_BINDING_RESOLUTION_FAILED:${sourceName}.${binding.path}`,
77
+ );
78
+ return value;
79
+ }
80
+
81
+ function readPath(root: unknown, path: string): unknown {
82
+ let current = root;
83
+ for (const part of path.trim().split('.')) {
84
+ if (
85
+ !current ||
86
+ typeof current !== 'object' ||
87
+ !Object.prototype.hasOwnProperty.call(current, part)
88
+ )
89
+ return undefined;
90
+ current = (current as Record<string, unknown>)[part];
91
+ }
92
+ return current;
93
+ }