@nvent-addon/app 0.5.6 → 0.5.8

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.
package/dist/module.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nventapp",
3
- "version": "0.5.6",
3
+ "version": "0.5.8",
4
4
  "configKey": "nventapp",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
@@ -42,7 +42,7 @@ interface FlowMeta {
42
42
  };
43
43
  }
44
44
  interface StepStatus {
45
- status: 'pending' | 'running' | 'completed' | 'failed' | 'retrying' | 'waiting' | 'timeout' | 'canceled';
45
+ status: 'pending' | 'running' | 'completed' | 'failed' | 'retrying' | 'waiting' | 'timeout' | 'canceled' | 'stalled';
46
46
  attempt?: number;
47
47
  error?: string;
48
48
  scheduledTriggerAt?: string;
@@ -306,6 +306,7 @@ function mapStatusToNodeStatus(status) {
306
306
  return "done";
307
307
  case "failed":
308
308
  case "timeout":
309
+ case "stalled":
309
310
  return "error";
310
311
  case "canceled":
311
312
  return "canceled";
@@ -42,7 +42,7 @@ interface FlowMeta {
42
42
  };
43
43
  }
44
44
  interface StepStatus {
45
- status: 'pending' | 'running' | 'completed' | 'failed' | 'retrying' | 'waiting' | 'timeout' | 'canceled';
45
+ status: 'pending' | 'running' | 'completed' | 'failed' | 'retrying' | 'waiting' | 'timeout' | 'canceled' | 'stalled';
46
46
  attempt?: number;
47
47
  error?: string;
48
48
  scheduledTriggerAt?: string;
@@ -13,9 +13,11 @@ type __VLS_Props = {
13
13
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
14
14
  "select-step": (stepKey: string | null) => any;
15
15
  "cancel-flow": () => any;
16
+ "restart-flow": () => any;
16
17
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
17
18
  "onSelect-step"?: ((stepKey: string | null) => any) | undefined;
18
19
  "onCancel-flow"?: (() => any) | undefined;
20
+ "onRestart-flow"?: (() => any) | undefined;
19
21
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
20
22
  declare const _default: typeof __VLS_export;
21
23
  export default _default;
@@ -21,15 +21,27 @@
21
21
  </div>
22
22
 
23
23
  <!-- Cancel Button (only show for running/awaiting flows) -->
24
- <UButton
25
- v-if="runStatus === 'running' || runStatus === 'awaiting'"
26
- color="neutral"
27
- variant="ghost"
28
- icon="i-lucide-x-circle"
29
- size="xs"
30
- label="Cancel"
31
- @click="handleCancelFlow"
32
- />
24
+ <div class="flex items-center gap-2">
25
+ <UButton
26
+ v-if="runStatus === 'running' || runStatus === 'awaiting'"
27
+ color="neutral"
28
+ variant="ghost"
29
+ icon="i-lucide-x-circle"
30
+ size="xs"
31
+ label="Cancel"
32
+ @click="handleCancelFlow"
33
+ />
34
+ <!-- Restart Button (show for terminal states) -->
35
+ <UButton
36
+ v-if="runStatus === 'failed' || runStatus === 'stalled' || runStatus === 'canceled' || runStatus === 'completed'"
37
+ color="primary"
38
+ variant="ghost"
39
+ icon="i-lucide-rotate-ccw"
40
+ size="xs"
41
+ label="Restart"
42
+ @click="handleRestartFlow"
43
+ />
44
+ </div>
33
45
  </div>
34
46
 
35
47
  <!-- Bottom Row: Compact Stats Grid -->
@@ -120,10 +132,13 @@ const props = defineProps({
120
132
  flowDef: { type: null, required: false },
121
133
  stallTimeout: { type: Number, required: false }
122
134
  });
123
- const emit = defineEmits(["select-step", "cancel-flow"]);
135
+ const emit = defineEmits(["select-step", "cancel-flow", "restart-flow"]);
124
136
  const handleCancelFlow = () => {
125
137
  emit("cancel-flow");
126
138
  };
139
+ const handleRestartFlow = () => {
140
+ emit("restart-flow");
141
+ };
127
142
  const selectedStep = ref("all-steps");
128
143
  const firstStepKey = computed(() => props.steps?.length > 0 ? props.steps[0]?.key : void 0);
129
144
  watch(firstStepKey, (newKey, oldKey) => {
@@ -13,9 +13,11 @@ type __VLS_Props = {
13
13
  declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
14
14
  "select-step": (stepKey: string | null) => any;
15
15
  "cancel-flow": () => any;
16
+ "restart-flow": () => any;
16
17
  }, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
17
18
  "onSelect-step"?: ((stepKey: string | null) => any) | undefined;
18
19
  "onCancel-flow"?: (() => any) | undefined;
20
+ "onRestart-flow"?: (() => any) | undefined;
19
21
  }>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
20
22
  declare const _default: typeof __VLS_export;
21
23
  export default _default;
@@ -438,6 +438,8 @@ const getStepStatusBg = (status) => {
438
438
  return "bg-emerald-50 dark:bg-emerald-900/20";
439
439
  case "failed":
440
440
  return "bg-red-50 dark:bg-red-900/20";
441
+ case "stalled":
442
+ return "bg-amber-50 dark:bg-amber-900/20";
441
443
  case "running":
442
444
  return "bg-blue-50 dark:bg-blue-900/20";
443
445
  default:
@@ -450,6 +452,8 @@ const getStepStatusIcon = (status) => {
450
452
  return "i-lucide-check-circle";
451
453
  case "failed":
452
454
  return "i-lucide-x-circle";
455
+ case "stalled":
456
+ return "i-lucide-alert-triangle";
453
457
  case "running":
454
458
  return "i-lucide-loader-circle";
455
459
  default:
@@ -462,6 +466,8 @@ const getStepStatusIconColor = (status) => {
462
466
  return "text-emerald-600 dark:text-emerald-400";
463
467
  case "failed":
464
468
  return "text-red-600 dark:text-red-400";
469
+ case "stalled":
470
+ return "text-amber-600 dark:text-amber-400";
465
471
  case "running":
466
472
  return "text-blue-600 dark:text-blue-400 animate-spin";
467
473
  default:
@@ -474,6 +480,8 @@ const getStepStatusTextColor = (status) => {
474
480
  return "text-emerald-600 dark:text-emerald-400";
475
481
  case "failed":
476
482
  return "text-red-600 dark:text-red-400";
483
+ case "stalled":
484
+ return "text-amber-600 dark:text-amber-400";
477
485
  case "running":
478
486
  return "text-blue-600 dark:text-blue-400";
479
487
  default:
@@ -21,7 +21,7 @@ export declare function useFlowRunTimeline(flowId: Ref<string>, runId: Ref<strin
21
21
  isStalled: import("vue").ComputedRef<boolean>;
22
22
  isAwaiting: import("vue").ComputedRef<boolean>;
23
23
  stepList: import("vue").ComputedRef<{
24
- status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout";
24
+ status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout" | "stalled";
25
25
  attempt: number;
26
26
  startedAt?: string;
27
27
  completedAt?: string;
@@ -33,7 +33,7 @@ export declare function useFlowRunTimeline(flowId: Ref<string>, runId: Ref<strin
33
33
  key: string;
34
34
  }[]>;
35
35
  runningSteps: import("vue").ComputedRef<{
36
- status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout";
36
+ status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout" | "stalled";
37
37
  attempt: number;
38
38
  startedAt?: string;
39
39
  completedAt?: string;
@@ -45,7 +45,7 @@ export declare function useFlowRunTimeline(flowId: Ref<string>, runId: Ref<strin
45
45
  key: string;
46
46
  }[]>;
47
47
  waitingSteps: import("vue").ComputedRef<{
48
- status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout";
48
+ status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout" | "stalled";
49
49
  attempt: number;
50
50
  startedAt?: string;
51
51
  completedAt?: string;
@@ -57,7 +57,7 @@ export declare function useFlowRunTimeline(flowId: Ref<string>, runId: Ref<strin
57
57
  key: string;
58
58
  }[]>;
59
59
  failedSteps: import("vue").ComputedRef<{
60
- status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout";
60
+ status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout" | "stalled";
61
61
  attempt: number;
62
62
  startedAt?: string;
63
63
  completedAt?: string;
@@ -69,7 +69,7 @@ export declare function useFlowRunTimeline(flowId: Ref<string>, runId: Ref<strin
69
69
  key: string;
70
70
  }[]>;
71
71
  completedSteps: import("vue").ComputedRef<{
72
- status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout";
72
+ status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout" | "stalled";
73
73
  attempt: number;
74
74
  startedAt?: string;
75
75
  completedAt?: string;
@@ -13,7 +13,7 @@ export interface FlowState {
13
13
  meta?: Record<string, any>;
14
14
  }
15
15
  export interface StepState {
16
- status: 'pending' | 'running' | 'completed' | 'failed' | 'retrying' | 'waiting' | 'timeout';
16
+ status: 'pending' | 'running' | 'completed' | 'failed' | 'retrying' | 'waiting' | 'timeout' | 'stalled';
17
17
  attempt: number;
18
18
  startedAt?: string;
19
19
  completedAt?: string;
@@ -72,7 +72,7 @@ export declare function useFlowState(initialEvents?: EventRecord[]): {
72
72
  isStalled: import("vue").ComputedRef<boolean>;
73
73
  isAwaiting: import("vue").ComputedRef<boolean>;
74
74
  stepList: import("vue").ComputedRef<{
75
- status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout";
75
+ status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout" | "stalled";
76
76
  attempt: number;
77
77
  startedAt?: string;
78
78
  completedAt?: string;
@@ -84,7 +84,7 @@ export declare function useFlowState(initialEvents?: EventRecord[]): {
84
84
  key: string;
85
85
  }[]>;
86
86
  runningSteps: import("vue").ComputedRef<{
87
- status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout";
87
+ status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout" | "stalled";
88
88
  attempt: number;
89
89
  startedAt?: string;
90
90
  completedAt?: string;
@@ -96,7 +96,7 @@ export declare function useFlowState(initialEvents?: EventRecord[]): {
96
96
  key: string;
97
97
  }[]>;
98
98
  waitingSteps: import("vue").ComputedRef<{
99
- status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout";
99
+ status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout" | "stalled";
100
100
  attempt: number;
101
101
  startedAt?: string;
102
102
  completedAt?: string;
@@ -108,7 +108,7 @@ export declare function useFlowState(initialEvents?: EventRecord[]): {
108
108
  key: string;
109
109
  }[]>;
110
110
  failedSteps: import("vue").ComputedRef<{
111
- status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout";
111
+ status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout" | "stalled";
112
112
  attempt: number;
113
113
  startedAt?: string;
114
114
  completedAt?: string;
@@ -120,7 +120,7 @@ export declare function useFlowState(initialEvents?: EventRecord[]): {
120
120
  key: string;
121
121
  }[]>;
122
122
  completedSteps: import("vue").ComputedRef<{
123
- status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout";
123
+ status: "pending" | "running" | "completed" | "failed" | "retrying" | "waiting" | "timeout" | "stalled";
124
124
  attempt: number;
125
125
  startedAt?: string;
126
126
  completedAt?: string;
@@ -94,6 +94,16 @@ export function reduceFlowState(events) {
94
94
  state.steps[stepKey].error = e.data?.error;
95
95
  break;
96
96
  }
97
+ case "step.stalled": {
98
+ if (!stepKey) break;
99
+ if (!state.steps[stepKey]) {
100
+ state.steps[stepKey] = { status: "stalled", attempt: 1 };
101
+ }
102
+ state.steps[stepKey].status = "stalled";
103
+ state.steps[stepKey].error = e.data?.reason || "Step execution interrupted";
104
+ state.steps[stepKey].completedAt = e.ts;
105
+ break;
106
+ }
97
107
  case "step.await.time":
98
108
  case "step.await.event":
99
109
  case "step.await.trigger": {
@@ -297,6 +297,7 @@
297
297
  :stall-timeout="runSnapshot.stallTimeout"
298
298
  @select-step="handleSelectStep"
299
299
  @cancel-flow="handleCancelFlow"
300
+ @restart-flow="handleRestartFlow"
300
301
  />
301
302
  </div>
302
303
  </div>
@@ -593,6 +594,21 @@ const handleCancelFlow = async () => {
593
594
  console.error("Failed to cancel flow:", error);
594
595
  }
595
596
  };
597
+ const handleRestartFlow = async () => {
598
+ if (!selectedFlow.value || !selectedRunId.value) return;
599
+ try {
600
+ const result = await $fetch(`/api/_flows/${selectedFlow.value}/runs/${selectedRunId.value}/restart`, {
601
+ method: "POST"
602
+ });
603
+ if (result?.newRunId) {
604
+ selectedRunId.value = result.newRunId;
605
+ mainTab.value = "timeline";
606
+ }
607
+ await refreshRuns();
608
+ } catch (error) {
609
+ console.error("Failed to restart flow:", error);
610
+ }
611
+ };
596
612
  const diagramStepStates = computed(() => {
597
613
  if (!selectedRunId.value) return void 0;
598
614
  return flowState.state.value.steps;
@@ -273,19 +273,17 @@ function updateFlowStats(data) {
273
273
  running: metadata["stats.running"] || 0,
274
274
  awaiting: metadata["stats.awaiting"] || 0
275
275
  };
276
- flows.value[flowIndex] = {
277
- ...flows.value[flowIndex],
278
- stats: {
279
- total: stats.total || 0,
280
- success: stats.success || 0,
281
- failure: stats.failure || 0,
282
- cancel: stats.cancel || 0,
283
- running: stats.running || 0,
284
- awaiting: stats.awaiting || 0
285
- },
286
- lastRunAt: metadata.lastRunAt,
287
- lastCompletedAt: metadata.lastCompletedAt
276
+ const flow = flows.value[flowIndex];
277
+ flow.stats = {
278
+ total: stats.total || 0,
279
+ success: stats.success || 0,
280
+ failure: stats.failure || 0,
281
+ cancel: stats.cancel || 0,
282
+ running: stats.running || 0,
283
+ awaiting: stats.awaiting || 0
288
284
  };
285
+ flow.lastRunAt = metadata.lastRunAt;
286
+ flow.lastCompletedAt = metadata.lastCompletedAt;
289
287
  }
290
288
  onMounted(async () => {
291
289
  await fetchAnalyzedFlows();
@@ -351,6 +351,7 @@ function updateTriggerStats(data) {
351
351
  }
352
352
  onMounted(async () => {
353
353
  await fetchTriggers();
354
+ loading.value = false;
354
355
  if (import.meta.client) {
355
356
  triggerWs.subscribeStats(
356
357
  {
@@ -363,9 +364,6 @@ onMounted(async () => {
363
364
  },
364
365
  {
365
366
  autoReconnect: true,
366
- onOpen: () => {
367
- loading.value = false;
368
- },
369
367
  onError: (err) => {
370
368
  console.error("[Trigger Stats] Error:", err);
371
369
  }
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,21 @@
1
+ import { defineEventHandler, getRouterParam, createError, useFlow } from "#imports";
2
+ export default defineEventHandler(async (event) => {
3
+ const flowName = getRouterParam(event, "name");
4
+ const runId = getRouterParam(event, "runId");
5
+ if (!flowName || !runId) {
6
+ throw createError({
7
+ statusCode: 400,
8
+ statusMessage: "Flow name and run ID are required"
9
+ });
10
+ }
11
+ const flowEngine = useFlow();
12
+ try {
13
+ const result = await flowEngine.restartFlow(flowName, runId);
14
+ return result;
15
+ } catch (error) {
16
+ throw createError({
17
+ statusCode: 500,
18
+ statusMessage: `Failed to restart flow: ${error.message}`
19
+ });
20
+ }
21
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nvent-addon/app",
3
- "version": "0.5.6",
3
+ "version": "0.5.8",
4
4
  "description": "nvent app module for Nuxt.js",
5
5
  "repository": "DevJoghurt/nvent",
6
6
  "license": "MIT",