@gadmin2n/schematics 0.0.72 → 0.0.75

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
@@ -1,15 +1,16 @@
1
1
  import React, { useCallback, useEffect, useRef, useState } from 'react';
2
2
  import {
3
+ Alert,
3
4
  Badge,
4
5
  Button,
5
6
  Card,
6
7
  Col,
7
8
  Input,
9
+ Modal,
8
10
  Popconfirm,
9
11
  Row,
10
12
  Select,
11
13
  Space,
12
- Statistic,
13
14
  Switch,
14
15
  Table,
15
16
  Tag,
@@ -20,12 +21,14 @@ import {
20
21
  import {
21
22
  DeleteOutlined,
22
23
  PlayCircleOutlined,
24
+ PlusOutlined,
23
25
  ReloadOutlined,
26
+ SendOutlined,
24
27
  } from '@ant-design/icons';
25
28
  import { useSearchParams, useNavigate } from 'react-router-dom';
26
29
  import { customRequest } from 'helpers/http';
27
30
 
28
- const { Title } = Typography;
31
+ const { Title, Text } = Typography;
29
32
 
30
33
  // ─── Types ────────────────────────────────────────────────────────────────────
31
34
 
@@ -57,6 +60,18 @@ interface Overview {
57
60
  active: number;
58
61
  }
59
62
 
63
+ interface MetricsOverview {
64
+ totalRuns: { last24h: number; total: number };
65
+ successRate: { last24h: number; total: number };
66
+ failed: { last24h: number; total: number };
67
+ duration: {
68
+ last24h: { avg: number; p95: number };
69
+ total: { avg: number; p95: number };
70
+ };
71
+ running: number;
72
+ queued: number;
73
+ }
74
+
60
75
  interface JobsResponse {
61
76
  overview: Overview;
62
77
  modules: string[];
@@ -118,16 +133,35 @@ function RunDot({
118
133
  );
119
134
  }
120
135
 
136
+ // ─── Duration formatter ───────────────────────────────────────────────────────
137
+
138
+ function formatDuration(ms: number): string {
139
+ if (ms <= 0) return '—';
140
+ if (ms < 1000) return `${Math.round(ms)}ms`;
141
+ const sec = ms / 1000;
142
+ if (sec < 60) return `${sec.toFixed(1)}s`;
143
+ const m = Math.floor(sec / 60);
144
+ const s = Math.round(sec % 60);
145
+ return `${m}m ${s}s`;
146
+ }
147
+
121
148
  // ─── AgendaJobsPage ───────────────────────────────────────────────────────────
122
149
 
123
150
  export default function AgendaJobsPage() {
124
151
  const navigate = useNavigate();
125
152
  const [jobs, setJobs] = useState<JobItem[]>([]);
126
153
  const [overview, setOverview] = useState<Overview | null>(null);
154
+ const [metricsOverview, setMetricsOverview] =
155
+ useState<MetricsOverview | null>(null);
127
156
  const [modules, setModules] = useState<string[]>([]);
128
157
  const [total, setTotal] = useState(0);
129
158
  const [loading, setLoading] = useState(false);
130
159
 
160
+ // AI Create modal
161
+ const [aiModalOpen, setAiModalOpen] = useState(false);
162
+ const [aiPrompt, setAiPrompt] = useState('');
163
+ const [aiSent, setAiSent] = useState(false);
164
+
131
165
  // Filters — synced with URL search params
132
166
  const [searchParams, setSearchParams] = useSearchParams();
133
167
  const filterState = searchParams.get('state') || undefined;
@@ -191,15 +225,15 @@ export default function AgendaJobsPage() {
191
225
  if (filterName) params.q = filterName;
192
226
  if (filterModule) params.module = filterModule;
193
227
 
194
- const res = await customRequest<JobsResponse>(
195
- 'agenda/jobs',
196
- 'GET',
197
- params,
198
- );
228
+ const [res, metrics] = await Promise.all([
229
+ customRequest<JobsResponse>('agenda/jobs', 'GET', params),
230
+ customRequest<MetricsOverview>('agenda/overview', 'GET'),
231
+ ]);
199
232
  setJobs(res.jobs);
200
233
  setOverview(res.overview);
201
234
  setModules(res.modules);
202
235
  setTotal(res.total);
236
+ setMetricsOverview(metrics);
203
237
  } catch (e: any) {
204
238
  message.error(e?.message ?? 'Failed to fetch jobs');
205
239
  } finally {
@@ -235,21 +269,17 @@ export default function AgendaJobsPage() {
235
269
  }
236
270
  }
237
271
 
238
- // ─── Overview cards ────────────────────────────────────────────────────────
239
-
240
- const OVERVIEW_ITEMS: {
241
- key: keyof Overview;
242
- label: string;
243
- color: string;
244
- }[] = [
245
- { key: 'running', label: 'Running', color: '#1677ff' },
246
- { key: 'scheduled', label: 'Scheduled', color: '#595959' },
247
- { key: 'queued', label: 'Queued', color: '#faad14' },
248
- { key: 'completed', label: 'Completed', color: '#52c41a' },
249
- { key: 'failed', label: 'Failed', color: '#ff4d4f' },
250
- { key: 'repeating', label: 'Repeating', color: '#722ed1' },
251
- { key: 'paused', label: 'Paused', color: '#8c8c8c' },
252
- ];
272
+ // ─── Metrics cards helpers ───────────────────────────────────────────────
273
+
274
+ const metricsCardStyle = (key?: string): React.CSSProperties => ({
275
+ cursor: key ? 'pointer' : 'default',
276
+ borderColor: key && filterState === key ? '#1677ff' : undefined,
277
+ height: '100%',
278
+ });
279
+
280
+ const handleMetricClick = (state: string) => {
281
+ setFilterState(filterState === state ? undefined : state);
282
+ };
253
283
 
254
284
  // ─── Table columns ─────────────────────────────────────────────────────────
255
285
 
@@ -304,6 +334,19 @@ export default function AgendaJobsPage() {
304
334
  width: 100,
305
335
  render: (state: string) => <StateTag state={state} />,
306
336
  },
337
+ {
338
+ title: 'Runs',
339
+ key: 'runs',
340
+ width: 170,
341
+ render: (_: any, record: JobItem) => (
342
+ <Space size={6}>
343
+ <RunDot count={record.runs.queued} color="#faad14" label="Queued" />
344
+ <RunDot count={record.runs.success} color="#006d32" label="Success" />
345
+ <RunDot count={record.runs.running} color="#52c41a" label="Running" />
346
+ <RunDot count={record.runs.failed} color="#ff4d4f" label="Failed" />
347
+ </Space>
348
+ ),
349
+ },
307
350
  {
308
351
  title: 'Schedule',
309
352
  dataIndex: 'repeatInterval',
@@ -353,19 +396,6 @@ export default function AgendaJobsPage() {
353
396
  '—'
354
397
  ),
355
398
  },
356
- {
357
- title: 'Runs',
358
- key: 'runs',
359
- width: 170,
360
- render: (_: any, record: JobItem) => (
361
- <Space size={6}>
362
- <RunDot count={record.runs.queued} color="#faad14" label="Queued" />
363
- <RunDot count={record.runs.success} color="#006d32" label="Success" />
364
- <RunDot count={record.runs.running} color="#52c41a" label="Running" />
365
- <RunDot count={record.runs.failed} color="#ff4d4f" label="Failed" />
366
- </Space>
367
- ),
368
- },
369
399
  {
370
400
  title: 'Actions',
371
401
  key: 'actions',
@@ -414,34 +444,193 @@ export default function AgendaJobsPage() {
414
444
  <Title level={4} style={{ margin: 0 }}>
415
445
  Cron Jobs
416
446
  </Title>
417
- <Button icon={<ReloadOutlined />} onClick={fetchJobs}></Button>
447
+ <Space>
448
+ <Button
449
+ type="primary"
450
+ icon={<PlusOutlined />}
451
+ onClick={() => {
452
+ setAiModalOpen(true);
453
+ setAiSent(false);
454
+ setAiPrompt('');
455
+ }}
456
+ >
457
+ AI创建任务
458
+ </Button>
459
+ <Button icon={<ReloadOutlined />} onClick={fetchJobs}></Button>
460
+ </Space>
418
461
  </div>
419
462
  </Card>
420
463
 
421
- {/* Overview cards */}
422
- {overview && (
464
+ {/* Metrics cards */}
465
+ {metricsOverview && (
423
466
  <Row gutter={12} style={{ marginBottom: 16 }}>
424
- {OVERVIEW_ITEMS.map(({ key, label, color }) => (
425
- <Col key={key} flex="1">
426
- <Card
427
- size="small"
428
- hoverable
429
- onClick={() =>
430
- setFilterState(filterState === key ? undefined : key)
431
- }
467
+ {/* Total Runs */}
468
+ <Col flex="1">
469
+ <Card size="small" style={metricsCardStyle()}>
470
+ <Text type="secondary" style={{ fontSize: 14 }}>
471
+ Total Runs
472
+ </Text>
473
+ <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
474
+ <span
475
+ style={{ fontSize: 24, fontWeight: 600, lineHeight: 1.3 }}
476
+ >
477
+ {metricsOverview.totalRuns.last24h}
478
+ </span>
479
+ <Text type="secondary" style={{ fontSize: 12 }}>
480
+ 24H
481
+ </Text>
482
+ </div>
483
+ <Text type="secondary" style={{ fontSize: 12 }}>
484
+ Total: {metricsOverview.totalRuns.total}
485
+ </Text>
486
+ </Card>
487
+ </Col>
488
+
489
+ {/* Success Rate */}
490
+ <Col flex="1">
491
+ <Card size="small" style={metricsCardStyle()}>
492
+ <Text type="secondary" style={{ fontSize: 14 }}>
493
+ Success Rate
494
+ </Text>
495
+ <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
496
+ <span
497
+ style={{
498
+ fontSize: 24,
499
+ fontWeight: 600,
500
+ lineHeight: 1.3,
501
+ color: '#52c41a',
502
+ }}
503
+ >
504
+ {metricsOverview.successRate.last24h}%
505
+ </span>
506
+ <Text type="secondary" style={{ fontSize: 12 }}>
507
+ 24H
508
+ </Text>
509
+ </div>
510
+ <Text type="secondary" style={{ fontSize: 12 }}>
511
+ Total: {metricsOverview.successRate.total}%
512
+ </Text>
513
+ </Card>
514
+ </Col>
515
+
516
+ {/* Failed — clickable */}
517
+ <Col flex="1">
518
+ <Card
519
+ size="small"
520
+ hoverable
521
+ onClick={() => handleMetricClick('failed')}
522
+ style={metricsCardStyle('failed')}
523
+ >
524
+ <Text type="secondary" style={{ fontSize: 14 }}>
525
+ Failed
526
+ </Text>
527
+ <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
528
+ <span
529
+ style={{
530
+ fontSize: 24,
531
+ fontWeight: 600,
532
+ lineHeight: 1.3,
533
+ color: '#ff4d4f',
534
+ }}
535
+ >
536
+ {metricsOverview.failed.last24h}
537
+ </span>
538
+ <Text type="secondary" style={{ fontSize: 12 }}>
539
+ 24H
540
+ </Text>
541
+ </div>
542
+ <Text type="secondary" style={{ fontSize: 12 }}>
543
+ Total: {metricsOverview.failed.total}
544
+ </Text>
545
+ </Card>
546
+ </Col>
547
+
548
+ {/* Duration P95 */}
549
+ <Col flex="1">
550
+ <Tooltip
551
+ title={
552
+ <>
553
+ <div>
554
+ Avg (24H):{' '}
555
+ {formatDuration(metricsOverview.duration.last24h.avg)}
556
+ </div>
557
+ <div>
558
+ Avg (Total):{' '}
559
+ {formatDuration(metricsOverview.duration.total.avg)}
560
+ </div>
561
+ </>
562
+ }
563
+ >
564
+ <Card size="small" style={metricsCardStyle()}>
565
+ <Text type="secondary" style={{ fontSize: 14 }}>
566
+ Duration (P95)
567
+ </Text>
568
+ <div
569
+ style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}
570
+ >
571
+ <span
572
+ style={{ fontSize: 24, fontWeight: 600, lineHeight: 1.3 }}
573
+ >
574
+ {formatDuration(metricsOverview.duration.last24h.p95)}
575
+ </span>
576
+ <Text type="secondary" style={{ fontSize: 12 }}>
577
+ 24H
578
+ </Text>
579
+ </div>
580
+ <Text type="secondary" style={{ fontSize: 12 }}>
581
+ Total: {formatDuration(metricsOverview.duration.total.p95)}
582
+ </Text>
583
+ </Card>
584
+ </Tooltip>
585
+ </Col>
586
+
587
+ {/* Running — clickable */}
588
+ <Col flex="1">
589
+ <Card
590
+ size="small"
591
+ hoverable
592
+ onClick={() => handleMetricClick('running')}
593
+ style={metricsCardStyle('running')}
594
+ >
595
+ <Text type="secondary" style={{ fontSize: 14 }}>
596
+ Running
597
+ </Text>
598
+ <div
432
599
  style={{
433
- borderColor: filterState === key ? color : undefined,
434
- cursor: 'pointer',
600
+ fontSize: 24,
601
+ fontWeight: 600,
602
+ lineHeight: 1.3,
603
+ color: '#1677ff',
435
604
  }}
436
605
  >
437
- <Statistic
438
- title={label}
439
- value={overview[key]}
440
- valueStyle={{ color }}
441
- />
442
- </Card>
443
- </Col>
444
- ))}
606
+ {metricsOverview.running}
607
+ </div>
608
+ </Card>
609
+ </Col>
610
+
611
+ {/* Queued — clickable */}
612
+ <Col flex="1">
613
+ <Card
614
+ size="small"
615
+ hoverable
616
+ onClick={() => handleMetricClick('queued')}
617
+ style={metricsCardStyle('queued')}
618
+ >
619
+ <Text type="secondary" style={{ fontSize: 14 }}>
620
+ Queued
621
+ </Text>
622
+ <div
623
+ style={{
624
+ fontSize: 24,
625
+ fontWeight: 600,
626
+ lineHeight: 1.3,
627
+ color: '#faad14',
628
+ }}
629
+ >
630
+ {metricsOverview.queued}
631
+ </div>
632
+ </Card>
633
+ </Col>
445
634
  </Row>
446
635
  )}
447
636
 
@@ -521,6 +710,7 @@ export default function AgendaJobsPage() {
521
710
  loading={loading}
522
711
  columns={columns}
523
712
  dataSource={jobs}
713
+ scroll={{ x: 1200 }}
524
714
  pagination={{
525
715
  current: page,
526
716
  pageSize: PAGE_SIZE,
@@ -531,6 +721,69 @@ export default function AgendaJobsPage() {
531
721
  size="small"
532
722
  />
533
723
  </Card>
724
+
725
+ {/* AI Create Cron Job Modal */}
726
+ <Modal
727
+ title="AI 创建定时任务"
728
+ open={aiModalOpen}
729
+ onCancel={() => setAiModalOpen(false)}
730
+ footer={null}
731
+ width={520}
732
+ >
733
+ <Text type="secondary" style={{ display: 'block', marginBottom: 12 }}>
734
+ 描述你的业务模块和定时任务需求,AI 将自动为你创建
735
+ </Text>
736
+ <Input.TextArea
737
+ value={aiPrompt}
738
+ onChange={(e) => setAiPrompt(e.target.value)}
739
+ placeholder={
740
+ '例:为 order 模块创建一个定时任务,每天凌晨2点自动清理超过30天的已取消订单,执行前先记录日志,失败时发送通知'
741
+ }
742
+ autoSize={{ minRows: 6, maxRows: 12 }}
743
+ onPressEnter={(e) => {
744
+ if (e.ctrlKey && aiPrompt.trim()) {
745
+ window.parent.postMessage(
746
+ {
747
+ type: 'SEND_PROMPT',
748
+ payload: `使用 cron-job-management skill来创建一个定时任务,任务描述:\n${aiPrompt.trim()}`,
749
+ },
750
+ '*',
751
+ );
752
+ setAiSent(true);
753
+ }
754
+ }}
755
+ />
756
+ <Button
757
+ type="primary"
758
+ icon={<SendOutlined />}
759
+ onClick={() => {
760
+ if (aiPrompt.trim()) {
761
+ window.parent.postMessage(
762
+ {
763
+ type: 'SEND_PROMPT',
764
+ payload: `使用 cron-job-management skill来创建一个定时任务,任务描述:\n${aiPrompt.trim()}`,
765
+ },
766
+ '*',
767
+ );
768
+ setAiSent(true);
769
+ }
770
+ }}
771
+ disabled={!aiPrompt.trim()}
772
+ style={{ marginTop: 12 }}
773
+ block
774
+ >
775
+ 发送
776
+ </Button>
777
+ {aiSent && (
778
+ <Alert
779
+ type="success"
780
+ showIcon
781
+ style={{ marginTop: 12 }}
782
+ message="已发送给 AI Agent"
783
+ description="请查看右下角 Agent 的工作情况,如果成功了,请点右侧刷新按钮查看。"
784
+ />
785
+ )}
786
+ </Modal>
534
787
  </div>
535
788
  );
536
789
  }
@@ -155,9 +155,7 @@ function DurationChart({
155
155
  xAxis: {
156
156
  type: 'category' as const,
157
157
  data: sorted.map((l) =>
158
- new Date(l.startAt).toLocaleString(undefined, {
159
- month: 'short',
160
- day: 'numeric',
158
+ new Date(l.startAt).toLocaleTimeString(undefined, {
161
159
  hour: '2-digit',
162
160
  minute: '2-digit',
163
161
  }),
@@ -0,0 +1,108 @@
1
+ import {
2
+ FieldDataType,
3
+ handleInitialValues,
4
+ handleOnFinish,
5
+ ModelType,
6
+ produceModel,
7
+ } from '@gadmin2n/react-common';
8
+ import { Create, useFileUploadState, useForm } from '@refinedev/antd';
9
+ import { Form } from 'antd';
10
+ import {
11
+ IResourceComponentsProps,
12
+ useApiUrl,
13
+ useTranslate,
14
+ } from '@refinedev/core';
15
+ import React, { useContext, useState } from 'react';
16
+ import { getFormItem, onFormValuesChange } from '../../helpers';
17
+ import { modelsMap, modelsEnum } from '../../generated/models.index';
18
+ import {
19
+ agendaJobFormConfig as formConfig,
20
+ agendaJobFormPrismaSelect as formPrismaSelect,
21
+ } from '../../generated/props/agendaJob/config';
22
+ import {
23
+ agendaJobModel,
24
+ useRelation,
25
+ } from '../../generated/props/agendaJob/model';
26
+ import { AgendaJob } from '../../generated/types/prisma.types';
27
+ import { AgendaJobForm as transformClass } from '../../generated/props/agendaJob/form.validator';
28
+ import { BusinessContext } from 'components/contexts/business';
29
+
30
+ export const AgendaJobCreate: React.FC<IResourceComponentsProps> = () => {
31
+ const resourceName = 'agendaJob';
32
+ const t = useTranslate();
33
+
34
+ const [[fields, model]] = useState(() => {
35
+ const model: ModelType = produceModel(
36
+ agendaJobModel,
37
+ {
38
+ // all formItem attrs surport, https://ant.design/components/form#formitem
39
+ // description : { component : <MDEditor data-color-mode="light" /> },
40
+ // status : { normalize : (value: any) => value ? "1" : "0" },
41
+ // cron: {validator: { validator: runCronValidator },},
42
+ },
43
+ transformClass,
44
+ );
45
+
46
+ const fields: FieldDataType[] = formConfig.fields
47
+ .map((fieldName: string) => model[fieldName])
48
+ .filter((field: FieldDataType) => field);
49
+
50
+ return [fields, model] as const;
51
+ });
52
+
53
+ const { formProps, saveButtonProps, onFinish, form } = useForm<AgendaJob>({
54
+ meta: { select: formPrismaSelect },
55
+ });
56
+ if (formProps.initialValues || formConfig.initialValues) {
57
+ formProps.initialValues = handleInitialValues(
58
+ formProps.initialValues || formConfig.initialValues || {},
59
+ fields,
60
+ );
61
+ }
62
+
63
+ const apiUrl = useApiUrl();
64
+ const { isLoading, onChange } = useFileUploadState();
65
+ const relationSelectProps = useRelation(modelsMap);
66
+
67
+ return (
68
+ <Create
69
+ saveButtonProps={{
70
+ ...saveButtonProps,
71
+ disabled: isLoading,
72
+ }}
73
+ >
74
+ <Form
75
+ {...formProps}
76
+ validateTrigger="onBlur"
77
+ onFinish={(values) => {
78
+ onFinish(
79
+ handleOnFinish(
80
+ {
81
+ ...values,
82
+ },
83
+ fields,
84
+ ),
85
+ );
86
+ }}
87
+ layout="vertical"
88
+ form={form}
89
+ onValuesChange={onFormValuesChange(form, formConfig.reaction)}
90
+ >
91
+ {fields.map((field) => {
92
+ return getFormItem(
93
+ field,
94
+ resourceName,
95
+ t,
96
+ form,
97
+ formConfig.reaction,
98
+ modelsEnum,
99
+ model,
100
+ apiUrl,
101
+ relationSelectProps,
102
+ onChange,
103
+ );
104
+ })}
105
+ </Form>
106
+ </Create>
107
+ );
108
+ };