nvent 0.4.0
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/LICENSE +21 -0
- package/README.md +389 -0
- package/dist/module.d.mts +193 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +974 -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 +64 -0
- package/dist/runtime/app/components/FlowDiagram.vue +338 -0
- package/dist/runtime/app/components/FlowDiagram.vue.d.ts +64 -0
- package/dist/runtime/app/components/FlowNodeCard.d.vue.ts +29 -0
- package/dist/runtime/app/components/FlowNodeCard.vue +156 -0
- package/dist/runtime/app/components/FlowNodeCard.vue.d.ts +29 -0
- package/dist/runtime/app/components/FlowRunOverview.d.vue.ts +9 -0
- package/dist/runtime/app/components/FlowRunOverview.vue +291 -0
- package/dist/runtime/app/components/FlowRunOverview.vue.d.ts +9 -0
- package/dist/runtime/app/components/FlowRunStatusBadge.d.vue.ts +14 -0
- package/dist/runtime/app/components/FlowRunStatusBadge.vue +60 -0
- package/dist/runtime/app/components/FlowRunStatusBadge.vue.d.ts +14 -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/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 +210 -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 +7 -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 +15 -0
- package/dist/runtime/app/composables/useFlowRunTimeline.js +66 -0
- package/dist/runtime/app/composables/useFlowRuns.d.ts +11 -0
- package/dist/runtime/app/composables/useFlowRuns.js +31 -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 +8 -0
- package/dist/runtime/app/composables/useFlowRunsPolling.js +26 -0
- package/dist/runtime/app/composables/useFlowState.d.ts +125 -0
- package/dist/runtime/app/composables/useFlowState.js +211 -0
- package/dist/runtime/app/composables/useFlowWebSocket.d.ts +27 -0
- package/dist/runtime/app/composables/useFlowWebSocket.js +205 -0
- package/dist/runtime/app/composables/useFlowsNavigation.d.ts +10 -0
- package/dist/runtime/app/composables/useFlowsNavigation.js +57 -0
- package/dist/runtime/app/composables/useQueueJobs.d.ts +20 -0
- package/dist/runtime/app/composables/useQueueJobs.js +20 -0
- package/dist/runtime/app/composables/useQueueUpdates.d.ts +26 -0
- package/dist/runtime/app/composables/useQueueUpdates.js +122 -0
- package/dist/runtime/app/composables/useQueues.d.ts +43 -0
- package/dist/runtime/app/composables/useQueues.js +26 -0
- package/dist/runtime/app/composables/useQueuesLive.d.ts +19 -0
- package/dist/runtime/app/composables/useQueuesLive.js +143 -0
- package/dist/runtime/app/pages/flows/index.d.vue.ts +3 -0
- package/dist/runtime/app/pages/flows/index.vue +645 -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 +6 -0
- package/dist/runtime/app/plugins/vueflow.client.js +15 -0
- package/dist/runtime/constants.d.ts +11 -0
- package/dist/runtime/constants.js +11 -0
- package/dist/runtime/python/get_config.py +64 -0
- package/dist/runtime/schema.d.ts +37 -0
- package/dist/runtime/schema.js +20 -0
- package/dist/runtime/server/api/_flows/[name]/clear-history.delete.d.ts +10 -0
- package/dist/runtime/server/api/_flows/[name]/clear-history.delete.js +44 -0
- package/dist/runtime/server/api/_flows/[name]/runs.get.d.ts +7 -0
- package/dist/runtime/server/api/_flows/[name]/runs.get.js +53 -0
- package/dist/runtime/server/api/_flows/[name]/schedule.post.d.ts +2 -0
- package/dist/runtime/server/api/_flows/[name]/schedule.post.js +57 -0
- package/dist/runtime/server/api/_flows/[name]/schedules/[id].delete.d.ts +2 -0
- package/dist/runtime/server/api/_flows/[name]/schedules/[id].delete.js +42 -0
- package/dist/runtime/server/api/_flows/[name]/schedules.get.d.ts +2 -0
- package/dist/runtime/server/api/_flows/[name]/schedules.get.js +48 -0
- package/dist/runtime/server/api/_flows/[name]/start.post.d.ts +2 -0
- package/dist/runtime/server/api/_flows/[name]/start.post.js +9 -0
- package/dist/runtime/server/api/_flows/index.get.d.ts +6 -0
- package/dist/runtime/server/api/_flows/index.get.js +5 -0
- package/dist/runtime/server/api/_flows/ws.d.ts +60 -0
- package/dist/runtime/server/api/_flows/ws.js +183 -0
- package/dist/runtime/server/api/_queues/[name]/job/[id].get.d.ts +2 -0
- package/dist/runtime/server/api/_queues/[name]/job/[id].get.js +9 -0
- package/dist/runtime/server/api/_queues/[name]/job/index.get.d.ts +2 -0
- package/dist/runtime/server/api/_queues/[name]/job/index.get.js +18 -0
- package/dist/runtime/server/api/_queues/index.get.d.ts +2 -0
- package/dist/runtime/server/api/_queues/index.get.js +63 -0
- package/dist/runtime/server/api/_queues/ws.d.ts +48 -0
- package/dist/runtime/server/api/_queues/ws.js +200 -0
- package/dist/runtime/server/events/adapters/fileAdapter.d.ts +2 -0
- package/dist/runtime/server/events/adapters/fileAdapter.js +382 -0
- package/dist/runtime/server/events/adapters/memoryAdapter.d.ts +2 -0
- package/dist/runtime/server/events/adapters/memoryAdapter.js +171 -0
- package/dist/runtime/server/events/adapters/redis/redisAdapter.d.ts +2 -0
- package/dist/runtime/server/events/adapters/redis/redisAdapter.js +348 -0
- package/dist/runtime/server/events/adapters/redis/redisPubSubGateway.d.ts +29 -0
- package/dist/runtime/server/events/adapters/redis/redisPubSubGateway.js +82 -0
- package/dist/runtime/server/events/eventBus.d.ts +20 -0
- package/dist/runtime/server/events/eventBus.js +35 -0
- package/dist/runtime/server/events/eventStoreFactory.d.ts +19 -0
- package/dist/runtime/server/events/eventStoreFactory.js +44 -0
- package/dist/runtime/server/events/streamNames.d.ts +17 -0
- package/dist/runtime/server/events/streamNames.js +17 -0
- package/dist/runtime/server/events/types.d.ts +63 -0
- package/dist/runtime/server/events/types.js +0 -0
- package/dist/runtime/server/events/wiring/flowWiring.d.ts +33 -0
- package/dist/runtime/server/events/wiring/flowWiring.js +406 -0
- package/dist/runtime/server/events/wiring/registry.d.ts +10 -0
- package/dist/runtime/server/events/wiring/registry.js +24 -0
- package/dist/runtime/server/plugins/00.event-store.d.ts +13 -0
- package/dist/runtime/server/plugins/00.event-store.js +16 -0
- package/dist/runtime/server/plugins/00.ws-lifecycle.d.ts +5 -0
- package/dist/runtime/server/plugins/00.ws-lifecycle.js +66 -0
- package/dist/runtime/server/plugins/flow-management.d.ts +13 -0
- package/dist/runtime/server/plugins/flow-management.js +65 -0
- package/dist/runtime/server/plugins/queue-management.d.ts +2 -0
- package/dist/runtime/server/plugins/queue-management.js +27 -0
- package/dist/runtime/server/plugins/state-cleanup.d.ts +11 -0
- package/dist/runtime/server/plugins/state-cleanup.js +93 -0
- package/dist/runtime/server/plugins/worker-management.d.ts +2 -0
- package/dist/runtime/server/plugins/worker-management.js +33 -0
- package/dist/runtime/server/queue/adapters/bullmq.d.ts +17 -0
- package/dist/runtime/server/queue/adapters/bullmq.js +164 -0
- package/dist/runtime/server/queue/queueFactory.d.ts +3 -0
- package/dist/runtime/server/queue/queueFactory.js +10 -0
- package/dist/runtime/server/queue/types.d.ts +47 -0
- package/dist/runtime/server/queue/types.js +0 -0
- package/dist/runtime/server/state/adapters/redis.d.ts +2 -0
- package/dist/runtime/server/state/adapters/redis.js +42 -0
- package/dist/runtime/server/state/stateFactory.d.ts +3 -0
- package/dist/runtime/server/state/stateFactory.js +17 -0
- package/dist/runtime/server/state/types.d.ts +23 -0
- package/dist/runtime/server/state/types.js +0 -0
- package/dist/runtime/server/tsconfig.json +3 -0
- package/dist/runtime/server/utils/defineQueueConfig.d.ts +154 -0
- package/dist/runtime/server/utils/defineQueueConfig.js +2 -0
- package/dist/runtime/server/utils/defineQueueWorker.d.ts +10 -0
- package/dist/runtime/server/utils/defineQueueWorker.js +17 -0
- package/dist/runtime/server/utils/useEventManager.d.ts +15 -0
- package/dist/runtime/server/utils/useEventManager.js +26 -0
- package/dist/runtime/server/utils/useEventStore.d.ts +20 -0
- package/dist/runtime/server/utils/useEventStore.js +119 -0
- package/dist/runtime/server/utils/useFlowEngine.d.ts +9 -0
- package/dist/runtime/server/utils/useFlowEngine.js +44 -0
- package/dist/runtime/server/utils/useLogs.d.ts +41 -0
- package/dist/runtime/server/utils/useLogs.js +74 -0
- package/dist/runtime/server/utils/useQueue.d.ts +31 -0
- package/dist/runtime/server/utils/useQueue.js +24 -0
- package/dist/runtime/server/utils/useServerLogger.d.ts +42 -0
- package/dist/runtime/server/utils/useServerLogger.js +54 -0
- package/dist/runtime/server/utils/wsPeerManager.d.ts +34 -0
- package/dist/runtime/server/utils/wsPeerManager.js +23 -0
- package/dist/runtime/server/worker/adapter.d.ts +4 -0
- package/dist/runtime/server/worker/adapter.js +65 -0
- package/dist/runtime/server/worker/runner/node.d.ts +27 -0
- package/dist/runtime/server/worker/runner/node.js +196 -0
- package/dist/runtime/types.d.ts +132 -0
- package/dist/types.d.mts +3 -0
- package/package.json +75 -0
|
@@ -0,0 +1,291 @@
|
|
|
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
|
+
<span
|
|
31
|
+
v-if="isAutoRefreshing"
|
|
32
|
+
class="text-[10px] text-gray-400"
|
|
33
|
+
>
|
|
34
|
+
(updating...)
|
|
35
|
+
</span>
|
|
36
|
+
</div>
|
|
37
|
+
<div
|
|
38
|
+
v-else-if="isReconnecting"
|
|
39
|
+
class="flex items-center gap-1.5 text-xs text-amber-600 dark:text-amber-400"
|
|
40
|
+
>
|
|
41
|
+
<div class="w-2 h-2 rounded-full bg-amber-500 animate-pulse" />
|
|
42
|
+
<span>Reconnecting...</span>
|
|
43
|
+
</div>
|
|
44
|
+
<UBadge
|
|
45
|
+
:label="counts?.active.toString() || '0'"
|
|
46
|
+
color="warning"
|
|
47
|
+
variant="subtle"
|
|
48
|
+
>
|
|
49
|
+
<template #leading>
|
|
50
|
+
Active
|
|
51
|
+
</template>
|
|
52
|
+
</UBadge>
|
|
53
|
+
<UBadge
|
|
54
|
+
:label="counts?.waiting.toString() || '0'"
|
|
55
|
+
color="info"
|
|
56
|
+
variant="subtle"
|
|
57
|
+
>
|
|
58
|
+
<template #leading>
|
|
59
|
+
Waiting
|
|
60
|
+
</template>
|
|
61
|
+
</UBadge>
|
|
62
|
+
<UBadge
|
|
63
|
+
:label="counts?.completed.toString() || '0'"
|
|
64
|
+
color="success"
|
|
65
|
+
variant="subtle"
|
|
66
|
+
>
|
|
67
|
+
<template #leading>
|
|
68
|
+
Completed
|
|
69
|
+
</template>
|
|
70
|
+
</UBadge>
|
|
71
|
+
<UBadge
|
|
72
|
+
:label="counts?.failed.toString() || '0'"
|
|
73
|
+
color="error"
|
|
74
|
+
variant="subtle"
|
|
75
|
+
>
|
|
76
|
+
<template #leading>
|
|
77
|
+
Failed
|
|
78
|
+
</template>
|
|
79
|
+
</UBadge>
|
|
80
|
+
<USelectMenu
|
|
81
|
+
v-model="selectedStateOption"
|
|
82
|
+
:items="stateOptions"
|
|
83
|
+
placeholder="All States"
|
|
84
|
+
size="xs"
|
|
85
|
+
class="w-32"
|
|
86
|
+
/>
|
|
87
|
+
<UButton
|
|
88
|
+
icon="i-lucide-refresh-cw"
|
|
89
|
+
size="xs"
|
|
90
|
+
color="neutral"
|
|
91
|
+
variant="ghost"
|
|
92
|
+
:loading="status === 'pending'"
|
|
93
|
+
@click.prevent="onRefresh"
|
|
94
|
+
>
|
|
95
|
+
Refresh
|
|
96
|
+
</UButton>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
|
|
101
|
+
<!-- Main Content -->
|
|
102
|
+
<div class="flex-1 min-h-0 overflow-hidden flex flex-col">
|
|
103
|
+
<div
|
|
104
|
+
v-if="!data || !data.jobs || data.jobs.length === 0"
|
|
105
|
+
class="flex-1 flex items-center justify-center text-sm text-gray-400"
|
|
106
|
+
>
|
|
107
|
+
No jobs found
|
|
108
|
+
</div>
|
|
109
|
+
<template v-else>
|
|
110
|
+
<div class="flex-1 min-h-0 p-4 overflow-auto">
|
|
111
|
+
<UTable
|
|
112
|
+
ref="table"
|
|
113
|
+
v-model:pagination="pagination"
|
|
114
|
+
:data="data.jobs"
|
|
115
|
+
:columns="columns"
|
|
116
|
+
:loading="status === 'pending'"
|
|
117
|
+
:pagination-options="{
|
|
118
|
+
getPaginationRowModel: getPaginationRowModel()
|
|
119
|
+
}"
|
|
120
|
+
:ui="{
|
|
121
|
+
base: 'table-fixed border-separate border-spacing-0',
|
|
122
|
+
thead: '[&>tr]:bg-elevated/50 [&>tr]:after:content-none',
|
|
123
|
+
tbody: '[&>tr]:last:[&>td]:border-b-0',
|
|
124
|
+
th: 'py-2 first:rounded-l-lg last:rounded-r-lg border-y border-default first:border-l last:border-r',
|
|
125
|
+
td: 'border-b border-default',
|
|
126
|
+
separator: 'h-0'
|
|
127
|
+
}"
|
|
128
|
+
/>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<div class="flex items-center justify-between gap-3 border-t border-default p-4 shrink-0">
|
|
132
|
+
<div class="text-sm text-muted">
|
|
133
|
+
Showing {{ Math.min(pagination.pageIndex * pagination.pageSize + pagination.pageSize, data.jobs.length) }} of {{ data.jobs.length }} job(s)
|
|
134
|
+
<span
|
|
135
|
+
v-if="selectedState"
|
|
136
|
+
class="text-gray-400"
|
|
137
|
+
>
|
|
138
|
+
(filtered by {{ selectedStateOption?.label }})
|
|
139
|
+
</span>
|
|
140
|
+
</div>
|
|
141
|
+
<div class="flex items-center gap-1.5">
|
|
142
|
+
<UPagination
|
|
143
|
+
:default-page="(table?.tableApi?.getState().pagination.pageIndex || 0) + 1"
|
|
144
|
+
:items-per-page="table?.tableApi?.getState().pagination.pageSize || 20"
|
|
145
|
+
:total="data.jobs.length"
|
|
146
|
+
@update:page="(p) => table?.tableApi?.setPageIndex(p - 1)"
|
|
147
|
+
/>
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
</template>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
</template>
|
|
154
|
+
|
|
155
|
+
<script setup>
|
|
156
|
+
import { ref, computed, watch } from "#imports";
|
|
157
|
+
import { getPaginationRowModel } from "@tanstack/table-core";
|
|
158
|
+
import { UTable, UButton, UBadge, UPagination, USelectMenu } from "#components";
|
|
159
|
+
import { useQueueJobs } from "../../composables/useQueueJobs";
|
|
160
|
+
import { useQueueUpdates } from "../../composables/useQueueUpdates";
|
|
161
|
+
import { useComponentRouter } from "../../composables/useComponentRouter";
|
|
162
|
+
const UBadgeComponent = resolveComponent("UBadge");
|
|
163
|
+
const UButtonComponent = resolveComponent("UButton");
|
|
164
|
+
const router = useComponentRouter();
|
|
165
|
+
const queueName = computed(() => router.route.value?.params?.name || "");
|
|
166
|
+
const stateOptions = [
|
|
167
|
+
{ label: "All States", value: null },
|
|
168
|
+
{ label: "Waiting", value: "waiting" },
|
|
169
|
+
{ label: "Active", value: "active" },
|
|
170
|
+
{ label: "Completed", value: "completed" },
|
|
171
|
+
{ label: "Failed", value: "failed" },
|
|
172
|
+
{ label: "Delayed", value: "delayed" },
|
|
173
|
+
{ label: "Paused", value: "paused" }
|
|
174
|
+
];
|
|
175
|
+
const selectedStateOption = ref(stateOptions[0]);
|
|
176
|
+
const selectedState = computed(() => selectedStateOption.value?.value ?? null);
|
|
177
|
+
const { data, refresh, status } = useQueueJobs(queueName, selectedState);
|
|
178
|
+
const { counts, isConnected, isReconnecting, shouldRefreshJobs, resetRefreshFlag } = useQueueUpdates(queueName);
|
|
179
|
+
const isAutoRefreshing = ref(false);
|
|
180
|
+
watch(selectedState, () => {
|
|
181
|
+
if (table.value?.tableApi) {
|
|
182
|
+
table.value.tableApi.setPageIndex(0);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
watch(shouldRefreshJobs, async (shouldRefresh) => {
|
|
186
|
+
if (shouldRefresh) {
|
|
187
|
+
isAutoRefreshing.value = true;
|
|
188
|
+
await refresh();
|
|
189
|
+
resetRefreshFlag();
|
|
190
|
+
setTimeout(() => {
|
|
191
|
+
isAutoRefreshing.value = false;
|
|
192
|
+
}, 500);
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
const table = useTemplateRef("table");
|
|
196
|
+
const pagination = ref({
|
|
197
|
+
pageIndex: 0,
|
|
198
|
+
pageSize: 20
|
|
199
|
+
});
|
|
200
|
+
const onRefresh = async () => {
|
|
201
|
+
await refresh();
|
|
202
|
+
};
|
|
203
|
+
const back = () => {
|
|
204
|
+
router.push("/queues");
|
|
205
|
+
};
|
|
206
|
+
const selectJob = (jobId) => {
|
|
207
|
+
router.push(`/queues/${queueName.value}/jobs/${jobId}`);
|
|
208
|
+
};
|
|
209
|
+
const columns = [
|
|
210
|
+
{
|
|
211
|
+
accessorKey: "id",
|
|
212
|
+
header: "Job ID",
|
|
213
|
+
cell: ({ row }) => {
|
|
214
|
+
const id = row.original.id;
|
|
215
|
+
return h("div", {
|
|
216
|
+
class: "font-mono text-xs cursor-pointer hover:underline",
|
|
217
|
+
onClick: () => selectJob(row.original.id)
|
|
218
|
+
}, id.length > 16 ? `${id.substring(0, 8)}...${id.substring(id.length - 8)}` : id);
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
accessorKey: "name",
|
|
223
|
+
header: "Name",
|
|
224
|
+
cell: ({ row }) => {
|
|
225
|
+
return h("div", {
|
|
226
|
+
class: "font-medium cursor-pointer hover:underline",
|
|
227
|
+
onClick: () => selectJob(row.original.id)
|
|
228
|
+
}, row.original.name);
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
accessorKey: "state",
|
|
233
|
+
header: "State",
|
|
234
|
+
cell: ({ row }) => {
|
|
235
|
+
const state = row.original.state;
|
|
236
|
+
const colorMap = {
|
|
237
|
+
waiting: "info",
|
|
238
|
+
active: "warning",
|
|
239
|
+
completed: "success",
|
|
240
|
+
failed: "error",
|
|
241
|
+
delayed: "secondary",
|
|
242
|
+
paused: "warning"
|
|
243
|
+
};
|
|
244
|
+
return h(UBadgeComponent, {
|
|
245
|
+
label: state || "unknown",
|
|
246
|
+
color: colorMap[state || ""] || "neutral",
|
|
247
|
+
variant: "subtle",
|
|
248
|
+
class: "capitalize"
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
{
|
|
253
|
+
accessorKey: "timestamp",
|
|
254
|
+
header: "Created",
|
|
255
|
+
cell: ({ row }) => {
|
|
256
|
+
const timestamp = row.original.timestamp;
|
|
257
|
+
if (!timestamp) return h("div", { class: "text-gray-400 text-xs" }, "-");
|
|
258
|
+
const date = new Date(timestamp);
|
|
259
|
+
return h(
|
|
260
|
+
"div",
|
|
261
|
+
{ class: "text-xs" },
|
|
262
|
+
date.toLocaleString("de-DE", {
|
|
263
|
+
timeZone: "Europe/Berlin",
|
|
264
|
+
day: "2-digit",
|
|
265
|
+
month: "2-digit",
|
|
266
|
+
year: "numeric",
|
|
267
|
+
hour: "2-digit",
|
|
268
|
+
minute: "2-digit",
|
|
269
|
+
second: "2-digit"
|
|
270
|
+
})
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
id: "actions",
|
|
276
|
+
header: "",
|
|
277
|
+
cell: ({ row }) => {
|
|
278
|
+
return h(UButtonComponent, {
|
|
279
|
+
icon: "i-lucide-arrow-right",
|
|
280
|
+
size: "xs",
|
|
281
|
+
color: "neutral",
|
|
282
|
+
variant: "ghost",
|
|
283
|
+
square: true,
|
|
284
|
+
onClick: () => {
|
|
285
|
+
selectJob(row.original.id);
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
];
|
|
291
|
+
</script>
|
|
@@ -0,0 +1,3 @@
|
|
|
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;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import '@vue-flow/core/dist/style.css';
|
|
2
|
+
import '@vue-flow/core/dist/theme-default.css';
|
|
3
|
+
import '@vue-flow/controls/dist/style.css';
|
|
4
|
+
import '@vue-flow/minimap/dist/style.css';
|
|
5
|
+
declare const _default: import("#app").Plugin<Record<string, unknown>> & import("#app").ObjectPlugin<Record<string, unknown>>;
|
|
6
|
+
export default _default;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { defineNuxtPlugin } from "#app";
|
|
2
|
+
import { VueFlow } from "@vue-flow/core";
|
|
3
|
+
import { Controls } from "@vue-flow/controls";
|
|
4
|
+
import { MiniMap } from "@vue-flow/minimap";
|
|
5
|
+
import { Background } from "@vue-flow/background";
|
|
6
|
+
import "@vue-flow/core/dist/style.css";
|
|
7
|
+
import "@vue-flow/core/dist/theme-default.css";
|
|
8
|
+
import "@vue-flow/controls/dist/style.css";
|
|
9
|
+
import "@vue-flow/minimap/dist/style.css";
|
|
10
|
+
export default defineNuxtPlugin((nuxtApp) => {
|
|
11
|
+
nuxtApp.vueApp.component("VueFlow", VueFlow);
|
|
12
|
+
nuxtApp.vueApp.component("Controls", Controls);
|
|
13
|
+
nuxtApp.vueApp.component("MiniMap", MiniMap);
|
|
14
|
+
nuxtApp.vueApp.component("Background", Background);
|
|
15
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const QUEUE_STATUSES: {
|
|
2
|
+
readonly latest: "latest";
|
|
3
|
+
readonly active: "active";
|
|
4
|
+
readonly waiting: "waiting";
|
|
5
|
+
readonly waitingChildren: "waiting-children";
|
|
6
|
+
readonly prioritized: "prioritized";
|
|
7
|
+
readonly completed: "completed";
|
|
8
|
+
readonly failed: "failed";
|
|
9
|
+
readonly delayed: "delayed";
|
|
10
|
+
readonly paused: "paused";
|
|
11
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
import json
|
|
3
|
+
import importlib.util
|
|
4
|
+
import os
|
|
5
|
+
import platform
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def send_message(payload):
|
|
9
|
+
"""Send a JSON line to the parent process.
|
|
10
|
+
|
|
11
|
+
On Unix-like systems, write to the file descriptor provided via env
|
|
12
|
+
NODE_CHANNEL_FD. On Windows, write to stdout.
|
|
13
|
+
"""
|
|
14
|
+
bytes_message = (json.dumps(payload) + "\n").encode("utf-8")
|
|
15
|
+
|
|
16
|
+
if platform.system() == "Windows":
|
|
17
|
+
# On Windows, write to stdout
|
|
18
|
+
sys.stdout.buffer.write(bytes_message)
|
|
19
|
+
sys.stdout.buffer.flush()
|
|
20
|
+
else:
|
|
21
|
+
# On Unix systems, use the provided file descriptor
|
|
22
|
+
fd = int(os.environ["NODE_CHANNEL_FD"]) # expected to be set by parent
|
|
23
|
+
os.write(fd, bytes_message)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
async def run_python_module(file_path: str) -> None:
|
|
27
|
+
try:
|
|
28
|
+
module_dir = os.path.dirname(os.path.abspath(file_path))
|
|
29
|
+
|
|
30
|
+
if module_dir not in sys.path:
|
|
31
|
+
sys.path.insert(0, module_dir)
|
|
32
|
+
|
|
33
|
+
spec = importlib.util.spec_from_file_location(
|
|
34
|
+
os.path.splitext(os.path.basename(file_path))[0], file_path
|
|
35
|
+
)
|
|
36
|
+
if spec is None or spec.loader is None:
|
|
37
|
+
raise ImportError(f"Could not load module from {file_path}")
|
|
38
|
+
|
|
39
|
+
module = importlib.util.module_from_spec(spec)
|
|
40
|
+
# Set a basic package name to allow relative imports from same dir
|
|
41
|
+
module.__package__ = os.path.basename(module_dir)
|
|
42
|
+
spec.loader.exec_module(module)
|
|
43
|
+
|
|
44
|
+
if not hasattr(module, "config"):
|
|
45
|
+
raise AttributeError(f"No 'config' found in module {file_path}")
|
|
46
|
+
|
|
47
|
+
cfg = getattr(module, "config")
|
|
48
|
+
# Remove keys that are not serializable or not needed
|
|
49
|
+
if isinstance(cfg, dict) and "middleware" in cfg:
|
|
50
|
+
del cfg["middleware"]
|
|
51
|
+
|
|
52
|
+
send_message(cfg)
|
|
53
|
+
except Exception as error:
|
|
54
|
+
print("Error running Python module:", str(error), file=sys.stderr)
|
|
55
|
+
sys.exit(1)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
if __name__ == "__main__":
|
|
59
|
+
if len(sys.argv) < 2:
|
|
60
|
+
sys.exit(1)
|
|
61
|
+
file_path = sys.argv[1]
|
|
62
|
+
import asyncio
|
|
63
|
+
|
|
64
|
+
asyncio.run(run_python_module(file_path))
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import z from 'zod';
|
|
2
|
+
export declare const JobSchema: z.ZodObject<{
|
|
3
|
+
id: z.ZodString;
|
|
4
|
+
name: z.ZodString;
|
|
5
|
+
data: z.ZodAny;
|
|
6
|
+
progress: z.ZodNumber;
|
|
7
|
+
opts: z.ZodObject<{
|
|
8
|
+
attempts: z.ZodNumber;
|
|
9
|
+
delay: z.ZodOptional<z.ZodNumber>;
|
|
10
|
+
}, z.core.$strip>;
|
|
11
|
+
state: z.ZodAny;
|
|
12
|
+
returnvalue: z.ZodAny;
|
|
13
|
+
attemptsStarted: z.ZodNumber;
|
|
14
|
+
attemptsMade: z.ZodNumber;
|
|
15
|
+
delay: z.ZodNumber;
|
|
16
|
+
timestamp: z.ZodNumber;
|
|
17
|
+
finishedOn: z.ZodOptional<z.ZodNumber>;
|
|
18
|
+
processedOn: z.ZodOptional<z.ZodNumber>;
|
|
19
|
+
}, z.core.$strip>;
|
|
20
|
+
export declare const JobSchemaArray: z.ZodArray<z.ZodObject<{
|
|
21
|
+
id: z.ZodString;
|
|
22
|
+
name: z.ZodString;
|
|
23
|
+
data: z.ZodAny;
|
|
24
|
+
progress: z.ZodNumber;
|
|
25
|
+
opts: z.ZodObject<{
|
|
26
|
+
attempts: z.ZodNumber;
|
|
27
|
+
delay: z.ZodOptional<z.ZodNumber>;
|
|
28
|
+
}, z.core.$strip>;
|
|
29
|
+
state: z.ZodAny;
|
|
30
|
+
returnvalue: z.ZodAny;
|
|
31
|
+
attemptsStarted: z.ZodNumber;
|
|
32
|
+
attemptsMade: z.ZodNumber;
|
|
33
|
+
delay: z.ZodNumber;
|
|
34
|
+
timestamp: z.ZodNumber;
|
|
35
|
+
finishedOn: z.ZodOptional<z.ZodNumber>;
|
|
36
|
+
processedOn: z.ZodOptional<z.ZodNumber>;
|
|
37
|
+
}, z.core.$strip>>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import z from "zod";
|
|
2
|
+
export const JobSchema = z.object({
|
|
3
|
+
id: z.string(),
|
|
4
|
+
name: z.string(),
|
|
5
|
+
data: z.any(),
|
|
6
|
+
progress: z.number(),
|
|
7
|
+
opts: z.object({
|
|
8
|
+
attempts: z.number(),
|
|
9
|
+
delay: z.number().optional()
|
|
10
|
+
}),
|
|
11
|
+
state: z.any(),
|
|
12
|
+
returnvalue: z.any(),
|
|
13
|
+
attemptsStarted: z.number(),
|
|
14
|
+
attemptsMade: z.number(),
|
|
15
|
+
delay: z.number(),
|
|
16
|
+
timestamp: z.number(),
|
|
17
|
+
finishedOn: z.number().optional(),
|
|
18
|
+
processedOn: z.number().optional()
|
|
19
|
+
});
|
|
20
|
+
export const JobSchemaArray = z.array(JobSchema);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DELETE /api/_flows/:flowName/clear-history
|
|
3
|
+
*
|
|
4
|
+
* Clears all event history for a specific flow.
|
|
5
|
+
* This deletes:
|
|
6
|
+
* - All flow run streams (nq:flow:run-*)
|
|
7
|
+
* - The flow runs index (nq:flows:<flowName>)
|
|
8
|
+
*/
|
|
9
|
+
declare const _default: any;
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { defineEventHandler, createError, useEventStore } from "#imports";
|
|
2
|
+
export default defineEventHandler(async (event) => {
|
|
3
|
+
const flowName = event.context.params?.name;
|
|
4
|
+
if (!flowName) {
|
|
5
|
+
throw createError({ statusCode: 400, statusMessage: "Flow name required" });
|
|
6
|
+
}
|
|
7
|
+
try {
|
|
8
|
+
const store = useEventStore();
|
|
9
|
+
const names = store.names();
|
|
10
|
+
let deletedStreams = 0;
|
|
11
|
+
let deletedIndex = false;
|
|
12
|
+
const indexKey = names.flowIndex(flowName);
|
|
13
|
+
if (store.indexRead) {
|
|
14
|
+
const runs = await store.indexRead(indexKey, { limit: 1e4 });
|
|
15
|
+
if (store.deleteStream) {
|
|
16
|
+
for (const run of runs) {
|
|
17
|
+
const streamName = names.flow(run.id);
|
|
18
|
+
await store.deleteStream(streamName);
|
|
19
|
+
if (store.deleteIndex) {
|
|
20
|
+
const metaKey = `${indexKey}:meta:${run.id}`;
|
|
21
|
+
await store.deleteIndex(metaKey);
|
|
22
|
+
}
|
|
23
|
+
deletedStreams++;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (store.deleteIndex) {
|
|
28
|
+
await store.deleteIndex(indexKey);
|
|
29
|
+
deletedIndex = true;
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
success: true,
|
|
33
|
+
flowName,
|
|
34
|
+
deletedStreams,
|
|
35
|
+
deletedIndex
|
|
36
|
+
};
|
|
37
|
+
} catch (error) {
|
|
38
|
+
throw createError({
|
|
39
|
+
statusCode: 500,
|
|
40
|
+
statusMessage: "Failed to clear flow history",
|
|
41
|
+
data: error instanceof Error ? error.message : String(error)
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { defineEventHandler, getRouterParam, getQuery, useEventStore, useServerLogger } from "#imports";
|
|
2
|
+
const logger = useServerLogger("api-flows-runs");
|
|
3
|
+
export default defineEventHandler(async (event) => {
|
|
4
|
+
const flowName = getRouterParam(event, "name");
|
|
5
|
+
const query = getQuery(event);
|
|
6
|
+
const limit = Math.min(Number.parseInt(query.limit) || 50, 100);
|
|
7
|
+
const offset = Math.max(Number.parseInt(query.offset) || 0, 0);
|
|
8
|
+
const status = query.status;
|
|
9
|
+
event.node.res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
|
|
10
|
+
event.node.res.setHeader("Pragma", "no-cache");
|
|
11
|
+
if (!flowName) {
|
|
12
|
+
return { error: "Missing flow name" };
|
|
13
|
+
}
|
|
14
|
+
const store = useEventStore();
|
|
15
|
+
const names = store.names();
|
|
16
|
+
try {
|
|
17
|
+
const runIndexKey = names.flowIndex(flowName);
|
|
18
|
+
let totalCount = 0;
|
|
19
|
+
try {
|
|
20
|
+
const allEntries = await store.indexRead(runIndexKey, { limit: 1e4 });
|
|
21
|
+
totalCount = allEntries.length;
|
|
22
|
+
} catch {
|
|
23
|
+
totalCount = 0;
|
|
24
|
+
}
|
|
25
|
+
const entries = await store.indexRead(runIndexKey, { offset, limit });
|
|
26
|
+
const filteredEntries = status ? entries.filter((e) => e.metadata?.status === status) : entries;
|
|
27
|
+
const items = filteredEntries.map((entry) => ({
|
|
28
|
+
id: entry.id,
|
|
29
|
+
flowName,
|
|
30
|
+
status: entry.metadata?.status || "unknown",
|
|
31
|
+
createdAt: new Date(entry.score).toISOString(),
|
|
32
|
+
startedAt: entry.metadata?.startedAt ? new Date(entry.metadata.startedAt).toISOString() : void 0,
|
|
33
|
+
completedAt: entry.metadata?.completedAt ? new Date(entry.metadata.completedAt).toISOString() : void 0,
|
|
34
|
+
stepCount: entry.metadata?.stepCount || 0,
|
|
35
|
+
completedSteps: entry.metadata?.completedSteps || 0
|
|
36
|
+
}));
|
|
37
|
+
return {
|
|
38
|
+
flowName,
|
|
39
|
+
count: items.length,
|
|
40
|
+
total: totalCount,
|
|
41
|
+
offset,
|
|
42
|
+
limit,
|
|
43
|
+
hasMore: offset + items.length < totalCount,
|
|
44
|
+
items
|
|
45
|
+
};
|
|
46
|
+
} catch (err) {
|
|
47
|
+
logger.error("[flows/runs] error:", { error: err });
|
|
48
|
+
return {
|
|
49
|
+
error: "Failed to list runs",
|
|
50
|
+
message: err instanceof Error ? err.message : String(err)
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { defineEventHandler, readBody, getRouterParam, createError, useQueue, $useQueueRegistry } from "#imports";
|
|
2
|
+
export default defineEventHandler(async (event) => {
|
|
3
|
+
const flowName = getRouterParam(event, "name");
|
|
4
|
+
if (!flowName) {
|
|
5
|
+
throw createError({ statusCode: 400, statusMessage: "Flow name is required" });
|
|
6
|
+
}
|
|
7
|
+
const body = await readBody(event);
|
|
8
|
+
const { input, cron, delay, jobId, metadata } = body;
|
|
9
|
+
if (cron && delay) {
|
|
10
|
+
throw createError({
|
|
11
|
+
statusCode: 400,
|
|
12
|
+
statusMessage: "Cannot specify both cron and delay"
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
if (!cron && !delay) {
|
|
16
|
+
throw createError({
|
|
17
|
+
statusCode: 400,
|
|
18
|
+
statusMessage: "Must specify either cron or delay"
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
const registry = $useQueueRegistry();
|
|
22
|
+
const flow = registry?.flows?.[flowName];
|
|
23
|
+
if (!flow || !flow.entry) {
|
|
24
|
+
throw createError({ statusCode: 404, statusMessage: `Flow '${flowName}' not found` });
|
|
25
|
+
}
|
|
26
|
+
const queueName = typeof flow.entry.queue === "string" ? flow.entry.queue : flow.entry.queue?.name || flow.entry.queue;
|
|
27
|
+
const queue = useQueue();
|
|
28
|
+
const scheduleOpts = {};
|
|
29
|
+
if (cron) scheduleOpts.cron = cron;
|
|
30
|
+
if (delay) scheduleOpts.delay = delay;
|
|
31
|
+
const jobData = {
|
|
32
|
+
__scheduledFlowStart: true,
|
|
33
|
+
__flowName: flowName,
|
|
34
|
+
__flowInput: input || {},
|
|
35
|
+
__schedule: {
|
|
36
|
+
metadata,
|
|
37
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
const id = await queue.schedule(
|
|
41
|
+
queueName,
|
|
42
|
+
{
|
|
43
|
+
name: flow.entry.step,
|
|
44
|
+
data: jobData,
|
|
45
|
+
opts: jobId ? { jobId } : void 0
|
|
46
|
+
},
|
|
47
|
+
scheduleOpts
|
|
48
|
+
);
|
|
49
|
+
return {
|
|
50
|
+
id,
|
|
51
|
+
flowName,
|
|
52
|
+
queue: queueName,
|
|
53
|
+
step: flow.entry.step,
|
|
54
|
+
schedule: scheduleOpts,
|
|
55
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
56
|
+
};
|
|
57
|
+
});
|