@nvent-addon/app 0.5.15 → 1.0.0-alpha.2
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 +1 -1
- package/dist/module.mjs +3 -2
- package/dist/runtime/app/components/DashboardCard.d.vue.ts +1 -1
- package/dist/runtime/app/components/DashboardCard.vue.d.ts +1 -1
- package/dist/runtime/app/composables/useWorkers.d.ts +57 -0
- package/dist/runtime/app/composables/useWorkers.js +42 -0
- package/dist/runtime/app/pages/dashboard.vue +1 -654
- package/dist/runtime/app/pages/index.vue +25 -41
- package/dist/runtime/app/pages/workers.vue +458 -0
- package/dist/runtime/server/api/_workers/index.get.d.ts +8 -0
- package/dist/runtime/server/api/_workers/index.get.js +14 -0
- package/package.json +12 -11
- package/dist/runtime/app/components/ComponentRouter.d.vue.ts +0 -46
- package/dist/runtime/app/components/ComponentRouter.vue +0 -26
- package/dist/runtime/app/components/ComponentRouter.vue.d.ts +0 -46
- package/dist/runtime/app/components/ComponentShell.d.vue.ts +0 -23
- package/dist/runtime/app/components/ComponentShell.vue +0 -97
- package/dist/runtime/app/components/ComponentShell.vue.d.ts +0 -23
- package/dist/runtime/app/components/ConfirmDialog.d.vue.ts +0 -33
- package/dist/runtime/app/components/ConfirmDialog.vue +0 -120
- package/dist/runtime/app/components/ConfirmDialog.vue.d.ts +0 -33
- package/dist/runtime/app/composables/useComponentRouter.d.ts +0 -46
- package/dist/runtime/app/composables/useComponentRouter.js +0 -248
- package/dist/runtime/app/pages/flows/[name].vue +0 -750
- package/dist/runtime/app/pages/flows/index.d.vue.ts +0 -3
- package/dist/runtime/app/pages/flows/index.vue +0 -381
- package/dist/runtime/app/pages/flows/index.vue.d.ts +0 -3
- package/dist/runtime/app/pages/queues/index.d.vue.ts +0 -3
- package/dist/runtime/app/pages/queues/index.vue +0 -236
- package/dist/runtime/app/pages/queues/index.vue.d.ts +0 -3
- package/dist/runtime/app/pages/queues/job.d.vue.ts +0 -3
- package/dist/runtime/app/pages/queues/job.vue +0 -261
- package/dist/runtime/app/pages/queues/job.vue.d.ts +0 -3
- package/dist/runtime/app/pages/queues/jobs.d.vue.ts +0 -3
- package/dist/runtime/app/pages/queues/jobs.vue +0 -595
- package/dist/runtime/app/pages/queues/jobs.vue.d.ts +0 -3
- package/dist/runtime/app/pages/settings/scheduler.d.vue.ts +0 -3
- package/dist/runtime/app/pages/settings/scheduler.vue +0 -310
- package/dist/runtime/app/pages/settings/scheduler.vue.d.ts +0 -3
- package/dist/runtime/app/pages/triggers/[name]/edit.d.vue.ts +0 -3
- package/dist/runtime/app/pages/triggers/[name]/edit.vue +0 -429
- package/dist/runtime/app/pages/triggers/[name]/edit.vue.d.ts +0 -3
- package/dist/runtime/app/pages/triggers/[name].d.vue.ts +0 -3
- package/dist/runtime/app/pages/triggers/[name].vue +0 -870
- package/dist/runtime/app/pages/triggers/[name].vue.d.ts +0 -3
- package/dist/runtime/app/pages/triggers/index.d.vue.ts +0 -3
- package/dist/runtime/app/pages/triggers/index.vue +0 -525
- package/dist/runtime/app/pages/triggers/index.vue.d.ts +0 -3
- package/dist/runtime/app/pages/triggers/new.d.vue.ts +0 -3
- package/dist/runtime/app/pages/triggers/new.vue +0 -610
- package/dist/runtime/app/pages/triggers/new.vue.d.ts +0 -3
- package/dist/runtime/server/api/_flows/[name]/clear-history.delete.d.ts +0 -10
- package/dist/runtime/server/api/_flows/[name]/clear-history.delete.js +0 -49
- package/dist/runtime/server/api/_flows/[name]/runs/[runId]/cancel.post.d.ts +0 -2
- package/dist/runtime/server/api/_flows/[name]/runs/[runId]/cancel.post.js +0 -21
- package/dist/runtime/server/api/_flows/[name]/runs/[runId]/restart.post.d.ts +0 -2
- package/dist/runtime/server/api/_flows/[name]/runs/[runId]/restart.post.js +0 -21
- package/dist/runtime/server/api/_flows/[name]/runs.get.d.ts +0 -17
- package/dist/runtime/server/api/_flows/[name]/runs.get.js +0 -64
- package/dist/runtime/server/api/_flows/[name]/start.post.d.ts +0 -2
- package/dist/runtime/server/api/_flows/[name]/start.post.js +0 -9
- package/dist/runtime/server/api/_flows/index.get.d.ts +0 -7
- package/dist/runtime/server/api/_flows/index.get.js +0 -5
- package/dist/runtime/server/api/_flows/recent-runs.get.d.ts +0 -15
- package/dist/runtime/server/api/_flows/recent-runs.get.js +0 -67
- package/dist/runtime/server/api/_flows/ws.d.ts +0 -80
- package/dist/runtime/server/api/_flows/ws.js +0 -309
- package/dist/runtime/server/api/_queues/[name]/job/[id].get.d.ts +0 -2
- package/dist/runtime/server/api/_queues/[name]/job/[id].get.js +0 -14
- package/dist/runtime/server/api/_queues/[name]/job/index.get.d.ts +0 -2
- package/dist/runtime/server/api/_queues/[name]/job/index.get.js +0 -39
- package/dist/runtime/server/api/_queues/index.get.d.ts +0 -2
- package/dist/runtime/server/api/_queues/index.get.js +0 -106
- package/dist/runtime/server/api/_queues/ws.d.ts +0 -48
- package/dist/runtime/server/api/_queues/ws.js +0 -215
- package/dist/runtime/server/api/_scheduler/jobs.get.d.ts +0 -19
- package/dist/runtime/server/api/_scheduler/jobs.get.js +0 -36
- package/dist/runtime/server/api/_triggers/[name]/events.get.d.ts +0 -6
- package/dist/runtime/server/api/_triggers/[name]/events.get.js +0 -43
- package/dist/runtime/server/api/_triggers/[name]/index.get.d.ts +0 -6
- package/dist/runtime/server/api/_triggers/[name]/index.get.js +0 -76
- package/dist/runtime/server/api/_triggers/[name].delete.d.ts +0 -7
- package/dist/runtime/server/api/_triggers/[name].delete.js +0 -37
- package/dist/runtime/server/api/_triggers/[name].patch.d.ts +0 -7
- package/dist/runtime/server/api/_triggers/[name].patch.js +0 -117
- package/dist/runtime/server/api/_triggers/index.get.d.ts +0 -6
- package/dist/runtime/server/api/_triggers/index.get.js +0 -44
- package/dist/runtime/server/api/_triggers/index.post.d.ts +0 -7
- package/dist/runtime/server/api/_triggers/index.post.js +0 -124
- package/dist/runtime/server/api/_triggers/stats.get.d.ts +0 -6
- package/dist/runtime/server/api/_triggers/stats.get.js +0 -41
- package/dist/runtime/server/api/_triggers/ws.d.ts +0 -74
- package/dist/runtime/server/api/_triggers/ws.js +0 -315
- /package/dist/runtime/app/pages/{flows/[name].d.vue.ts → workers.d.vue.ts} +0 -0
- /package/dist/runtime/app/pages/{flows/[name].vue.d.ts → workers.vue.d.ts} +0 -0
|
@@ -1,595 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="h-full flex flex-col overflow-hidden">
|
|
3
|
-
<!-- Header -->
|
|
4
|
-
<div class="border-b border-gray-200 dark:border-gray-800 px-6 py-3 shrink-0">
|
|
5
|
-
<div class="flex items-center justify-between">
|
|
6
|
-
<div class="flex items-center gap-4">
|
|
7
|
-
<UButton
|
|
8
|
-
icon="i-lucide-arrow-left"
|
|
9
|
-
size="xs"
|
|
10
|
-
color="neutral"
|
|
11
|
-
variant="ghost"
|
|
12
|
-
@click="back"
|
|
13
|
-
/>
|
|
14
|
-
<div>
|
|
15
|
-
<h1 class="text-lg font-semibold">
|
|
16
|
-
{{ queueName }}
|
|
17
|
-
</h1>
|
|
18
|
-
<p class="text-xs text-gray-500">
|
|
19
|
-
Queue Jobs
|
|
20
|
-
</p>
|
|
21
|
-
</div>
|
|
22
|
-
</div>
|
|
23
|
-
<div class="flex items-center gap-3">
|
|
24
|
-
<div
|
|
25
|
-
v-if="isConnected"
|
|
26
|
-
class="flex items-center gap-1.5 text-xs text-emerald-600 dark:text-emerald-400"
|
|
27
|
-
>
|
|
28
|
-
<div class="w-2 h-2 rounded-full bg-emerald-500 animate-pulse" />
|
|
29
|
-
<span>Live</span>
|
|
30
|
-
</div>
|
|
31
|
-
<div
|
|
32
|
-
v-else-if="isReconnecting"
|
|
33
|
-
class="flex items-center gap-1.5 text-xs text-amber-600 dark:text-amber-400"
|
|
34
|
-
>
|
|
35
|
-
<div class="w-2 h-2 rounded-full bg-amber-500 animate-pulse" />
|
|
36
|
-
<span>Reconnecting...</span>
|
|
37
|
-
</div>
|
|
38
|
-
<UButton
|
|
39
|
-
icon="i-lucide-settings"
|
|
40
|
-
size="xs"
|
|
41
|
-
color="neutral"
|
|
42
|
-
variant="ghost"
|
|
43
|
-
square
|
|
44
|
-
title="View configuration"
|
|
45
|
-
@click="showConfig = !showConfig"
|
|
46
|
-
/>
|
|
47
|
-
</div>
|
|
48
|
-
</div>
|
|
49
|
-
</div>
|
|
50
|
-
|
|
51
|
-
<!-- Main Content -->
|
|
52
|
-
<div class="flex-1 min-h-0 overflow-hidden">
|
|
53
|
-
<div class="h-full flex gap-px bg-gray-200 dark:bg-gray-800">
|
|
54
|
-
<!-- Left: Jobs List -->
|
|
55
|
-
<div class="w-1/3 min-w-0 flex-shrink-0 bg-white dark:bg-gray-950 flex flex-col min-h-0 overflow-hidden">
|
|
56
|
-
<div class="px-4 py-3 border-b border-gray-200 dark:border-gray-800 flex items-center justify-between shrink-0">
|
|
57
|
-
<h2 class="text-sm font-medium text-gray-900 dark:text-gray-100">
|
|
58
|
-
Jobs
|
|
59
|
-
</h2>
|
|
60
|
-
<div class="flex items-center gap-2">
|
|
61
|
-
<USelectMenu
|
|
62
|
-
v-model="selectedStateOption"
|
|
63
|
-
:items="stateOptions"
|
|
64
|
-
placeholder="All States"
|
|
65
|
-
size="xs"
|
|
66
|
-
class="w-32"
|
|
67
|
-
/>
|
|
68
|
-
</div>
|
|
69
|
-
</div>
|
|
70
|
-
|
|
71
|
-
<div
|
|
72
|
-
v-if="!data || !data.jobs || data.jobs.length === 0"
|
|
73
|
-
class="flex-1 flex items-center justify-center"
|
|
74
|
-
>
|
|
75
|
-
<div class="text-center">
|
|
76
|
-
<UIcon
|
|
77
|
-
name="i-lucide-inbox"
|
|
78
|
-
class="w-8 h-8 mx-auto mb-2 text-gray-300 dark:text-gray-700"
|
|
79
|
-
/>
|
|
80
|
-
<p class="text-sm text-gray-500 dark:text-gray-400">
|
|
81
|
-
No jobs found
|
|
82
|
-
</p>
|
|
83
|
-
</div>
|
|
84
|
-
</div>
|
|
85
|
-
|
|
86
|
-
<div
|
|
87
|
-
v-else
|
|
88
|
-
class="flex-1 min-h-0 overflow-y-auto"
|
|
89
|
-
>
|
|
90
|
-
<div class="divide-y divide-gray-100 dark:divide-gray-800">
|
|
91
|
-
<SelectableListItem
|
|
92
|
-
v-for="job in paginatedJobs"
|
|
93
|
-
:key="job.id"
|
|
94
|
-
:selected="selectedJobId === job.id"
|
|
95
|
-
:icon="getJobIcon(job.state)"
|
|
96
|
-
:icon-class="getJobIconColor(job.state)"
|
|
97
|
-
:title="job.name"
|
|
98
|
-
:subtitle="truncateId(job.id)"
|
|
99
|
-
:badge="job.state || 'unknown'"
|
|
100
|
-
:badge-color="getStateBadgeColor(job.state)"
|
|
101
|
-
@click="selectJob(job.id)"
|
|
102
|
-
>
|
|
103
|
-
<template #meta>
|
|
104
|
-
<span v-if="job.timestamp">
|
|
105
|
-
{{ formatTime(job.timestamp) }}
|
|
106
|
-
</span>
|
|
107
|
-
<span v-if="job.finishedOn && job.processedOn">
|
|
108
|
-
• {{ formatDuration(job.processedOn, job.finishedOn) }}
|
|
109
|
-
</span>
|
|
110
|
-
</template>
|
|
111
|
-
</SelectableListItem>
|
|
112
|
-
</div>
|
|
113
|
-
</div>
|
|
114
|
-
|
|
115
|
-
<!-- Pagination Footer -->
|
|
116
|
-
<div
|
|
117
|
-
v-if="data && data.total > jobsPerPage"
|
|
118
|
-
class="border-t border-gray-200 dark:border-gray-800 px-4 py-3 flex items-center justify-center shrink-0"
|
|
119
|
-
>
|
|
120
|
-
<UPagination
|
|
121
|
-
v-model:page="currentPage"
|
|
122
|
-
:items-per-page="jobsPerPage"
|
|
123
|
-
:total="data.total"
|
|
124
|
-
size="xs"
|
|
125
|
-
/>
|
|
126
|
-
</div>
|
|
127
|
-
</div>
|
|
128
|
-
|
|
129
|
-
<!-- Right: Overview or Job Details -->
|
|
130
|
-
<div class="flex-1 min-w-0 bg-white dark:bg-gray-950 flex flex-col min-h-0 overflow-hidden">
|
|
131
|
-
<div class="px-4 py-2.5 border-b border-gray-200 dark:border-gray-800 shrink-0">
|
|
132
|
-
<div class="flex items-center justify-between">
|
|
133
|
-
<UTabs
|
|
134
|
-
v-model="activeTab"
|
|
135
|
-
:items="tabItems"
|
|
136
|
-
size="xs"
|
|
137
|
-
:ui="{
|
|
138
|
-
root: 'gap-0',
|
|
139
|
-
trigger: 'px-2 py-0.5'
|
|
140
|
-
}"
|
|
141
|
-
/>
|
|
142
|
-
</div>
|
|
143
|
-
</div>
|
|
144
|
-
|
|
145
|
-
<div class="flex-1 min-h-0 overflow-y-auto">
|
|
146
|
-
<!-- Overview Tab -->
|
|
147
|
-
<div
|
|
148
|
-
v-if="activeTab === 'overview'"
|
|
149
|
-
class="p-6 space-y-6"
|
|
150
|
-
>
|
|
151
|
-
<!-- Stats Cards -->
|
|
152
|
-
<div>
|
|
153
|
-
<h3 class="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-4">
|
|
154
|
-
Queue Statistics
|
|
155
|
-
</h3>
|
|
156
|
-
<div class="grid grid-cols-2 gap-4">
|
|
157
|
-
<StatCard
|
|
158
|
-
icon="i-lucide-clock"
|
|
159
|
-
:count="counts?.waiting || 0"
|
|
160
|
-
label="Waiting"
|
|
161
|
-
variant="blue"
|
|
162
|
-
/>
|
|
163
|
-
<StatCard
|
|
164
|
-
icon="i-lucide-loader-2"
|
|
165
|
-
:count="counts?.active || 0"
|
|
166
|
-
label="Active"
|
|
167
|
-
variant="amber"
|
|
168
|
-
/>
|
|
169
|
-
<StatCard
|
|
170
|
-
icon="i-lucide-check-circle"
|
|
171
|
-
:count="counts?.completed || 0"
|
|
172
|
-
label="Completed"
|
|
173
|
-
variant="emerald"
|
|
174
|
-
/>
|
|
175
|
-
<StatCard
|
|
176
|
-
icon="i-lucide-x-circle"
|
|
177
|
-
:count="counts?.failed || 0"
|
|
178
|
-
label="Failed"
|
|
179
|
-
variant="red"
|
|
180
|
-
/>
|
|
181
|
-
<StatCard
|
|
182
|
-
icon="i-lucide-timer"
|
|
183
|
-
:count="counts?.delayed || 0"
|
|
184
|
-
label="Delayed"
|
|
185
|
-
variant="purple"
|
|
186
|
-
/>
|
|
187
|
-
<StatCard
|
|
188
|
-
icon="i-lucide-pause-circle"
|
|
189
|
-
:count="counts?.paused || 0"
|
|
190
|
-
label="Paused"
|
|
191
|
-
variant="gray"
|
|
192
|
-
/>
|
|
193
|
-
</div>
|
|
194
|
-
</div>
|
|
195
|
-
|
|
196
|
-
<!-- Queue Configuration -->
|
|
197
|
-
<div>
|
|
198
|
-
<h3 class="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-4">
|
|
199
|
-
Queue Configuration
|
|
200
|
-
</h3>
|
|
201
|
-
<div class="bg-gray-50 dark:bg-gray-900/50 rounded-lg p-4 space-y-3">
|
|
202
|
-
<div class="flex items-center justify-between py-2 border-b border-gray-200 dark:border-gray-800">
|
|
203
|
-
<span class="text-sm text-gray-600 dark:text-gray-400">Queue Name</span>
|
|
204
|
-
<span class="text-sm font-medium text-gray-900 dark:text-gray-100 font-mono">{{ queueName }}</span>
|
|
205
|
-
</div>
|
|
206
|
-
<div class="flex items-center justify-between py-2 border-b border-gray-200 dark:border-gray-800">
|
|
207
|
-
<span class="text-sm text-gray-600 dark:text-gray-400">Total Jobs</span>
|
|
208
|
-
<span class="text-sm font-medium text-gray-900 dark:text-gray-100">{{ data?.jobs?.length || 0 }}</span>
|
|
209
|
-
</div>
|
|
210
|
-
<div class="flex items-center justify-between py-2">
|
|
211
|
-
<span class="text-sm text-gray-600 dark:text-gray-400">Connection Status</span>
|
|
212
|
-
<UBadge
|
|
213
|
-
:label="isConnected ? 'Connected' : isReconnecting ? 'Reconnecting' : 'Disconnected'"
|
|
214
|
-
:color="isConnected ? 'success' : isReconnecting ? 'warning' : 'error'"
|
|
215
|
-
variant="subtle"
|
|
216
|
-
size="xs"
|
|
217
|
-
/>
|
|
218
|
-
</div>
|
|
219
|
-
</div>
|
|
220
|
-
</div>
|
|
221
|
-
</div>
|
|
222
|
-
|
|
223
|
-
<!-- Job Details Tab -->
|
|
224
|
-
<div
|
|
225
|
-
v-else-if="activeTab === 'details' && selectedJob"
|
|
226
|
-
class="p-6 space-y-6"
|
|
227
|
-
>
|
|
228
|
-
<!-- Job Info -->
|
|
229
|
-
<div>
|
|
230
|
-
<h3 class="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-4 flex items-center gap-2">
|
|
231
|
-
<UIcon
|
|
232
|
-
:name="getJobIcon(selectedJob.state)"
|
|
233
|
-
class="w-5 h-5"
|
|
234
|
-
:class="getJobIconColor(selectedJob.state)"
|
|
235
|
-
/>
|
|
236
|
-
<span>Job Information</span>
|
|
237
|
-
</h3>
|
|
238
|
-
<div class="bg-gray-50 dark:bg-gray-900/50 rounded-lg p-4 space-y-3">
|
|
239
|
-
<div class="flex items-center justify-between py-2 border-b border-gray-200 dark:border-gray-800">
|
|
240
|
-
<span class="text-sm text-gray-600 dark:text-gray-400">ID</span>
|
|
241
|
-
<span class="text-xs font-mono text-gray-900 dark:text-gray-100">{{ selectedJob.id }}</span>
|
|
242
|
-
</div>
|
|
243
|
-
<div class="flex items-center justify-between py-2 border-b border-gray-200 dark:border-gray-800">
|
|
244
|
-
<span class="text-sm text-gray-600 dark:text-gray-400">Name</span>
|
|
245
|
-
<span class="text-sm font-medium text-gray-900 dark:text-gray-100">{{ selectedJob.name }}</span>
|
|
246
|
-
</div>
|
|
247
|
-
<div class="flex items-center justify-between py-2">
|
|
248
|
-
<span class="text-sm text-gray-600 dark:text-gray-400">State</span>
|
|
249
|
-
<UBadge
|
|
250
|
-
:label="selectedJob.state || 'unknown'"
|
|
251
|
-
:color="getStateBadgeColor(selectedJob.state)"
|
|
252
|
-
variant="subtle"
|
|
253
|
-
size="xs"
|
|
254
|
-
class="capitalize"
|
|
255
|
-
/>
|
|
256
|
-
</div>
|
|
257
|
-
</div>
|
|
258
|
-
</div>
|
|
259
|
-
|
|
260
|
-
<!-- Timing -->
|
|
261
|
-
<div>
|
|
262
|
-
<h3 class="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-4">
|
|
263
|
-
Timing
|
|
264
|
-
</h3>
|
|
265
|
-
<div class="space-y-4">
|
|
266
|
-
<div class="grid grid-cols-1 gap-3">
|
|
267
|
-
<div class="flex items-center justify-between py-2 bg-gray-50 dark:bg-gray-900/50 rounded-lg px-4">
|
|
268
|
-
<span class="text-sm text-gray-600 dark:text-gray-400">Created</span>
|
|
269
|
-
<span class="text-sm font-medium text-gray-900 dark:text-gray-100">{{ formatDate(selectedJob.timestamp) }}</span>
|
|
270
|
-
</div>
|
|
271
|
-
<div
|
|
272
|
-
v-if="selectedJob.processedOn"
|
|
273
|
-
class="flex items-center justify-between py-2 bg-gray-50 dark:bg-gray-900/50 rounded-lg px-4"
|
|
274
|
-
>
|
|
275
|
-
<span class="text-sm text-gray-600 dark:text-gray-400">Processed</span>
|
|
276
|
-
<span class="text-sm font-medium text-gray-900 dark:text-gray-100">{{ formatDate(selectedJob.processedOn) }}</span>
|
|
277
|
-
</div>
|
|
278
|
-
<div
|
|
279
|
-
v-if="selectedJob.finishedOn"
|
|
280
|
-
class="flex items-center justify-between py-2 bg-gray-50 dark:bg-gray-900/50 rounded-lg px-4"
|
|
281
|
-
>
|
|
282
|
-
<span class="text-sm text-gray-600 dark:text-gray-400">Finished</span>
|
|
283
|
-
<span class="text-sm font-medium text-gray-900 dark:text-gray-100">{{ formatDate(selectedJob.finishedOn) }}</span>
|
|
284
|
-
</div>
|
|
285
|
-
</div>
|
|
286
|
-
|
|
287
|
-
<!-- Duration Cards -->
|
|
288
|
-
<div
|
|
289
|
-
v-if="selectedJobWaitDuration || selectedJobExecutionDuration"
|
|
290
|
-
class="grid grid-cols-2 gap-3 pt-2"
|
|
291
|
-
>
|
|
292
|
-
<div
|
|
293
|
-
v-if="selectedJobWaitDuration"
|
|
294
|
-
class="bg-blue-50 dark:bg-blue-950/30 border border-blue-200 dark:border-blue-800 rounded-lg p-4 text-center"
|
|
295
|
-
>
|
|
296
|
-
<p class="text-xs text-blue-600 dark:text-blue-400 mb-1">
|
|
297
|
-
Wait Time
|
|
298
|
-
</p>
|
|
299
|
-
<p class="text-lg font-bold text-blue-700 dark:text-blue-300">
|
|
300
|
-
{{ selectedJobWaitDuration }}
|
|
301
|
-
</p>
|
|
302
|
-
</div>
|
|
303
|
-
<div
|
|
304
|
-
v-if="selectedJobExecutionDuration"
|
|
305
|
-
class="rounded-lg p-4 text-center border"
|
|
306
|
-
:class="selectedJob.state === 'active' ? 'bg-amber-50 dark:bg-amber-950/30 border-amber-200 dark:border-amber-800' : 'bg-emerald-50 dark:bg-emerald-950/30 border-emerald-200 dark:border-emerald-800'"
|
|
307
|
-
>
|
|
308
|
-
<p
|
|
309
|
-
class="text-xs mb-1"
|
|
310
|
-
:class="selectedJob.state === 'active' ? 'text-amber-600 dark:text-amber-400' : 'text-emerald-600 dark:text-emerald-400'"
|
|
311
|
-
>
|
|
312
|
-
{{ selectedJob.state === "active" ? "Running" : "Execution" }}
|
|
313
|
-
</p>
|
|
314
|
-
<p
|
|
315
|
-
class="text-lg font-bold"
|
|
316
|
-
:class="selectedJob.state === 'active' ? 'text-amber-700 dark:text-amber-300' : 'text-emerald-700 dark:text-emerald-300'"
|
|
317
|
-
>
|
|
318
|
-
{{ selectedJobExecutionDuration }}
|
|
319
|
-
</p>
|
|
320
|
-
</div>
|
|
321
|
-
</div>
|
|
322
|
-
</div>
|
|
323
|
-
</div>
|
|
324
|
-
|
|
325
|
-
<!-- Job Data -->
|
|
326
|
-
<div>
|
|
327
|
-
<h3 class="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-4">
|
|
328
|
-
Job Data
|
|
329
|
-
</h3>
|
|
330
|
-
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 overflow-x-auto">
|
|
331
|
-
<pre class="text-xs font-mono">{{ JSON.stringify(selectedJob.data, null, 2) }}</pre>
|
|
332
|
-
</div>
|
|
333
|
-
</div>
|
|
334
|
-
|
|
335
|
-
<!-- Return Value -->
|
|
336
|
-
<div v-if="selectedJob.returnvalue">
|
|
337
|
-
<h3 class="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-4">
|
|
338
|
-
Return Value
|
|
339
|
-
</h3>
|
|
340
|
-
<div class="bg-emerald-50 dark:bg-emerald-950/30 border border-emerald-200 dark:border-emerald-800 rounded-lg p-4 overflow-x-auto">
|
|
341
|
-
<pre class="text-xs font-mono text-emerald-900 dark:text-emerald-100">{{ JSON.stringify(selectedJob.returnvalue, null, 2) }}</pre>
|
|
342
|
-
</div>
|
|
343
|
-
</div>
|
|
344
|
-
|
|
345
|
-
<!-- Error -->
|
|
346
|
-
<div v-if="selectedJob.failedReason">
|
|
347
|
-
<h3 class="text-sm font-semibold text-red-600 dark:text-red-400 mb-4">
|
|
348
|
-
Error
|
|
349
|
-
</h3>
|
|
350
|
-
<div class="bg-red-50 dark:bg-red-950/30 border border-red-200 dark:border-red-800 rounded-lg p-4">
|
|
351
|
-
<p class="text-sm text-red-700 dark:text-red-300 whitespace-pre-wrap">
|
|
352
|
-
{{ selectedJob.failedReason }}
|
|
353
|
-
</p>
|
|
354
|
-
</div>
|
|
355
|
-
</div>
|
|
356
|
-
</div>
|
|
357
|
-
</div>
|
|
358
|
-
</div>
|
|
359
|
-
</div>
|
|
360
|
-
</div>
|
|
361
|
-
|
|
362
|
-
<!-- Configuration Slideover -->
|
|
363
|
-
<USlideover
|
|
364
|
-
v-model:open="showConfig"
|
|
365
|
-
title="Queue Configuration"
|
|
366
|
-
>
|
|
367
|
-
<template #body>
|
|
368
|
-
<QueueConfiguration
|
|
369
|
-
:queue-name="queueName"
|
|
370
|
-
:queue-config="queueInfo?.config?.queue"
|
|
371
|
-
:worker-config="queueInfo?.config?.worker"
|
|
372
|
-
/>
|
|
373
|
-
</template>
|
|
374
|
-
</USlideover>
|
|
375
|
-
</div>
|
|
376
|
-
</template>
|
|
377
|
-
|
|
378
|
-
<script setup>
|
|
379
|
-
import { ref, computed, watch } from "#imports";
|
|
380
|
-
import { useQueueJobs } from "../../composables/useQueueJobs";
|
|
381
|
-
import { useQueueUpdates } from "../../composables/useQueueUpdates";
|
|
382
|
-
import { useQueues } from "../../composables/useQueues";
|
|
383
|
-
import { useComponentRouter } from "../../composables/useComponentRouter";
|
|
384
|
-
import { useRoute, useRouter } from "#app";
|
|
385
|
-
import StatCard from "../../components/StatCard.vue";
|
|
386
|
-
import QueueConfiguration from "../../components/QueueConfiguration.vue";
|
|
387
|
-
import SelectableListItem from "../../components/SelectableListItem.vue";
|
|
388
|
-
const componentRouter = useComponentRouter();
|
|
389
|
-
const router = useRouter();
|
|
390
|
-
const route = useRoute();
|
|
391
|
-
const queueName = computed(() => componentRouter.route.value?.params?.name || "");
|
|
392
|
-
const stateOptions = [
|
|
393
|
-
{ label: "All States", value: null },
|
|
394
|
-
{ label: "Waiting", value: "waiting" },
|
|
395
|
-
{ label: "Active", value: "active" },
|
|
396
|
-
{ label: "Completed", value: "completed" },
|
|
397
|
-
{ label: "Failed", value: "failed" },
|
|
398
|
-
{ label: "Delayed", value: "delayed" },
|
|
399
|
-
{ label: "Paused", value: "paused" }
|
|
400
|
-
];
|
|
401
|
-
const selectedState = computed({
|
|
402
|
-
get: () => route.query.state || null,
|
|
403
|
-
set: (value) => {
|
|
404
|
-
router.push({
|
|
405
|
-
query: {
|
|
406
|
-
...route.query,
|
|
407
|
-
state: value || void 0,
|
|
408
|
-
page: void 0
|
|
409
|
-
// Reset page when filter changes
|
|
410
|
-
}
|
|
411
|
-
});
|
|
412
|
-
}
|
|
413
|
-
});
|
|
414
|
-
const currentPage = computed({
|
|
415
|
-
get: () => {
|
|
416
|
-
const page = route.query.page;
|
|
417
|
-
return page ? Number.parseInt(page, 10) : 1;
|
|
418
|
-
},
|
|
419
|
-
set: (value) => {
|
|
420
|
-
router.push({
|
|
421
|
-
query: {
|
|
422
|
-
...route.query,
|
|
423
|
-
page: value > 1 ? value.toString() : void 0
|
|
424
|
-
}
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
|
-
});
|
|
428
|
-
const selectedStateOption = computed({
|
|
429
|
-
get: () => stateOptions.find((opt) => opt.value === selectedState.value) || stateOptions[0],
|
|
430
|
-
set: (option) => {
|
|
431
|
-
selectedState.value = option.value;
|
|
432
|
-
}
|
|
433
|
-
});
|
|
434
|
-
const jobsPerPage = 20;
|
|
435
|
-
const jobQueryOptions = computed(() => ({
|
|
436
|
-
state: selectedState.value,
|
|
437
|
-
limit: jobsPerPage,
|
|
438
|
-
offset: (currentPage.value - 1) * jobsPerPage
|
|
439
|
-
}));
|
|
440
|
-
const { data, refresh } = useQueueJobs(queueName, jobQueryOptions);
|
|
441
|
-
const { counts: liveCounts, isConnected, isReconnecting, shouldRefreshJobs, resetRefreshFlag } = useQueueUpdates(queueName);
|
|
442
|
-
const { queues } = useQueues();
|
|
443
|
-
const queueInfo = computed(() => {
|
|
444
|
-
return queues.value?.find((q) => q.name === queueName.value);
|
|
445
|
-
});
|
|
446
|
-
const counts = computed(() => liveCounts.value || queueInfo.value?.counts || null);
|
|
447
|
-
watch(shouldRefreshJobs, async (shouldRefresh) => {
|
|
448
|
-
if (shouldRefresh) {
|
|
449
|
-
await refresh();
|
|
450
|
-
resetRefreshFlag();
|
|
451
|
-
}
|
|
452
|
-
});
|
|
453
|
-
watch(() => jobQueryOptions.value, () => {
|
|
454
|
-
refresh();
|
|
455
|
-
}, { deep: true });
|
|
456
|
-
const paginatedJobs = computed(() => {
|
|
457
|
-
return data.value?.jobs || [];
|
|
458
|
-
});
|
|
459
|
-
const selectedJobId = ref(null);
|
|
460
|
-
const selectedJob = computed(() => {
|
|
461
|
-
if (!selectedJobId.value || !data.value?.jobs) return null;
|
|
462
|
-
return data.value.jobs.find((job) => job.id === selectedJobId.value);
|
|
463
|
-
});
|
|
464
|
-
const showConfig = ref(false);
|
|
465
|
-
const activeTab = ref("overview");
|
|
466
|
-
const tabItems = computed(() => [
|
|
467
|
-
{ label: "Overview", value: "overview", icon: "i-lucide-bar-chart-3" },
|
|
468
|
-
{
|
|
469
|
-
label: "Job Details",
|
|
470
|
-
value: "details",
|
|
471
|
-
icon: "i-lucide-file-text",
|
|
472
|
-
disabled: !selectedJobId.value
|
|
473
|
-
}
|
|
474
|
-
]);
|
|
475
|
-
watch(selectedJobId, (newId) => {
|
|
476
|
-
if (newId) {
|
|
477
|
-
activeTab.value = "details";
|
|
478
|
-
showConfig.value = false;
|
|
479
|
-
} else {
|
|
480
|
-
activeTab.value = "overview";
|
|
481
|
-
}
|
|
482
|
-
});
|
|
483
|
-
watch(showConfig, (show) => {
|
|
484
|
-
if (show) {
|
|
485
|
-
selectedJobId.value = null;
|
|
486
|
-
}
|
|
487
|
-
});
|
|
488
|
-
const selectJob = (jobId) => {
|
|
489
|
-
selectedJobId.value = jobId;
|
|
490
|
-
};
|
|
491
|
-
const back = () => {
|
|
492
|
-
componentRouter.push("/queues");
|
|
493
|
-
};
|
|
494
|
-
const getJobIcon = (state) => {
|
|
495
|
-
switch (state) {
|
|
496
|
-
case "waiting":
|
|
497
|
-
return "i-lucide-clock";
|
|
498
|
-
case "active":
|
|
499
|
-
return "i-lucide-loader-2";
|
|
500
|
-
case "completed":
|
|
501
|
-
return "i-lucide-check-circle";
|
|
502
|
-
case "failed":
|
|
503
|
-
return "i-lucide-x-circle";
|
|
504
|
-
case "delayed":
|
|
505
|
-
return "i-lucide-timer";
|
|
506
|
-
case "paused":
|
|
507
|
-
return "i-lucide-pause-circle";
|
|
508
|
-
default:
|
|
509
|
-
return "i-lucide-circle";
|
|
510
|
-
}
|
|
511
|
-
};
|
|
512
|
-
const getJobIconColor = (state) => {
|
|
513
|
-
switch (state) {
|
|
514
|
-
case "waiting":
|
|
515
|
-
return "text-blue-500";
|
|
516
|
-
case "active":
|
|
517
|
-
return "text-amber-500 animate-spin";
|
|
518
|
-
case "completed":
|
|
519
|
-
return "text-emerald-500";
|
|
520
|
-
case "failed":
|
|
521
|
-
return "text-red-500";
|
|
522
|
-
case "delayed":
|
|
523
|
-
return "text-purple-500";
|
|
524
|
-
case "paused":
|
|
525
|
-
return "text-gray-500";
|
|
526
|
-
default:
|
|
527
|
-
return "text-gray-400";
|
|
528
|
-
}
|
|
529
|
-
};
|
|
530
|
-
const getStateBadgeColor = (state) => {
|
|
531
|
-
switch (state) {
|
|
532
|
-
case "waiting":
|
|
533
|
-
return "info";
|
|
534
|
-
case "active":
|
|
535
|
-
return "warning";
|
|
536
|
-
case "completed":
|
|
537
|
-
return "success";
|
|
538
|
-
case "failed":
|
|
539
|
-
return "error";
|
|
540
|
-
case "delayed":
|
|
541
|
-
return "secondary";
|
|
542
|
-
case "paused":
|
|
543
|
-
return "warning";
|
|
544
|
-
default:
|
|
545
|
-
return "neutral";
|
|
546
|
-
}
|
|
547
|
-
};
|
|
548
|
-
const truncateId = (id) => {
|
|
549
|
-
if (id.length <= 16) return id;
|
|
550
|
-
return `${id.substring(0, 8)}...${id.substring(id.length - 8)}`;
|
|
551
|
-
};
|
|
552
|
-
const formatTime = (timestamp) => {
|
|
553
|
-
if (!timestamp) return "-";
|
|
554
|
-
const date = new Date(timestamp);
|
|
555
|
-
const now = /* @__PURE__ */ new Date();
|
|
556
|
-
const diff = now.getTime() - date.getTime();
|
|
557
|
-
const seconds = Math.floor(diff / 1e3);
|
|
558
|
-
const minutes = Math.floor(seconds / 60);
|
|
559
|
-
const hours = Math.floor(minutes / 60);
|
|
560
|
-
const days = Math.floor(hours / 24);
|
|
561
|
-
if (days > 0) return `${days}d ago`;
|
|
562
|
-
if (hours > 0) return `${hours}h ago`;
|
|
563
|
-
if (minutes > 0) return `${minutes}m ago`;
|
|
564
|
-
if (seconds > 10) return `${seconds}s ago`;
|
|
565
|
-
return "just now";
|
|
566
|
-
};
|
|
567
|
-
const formatDuration = (start, end) => {
|
|
568
|
-
const diff = end - start;
|
|
569
|
-
if (diff < 1e3) return `${diff}ms`;
|
|
570
|
-
if (diff < 6e4) return `${(diff / 1e3).toFixed(2)}s`;
|
|
571
|
-
if (diff < 36e5) return `${(diff / 6e4).toFixed(2)}m`;
|
|
572
|
-
return `${(diff / 36e5).toFixed(2)}h`;
|
|
573
|
-
};
|
|
574
|
-
const formatDate = (timestamp) => {
|
|
575
|
-
if (!timestamp) return "-";
|
|
576
|
-
return new Date(timestamp).toLocaleString("de-DE", {
|
|
577
|
-
timeZone: "Europe/Berlin",
|
|
578
|
-
day: "2-digit",
|
|
579
|
-
month: "2-digit",
|
|
580
|
-
year: "numeric",
|
|
581
|
-
hour: "2-digit",
|
|
582
|
-
minute: "2-digit",
|
|
583
|
-
second: "2-digit"
|
|
584
|
-
});
|
|
585
|
-
};
|
|
586
|
-
const selectedJobWaitDuration = computed(() => {
|
|
587
|
-
if (!selectedJob.value?.timestamp || !selectedJob.value?.processedOn) return null;
|
|
588
|
-
return formatDuration(selectedJob.value.timestamp, selectedJob.value.processedOn);
|
|
589
|
-
});
|
|
590
|
-
const selectedJobExecutionDuration = computed(() => {
|
|
591
|
-
if (!selectedJob.value?.processedOn) return null;
|
|
592
|
-
const endTime = selectedJob.value.finishedOn || Date.now();
|
|
593
|
-
return formatDuration(selectedJob.value.processedOn, endTime);
|
|
594
|
-
});
|
|
595
|
-
</script>
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
-
declare const _default: typeof __VLS_export;
|
|
3
|
-
export default _default;
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
-
declare const _default: typeof __VLS_export;
|
|
3
|
-
export default _default;
|