@nvent-addon/app 0.5.4 → 0.5.6

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 (30) hide show
  1. package/dist/module.json +1 -1
  2. package/dist/module.mjs +9 -1
  3. package/dist/runtime/app/components/ComponentShell.d.vue.ts +1 -0
  4. package/dist/runtime/app/components/ComponentShell.vue +13 -3
  5. package/dist/runtime/app/components/ComponentShell.vue.d.ts +1 -0
  6. package/dist/runtime/app/components/DashboardCard.d.vue.ts +15 -0
  7. package/dist/runtime/app/components/DashboardCard.vue +76 -0
  8. package/dist/runtime/app/components/DashboardCard.vue.d.ts +15 -0
  9. package/dist/runtime/app/components/TimelineList.vue +222 -31
  10. package/dist/runtime/app/components/flow/AwaitNode.d.vue.ts +19 -2
  11. package/dist/runtime/app/components/flow/AwaitNode.vue +317 -29
  12. package/dist/runtime/app/components/flow/AwaitNode.vue.d.ts +19 -2
  13. package/dist/runtime/app/components/flow/Diagram.d.vue.ts +2 -1
  14. package/dist/runtime/app/components/flow/Diagram.vue +138 -74
  15. package/dist/runtime/app/components/flow/Diagram.vue.d.ts +2 -1
  16. package/dist/runtime/app/components/flow/NodeCard.d.vue.ts +14 -11
  17. package/dist/runtime/app/components/flow/NodeCard.vue +119 -35
  18. package/dist/runtime/app/components/flow/NodeCard.vue.d.ts +14 -11
  19. package/dist/runtime/app/components/flow/RunOverview.d.vue.ts +1 -0
  20. package/dist/runtime/app/components/flow/RunOverview.vue +85 -86
  21. package/dist/runtime/app/components/flow/RunOverview.vue.d.ts +1 -0
  22. package/dist/runtime/app/components/flow/RunTimeline.vue +51 -22
  23. package/dist/runtime/app/components/flow/StepSelector.vue +124 -46
  24. package/dist/runtime/app/composables/useFlowRunTimeline.d.ts +6 -0
  25. package/dist/runtime/app/composables/useFlowState.d.ts +8 -1
  26. package/dist/runtime/app/composables/useFlowState.js +34 -59
  27. package/dist/runtime/app/pages/dashboard.vue +51 -103
  28. package/dist/runtime/app/pages/flows/[name].vue +26 -3
  29. package/dist/runtime/app/pages/triggers/[name]/edit.vue +1 -1
  30. package/package.json +1 -1
@@ -1,83 +1,28 @@
1
1
  <template>
2
2
  <div class="flex flex-col h-full w-full max-w-full min-w-0">
3
3
  <!-- Fixed Header with Run Stats -->
4
- <div class="px-6 py-[17px] border-b border-gray-200 dark:border-gray-800 bg-gray-50 dark:bg-gray-900/50 shrink-0">
5
- <div class="flex items-center justify-between gap-4 text-xs">
6
- <div class="flex items-center gap-4">
7
- <!-- Status -->
8
- <div class="flex items-center gap-1.5">
9
- <div
10
- class="w-1.5 h-1.5 rounded-full"
11
- :class="getStatusColor(runStatus)"
12
- />
13
- <span class="text-gray-700 dark:text-gray-300 font-medium capitalize">
14
- {{ runStatus || "unknown" }}
15
- </span>
16
- </div>
17
-
18
- <!-- Divider -->
19
- <div class="w-px h-3 bg-gray-300 dark:bg-gray-700" />
20
-
21
- <!-- Entry Trigger -->
4
+ <div class="h-[72px] px-6 py-3 border-b border-gray-200 dark:border-gray-800 bg-gray-50 dark:bg-gray-900/50 shrink-0">
5
+ <!-- Top Row: Status and Action -->
6
+ <div class="flex items-center justify-between gap-4 mb-2">
7
+ <div class="flex items-center gap-2">
22
8
  <div
9
+ class="w-2 h-2 rounded-full"
10
+ :class="getStatusColor(runStatus)"
11
+ />
12
+ <span class="text-sm font-semibold text-gray-900 dark:text-gray-100 capitalize">
13
+ {{ runStatus || "unknown" }}
14
+ </span>
15
+ <span
23
16
  v-if="triggerName"
