@antelopejs/dms-automation 0.0.1

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 (305) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +95 -0
  3. package/dist/cluster/bus.d.ts +17 -0
  4. package/dist/cluster/bus.js +82 -0
  5. package/dist/cluster/bus.js.map +1 -0
  6. package/dist/cluster/instance.d.ts +1 -0
  7. package/dist/cluster/instance.js +6 -0
  8. package/dist/cluster/instance.js.map +1 -0
  9. package/dist/cluster/leader.d.ts +7 -0
  10. package/dist/cluster/leader.js +123 -0
  11. package/dist/cluster/leader.js.map +1 -0
  12. package/dist/cluster/mode.d.ts +3 -0
  13. package/dist/cluster/mode.js +25 -0
  14. package/dist/cluster/mode.js.map +1 -0
  15. package/dist/data/procedures-table.d.ts +66 -0
  16. package/dist/data/procedures-table.js +271 -0
  17. package/dist/data/procedures-table.js.map +1 -0
  18. package/dist/data/runs-table.d.ts +23 -0
  19. package/dist/data/runs-table.js +125 -0
  20. package/dist/data/runs-table.js.map +1 -0
  21. package/dist/db/index.d.ts +7 -0
  22. package/dist/db/index.js +24 -0
  23. package/dist/db/index.js.map +1 -0
  24. package/dist/db/models/automation_template.model.d.ts +58 -0
  25. package/dist/db/models/automation_template.model.js +134 -0
  26. package/dist/db/models/automation_template.model.js.map +1 -0
  27. package/dist/db/models/index.d.ts +3 -0
  28. package/dist/db/models/index.js +20 -0
  29. package/dist/db/models/index.js.map +1 -0
  30. package/dist/db/models/procedure.model.d.ts +25 -0
  31. package/dist/db/models/procedure.model.js +28 -0
  32. package/dist/db/models/procedure.model.js.map +1 -0
  33. package/dist/db/models/procedure_run.model.d.ts +34 -0
  34. package/dist/db/models/procedure_run.model.js +39 -0
  35. package/dist/db/models/procedure_run.model.js.map +1 -0
  36. package/dist/db/models/stats.model.d.ts +73 -0
  37. package/dist/db/models/stats.model.js +267 -0
  38. package/dist/db/models/stats.model.js.map +1 -0
  39. package/dist/db/models/type_config.model.d.ts +47 -0
  40. package/dist/db/models/type_config.model.js +51 -0
  41. package/dist/db/models/type_config.model.js.map +1 -0
  42. package/dist/db/tables/action_type_config.table.d.ts +7 -0
  43. package/dist/db/tables/action_type_config.table.js +35 -0
  44. package/dist/db/tables/action_type_config.table.js.map +1 -0
  45. package/dist/db/tables/automation_template.table.d.ts +11 -0
  46. package/dist/db/tables/automation_template.table.js +52 -0
  47. package/dist/db/tables/automation_template.table.js.map +1 -0
  48. package/dist/db/tables/index.d.ts +5 -0
  49. package/dist/db/tables/index.js +22 -0
  50. package/dist/db/tables/index.js.map +1 -0
  51. package/dist/db/tables/procedure.table.d.ts +10 -0
  52. package/dist/db/tables/procedure.table.js +48 -0
  53. package/dist/db/tables/procedure.table.js.map +1 -0
  54. package/dist/db/tables/procedure_run.table.d.ts +13 -0
  55. package/dist/db/tables/procedure_run.table.js +57 -0
  56. package/dist/db/tables/procedure_run.table.js.map +1 -0
  57. package/dist/db/tables/trigger_type_config.table.d.ts +7 -0
  58. package/dist/db/tables/trigger_type_config.table.js +35 -0
  59. package/dist/db/tables/trigger_type_config.table.js.map +1 -0
  60. package/dist/implementations/dms-automation/index.d.ts +19 -0
  61. package/dist/implementations/dms-automation/index.js +50 -0
  62. package/dist/implementations/dms-automation/index.js.map +1 -0
  63. package/dist/index.d.ts +14 -0
  64. package/dist/index.js +121 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/pages/builder.d.ts +10 -0
  67. package/dist/pages/builder.js +28 -0
  68. package/dist/pages/builder.js.map +1 -0
  69. package/dist/pages/category.d.ts +1 -0
  70. package/dist/pages/category.js +10 -0
  71. package/dist/pages/category.js.map +1 -0
  72. package/dist/pages/index.d.ts +6 -0
  73. package/dist/pages/index.js +9 -0
  74. package/dist/pages/index.js.map +1 -0
  75. package/dist/pages/library.d.ts +10 -0
  76. package/dist/pages/library.js +28 -0
  77. package/dist/pages/library.js.map +1 -0
  78. package/dist/pages/overview.d.ts +10 -0
  79. package/dist/pages/overview.js +28 -0
  80. package/dist/pages/overview.js.map +1 -0
  81. package/dist/pages/procedures.d.ts +10 -0
  82. package/dist/pages/procedures.js +72 -0
  83. package/dist/pages/procedures.js.map +1 -0
  84. package/dist/pages/runs.d.ts +11 -0
  85. package/dist/pages/runs.js +61 -0
  86. package/dist/pages/runs.js.map +1 -0
  87. package/dist/routes/action-types.d.ts +23 -0
  88. package/dist/routes/action-types.js +80 -0
  89. package/dist/routes/action-types.js.map +1 -0
  90. package/dist/routes/data-node-types.d.ts +6 -0
  91. package/dist/routes/data-node-types.js +36 -0
  92. package/dist/routes/data-node-types.js.map +1 -0
  93. package/dist/routes/graphSchema.d.ts +92 -0
  94. package/dist/routes/graphSchema.js +60 -0
  95. package/dist/routes/graphSchema.js.map +1 -0
  96. package/dist/routes/index.d.ts +8 -0
  97. package/dist/routes/index.js +11 -0
  98. package/dist/routes/index.js.map +1 -0
  99. package/dist/routes/node-kinds.d.ts +9 -0
  100. package/dist/routes/node-kinds.js +35 -0
  101. package/dist/routes/node-kinds.js.map +1 -0
  102. package/dist/routes/procedures.d.ts +23 -0
  103. package/dist/routes/procedures.js +181 -0
  104. package/dist/routes/procedures.js.map +1 -0
  105. package/dist/routes/runs.d.ts +7 -0
  106. package/dist/routes/runs.js +81 -0
  107. package/dist/routes/runs.js.map +1 -0
  108. package/dist/routes/stats.d.ts +6 -0
  109. package/dist/routes/stats.js +35 -0
  110. package/dist/routes/stats.js.map +1 -0
  111. package/dist/routes/templates.d.ts +20 -0
  112. package/dist/routes/templates.js +243 -0
  113. package/dist/routes/templates.js.map +1 -0
  114. package/dist/routes/trigger-types.d.ts +24 -0
  115. package/dist/routes/trigger-types.js +80 -0
  116. package/dist/routes/trigger-types.js.map +1 -0
  117. package/dist/routes/typeConfigShared.d.ts +22 -0
  118. package/dist/routes/typeConfigShared.js +37 -0
  119. package/dist/routes/typeConfigShared.js.map +1 -0
  120. package/dist/runtime/builtins/actions/http.d.ts +13 -0
  121. package/dist/runtime/builtins/actions/http.js +47 -0
  122. package/dist/runtime/builtins/actions/http.js.map +1 -0
  123. package/dist/runtime/builtins/actions/index.d.ts +2 -0
  124. package/dist/runtime/builtins/actions/index.js +7 -0
  125. package/dist/runtime/builtins/actions/index.js.map +1 -0
  126. package/dist/runtime/builtins/actions/log.d.ts +13 -0
  127. package/dist/runtime/builtins/actions/log.js +49 -0
  128. package/dist/runtime/builtins/actions/log.js.map +1 -0
  129. package/dist/runtime/builtins/data/boolean.d.ts +2 -0
  130. package/dist/runtime/builtins/data/boolean.js +39 -0
  131. package/dist/runtime/builtins/data/boolean.js.map +1 -0
  132. package/dist/runtime/builtins/data/compare.d.ts +2 -0
  133. package/dist/runtime/builtins/data/compare.js +29 -0
  134. package/dist/runtime/builtins/data/compare.js.map +1 -0
  135. package/dist/runtime/builtins/data/constant.d.ts +2 -0
  136. package/dist/runtime/builtins/data/constant.js +29 -0
  137. package/dist/runtime/builtins/data/constant.js.map +1 -0
  138. package/dist/runtime/builtins/data/index.d.ts +2 -0
  139. package/dist/runtime/builtins/data/index.js +20 -0
  140. package/dist/runtime/builtins/data/index.js.map +1 -0
  141. package/dist/runtime/builtins/data/json.d.ts +2 -0
  142. package/dist/runtime/builtins/data/json.js +46 -0
  143. package/dist/runtime/builtins/data/json.js.map +1 -0
  144. package/dist/runtime/builtins/data/math.d.ts +2 -0
  145. package/dist/runtime/builtins/data/math.js +53 -0
  146. package/dist/runtime/builtins/data/math.js.map +1 -0
  147. package/dist/runtime/builtins/data/object.d.ts +2 -0
  148. package/dist/runtime/builtins/data/object.js +121 -0
  149. package/dist/runtime/builtins/data/object.js.map +1 -0
  150. package/dist/runtime/builtins/data/string.d.ts +2 -0
  151. package/dist/runtime/builtins/data/string.js +143 -0
  152. package/dist/runtime/builtins/data/string.js.map +1 -0
  153. package/dist/runtime/builtins/index.d.ts +17 -0
  154. package/dist/runtime/builtins/index.js +24 -0
  155. package/dist/runtime/builtins/index.js.map +1 -0
  156. package/dist/runtime/builtins/nodes/action.d.ts +1 -0
  157. package/dist/runtime/builtins/nodes/action.js +36 -0
  158. package/dist/runtime/builtins/nodes/action.js.map +1 -0
  159. package/dist/runtime/builtins/nodes/data.d.ts +1 -0
  160. package/dist/runtime/builtins/nodes/data.js +28 -0
  161. package/dist/runtime/builtins/nodes/data.js.map +1 -0
  162. package/dist/runtime/builtins/nodes/delay.d.ts +1 -0
  163. package/dist/runtime/builtins/nodes/delay.js +41 -0
  164. package/dist/runtime/builtins/nodes/delay.js.map +1 -0
  165. package/dist/runtime/builtins/nodes/forRange.d.ts +1 -0
  166. package/dist/runtime/builtins/nodes/forRange.js +52 -0
  167. package/dist/runtime/builtins/nodes/forRange.js.map +1 -0
  168. package/dist/runtime/builtins/nodes/foreach.d.ts +1 -0
  169. package/dist/runtime/builtins/nodes/foreach.js +31 -0
  170. package/dist/runtime/builtins/nodes/foreach.js.map +1 -0
  171. package/dist/runtime/builtins/nodes/groupInput.d.ts +1 -0
  172. package/dist/runtime/builtins/nodes/groupInput.js +11 -0
  173. package/dist/runtime/builtins/nodes/groupInput.js.map +1 -0
  174. package/dist/runtime/builtins/nodes/groupOutput.d.ts +1 -0
  175. package/dist/runtime/builtins/nodes/groupOutput.js +11 -0
  176. package/dist/runtime/builtins/nodes/groupOutput.js.map +1 -0
  177. package/dist/runtime/builtins/nodes/if.d.ts +1 -0
  178. package/dist/runtime/builtins/nodes/if.js +23 -0
  179. package/dist/runtime/builtins/nodes/if.js.map +1 -0
  180. package/dist/runtime/builtins/nodes/parallel.d.ts +1 -0
  181. package/dist/runtime/builtins/nodes/parallel.js +34 -0
  182. package/dist/runtime/builtins/nodes/parallel.js.map +1 -0
  183. package/dist/runtime/builtins/nodes/retry.d.ts +1 -0
  184. package/dist/runtime/builtins/nodes/retry.js +46 -0
  185. package/dist/runtime/builtins/nodes/retry.js.map +1 -0
  186. package/dist/runtime/builtins/nodes/setVariable.d.ts +1 -0
  187. package/dist/runtime/builtins/nodes/setVariable.js +31 -0
  188. package/dist/runtime/builtins/nodes/setVariable.js.map +1 -0
  189. package/dist/runtime/builtins/nodes/switch.d.ts +1 -0
  190. package/dist/runtime/builtins/nodes/switch.js +33 -0
  191. package/dist/runtime/builtins/nodes/switch.js.map +1 -0
  192. package/dist/runtime/builtins/nodes/trigger.d.ts +1 -0
  193. package/dist/runtime/builtins/nodes/trigger.js +25 -0
  194. package/dist/runtime/builtins/nodes/trigger.js.map +1 -0
  195. package/dist/runtime/builtins/nodes/tryCatch.d.ts +1 -0
  196. package/dist/runtime/builtins/nodes/tryCatch.js +35 -0
  197. package/dist/runtime/builtins/nodes/tryCatch.js.map +1 -0
  198. package/dist/runtime/builtins/triggers/cron.d.ts +9 -0
  199. package/dist/runtime/builtins/triggers/cron.js +52 -0
  200. package/dist/runtime/builtins/triggers/cron.js.map +1 -0
  201. package/dist/runtime/builtins/triggers/index.d.ts +2 -0
  202. package/dist/runtime/builtins/triggers/index.js +12 -0
  203. package/dist/runtime/builtins/triggers/index.js.map +1 -0
  204. package/dist/runtime/builtins/triggers/manual.d.ts +3 -0
  205. package/dist/runtime/builtins/triggers/manual.js +20 -0
  206. package/dist/runtime/builtins/triggers/manual.js.map +1 -0
  207. package/dist/runtime/builtins/triggers/webhook.d.ts +14 -0
  208. package/dist/runtime/builtins/triggers/webhook.js +90 -0
  209. package/dist/runtime/builtins/triggers/webhook.js.map +1 -0
  210. package/dist/runtime/executionResult.d.ts +6 -0
  211. package/dist/runtime/executionResult.js +3 -0
  212. package/dist/runtime/executionResult.js.map +1 -0
  213. package/dist/runtime/executor.d.ts +9 -0
  214. package/dist/runtime/executor.js +300 -0
  215. package/dist/runtime/executor.js.map +1 -0
  216. package/dist/runtime/flatten.d.ts +3 -0
  217. package/dist/runtime/flatten.js +188 -0
  218. package/dist/runtime/flatten.js.map +1 -0
  219. package/dist/runtime/nodeKinds.d.ts +64 -0
  220. package/dist/runtime/nodeKinds.js +43 -0
  221. package/dist/runtime/nodeKinds.js.map +1 -0
  222. package/dist/runtime/reconcileDiff.d.ts +9 -0
  223. package/dist/runtime/reconcileDiff.js +26 -0
  224. package/dist/runtime/reconcileDiff.js.map +1 -0
  225. package/dist/runtime/registry.d.ts +19 -0
  226. package/dist/runtime/registry.js +47 -0
  227. package/dist/runtime/registry.js.map +1 -0
  228. package/dist/runtime/resolveInputs.d.ts +14 -0
  229. package/dist/runtime/resolveInputs.js +64 -0
  230. package/dist/runtime/resolveInputs.js.map +1 -0
  231. package/dist/runtime/resolveSubgraph.d.ts +7 -0
  232. package/dist/runtime/resolveSubgraph.js +15 -0
  233. package/dist/runtime/resolveSubgraph.js.map +1 -0
  234. package/dist/runtime/subscriptions.d.ts +16 -0
  235. package/dist/runtime/subscriptions.js +419 -0
  236. package/dist/runtime/subscriptions.js.map +1 -0
  237. package/dist/runtime/subwalk.d.ts +17 -0
  238. package/dist/runtime/subwalk.js +74 -0
  239. package/dist/runtime/subwalk.js.map +1 -0
  240. package/dist/runtime/topo.d.ts +3 -0
  241. package/dist/runtime/topo.js +75 -0
  242. package/dist/runtime/topo.js.map +1 -0
  243. package/dist/runtime/typeOrigin.d.ts +7 -0
  244. package/dist/runtime/typeOrigin.js +24 -0
  245. package/dist/runtime/typeOrigin.js.map +1 -0
  246. package/dist/runtime/validate.d.ts +10 -0
  247. package/dist/runtime/validate.js +185 -0
  248. package/dist/runtime/validate.js.map +1 -0
  249. package/dist/runtime/validateTemplate.d.ts +3 -0
  250. package/dist/runtime/validateTemplate.js +54 -0
  251. package/dist/runtime/validateTemplate.js.map +1 -0
  252. package/dist/types/constants.d.ts +6 -0
  253. package/dist/types/constants.js +10 -0
  254. package/dist/types/constants.js.map +1 -0
  255. package/dist/types/graph.d.ts +51 -0
  256. package/dist/types/graph.js +23 -0
  257. package/dist/types/graph.js.map +1 -0
  258. package/dist/types/pagination.d.ts +8 -0
  259. package/dist/types/pagination.js +3 -0
  260. package/dist/types/pagination.js.map +1 -0
  261. package/dist/types/runLog.d.ts +26 -0
  262. package/dist/types/runLog.js +3 -0
  263. package/dist/types/runLog.js.map +1 -0
  264. package/frontend-vue/.prettierignore +4 -0
  265. package/frontend-vue/app/components/Actions.vue +141 -0
  266. package/frontend-vue/app/components/Catalog/TypeConfigForm.vue +166 -0
  267. package/frontend-vue/app/components/Catalog/TypeList.vue +198 -0
  268. package/frontend-vue/app/components/DataNodes.vue +259 -0
  269. package/frontend-vue/app/components/Editor/BuilderPalette.vue +234 -0
  270. package/frontend-vue/app/components/Editor/GraphCanvas.vue +994 -0
  271. package/frontend-vue/app/components/Editor/GroupPortEditor.vue +289 -0
  272. package/frontend-vue/app/components/Editor/JsonField.vue +63 -0
  273. package/frontend-vue/app/components/Editor/NodeInspector.vue +356 -0
  274. package/frontend-vue/app/components/Editor/ProcedureList.vue +156 -0
  275. package/frontend-vue/app/components/Editor/RunsDrawer.vue +312 -0
  276. package/frontend-vue/app/components/Editor/WiredField.vue +42 -0
  277. package/frontend-vue/app/components/Editor/nodes/GenericNode.vue +161 -0
  278. package/frontend-vue/app/components/Editor/nodes/GroupInputNode.vue +19 -0
  279. package/frontend-vue/app/components/Editor/nodes/GroupNode.vue +200 -0
  280. package/frontend-vue/app/components/Editor/nodes/GroupOutputNode.vue +19 -0
  281. package/frontend-vue/app/components/Editor/nodes/GroupSentinel.vue +161 -0
  282. package/frontend-vue/app/components/Editor/nodes/styles.ts +53 -0
  283. package/frontend-vue/app/components/Editor.vue +2504 -0
  284. package/frontend-vue/app/components/Library.vue +67 -0
  285. package/frontend-vue/app/components/Overview.vue +503 -0
  286. package/frontend-vue/app/components/RunDetailDrawer.vue +165 -0
  287. package/frontend-vue/app/components/RunFireTree.vue +170 -0
  288. package/frontend-vue/app/components/RunTraceDrawer.vue +59 -0
  289. package/frontend-vue/app/components/RunsStats.vue +126 -0
  290. package/frontend-vue/app/components/RunsTimelineDisplay.vue +287 -0
  291. package/frontend-vue/app/components/Templates.vue +663 -0
  292. package/frontend-vue/app/components/Triggers.vue +137 -0
  293. package/frontend-vue/app/composables/useAutomationNodeKinds.ts +48 -0
  294. package/frontend-vue/app/composables/useAutomationRuns.ts +75 -0
  295. package/frontend-vue/app/composables/useGraphConnect.ts +542 -0
  296. package/frontend-vue/app/plugins/runs-timeline-display.client.ts +16 -0
  297. package/frontend-vue/app/utils/automation.ts +51 -0
  298. package/frontend-vue/dms.frontend.ts +26 -0
  299. package/frontend-vue/eslint.config.mjs +24 -0
  300. package/frontend-vue/i18n/locales/dms-automation-en-GB.json +369 -0
  301. package/frontend-vue/i18n/locales/dms-automation-fr-FR.json +369 -0
  302. package/frontend-vue/package.json +33 -0
  303. package/frontend-vue/pnpm-lock.yaml +6483 -0
  304. package/frontend-vue/pnpm-workspace.yaml +2 -0
  305. package/package.json +81 -0
