@nvent-addon/app 0.4.5
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.d.mts +6 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +42 -0
- package/dist/runtime/app/assets/vueflow.css +1 -0
- package/dist/runtime/app/components/ConfirmDialog.d.vue.ts +33 -0
- package/dist/runtime/app/components/ConfirmDialog.vue +121 -0
- package/dist/runtime/app/components/ConfirmDialog.vue.d.ts +33 -0
- package/dist/runtime/app/components/FlowDiagram.d.vue.ts +65 -0
- package/dist/runtime/app/components/FlowDiagram.vue +341 -0
- package/dist/runtime/app/components/FlowDiagram.vue.d.ts +65 -0
- package/dist/runtime/app/components/FlowNodeCard.d.vue.ts +29 -0
- package/dist/runtime/app/components/FlowNodeCard.vue +158 -0
- package/dist/runtime/app/components/FlowNodeCard.vue.d.ts +29 -0
- package/dist/runtime/app/components/FlowRunOverview.d.vue.ts +17 -0
- package/dist/runtime/app/components/FlowRunOverview.vue +188 -0
- package/dist/runtime/app/components/FlowRunOverview.vue.d.ts +17 -0
- package/dist/runtime/app/components/FlowRunStatusBadge.d.vue.ts +18 -0
- package/dist/runtime/app/components/FlowRunStatusBadge.vue +74 -0
- package/dist/runtime/app/components/FlowRunStatusBadge.vue.d.ts +18 -0
- package/dist/runtime/app/components/FlowRunTimeline.d.vue.ts +12 -0
- package/dist/runtime/app/components/FlowRunTimeline.vue +127 -0
- package/dist/runtime/app/components/FlowRunTimeline.vue.d.ts +12 -0
- package/dist/runtime/app/components/FlowScheduleDialog.d.vue.ts +16 -0
- package/dist/runtime/app/components/FlowScheduleDialog.vue +226 -0
- package/dist/runtime/app/components/FlowScheduleDialog.vue.d.ts +16 -0
- package/dist/runtime/app/components/FlowSchedulesList.d.vue.ts +12 -0
- package/dist/runtime/app/components/FlowSchedulesList.vue +99 -0
- package/dist/runtime/app/components/FlowSchedulesList.vue.d.ts +12 -0
- package/dist/runtime/app/components/FlowStepSelector.d.vue.ts +22 -0
- package/dist/runtime/app/components/FlowStepSelector.vue +238 -0
- package/dist/runtime/app/components/FlowStepSelector.vue.d.ts +22 -0
- package/dist/runtime/app/components/JobScheduling.d.vue.ts +6 -0
- package/dist/runtime/app/components/JobScheduling.vue +203 -0
- package/dist/runtime/app/components/JobScheduling.vue.d.ts +6 -0
- package/dist/runtime/app/components/ListItem.d.vue.ts +23 -0
- package/dist/runtime/app/components/ListItem.vue +70 -0
- package/dist/runtime/app/components/ListItem.vue.d.ts +23 -0
- package/dist/runtime/app/components/QueueConfigDetails.d.vue.ts +45 -0
- package/dist/runtime/app/components/QueueConfigDetails.vue +412 -0
- package/dist/runtime/app/components/QueueConfigDetails.vue.d.ts +45 -0
- package/dist/runtime/app/components/StatCounter.d.vue.ts +9 -0
- package/dist/runtime/app/components/StatCounter.vue +25 -0
- package/dist/runtime/app/components/StatCounter.vue.d.ts +9 -0
- package/dist/runtime/app/components/TimelineList.d.vue.ts +7 -0
- package/dist/runtime/app/components/TimelineList.vue +211 -0
- package/dist/runtime/app/components/TimelineList.vue.d.ts +7 -0
- package/dist/runtime/app/components/nhealth/component-router.d.vue.ts +46 -0
- package/dist/runtime/app/components/nhealth/component-router.vue +26 -0
- package/dist/runtime/app/components/nhealth/component-router.vue.d.ts +46 -0
- package/dist/runtime/app/components/nhealth/component-shell.d.vue.ts +24 -0
- package/dist/runtime/app/components/nhealth/component-shell.vue +89 -0
- package/dist/runtime/app/components/nhealth/component-shell.vue.d.ts +24 -0
- package/dist/runtime/app/composables/useAnalyzedFlows.d.ts +14 -0
- package/dist/runtime/app/composables/useAnalyzedFlows.js +8 -0
- package/dist/runtime/app/composables/useComponentRouter.d.ts +38 -0
- package/dist/runtime/app/composables/useComponentRouter.js +240 -0
- package/dist/runtime/app/composables/useFlowRunTimeline.d.ts +82 -0
- package/dist/runtime/app/composables/useFlowRunTimeline.js +67 -0
- package/dist/runtime/app/composables/useFlowRuns.d.ts +18 -0
- package/dist/runtime/app/composables/useFlowRuns.js +32 -0
- package/dist/runtime/app/composables/useFlowRunsInfinite.d.ts +24 -0
- package/dist/runtime/app/composables/useFlowRunsInfinite.js +123 -0
- package/dist/runtime/app/composables/useFlowRunsPolling.d.ts +9 -0
- package/dist/runtime/app/composables/useFlowRunsPolling.js +33 -0
- package/dist/runtime/app/composables/useFlowState.d.ts +127 -0
- package/dist/runtime/app/composables/useFlowState.js +225 -0
- package/dist/runtime/app/composables/useFlowWebSocket.d.ts +27 -0
- package/dist/runtime/app/composables/useFlowWebSocket.js +222 -0
- package/dist/runtime/app/composables/useFlowsNavigation.d.ts +10 -0
- package/dist/runtime/app/composables/useFlowsNavigation.js +58 -0
- package/dist/runtime/app/composables/useQueueJobs.d.ts +26 -0
- package/dist/runtime/app/composables/useQueueJobs.js +20 -0
- package/dist/runtime/app/composables/useQueueUpdates.d.ts +24 -0
- package/dist/runtime/app/composables/useQueueUpdates.js +54 -0
- package/dist/runtime/app/composables/useQueues.d.ts +45 -0
- package/dist/runtime/app/composables/useQueues.js +26 -0
- package/dist/runtime/app/composables/useQueuesLive.d.ts +16 -0
- package/dist/runtime/app/composables/useQueuesLive.js +62 -0
- package/dist/runtime/app/composables/useQueuesWebSocket.d.ts +17 -0
- package/dist/runtime/app/composables/useQueuesWebSocket.js +159 -0
- package/dist/runtime/app/pages/flows/index.d.vue.ts +3 -0
- package/dist/runtime/app/pages/flows/index.vue +683 -0
- package/dist/runtime/app/pages/flows/index.vue.d.ts +3 -0
- package/dist/runtime/app/pages/index.d.vue.ts +3 -0
- package/dist/runtime/app/pages/index.vue +34 -0
- package/dist/runtime/app/pages/index.vue.d.ts +3 -0
- package/dist/runtime/app/pages/queues/index.d.vue.ts +3 -0
- package/dist/runtime/app/pages/queues/index.vue +229 -0
- package/dist/runtime/app/pages/queues/index.vue.d.ts +3 -0
- package/dist/runtime/app/pages/queues/job.d.vue.ts +3 -0
- package/dist/runtime/app/pages/queues/job.vue +262 -0
- package/dist/runtime/app/pages/queues/job.vue.d.ts +3 -0
- package/dist/runtime/app/pages/queues/jobs.d.vue.ts +3 -0
- package/dist/runtime/app/pages/queues/jobs.vue +291 -0
- package/dist/runtime/app/pages/queues/jobs.vue.d.ts +3 -0
- package/dist/runtime/app/plugins/vueflow.client.d.ts +2 -0
- package/dist/runtime/app/plugins/vueflow.client.js +11 -0
- package/dist/types.d.mts +7 -0
- package/package.json +47 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div :class="ui.root">
|
|
3
|
+
<button
|
|
4
|
+
v-for="item in items"
|
|
5
|
+
:key="item.value"
|
|
6
|
+
type="button"
|
|
7
|
+
:class="itemClasses(item)"
|
|
8
|
+
@click="$emit('update:modelValue', item.value)"
|
|
9
|
+
>
|
|
10
|
+
<!-- Status Icon or All Icon -->
|
|
11
|
+
<div
|
|
12
|
+
class="flex-shrink-0"
|
|
13
|
+
:class="item.step.showAllIndicator ? '' : 'mt-0.5'"
|
|
14
|
+
>
|
|
15
|
+
<div
|
|
16
|
+
v-if="item.step.showAllIndicator"
|
|
17
|
+
class="w-6 h-6 rounded-full flex items-center justify-center bg-gray-100 dark:bg-gray-800"
|
|
18
|
+
>
|
|
19
|
+
<UIcon
|
|
20
|
+
name="i-lucide-layers"
|
|
21
|
+
class="w-3 h-3 text-gray-600 dark:text-gray-400"
|
|
22
|
+
/>
|
|
23
|
+
</div>
|
|
24
|
+
<div
|
|
25
|
+
v-else
|
|
26
|
+
class="w-8 h-8 rounded-full flex items-center justify-center"
|
|
27
|
+
:class="getStepStatusBg(item.step.status)"
|
|
28
|
+
>
|
|
29
|
+
<UIcon
|
|
30
|
+
:name="getStepStatusIcon(item.step.status)"
|
|
31
|
+
class="w-4 h-4"
|
|
32
|
+
:class="getStepStatusIconColor(item.step.status)"
|
|
33
|
+
/>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
<!-- Step Details -->
|
|
38
|
+
<div class="flex-1 min-w-0 ml-3">
|
|
39
|
+
<h4 class="text-sm font-medium text-gray-900 dark:text-gray-100">
|
|
40
|
+
{{ item.step.key }}
|
|
41
|
+
</h4>
|
|
42
|
+
<div
|
|
43
|
+
v-if="!item.step.showAllIndicator"
|
|
44
|
+
class="flex items-center gap-3 mt-1 text-xs text-gray-500"
|
|
45
|
+
>
|
|
46
|
+
<span
|
|
47
|
+
class="capitalize"
|
|
48
|
+
:class="getStepStatusTextColor(item.step.status)"
|
|
49
|
+
>
|
|
50
|
+
{{ item.step.status || "pending" }}
|
|
51
|
+
</span>
|
|
52
|
+
<span v-if="item.step.attempt && item.step.attempt > 1">
|
|
53
|
+
Attempt {{ item.step.attempt }}
|
|
54
|
+
</span>
|
|
55
|
+
</div>
|
|
56
|
+
<div
|
|
57
|
+
v-else
|
|
58
|
+
class="mt-1 text-xs text-gray-500"
|
|
59
|
+
>
|
|
60
|
+
Show all events from all steps
|
|
61
|
+
</div>
|
|
62
|
+
|
|
63
|
+
<!-- Additional Details (from description slot) -->
|
|
64
|
+
<div
|
|
65
|
+
v-if="!item.step.showAllIndicator && (item.step.startedAt || item.step.completedAt || item.step.error || item.step.awaitType)"
|
|
66
|
+
class="mt-3"
|
|
67
|
+
>
|
|
68
|
+
<!-- Timing Info -->
|
|
69
|
+
<div
|
|
70
|
+
v-if="item.step.startedAt || item.step.completedAt"
|
|
71
|
+
class="flex items-center gap-4 text-xs text-gray-500"
|
|
72
|
+
>
|
|
73
|
+
<div
|
|
74
|
+
v-if="item.step.startedAt"
|
|
75
|
+
class="flex items-center gap-1"
|
|
76
|
+
>
|
|
77
|
+
<UIcon
|
|
78
|
+
name="i-lucide-clock"
|
|
79
|
+
class="w-3 h-3"
|
|
80
|
+
/>
|
|
81
|
+
<span>{{ formatTime(item.step.startedAt) }}</span>
|
|
82
|
+
</div>
|
|
83
|
+
<div
|
|
84
|
+
v-if="item.step.completedAt"
|
|
85
|
+
class="flex items-center gap-1"
|
|
86
|
+
>
|
|
87
|
+
<UIcon
|
|
88
|
+
name="i-lucide-check-circle"
|
|
89
|
+
class="w-3 h-3"
|
|
90
|
+
/>
|
|
91
|
+
<span>{{ formatTime(item.step.completedAt) }}</span>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<!-- Error Message -->
|
|
96
|
+
<div
|
|
97
|
+
v-if="item.step.error"
|
|
98
|
+
class="mt-2"
|
|
99
|
+
>
|
|
100
|
+
<div
|
|
101
|
+
class="p-2 bg-red-50 dark:bg-red-900/10 border border-red-200 dark:border-red-900/30 rounded text-xs text-red-600 dark:text-red-400"
|
|
102
|
+
:title="String(item.step.error || '')"
|
|
103
|
+
>
|
|
104
|
+
<div class="flex items-start gap-1">
|
|
105
|
+
<UIcon
|
|
106
|
+
name="i-lucide-alert-circle"
|
|
107
|
+
class="w-3 h-3 flex-shrink-0 mt-0.5"
|
|
108
|
+
/>
|
|
109
|
+
<p class="line-clamp-2 break-all">
|
|
110
|
+
{{ item.step.error }}
|
|
111
|
+
</p>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
<!-- Await Info -->
|
|
117
|
+
<div
|
|
118
|
+
v-if="item.step.awaitType"
|
|
119
|
+
class="mt-2 p-2 bg-blue-50 dark:bg-blue-900/10 border border-blue-200 dark:border-blue-900/30 rounded text-xs text-blue-600 dark:text-blue-400"
|
|
120
|
+
>
|
|
121
|
+
<div class="flex items-center gap-1">
|
|
122
|
+
<UIcon
|
|
123
|
+
name="i-lucide-timer"
|
|
124
|
+
class="w-3 h-3"
|
|
125
|
+
/>
|
|
126
|
+
<span>Waiting: {{ item.step.awaitType }}</span>
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
</div>
|
|
130
|
+
</div>
|
|
131
|
+
</button>
|
|
132
|
+
</div>
|
|
133
|
+
</template>
|
|
134
|
+
|
|
135
|
+
<script setup>
|
|
136
|
+
import { computed } from "vue";
|
|
137
|
+
import { tv } from "tailwind-variants";
|
|
138
|
+
import { twMerge } from "tailwind-merge";
|
|
139
|
+
import { UIcon } from "#components";
|
|
140
|
+
const props = defineProps({
|
|
141
|
+
modelValue: { type: String, required: true },
|
|
142
|
+
items: { type: Array, required: true },
|
|
143
|
+
ui: { type: Object, required: false }
|
|
144
|
+
});
|
|
145
|
+
defineEmits(["update:modelValue"]);
|
|
146
|
+
const defaultUi = {
|
|
147
|
+
root: "space-y-3",
|
|
148
|
+
itemBase: "w-full flex items-start border rounded-lg text-sm p-3.5 transition-colors text-left hover:bg-gray-50 dark:hover:bg-gray-900/50",
|
|
149
|
+
item: "border-gray-200 dark:border-gray-800",
|
|
150
|
+
itemSelected: "border-primary bg-primary/5 dark:bg-primary/10"
|
|
151
|
+
};
|
|
152
|
+
const ui = computed(() => ({
|
|
153
|
+
root: twMerge(defaultUi.root, props.ui?.root),
|
|
154
|
+
itemBase: twMerge(defaultUi.itemBase, props.ui?.itemBase),
|
|
155
|
+
item: props.ui?.item || defaultUi.item,
|
|
156
|
+
itemSelected: props.ui?.itemSelected || defaultUi.itemSelected
|
|
157
|
+
}));
|
|
158
|
+
const itemVariants = computed(() => tv({
|
|
159
|
+
base: ui.value.itemBase,
|
|
160
|
+
variants: {
|
|
161
|
+
selected: {
|
|
162
|
+
true: ui.value.itemSelected,
|
|
163
|
+
false: ui.value.item
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}));
|
|
167
|
+
const itemClasses = (item) => {
|
|
168
|
+
return itemVariants.value({
|
|
169
|
+
selected: props.modelValue === item.value
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
const formatTime = (timestamp) => {
|
|
173
|
+
const date = new Date(timestamp);
|
|
174
|
+
const now = /* @__PURE__ */ new Date();
|
|
175
|
+
const diff = now.getTime() - date.getTime();
|
|
176
|
+
const seconds = Math.floor(diff / 1e3);
|
|
177
|
+
const minutes = Math.floor(seconds / 60);
|
|
178
|
+
const hours = Math.floor(minutes / 60);
|
|
179
|
+
const days = Math.floor(hours / 24);
|
|
180
|
+
if (days > 0)
|
|
181
|
+
return `${days}d ago`;
|
|
182
|
+
if (hours > 0)
|
|
183
|
+
return `${hours}h ago`;
|
|
184
|
+
if (minutes > 0)
|
|
185
|
+
return `${minutes}m ago`;
|
|
186
|
+
if (seconds > 10)
|
|
187
|
+
return `${seconds}s ago`;
|
|
188
|
+
return "just now";
|
|
189
|
+
};
|
|
190
|
+
const getStepStatusBg = (status) => {
|
|
191
|
+
switch (status) {
|
|
192
|
+
case "completed":
|
|
193
|
+
return "bg-emerald-50 dark:bg-emerald-900/20";
|
|
194
|
+
case "failed":
|
|
195
|
+
return "bg-red-50 dark:bg-red-900/20";
|
|
196
|
+
case "running":
|
|
197
|
+
return "bg-blue-50 dark:bg-blue-900/20";
|
|
198
|
+
default:
|
|
199
|
+
return "bg-gray-50 dark:bg-gray-900/20";
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
const getStepStatusIcon = (status) => {
|
|
203
|
+
switch (status) {
|
|
204
|
+
case "completed":
|
|
205
|
+
return "i-lucide-check-circle";
|
|
206
|
+
case "failed":
|
|
207
|
+
return "i-lucide-x-circle";
|
|
208
|
+
case "running":
|
|
209
|
+
return "i-lucide-loader-circle";
|
|
210
|
+
default:
|
|
211
|
+
return "i-lucide-circle";
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
const getStepStatusIconColor = (status) => {
|
|
215
|
+
switch (status) {
|
|
216
|
+
case "completed":
|
|
217
|
+
return "text-emerald-600 dark:text-emerald-400";
|
|
218
|
+
case "failed":
|
|
219
|
+
return "text-red-600 dark:text-red-400";
|
|
220
|
+
case "running":
|
|
221
|
+
return "text-blue-600 dark:text-blue-400 animate-spin";
|
|
222
|
+
default:
|
|
223
|
+
return "text-gray-400";
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
const getStepStatusTextColor = (status) => {
|
|
227
|
+
switch (status) {
|
|
228
|
+
case "completed":
|
|
229
|
+
return "text-emerald-600 dark:text-emerald-400";
|
|
230
|
+
case "failed":
|
|
231
|
+
return "text-red-600 dark:text-red-400";
|
|
232
|
+
case "running":
|
|
233
|
+
return "text-blue-600 dark:text-blue-400";
|
|
234
|
+
default:
|
|
235
|
+
return "text-gray-500";
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
</script>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ClassValue } from 'tailwind-variants';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
modelValue: string;
|
|
4
|
+
items: Array<{
|
|
5
|
+
value: string;
|
|
6
|
+
label: string;
|
|
7
|
+
step: any;
|
|
8
|
+
}>;
|
|
9
|
+
ui?: {
|
|
10
|
+
root?: ClassValue;
|
|
11
|
+
item?: ClassValue;
|
|
12
|
+
itemSelected?: ClassValue;
|
|
13
|
+
itemBase?: ClassValue;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
17
|
+
"update:modelValue": (value: string) => any;
|
|
18
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
19
|
+
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
20
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
21
|
+
declare const _default: typeof __VLS_export;
|
|
22
|
+
export default _default;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
queue: string;
|
|
3
|
+
};
|
|
4
|
+
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>;
|
|
5
|
+
declare const _default: typeof __VLS_export;
|
|
6
|
+
export default _default;
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="space-y-4">
|
|
3
|
+
<div class="flex justify-end">
|
|
4
|
+
<Button
|
|
5
|
+
icon="i-heroicons-clock"
|
|
6
|
+
color="neutral"
|
|
7
|
+
variant="outline"
|
|
8
|
+
@click="jobSchedulerEditor = !jobSchedulerEditor"
|
|
9
|
+
>
|
|
10
|
+
Job Scheduler
|
|
11
|
+
</Button>
|
|
12
|
+
</div>
|
|
13
|
+
<UForm
|
|
14
|
+
:schema="schema"
|
|
15
|
+
:state="state"
|
|
16
|
+
@submit="onSubmit"
|
|
17
|
+
>
|
|
18
|
+
<UCard
|
|
19
|
+
v-if="jobSchedulerEditor"
|
|
20
|
+
:ui="{
|
|
21
|
+
body: 'space-y-6'
|
|
22
|
+
}"
|
|
23
|
+
>
|
|
24
|
+
<UFormField
|
|
25
|
+
label="Name"
|
|
26
|
+
name="name"
|
|
27
|
+
>
|
|
28
|
+
<UInput
|
|
29
|
+
v-model="state.name"
|
|
30
|
+
placeholder="Name"
|
|
31
|
+
class="w-full"
|
|
32
|
+
/>
|
|
33
|
+
</UFormField>
|
|
34
|
+
<UTabs
|
|
35
|
+
v-model="state.scheduleType"
|
|
36
|
+
:items="scheduleInputTypes"
|
|
37
|
+
size="xs"
|
|
38
|
+
default-value="every"
|
|
39
|
+
variant="pill"
|
|
40
|
+
color="neutral"
|
|
41
|
+
:ui="{
|
|
42
|
+
list: 'w-28 self-start',
|
|
43
|
+
content: 'w-full'
|
|
44
|
+
}"
|
|
45
|
+
>
|
|
46
|
+
<template #content="{ item }">
|
|
47
|
+
<UFormField name="scheduleValue">
|
|
48
|
+
<UInput
|
|
49
|
+
v-if="item.value === 'every'"
|
|
50
|
+
v-model="state.scheduleValue"
|
|
51
|
+
class="w-full"
|
|
52
|
+
type="number"
|
|
53
|
+
/>
|
|
54
|
+
<UInput
|
|
55
|
+
v-if="item.value === 'cron'"
|
|
56
|
+
v-model="state.scheduleValue"
|
|
57
|
+
class="w-full"
|
|
58
|
+
type="string"
|
|
59
|
+
/>
|
|
60
|
+
</UFormField>
|
|
61
|
+
</template>
|
|
62
|
+
</UTabs>
|
|
63
|
+
<div>
|
|
64
|
+
<div class="text-sm font-bold mb-2">
|
|
65
|
+
Job
|
|
66
|
+
</div>
|
|
67
|
+
<div class="flex flex-col space-y-2 p-2 rounded-sm ring-1 ring-gray-200 dark:ring-gray-800 shadow">
|
|
68
|
+
<UFormField
|
|
69
|
+
label="Name"
|
|
70
|
+
name="jobName"
|
|
71
|
+
>
|
|
72
|
+
<UInput
|
|
73
|
+
v-model="state.jobName"
|
|
74
|
+
placeholder="Job Name"
|
|
75
|
+
class="w-full"
|
|
76
|
+
/>
|
|
77
|
+
</UFormField>
|
|
78
|
+
<UFormField
|
|
79
|
+
label="Data"
|
|
80
|
+
name="jobData"
|
|
81
|
+
>
|
|
82
|
+
<JsonEditorVue
|
|
83
|
+
v-model="state.jobData"
|
|
84
|
+
:main-menu-bar="false"
|
|
85
|
+
mode="text"
|
|
86
|
+
/>
|
|
87
|
+
</UFormField>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
<template #footer>
|
|
91
|
+
<div class="flex justify-end">
|
|
92
|
+
<Button
|
|
93
|
+
type="submit"
|
|
94
|
+
color="neutral"
|
|
95
|
+
variant="outline"
|
|
96
|
+
class="cursor-pointer"
|
|
97
|
+
>
|
|
98
|
+
Create
|
|
99
|
+
</Button>
|
|
100
|
+
</div>
|
|
101
|
+
</template>
|
|
102
|
+
</UCard>
|
|
103
|
+
</UForm>
|
|
104
|
+
<div>
|
|
105
|
+
<div
|
|
106
|
+
v-if="scheduler && scheduler.length > 0"
|
|
107
|
+
class="space-y-4"
|
|
108
|
+
>
|
|
109
|
+
<div
|
|
110
|
+
v-for="item of scheduler"
|
|
111
|
+
:key="item.key"
|
|
112
|
+
class="flex flex-col rounded-sm ring-1 ring-gray-200 dark:ring-gray-800 shadow p-4"
|
|
113
|
+
>
|
|
114
|
+
<div class="flex justify-end">
|
|
115
|
+
<Button
|
|
116
|
+
icon="i-heroicons-x-circle"
|
|
117
|
+
color="error"
|
|
118
|
+
variant="outline"
|
|
119
|
+
class="cursor-pointer"
|
|
120
|
+
@click="deleteScheduledJob(item.key)"
|
|
121
|
+
/>
|
|
122
|
+
</div>
|
|
123
|
+
<div>
|
|
124
|
+
<span class="text-sm font-bold">Name:</span> {{ item.key }}
|
|
125
|
+
</div>
|
|
126
|
+
<div>
|
|
127
|
+
<span class="text-sm font-bold">Next schedule:</span> {{
|
|
128
|
+
new Date(item.next).toLocaleString("de", {
|
|
129
|
+
day: "numeric",
|
|
130
|
+
month: "short",
|
|
131
|
+
hour: "2-digit",
|
|
132
|
+
minute: "2-digit",
|
|
133
|
+
second: "2-digit",
|
|
134
|
+
hour12: false
|
|
135
|
+
})
|
|
136
|
+
}}
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
<div v-else>
|
|
141
|
+
<UAlert
|
|
142
|
+
color="info"
|
|
143
|
+
title="No scheduled jobs"
|
|
144
|
+
variant="subtle"
|
|
145
|
+
icon="i-heroicons-information-circle"
|
|
146
|
+
class="flex items-center space-x-2"
|
|
147
|
+
/>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
</div>
|
|
151
|
+
</template>
|
|
152
|
+
|
|
153
|
+
<script setup>
|
|
154
|
+
import { z } from "zod";
|
|
155
|
+
import { ref, useFetch } from "#imports";
|
|
156
|
+
const props = defineProps({
|
|
157
|
+
queue: { type: String, required: true }
|
|
158
|
+
});
|
|
159
|
+
const jobSchedulerEditor = ref(false);
|
|
160
|
+
const scheduleInputTypes = [
|
|
161
|
+
{ label: "Every", value: "every" },
|
|
162
|
+
{ label: "Cron", value: "cron" }
|
|
163
|
+
];
|
|
164
|
+
const {
|
|
165
|
+
data: scheduler,
|
|
166
|
+
refresh
|
|
167
|
+
} = await useFetch(`/api/_queue/${props.queue}/job/scheduler`, {
|
|
168
|
+
method: "GET"
|
|
169
|
+
});
|
|
170
|
+
const state = ref({
|
|
171
|
+
name: void 0,
|
|
172
|
+
scheduleType: "every",
|
|
173
|
+
scheduleValue: void 0,
|
|
174
|
+
jobName: void 0,
|
|
175
|
+
jobData: void 0
|
|
176
|
+
});
|
|
177
|
+
const schema = z.object({
|
|
178
|
+
name: z.string().regex(/^\S*$/gm, "No spaces allowed"),
|
|
179
|
+
scheduleType: z.enum(["every", "cron"]),
|
|
180
|
+
scheduleValue: z.any(),
|
|
181
|
+
jobName: z.string().regex(/^\S*$/gm, "No spaces allowed"),
|
|
182
|
+
jobData: z.string().default("{}")
|
|
183
|
+
});
|
|
184
|
+
async function onSubmit(event) {
|
|
185
|
+
await $fetch(`/api/_queue/${props.queue}/job/scheduler`, {
|
|
186
|
+
method: "POST",
|
|
187
|
+
body: {
|
|
188
|
+
name: event.data.name,
|
|
189
|
+
scheduleType: event.data.scheduleType,
|
|
190
|
+
scheduleValue: event.data.scheduleValue,
|
|
191
|
+
jobName: event.data.jobName,
|
|
192
|
+
jobData: JSON.stringify(event.data.jobData)
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
refresh();
|
|
196
|
+
}
|
|
197
|
+
const deleteScheduledJob = async (id) => {
|
|
198
|
+
await $fetch(`/api/_queue/${props.queue}/job/scheduler/${id}`, {
|
|
199
|
+
method: "DELETE"
|
|
200
|
+
});
|
|
201
|
+
refresh();
|
|
202
|
+
};
|
|
203
|
+
</script>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
type __VLS_Props = {
|
|
2
|
+
queue: string;
|
|
3
|
+
};
|
|
4
|
+
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>;
|
|
5
|
+
declare const _default: typeof __VLS_export;
|
|
6
|
+
export default _default;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DropdownMenuItem } from '@nuxt/ui';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
title?: string;
|
|
4
|
+
link: string;
|
|
5
|
+
origin?: string | null;
|
|
6
|
+
dropdown?: DropdownMenuItem[];
|
|
7
|
+
};
|
|
8
|
+
declare var __VLS_24: {};
|
|
9
|
+
type __VLS_Slots = {} & {
|
|
10
|
+
default?: (props: typeof __VLS_24) => any;
|
|
11
|
+
};
|
|
12
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
13
|
+
title: string;
|
|
14
|
+
origin: string | null;
|
|
15
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
16
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
17
|
+
declare const _default: typeof __VLS_export;
|
|
18
|
+
export default _default;
|
|
19
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
20
|
+
new (): {
|
|
21
|
+
$slots: S;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div
|
|
3
|
+
:to="link"
|
|
4
|
+
class="rounded-lg divide-y divide-gray-200 dark:divide-gray-800 ring-1 ring-gray-200 dark:ring-gray-800 shadow bg-white dark:bg-gray-900"
|
|
5
|
+
>
|
|
6
|
+
<div class="px-4 py-5 sm:p-6">
|
|
7
|
+
<div class="flex flex-col md:flex-row">
|
|
8
|
+
<div class="flex-none flex flex-col justify-between space-y-2">
|
|
9
|
+
<ULink
|
|
10
|
+
class="inline-flex items-center gap-1"
|
|
11
|
+
@click="push(link)"
|
|
12
|
+
>
|
|
13
|
+
<span class="text-lg font-semibold">{{ title }}</span>
|
|
14
|
+
<UIcon
|
|
15
|
+
name="i-heroicons-arrow-up-right"
|
|
16
|
+
class="w-5 h-5 text-primary-500"
|
|
17
|
+
/>
|
|
18
|
+
</ULink>
|
|
19
|
+
<div class="flex flex-wrap items-center gap-2">
|
|
20
|
+
<div class="inline-flex gap-1 items-center">
|
|
21
|
+
<UIcon
|
|
22
|
+
name="i-heroicons-check-circle"
|
|
23
|
+
class="w-4 h-4 text-green-500"
|
|
24
|
+
/>
|
|
25
|
+
<span class="text-sm">Active</span>
|
|
26
|
+
</div>
|
|
27
|
+
<UBadge
|
|
28
|
+
v-if="origin"
|
|
29
|
+
size="sm"
|
|
30
|
+
color="neutral"
|
|
31
|
+
>
|
|
32
|
+
<span v-if="origin === 'local'">Local</span>
|
|
33
|
+
<span v-if="origin === 'remote'">Remote</span>
|
|
34
|
+
</UBadge>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
<div class="grow pr-12">
|
|
38
|
+
<div class="flex flex-row gap-4 justify-end">
|
|
39
|
+
<slot />
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
<div class="flex-none">
|
|
43
|
+
<div class="flex gap-2 items-center">
|
|
44
|
+
<UDropdownMenu
|
|
45
|
+
:items="dropdown"
|
|
46
|
+
>
|
|
47
|
+
<UButton
|
|
48
|
+
icon="i-heroicons-ellipsis-vertical"
|
|
49
|
+
color="neutral"
|
|
50
|
+
variant="outline"
|
|
51
|
+
/>
|
|
52
|
+
</UDropdownMenu>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
</template>
|
|
59
|
+
|
|
60
|
+
<script setup>
|
|
61
|
+
import { useComponentRouter } from "#imports";
|
|
62
|
+
import { ULink, UDropdownMenu, UButton, UIcon, UBadge } from "#components";
|
|
63
|
+
defineProps({
|
|
64
|
+
title: { type: String, required: false, default: "" },
|
|
65
|
+
link: { type: String, required: true },
|
|
66
|
+
origin: { type: [String, null], required: false, default: null },
|
|
67
|
+
dropdown: { type: Array, required: false }
|
|
68
|
+
});
|
|
69
|
+
const { push } = useComponentRouter();
|
|
70
|
+
</script>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DropdownMenuItem } from '@nuxt/ui';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
title?: string;
|
|
4
|
+
link: string;
|
|
5
|
+
origin?: string | null;
|
|
6
|
+
dropdown?: DropdownMenuItem[];
|
|
7
|
+
};
|
|
8
|
+
declare var __VLS_24: {};
|
|
9
|
+
type __VLS_Slots = {} & {
|
|
10
|
+
default?: (props: typeof __VLS_24) => any;
|
|
11
|
+
};
|
|
12
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
13
|
+
title: string;
|
|
14
|
+
origin: string | null;
|
|
15
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
16
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
17
|
+
declare const _default: typeof __VLS_export;
|
|
18
|
+
export default _default;
|
|
19
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
20
|
+
new (): {
|
|
21
|
+
$slots: S;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
interface QueueConfig {
|
|
2
|
+
name?: string;
|
|
3
|
+
prefix?: string;
|
|
4
|
+
limiter?: {
|
|
5
|
+
max?: number;
|
|
6
|
+
duration?: number;
|
|
7
|
+
groupKey?: string;
|
|
8
|
+
};
|
|
9
|
+
defaultJobOptions?: {
|
|
10
|
+
attempts?: number;
|
|
11
|
+
backoff?: {
|
|
12
|
+
type?: string;
|
|
13
|
+
delay?: number;
|
|
14
|
+
};
|
|
15
|
+
priority?: number;
|
|
16
|
+
timeout?: number;
|
|
17
|
+
removeOnComplete?: boolean | number;
|
|
18
|
+
removeOnFail?: boolean | number;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
interface WorkerConfig {
|
|
22
|
+
concurrency?: number;
|
|
23
|
+
lockDurationMs?: number;
|
|
24
|
+
maxStalledCount?: number;
|
|
25
|
+
drainDelayMs?: number;
|
|
26
|
+
pollingIntervalMs?: number;
|
|
27
|
+
autorun?: boolean;
|
|
28
|
+
}
|
|
29
|
+
interface Props {
|
|
30
|
+
queueName: string;
|
|
31
|
+
queueConfig?: QueueConfig;
|
|
32
|
+
workerConfig?: WorkerConfig;
|
|
33
|
+
}
|
|
34
|
+
type __VLS_Props = Props;
|
|
35
|
+
type __VLS_ModelProps = {
|
|
36
|
+
'open'?: boolean;
|
|
37
|
+
};
|
|
38
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
39
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
40
|
+
"update:open": (value: boolean) => any;
|
|
41
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
42
|
+
"onUpdate:open"?: ((value: boolean) => any) | undefined;
|
|
43
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
44
|
+
declare const _default: typeof __VLS_export;
|
|
45
|
+
export default _default;
|