@nvent-addon/app 0.4.5 → 0.5.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 (153) hide show
  1. package/dist/module.d.mts +19 -1
  2. package/dist/module.mjs +20 -8
  3. package/dist/runtime/app/components/{nhealth/component-router.d.vue.ts → ComponentRouter.d.vue.ts} +1 -5
  4. package/dist/runtime/app/components/{nhealth/component-router.vue.d.ts → ComponentRouter.vue.d.ts} +1 -5
  5. package/dist/runtime/app/components/{nhealth/component-shell.d.vue.ts → ComponentShell.d.vue.ts} +4 -9
  6. package/dist/runtime/app/components/ComponentShell.vue +87 -0
  7. package/dist/runtime/app/components/{nhealth/component-shell.vue.d.ts → ComponentShell.vue.d.ts} +4 -9
  8. package/dist/runtime/app/components/ConfirmDialog.d.vue.ts +1 -6
  9. package/dist/runtime/app/components/ConfirmDialog.vue.d.ts +1 -6
  10. package/dist/runtime/app/components/ListItem.d.vue.ts +3 -6
  11. package/dist/runtime/app/components/ListItem.vue.d.ts +3 -6
  12. package/dist/runtime/app/components/LiveIndicator.d.vue.ts +7 -0
  13. package/dist/runtime/app/components/LiveIndicator.vue +30 -0
  14. package/dist/runtime/app/components/LiveIndicator.vue.d.ts +7 -0
  15. package/dist/runtime/app/components/{QueueConfigDetails.d.vue.ts → QueueConfiguration.d.vue.ts} +1 -10
  16. package/dist/runtime/app/components/QueueConfiguration.vue +387 -0
  17. package/dist/runtime/app/components/{QueueConfigDetails.vue.d.ts → QueueConfiguration.vue.d.ts} +1 -10
  18. package/dist/runtime/app/components/StatCard.d.vue.ts +9 -0
  19. package/dist/runtime/app/components/StatCard.vue +57 -0
  20. package/dist/runtime/app/components/StatCard.vue.d.ts +9 -0
  21. package/dist/runtime/app/components/TimelineList.vue +67 -0
  22. package/dist/runtime/app/components/flow/AwaitNode.d.vue.ts +18 -0
  23. package/dist/runtime/app/components/flow/AwaitNode.vue +91 -0
  24. package/dist/runtime/app/components/flow/AwaitNode.vue.d.ts +18 -0
  25. package/dist/runtime/app/components/{FlowDiagram.d.vue.ts → flow/Diagram.d.vue.ts} +12 -1
  26. package/dist/runtime/app/components/{FlowDiagram.vue → flow/Diagram.vue} +92 -11
  27. package/dist/runtime/app/components/{FlowDiagram.vue.d.ts → flow/Diagram.vue.d.ts} +12 -1
  28. package/dist/runtime/app/components/{FlowRunOverview.d.vue.ts → flow/RunOverview.d.vue.ts} +3 -0
  29. package/dist/runtime/app/components/{FlowRunOverview.vue → flow/RunOverview.vue} +94 -8
  30. package/dist/runtime/app/components/{FlowRunOverview.vue.d.ts → flow/RunOverview.vue.d.ts} +3 -0
  31. package/dist/runtime/app/components/{FlowRunStatusBadge.d.vue.ts → flow/RunStatusBadge.d.vue.ts} +2 -8
  32. package/dist/runtime/app/components/{FlowRunStatusBadge.vue → flow/RunStatusBadge.vue} +8 -1
  33. package/dist/runtime/app/components/{FlowRunStatusBadge.vue.d.ts → flow/RunStatusBadge.vue.d.ts} +2 -8
  34. package/dist/runtime/app/components/{FlowRunTimeline.vue → flow/RunTimeline.vue} +1 -1
  35. package/dist/runtime/app/components/{FlowStepSelector.d.vue.ts → flow/StepSelector.d.vue.ts} +1 -0
  36. package/dist/runtime/app/components/flow/StepSelector.vue +553 -0
  37. package/dist/runtime/app/components/{FlowStepSelector.vue.d.ts → flow/StepSelector.vue.d.ts} +1 -0
  38. package/dist/runtime/app/components/trigger/BasicInfoCard.d.vue.ts +33 -0
  39. package/dist/runtime/app/components/trigger/BasicInfoCard.vue +168 -0
  40. package/dist/runtime/app/components/trigger/BasicInfoCard.vue.d.ts +33 -0
  41. package/dist/runtime/app/components/{FlowSchedulesList.d.vue.ts → trigger/DangerZone.d.vue.ts} +4 -6
  42. package/dist/runtime/app/components/trigger/DangerZone.vue +46 -0
  43. package/dist/runtime/app/components/{FlowSchedulesList.vue.d.ts → trigger/DangerZone.vue.d.ts} +4 -6
  44. package/dist/runtime/app/components/trigger/EditHeader.d.vue.ts +15 -0
  45. package/dist/runtime/app/components/trigger/EditHeader.vue +55 -0
  46. package/dist/runtime/app/components/trigger/EditHeader.vue.d.ts +15 -0
  47. package/dist/runtime/app/components/trigger/EventConfig.d.vue.ts +24 -0
  48. package/dist/runtime/app/components/trigger/EventConfig.vue +68 -0
  49. package/dist/runtime/app/components/trigger/EventConfig.vue.d.ts +24 -0
  50. package/dist/runtime/app/components/trigger/FlowSubscriptions.d.vue.ts +14 -0
  51. package/dist/runtime/app/components/trigger/FlowSubscriptions.vue +128 -0
  52. package/dist/runtime/app/components/trigger/FlowSubscriptions.vue.d.ts +14 -0
  53. package/dist/runtime/app/components/trigger/ScheduleConfig.d.vue.ts +27 -0
  54. package/dist/runtime/app/components/trigger/ScheduleConfig.vue +375 -0
  55. package/dist/runtime/app/components/trigger/ScheduleConfig.vue.d.ts +27 -0
  56. package/dist/runtime/app/components/{FlowScheduleDialog.d.vue.ts → trigger/StatusConfig.d.vue.ts} +6 -6
  57. package/dist/runtime/app/components/trigger/StatusConfig.vue +78 -0
  58. package/dist/runtime/app/components/{FlowScheduleDialog.vue.d.ts → trigger/StatusConfig.vue.d.ts} +6 -6
  59. package/dist/runtime/app/components/trigger/WebhookConfig.d.vue.ts +30 -0
  60. package/dist/runtime/app/components/trigger/WebhookConfig.vue +97 -0
  61. package/dist/runtime/app/components/trigger/WebhookConfig.vue.d.ts +30 -0
  62. package/dist/runtime/app/composables/useAnalyzedFlows.d.ts +5 -0
  63. package/dist/runtime/app/composables/useAnalyzedFlows.js +15 -1
  64. package/dist/runtime/app/composables/useComponentRouter.d.ts +8 -0
  65. package/dist/runtime/app/composables/useComponentRouter.js +10 -2
  66. package/dist/runtime/app/composables/useFlowRunsInfinite.d.ts +1 -1
  67. package/dist/runtime/app/composables/useFlowState.js +65 -0
  68. package/dist/runtime/app/composables/useFlowWebSocket.d.ts +11 -2
  69. package/dist/runtime/app/composables/useFlowWebSocket.js +181 -65
  70. package/dist/runtime/app/composables/useQueueJobs.d.ts +12 -1
  71. package/dist/runtime/app/composables/useQueueJobs.js +13 -7
  72. package/dist/runtime/app/composables/useTrigger.d.ts +137 -0
  73. package/dist/runtime/app/composables/useTrigger.js +116 -0
  74. package/dist/runtime/app/composables/useTriggerWebSocket.d.ts +35 -0
  75. package/dist/runtime/app/composables/useTriggerWebSocket.js +333 -0
  76. package/dist/runtime/app/pages/dashboard.d.vue.ts +3 -0
  77. package/dist/runtime/app/pages/dashboard.vue +738 -0
  78. package/dist/runtime/app/pages/dashboard.vue.d.ts +3 -0
  79. package/dist/runtime/app/pages/flows/[name].d.vue.ts +3 -0
  80. package/dist/runtime/app/pages/flows/[name].vue +680 -0
  81. package/dist/runtime/app/pages/flows/[name].vue.d.ts +3 -0
  82. package/dist/runtime/app/pages/flows/index.vue +321 -620
  83. package/dist/runtime/app/pages/index.vue +39 -9
  84. package/dist/runtime/app/pages/queues/index.vue +202 -194
  85. package/dist/runtime/app/pages/queues/jobs.vue +534 -207
  86. package/dist/runtime/app/pages/settings/scheduler.d.vue.ts +3 -0
  87. package/dist/runtime/app/pages/settings/scheduler.vue +310 -0
  88. package/dist/runtime/app/pages/settings/scheduler.vue.d.ts +3 -0
  89. package/dist/runtime/app/pages/triggers/[name]/edit.d.vue.ts +3 -0
  90. package/dist/runtime/app/pages/triggers/[name]/edit.vue +429 -0
  91. package/dist/runtime/app/pages/triggers/[name]/edit.vue.d.ts +3 -0
  92. package/dist/runtime/app/pages/triggers/[name].d.vue.ts +3 -0
  93. package/dist/runtime/app/pages/triggers/[name].vue +898 -0
  94. package/dist/runtime/app/pages/triggers/[name].vue.d.ts +3 -0
  95. package/dist/runtime/app/pages/triggers/index.d.vue.ts +3 -0
  96. package/dist/runtime/app/pages/triggers/index.vue +528 -0
  97. package/dist/runtime/app/pages/triggers/index.vue.d.ts +3 -0
  98. package/dist/runtime/app/pages/triggers/new.d.vue.ts +3 -0
  99. package/dist/runtime/app/pages/triggers/new.vue +610 -0
  100. package/dist/runtime/app/pages/triggers/new.vue.d.ts +3 -0
  101. package/dist/runtime/server/api/_flows/[name]/clear-history.delete.d.ts +10 -0
  102. package/dist/runtime/server/api/_flows/[name]/clear-history.delete.js +49 -0
  103. package/dist/runtime/server/api/_flows/[name]/runs/[runId]/cancel.post.d.ts +2 -0
  104. package/dist/runtime/server/api/_flows/[name]/runs/[runId]/cancel.post.js +21 -0
  105. package/dist/runtime/server/api/_flows/[name]/runs.get.d.ts +17 -0
  106. package/dist/runtime/server/api/_flows/[name]/runs.get.js +64 -0
  107. package/dist/runtime/server/api/_flows/[name]/start.post.d.ts +2 -0
  108. package/dist/runtime/server/api/_flows/[name]/start.post.js +9 -0
  109. package/dist/runtime/server/api/_flows/index.get.d.ts +7 -0
  110. package/dist/runtime/server/api/_flows/index.get.js +5 -0
  111. package/dist/runtime/server/api/_flows/recent-runs.get.d.ts +15 -0
  112. package/dist/runtime/server/api/_flows/recent-runs.get.js +67 -0
  113. package/dist/runtime/server/api/_flows/ws.d.ts +80 -0
  114. package/dist/runtime/server/api/_flows/ws.js +309 -0
  115. package/dist/runtime/server/api/_queues/[name]/job/[id].get.d.ts +2 -0
  116. package/dist/runtime/server/api/_queues/[name]/job/[id].get.js +14 -0
  117. package/dist/runtime/server/api/_queues/[name]/job/index.get.d.ts +2 -0
  118. package/dist/runtime/server/api/_queues/[name]/job/index.get.js +39 -0
  119. package/dist/runtime/server/api/_queues/index.get.d.ts +2 -0
  120. package/dist/runtime/server/api/_queues/index.get.js +106 -0
  121. package/dist/runtime/server/api/_queues/ws.d.ts +48 -0
  122. package/dist/runtime/server/api/_queues/ws.js +215 -0
  123. package/dist/runtime/server/api/_scheduler/jobs.get.d.ts +19 -0
  124. package/dist/runtime/server/api/_scheduler/jobs.get.js +36 -0
  125. package/dist/runtime/server/api/_triggers/[name]/events.get.d.ts +6 -0
  126. package/dist/runtime/server/api/_triggers/[name]/events.get.js +43 -0
  127. package/dist/runtime/server/api/_triggers/[name]/index.get.d.ts +6 -0
  128. package/dist/runtime/server/api/_triggers/[name]/index.get.js +76 -0
  129. package/dist/runtime/server/api/_triggers/[name].delete.d.ts +7 -0
  130. package/dist/runtime/server/api/_triggers/[name].delete.js +37 -0
  131. package/dist/runtime/server/api/_triggers/[name].patch.d.ts +7 -0
  132. package/dist/runtime/server/api/_triggers/[name].patch.js +117 -0
  133. package/dist/runtime/server/api/_triggers/index.get.d.ts +6 -0
  134. package/dist/runtime/server/api/_triggers/index.get.js +44 -0
  135. package/dist/runtime/server/api/_triggers/index.post.d.ts +7 -0
  136. package/dist/runtime/server/api/_triggers/index.post.js +124 -0
  137. package/dist/runtime/server/api/_triggers/stats.get.d.ts +6 -0
  138. package/dist/runtime/server/api/_triggers/stats.get.js +41 -0
  139. package/dist/runtime/server/api/_triggers/ws.d.ts +74 -0
  140. package/dist/runtime/server/api/_triggers/ws.js +315 -0
  141. package/dist/runtime/server/tsconfig.json +7 -0
  142. package/package.json +8 -8
  143. package/dist/runtime/app/components/FlowScheduleDialog.vue +0 -226
  144. package/dist/runtime/app/components/FlowSchedulesList.vue +0 -99
  145. package/dist/runtime/app/components/FlowStepSelector.vue +0 -238
  146. package/dist/runtime/app/components/QueueConfigDetails.vue +0 -412
  147. package/dist/runtime/app/components/nhealth/component-shell.vue +0 -89
  148. /package/dist/runtime/app/components/{nhealth/component-router.vue → ComponentRouter.vue} +0 -0
  149. /package/dist/runtime/app/components/{FlowNodeCard.d.vue.ts → flow/NodeCard.d.vue.ts} +0 -0
  150. /package/dist/runtime/app/components/{FlowNodeCard.vue → flow/NodeCard.vue} +0 -0
  151. /package/dist/runtime/app/components/{FlowNodeCard.vue.d.ts → flow/NodeCard.vue.d.ts} +0 -0
  152. /package/dist/runtime/app/components/{FlowRunTimeline.d.vue.ts → flow/RunTimeline.d.vue.ts} +0 -0
  153. /package/dist/runtime/app/components/{FlowRunTimeline.vue.d.ts → flow/RunTimeline.vue.d.ts} +0 -0