24
- class="flex items-center gap-1.5"
17
+ class="text-xs text-gray-500 dark:text-gray-400 ml-1"
25
18
  >
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
-
38
- <!-- Total Steps -->
39
- <div class="flex items-center gap-1.5">
40
- <UIcon
41
- name="i-lucide-layers"
42
- class="w-3 h-3 text-gray-500"
43
- />
44
- <span class="text-gray-700 dark:text-gray-300">
45
- {{ steps.length }} {{ steps.length === 1 ? "step" : "steps" }}
46
- </span>
47
- </div>
48
-
49
- <!-- Divider -->
50
- <div class="w-px h-3 bg-gray-300 dark:bg-gray-700" />
51
-
52
- <!-- Started -->
53
- <div class="flex items-center gap-1.5">
54
- <UIcon
55
- name="i-lucide-clock"
56
- class="w-3 h-3 text-gray-500"
57
- />
58
- <span class="text-gray-600 dark:text-gray-400">
59
- {{ startedAt ? formatTime(startedAt) : "Not started" }}
60
- </span>
61
- </div>
62
-
63
- <!-- Divider -->
64
- <div class="w-px h-3 bg-gray-300 dark:bg-gray-700" />
65
-
66
- <!-- Duration -->
67
- <div class="flex items-center gap-1.5">
68
- <UIcon
69
- name="i-lucide-timer"
70
- class="w-3 h-3 text-gray-500"
71
- />
72
- <span class="text-gray-600 dark:text-gray-400">
73
- {{ getDuration(startedAt, completedAt) }}
74
- </span>
75
- </div>
19
+ via {{ triggerName }}
20
+ </span>
76
21
  </div>
77
22
 
78
- <!-- Cancel Button (only show for running flows) -->
23
+ <!-- Cancel Button (only show for running/awaiting flows) -->
79
24
  <UButton
80
- v-if="runStatus === 'running'"
25
+ v-if="runStatus === 'running' || runStatus === 'awaiting'"
81
26
  color="neutral"
82
27
  variant="ghost"
83
28
  icon="i-lucide-x-circle"
@@ -86,6 +31,56 @@
86
31
  @click="handleCancelFlow"
87
32
  />
88
33
  </div>
34
+
35
+ <!-- Bottom Row: Compact Stats Grid -->
36
+ <div class="grid grid-cols-2 sm:grid-cols-4 gap-x-4 gap-y-1.5 text-xs">
37
+ <!-- Steps -->
38
+ <div class="flex items-center gap-1.5">
39
+ <UIcon
40
+ name="i-lucide-layers"
41
+ class="w-3.5 h-3.5 text-gray-400"
42
+ />
43
+ <span class="text-gray-600 dark:text-gray-300">
44
+ {{ steps.length }} {{ steps.length === 1 ? "step" : "steps" }}
45
+ </span>
46
+ </div>
47
+
48
+ <!-- Started -->
49
+ <div class="flex items-center gap-1.5">
50
+ <UIcon
51
+ name="i-lucide-clock"
52
+ class="w-3.5 h-3.5 text-gray-400"
53
+ />
54
+ <span class="text-gray-600 dark:text-gray-300">
55
+ {{ startedAt ? formatTime(startedAt) : "Not started" }}
56
+ </span>
57
+ </div>
58
+
59
+ <!-- Duration -->
60
+ <div class="flex items-center gap-1.5">
61
+ <UIcon
62
+ name="i-lucide-timer"
63
+ class="w-3.5 h-3.5 text-gray-400"
64
+ />
65
+ <span class="text-gray-600 dark:text-gray-300">
66
+ {{ getDuration(startedAt, completedAt) }}
67
+ </span>
68
+ </div>
69
+
70
+ <!-- Stall Warning (for running/awaiting flows) -->
71
+ <div
72
+ v-if="(runStatus === 'running' || runStatus === 'awaiting') && stallTimeout"
73
+ class="flex items-center gap-1.5"
74
+ >
75
+ <UIcon
76
+ name="i-lucide-alert-triangle"
77
+ class="w-3.5 h-3.5 text-amber-500"
78
+ />
79
+ <span class="text-gray-600 dark:text-gray-300">
80
+ Stall in {{ formatStallTimeout(startedAt, stallTimeout) }}
81
+ </span>
82
+ </div>
83
+ </div>
89
84
  </div>
90
85
 
91
86
  <!-- Scrollable Steps List -->
