@gadmin2n/schematics 0.0.87 → 0.0.89

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 (99) hide show
  1. package/dist/lib/application/files/gadmin2-game-angle-demo/.dockerignore +16 -2
  2. package/dist/lib/application/files/gadmin2-game-angle-demo/Dockerfile.codegen +40 -0
  3. package/dist/lib/application/files/gadmin2-game-angle-demo/Dockerfile.server +76 -0
  4. package/dist/lib/application/files/gadmin2-game-angle-demo/Dockerfile.web +53 -0
  5. package/dist/lib/application/files/gadmin2-game-angle-demo/Jenkinsfile +219 -33
  6. package/dist/lib/application/files/gadmin2-game-angle-demo/compose-ctl.sh +250 -0
  7. package/dist/lib/application/files/gadmin2-game-angle-demo/config/prisma/workflow.prisma +4 -1
  8. package/dist/lib/application/files/gadmin2-game-angle-demo/dev/postgres/init.sql +12 -0
  9. package/dist/lib/application/files/gadmin2-game-angle-demo/docker-compose.md +170 -0
  10. package/dist/lib/application/files/gadmin2-game-angle-demo/docker-compose.yml +254 -0
  11. package/dist/lib/application/files/gadmin2-game-angle-demo/server/package.json +8 -7
  12. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/lib/page-helpers.ts +1 -1
  13. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/prismaModels.ts +1 -1
  14. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/agenda.seed.ts +39 -0
  15. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/audit.seed.ts +40 -0
  16. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/bootstrap.ts +56 -0
  17. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/canvas.seed.ts +39 -0
  18. package/dist/lib/application/files/gadmin2-game-angle-demo/server/{scripts/sync-data-mngt-pages.ts → seed/data-mngt.seed.ts} +36 -20
  19. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/game.seed.ts +44 -0
  20. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/index.ts +30 -6
  21. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/permission.seed.ts +130 -0
  22. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-event-trigger.ts +60 -0
  23. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow-node-types.ts +11 -25
  24. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/workflow.seed.ts +108 -0
  25. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/main.ts +1 -0
  26. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/agendaJob/agendaJob.controller.spec.ts +31 -2
  27. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/audit/audit.controller.spec.ts +31 -2
  28. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/audit/audit.service.spec.ts +41 -57
  29. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/game/game.controller.spec.ts +31 -2
  30. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/game/game.service.spec.ts +309 -1
  31. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.controller.spec.ts +31 -2
  32. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/page/page.service.spec.ts +315 -1
  33. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/pageResource/pageResource.controller.spec.ts +31 -2
  34. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/pageResource/pageResource.service.spec.ts +312 -2
  35. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.controller.spec.ts +31 -2
  36. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/resource/resource.service.spec.ts +317 -1
  37. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.controller.spec.ts +31 -2
  38. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/role/role.service.spec.ts +309 -1
  39. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/rolePages/rolePages.controller.spec.ts +31 -2
  40. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/rolePages/rolePages.service.spec.ts +299 -1
  41. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/roleResource/roleResource.controller.spec.ts +31 -2
  42. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/roleResource/roleResource.service.spec.ts +307 -1
  43. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.controller.spec.ts +31 -2
  44. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/user/user.service.spec.ts +309 -1
  45. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/dsl-validate.util.spec.ts +205 -0
  46. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/dsl-validate.util.ts +116 -0
  47. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/temporal.service.spec.ts +158 -0
  48. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/temporal.service.ts +110 -1
  49. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/webhook-signature.util.spec.ts +79 -0
  50. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/webhook-signature.util.ts +54 -0
  51. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.controller.ts +34 -0
  52. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.spec.ts +457 -0
  53. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflow/workflow.service.ts +241 -4
  54. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.controller.spec.ts +34 -2
  55. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowEventOutbox/workflowEventOutbox.service.spec.ts +24 -30
  56. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.controller.spec.ts +34 -2
  57. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeInstance/workflowNodeInstance.service.spec.ts +36 -36
  58. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeType/workflowNodeType.controller.spec.ts +34 -2
  59. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/workflowNodeType/workflowNodeType.service.spec.ts +48 -24
  60. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/README.md +312 -3
  61. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/TODO.md +152 -0
  62. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/.dockerignore +12 -0
  63. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/Dockerfile +79 -0
  64. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/GRACEFUL-DEPLOYMENT.md +270 -0
  65. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/index.ts +1 -1
  66. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/activities/reporting.ts +23 -0
  67. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/index.ts +70 -5
  68. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/outbox-poller.ts +246 -90
  69. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/tests/cron-trigger-workflow.test.ts +20 -0
  70. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/worker/src/workflows/dsl-workflow.ts +96 -8
  71. package/dist/lib/application/files/gadmin2-game-angle-demo/web/nginx.conf +74 -0
  72. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/agentPanel/ElementInspector.tsx +18 -0
  73. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/components/agentPanel/promptGenerator.ts +1 -1
  74. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/helpers/form.tsx +1 -1
  75. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/en/common.json +3 -3
  76. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/locales/zh_CN/common.json +3 -3
  77. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/plugins/devShellPlugin.ts +4 -1
  78. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasEditPage.tsx +9 -0
  79. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasListPage.tsx +156 -139
  80. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasPage.tsx +14 -2
  81. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/CanvasToolbar.tsx +62 -0
  82. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/PublishModal.tsx +4 -6
  83. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/canvasApi.ts +18 -27
  84. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/canvasDefaults.ts +32 -11
  85. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas/demos.ts +48 -61
  86. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/canvas-page/index.tsx +3 -6
  87. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/components/DslView.tsx +16 -16
  88. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/editor.tsx +28 -35
  89. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/instance-detail.tsx +34 -3
  90. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/show.tsx +1 -1
  91. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/routes/workflow/types.ts +1 -1
  92. package/dist/lib/application/files/gadmin2-game-angle-demo/web/src/styles/antd.css +6 -0
  93. package/package.json +1 -1
  94. package/dist/lib/application/files/gadmin2-game-angle-demo/Dockerfile +0 -63
  95. package/dist/lib/application/files/gadmin2-game-angle-demo/server/scripts/sync-resources.ts +0 -100
  96. package/dist/lib/application/files/gadmin2-game-angle-demo/server/seed/permissions.ts +0 -302
  97. package/dist/lib/application/files/gadmin2-game-angle-demo/server/src/modules/canvas/canvas.controller.spec.ts +0 -20
  98. package/dist/lib/application/files/gadmin2-game-angle-demo/temporal/sql/create-event-trigger.sql +0 -87
  99. /package/dist/lib/application/files/gadmin2-game-angle-demo/{GRACEFUL-DEPLOYMENT.md → server/GRACEFUL-DEPLOYMENT.md} +0 -0