@@ -0,0 +1,200 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import { Handle, Position } from '@vue-flow/core'
4
+ import type { GroupPort } from '../../../composables/useGraphConnect'
5
+
6
+ interface NodeData {
7
+ label?: string
8
+ icon?: string
9
+ typeId?: string
10
+ templateId?: string
11
+ templateName?: string
12
+ ports?: GroupPort[]
13
+ config?: { name?: string; [k: string]: unknown }
14
+ subgraph?: unknown
15
+ }
16
+
17
+ const props = defineProps<{
18
+ id: string
19
+ data: NodeData
20
+ selected?: boolean
21
+ }>()
22
+
23
+ const ports = computed<GroupPort[]>(() =>
24
+ Array.isArray(props.data?.ports) ? props.data.ports : [],
25
+ )
26
+
27
+ const triggerInPorts = computed(() =>
28
+ ports.value.filter((p) => p.kind === 'trigger' && p.direction === 'in'),
29
+ )
30
+ const triggerOutPorts = computed(() =>
31
+ ports.value.filter((p) => p.kind === 'trigger' && p.direction === 'out'),
32
+ )
33
+ const dataInPorts = computed(() =>
34
+ ports.value.filter((p) => p.kind === 'data' && p.direction === 'in'),
35
+ )
36
+ const dataOutPorts = computed(() =>
37
+ ports.value.filter((p) => p.kind === 'data' && p.direction === 'out'),
38
+ )
39
+
40
+ const isTemplateInstance = computed(() => Boolean(props.data?.templateId))
41
+
42
+ const title = computed(
43
+ () => props.data?.config?.name ?? props.data?.label ?? 'Group',
44
+ )
45
+
46
+ const headerIcon = computed(() =>
47
+ isTemplateInstance.value ? 'i-ph-link' : 'i-ph-package',
48
+ )
49
+
50
+ import { dataHandleStyle, triggerStyle } from './styles'
51
+
52
+ // Mirror the convention used by GenericNode: the trigger port named "main"
53
+ // lives on the title bar (left for trigger-in, right for trigger-out). Any
54
+ // other trigger ports spill into the body rows below, interleaved with the
55
+ // data port rows. If no port is named "main", the title bar has no trigger
56
+ // handle on that side — the user picks which port is the "main" one by
57
+ // naming it.
58
+ const mainTriggerIn = computed(
59
+ () => triggerInPorts.value.find((p) => p.name === 'main') ?? null,
60
+ )
61
+ const mainTriggerOut = computed(
62
+ () => triggerOutPorts.value.find((p) => p.name === 'main') ?? null,
63
+ )
64
+ const extraTriggerIn = computed(() =>
65
+ triggerInPorts.value.filter((p) => p.name !== 'main'),
66
+ )
67
+ const extraTriggerOut = computed(() =>
68
+ triggerOutPorts.value.filter((p) => p.name !== 'main'),
69
+ )
70
+
71
+ // Body rows: left column shows trigger-in extras followed by data-in ports;
72
+ // right column shows trigger-out extras followed by data-out ports. Each row
73
+ // gets one entry per side (may be null if that side has fewer entries).
74
+ interface LeftRow {
75
+ kind: 'trigger' | 'data'
76
+ port: GroupPort
77
+ }
78
+ interface RightRow {
79
+ kind: 'trigger' | 'data'
80
+ port: GroupPort
81
+ }
82
+ const leftRows = computed<LeftRow[]>(() => [
83
+ ...extraTriggerIn.value.map((p) => ({ kind: 'trigger' as const, port: p })),
84
+ ...dataInPorts.value.map((p) => ({ kind: 'data' as const, port: p })),
85
+ ])
86
+ const rightRows = computed<RightRow[]>(() => [
87
+ ...extraTriggerOut.value.map((p) => ({ kind: 'trigger' as const, port: p })),
88
+ ...dataOutPorts.value.map((p) => ({ kind: 'data' as const, port: p })),
89
+ ])
90
+ const bodyRowCount = computed(() =>
91
+ Math.max(leftRows.value.length, rightRows.value.length),
92
+ )
93
+ const hasAnyPorts = computed(
94
+ () =>
95
+ mainTriggerIn.value !== null ||
96
+ mainTriggerOut.value !== null ||
97
+ bodyRowCount.value > 0,
98
+ )
99
+ </script>
100
+
101
+ <template>
102
+ <div
103
+ class="dms-automation-node group-node relative min-w-[220px] rounded-lg border bg-default shadow-sm"
104
+ :class="
105
+ selected
106
+ ? 'border-primary ring-1 ring-primary'
107
+ : 'border-default'
108
+ "
109
+ >
110
+ <!-- Header — main trigger-in (left) / main trigger-out (right), mirroring
111
+ the GenericNode convention. -->
112
+ <div
113
+ class="relative flex items-center gap-2 rounded-t-lg border-b border-default bg-elevated px-3 py-2"
114
+ >
115
+ <Handle
116
+ v-if="mainTriggerIn"
117
+ :id="`group-trigger-in-${mainTriggerIn.name}`"
118
+ type="target"
119
+ :position="Position.Left"
120
+ :style="triggerStyle"
121
+ />
122
+ <div class="relative">
123
+ <UIcon :name="headerIcon" class="size-4 text-primary" />
124
+ </div>
125
+ <div class="truncate text-sm font-medium text-highlighted">
126
+ {{ title }}
127
+ </div>
128
+ <span
129
+ v-if="isTemplateInstance"
130
+ class="ml-auto inline-flex items-center gap-1 rounded-sm bg-primary/10 px-1.5 py-0.5 text-[10px] uppercase tracking-wide text-primary"
131
+ :title="`Linked to template ${data.templateId}`"
132
+ >
133
+ <UIcon name="i-ph-link" class="w-3 h-3" />
134
+ linked
135
+ </span>
136
+ <Handle
137
+ v-if="mainTriggerOut"
138
+ :id="`group-trigger-out-${mainTriggerOut.name}`"
139
+ type="source"
140
+ :position="Position.Right"
141
+ :style="triggerStyle"
142
+ />
143
+ </div>
144
+
145
+ <!-- Body rows: trigger-in extras + data-in on the left, trigger-out
146
+ extras + data-out on the right. -->
147
+ <div v-if="bodyRowCount > 0" class="py-2 text-xs text-dimmed">
148
+ <div
149
+ v-for="i in bodyRowCount"
150
+ :key="`row-${i - 1}`"
151
+ class="relative flex items-stretch py-1"
152
+ >
153
+ <div class="flex-1 flex items-center gap-1 pl-3">
154
+ <template v-if="leftRows[i - 1]">
155
+ <Handle
156
+ v-if="leftRows[i - 1]!.kind === 'trigger'"
157
+ :id="`group-trigger-in-${leftRows[i - 1]!.port.name}`"
158
+ type="target"
159
+ :position="Position.Left"
160
+ :style="triggerStyle"
161
+ />
162
+ <Handle
163
+ v-else
164
+ :id="`group-data-in-${leftRows[i - 1]!.port.name}`"
165
+ type="target"
166
+ :position="Position.Left"
167
+ :style="dataHandleStyle(leftRows[i - 1]!.port)"
168
+ />
169
+ <span>{{ leftRows[i - 1]!.port.name }}</span>
170
+ </template>
171
+ </div>
172
+ <div class="flex-1 flex items-center justify-end gap-1 pr-3">
173
+ <template v-if="rightRows[i - 1]">
174
+ <span>{{ rightRows[i - 1]!.port.name }}</span>
175
+ <Handle
176
+ v-if="rightRows[i - 1]!.kind === 'trigger'"
177
+ :id="`group-trigger-out-${rightRows[i - 1]!.port.name}`"
178
+ type="source"
179
+ :position="Position.Right"
180
+ :style="triggerStyle"
181
+ />
182
+ <Handle
183
+ v-else
184
+ :id="`group-data-out-${rightRows[i - 1]!.port.name}`"
185
+ type="source"
186
+ :position="Position.Right"
187
+ :style="dataHandleStyle(rightRows[i - 1]!.port)"
188
+ />
189
+ </template>
190
+ </div>
191
+ </div>
192
+ </div>
193
+ <div
194
+ v-else-if="!hasAnyPorts"
195
+ class="py-2 px-3 text-xs text-dimmed italic"
196
+ >
197
+ no ports
198
+ </div>
199
+ </div>
200
+ </template>
@@ -0,0 +1,19 @@
1
+ <script setup lang="ts">
2
+ import type { GroupPort } from '../../../composables/useGraphConnect'
3
+ import GroupSentinel from './GroupSentinel.vue'
4
+
5
+ const props = defineProps<{
6
+ id: string
7
+ data: { ports?: GroupPort[] }
8
+ selected?: boolean
9
+ }>()
10
+ </script>
11
+
12
+ <template>
13
+ <GroupSentinel
14
+ :id="props.id"
15
+ side="out"
16
+ :data="props.data"
17
+ :selected="props.selected"
18
+ />
19
+ </template>
@@ -0,0 +1,161 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+ import { Handle, Position } from '@vue-flow/core'
4
+ import type { GroupPort } from '../../../composables/useGraphConnect'
5
+ import { dataHandleStyle, triggerStyle } from './styles'
6
+
7
+ // Shared body for both group sentinels (groupInput / groupOutput). The two
8
+ // are mirror images: `groupInput` exposes the parent group's IN ports as
9
+ // SOURCE handles on the right edge; `groupOutput` exposes its OUT ports as
10
+ // TARGET handles on the left edge. Naming, icon, label, alignment, and
11
+ // empty-state copy all flip on `side`.
12
+ //
13
+ // Sentinel naming:
14
+ // groupInput-trigger-out-<port> / groupInput-data-out-<port>
15
+ // groupOutput-trigger-in-<port> / groupOutput-data-in-<port>
16
+ //
17
+ // Sentinels are not user-deletable — enforcement lives in GraphCanvas.vue's
18
+ // onNodesChange handler.
19
+
20
+ interface NodeData {
21
+ ports?: GroupPort[]
22
+ }
23
+
24
+ const props = defineProps<{
25
+ id: string
26
+ data: NodeData
27
+ selected?: boolean
28
+ side: 'in' | 'out'
29
+ }>()
30
+
31
+ const isInput = computed(() => props.side === 'in')
32
+ const handleDirection = computed(() => (isInput.value ? 'source' : 'target'))
33
+ const handlePosition = computed(() =>
34
+ isInput.value ? Position.Right : Position.Left,
35
+ )
36
+ const handlePrefix = computed(() => (isInput.value ? 'groupInput' : 'groupOutput'))
37
+ const handleVerb = computed(() => (isInput.value ? 'out' : 'in'))
38
+ const headerIcon = computed(() => (isInput.value ? 'i-ph-sign-in' : 'i-ph-sign-out'))
39
+ const headerLabel = computed(() =>
40
+ isInput.value ? 'Group Input' : 'Group Output',
41
+ )
42
+ const emptyText = computed(() =>
43
+ isInput.value ? 'no input ports' : 'no output ports',
44
+ )
45
+ const rowKeyPrefix = computed(() => (isInput.value ? 'gi-row' : 'go-row'))
46
+
47
+ const ports = computed<GroupPort[]>(() =>
48
+ Array.isArray(props.data?.ports) ? props.data.ports : [],
49
+ )
50
+
51
+ // `groupInput` surfaces the parent's IN ports (they look like sources to
52
+ // the inner subgraph); `groupOutput` surfaces the parent's OUT ports
53
+ // (sinks to the inner subgraph).
54
+ const dataPorts = computed(() =>
55
+ ports.value.filter((p) => p.kind === 'data' && p.direction === props.side),
56
+ )
57
+ const triggerPorts = computed(() =>
58
+ ports.value.filter((p) => p.kind === 'trigger' && p.direction === props.side),
59
+ )
60
+
61
+ const mainTrigger = computed(
62
+ () => triggerPorts.value.find((p) => p.name === 'main') ?? null,
63
+ )
64
+ const extraTrigger = computed(() =>
65
+ triggerPorts.value.filter((p) => p.name !== 'main'),
66
+ )
67
+
68
+ interface BodyRow {
69
+ kind: 'trigger' | 'data'
70
+ port: GroupPort
71
+ }
72
+ const bodyRows = computed<BodyRow[]>(() => [
73
+ ...extraTrigger.value.map((p) => ({ kind: 'trigger' as const, port: p })),
74
+ ...dataPorts.value.map((p) => ({ kind: 'data' as const, port: p })),
75
+ ])
76
+
77
+ function handleId(row: BodyRow): string {
78
+ const subject = row.kind === 'trigger' ? 'trigger' : 'data'
79
+ return `${handlePrefix.value}-${subject}-${handleVerb.value}-${row.port.name}`
80
+ }
81
+ </script>
82
+
83
+ <template>
84
+ <div
85
+ class="dms-automation-node group-sentinel relative min-w-[180px] rounded-lg border border-dashed bg-elevated/40 opacity-90"
86
+ :class="[
87
+ isInput ? 'group-input-sentinel' : 'group-output-sentinel',
88
+ selected
89
+ ? 'border-primary ring-1 ring-primary'
90
+ : 'border-default',
91
+ ]"
92
+ >
93
+ <!-- Header: main trigger handle on the appropriate edge mirrors
94
+ GroupNode title-bar layout. -->
95
+ <div
96
+ class="relative flex items-center gap-2 px-3 py-1.5 border-b border-dashed border-default rounded-t-md"
97
+ >
98
+ <Handle
99
+ v-if="!isInput && mainTrigger"
100
+ :id="`${handlePrefix}-trigger-${handleVerb}-${mainTrigger.name}`"
101
+ :type="handleDirection"
102
+ :position="handlePosition"
103
+ :style="triggerStyle"
104
+ />
105
+ <UIcon :name="headerIcon" class="text-dimmed" />
106
+ <div class="text-dimmed text-xs font-medium uppercase tracking-wide">
107
+ {{ headerLabel }}
108
+ </div>
109
+ <Handle
110
+ v-if="isInput && mainTrigger"
111
+ :id="`${handlePrefix}-trigger-${handleVerb}-${mainTrigger.name}`"
112
+ :type="handleDirection"
113
+ :position="handlePosition"
114
+ :style="triggerStyle"
115
+ />
116
+ </div>
117
+
118
+ <!-- Body: trigger extras + data ports, one per row. Layout mirrors
119
+ GroupNode.vue: row is `relative` so each Handle (absolute)
120
+ anchors to its row's vertical center; an inner flex-1 column
121
+ reserves a track for the label so the absolute handle doesn't
122
+ crowd it on narrow nodes. -->
123
+ <div v-if="bodyRows.length > 0" class="py-2 text-xs text-dimmed">
124
+ <div
125
+ v-for="(row, idx) in bodyRows"
126
+ :key="`${rowKeyPrefix}-${row.kind}-${idx}`"
127
+ class="relative flex items-stretch py-1"
128
+ >
129
+ <div
130
+ class="flex-1 flex items-center gap-1"
131
+ :class="isInput ? 'justify-end pr-3' : 'pl-3'"
132
+ >
133
+ <template v-if="isInput">
134
+ <span>{{ row.port.name }}</span>
135
+ <Handle
136
+ :id="handleId(row)"
137
+ :type="handleDirection"
138
+ :position="handlePosition"
139
+ :style="row.kind === 'trigger' ? triggerStyle : dataHandleStyle(row.port)"
140
+ />
141
+ </template>
142
+ <template v-else>
143
+ <Handle
144
+ :id="handleId(row)"
145
+ :type="handleDirection"
146
+ :position="handlePosition"
147
+ :style="row.kind === 'trigger' ? triggerStyle : dataHandleStyle(row.port)"
148
+ />
149
+ <span>{{ row.port.name }}</span>
150
+ </template>
151
+ </div>
152
+ </div>
153
+ </div>
154
+ <div
155
+ v-else-if="!mainTrigger"
156
+ class="py-2 px-3 text-xs text-dimmed italic"
157
+ >
158
+ {{ emptyText }}
159
+ </div>
160
+ </div>
161
+ </template>
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Shared handle styling for the editor's node Vue components. Trigger and
3
+ * data handles use a fixed color and size; data handles can additionally
4
+ * pick a per-JSON-schema-type color via `dataHandleStyle(port)` (keyed off
5
+ * `port.schema`) for the group/sentinel node variants.
6
+ */
7
+
8
+ import type {
9
+ GroupPort,
10
+ JsonSchema,
11
+ } from "../../../composables/useGraphConnect";
12
+
13
+ // Trigger (control-flow) handles use the DMS accent cyan so the procedure's
14
+ // main flow reads as the brand colour; data handles stay emerald (success).
15
+ export const triggerStyle = {
16
+ background: "#2dc1cf",
17
+ width: "10px",
18
+ height: "10px",
19
+ };
20
+
21
+ export const dataStyle = {
22
+ background: "#10b981",
23
+ width: "8px",
24
+ height: "8px",
25
+ };
26
+
27
+ // Per-JSON-schema-type color for data handles. Falls back to the
28
+ // emerald baseline (the data-port default) for unknown / missing types.
29
+ const TYPE_COLORS: Record<string, string> = {
30
+ string: "#10b981", // emerald — matches DataNode default
31
+ number: "#f59e0b", // amber
32
+ integer: "#f59e0b", // amber
33
+ boolean: "#ef4444", // red
34
+ object: "#8b5cf6", // violet
35
+ array: "#06b6d4", // cyan
36
+ null: "#6b7280", // gray
37
+ };
38
+
39
+ function schemaType(schema: JsonSchema | undefined): string {
40
+ if (!schema) return "";
41
+ const t = schema.type;
42
+ if (Array.isArray(t)) return typeof t[0] === "string" ? (t[0] as string) : "";
43
+ return typeof t === "string" ? t : "";
44
+ }
45
+
46
+ export function dataHandleStyle(port: Pick<GroupPort, "schema">): {
47
+ background: string;
48
+ width: string;
49
+ height: string;
50
+ } {
51
+ const color = TYPE_COLORS[schemaType(port.schema)] ?? "#10b981";
52
+ return { background: color, width: "8px", height: "8px" };
53
+ }