@@ -0,0 +1,91 @@
1
+ <template>
2
+ <div
3
+ class="px-3 py-2 rounded-lg border-2 min-w-[180px] bg-white dark:bg-gray-900 transition-all duration-300"
4
+ :class="borderClass"
5
+ >
6
+ <div class="flex items-center justify-between gap-2 text-xs mb-2">
7
+ <div class="flex items-center gap-2">
8
+ <UIcon
9
+ :name="getAwaitIcon(data.awaitType)"
10
+ class="w-3.5 h-3.5"
11
+ />
12
+ <span class="font-medium text-gray-700 dark:text-gray-300">
13
+ {{ data.label }}
14
+ </span>
15
+ </div>
16
+ <UBadge
17
+ :label="statusLabel"
18
+ size="xs"
19
+ :color="statusColor"
20
+ />
21
+ </div>
22
+ <div
23
+ v-if="data.awaitConfig"
24
+ class="text-[10px] text-gray-500 dark:text-gray-400"
25
+ >
26
+ <div v-if="data.awaitType === 'time'">
27
+ Delay: {{ formatDelay(data.awaitConfig.delay) }}
28
+ </div>
29
+ <div v-else-if="data.awaitType === 'event'">
30
+ Event: {{ data.awaitConfig.event }}
31
+ </div>
32
+ <div v-else-if="data.awaitType === 'webhook'">
33
+ Webhook: {{ data.awaitConfig.method || "POST" }}
34
+ </div>
35
+ </div>
36
+ </div>
37
+ </template>
38
+
39
+ <script setup>
40
+ import { computed } from "#imports";
41
+ import { UIcon, UBadge } from "#components";
42
+ const props = defineProps({
43
+ data: { type: Object, required: true }
44
+ });
45
+ const statusLabel = computed(() => {
46
+ return (props.data.status || "idle").toUpperCase();
47
+ });
48
+ const statusColor = computed(() => {
49
+ switch (props.data.status) {
50
+ case "waiting":
51
+ return "warning";
52
+ case "resolved":
53
+ return "success";
54
+ case "timeout":
55
+ return "error";
56
+ default:
57
+ return "neutral";
58
+ }
59
+ });
60
+ const borderClass = computed(() => {
61
+ switch (props.data.status) {
62
+ case "waiting":
63
+ return "border-amber-400 dark:border-amber-500 bg-amber-50 dark:bg-amber-950/20";
64
+ case "resolved":
65
+ return "border-emerald-400 dark:border-emerald-500 bg-emerald-50 dark:bg-emerald-950/20";
66
+ case "timeout":
67
+ return "border-red-400 dark:border-red-500 bg-red-50 dark:bg-red-950/20";
68
+ default:
69
+ return "border-gray-300 dark:border-gray-700";
70
+ }
71
+ });
72
+ function getAwaitIcon(type) {
73
+ switch (type) {
74
+ case "time":
75
+ return "i-lucide-clock";
76
+ case "event":
77
+ return "i-lucide-zap";
78
+ case "webhook":
79
+ return "i-lucide-webhook";
80
+ default:
81
+ return "i-lucide-clock";
82
+ }
83
+ }
84
+ function formatDelay(ms) {
85
+ if (!ms) return "0ms";
86
+ if (ms < 1e3) return `${ms}ms`;
87
+ if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
88
+ if (ms < 36e5) return `${(ms / 6e4).toFixed(1)}m`;
89
+ return `${(ms / 36e5).toFixed(1)}h`;
90
+ }
91
+ </script>
@@ -0,0 +1,18 @@
1
+ interface AwaitConfig {
2
+ type?: 'time' | 'event' | 'webhook';
3
+ delay?: number;
4
+ event?: string;
5
+ method?: string;
6
+ timeout?: number;
7
+ }
8
+ type __VLS_Props = {
9
+ data: {
10
+ label: string;
11
+ awaitType?: 'time' | 'event' | 'webhook';
12
+ awaitConfig?: AwaitConfig;
13
+ status?: 'idle' | 'waiting' | 'resolved' | 'timeout';
14
+ };
15
+ };
16
+ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
17
+ declare const _default: typeof __VLS_export;
18
+ export default _default;
@@ -1,3 +1,11 @@
1
+ interface AwaitConfig {
2
+ type: 'time' | 'event' | 'webhook';
3
+ delay?: number;
4
+ event?: string;
5
+ method?: string;
6
+ timeout?: number;
7
+ timeoutAction?: 'fail' | 'continue';
8
+ }
1
9
  interface FlowEntry {
2
10
  step: string;
3
11
  queue: string;
@@ -5,6 +13,7 @@ interface FlowEntry {
5
13
  runtime?: 'nodejs' | 'python';
6
14
  runtype?: 'inprocess' | 'task';
7
15
  emits?: string[];
16
+ awaitAfter?: AwaitConfig;
8
17
  }
9
18
  interface FlowStep {
10
19
  queue: string;
@@ -13,6 +22,8 @@ interface FlowStep {
13
22
  runtime?: 'nodejs' | 'python';
14
23
  runtype?: 'inprocess' | 'task';
15
24
  emits?: string[];
25
+ awaitBefore?: AwaitConfig;
26
+ awaitAfter?: AwaitConfig;
16
27
  }
17
28
  interface AnalyzedStep extends FlowStep {
18
29
  name: string;
@@ -42,7 +53,7 @@ type __VLS_Props = {
42
53
  showMiniMap?: boolean;
43
54
  showBackground?: boolean;
44
55
  stepStates?: Record<string, StepStatus>;
45
- flowStatus?: 'running' | 'completed' | 'failed' | 'canceled';
56
+ flowStatus?: 'running' | 'completed' | 'failed' | 'canceled' | 'stalled';
46
57
  };
47
58
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
48
59
  nodeSelected: (payload: {
@@ -52,6 +52,20 @@
52
52
  />
53
53
  </template>
54
54
 
55
+ <template #node-flow-await="{ data }">
56
+ <FlowAwaitNode
57
+ :data="data"
58
+ />
59
+ <Handle
60
+ type="target"
61
+ :position="Position.Top"
62
+ />
63
+ <Handle
64
+ type="source"
65
+ :position="Position.Bottom"
66
+ />
67
+ </template>
68
+
55
69
  <Background
56
70
  v-if="showBackground"
57
71
  pattern-color="#888"
@@ -68,7 +82,8 @@
68
82
  <script setup>
69
83
  import { computed, ref, watch, nextTick } from "#imports";
70
84
  import { Handle, Position } from "@vue-flow/core";
71
- import FlowNodeCard from "../components/FlowNodeCard.vue";
85
+ import FlowNodeCard from "./NodeCard.vue";
86
+ import FlowAwaitNode from "./AwaitNode.vue";
72
87
  const props = defineProps({
73
88
  flow: { type: [Object, null], required: false },
74
89
  heightClass: { type: String, required: false },
@@ -190,7 +205,50 @@ const nodes = computed(() => {
190
205
  });
191
206
  });
192
207
  }
193
- return out;
208
+ const awaitNodes = [];
209
+ const awaitGap = 70;
210
+ if (f.entry?.awaitAfter && f.entry) {
211
+ const entryNode = out.find((n) => n.id === `entry:${f.entry.step}`);
212
+ if (entryNode) {
213
+ const awaitKey = `${f.entry.step}:await-after`;
214
+ const awaitState = states[awaitKey];
215
+ const awaitStatus = awaitState?.status === "waiting" ? "waiting" : awaitState?.status === "completed" ? "resolved" : awaitState?.status === "timeout" ? "timeout" : "idle";
216
+ awaitNodes.push({
217
+ id: `await:entry-after:${f.entry.step}`,
218
+ position: { x: -90, y: entryNode.position.y + rowHeight + awaitGap },
219
+ data: {
220
+ label: `Await (${f.entry.awaitAfter.type})`,
221
+ awaitType: f.entry.awaitAfter.type,
222
+ awaitConfig: f.entry.awaitAfter,
223
+ status: awaitStatus
224
+ },
225
+ type: "flow-await",
226
+ style: { minWidth: "180px" }
227
+ });
228
+ }
229
+ }
230
+ Object.entries(steps).forEach(([stepName, step]) => {
231
+ if (step.awaitBefore) {
232
+ const stepNode = out.find((n) => n.id === `step:${stepName}`);
233
+ if (stepNode) {
234
+ const awaitState = states[`${stepName}:await-before`];
235
+ const awaitStatus = awaitState?.status === "waiting" ? "waiting" : awaitState?.status === "completed" ? "resolved" : awaitState?.status === "timeout" ? "timeout" : "idle";
236
+ awaitNodes.push({
237
+ id: `await:step-before:${stepName}`,
238
+ position: { x: stepNode.position.x + 20, y: stepNode.position.y - awaitGap - 50 },
239
+ data: {
240
+ label: `Await (${step.awaitBefore.type})`,
241
+ awaitType: step.awaitBefore.type,
242
+ awaitConfig: step.awaitBefore,
243
+ status: awaitStatus
244
+ },
245
+ type: "flow-await",
246
+ style: { minWidth: "180px" }
247
+ });
248
+ }
249
+ }
250
+ });
251
+ return [...out, ...awaitNodes];
194
252
  });
195
253
  function mapStatusToNodeStatus(status) {
196
254
  switch (status) {
@@ -213,6 +271,7 @@ const edges = computed(() => {
213
271
  const f = props.flow;
214
272
  if (!f) return [];
215
273
  const states = props.stepStates || {};
274
+ const steps = f.steps || {};
216
275
  const added = /* @__PURE__ */ new Set();
217
276
  const out = [];
218
277
  function addEdge(source, target, label) {
@@ -229,14 +288,32 @@ const edges = computed(() => {
229
288
  if (f.analyzed?.steps) {
230
289
  const analyzedSteps = f.analyzed.steps;
231
290
  for (const [stepName, stepInfo] of Object.entries(analyzedSteps)) {
291
+ const targetStep = steps[stepName];
232
292
  const target = `step:${stepName}`;
233
293
  if (stepInfo.dependsOn.length > 0) {
234
294
  for (const depName of stepInfo.dependsOn) {
235
295
  const source = depName === f.entry?.step ? `entry:${depName}` : `step:${depName}`;
236
- addEdge(source, target);
296
+ if (targetStep?.awaitBefore) {
297
+ const awaitNodeId = `await:step-before:${stepName}`;
298
+ addEdge(source, awaitNodeId);
299
+ addEdge(awaitNodeId, target);
300
+ } else {
301
+ addEdge(source, target);
302
+ }
237
303
  }
238
304
  } else if (f.entry) {
239
- addEdge(`entry:${f.entry.step}`, target);
305
+ const entryId = `entry:${f.entry.step}`;
306
+ if (f.entry.awaitAfter) {
307
+ const awaitNodeId = `await:entry-after:${f.entry.step}`;
308
+ addEdge(entryId, awaitNodeId);
309
+ addEdge(awaitNodeId, target);
310
+ } else if (targetStep?.awaitBefore) {
311
+ const awaitNodeId = `await:step-before:${stepName}`;
312
+ addEdge(entryId, awaitNodeId);
313
+ addEdge(awaitNodeId, target);
314
+ } else {
315
+ addEdge(entryId, target);
316
+ }
240
317
  }
241
318
  }
242
319
  } else {
@@ -289,15 +366,19 @@ watch(() => props.flow, (f) => {
289
366
  }
290
367
  }, 100);
291
368
  }, { immediate: true, deep: false });
292
- watch(() => props.stepStates, () => {
369
+ watch([() => props.stepStates, () => props.flowStatus], () => {
293
370
  if (!props.flow) return;
294
- const builtNodes = nodes.value.map((n) => ({ id: n.id, position: { ...n.position }, data: { ...n.data }, type: n.type, style: n.style }));
371
+ const latestNodes = nodes.value;
295
372
  const positionMap = new Map(internalNodes.value.map((n) => [n.id, n.position]));
296
- builtNodes.forEach((n) => {
297
- const existing = positionMap.get(n.id);
298
- if (existing) n.position = existing;
299
- });
300
- internalNodes.value = builtNodes;
373
+ const updatedNodes = latestNodes.map((n) => ({
374
+ id: n.id,
375
+ position: positionMap.get(n.id) || { ...n.position },
376
+ data: { ...n.data },
377
+ // Create new data object reference
378
+ type: n.type,
379
+ style: n.style
380
+ }));
381
+ internalNodes.value = updatedNodes;
301
382
  const builtEdges = edges.value.map((e) => ({ id: e.id, source: e.source, target: e.target, label: e.label, animated: e.animated }));
302
383
  internalEdges.value = builtEdges;
303
384
  }, { deep: true });
@@ -1,3 +1,11 @@
1
+ interface AwaitConfig {
2
+ type: 'time' | 'event' | 'webhook';
3
+ delay?: number;
4
+ event?: string;
5
+ method?: string;
6
+ timeout?: number;
7
+ timeoutAction?: 'fail' | 'continue';
8
+ }
1
9
  interface FlowEntry {
2
10
  step: string;
3
11
  queue: string;
@@ -5,6 +13,7 @@ interface FlowEntry {
5
13
  runtime?: 'nodejs' | 'python';
6
14
  runtype?: 'inprocess' | 'task';
7
15
  emits?: string[];
16
+ awaitAfter?: AwaitConfig;
8
17
  }
9
18
  interface FlowStep {
10
19
  queue: string;
@@ -13,6 +22,8 @@ interface FlowStep {
13
22
  runtime?: 'nodejs' | 'python';
14
23
  runtype?: 'inprocess' | 'task';
15
24
  emits?: string[];
25
+ awaitBefore?: AwaitConfig;
26
+ awaitAfter?: AwaitConfig;
16
27
  }
17
28
  interface AnalyzedStep extends FlowStep {
18
29
  name: string;
@@ -42,7 +53,7 @@ type __VLS_Props = {
42
53
  showMiniMap?: boolean;
43
54
  showBackground?: boolean;
44
55
  stepStates?: Record<string, StepStatus>;
45
- flowStatus?: 'running' | 'completed' | 'failed' | 'canceled';
56
+ flowStatus?: 'running' | 'completed' | 'failed' | 'canceled' | 'stalled';
46
57
  };
47
58
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
48
59
  nodeSelected: (payload: {
@@ -5,6 +5,9 @@ type __VLS_Props = {
5
5
  steps: any[];
6
6
  flowName?: string;
7
7
  runId?: string;
8
+ triggerName?: string;
9
+ triggerType?: 'manual' | 'event' | 'webhook' | 'schedule';
10
+ flowDef?: any;
8
11
  };
9
12
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
10
13
  "select-step": (stepKey: string | null) => any;
@@ -18,6 +18,23 @@
18
18
  <!-- Divider -->
19
19
  <div class="w-px h-3 bg-gray-300 dark:bg-gray-700" />
20
20
 
21
+ <!-- Entry Trigger -->
22
+ <div
23
+ v-if="triggerName"
24
+ class="flex items-center gap-1.5"
25
+ >
26
+ <UIcon
27
+ :name="getTriggerIcon(triggerType)"
28
+ class="w-3 h-3 text-gray-500"
29
+ />
30
+ <span class="text-gray-700 dark:text-gray-300">
31
+ {{ triggerName }}
32
+ </span>
33
+ </div>
34
+
35
+ <!-- Divider -->
36
+ <div class="w-px h-3 bg-gray-300 dark:bg-gray-700" />
37
+
21
38
  <!-- Total Steps -->
22
39
  <div class="flex items-center gap-1.5">
23
40
  <UIcon
@@ -96,14 +113,17 @@
96
113
  <script setup>
97
114
  import { ref, computed, watch } from "#imports";
98
115
  import { UIcon, UButton } from "#components";
99
- import FlowStepSelector from "./FlowStepSelector.vue";
116
+ import FlowStepSelector from "./StepSelector.vue";
100
117
  const props = defineProps({
101
118
  runStatus: { type: String, required: false },
102
119
  startedAt: { type: [String, Number], required: false },
103
120
  completedAt: { type: [String, Number], required: false },
104
121
  steps: { type: Array, required: true },
105
122
  flowName: { type: String, required: false },
106
- runId: { type: String, required: false }
123
+ runId: { type: String, required: false },
124
+ triggerName: { type: String, required: false },
125
+ triggerType: { type: String, required: false },
126
+ flowDef: { type: null, required: false }
107
127
  });
108
128
  const emit = defineEmits(["select-step", "cancel-flow"]);
109
129
  const handleCancelFlow = () => {
@@ -119,6 +139,23 @@ watch(firstStepKey, (newKey, oldKey) => {
119
139
  watch(selectedStep, (newStep) => {
120
140
  emit("select-step", newStep === "all-steps" ? null : newStep);
121
141
  });
142
+ const isValidAwaitStep = (stepKey) => {
143
+ if (!stepKey.includes(":await-")) return true;
144
+ if (!props.flowDef) return false;
145
+ const parts = stepKey.split(":await-");
146
+ const stepName = parts[0];
147
+ const position = parts[1];
148
+ if (props.flowDef.entry?.step === stepName) {
149
+ if (position === "after" && props.flowDef.entry?.awaitAfter) return true;
150
+ if (position === "before" && props.flowDef.entry?.awaitBefore) return true;
151
+ }
152
+ const step = stepName ? props.flowDef.steps?.[stepName] : void 0;
153
+ if (step) {
154
+ if (position === "after" && step.awaitAfter) return true;
155
+ if (position === "before" && step.awaitBefore) return true;
156
+ }
157
+ return false;
158
+ };
122
159
  const radioItems = computed(() => {
123
160
  const allItem = {
124
161
  value: "all-steps",
@@ -127,13 +164,48 @@ const radioItems = computed(() => {
127
164
  key: "All Steps",
128
165
  status: null,
129
166
  showAllIndicator: true
130
- }
167
+ },
168
+ clickable: true
131
169
  };
132
- const stepItems = props.steps.map((step) => ({
133
- value: step.key,
134
- label: step.key,
135
- step
136
- }));
170
+ const filteredSteps = props.steps.filter((step) => isValidAwaitStep(step.key));
171
+ const stepItems = filteredSteps.map((step) => {
172
+ const isAwait = step.key.includes(":await-");
173
+ let awaitConfig = void 0;
174
+ let webhookUrl = void 0;
175
+ if (isAwait && props.flowDef) {
176
+ const parts = step.key.split(":await-");
177
+ const stepName = parts[0];
178
+ const position = parts[1];
179
+ if (props.flowDef.entry?.step === stepName) {
180
+ awaitConfig = position === "after" ? props.flowDef.entry?.awaitAfter : props.flowDef.entry?.awaitBefore;
181
+ } else {
182
+ const stepDef = stepName ? props.flowDef.steps?.[stepName] : void 0;
183
+ if (stepDef) {
184
+ awaitConfig = position === "after" ? stepDef.awaitAfter : stepDef.awaitBefore;
185
+ }
186
+ }
187
+ if (awaitConfig?.type === "webhook" && props.flowName && props.runId) {
188
+ const baseUrl = typeof window !== "undefined" ? `${window.location.protocol}//${window.location.host}` : "";
189
+ webhookUrl = `${baseUrl}/api/_webhook/await/${props.flowName}/${props.runId}/${stepName}`;
190
+ }
191
+ }
192
+ const finalStep = {
193
+ ...step,
194
+ awaitConfig,
195
+ // Add await config from flow definition
196
+ // Extract awaitType from config if available
197
+ awaitType: awaitConfig?.type || step.awaitType,
198
+ webhookUrl
199
+ // Add constructed webhook URL
200
+ };
201
+ return {
202
+ value: step.key,
203
+ label: step.key,
204
+ step: finalStep,
205
+ clickable: !isAwait
206
+ // Await steps are not clickable
207
+ };
208
+ });
137
209
  return [allItem, ...stepItems];
138
210
  });
139
211
  const formatTime = (timestamp) => {
@@ -185,4 +257,18 @@ const getStatusColor = (status) => {
185
257
  return "bg-gray-300";
186
258
  }
187
259
  };
260
+ const getTriggerIcon = (type) => {
261
+ switch (type) {
262
+ case "manual":
263
+ return "i-lucide-hand";
264
+ case "event":
265
+ return "i-lucide-zap";
266
+ case "webhook":
267
+ return "i-lucide-webhook";
268
+ case "schedule":
269
+ return "i-lucide-calendar-clock";
270
+ default:
271
+ return "i-lucide-play-circle";
272
+ }
273
+ };
188
274
  </script>
@@ -5,6 +5,9 @@ type __VLS_Props = {
5
5
  steps: any[];
6
6
  flowName?: string;
7
7
  runId?: string;
8
+ triggerName?: string;
9
+ triggerType?: 'manual' | 'event' | 'webhook' | 'schedule';
10
+ flowDef?: any;
8
11
  };
9
12
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
10
13
  "select-step": (stepKey: string | null) => any;
@@ -4,15 +4,9 @@ interface Props {
4
4
  isFailed?: boolean;
5
5
  isCanceled?: boolean;
6
6
  isStalled?: boolean;
7
+ isAwaiting?: boolean;
7
8
  isReconnecting?: boolean;
8
9
  }
9
- declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
10
- isRunning: boolean;
11
- isCompleted: boolean;
12
- isFailed: boolean;
13
- isCanceled: boolean;
14
- isStalled: boolean;
15
- isReconnecting: boolean;
16
- }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
10
+ declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
17
11
  declare const _default: typeof __VLS_export;
18
12
  export default _default;
@@ -5,6 +5,7 @@
5
5
  'bg-emerald-50 dark:bg-emerald-950/30 border-emerald-200 dark:border-emerald-800': isCompleted,
6
6
  'bg-red-50 dark:bg-red-950/30 border-red-200 dark:border-red-800': isFailed,
7
7
  'bg-blue-50 dark:bg-blue-950/30 border-blue-200 dark:border-blue-800': isRunning,
8
+ 'bg-purple-50 dark:bg-purple-950/30 border-purple-200 dark:border-purple-800': isAwaiting,
8
9
  'bg-orange-50 dark:bg-orange-950/30 border-orange-200 dark:border-orange-800': isCanceled,
9
10
  'bg-amber-50 dark:bg-amber-950/30 border-amber-200 dark:border-amber-800': isStalled,
10
11
  'bg-gray-50 dark:bg-gray-900/30 border-gray-200 dark:border-gray-800': isIdle
@@ -16,6 +17,7 @@
16
17
  'bg-emerald-500': isCompleted,
17
18
  'bg-red-500': isFailed,
18
19
  'bg-blue-500 animate-pulse': isRunning && !isReconnecting,
20
+ 'bg-purple-500 animate-pulse': isAwaiting,
19
21
  'bg-amber-500 animate-pulse': isReconnecting,
20
22
  'bg-orange-500': isCanceled,
21
23
  'bg-amber-600': isStalled,
@@ -28,6 +30,7 @@
28
30
  'text-emerald-700 dark:text-emerald-400': isCompleted,
29
31
  'text-red-700 dark:text-red-400': isFailed,
30
32
  'text-blue-700 dark:text-blue-400': isRunning,
33
+ 'text-purple-700 dark:text-purple-400': isAwaiting,
31
34
  'text-orange-700 dark:text-orange-400': isCanceled,
32
35
  'text-amber-700 dark:text-amber-400': isStalled,
33
36
  'text-gray-600 dark:text-gray-400': isIdle
@@ -39,6 +42,9 @@
39
42
  <template v-else-if="isRunning">
40
43
  Running
41
44
  </template>
45
+ <template v-else-if="isAwaiting">
46
+ Awaiting
47
+ </template>
42
48
  <template v-else-if="isCompleted">
43
49
  Done
44
50
  </template>
@@ -66,9 +72,10 @@ const props = defineProps({
66
72
  isFailed: { type: Boolean, required: false, default: false },
67
73
  isCanceled: { type: Boolean, required: false, default: false },
68
74
  isStalled: { type: Boolean, required: false, default: false },
75
+ isAwaiting: { type: Boolean, required: false, default: false },
69
76
  isReconnecting: { type: Boolean, required: false, default: false }
70
77
  });
71
78
  const isIdle = computed(() => {
72
- return !props.isRunning && !props.isCompleted && !props.isFailed && !props.isCanceled && !props.isStalled;
79
+ return !props.isRunning && !props.isCompleted && !props.isFailed && !props.isCanceled && !props.isStalled && !props.isAwaiting;
73
80
  });
74
81
  </script>
@@ -4,15 +4,9 @@ interface Props {
4
4
  isFailed?: boolean;
5
5
  isCanceled?: boolean;
6
6
  isStalled?: boolean;
7
+ isAwaiting?: boolean;
7
8
  isReconnecting?: boolean;
8
9
  }
9
- declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {
10
- isRunning: boolean;
11
- isCompleted: boolean;
12
- isFailed: boolean;
13
- isCanceled: boolean;
14
- isStalled: boolean;
15
- isReconnecting: boolean;
16
- }, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
10
+ declare const __VLS_export: import("vue").DefineComponent<Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
17
11
  declare const _default: typeof __VLS_export;
18
12
  export default _default;
@@ -58,7 +58,7 @@
58
58
 
59
59
  <script setup>
60
60
  import { ref, computed } from "#imports";
61
- import TimelineList from "./TimelineList.vue";
61
+ import TimelineList from "../TimelineList.vue";
62
62
  import { UButton, UIcon, URadioGroup } from "#components";
63
63
  const props = defineProps({
64
64
  events: { type: Array, required: true },
@@ -5,6 +5,7 @@ type __VLS_Props = {
5
5
  value: string;
6
6
  label: string;
7
7
  step: any;
8
+ clickable?: boolean;
8
9
  }>;
9
10
  ui?: {
10
11
  root?: ClassValue;