@@ -28,7 +28,6 @@ export const CANVAS_COMPONENTS: string[] = [
28
28
  'PieChart',
29
29
  'RadarChart',
30
30
  'TreemapChart',
31
- 'MultiChart',
32
31
  'Table',
33
32
  'WorldMap',
34
33
  ];
@@ -51,31 +50,52 @@ export const CANVAS_DEFAULTS: Record<string, CanvasDefault> = {
51
50
  },
52
51
 
53
52
  BarChart: {
54
- code: `<BarChart variant="bar" data={[{ name: "A", value: 1 }]} height={300} testId="canvas-barchart" />`,
53
+ code: `<MultiChart
54
+ defaultVariant="bar"
55
+ charts={["bar","line","pie"]}
56
+ data={{ xData: ["A", "B", "C", "D"], series: [{ name: "数据", data: [420, 580, 310, 670] }] }}
57
+ showDownload={true}
58
+ height={300}
59
+ testId="canvas-barchart"
60
+ />`,
55
61
  layout: { w: 24, h: 20, minW: 8, minH: 8 },
56
62
  props: getPropsFor('BarChart'),
57
63
  variants: getVariantsFor('BarChart'),
58
- imports: `import { BarChart } from "@gadmin2n/charts";`,
64
+ imports: `import { MultiChart } from "@gadmin2n/charts";`,
59
65
  },
60
66
 
61
67
  LineChart: {
62
- code: `<LineChart data={[{ name: "A", value: 1 }]} height={300} legendShow={true} testId="canvas-linechart" />`,
68
+ code: `<MultiChart
69
+ defaultVariant="line"
70
+ charts={["line","bar","pie"]}
71
+ data={{ xData: ["Jan", "Feb", "Mar", "Apr", "May", "Jun"], series: [{ name: "趋势", data: [65, 72, 78, 85, 82, 91] }] }}
72
+ showDownload={true}
73
+ height={300}
74
+ testId="canvas-linechart"
75
+ />`,
63
76
  layout: { w: 24, h: 20, minW: 10, minH: 8 },
64
77
  props: getPropsFor('LineChart'),
65
78
  variants: getVariantsFor('LineChart'),
66
- imports: `import { LineChart } from "@gadmin2n/charts";`,
79
+ imports: `import { MultiChart } from "@gadmin2n/charts";`,
67
80
  },