@@ -122,14 +117,15 @@ const props = defineProps({
122
117
  runId: { type: String, required: false },
123
118
  triggerName: { type: String, required: false },
124
119
  triggerType: { type: String, required: false },
125
- flowDef: { type: null, required: false }
120
+ flowDef: { type: null, required: false },
121
+ stallTimeout: { type: Number, required: false }
126
122
  });
127
123
  const emit = defineEmits(["select-step", "cancel-flow"]);
128
124
  const handleCancelFlow = () => {
129
125
  emit("cancel-flow");
130
126
  };
131
127
  const selectedStep = ref("all-steps");
132
- const firstStepKey = computed(() => props.steps[0]?.key);
128
+ const firstStepKey = computed(() => props.steps?.length > 0 ? props.steps[0]?.key : void 0);
133
129
  watch(firstStepKey, (newKey, oldKey) => {
134
130
  if (oldKey !== void 0 && newKey !== oldKey) {
135
131
  selectedStep.value = "all-steps";
@@ -248,6 +244,8 @@ const getStatusColor = (status) => {
248
244
  return "bg-red-500";
249
245
  case "running":
250
246
  return "bg-blue-500 animate-pulse";
247
+ case "awaiting":
248
+ return "bg-purple-500 animate-pulse";
251
249
  case "canceled":
252
250
  return "bg-orange-500";
253
251
  case "stalled":
@@ -256,18 +254,19 @@ const getStatusColor = (status) => {
256
254
  return "bg-gray-300";
257
255
  }
258
256
  };
259
- const getTriggerIcon = (type) => {
260
- switch (type) {
261
- case "manual":
262
- return "i-lucide-hand";
263
- case "event":
264
- return "i-lucide-zap";
265
- case "webhook":
266
- return "i-lucide-webhook";
267
- case "schedule":
268
- return "i-lucide-calendar-clock";
269
- default:
270
- return "i-lucide-play-circle";
271
- }
257
+ const formatStallTimeout = (start, timeout) => {
258
+ if (!start || !timeout) return "\u2014";
259
+ const startTime = new Date(start).getTime();
260
+ const stallTime = startTime + timeout;
261
+ const remaining = stallTime - Date.now();
262
+ if (remaining <= 0) return "now";
263
+ const seconds = Math.floor(remaining / 1e3);
264
+ const minutes = Math.floor(seconds / 60);
265
+ const hours = Math.floor(minutes / 60);
266
+ const days = Math.floor(hours / 24);
267
+ if (days > 0) return `${days}d ${hours % 24}h`;
268
+ if (hours > 0) return `${hours}h ${minutes % 60}m`;
269
+ if (minutes > 0) return `${minutes}m`;
270
+ return `${seconds}s`;
272
271
  };
273
272
  </script>
@@ -8,6 +8,7 @@ type __VLS_Props = {
8
8
  triggerName?: string;
9
9
  triggerType?: 'manual' | 'event' | 'webhook' | 'schedule';
10
10
  flowDef?: any;
11
+ stallTimeout?: number;
11
12
  };
12
13
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
13
14
  "select-step": (stepKey: string | null) => any;
@@ -1,36 +1,65 @@
1
1
  <template>
2
2
  <div class="flex flex-col h-full">
3
3
  <!-- Filter Bar -->
4
- <div class="flex items-center gap-3 px-6 py-3 border-b border-gray-200 dark:border-gray-800 bg-gray-50 dark:bg-gray-900/50 shrink-0">
5
- <div class="flex items-center gap-2">
6
- <span class="text-xs font-medium text-gray-700 dark:text-gray-300">Show:</span>
7
- <URadioGroup
8
- v-model="filter"
9
- :items="filterOptions"
10
- orientation="horizontal"
11
- size="xs"
12
- variant="table"
13
- indicator="hidden"
14
- :ui="{
15
- base: 'size-2',
16
- container: 'h-2',
17
- item: 'p-1'
18
- }"
19
- />
20
- </div>
4
+ <div class="h-[72px] px-6 py-3 border-b border-gray-200 dark:border-gray-800 bg-gray-50 dark:bg-gray-900/50 shrink-0">
5
+ <!-- Top Row: Title and Action -->
6
+ <div class="flex items-center justify-between gap-4 mb-2">
7
+ <div class="flex items-center gap-2">
8
+ <UIcon
9
+ name="i-lucide-activity"
10
+ class="w-4 h-4 text-gray-400"
11
+ />
12
+ <span class="text-sm font-semibold text-gray-900 dark:text-gray-100">
13
+ Timeline & Logs
14
+ </span>
15
+ <span
16
+ v-if="isLive"
17
+ class="flex items-center gap-1.5 ml-2"
18
+ >
19
+ <div class="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse" />
20
+ <span class="text-xs text-gray-500 dark:text-gray-400">Live</span>
21
+ </span>
22
+ </div>
21
23
 
22
- <div class="flex items-center gap-2 ml-auto">
23
24
  <UButton
24
25
  size="xs"
25
26
  color="neutral"
26
- variant="outline"
27
+ variant="ghost"
28
+ icon="i-lucide-download"
27
29
  :disabled="filteredItems.length === 0"
28
30
  @click="$emit('export')"
29
31
  >
30
- Export JSON
32
+ Export
31
33
  </UButton>
32
- <div class="text-xs text-gray-500">
33
- {{ filteredItems.length }} item{{ filteredItems.length === 1 ? "" : "s" }}
34
+ </div>
35
+
36
+ <!-- Bottom Row: Filter and Count -->
37
+ <div class="flex items-center justify-between gap-4 text-[11px]">
38
+ <div class="flex items-center gap-1.5">
39
+ <span class="text-gray-500 dark:text-gray-400">Filter:</span>
40
+ <URadioGroup
41
+ v-model="filter"
42
+ :items="filterOptions"
43
+ orientation="horizontal"
44
+ size="xs"
45
+ variant="table"
46
+ indicator="hidden"
47
+ :ui="{
48
+ base: 'text-[9px]',
49
+ container: 'gap-0',
50
+ item: 'px-1 py-0'
51
+ }"
52
+ />
53
+ </div>
54
+
55
+ <div class="flex items-center gap-1.5">
56
+ <UIcon
57
+ name="i-lucide-list"
58
+ class="w-3.5 h-3.5 text-gray-400"
59
+ />
60
+ <span class="text-gray-600 dark:text-gray-300">
61
+ {{ filteredItems.length }} {{ filteredItems.length === 1 ? "item" : "items" }}
62
+ </span>
34
63
  </div>
35
64
  </div>
36
65
  </div>
@@ -78,6 +78,18 @@
78
78
  >
79
79
  {{ getAwaitPosition(item.step.key) }}
80
80
  </UBadge>
81
+ <!-- Step Timeout Badge (only for regular steps, not await steps) -->
82
+ <span
83
+ v-if="item.step.stepTimeout && !isAwaitStep(item.step.key)"
84
+ class="flex items-center gap-1"
85
+ :title="`Step Execution Timeout: ${formatDuration(item.step.stepTimeout)}`"
86
+ >
87
+ <UIcon
88
+ name="i-lucide-hourglass"
89
+ class="w-3 h-3 opacity-60"
90
+ />
91
+ <span>{{ formatDuration(item.step.stepTimeout) }}</span>
92
+ </span>
81
93
  </div>
82
94
  <div
83
95
  v-else
@@ -141,7 +153,7 @@
141
153
 
142
154
  <!-- Await Config Details -->
143
155
  <div
144
- v-if="item.step.awaitType"
156
+ v-if="item.step.awaitType && (item.step.awaitConfig || item.step.awaitData)"
145
157
  class="mt-2 p-2.5 rounded-md border"
146
158
  :class="getAwaitConfigBgClass(item.step.status)"
147
159
  >
@@ -165,119 +177,174 @@
165
177
  <div class="space-y-1.5 text-xs">
166
178
  <!-- Webhook specific -->
167
179
  <div
168
- v-if="item.step.awaitType === 'webhook' && item.step.awaitConfig"
180
+ v-if="item.step.awaitType === 'webhook'"
169
181
  class="space-y-1"
170
182
  >
171
183
  <div
172
- v-if="item.step.awaitConfig.method"
184
+ v-if="item.step.awaitConfig?.method || item.step.awaitData?.method"
173
185
  class="flex items-center gap-1.5"
174
186
  >
175
187
  <UIcon
176
- name="i-lucide-route"
188
+ name="i-lucide-git-branch"
177
189
  class="w-3 h-3 opacity-60"
178
190
  />
179
191
  <span class="opacity-75">Method:</span>
180
192
  <UBadge
181
193
  size="xs"
182
- :color="getMethodBadgeColor(item.step.awaitConfig.method)"
194
+ :color="getMethodBadgeColor(item.step.awaitData?.method || item.step.awaitConfig?.method)"
183
195
  variant="subtle"
184
196
  >
185
- {{ item.step.awaitConfig.method }}
197
+ {{ item.step.awaitData?.method || item.step.awaitConfig?.method }}
186
198
  </UBadge>
187
199
  </div>
188
200
  <div
189
- v-if="item.step.awaitConfig.path"
201
+ v-if="item.step.awaitData?.webhookUrl"
190
202
  class="flex items-start gap-1.5"
191
203
  >
192
204
  <UIcon
193
205
  name="i-lucide-link"
194
206
  class="w-3 h-3 opacity-60 mt-0.5"
195
207
  />
196
- <span class="opacity-75">Path:</span>
197
- <code class="px-1.5 py-0.5 bg-black/5 dark:bg-white/5 rounded text-[10px] flex-1">{{ item.step.awaitConfig.path }}</code>
198
- </div>
199
- <div
200
- v-if="item.step.webhookUrl"
201
- class="flex items-start gap-1.5 pt-1"
202
- >
203
- <UIcon
204
- name="i-lucide-globe"
205
- class="w-3 h-3 opacity-60 mt-1"
206
- />
207
- <span class="opacity-75 mt-0.5">URL:</span>
208
+ <span class="opacity-75">URL:</span>
208
209
  <div class="flex-1 flex items-start gap-1">
209
- <code class="px-1.5 py-0.5 bg-black/5 dark:bg-white/5 rounded text-[10px] flex-1 break-all">{{ item.step.webhookUrl }}</code>
210
+ <code class="px-1.5 py-0.5 bg-black/5 dark:bg-white/5 rounded text-[10px] flex-1 break-all">{{ item.step.awaitData.webhookUrl }}</code>
210
211
  <button
211
212
  type="button"
212
213
  class="flex-shrink-0 p-1 hover:bg-black/5 dark:hover:bg-white/5 rounded transition-colors"
213
- :title="copiedUrl === item.step.webhookUrl ? 'Copied!' : 'Copy URL'"
214
- @click.stop="copyToClipboard(item.step.webhookUrl)"
214
+ :title="copiedUrl === item.step.awaitData.webhookUrl ? 'Copied!' : 'Copy URL'"
215
+ @click.stop="copyToClipboard(item.step.awaitData.webhookUrl)"
215
216
  >
216
217
  <UIcon
217
- :name="copiedUrl === item.step.webhookUrl ? 'i-lucide-check' : 'i-lucide-copy'"
218
+ :name="copiedUrl === item.step.awaitData.webhookUrl ? 'i-lucide-check' : 'i-lucide-copy'"
218
219
  class="w-3 h-3"
219
- :class="copiedUrl === item.step.webhookUrl ? 'text-emerald-600 dark:text-emerald-400' : 'opacity-60'"
220
+ :class="copiedUrl === item.step.awaitData.webhookUrl ? 'text-emerald-600 dark:text-emerald-400' : 'opacity-60'"
220
221
  />
221
222
  </button>
222
223
  </div>
223
224
  </div>
225
+ <div
226
+ v-else-if="item.step.awaitConfig?.path"
227
+ class="flex items-start gap-1.5"
228
+ >
229
+ <UIcon
230
+ name="i-lucide-route"
231
+ class="w-3 h-3 opacity-60 mt-0.5"
232
+ />
233
+ <span class="opacity-75">Path:</span>
234
+ <code class="px-1.5 py-0.5 bg-black/5 dark:bg-white/5 rounded text-[10px] flex-1">{{ item.step.awaitConfig.path }}</code>
235
+ </div>
224
236
  </div>
225
237
 
226
238
  <!-- Event specific -->
227
239
  <div
228
- v-if="item.step.awaitType === 'event' && item.step.awaitConfig?.event"
229
- class="flex items-center gap-1.5"
240
+ v-if="item.step.awaitType === 'event'"
241
+ class="space-y-1"
230
242
  >
231
- <UIcon
232
- name="i-lucide-radio"
233
- class="w-3 h-3 opacity-60"
234
- />
235
- <span class="opacity-75">Event:</span>
236
- <code class="px-1.5 py-0.5 bg-black/5 dark:bg-white/5 rounded text-xs">{{ item.step.awaitConfig.event }}</code>
243
+ <div
244
+ v-if="item.step.awaitConfig?.event || item.step.awaitData?.eventName"
245
+ class="flex items-center gap-1.5"
246
+ >
247
+ <UIcon
248
+ name="i-lucide-zap"
249
+ class="w-3 h-3 opacity-60"
250
+ />
251
+ <span class="opacity-75">Event:</span>
252
+ <code class="px-1.5 py-0.5 bg-black/5 dark:bg-white/5 rounded text-[10px]">{{ item.step.awaitData?.eventName || item.step.awaitConfig?.event }}</code>
253
+ </div>
254
+ <div
255
+ v-if="item.step.awaitConfig?.filterKey || item.step.awaitData?.filterKey"
256
+ class="flex items-center gap-1.5"
257
+ >
258
+ <UIcon
259
+ name="i-lucide-filter"
260
+ class="w-3 h-3 opacity-60"
261
+ />
262
+ <span class="opacity-75">Filter:</span>
263
+ <code class="px-1.5 py-0.5 bg-black/5 dark:bg-white/5 rounded text-[10px]">{{ item.step.awaitData?.filterKey || item.step.awaitConfig?.filterKey }}</code>
264
+ </div>
237
265
  </div>
238
266
 
239
267
  <!-- Time specific -->
240
268
  <div
241
269
  v-if="item.step.awaitType === 'time' && item.step.awaitConfig?.delay"
242
- class="flex items-center gap-1.5"
270
+ class="space-y-1"
243
271
  >
244
- <UIcon
245
- name="i-lucide-hourglass"
246
- class="w-3 h-3 opacity-60"
247
- />
248
- <span class="opacity-75">Delay:</span>
249
- <span class="font-medium">{{ formatDuration(item.step.awaitConfig.delay) }}</span>
272
+ <div class="flex items-center gap-1.5">
273
+ <UIcon
274
+ name="i-lucide-timer"
275
+ class="w-3 h-3 opacity-60"
276
+ />
277
+ <span class="opacity-75">Delay:</span>
278
+ <span class="font-medium">{{ formatDuration(item.step.awaitConfig.delay) }}</span>
279
+ </div>
280
+ <div
281
+ v-if="item.step.scheduledTriggerAt"
282
+ class="flex items-center gap-1.5"
283
+ >
284
+ <UIcon
285
+ name="i-lucide-calendar-clock"
286
+ class="w-3 h-3 opacity-60"
287
+ />
288
+ <span class="opacity-75">Triggers at:</span>
289
+ <span class="font-medium">{{ formatScheduledTime(item.step.scheduledTriggerAt) }}</span>
290
+ </div>
291
+ </div>
292
+
293
+ <!-- Schedule specific -->
294
+ <div
295
+ v-if="item.step.awaitType === 'schedule' && item.step.awaitConfig?.cron"
296
+ class="space-y-1"
297
+ >
298
+ <div class="flex items-center gap-1.5">
299
+ <UIcon
300
+ name="i-lucide-calendar-cog"
301
+ class="w-3 h-3 opacity-60"
302
+ />
303
+ <span class="opacity-75">Cron:</span>
304
+ <code class="px-1.5 py-0.5 bg-black/5 dark:bg-white/5 rounded text-[10px]">{{ item.step.awaitConfig.cron }}</code>
305
+ </div>
306
+ <div
307
+ v-if="item.step.scheduledTriggerAt"
308
+ class="flex items-center gap-1.5"
309
+ >
310
+ <UIcon
311
+ name="i-lucide-calendar-check"
312
+ class="w-3 h-3 opacity-60"
313
+ />
314
+ <span class="opacity-75">Next trigger:</span>
315
+ <span class="font-medium">{{ formatScheduledTime(item.step.scheduledTriggerAt) }}</span>
316
+ </div>
250
317
  </div>
251
318
 
252
319
  <!-- Timeout -->
253
320
  <div
254
- v-if="item.step.awaitConfig?.timeout"
321
+ v-if="item.step.awaitConfig?.timeout || item.step.awaitData?.timeout"
255
322
  class="flex items-center gap-1.5"
256
323
  >
257
324
  <UIcon
258
- name="i-lucide-clock-alert"
325
+ name="i-lucide-hourglass"
259
326
  class="w-3 h-3 opacity-60"
260
327
  />
261
328
  <span class="opacity-75">Timeout:</span>
262
- <span class="font-medium">{{ formatDuration(item.step.awaitConfig.timeout) }}</span>
329
+ <span class="font-medium">{{ formatDuration(item.step.awaitData?.timeout || item.step.awaitConfig?.timeout) }}</span>
263
330
  </div>
264
331
 
265
332
  <!-- Timeout Action -->
266
333
  <div
267
- v-if="item.step.awaitConfig?.timeoutAction"
334
+ v-if="item.step.awaitConfig?.timeoutAction || item.step.awaitData?.timeoutAction"
268
335
  class="flex items-center gap-1.5"
269
336
  >
270
337
  <UIcon
271
- name="i-lucide-zap"
338
+ name="i-lucide-shield-alert"
272
339
  class="w-3 h-3 opacity-60"
273
340
  />
274
341
  <span class="opacity-75">On Timeout:</span>
275
342
  <UBadge
276
343
  size="xs"
277
- :color="getTimeoutActionColor(item.step.awaitConfig.timeoutAction)"
344
+ :color="getTimeoutActionColor(item.step.awaitData?.timeoutAction || item.step.awaitConfig?.timeoutAction)"
278
345
  variant="subtle"
279
346
  >
280
- {{ item.step.awaitConfig.timeoutAction }}
347
+ {{ item.step.awaitData?.timeoutAction || item.step.awaitConfig?.timeoutAction }}
281
348
  </UBadge>
282
349
  </div>
283
350
  </div>
@@ -549,4 +616,15 @@ const formatDuration = (ms) => {
549
616
  }
550
617
  return `${seconds}s`;
551
618
  };
619
+ const formatScheduledTime = (timestamp) => {
620
+ const date = new Date(timestamp);
621
+ if (Number.isNaN(date.getTime())) return "No schedule";
622
+ return date.toLocaleString(void 0, {
623
+ month: "short",
624
+ day: "numeric",
625
+ hour: "2-digit",
626
+ minute: "2-digit",
627
+ timeZoneName: "short"
628
+ });
629
+ };
552
630
  </script>
@@ -19,11 +19,13 @@ export declare function useFlowRunTimeline(flowId: Ref<string>, runId: Ref<strin
19
19
  isFailed: import("vue").ComputedRef<boolean>;
20
20
  isCanceled: import("vue").ComputedRef<boolean>;
21
21
  isStalled: import("vue").ComputedRef<boolean>;
22
+ isAwaiting: import("vue").ComputedRef<boolean>;
22
23
  stepList: import("vue").ComputedRef<{
23
24
  status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout";
24
25
  attempt: number;
25
26
  startedAt?: string;
26
27
  completedAt?: string;
28
+ scheduledTriggerAt?: string;
27
29
  error?: string;
28
30
  awaitType?: "time" | "event" | "trigger";
29
31
  awaitData?: any;
@@ -35,6 +37,7 @@ export declare function useFlowRunTimeline(flowId: Ref<string>, runId: Ref<strin
35
37
  attempt: number;
36
38
  startedAt?: string;
37
39
  completedAt?: string;
40
+ scheduledTriggerAt?: string;
38
41
  error?: string;
39
42
  awaitType?: "time" | "event" | "trigger";
40
43
  awaitData?: any;
@@ -46,6 +49,7 @@ export declare function useFlowRunTimeline(flowId: Ref<string>, runId: Ref<strin
46
49
  attempt: number;
47
50
  startedAt?: string;
48
51
  completedAt?: string;
52
+ scheduledTriggerAt?: string;
49
53
  error?: string;
50
54
  awaitType?: "time" | "event" | "trigger";
51
55
  awaitData?: any;
@@ -57,6 +61,7 @@ export declare function useFlowRunTimeline(flowId: Ref<string>, runId: Ref<strin
57
61
  attempt: number;
58
62
  startedAt?: string;
59
63
  completedAt?: string;
64
+ scheduledTriggerAt?: string;
60
65
  error?: string;
61
66
  awaitType?: "time" | "event" | "trigger";
62
67
  awaitData?: any;
@@ -68,6 +73,7 @@ export declare function useFlowRunTimeline(flowId: Ref<string>, runId: Ref<strin
68
73
  attempt: number;
69
74
  startedAt?: string;
70
75
  completedAt?: string;
76
+ scheduledTriggerAt?: string;
71
77
  error?: string;
72
78
  awaitType?: "time" | "event" | "trigger";
73
79
  awaitData?: any;