@gadmin2n/schematics 0.0.72 → 0.0.74

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 (173) hide show
  1. package/dist/index.d.ts +2 -0
  2. package/dist/index.js +2 -0
  3. package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/job.prisma +62 -0
  4. package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/system.prisma +0 -21
  5. package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/workflow.prisma +171 -0
  6. package/dist/lib/application/files/gadmin2-game-angle-demo/config/ui/AgendaJob.ts +60 -0
  7. package/dist/lib/application/files/gadmin2-game-angle-demo/config/ui/Event.ts +1 -1
  8. package/dist/lib/application/files/gadmin2-game-angle-demo/config/ui/WorkflowEventOutbox.ts +62 -0
  9. package/dist/lib/application/files/gadmin2-game-angle-demo/config/ui/WorkflowNodeInstance.ts +62 -0
  10. package/dist/lib/application/files/gadmin2-game-angle-demo/config/ui/WorkflowNodeType.ts +62 -0
  11. package/dist/lib/application/files/gadmin2-game-angle-demo/server/.env +5 -0
  12. package/dist/lib/application/files/gadmin2-game-angle-demo/server/package.json +5 -4
  13. package/dist/lib/application/files/gadmin2-game-angle-demo/server/prisma.config.ts +14 -7
  14. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/index.ts +4 -0
  15. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/permissions.ts +49 -3
  16. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-node-types.ts +746 -0
  17. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflows.ts +786 -0
  18. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/agenda/agenda.controller.ts +6 -0
  19. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/agenda/agenda.service.ts +79 -0
  20. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/agendaJob/agendaJob.controller.spec.ts +20 -0
  21. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/agendaJob/agendaJob.controller.ts +145 -0
  22. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/agendaJob/agendaJob.module.ts +10 -0
  23. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/{canvas/canvas.service.spec.ts → agendaJob/agendaJob.service.spec.ts} +71 -65
  24. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/agendaJob/agendaJob.service.ts +83 -0
  25. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/index.ts +2 -1
  26. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/temporal.module.ts +9 -0
  27. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/temporal.service.ts +100 -0
  28. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-execution.dto.ts +19 -0
  29. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-export.dto.ts +43 -0
  30. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-export.service.ts +317 -0
  31. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-node-type.controller.ts +16 -0
  32. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow-node-type.service.ts +13 -0
  33. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.ts +220 -0
  34. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.dto.ts +82 -0
  35. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.module.ts +16 -0
  36. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.ts +505 -0
  37. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.controller.spec.ts +22 -0
  38. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.controller.ts +147 -0
  39. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.module.ts +10 -0
  40. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.service.spec.ts +356 -0
  41. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.service.ts +110 -0
  42. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.controller.spec.ts +22 -0
  43. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.controller.ts +216 -0
  44. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.module.ts +10 -0
  45. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.service.spec.ts +356 -0
  46. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.service.ts +168 -0
  47. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeType/workflowNodeType.controller.spec.ts +22 -0
  48. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeType/workflowNodeType.controller.ts +199 -0
  49. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeType/workflowNodeType.module.ts +10 -0
  50. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeType/workflowNodeType.service.spec.ts +348 -0
  51. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeType/workflowNodeType.service.ts +106 -0
  52. package/dist/lib/application/files/gadmin2-game-angle-demo/server/yarn.lock +579 -1082
  53. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/README.md +278 -0
  54. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/config/development-sql.yaml +5 -0
  55. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/docker-compose.yml +25 -0
  56. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/package.json +13 -0
  57. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/sql/create-event-trigger.sql +87 -0
  58. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/.env +7 -0
  59. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/SANDBOX.md +122 -0
  60. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/package-lock.json +4285 -0
  61. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/package.json +28 -0
  62. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/__tests__/activities/code-execute.test.ts +44 -0
  63. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/__tests__/activities/http-request.test.ts +87 -0
  64. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/__tests__/helpers.test.ts +225 -0
  65. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/__tests__/node-type-consistency.test.ts +101 -0
  66. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/code-execute.ts +51 -0
  67. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/db-execute.ts +85 -0
  68. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/db-query.ts +35 -0
  69. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/http-request.ts +54 -0
  70. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/index.ts +6 -0
  71. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/reporting.ts +62 -0
  72. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/send-notification.ts +47 -0
  73. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/config.ts +13 -0
  74. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/dsl/condition.ts +101 -0
  75. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/dsl/context.ts +58 -0
  76. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/dsl/graph.ts +184 -0
  77. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/dsl/helpers.ts +133 -0
  78. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/dsl/node-types.ts +57 -0
  79. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/dsl/types.ts +77 -0
  80. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/index.ts +36 -0
  81. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/outbox-poller.ts +226 -0
  82. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/workflows/dsl-workflow.ts +411 -0
  83. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/tsconfig.json +19 -0
  84. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/vitest.config.ts +8 -0
  85. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/yarn.lock +1905 -0
  86. package/dist/lib/application/files/gadmin2-game-angle-demo/web/package-lock.json +17555 -0
  87. package/dist/lib/application/files/gadmin2-game-angle-demo/web/package.json +5 -2
  88. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/App.tsx +1 -0
  89. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/sider.tsx +5 -1
  90. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/layout/title.tsx +1 -1
  91. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/config/routeRegistry.tsx +63 -0
  92. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/dev-shell/DevShell.tsx +91 -2
  93. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/helpers/list.tsx +48 -2
  94. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/helpers/show.tsx +43 -2
  95. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/common.json +14 -9
  96. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/common.json +14 -9
  97. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agenda/index.tsx +309 -56
  98. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agenda/show.tsx +1 -3
  99. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agendaJob/create.tsx +108 -0
  100. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agendaJob/edit.tsx +124 -0
  101. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agendaJob/index.tsx +4 -0
  102. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agendaJob/list.tsx +245 -0
  103. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/agendaJob/show.tsx +70 -0
  104. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasListPage.tsx +0 -1
  105. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasPage.tsx +160 -2
  106. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasToolbar.tsx +120 -148
  107. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CodeFloatWindow.tsx +74 -181
  108. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/LivePreview.tsx +15 -13
  109. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/canvasConfigRegistry.tsx +2 -2
  110. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/canvasContextMenuRegistry.tsx +338 -3
  111. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/canvasDefaults.ts +18 -17
  112. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/BarChartDataSourceModal.tsx +10 -4
  113. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/LineChartDataSourceModal.tsx +10 -4
  114. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/{ChartViewerConfigModal.tsx → MultiChartConfigModal.tsx} +30 -18
  115. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/MultiChartDataSourceModal.tsx +427 -0
  116. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/NumCardDataSourceModal.tsx +10 -4
  117. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/PromptModal.tsx +6 -14
  118. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/RadarChartDataSourceModal.tsx +10 -4
  119. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/TableDataSourceModal.tsx +10 -4
  120. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/components/canvasModalProps.ts +24 -0
  121. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/demos.ts +45 -63
  122. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/CustomNode.tsx +99 -0
  123. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ExportModal.tsx +87 -0
  124. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/FlowRenderer.tsx +322 -0
  125. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/ImportModal.tsx +175 -0
  126. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodeEditModal.tsx +60 -0
  127. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/NodePropertyPanel.tsx +1150 -0
  128. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/RunWorkflowModal.tsx +101 -0
  129. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/StatusCards.tsx +198 -0
  130. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/VersionPanel.tsx +81 -0
  131. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/editor.tsx +566 -0
  132. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/hooks/useWorkflowAgent.ts +224 -0
  133. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/index.tsx +524 -0
  134. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.tsx +343 -0
  135. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instances.tsx +243 -0
  136. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/components/CreateNodeInstanceModal.tsx +363 -0
  137. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/components/DynamicConfigForm.tsx +154 -0
  138. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/components/NodeInstanceForm.tsx +176 -0
  139. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/create.tsx +77 -0
  140. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/edit.tsx +112 -0
  141. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/index.tsx +305 -0
  142. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/node-instances/show.tsx +282 -0
  143. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/show.tsx +469 -0
  144. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/types.ts +92 -0
  145. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/create.tsx +111 -0
  146. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/edit.tsx +127 -0
  147. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/index.tsx +4 -0
  148. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/list.tsx +254 -0
  149. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflowEventOutbox/show.tsx +74 -0
  150. package/dist/lib/application/files/gadmin2-game-angle-demo/web/yarn.lock +1501 -1199
  151. package/package.json +1 -1
  152. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/app.controller.spec.ts +0 -22
  153. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/BarChart/index.tsx +0 -896
  154. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/ChartSwitcher/index.tsx +0 -219
  155. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/ChartViewer/index.tsx +0 -159
  156. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/Filter/index.tsx +0 -192
  157. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/LineChart/index.tsx +0 -1034
  158. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/NumCard/NumCard.module.css +0 -8
  159. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/NumCard/index.tsx +0 -509
  160. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/NumLineCard/index.tsx +0 -66
  161. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/PieChart/index.tsx +0 -552
  162. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/RadarChart/index.tsx +0 -263
  163. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/Section/index.tsx +0 -35
  164. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/Table/index.tsx +0 -207
  165. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/TreemapChart/index.tsx +0 -382
  166. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/WorldMap/index.tsx +0 -135
  167. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/chart-constants.ts +0 -53
  168. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/icon/InfoIcon.tsx +0 -8
  169. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/icon/index.ts +0 -1
  170. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/map/config.ts +0 -31
  171. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/map/nameMap.json +0 -9
  172. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/map/world.geo.json +0 -39349
  173. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/canvas/metric-info-tooltip/index.tsx +0 -19