68
81
 
69
82
  PieChart: {
70
- code: `<PieChart variant="pie" data={[{ name: "A", value: 1 }]} height={300} legendShow={true} testId="canvas-piechart" />`,
83
+ code: `<MultiChart
84
+ defaultVariant="pie"
85
+ charts={["pie","bar","line"]}
86
+ data={{ xData: ["类目A", "类目B", "类目C", "类目D", "类目E"], series: [{ name: "分布", data: [1245, 876, 234, 189, 156] }] }}
87
+ showDownload={true}
88
+ height={300}
89
+ testId="canvas-piechart"
90
+ />`,
71
91
  layout: { w: 24, h: 20, minW: 8, minH: 8 },
72
92
  props: getPropsFor('PieChart'),
73
93
  variants: getVariantsFor('PieChart'),
74
- imports: `import { PieChart } from "@gadmin2n/charts";`,
94
+ imports: `import { MultiChart } from "@gadmin2n/charts";`,
75
95
  },
76
96
 
77
97
  RadarChart: {
78
- code: `<RadarChart indicators={[{ name: "A" }]} series={[{ name: "S", data: [1] }]} height={300} testId="canvas-radarchart" />`,
98
+ code: `<RadarChart indicators={[{ name: "A" }]} series={[{ name: "S", data: [1] }]} height={300} showDownload={true} testId="canvas-radarchart" />`,
79
99
  layout: { w: 24, h: 20, minW: 8, minH: 8 },
80
100
  props: getPropsFor('RadarChart'),
81
101
  variants: getVariantsFor('RadarChart'),
@@ -83,7 +103,7 @@ export const CANVAS_DEFAULTS: Record<string, CanvasDefault> = {
83
103
  },
84
104
 
85
105
  TreemapChart: {
86
- code: `<TreemapChart data={[{ name: "A", value: 1 }]} height={300} legendShow={true} testId="canvas-treemap" />`,
106
+ code: `<TreemapChart data={[{ name: "A", value: 1 }]} height={300} legendShow={true} showDownload={true} testId="canvas-treemap" />`,
87
107
  layout: { w: 24, h: 20, minW: 8, minH: 8 },
88
108
  props: getPropsFor('TreemapChart'),
89
109
  variants: getVariantsFor('TreemapChart'),
@@ -91,7 +111,7 @@ export const CANVAS_DEFAULTS: Record<string, CanvasDefault> = {
91
111
  },
92
112
 
93
113
  Table: {
94
- code: `<Table size="small" dataSource={[]} columns={[]} testId="canvas-table" />`,
114
+ code: `<Table size="small" dataSource={[]} columns={[]} showDownload={true} testId="canvas-table" />`,
95
115
  layout: { w: 24, h: 20, minW: 10, minH: 5 },
96
116
  props: getPropsFor('Table'),
97
117
  variants: getVariantsFor('Table'),
@@ -99,7 +119,7 @@ export const CANVAS_DEFAULTS: Record<string, CanvasDefault> = {
99
119
  },
100
120
 
101
121
  WorldMap: {
102
- code: `<WorldMap option={{ geo: {}, series: [] }} style={{ height: 400 }} testId="canvas-worldmap" />`,
122
+ code: `<WorldMap option={{ geo: {}, series: [] }} style={{ height: 400 }} showDownload={true} testId="canvas-worldmap" />`,
103
123
  layout: { w: 32, h: 20, minW: 14, minH: 10 },
104
124
  props: getPropsFor('WorldMap'),
105
125
  variants: getVariantsFor('WorldMap'),
@@ -108,6 +128,7 @@ export const CANVAS_DEFAULTS: Record<string, CanvasDefault> = {
108
128
 
109
129
  MultiChart: {
110
130
  code: `<MultiChart
131
+ showDownload={true}
111
132
  height={300}
112
133
  testId="canvas-multichart"
113
134
  />`,
@@ -362,37 +362,26 @@ const barChartDemo: ComponentDemo = {
362
362
  {
363
363
  name: 'bar',
364
364
  label: 'bar',
365
- code: `<BarChart
366
- variant="bar"
367
- data={[
368
- { name: "A", value: 420 },
369
- { name: "B", value: 580 },
370
- { name: "C", value: 310 },
371
- { name: "D", value: 670 },
372
- ]}
373
- unit="件"
374
- title="数据对比"
365
+ code: `<MultiChart
366
+ defaultVariant="bar"
367
+ charts={["bar","line","pie"]}
368
+ data={{ xData: ["A", "B", "C", "D"], series: [{ name: "数据", data: [420, 580, 310, 670] }] }}
369
+ showDownload={true}
375
370
  height={300}
376
- testId="canvas-barchart-bar"
371
+ testId="demo-barchart-bar"
377
372
  />`,
378
373
  },
379
374
  {
380
375
  name: 'groupBar',
381
376
  label: 'groupBar',
382
- code: `<BarChart
383
- variant="groupBar"
384
- data={{
385
- xData: ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
386
- series: [
387
- { name: "系列A", data: [120, 132, 101, 134, 90, 150] },
388
- { name: "系列B", data: [220, 182, 191, 234, 290, 330] },
389
- { name: "系列C", data: [ 80, 72, 85, 90, 110, 95] },
390
- ],
391
- }}
392
- unit="万"
393
- title="分组对比"
377
+ code: `<MultiChart
378
+ defaultVariant="bar"
379
+ charts={["bar","line","pie"]}
380
+ data={{ xData: ["Jan", "Feb", "Mar", "Apr", "May", "Jun"], series: [{ name: "系列A", data: [120, 132, 101, 134, 90, 150] }, { name: "系列B", data: [220, 182, 191, 234, 290, 330] }] }}
381
+ chartConfig={{"bar":{"variant":"groupBar"}}}
382
+ showDownload={true}
394
383
  height={300}
395
- testId="canvas-barchart-group"
384
+ testId="demo-barchart-group"
396
385
  />`,
397
386
  },
398
387
  ],
@@ -491,18 +480,13 @@ const lineChartDemo: ComponentDemo = {
491
480
  {
492
481
  name: 'default',
493
482
  label: 'default',
494
- code: `<LineChart
495
- data={{
496
- xData: ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
497
- series: [
498
- { name: "利用率", data: [65, 72, 78, 85, 82, 91] },
499
- ],
500
- }}
501
- unit="%"
502
- title="利用率"
483
+ code: `<MultiChart
484
+ defaultVariant="line"
485
+ charts={["line","bar","pie"]}
486
+ data={{ xData: ["Jan", "Feb", "Mar", "Apr", "May", "Jun"], series: [{ name: "利用率", data: [65, 72, 78, 85, 82, 91] }] }}
487
+ showDownload={true}
503
488
  height={300}
504
- legendShow={true}
505
- testId="canvas-linechart-default"
489
+ testId="demo-linechart-default"
506
490
  />`,
507
491
  },
508
492
  ],
@@ -597,27 +581,25 @@ const pieChartDemo: ComponentDemo = {
597
581
  {
598
582
  name: 'pie',
599
583
  label: 'pie',
600
- code: `<PieChart
601
- variant="pie"
602
- data={[
603
- { name: "类目A", value: 1245 },
604
- { name: "类目B", value: 876 },
605
- { name: "类目C", value: 234 },
606
- { name: "类目D", value: 189 },
607
- { name: "类目E", value: 156 },
608
- ]}
584
+ code: `<MultiChart
585
+ defaultVariant="pie"
586
+ charts={["pie","bar","line"]}
587
+ data={{ xData: ["类目A", "类目B", "类目C", "类目D", "类目E"], series: [{ name: "分布", data: [1245, 876, 234, 189, 156] }] }}
588
+ showDownload={true}
609
589
  height={300}
610
- title="分布"
611
- legendShow={true}
612
- insideLabelThreshold={15}
613
- topN={0}
614
- testId="canvas-piechart-pie"
590
+ testId="demo-piechart-pie"
615
591
  />`,
616
592
  },
617
- {
618
- name: 'ring',
619
- label: 'ring',
620
- code: `<PieChart
593
+ ],
594
+ };
595
+
596
+ // PieChart 备用 variants(不在组件库中展示,保留代码供参考)
597
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
598
+ const _pieChartUnusedVariants = [
599
+ {
600
+ name: 'ring',
601
+ label: 'ring',
602
+ code: `<PieChart
621
603
  variant="ring"
622
604
  data={[
623
605
  { name: "正常", value: 820, itemStyle: { color: "#52c41a" } },
@@ -630,11 +612,11 @@ const pieChartDemo: ComponentDemo = {
630
612
  topN={0}
631
613
  testId="canvas-piechart-ring"
632
614
  />`,
633
- },
634
- {
635
- name: 'sunburst',
636
- label: 'sunburst',
637
- code: `<PieChart
615
+ },
616
+ {
617
+ name: 'sunburst',
618
+ label: 'sunburst',
619
+ code: `<PieChart
638
620
  variant="sunburst"
639
621
  data={[
640
622
  {
@@ -666,9 +648,8 @@ const pieChartDemo: ComponentDemo = {
666
648
  legendShow={true}
667
649
  testId="canvas-piechart-sunburst"
668
650
  />`,
669
- },
670
- ],
671
- };
651
+ },
652
+ ];
672
653
 
673
654
  // ─── RadarChart ────────────────────────────────────────────────────────────────
674
655
  const radarChartDemo: ComponentDemo = {
@@ -746,6 +727,7 @@ const radarChartDemo: ComponentDemo = {
746
727
  { name: "组A", data: [92, 88, 75, 84, 90, 78], color: "#3889f3" },
747
728
  { name: "组B", data: [85, 92, 88, 91, 83, 95], color: "#0db46c" },
748
729
  ]}
730
+ showDownload={true}
749
731
  height={300}
750
732
  testId="canvas-radar-demo"
751
733
  />`,
@@ -856,6 +838,7 @@ const treemapChartDemo: ComponentDemo = {
856
838
  ]}
857
839
  height={400}
858
840
  title="矩形树图"
841
+ showDownload={true}
859
842
  testId="canvas-treemap-demo"
860
843
  />`,
861
844
  },
@@ -933,6 +916,7 @@ const tableDemo: ComponentDemo = {
933
916
  { title: "部门", dataIndex: "dept", key: "dept" },
934
917
  { title: "状态", dataIndex: "status", key: "status" },
935
918
  ]}
919
+ showDownload={true}
936
920
  testId="canvas-table-default"
937
921
  />`,
938
922
  },
@@ -1014,6 +998,7 @@ const worldMapDemo: ComponentDemo = {
1014
998
  series: [],
1015
999
  }}
1016
1000
  style={{ height: 400 }}
1001
+ showDownload={true}
1017
1002
  testId="canvas-worldmap-basic"
1018
1003
  />`,
1019
1004
  },
@@ -1054,6 +1039,7 @@ const worldMapDemo: ComponentDemo = {
1054
1039
  tooltip: { trigger: "item" },
1055
1040
  }}
1056
1041
  style={{ height: 400 }}
1042
+ showDownload={true}
1057
1043
  testId="canvas-worldmap-heatmap"
1058
1044
  />`,
1059
1045
  },
@@ -1089,6 +1075,7 @@ const multiChartDemo: ComponentDemo = {
1089
1075
  name: 'default',
1090
1076
  label: 'default',
1091
1077
  code: `<MultiChart
1078
+ showDownload={true}
1092
1079
  height={300}
1093
1080
  testId="canvas-multichart-default"
1094
1081
  />`,
@@ -5,6 +5,7 @@ import { GridLayout, useContainerWidth } from 'react-grid-layout';
5
5
  import type { LayoutItem } from 'react-grid-layout';
6
6
  import CanvasCell from '../canvas/CanvasCell';
7
7
  import type { CanvasItem } from '../canvas/types';
8
+ import { customRequest } from 'helpers/http';
8
9
  import 'react-grid-layout/css/styles.css';
9
10
  import 'react-resizable/css/styles.css';
10
11
 
@@ -27,16 +28,12 @@ export default function CanvasViewPage() {
27
28
  useEffect(() => {
28
29
  if (!slug) return;
29
30
  setLoading(true);
30
- fetch(`/api/canvas/by-page-code/${slug}`, { credentials: 'include' })
31
- .then((r) => {
32
- if (!r.ok) throw new Error(`${r.status}`);
33
- return r.json();
34
- })
31
+ customRequest<CanvasData>(`canvas/by-page-code/${slug}`, 'GET')
35
32
  .then((d) => {
36
33
  setData(d);
37
34
  setError(null);
38
35
  })
39
- .catch((e) => setError(e.message))
36
+ .catch((e) => setError(e?.message ?? String(e)))
40
37
  .finally(() => setLoading(false));
41
38
  }, [slug]);
42
39
 
@@ -16,12 +16,14 @@ interface DslViewProps {
16
16
  dsl: WorkflowDSL | null;
17
17
  readonly?: boolean;
18
18
  onApply?: (newDsl: WorkflowDSL) => void;
19
- onDirtyChange?: (dirty: boolean) => void;
20
19
  }
21
20
 
22
21
  export interface DslViewHandle {
23
- apply: () => void;
22
+ /** Validate textarea and apply to parent. Returns true on success (or no-op when text unchanged), false on validation failure. */
23
+ apply: () => boolean;
24
24
  copy: () => Promise<void>;
25
+ /** Whether textarea content differs from last applied DSL. */
26
+ isDirty: () => boolean;
25
27
  }
26
28
 
27
29
  function stringifyDsl(dsl: WorkflowDSL | null): string {
@@ -98,7 +100,7 @@ async function copyToClipboard(text: string): Promise<boolean> {
98
100
  }
99
101
 
100
102
  export const DslView = forwardRef<DslViewHandle, DslViewProps>(function DslView(
101
- { dsl, readonly = false, onApply, onDirtyChange },
103
+ { dsl, readonly = false, onApply },
102
104
  ref,
103
105
  ) {
104
106
  const initial = useMemo(() => stringifyDsl(dsl), [dsl]);
@@ -109,39 +111,36 @@ export const DslView = forwardRef<DslViewHandle, DslViewProps>(function DslView(
109
111
  useEffect(() => {
110
112
  setText(initial);
111
113
  setError(null);
112
- onDirtyChange?.(false);
113
- // onDirtyChange 故意不放进依赖数组:调用方传不稳定函数会导致死循环
114
- // eslint-disable-next-line react-hooks/exhaustive-deps
115
114
  }, [initial]);
116
115
 
117
116
  function handleTextChange(next: string) {
118
117
  setText(next);
119
118
  if (error) setError(null);
120
- if (!readonly) {
121
- const dirty = next !== initial;
122
- onDirtyChange?.(dirty);
123
- }
124
119
  }
125
120
 
126
- function handleApply() {
121
+ function handleApply(): boolean {
122
+ // 文本未变更:no-op success(无需重复应用,避免无意义重渲染)
123
+ if (text === initial) {
124
+ setError(null);
125
+ return true;
126
+ }
127
127
  let parsed: any;
128
128
  try {
129
129
  parsed = JSON.parse(text);
130
130
  } catch (e: any) {
131
131
  setError(`JSON 解析失败:${e?.message ?? String(e)}`);
132
- return;
132
+ return false;
133
133
  }
134
134
  const result = validateDsl(parsed);
135
135
  if (!result.ok) {
136
136
  setError(result.error);
137
- return;
137
+ return false;
138
138
  }
139
139
  const normalized = JSON.stringify(result.dsl, null, 2);
140
140
  setText(normalized);
141
141
  setError(null);
142
142
  onApply?.(result.dsl);
143
- onDirtyChange?.(false);
144
- message.success('已应用到画布');
143
+ return true;
145
144
  }
146
145
 
147
146
  async function handleCopy() {
@@ -158,9 +157,10 @@ export const DslView = forwardRef<DslViewHandle, DslViewProps>(function DslView(
158
157
  () => ({
159
158
  apply: handleApply,
160
159
  copy: handleCopy,
160
+ isDirty: () => text !== initial,
161
161
  }),
162
162
  // eslint-disable-next-line react-hooks/exhaustive-deps
163
- [text, onApply, onDirtyChange],
163
+ [text, initial, onApply],
164
164
  );
165
165
 
166
166
  return (
@@ -20,7 +20,6 @@ import {
20
20
  } from 'antd';
21
21
  import {
22
22
  ArrowLeftOutlined,
23
- CheckOutlined,
24
23
  EditOutlined,
25
24
  RobotOutlined,
26
25
  RocketOutlined,
@@ -63,7 +62,6 @@ export default function WorkflowEditorPage() {
63
62
 
64
63
  const [selectedNodeId, setSelectedNodeId] = useState<string | null>(null);
65
64
  const [viewMode, setViewMode] = useState<'canvas' | 'dsl'>('canvas');
66
- const [dslDirty, setDslDirty] = useState(false);
67
65
  const dslViewRef = useRef<DslViewHandle>(null);
68
66
 
69
67
  // Title editing state
@@ -340,7 +338,10 @@ export default function WorkflowEditorPage() {
340
338
  async function handleSelectVersion(version: number) {
341
339
  if (!id) return;
342
340
 
343
- if (hasUnsavedChanges || (viewMode === 'dsl' && dslDirty)) {
341
+ const dslDirty =
342
+ viewMode === 'dsl' && (dslViewRef.current?.isDirty() ?? false);
343
+
344
+ if (hasUnsavedChanges || dslDirty) {
344
345
  Modal.confirm({
345
346
  title: hasUnsavedChanges ? '未保存的修改' : 'DSL 有未应用的编辑',
346
347
  content: hasUnsavedChanges
@@ -378,21 +379,31 @@ export default function WorkflowEditorPage() {
378
379
  }
379
380
 
380
381
  function handleViewModeChange(next: 'canvas' | 'dsl') {
381
- if (next === 'canvas' && dslDirty) {
382
+ if (next === 'canvas' && viewMode === 'dsl') {
383
+ // 切回画布前自动应用 textarea 中的 DSL;校验失败则阻止切换
384
+ const success = dslViewRef.current?.apply() ?? true;
385
+ if (!success) {
386
+ // DslView 已显示内联 Alert,无需额外提示
387
+ return;
388
+ }
389
+ }
390
+ setViewMode(next);
391
+ }
392
+
393
+ function handleOpenAiModal() {
394
+ const hasExistingWorkflow = !!(dsl && dsl.nodes.length > 0);
395
+ if (hasExistingWorkflow) {
382
396
  Modal.confirm({
383
- title: '未应用的修改',
397
+ title: '覆盖现有工作流',
384
398
  content:
385
- 'DSL 视图中有未应用到画布的修改,切换到 Canvas 将丢弃这些修改。确定要继续吗?',
386
- okText: '确定切换',
399
+ '当前已有工作流内容,AI 自动生成将覆盖现有内容。确定要继续吗?',
400
+ okText: '确定继续',
387
401
  cancelText: '取消',
388
- onOk: () => {
389
- setDslDirty(false);
390
- setViewMode('canvas');
391
- },
402
+ onOk: () => setAiModalOpen(true),
392
403
  });
393
404
  return;
394
405
  }
395
- setViewMode(next);
406
+ setAiModalOpen(true);
396
407
  }
397
408
 
398
409
  function handleDslApply(newDsl: WorkflowDSL) {
@@ -478,11 +489,11 @@ export default function WorkflowEditorPage() {
478
489
  }))}
479
490
  />
480
491
  )}
481
- {isDev && viewMode === 'canvas' && (
492
+ {isDev && (
482
493
  <Button
483
494
  type="primary"
484
495
  icon={<RobotOutlined />}
485
- onClick={() => setAiModalOpen(true)}
496
+ onClick={handleOpenAiModal}
486
497
  >
487
498
  AI自动生成
488
499
  </Button>
@@ -500,36 +511,23 @@ export default function WorkflowEditorPage() {
500
511
  </div>
501
512
  </Card>
502
513
 
503
- {/* View toggle row + DSL actions */}
514
+ {/* View toggle row */}
504
515
  <div
505
516
  style={{
506
517
  marginBottom: 12,
507
518
  flexShrink: 0,
508
519
  display: 'flex',
509
520
  alignItems: 'center',
510
- justifyContent: 'space-between',
511
521
  }}
512
522
  >
513
523
  <Segmented
514
524
  value={viewMode}
515
525
  onChange={(v) => handleViewModeChange(v as 'canvas' | 'dsl')}
516
526
  options={[
517
- { label: 'Canvas', value: 'canvas' },
527
+ { label: '画布', value: 'canvas' },
518
528
  { label: 'DSL', value: 'dsl' },
519
529
  ]}
520
530
  />
521
- {viewMode === 'dsl' && (
522
- <Space>
523
- {dslDirty && <Tag color="orange">未应用</Tag>}
524
- <Button
525
- type="primary"
526
- icon={<CheckOutlined />}
527
- onClick={() => dslViewRef.current?.apply()}
528
- >
529
- 应用到画布
530
- </Button>
531
- </Space>
532
- )}
533
531
  </div>
534
532
 
535
533
  {/* Main area: Flow + Property Panel */}
@@ -560,12 +558,7 @@ export default function WorkflowEditorPage() {
560
558
  />
561
559
  </>
562
560
  ) : (
563
- <DslView
564
- ref={dslViewRef}
565
- dsl={dsl}
566
- onApply={handleDslApply}
567
- onDirtyChange={setDslDirty}
568
- />
561
+ <DslView ref={dslViewRef} dsl={dsl} onApply={handleDslApply} />
569
562
  )}
570
563
  </div>
571
564
 
@@ -9,6 +9,7 @@ import {
9
9
  Spin,
10
10
  Steps,
11
11
  Tag,
12
+ Tooltip,
12
13
  Typography,
13
14
  } from 'antd';
14
15
  import {
@@ -16,6 +17,7 @@ import {
16
17
  CheckCircleOutlined,
17
18
  ClockCircleOutlined,
18
19
  CloseCircleOutlined,
20
+ LinkOutlined,
19
21
  LoadingOutlined,
20
22
  ReloadOutlined,
21
23
  StopOutlined,
@@ -243,9 +245,35 @@ export default function WorkflowInstanceDetailPage() {
243
245
  </Tag>
244
246
  </Space>
245
247
  <Space>
246
- <Button icon={<ReloadOutlined />} onClick={fetchData}>
247
- Refresh
248
- </Button>
248
+ <Tooltip
249
+ title={
250
+ data.temporalRunId
251
+ ? '在 Temporal Web UI 中查看完整执行历史、Pending Activities 和 Worker 状态'
252
+ : '此实例无 Temporal Run ID(可能由 outbox-poller 创建或 Temporal 当时不可用)'
253
+ }
254
+ >
255
+ <Button
256
+ icon={<LinkOutlined />}
257
+ disabled={!data.temporalRunId}
258
+ onClick={() => {
259
+ if (!data.temporalRunId) return;
260
+ const base =
261
+ import.meta.env.VITE_TEMPORAL_UI_URL ||
262
+ 'http://localhost:8080';
263
+ const ns =
264
+ import.meta.env.VITE_TEMPORAL_NAMESPACE || 'default';
265
+ window.open(
266
+ `${base}/namespaces/${ns}/workflows/${encodeURIComponent(
267
+ data.temporalRunId,
268
+ )}`,
269
+ '_blank',
270
+ 'noopener,noreferrer',
271
+ );
272
+ }}
273
+ >
274
+ 在 Temporal 中查看
275
+ </Button>
276
+ </Tooltip>
249
277
  {(data.status === 'RUNNING' || data.status === 'PENDING') && (
250
278
  <Popconfirm
251
279
  title="Cancel this workflow execution?"
@@ -267,6 +295,9 @@ export default function WorkflowInstanceDetailPage() {
267
295
  Retry
268
296
  </Button>
269
297
  )}
298
+ <Button icon={<ReloadOutlined />} onClick={fetchData}>
299
+ Refresh
300
+ </Button>
270
301
  </Space>
271
302
  </div>
272
303
  </Card>
@@ -347,7 +347,7 @@ ${diffRightDsl}
347
347
  value={viewMode}
348
348
  onChange={(v) => setViewMode(v as 'canvas' | 'dsl')}
349
349
  options={[
350
- { label: 'Canvas', value: 'canvas' },
350
+ { label: '画布', value: 'canvas' },
351
351
  { label: 'DSL', value: 'dsl' },
352
352
  ]}
353
353
  />
@@ -40,7 +40,7 @@ export interface Workflow {
40
40
  creator: string;
41
41
  createdAt: string;
42
42
  updatedAt: string;
43
- versions?: { version: number }[];
43
+ versions?: { version: number; changeSummary?: string | null }[];
44
44
  _count?: { instances: number };
45
45
  runs?: {
46
46
  pending: number;
@@ -22,6 +22,12 @@
22
22
  border-top: 1px solid #d9d9d9;
23
23
  margin-top: 0px;
24
24
  }
25
+
26
+ /* Modal.confirm/warning/info/error 不走 header/body/footer 结构,
27
+ 需单独补回 padding,否则内容会顶到边 */
28
+ &.ant-modal-confirm .ant-modal-content {
29
+ padding: 32px 32px 24px;
30
+ }
25
31
  }
26
32
 
27
33
  .kanban-update-modal {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gadmin2n/schematics",
3
- "version": "0.0.87",
3
+ "version": "0.0.89",
4
4
  "description": "Gadmin - modern, fast, powerful node.js web framework (@schematics)",
5
5
  "main": "dist/index.js",
6
6
  "files": [