@nvent-addon/app 0.5.15 → 1.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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,870 +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-3">
|
|
7
|
-
<UButton
|
|
8
|
-
icon="i-lucide-arrow-left"
|
|
9
|
-
size="xs"
|
|
10
|
-
color="neutral"
|
|
11
|
-
variant="ghost"
|
|
12
|
-
square
|
|
13
|
-
@click="goBack"
|
|
14
|
-
/>
|
|
15
|
-
<div>
|
|
16
|
-
<h1 class="text-lg font-semibold flex items-center gap-2">
|
|
17
|
-
<UIcon
|
|
18
|
-
:name="getTriggerIcon(trigger?.type || 'event')"
|
|
19
|
-
class="w-5 h-5"
|
|
20
|
-
:class="getTriggerIconColor(trigger?.type || 'event')"
|
|
21
|
-
/>
|
|
22
|
-
<span>{{ trigger?.displayName || trigger?.name }}</span>
|
|
23
|
-
</h1>
|
|
24
|
-
<div class="flex items-center gap-2 mt-1">
|
|
25
|
-
<UBadge
|
|
26
|
-
v-if="trigger"
|
|
27
|
-
:label="trigger.type"
|
|
28
|
-
:color="getTriggerTypeColor(trigger.type)"
|
|
29
|
-
variant="subtle"
|
|
30
|
-
size="xs"
|
|
31
|
-
/>
|
|
32
|
-
<UBadge
|
|
33
|
-
v-if="trigger"
|
|
34
|
-
:label="trigger.scope"
|
|
35
|
-
color="neutral"
|
|
36
|
-
variant="subtle"
|
|
37
|
-
size="xs"
|
|
38
|
-
/>
|
|
39
|
-
<UBadge
|
|
40
|
-
v-if="trigger"
|
|
41
|
-
:label="trigger.status"
|
|
42
|
-
:color="trigger.status === 'active' ? 'success' : trigger.status === 'inactive' ? 'warning' : 'neutral'"
|
|
43
|
-
variant="subtle"
|
|
44
|
-
size="xs"
|
|
45
|
-
/>
|
|
46
|
-
</div>
|
|
47
|
-
</div>
|
|
48
|
-
</div>
|
|
49
|
-
<div class="flex items-center gap-3">
|
|
50
|
-
<UButton
|
|
51
|
-
icon="i-lucide-pencil"
|
|
52
|
-
color="neutral"
|
|
53
|
-
variant="outline"
|
|
54
|
-
size="sm"
|
|
55
|
-
@click="goToEdit"
|
|
56
|
-
>
|
|
57
|
-
Edit
|
|
58
|
-
</UButton>
|
|
59
|
-
<div
|
|
60
|
-
v-if="isConnected"
|
|
61
|
-
class="flex items-center gap-1.5 text-xs text-emerald-600 dark:text-emerald-400"
|
|
62
|
-
>
|
|
63
|
-
<div class="w-2 h-2 rounded-full bg-emerald-500 animate-pulse" />
|
|
64
|
-
<span>Live</span>
|
|
65
|
-
</div>
|
|
66
|
-
<div
|
|
67
|
-
v-else-if="isReconnecting"
|
|
68
|
-
class="flex items-center gap-1.5 text-xs text-amber-600 dark:text-amber-400"
|
|
69
|
-
>
|
|
70
|
-
<div class="w-2 h-2 rounded-full bg-amber-500 animate-pulse" />
|
|
71
|
-
<span>Reconnecting...</span>
|
|
72
|
-
</div>
|
|
73
|
-
</div>
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|
|
76
|
-
|
|
77
|
-
<!-- Main Content -->
|
|
78
|
-
<div class="flex-1 min-h-0 overflow-hidden">
|
|
79
|
-
<div
|
|
80
|
-
v-if="status === 'pending' && !trigger"
|
|
81
|
-
class="h-full flex items-center justify-center"
|
|
82
|
-
>
|
|
83
|
-
<div class="text-center">
|
|
84
|
-
<UIcon
|
|
85
|
-
name="i-lucide-loader-2"
|
|
86
|
-
class="w-8 h-8 animate-spin mx-auto mb-2 text-gray-400"
|
|
87
|
-
/>
|
|
88
|
-
<p class="text-sm text-gray-500 dark:text-gray-400">
|
|
89
|
-
Loading trigger...
|
|
90
|
-
</p>
|
|
91
|
-
</div>
|
|
92
|
-
</div>
|
|
93
|
-
|
|
94
|
-
<div
|
|
95
|
-
v-else-if="!trigger"
|
|
96
|
-
class="h-full flex items-center justify-center"
|
|
97
|
-
>
|
|
98
|
-
<div class="text-center">
|
|
99
|
-
<UIcon
|
|
100
|
-
name="i-lucide-alert-circle"
|
|
101
|
-
class="w-8 h-8 mx-auto mb-2 text-gray-300 dark:text-gray-700"
|
|
102
|
-
/>
|
|
103
|
-
<p class="text-sm text-gray-500 dark:text-gray-400">
|
|
104
|
-
Trigger not found
|
|
105
|
-
</p>
|
|
106
|
-
</div>
|
|
107
|
-
</div>
|
|
108
|
-
|
|
109
|
-
<div
|
|
110
|
-
v-else
|
|
111
|
-
class="h-full flex gap-px bg-gray-200 dark:bg-gray-800"
|
|
112
|
-
>
|
|
113
|
-
<!-- Left: Events List -->
|
|
114
|
-
<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">
|
|
115
|
-
<div class="px-4 py-3 border-b border-gray-200 dark:border-gray-800 flex items-center justify-between shrink-0">
|
|
116
|
-
<h2 class="text-sm font-medium text-gray-900 dark:text-gray-100">
|
|
117
|
-
Events
|
|
118
|
-
</h2>
|
|
119
|
-
<div class="flex items-center gap-2">
|
|
120
|
-
<USelectMenu
|
|
121
|
-
v-model="eventTypeFilter"
|
|
122
|
-
:items="eventTypeFilterOptions"
|
|
123
|
-
value-key="value"
|
|
124
|
-
placeholder="All Events"
|
|
125
|
-
size="xs"
|
|
126
|
-
class="w-40"
|
|
127
|
-
>
|
|
128
|
-
<template #label>
|
|
129
|
-
<div class="flex items-center gap-2">
|
|
130
|
-
<UIcon
|
|
131
|
-
:name="getFilterIcon(eventTypeFilter)"
|
|
132
|
-
class="w-4 h-4"
|
|
133
|
-
:class="getFilterIconColor(eventTypeFilter)"
|
|
134
|
-
/>
|
|
135
|
-
<span class="text-xs">{{ getFilterLabel(eventTypeFilter) }}</span>
|
|
136
|
-
</div>
|
|
137
|
-
</template>
|
|
138
|
-
<template #option="{ option }">
|
|
139
|
-
<div class="flex items-center gap-2">
|
|
140
|
-
<UIcon
|
|
141
|
-
:name="getFilterIcon(option.value)"
|
|
142
|
-
class="w-4 h-4"
|
|
143
|
-
:class="getFilterIconColor(option.value)"
|
|
144
|
-
/>
|
|
145
|
-
<span>{{ option.label }}</span>
|
|
146
|
-
</div>
|
|
147
|
-
</template>
|
|
148
|
-
</USelectMenu>
|
|
149
|
-
</div>
|
|
150
|
-
</div>
|
|
151
|
-
|
|
152
|
-
<div
|
|
153
|
-
v-if="eventsStatus === 'pending' && !events"
|
|
154
|
-
class="flex-1 flex items-center justify-center"
|
|
155
|
-
>
|
|
156
|
-
<div class="text-center">
|
|
157
|
-
<UIcon
|
|
158
|
-
name="i-lucide-loader-2"
|
|
159
|
-
class="w-8 h-8 animate-spin mx-auto mb-2 text-gray-400"
|
|
160
|
-
/>
|
|
161
|
-
<p class="text-sm text-gray-500 dark:text-gray-400">
|
|
162
|
-
Loading events...
|
|
163
|
-
</p>
|
|
164
|
-
</div>
|
|
165
|
-
</div>
|
|
166
|
-
|
|
167
|
-
<div
|
|
168
|
-
v-else-if="!events || events.events.length === 0"
|
|
169
|
-
class="flex-1 flex items-center justify-center"
|
|
170
|
-
>
|
|
171
|
-
<div class="text-center">
|
|
172
|
-
<UIcon
|
|
173
|
-
name="i-lucide-inbox"
|
|
174
|
-
class="w-8 h-8 mx-auto mb-2 text-gray-300 dark:text-gray-700"
|
|
175
|
-
/>
|
|
176
|
-
<p class="text-sm text-gray-500 dark:text-gray-400">
|
|
177
|
-
No events yet
|
|
178
|
-
</p>
|
|
179
|
-
</div>
|
|
180
|
-
</div>
|
|
181
|
-
|
|
182
|
-
<div
|
|
183
|
-
v-else
|
|
184
|
-
class="flex-1 min-h-0 overflow-y-auto"
|
|
185
|
-
>
|
|
186
|
-
<div class="divide-y divide-gray-100 dark:divide-gray-800">
|
|
187
|
-
<SelectableListItem
|
|
188
|
-
v-for="(event, idx) in paginatedEvents"
|
|
189
|
-
:key="idx"
|
|
190
|
-
:selected="!!(selectedEvent && selectedEvent.type === event.type && (selectedEvent.ts || selectedEvent.timestamp) === (event.ts || event.timestamp))"
|
|
191
|
-
:icon="getEventIcon(event.type)"
|
|
192
|
-
:icon-class="getEventIconColor(event.type)"
|
|
193
|
-
:title="event.type"
|
|
194
|
-
:subtitle="formatDate(event.ts || event.timestamp)"
|
|
195
|
-
:badge="event.type.split('.')[1] || 'event'"
|
|
196
|
-
:badge-color="getEventBadgeColor(event.type)"
|
|
197
|
-
:meta="formatTime(event.ts || event.timestamp)"
|
|
198
|
-
@click="selectEvent(event)"
|
|
199
|
-
/>
|
|
200
|
-
</div>
|
|
201
|
-
</div>
|
|
202
|
-
|
|
203
|
-
<!-- Pagination Footer -->
|
|
204
|
-
<div
|
|
205
|
-
v-if="events && (events.total || events.count) > eventsPerPage"
|
|
206
|
-
class="border-t border-gray-200 dark:border-gray-800 px-4 py-3 flex items-center justify-center shrink-0"
|
|
207
|
-
>
|
|
208
|
-
<UPagination
|
|
209
|
-
v-model:page="currentPage"
|
|
210
|
-
:items-per-page="eventsPerPage"
|
|
211
|
-
:total="events.total || events.count"
|
|
212
|
-
size="xs"
|
|
213
|
-
/>
|
|
214
|
-
</div>
|
|
215
|
-
</div>
|
|
216
|
-
|
|
217
|
-
<!-- Right: Overview or Event Details -->
|
|
218
|
-
<div class="flex-1 min-w-0 bg-white dark:bg-gray-950 flex flex-col min-h-0 overflow-hidden">
|
|
219
|
-
<div class="px-4 py-2.5 border-b border-gray-200 dark:border-gray-800 shrink-0">
|
|
220
|
-
<div class="flex items-center justify-between">
|
|
221
|
-
<UTabs
|
|
222
|
-
v-model="activeTab"
|
|
223
|
-
:items="tabItems"
|
|
224
|
-
size="xs"
|
|
225
|
-
:ui="{
|
|
226
|
-
root: 'gap-0',
|
|
227
|
-
trigger: 'px-2 py-0.5'
|
|
228
|
-
}"
|
|
229
|
-
/>
|
|
230
|
-
</div>
|
|
231
|
-
</div>
|
|
232
|
-
|
|
233
|
-
<div class="flex-1 min-h-0 overflow-y-auto">
|
|
234
|
-
<!-- Overview Tab -->
|
|
235
|
-
<div
|
|
236
|
-
v-if="activeTab === 'overview'"
|
|
237
|
-
class="p-6 space-y-6"
|
|
238
|
-
>
|
|
239
|
-
<!-- Stats Cards -->
|
|
240
|
-
<div>
|
|
241
|
-
<h3 class="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-4">
|
|
242
|
-
Trigger Statistics
|
|
243
|
-
</h3>
|
|
244
|
-
<div class="grid grid-cols-2 gap-4">
|
|
245
|
-
<StatCard
|
|
246
|
-
icon="i-lucide-zap"
|
|
247
|
-
:count="trigger.stats.totalFires"
|
|
248
|
-
label="Total Fires"
|
|
249
|
-
variant="gray"
|
|
250
|
-
/>
|
|
251
|
-
<StatCard
|
|
252
|
-
icon="i-lucide-git-branch"
|
|
253
|
-
:count="trigger.stats.activeSubscribers"
|
|
254
|
-
label="Active Subscribers"
|
|
255
|
-
variant="purple"
|
|
256
|
-
/>
|
|
257
|
-
<StatCard
|
|
258
|
-
v-if="trigger.stats.lastFiredAt"
|
|
259
|
-
icon="i-lucide-clock"
|
|
260
|
-
:count="formatTime(new Date(trigger.stats.lastFiredAt).getTime())"
|
|
261
|
-
label="Last Fired"
|
|
262
|
-
variant="blue"
|
|
263
|
-
/>
|
|
264
|
-
<StatCard
|
|
265
|
-
icon="i-lucide-users"
|
|
266
|
-
:count="trigger.subscriptionCount"
|
|
267
|
-
label="Subscriptions"
|
|
268
|
-
variant="emerald"
|
|
269
|
-
/>
|
|
270
|
-
</div>
|
|
271
|
-
</div>
|
|
272
|
-
|
|
273
|
-
<!-- Description -->
|
|
274
|
-
<div
|
|
275
|
-
v-if="trigger.description"
|
|
276
|
-
class="bg-blue-50 dark:bg-blue-950/30 border border-blue-200 dark:border-blue-800 rounded-lg p-4"
|
|
277
|
-
>
|
|
278
|
-
<div class="flex items-start gap-2">
|
|
279
|
-
<UIcon
|
|
280
|
-
name="i-lucide-info"
|
|
281
|
-
class="w-4 h-4 text-blue-600 dark:text-blue-400 mt-0.5 shrink-0"
|
|
282
|
-
/>
|
|
283
|
-
<p class="text-sm text-blue-900 dark:text-blue-100">
|
|
284
|
-
{{ trigger.description }}
|
|
285
|
-
</p>
|
|
286
|
-
</div>
|
|
287
|
-
</div>
|
|
288
|
-
|
|
289
|
-
<!-- Configuration -->
|
|
290
|
-
<div>
|
|
291
|
-
<h3 class="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-4">
|
|
292
|
-
Configuration
|
|
293
|
-
</h3>
|
|
294
|
-
<div class="bg-gray-50 dark:bg-gray-900/50 rounded-lg p-4 space-y-3">
|
|
295
|
-
<div class="flex items-center justify-between py-2 border-b border-gray-200 dark:border-gray-800">
|
|
296
|
-
<span class="text-sm text-gray-600 dark:text-gray-400">Name</span>
|
|
297
|
-
<span class="text-sm font-medium font-mono text-gray-900 dark:text-gray-100">{{ trigger.name }}</span>
|
|
298
|
-
</div>
|
|
299
|
-
<div class="flex items-center justify-between py-2 border-b border-gray-200 dark:border-gray-800">
|
|
300
|
-
<span class="text-sm text-gray-600 dark:text-gray-400">Type</span>
|
|
301
|
-
<UBadge
|
|
302
|
-
:label="trigger.type"
|
|
303
|
-
:color="getTriggerTypeColor(trigger.type)"
|
|
304
|
-
variant="subtle"
|
|
305
|
-
size="xs"
|
|
306
|
-
/>
|
|
307
|
-
</div>
|
|
308
|
-
<div class="flex items-center justify-between py-2 border-b border-gray-200 dark:border-gray-800">
|
|
309
|
-
<span class="text-sm text-gray-600 dark:text-gray-400">Scope</span>
|
|
310
|
-
<span class="text-sm font-medium text-gray-900 dark:text-gray-100">{{ trigger.scope }}</span>
|
|
311
|
-
</div>
|
|
312
|
-
<div
|
|
313
|
-
v-if="trigger.source"
|
|
314
|
-
class="flex items-center justify-between py-2 border-b border-gray-200 dark:border-gray-800"
|
|
315
|
-
>
|
|
316
|
-
<span class="text-sm text-gray-600 dark:text-gray-400">Source</span>
|
|
317
|
-
<span class="text-sm font-medium text-gray-900 dark:text-gray-100">{{ trigger.source }}</span>
|
|
318
|
-
</div>
|
|
319
|
-
<div
|
|
320
|
-
v-if="trigger.registeredAt"
|
|
321
|
-
class="flex items-center justify-between py-2 border-b border-gray-200 dark:border-gray-800"
|
|
322
|
-
>
|
|
323
|
-
<span class="text-sm text-gray-600 dark:text-gray-400">Registered</span>
|
|
324
|
-
<span class="text-sm font-medium text-gray-900 dark:text-gray-100">{{ formatDate(trigger.registeredAt) }}</span>
|
|
325
|
-
</div>
|
|
326
|
-
<div
|
|
327
|
-
v-if="trigger.stats.lastFiredAt"
|
|
328
|
-
class="flex items-center justify-between py-2 border-b border-gray-200 dark:border-gray-800"
|
|
329
|
-
>
|
|
330
|
-
<span class="text-sm text-gray-600 dark:text-gray-400">Last Fired</span>
|
|
331
|
-
<span class="text-sm font-medium text-gray-900 dark:text-gray-100">{{ formatTime(trigger.stats.lastFiredAt) }}</span>
|
|
332
|
-
</div>
|
|
333
|
-
<div
|
|
334
|
-
v-if="trigger.lastActivityAt"
|
|
335
|
-
class="flex items-center justify-between py-2"
|
|
336
|
-
>
|
|
337
|
-
<span class="text-sm text-gray-600 dark:text-gray-400">Last Modified</span>
|
|
338
|
-
<span class="text-sm font-medium text-gray-900 dark:text-gray-100">{{ formatTime(trigger.lastActivityAt) }}</span>
|
|
339
|
-
</div>
|
|
340
|
-
</div>
|
|
341
|
-
</div>
|
|
342
|
-
|
|
343
|
-
<!-- Webhook Config -->
|
|
344
|
-
<div v-if="trigger.webhook">
|
|
345
|
-
<h3 class="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-3">
|
|
346
|
-
Webhook Configuration
|
|
347
|
-
</h3>
|
|
348
|
-
<div class="space-y-3">
|
|
349
|
-
<div class="bg-gray-50 dark:bg-gray-900/50 rounded-lg p-3">
|
|
350
|
-
<div class="flex items-center justify-between mb-2">
|
|
351
|
-
<span class="text-xs text-gray-500 dark:text-gray-400">Webhook URL</span>
|
|
352
|
-
<UButton
|
|
353
|
-
v-if="trigger.webhook.fullUrl"
|
|
354
|
-
icon="i-lucide-copy"
|
|
355
|
-
size="xs"
|
|
356
|
-
color="neutral"
|
|
357
|
-
variant="ghost"
|
|
358
|
-
@click="copyToClipboard(trigger.webhook.fullUrl)"
|
|
359
|
-
/>
|
|
360
|
-
</div>
|
|
361
|
-
<code class="text-xs font-mono text-blue-600 dark:text-blue-400 break-all">
|
|
362
|
-
{{ trigger.webhook.fullUrl || trigger.webhook.path }}
|
|
363
|
-
</code>
|
|
364
|
-
</div>
|
|
365
|
-
<div class="flex items-center justify-between py-2 border-b border-gray-100 dark:border-gray-800">
|
|
366
|
-
<span class="text-sm text-gray-500 dark:text-gray-400">Method</span>
|
|
367
|
-
<UBadge
|
|
368
|
-
:label="trigger.webhook.method || 'POST'"
|
|
369
|
-
color="neutral"
|
|
370
|
-
variant="subtle"
|
|
371
|
-
size="xs"
|
|
372
|
-
/>
|
|
373
|
-
</div>
|
|
374
|
-
</div>
|
|
375
|
-
</div>
|
|
376
|
-
|
|
377
|
-
<!-- Schedule Config -->
|
|
378
|
-
<div v-if="trigger.schedule">
|
|
379
|
-
<h3 class="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-3">
|
|
380
|
-
Schedule Configuration
|
|
381
|
-
</h3>
|
|
382
|
-
<div class="space-y-2 text-sm">
|
|
383
|
-
<div
|
|
384
|
-
v-if="trigger.schedule.cron"
|
|
385
|
-
class="flex items-center justify-between py-2 border-b border-gray-100 dark:border-gray-800"
|
|
386
|
-
>
|
|
387
|
-
<span class="text-gray-500 dark:text-gray-400">Cron Expression</span>
|
|
388
|
-
<span class="font-mono text-gray-900 dark:text-gray-100">{{ trigger.schedule.cron }}</span>
|
|
389
|
-
</div>
|
|
390
|
-
<div
|
|
391
|
-
v-if="trigger.schedule.interval"
|
|
392
|
-
class="flex items-center justify-between py-2 border-b border-gray-100 dark:border-gray-800"
|
|
393
|
-
>
|
|
394
|
-
<span class="text-gray-500 dark:text-gray-400">Interval</span>
|
|
395
|
-
<span class="text-gray-900 dark:text-gray-100">{{ formatInterval(trigger.schedule.interval) }}</span>
|
|
396
|
-
</div>
|
|
397
|
-
<div
|
|
398
|
-
v-if="trigger.schedule.timezone"
|
|
399
|
-
class="flex items-center justify-between py-2"
|
|
400
|
-
>
|
|
401
|
-
<span class="text-gray-500 dark:text-gray-400">Timezone</span>
|
|
402
|
-
<span class="text-gray-900 dark:text-gray-100">{{ trigger.schedule.timezone }}</span>
|
|
403
|
-
</div>
|
|
404
|
-
</div>
|
|
405
|
-
</div>
|
|
406
|
-
|
|
407
|
-
<!-- Subscribed Flows -->
|
|
408
|
-
<div>
|
|
409
|
-
<h3 class="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-4">
|
|
410
|
-
Subscribed Flows ({{ trigger.subscriptionCount }})
|
|
411
|
-
</h3>
|
|
412
|
-
<div
|
|
413
|
-
v-if="trigger.subscriptions.length === 0"
|
|
414
|
-
class="text-center py-8"
|
|
415
|
-
>
|
|
416
|
-
<UIcon
|
|
417
|
-
name="i-lucide-git-branch-plus"
|
|
418
|
-
class="w-8 h-8 mx-auto mb-2 text-gray-300 dark:text-gray-700"
|
|
419
|
-
/>
|
|
420
|
-
<p class="text-sm text-gray-500 dark:text-gray-400">
|
|
421
|
-
No subscriptions
|
|
422
|
-
</p>
|
|
423
|
-
</div>
|
|
424
|
-
<div
|
|
425
|
-
v-else
|
|
426
|
-
class="space-y-2"
|
|
427
|
-
>
|
|
428
|
-
<div
|
|
429
|
-
v-for="sub in trigger.subscriptions"
|
|
430
|
-
:key="`${sub.flowName}-${sub.triggerName}`"
|
|
431
|
-
class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-900/50 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-900 transition-colors cursor-pointer"
|
|
432
|
-
@click="goToFlow(sub.flowName)"
|
|
433
|
-
>
|
|
434
|
-
<div class="flex items-center gap-2 min-w-0">
|
|
435
|
-
<UIcon
|
|
436
|
-
name="i-lucide-git-branch"
|
|
437
|
-
class="w-4 h-4 text-blue-500 shrink-0"
|
|
438
|
-
/>
|
|
439
|
-
<span class="text-sm font-medium text-gray-900 dark:text-gray-100 truncate">{{ sub.flowName }}</span>
|
|
440
|
-
</div>
|
|
441
|
-
<div class="flex items-center gap-2">
|
|
442
|
-
<UBadge
|
|
443
|
-
:label="sub.mode"
|
|
444
|
-
:color="sub.mode === 'auto' ? 'success' : 'neutral'"
|
|
445
|
-
variant="subtle"
|
|
446
|
-
size="xs"
|
|
447
|
-
/>
|
|
448
|
-
<UIcon
|
|
449
|
-
name="i-lucide-arrow-right"
|
|
450
|
-
class="w-4 h-4 text-gray-400"
|
|
451
|
-
/>
|
|
452
|
-
</div>
|
|
453
|
-
</div>
|
|
454
|
-
</div>
|
|
455
|
-
</div>
|
|
456
|
-
</div>
|
|
457
|
-
|
|
458
|
-
<!-- Event Details Tab -->
|
|
459
|
-
<div
|
|
460
|
-
v-else-if="activeTab === 'details' && selectedEvent"
|
|
461
|
-
class="p-6 space-y-6"
|
|
462
|
-
>
|
|
463
|
-
<!-- Event Info -->
|
|
464
|
-
<div>
|
|
465
|
-
<h3 class="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-4 flex items-center gap-2">
|
|
466
|
-
<UIcon
|
|
467
|
-
:name="getEventIcon(selectedEvent.type)"
|
|
468
|
-
class="w-5 h-5"
|
|
469
|
-
:class="getEventIconColor(selectedEvent.type)"
|
|
470
|
-
/>
|
|
471
|
-
<span>Event Information</span>
|
|
472
|
-
</h3>
|
|
473
|
-
<div class="bg-gray-50 dark:bg-gray-900/50 rounded-lg p-4 space-y-3">
|
|
474
|
-
<div class="flex items-center justify-between py-2 border-b border-gray-200 dark:border-gray-800">
|
|
475
|
-
<span class="text-sm text-gray-600 dark:text-gray-400">Type</span>
|
|
476
|
-
<UBadge
|
|
477
|
-
:label="selectedEvent.type"
|
|
478
|
-
:color="getEventBadgeColor(selectedEvent.type)"
|
|
479
|
-
variant="subtle"
|
|
480
|
-
size="xs"
|
|
481
|
-
/>
|
|
482
|
-
</div>
|
|
483
|
-
<div class="flex items-center justify-between py-2">
|
|
484
|
-
<span class="text-sm text-gray-600 dark:text-gray-400">Timestamp</span>
|
|
485
|
-
<span class="text-sm font-medium text-gray-900 dark:text-gray-100">{{ formatDate(selectedEvent.ts || selectedEvent.timestamp) }}</span>
|
|
486
|
-
</div>
|
|
487
|
-
</div>
|
|
488
|
-
</div>
|
|
489
|
-
|
|
490
|
-
<!-- Event Data -->
|
|
491
|
-
<div>
|
|
492
|
-
<h3 class="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-4">
|
|
493
|
-
Event Data
|
|
494
|
-
</h3>
|
|
495
|
-
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 overflow-x-auto">
|
|
496
|
-
<pre class="text-xs font-mono">{{ JSON.stringify(selectedEvent.data, null, 2) }}</pre>
|
|
497
|
-
</div>
|
|
498
|
-
</div>
|
|
499
|
-
|
|
500
|
-
<!-- Raw Event -->
|
|
501
|
-
<div>
|
|
502
|
-
<h3 class="text-sm font-semibold text-gray-900 dark:text-gray-100 mb-4">
|
|
503
|
-
Raw Event
|
|
504
|
-
</h3>
|
|
505
|
-
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 overflow-x-auto">
|
|
506
|
-
<pre class="text-xs font-mono">{{ JSON.stringify(selectedEvent, null, 2) }}</pre>
|
|
507
|
-
</div>
|
|
508
|
-
</div>
|
|
509
|
-
</div>
|
|
510
|
-
</div>
|
|
511
|
-
</div>
|
|
512
|
-
</div>
|
|
513
|
-
</div>
|
|
514
|
-
</div>
|
|
515
|
-
</template>
|
|
516
|
-
|
|
517
|
-
<script setup>
|
|
518
|
-
import { ref, computed, onUnmounted, watch, onMounted } from "#imports";
|
|
519
|
-
import { useTrigger, useTriggerEvents } from "../../composables/useTrigger";
|
|
520
|
-
import { useComponentRouter } from "../../composables/useComponentRouter";
|
|
521
|
-
import { useTriggerWebSocket } from "../../composables/useTriggerWebSocket";
|
|
522
|
-
import { useRoute, useRouter } from "#app";
|
|
523
|
-
import StatCard from "../../components/StatCard.vue";
|
|
524
|
-
import SelectableListItem from "../../components/SelectableListItem.vue";
|
|
525
|
-
const componentRouter = useComponentRouter();
|
|
526
|
-
const router = useRouter();
|
|
527
|
-
const route = useRoute();
|
|
528
|
-
const triggerName = computed(() => {
|
|
529
|
-
const name = componentRouter.route.value?.params?.name;
|
|
530
|
-
return name || null;
|
|
531
|
-
});
|
|
532
|
-
const { trigger, status } = useTrigger(triggerName);
|
|
533
|
-
const eventTypeFilter = computed({
|
|
534
|
-
get: () => route.query.type || "all",
|
|
535
|
-
set: (value) => {
|
|
536
|
-
router.push({
|
|
537
|
-
query: {
|
|
538
|
-
...route.query,
|
|
539
|
-
type: value === "all" ? void 0 : value,
|
|
540
|
-
page: void 0
|
|
541
|
-
// Reset page when filter changes
|
|
542
|
-
}
|
|
543
|
-
});
|
|
544
|
-
}
|
|
545
|
-
});
|
|
546
|
-
const currentPage = computed({
|
|
547
|
-
get: () => {
|
|
548
|
-
const page = route.query.page;
|
|
549
|
-
return page ? Number.parseInt(page, 10) : 1;
|
|
550
|
-
},
|
|
551
|
-
set: (value) => {
|
|
552
|
-
router.push({
|
|
553
|
-
query: {
|
|
554
|
-
...route.query,
|
|
555
|
-
page: value > 1 ? value.toString() : void 0
|
|
556
|
-
}
|
|
557
|
-
});
|
|
558
|
-
}
|
|
559
|
-
});
|
|
560
|
-
const eventTypeFilterOptions = [
|
|
561
|
-
{ label: "All Events", value: "all" },
|
|
562
|
-
{ label: "Fired", value: "trigger.fired" },
|
|
563
|
-
{ label: "Registered", value: "trigger.registered" },
|
|
564
|
-
{ label: "Updated", value: "trigger.updated" }
|
|
565
|
-
];
|
|
566
|
-
const eventsPerPage = 20;
|
|
567
|
-
const eventQueryOptions = computed(() => {
|
|
568
|
-
const options = {
|
|
569
|
-
limit: eventsPerPage,
|
|
570
|
-
offset: (currentPage.value - 1) * eventsPerPage
|
|
571
|
-
};
|
|
572
|
-
if (eventTypeFilter.value !== "all") {
|
|
573
|
-
options.types = [eventTypeFilter.value];
|
|
574
|
-
}
|
|
575
|
-
return options;
|
|
576
|
-
});
|
|
577
|
-
const { events: fetchedEvents, refresh: refreshEvents, status: eventsStatus } = useTriggerEvents(triggerName, eventQueryOptions);
|
|
578
|
-
const liveEvents = ref([]);
|
|
579
|
-
const { connected: isConnected, reconnecting: isReconnecting, subscribe, unsubscribe, subscribeStats, unsubscribeStats } = useTriggerWebSocket();
|
|
580
|
-
const pendingStatsUpdate = ref(null);
|
|
581
|
-
watch(trigger, (newTrigger) => {
|
|
582
|
-
if (newTrigger && pendingStatsUpdate.value) {
|
|
583
|
-
const metadata = pendingStatsUpdate.value.metadata;
|
|
584
|
-
if (metadata) {
|
|
585
|
-
trigger.value = {
|
|
586
|
-
...newTrigger,
|
|
587
|
-
stats: {
|
|
588
|
-
totalFires: metadata.stats?.totalFires || metadata.totalFires || metadata["stats.totalFires"] || newTrigger.stats.totalFires || 0,
|
|
589
|
-
totalFlowsStarted: metadata.stats?.totalFlowsStarted || metadata.totalFlowsStarted || metadata["stats.totalFlowsStarted"] || newTrigger.stats.totalFlowsStarted || 0,
|
|
590
|
-
activeSubscribers: metadata.stats?.activeSubscribers || metadata.activeSubscribers || metadata["stats.activeSubscribers"] || newTrigger.stats.activeSubscribers || 0,
|
|
591
|
-
lastFiredAt: metadata.stats?.lastFiredAt || metadata.lastFiredAt || metadata["stats.lastFiredAt"] || newTrigger.stats.lastFiredAt
|
|
592
|
-
},
|
|
593
|
-
lastActivityAt: metadata.lastActivityAt || newTrigger.lastActivityAt
|
|
594
|
-
};
|
|
595
|
-
pendingStatsUpdate.value = null;
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
});
|
|
599
|
-
function setupSubscriptions(newName) {
|
|
600
|
-
subscribe({
|
|
601
|
-
triggerName: newName,
|
|
602
|
-
onEvent: (event) => {
|
|
603
|
-
liveEvents.value = [event, ...liveEvents.value].slice(0, 50);
|
|
604
|
-
},
|
|
605
|
-
onHistory: (events2) => {
|
|
606
|
-
liveEvents.value = events2.slice(0, 50);
|
|
607
|
-
}
|
|
608
|
-
});
|
|
609
|
-
subscribeStats({
|
|
610
|
-
onInitial: (data) => {
|
|
611
|
-
if (data.id !== newName) {
|
|
612
|
-
return;
|
|
613
|
-
}
|
|
614
|
-
const metadata = data?.metadata;
|
|
615
|
-
if (!metadata) {
|
|
616
|
-
return;
|
|
617
|
-
}
|
|
618
|
-
if (!trigger.value) {
|
|
619
|
-
pendingStatsUpdate.value = data;
|
|
620
|
-
return;
|
|
621
|
-
}
|
|
622
|
-
trigger.value = {
|
|
623
|
-
...trigger.value,
|
|
624
|
-
stats: {
|
|
625
|
-
totalFires: metadata.stats?.totalFires || metadata.totalFires || metadata["stats.totalFires"] || trigger.value.stats.totalFires || 0,
|
|
626
|
-
totalFlowsStarted: metadata.stats?.totalFlowsStarted || metadata.totalFlowsStarted || metadata["stats.totalFlowsStarted"] || trigger.value.stats.totalFlowsStarted || 0,
|
|
627
|
-
activeSubscribers: metadata.stats?.activeSubscribers || metadata.activeSubscribers || metadata["stats.activeSubscribers"] || trigger.value.stats.activeSubscribers || 0,
|
|
628
|
-
lastFiredAt: metadata.stats?.lastFiredAt || metadata.lastFiredAt || metadata["stats.lastFiredAt"] || trigger.value.stats.lastFiredAt
|
|
629
|
-
},
|
|
630
|
-
lastActivityAt: metadata.lastActivityAt || trigger.value.lastActivityAt
|
|
631
|
-
};
|
|
632
|
-
},
|
|
633
|
-
onUpdate: (data) => {
|
|
634
|
-
if (data.id !== newName) {
|
|
635
|
-
return;
|
|
636
|
-
}
|
|
637
|
-
if (!trigger.value) {
|
|
638
|
-
pendingStatsUpdate.value = data;
|
|
639
|
-
return;
|
|
640
|
-
}
|
|
641
|
-
const metadata = data?.metadata;
|
|
642
|
-
if (!metadata) {
|
|
643
|
-
return;
|
|
644
|
-
}
|
|
645
|
-
trigger.value = {
|
|
646
|
-
...trigger.value,
|
|
647
|
-
stats: {
|
|
648
|
-
totalFires: metadata.stats?.totalFires || metadata.totalFires || metadata["stats.totalFires"] || trigger.value.stats.totalFires || 0,
|
|
649
|
-
totalFlowsStarted: metadata.stats?.totalFlowsStarted || metadata.totalFlowsStarted || metadata["stats.totalFlowsStarted"] || trigger.value.stats.totalFlowsStarted || 0,
|
|
650
|
-
activeSubscribers: metadata.stats?.activeSubscribers || metadata.activeSubscribers || metadata["stats.activeSubscribers"] || trigger.value.stats.activeSubscribers || 0,
|
|
651
|
-
lastFiredAt: metadata.stats?.lastFiredAt || metadata.lastFiredAt || metadata["stats.lastFiredAt"] || trigger.value.stats.lastFiredAt
|
|
652
|
-
},
|
|
653
|
-
lastActivityAt: metadata.lastActivityAt || trigger.value.lastActivityAt
|
|
654
|
-
};
|
|
655
|
-
}
|
|
656
|
-
});
|
|
657
|
-
}
|
|
658
|
-
onMounted(() => {
|
|
659
|
-
if (import.meta.server) return;
|
|
660
|
-
if (triggerName.value) {
|
|
661
|
-
setupSubscriptions(triggerName.value);
|
|
662
|
-
}
|
|
663
|
-
});
|
|
664
|
-
onUnmounted(() => {
|
|
665
|
-
unsubscribe();
|
|
666
|
-
unsubscribeStats();
|
|
667
|
-
});
|
|
668
|
-
const events = computed(() => {
|
|
669
|
-
return fetchedEvents.value;
|
|
670
|
-
});
|
|
671
|
-
const paginatedEvents = computed(() => {
|
|
672
|
-
if (!events.value) return [];
|
|
673
|
-
if (currentPage.value === 1) {
|
|
674
|
-
const filteredLiveEvents = liveEvents.value.filter((event) => {
|
|
675
|
-
if (eventTypeFilter.value === "all") return true;
|
|
676
|
-
return event.type === eventTypeFilter.value;
|
|
677
|
-
});
|
|
678
|
-
const allEvents = [...filteredLiveEvents, ...events.value.events || []];
|
|
679
|
-
const seen = /* @__PURE__ */ new Set();
|
|
680
|
-
const unique = allEvents.filter((event) => {
|
|
681
|
-
const key = event.id || `${event.type}-${event.ts || event.timestamp}`;
|
|
682
|
-
if (seen.has(key)) return false;
|
|
683
|
-
seen.add(key);
|
|
684
|
-
return true;
|
|
685
|
-
});
|
|
686
|
-
unique.sort((a, b) => {
|
|
687
|
-
const aTime = a.ts || a.timestamp || 0;
|
|
688
|
-
const bTime = b.ts || b.timestamp || 0;
|
|
689
|
-
return bTime - aTime;
|
|
690
|
-
});
|
|
691
|
-
return unique.slice(0, eventsPerPage);
|
|
692
|
-
}
|
|
693
|
-
return events.value.events || [];
|
|
694
|
-
});
|
|
695
|
-
watch(() => eventQueryOptions.value, () => {
|
|
696
|
-
refreshEvents();
|
|
697
|
-
}, { deep: true });
|
|
698
|
-
const activeTab = ref("overview");
|
|
699
|
-
const tabItems = computed(() => [
|
|
700
|
-
{ label: "Overview", value: "overview", icon: "i-lucide-bar-chart-3" },
|
|
701
|
-
{
|
|
702
|
-
label: "Event Details",
|
|
703
|
-
value: "details",
|
|
704
|
-
icon: "i-lucide-file-text",
|
|
705
|
-
disabled: !selectedEvent.value
|
|
706
|
-
}
|
|
707
|
-
]);
|
|
708
|
-
const selectedEvent = ref(null);
|
|
709
|
-
const selectEvent = (event) => {
|
|
710
|
-
selectedEvent.value = event;
|
|
711
|
-
activeTab.value = "details";
|
|
712
|
-
};
|
|
713
|
-
watch(selectedEvent, (newEvent) => {
|
|
714
|
-
if (newEvent) {
|
|
715
|
-
activeTab.value = "details";
|
|
716
|
-
} else {
|
|
717
|
-
activeTab.value = "overview";
|
|
718
|
-
}
|
|
719
|
-
});
|
|
720
|
-
const goBack = () => {
|
|
721
|
-
componentRouter.push("/triggers");
|
|
722
|
-
};
|
|
723
|
-
const goToEdit = () => {
|
|
724
|
-
if (triggerName.value) {
|
|
725
|
-
componentRouter.push(`/triggers/${encodeURIComponent(triggerName.value)}/edit`);
|
|
726
|
-
}
|
|
727
|
-
};
|
|
728
|
-
const goToFlow = (flowName) => {
|
|
729
|
-
componentRouter.push(`/flows?flow=${encodeURIComponent(flowName)}`);
|
|
730
|
-
};
|
|
731
|
-
const getTriggerIcon = (type) => {
|
|
732
|
-
switch (type) {
|
|
733
|
-
case "event":
|
|
734
|
-
return "i-lucide-radio";
|
|
735
|
-
case "webhook":
|
|
736
|
-
return "i-lucide-webhook";
|
|
737
|
-
case "schedule":
|
|
738
|
-
return "i-lucide-clock";
|
|
739
|
-
case "manual":
|
|
740
|
-
return "i-lucide-hand";
|
|
741
|
-
default:
|
|
742
|
-
return "i-lucide-zap";
|
|
743
|
-
}
|
|
744
|
-
};
|
|
745
|
-
const getTriggerIconColor = (type) => {
|
|
746
|
-
switch (type) {
|
|
747
|
-
case "event":
|
|
748
|
-
return "text-blue-500";
|
|
749
|
-
case "webhook":
|
|
750
|
-
return "text-purple-500";
|
|
751
|
-
case "schedule":
|
|
752
|
-
return "text-emerald-500";
|
|
753
|
-
case "manual":
|
|
754
|
-
return "text-amber-500";
|
|
755
|
-
default:
|
|
756
|
-
return "text-gray-500";
|
|
757
|
-
}
|
|
758
|
-
};
|
|
759
|
-
const getTriggerTypeColor = (type) => {
|
|
760
|
-
switch (type) {
|
|
761
|
-
case "event":
|
|
762
|
-
return "primary";
|
|
763
|
-
case "webhook":
|
|
764
|
-
return "success";
|
|
765
|
-
case "schedule":
|
|
766
|
-
return "warning";
|
|
767
|
-
case "manual":
|
|
768
|
-
return "neutral";
|
|
769
|
-
default:
|
|
770
|
-
return "neutral";
|
|
771
|
-
}
|
|
772
|
-
};
|
|
773
|
-
const getEventIcon = (type) => {
|
|
774
|
-
if (type.includes("fired")) return "i-lucide-zap";
|
|
775
|
-
if (type.includes("registered")) return "i-lucide-plus-circle";
|
|
776
|
-
if (type.includes("updated")) return "i-lucide-pencil";
|
|
777
|
-
if (type.includes("subscription")) return "i-lucide-link";
|
|
778
|
-
return "i-lucide-circle-dot";
|
|
779
|
-
};
|
|
780
|
-
const getEventIconColor = (type) => {
|
|
781
|
-
if (type.includes("fired")) return "text-emerald-500";
|
|
782
|
-
if (type.includes("registered")) return "text-blue-500";
|
|
783
|
-
if (type.includes("updated")) return "text-amber-500";
|
|
784
|
-
if (type.includes("subscription")) return "text-purple-500";
|
|
785
|
-
return "text-gray-500";
|
|
786
|
-
};
|
|
787
|
-
const getEventBadgeColor = (type) => {
|
|
788
|
-
if (type.includes("fired")) return "success";
|
|
789
|
-
if (type.includes("registered")) return "primary";
|
|
790
|
-
if (type.includes("updated")) return "warning";
|
|
791
|
-
if (type.includes("subscription")) return "secondary";
|
|
792
|
-
return "neutral";
|
|
793
|
-
};
|
|
794
|
-
const formatTime = (timestamp) => {
|
|
795
|
-
const date = new Date(timestamp);
|
|
796
|
-
const now = /* @__PURE__ */ new Date();
|
|
797
|
-
const diff = now.getTime() - date.getTime();
|
|
798
|
-
const seconds = Math.floor(diff / 1e3);
|
|
799
|
-
const minutes = Math.floor(seconds / 60);
|
|
800
|
-
const hours = Math.floor(minutes / 60);
|
|
801
|
-
const days = Math.floor(hours / 24);
|
|
802
|
-
if (days > 0) return `${days}d ago`;
|
|
803
|
-
if (hours > 0) return `${hours}h ago`;
|
|
804
|
-
if (minutes > 0) return `${minutes}m ago`;
|
|
805
|
-
if (seconds > 10) return `${seconds}s ago`;
|
|
806
|
-
return "just now";
|
|
807
|
-
};
|
|
808
|
-
const formatDate = (timestamp) => {
|
|
809
|
-
return new Date(timestamp).toLocaleString();
|
|
810
|
-
};
|
|
811
|
-
const getFilterIcon = (value) => {
|
|
812
|
-
switch (value) {
|
|
813
|
-
case "trigger.fired":
|
|
814
|
-
return "i-lucide-zap";
|
|
815
|
-
case "trigger.registered":
|
|
816
|
-
return "i-lucide-plus-circle";
|
|
817
|
-
case "trigger.updated":
|
|
818
|
-
return "i-lucide-pencil";
|
|
819
|
-
default:
|
|
820
|
-
return "i-lucide-filter";
|
|
821
|
-
}
|
|
822
|
-
};
|
|
823
|
-
const getFilterIconColor = (value) => {
|
|
824
|
-
switch (value) {
|
|
825
|
-
case "trigger.fired":
|
|
826
|
-
return "text-emerald-500";
|
|
827
|
-
case "trigger.registered":
|
|
828
|
-
return "text-blue-500";
|
|
829
|
-
case "trigger.updated":
|
|
830
|
-
return "text-amber-500";
|
|
831
|
-
default:
|
|
832
|
-
return "text-gray-500";
|
|
833
|
-
}
|
|
834
|
-
};
|
|
835
|
-
const getFilterLabel = (value) => {
|
|
836
|
-
const option = eventTypeFilterOptions.find((o) => o.value === value);
|
|
837
|
-
return option?.label || "All Events";
|
|
838
|
-
};
|
|
839
|
-
const copyToClipboard = async (text) => {
|
|
840
|
-
try {
|
|
841
|
-
await navigator.clipboard.writeText(text);
|
|
842
|
-
} catch (err) {
|
|
843
|
-
console.error("Failed to copy:", err);
|
|
844
|
-
}
|
|
845
|
-
};
|
|
846
|
-
const formatInterval = (seconds) => {
|
|
847
|
-
const units = [
|
|
848
|
-
{ value: 86400, label: "day", pluralLabel: "days" },
|
|
849
|
-
{ value: 3600, label: "hour", pluralLabel: "hours" },
|
|
850
|
-
{ value: 60, label: "minute", pluralLabel: "minutes" },
|
|
851
|
-
{ value: 1, label: "second", pluralLabel: "seconds" }
|
|
852
|
-
];
|
|
853
|
-
for (const unit of units) {
|
|
854
|
-
if (seconds >= unit.value && seconds % unit.value === 0) {
|
|
855
|
-
const count = seconds / unit.value;
|
|
856
|
-
const label = count === 1 ? unit.label : unit.pluralLabel;
|
|
857
|
-
return `Every ${count} ${label}`;
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
if (seconds >= 60) {
|
|
861
|
-
const minutes = Math.floor(seconds / 60);
|
|
862
|
-
const remainingSeconds = seconds % 60;
|
|
863
|
-
if (remainingSeconds === 0) {
|
|
864
|
-
return `Every ${minutes} ${minutes === 1 ? "minute" : "minutes"}`;
|
|
865
|
-
}
|
|
866
|
-
return `Every ${minutes}m ${remainingSeconds}s`;
|
|
867
|
-
}
|
|
868
|
-
return `Every ${seconds} ${seconds === 1 ? "second" : "seconds"}`;
|
|
869
|
-
};
|
|
870
|
-
</script>
|