@@ -0,0 +1,363 @@
1
+ import React, { useMemo, useState } from 'react';
2
+ import {
3
+ Alert,
4
+ Button,
5
+ Input,
6
+ Modal,
7
+ Select,
8
+ Space,
9
+ Spin,
10
+ Typography,
11
+ message,
12
+ } from 'antd';
13
+ import { CheckCircleOutlined, LoadingOutlined } from '@ant-design/icons';
14
+ import { useWorkflowAgent } from '../../hooks/useWorkflowAgent';
15
+ import type { WorkflowNodeType, NodeInstanceAgentOutput } from '../../types';
16
+
17
+ const { Text } = Typography;
18
+ const { TextArea } = Input;
19
+
20
+ /**
21
+ * Front-end hardcoded mapping: nodeType category → prompt placeholder & scenario hint.
22
+ */
23
+ const CATEGORY_PROMPT_CONFIG: Record<
24
+ string,
25
+ { placeholder: string; scenarioHint: string }
26
+ > = {
27
+ TRIGGER: {
28
+ placeholder: 'e.g. Trigger every weekday at 9am Shanghai time',
29
+ scenarioHint:
30
+ 'This is a trigger node. Generate config for defining when/how the workflow starts.',
31
+ },
32
+ ACTION: {
33
+ placeholder:
34
+ 'e.g. Send a POST request to https://api.example.com/notify with the order data',
35
+ scenarioHint:
36
+ 'This is an action node. Generate config for performing an operation (HTTP call, DB query, notification, etc.).',
37
+ },
38
+ CONDITION: {
39
+ placeholder:
40
+ 'e.g. Check if order.amount > 1000 AND order.status is "pending"',
41
+ scenarioHint:
42
+ 'This is a condition/branching node. Generate config for evaluating conditions to decide the flow path.',
43
+ },
44
+ LOOP: {
45
+ placeholder: 'e.g. Iterate over the "items" array field with concurrency 3',
46
+ scenarioHint:
47
+ 'This is a loop node. Generate config for iterating over data collections.',
48
+ },
49
+ FLOW_CONTROL: {
50
+ placeholder: 'e.g. Wait 30 seconds before proceeding to the next step',
51
+ scenarioHint:
52
+ 'This is a flow control node. Generate config for managing execution flow (delay, parallel, error handling).',
53
+ },
54
+ APPROVAL: {
55
+ placeholder:
56
+ 'e.g. Wait for manager@company.com to approve, timeout after 24 hours',
57
+ scenarioHint:
58
+ 'This is an approval node. Generate config for human approval gates with escalation rules.',
59
+ },
60
+ SUB_WORKFLOW: {
61
+ placeholder:
62
+ 'e.g. Call the "order-processing" workflow and wait for completion',
63
+ scenarioHint:
64
+ 'This is a sub-workflow node. Generate config for invoking another workflow as a child process.',
65
+ },
66
+ };
67
+
68
+ const DEFAULT_PROMPT_CONFIG = {
69
+ placeholder: 'Describe what this node instance should do...',
70
+ scenarioHint: 'Generate appropriate configuration for this node type.',
71
+ };
72
+
73
+ function getPromptConfig(category: string) {
74
+ return CATEGORY_PROMPT_CONFIG[category] || DEFAULT_PROMPT_CONFIG;
75
+ }
76
+
77
+ function tryParseNodeInstanceOutput(
78
+ raw: string,
79
+ ): NodeInstanceAgentOutput | null {
80
+ try {
81
+ const match = raw.match(/```json\s*([\s\S]*?)```/);
82
+ const jsonStr = match ? match[1].trim() : raw.trim();
83
+ const parsed = JSON.parse(jsonStr);
84
+ if (typeof parsed.name === 'string' && typeof parsed.config === 'object') {
85
+ return parsed as NodeInstanceAgentOutput;
86
+ }
87
+ } catch {
88
+ // not valid
89
+ }
90
+ return null;
91
+ }
92
+
93
+ export interface AiGenerateResult {
94
+ nodeTypeId: string;
95
+ name: string;
96
+ description: string;
97
+ config: Record<string, any>;
98
+ }
99
+
100
+ interface Props {
101
+ open: boolean;
102
+ nodeTypes: WorkflowNodeType[];
103
+ onClose: () => void;
104
+ onApply: (data: AiGenerateResult) => void;
105
+ }
106
+
107
+ export function CreateNodeInstanceModal({
108
+ open,
109
+ nodeTypes,
110
+ onClose,
111
+ onApply,
112
+ }: Props) {
113
+ const [selectedNodeTypeId, setSelectedNodeTypeId] = useState<
114
+ string | undefined
115
+ >();
116
+ const [prompt, setPrompt] = useState('');
117
+ const [step, setStep] = useState<'selectType' | 'generating' | 'done'>(
118
+ 'selectType',
119
+ );
120
+ const [generatedResult, setGeneratedResult] =
121
+ useState<NodeInstanceAgentOutput | null>(null);
122
+ const [resultInput, setResultInput] = useState('');
123
+
124
+ const {
125
+ generate,
126
+ abort: abortAgent,
127
+ loading: agentLoading,
128
+ error: agentError,
129
+ } = useWorkflowAgent({ nodeTypes });
130
+
131
+ const selectedNodeType = useMemo(
132
+ () => nodeTypes.find((nt) => String(nt.id) === selectedNodeTypeId),
133
+ [selectedNodeTypeId, nodeTypes],
134
+ );
135
+
136
+ const promptConfig = useMemo(
137
+ () =>
138
+ selectedNodeType
139
+ ? getPromptConfig(selectedNodeType.category)
140
+ : DEFAULT_PROMPT_CONFIG,
141
+ [selectedNodeType],
142
+ );
143
+
144
+ async function handleGenerate() {
145
+ if (!prompt.trim()) {
146
+ message.warning('Please describe what this node instance should do');
147
+ return;
148
+ }
149
+ if (!selectedNodeType) return;
150
+
151
+ setStep('generating');
152
+ const result = await generate({
153
+ action: 'create_node_instance',
154
+ prompt: prompt.trim(),
155
+ nodeType: selectedNodeType,
156
+ scenarioHint: promptConfig.scenarioHint,
157
+ });
158
+
159
+ if (result && 'config' in result) {
160
+ const nodeResult = result as NodeInstanceAgentOutput;
161
+ setGeneratedResult(nodeResult);
162
+ setResultInput(JSON.stringify(nodeResult, null, 2));
163
+ setStep('done');
164
+ } else if (!result) {
165
+ // Aborted or still waiting — stay in generating to allow manual paste
166
+ setStep('generating');
167
+ }
168
+ }
169
+
170
+ function handleApplyManualJson() {
171
+ const parsed = tryParseNodeInstanceOutput(resultInput);
172
+ if (!parsed) {
173
+ message.error(
174
+ 'Invalid JSON format. Expected: { "name": "...", "description": "...", "config": {...} }',
175
+ );
176
+ return;
177
+ }
178
+ setGeneratedResult(parsed);
179
+ setResultInput(JSON.stringify(parsed, null, 2));
180
+ setStep('done');
181
+ }
182
+
183
+ function handleConfirm() {
184
+ if (!generatedResult || !selectedNodeTypeId) return;
185
+
186
+ onApply({
187
+ nodeTypeId: selectedNodeTypeId,
188
+ name: generatedResult.name,
189
+ description: generatedResult.description || '',
190
+ config: generatedResult.config,
191
+ });
192
+ handleClose();
193
+ }
194
+
195
+ function handleClose() {
196
+ abortAgent();
197
+ setSelectedNodeTypeId(undefined);
198
+ setPrompt('');
199
+ setStep('selectType');
200
+ setGeneratedResult(null);
201
+ setResultInput('');
202
+ onClose();
203
+ }
204
+
205
+ return (
206
+ <Modal
207
+ title="AI Create Node Instance"
208
+ open={open}
209
+ onCancel={handleClose}
210
+ footer={null}
211
+ destroyOnClose
212
+ width={560}
213
+ >
214
+ <Space direction="vertical" style={{ width: '100%' }} size="middle">
215
+ {/* Node Type Select — always visible */}
216
+ <div>
217
+ <Text strong>Node Type</Text>
218
+ <Select
219
+ placeholder="Select a node type"
220
+ value={selectedNodeTypeId}
221
+ onChange={setSelectedNodeTypeId}
222
+ disabled={step === 'generating'}
223
+ style={{ width: '100%', marginTop: 4 }}
224
+ showSearch
225
+ optionFilterProp="label"
226
+ options={nodeTypes.map((nt) => ({
227
+ label: `${nt.label} (${nt.category})`,
228
+ value: String(nt.id),
229
+ }))}
230
+ />
231
+ </div>
232
+
233
+ {/* Prompt Input — visible once type is selected */}
234
+ {selectedNodeTypeId && (
235
+ <div>
236
+ <Text strong>Describe your node instance</Text>
237
+ <TextArea
238
+ rows={4}
239
+ placeholder={promptConfig.placeholder}
240
+ value={prompt}
241
+ onChange={(e) => setPrompt(e.target.value)}
242
+ disabled={step === 'generating' || step === 'done'}
243
+ style={{ marginTop: 4 }}
244
+ />
245
+ </div>
246
+ )}
247
+
248
+ {/* Generating state */}
249
+ {step === 'generating' && (
250
+ <>
251
+ <Alert
252
+ type="info"
253
+ icon={<Spin indicator={<LoadingOutlined />} size="small" />}
254
+ showIcon
255
+ message="Waiting for Agent..."
256
+ description="Continue your conversation with the Agent in the chat panel. Once it outputs valid JSON, it will be captured automatically. Or paste JSON below manually."
257
+ />
258
+ <div>
259
+ <Text strong>JSON Result</Text>
260
+ <Text type="secondary" style={{ marginLeft: 8, fontSize: 12 }}>
261
+ Auto-filled by Agent or paste manually
262
+ </Text>
263
+ <TextArea
264
+ rows={6}
265
+ placeholder={
266
+ '{"name": "...", "description": "...", "config": {...}}'
267
+ }
268
+ value={resultInput}
269
+ onChange={(e) => setResultInput(e.target.value)}
270
+ style={{ marginTop: 4, fontFamily: 'monospace', fontSize: 12 }}
271
+ />
272
+ </div>
273
+ </>
274
+ )}
275
+
276
+ {/* Done state */}
277
+ {step === 'done' && generatedResult && (
278
+ <>
279
+ <Alert
280
+ type="success"
281
+ icon={<CheckCircleOutlined />}
282
+ showIcon
283
+ message="Node instance config generated!"
284
+ description={`Name: ${generatedResult.name}. Config has ${Object.keys(generatedResult.config).length} fields.`}
285
+ />
286
+ <div>
287
+ <Text strong>JSON Result</Text>
288
+ <TextArea
289
+ rows={6}
290
+ value={resultInput}
291
+ onChange={(e) => setResultInput(e.target.value)}
292
+ style={{ marginTop: 4, fontFamily: 'monospace', fontSize: 12 }}
293
+ />
294
+ </div>
295
+ </>
296
+ )}
297
+
298
+ {/* Agent error */}
299
+ {agentError && (
300
+ <Alert
301
+ type="error"
302
+ message="Generation failed"
303
+ description={agentError}
304
+ showIcon
305
+ />
306
+ )}
307
+
308
+ {/* Action buttons */}
309
+ <div style={{ textAlign: 'right' }}>
310
+ <Space>
311
+ <Button onClick={handleClose}>Cancel</Button>
312
+ {step === 'selectType' && (
313
+ <Button
314
+ type="primary"
315
+ disabled={!selectedNodeTypeId || !prompt.trim()}
316
+ loading={agentLoading}
317
+ onClick={handleGenerate}
318
+ >
319
+ Generate
320
+ </Button>
321
+ )}
322
+ {step === 'generating' && (
323
+ <Button
324
+ type="primary"
325
+ disabled={!resultInput.trim()}
326
+ onClick={handleApplyManualJson}
327
+ >
328
+ Apply JSON
329
+ </Button>
330
+ )}
331
+ {step === 'done' && (
332
+ <>
333
+ <Button
334
+ onClick={() => {
335
+ setStep('selectType');
336
+ setGeneratedResult(null);
337
+ setResultInput('');
338
+ }}
339
+ >
340
+ Re-generate
341
+ </Button>
342
+ <Button
343
+ type="primary"
344
+ onClick={() => {
345
+ const parsed = tryParseNodeInstanceOutput(resultInput);
346
+ if (parsed) {
347
+ setGeneratedResult(parsed);
348
+ handleConfirm();
349
+ } else {
350
+ message.error('Invalid JSON format');
351
+ }
352
+ }}
353
+ >
354
+ Confirm &amp; Create
355
+ </Button>
356
+ </>
357
+ )}
358
+ </Space>
359
+ </div>
360
+ </Space>
361
+ </Modal>
362
+ );
363
+ }
@@ -0,0 +1,154 @@
1
+ import React from 'react';
2
+ import { Form, Input, InputNumber, Switch, Select } from 'antd';
3
+
4
+ const { TextArea } = Input;
5
+
6
+ interface SchemaProperty {
7
+ type: string;
8
+ title?: string;
9
+ description?: string;
10
+ enum?: string[];
11
+ default?: any;
12
+ items?: { type: string; enum?: string[] };
13
+ }
14
+
15
+ interface ConfigSchema {
16
+ type?: string;
17
+ properties?: Record<string, SchemaProperty>;
18
+ required?: string[];
19
+ }
20
+
21
+ interface Props {
22
+ schema: ConfigSchema | null;
23
+ disabled?: boolean;
24
+ }
25
+
26
+ /**
27
+ * Renders Ant Design Form.Items dynamically based on a JSON Schema.
28
+ * Must be used inside a <Form> parent — it does not create its own Form instance.
29
+ * All fields are namespaced under "config" (e.g., Form field name = ["config", "fieldKey"]).
30
+ */
31
+ export function DynamicConfigForm({ schema, disabled = false }: Props) {
32
+ if (!schema?.properties) {
33
+ return null;
34
+ }
35
+
36
+ const requiredFields = schema.required ?? [];
37
+
38
+ return (
39
+ <>
40
+ {Object.entries(schema.properties).map(([key, prop]) => {
41
+ const label = prop.title || key;
42
+ const isRequired = requiredFields.includes(key);
43
+
44
+ // Boolean → Switch
45
+ if (prop.type === 'boolean') {
46
+ return (
47
+ <Form.Item
48
+ key={key}
49
+ name={['config', key]}
50
+ label={label}
51
+ tooltip={prop.description}
52
+ valuePropName="checked"
53
+ rules={isRequired ? [{ required: true }] : undefined}
54
+ >
55
+ <Switch disabled={disabled} />
56
+ </Form.Item>
57
+ );
58
+ }
59
+
60
+ // Enum → Select
61
+ if (prop.enum) {
62
+ return (
63
+ <Form.Item
64
+ key={key}
65
+ name={['config', key]}
66
+ label={label}
67
+ tooltip={prop.description}
68
+ rules={
69
+ isRequired
70
+ ? [{ required: true, message: `${label} is required` }]
71
+ : undefined
72
+ }
73
+ >
74
+ <Select
75
+ disabled={disabled}
76
+ allowClear
77
+ options={prop.enum.map((v) => ({ label: v, value: v }))}
78
+ />
79
+ </Form.Item>
80
+ );
81
+ }
82
+
83
+ // Array → Select tags mode
84
+ if (prop.type === 'array') {
85
+ const enumOptions = prop.items?.enum;
86
+ return (
87
+ <Form.Item
88
+ key={key}
89
+ name={['config', key]}
90
+ label={label}
91
+ tooltip={prop.description}
92
+ rules={
93
+ isRequired
94
+ ? [{ required: true, message: `${label} is required` }]
95
+ : undefined
96
+ }
97
+ >
98
+ <Select
99
+ mode="tags"
100
+ disabled={disabled}
101
+ allowClear
102
+ options={enumOptions?.map((v) => ({ label: v, value: v }))}
103
+ />
104
+ </Form.Item>
105
+ );
106
+ }
107
+
108
+ // Number → InputNumber
109
+ if (prop.type === 'number' || prop.type === 'integer') {
110
+ return (
111
+ <Form.Item
112
+ key={key}
113
+ name={['config', key]}
114
+ label={label}
115
+ tooltip={prop.description}
116
+ rules={
117
+ isRequired
118
+ ? [{ required: true, message: `${label} is required` }]
119
+ : undefined
120
+ }
121
+ >
122
+ <InputNumber disabled={disabled} style={{ width: '100%' }} />
123
+ </Form.Item>
124
+ );
125
+ }
126
+
127
+ // String (default) → Input or TextArea
128
+ const isLongText =
129
+ prop.description?.includes('multiline') ||
130
+ key.toLowerCase().includes('body') ||
131
+ key.toLowerCase().includes('template');
132
+ return (
133
+ <Form.Item
134
+ key={key}
135
+ name={['config', key]}
136
+ label={label}
137
+ tooltip={prop.description}
138
+ rules={
139
+ isRequired
140
+ ? [{ required: true, message: `${label} is required` }]
141
+ : undefined
142
+ }
143
+ >
144
+ {isLongText ? (
145
+ <TextArea rows={3} disabled={disabled} />
146
+ ) : (
147
+ <Input disabled={disabled} />
148
+ )}
149
+ </Form.Item>
150
+ );
151
+ })}
152
+ </>
153
+ );
154
+ }
@@ -0,0 +1,176 @@
1
+ import React, { useMemo, useState } from 'react';
2
+ import {
3
+ Button,
4
+ Card,
5
+ Form,
6
+ Input,
7
+ Modal,
8
+ Select,
9
+ Switch,
10
+ Typography,
11
+ } from 'antd';
12
+ import { ArrowLeftOutlined, RobotOutlined } from '@ant-design/icons';
13
+ import type { FormInstance } from 'antd';
14
+ import { DynamicConfigForm } from './DynamicConfigForm';
15
+ import {
16
+ CreateNodeInstanceModal,
17
+ type AiGenerateResult,
18
+ } from './CreateNodeInstanceModal';
19
+ import type { WorkflowNodeType } from '../../types';
20
+
21
+ const { Title } = Typography;
22
+ const isDev = import.meta.env.DEV;
23
+
24
+ interface NodeInstanceFormProps {
25
+ form: FormInstance;
26
+ nodeTypes: WorkflowNodeType[];
27
+ title: string;
28
+ submitText: string;
29
+ submitting: boolean;
30
+ disableNodeType?: boolean;
31
+ onSubmit: () => void;
32
+ onBack: () => void;
33
+ }
34
+
35
+ export function NodeInstanceForm({
36
+ form,
37
+ nodeTypes,
38
+ title,
39
+ submitText,
40
+ submitting,
41
+ disableNodeType,
42
+ onSubmit,
43
+ onBack,
44
+ }: NodeInstanceFormProps) {
45
+ const [aiModalOpen, setAiModalOpen] = useState(false);
46
+
47
+ const selectedNodeTypeId = Form.useWatch('nodeTypeId', form);
48
+
49
+ const selectedSchema = useMemo(() => {
50
+ if (!selectedNodeTypeId) return null;
51
+ const nt = nodeTypes.find(
52
+ (t) => String(t.id) === String(selectedNodeTypeId),
53
+ );
54
+ return nt?.configSchema ?? null;
55
+ }, [selectedNodeTypeId, nodeTypes]);
56
+
57
+ function handleAiApply(data: AiGenerateResult) {
58
+ const currentName = form.getFieldValue('name');
59
+ const currentDesc = form.getFieldValue('description');
60
+ const currentConfig = form.getFieldValue('config');
61
+ const hasExistingValues = currentName || currentDesc || currentConfig;
62
+
63
+ if (hasExistingValues) {
64
+ Modal.confirm({
65
+ title: '覆盖确认',
66
+ content: 'AI 生成的内容将覆盖当前填写的内容,是否继续?',
67
+ okText: '确认覆盖',
68
+ cancelText: '取消',
69
+ onOk: () => applyAiData(data),
70
+ });
71
+ } else {
72
+ applyAiData(data);
73
+ }
74
+ }
75
+
76
+ function applyAiData(data: AiGenerateResult) {
77
+ form.setFieldsValue({
78
+ nodeTypeId: data.nodeTypeId ? String(data.nodeTypeId) : undefined,
79
+ name: data.name || undefined,
80
+ description: data.description || undefined,
81
+ config: data.config || undefined,
82
+ });
83
+ }
84
+
85
+ return (
86
+ <div style={{ background: '#f0f2f5', minHeight: 'calc(100vh - 64px)' }}>
87
+ <Card style={{ marginBottom: 16 }}>
88
+ <div
89
+ style={{
90
+ display: 'flex',
91
+ alignItems: 'center',
92
+ justifyContent: 'space-between',
93
+ }}
94
+ >
95
+ <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
96
+ <Button type="text" icon={<ArrowLeftOutlined />} onClick={onBack}>
97
+ 返回
98
+ </Button>
99
+ <Title level={4} style={{ margin: 0 }}>
100
+ {title}
101
+ </Title>
102
+ </div>
103
+ {isDev && (
104
+ <Button
105
+ type="primary"
106
+ icon={<RobotOutlined />}
107
+ onClick={() => setAiModalOpen(true)}
108
+ >
109
+ AI 自动生成
110
+ </Button>
111
+ )}
112
+ </div>
113
+ </Card>
114
+
115
+ <Card style={{ padding: '24px 32px' }}>
116
+ <Form form={form} layout="vertical" style={{ maxWidth: 600 }}>
117
+ <Form.Item
118
+ name="nodeTypeId"
119
+ label="Node Type"
120
+ rules={[{ required: true, message: 'Please select a node type' }]}
121
+ >
122
+ <Select
123
+ placeholder="Select node type"
124
+ disabled={disableNodeType}
125
+ showSearch
126
+ optionFilterProp="label"
127
+ options={nodeTypes.map((nt) => ({
128
+ label: `${nt.label} (${nt.category})`,
129
+ value: String(nt.id),
130
+ }))}
131
+ />
132
+ </Form.Item>
133
+
134
+ <Form.Item
135
+ name="name"
136
+ label="Instance Name"
137
+ rules={[{ required: true, message: 'Please enter a name' }]}
138
+ >
139
+ <Input placeholder="e.g. Send Slack to #general" />
140
+ </Form.Item>
141
+
142
+ <Form.Item name="description" label="Description">
143
+ <Input.TextArea rows={2} placeholder="Optional description" />
144
+ </Form.Item>
145
+
146
+ <Form.Item name="isEnabled" label="Enabled" valuePropName="checked">
147
+ <Switch />
148
+ </Form.Item>
149
+
150
+ {selectedSchema && (
151
+ <>
152
+ <Title level={5} style={{ color: '#595959' }}>
153
+ Configuration
154
+ </Title>
155
+ <DynamicConfigForm schema={selectedSchema} />
156
+ </>
157
+ )}
158
+
159
+ <div style={{ marginTop: 24, display: 'flex', gap: 12 }}>
160
+ <Button onClick={onBack}>Cancel</Button>
161
+ <Button type="primary" loading={submitting} onClick={onSubmit}>
162
+ {submitText}
163
+ </Button>
164
+ </div>
165
+ </Form>
166
+ </Card>
167
+
168
+ <CreateNodeInstanceModal
169
+ open={aiModalOpen}
170
+ nodeTypes={nodeTypes}
171
+ onClose={() => setAiModalOpen(false)}
172
+ onApply={handleAiApply}
173
+ />
174
+ </div>
175
+ );
176
+ }