@nvent-addon/app 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.d.mts +6 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +42 -0
- package/dist/runtime/app/assets/vueflow.css +1 -0
- package/dist/runtime/app/components/ConfirmDialog.d.vue.ts +33 -0
- package/dist/runtime/app/components/ConfirmDialog.vue +121 -0
- package/dist/runtime/app/components/ConfirmDialog.vue.d.ts +33 -0
- package/dist/runtime/app/components/FlowDiagram.d.vue.ts +65 -0
- package/dist/runtime/app/components/FlowDiagram.vue +341 -0
- package/dist/runtime/app/components/FlowDiagram.vue.d.ts +65 -0
- package/dist/runtime/app/components/FlowNodeCard.d.vue.ts +29 -0
- package/dist/runtime/app/components/FlowNodeCard.vue +158 -0
- package/dist/runtime/app/components/FlowNodeCard.vue.d.ts +29 -0
- package/dist/runtime/app/components/FlowRunOverview.d.vue.ts +17 -0
- package/dist/runtime/app/components/FlowRunOverview.vue +188 -0
- package/dist/runtime/app/components/FlowRunOverview.vue.d.ts +17 -0
- package/dist/runtime/app/components/FlowRunStatusBadge.d.vue.ts +18 -0
- package/dist/runtime/app/components/FlowRunStatusBadge.vue +74 -0
- package/dist/runtime/app/components/FlowRunStatusBadge.vue.d.ts +18 -0
- package/dist/runtime/app/components/FlowRunTimeline.d.vue.ts +12 -0
- package/dist/runtime/app/components/FlowRunTimeline.vue +127 -0
- package/dist/runtime/app/components/FlowRunTimeline.vue.d.ts +12 -0
- package/dist/runtime/app/components/FlowScheduleDialog.d.vue.ts +16 -0
- package/dist/runtime/app/components/FlowScheduleDialog.vue +226 -0
- package/dist/runtime/app/components/FlowScheduleDialog.vue.d.ts +16 -0
- package/dist/runtime/app/components/FlowSchedulesList.d.vue.ts +12 -0
- package/dist/runtime/app/components/FlowSchedulesList.vue +99 -0
- package/dist/runtime/app/components/FlowSchedulesList.vue.d.ts +12 -0
- package/dist/runtime/app/components/FlowStepSelector.d.vue.ts +22 -0
- package/dist/runtime/app/components/FlowStepSelector.vue +238 -0
- package/dist/runtime/app/components/FlowStepSelector.vue.d.ts +22 -0
- package/dist/runtime/app/components/JobScheduling.d.vue.ts +6 -0
- package/dist/runtime/app/components/JobScheduling.vue +203 -0
- package/dist/runtime/app/components/JobScheduling.vue.d.ts +6 -0
- package/dist/runtime/app/components/ListItem.d.vue.ts +23 -0
- package/dist/runtime/app/components/ListItem.vue +70 -0
- package/dist/runtime/app/components/ListItem.vue.d.ts +23 -0
- package/dist/runtime/app/components/QueueConfigDetails.d.vue.ts +45 -0
- package/dist/runtime/app/components/QueueConfigDetails.vue +412 -0
- package/dist/runtime/app/components/QueueConfigDetails.vue.d.ts +45 -0
- package/dist/runtime/app/components/StatCounter.d.vue.ts +9 -0
- package/dist/runtime/app/components/StatCounter.vue +25 -0
- package/dist/runtime/app/components/StatCounter.vue.d.ts +9 -0
- package/dist/runtime/app/components/TimelineList.d.vue.ts +7 -0
- package/dist/runtime/app/components/TimelineList.vue +211 -0
- package/dist/runtime/app/components/TimelineList.vue.d.ts +7 -0
- package/dist/runtime/app/components/nhealth/component-router.d.vue.ts +46 -0
- package/dist/runtime/app/components/nhealth/component-router.vue +26 -0
- package/dist/runtime/app/components/nhealth/component-router.vue.d.ts +46 -0
- package/dist/runtime/app/components/nhealth/component-shell.d.vue.ts +24 -0
- package/dist/runtime/app/components/nhealth/component-shell.vue +89 -0
- package/dist/runtime/app/components/nhealth/component-shell.vue.d.ts +24 -0
- package/dist/runtime/app/composables/useAnalyzedFlows.d.ts +14 -0
- package/dist/runtime/app/composables/useAnalyzedFlows.js +8 -0
- package/dist/runtime/app/composables/useComponentRouter.d.ts +38 -0
- package/dist/runtime/app/composables/useComponentRouter.js +240 -0
- package/dist/runtime/app/composables/useFlowRunTimeline.d.ts +82 -0
- package/dist/runtime/app/composables/useFlowRunTimeline.js +67 -0
- package/dist/runtime/app/composables/useFlowRuns.d.ts +18 -0
- package/dist/runtime/app/composables/useFlowRuns.js +32 -0
- package/dist/runtime/app/composables/useFlowRunsInfinite.d.ts +24 -0
- package/dist/runtime/app/composables/useFlowRunsInfinite.js +123 -0
- package/dist/runtime/app/composables/useFlowRunsPolling.d.ts +9 -0
- package/dist/runtime/app/composables/useFlowRunsPolling.js +33 -0
- package/dist/runtime/app/composables/useFlowState.d.ts +127 -0
- package/dist/runtime/app/composables/useFlowState.js +225 -0
- package/dist/runtime/app/composables/useFlowWebSocket.d.ts +27 -0
- package/dist/runtime/app/composables/useFlowWebSocket.js +222 -0
- package/dist/runtime/app/composables/useFlowsNavigation.d.ts +10 -0
- package/dist/runtime/app/composables/useFlowsNavigation.js +58 -0
- package/dist/runtime/app/composables/useQueueJobs.d.ts +26 -0
- package/dist/runtime/app/composables/useQueueJobs.js +20 -0
- package/dist/runtime/app/composables/useQueueUpdates.d.ts +24 -0
- package/dist/runtime/app/composables/useQueueUpdates.js +54 -0
- package/dist/runtime/app/composables/useQueues.d.ts +45 -0
- package/dist/runtime/app/composables/useQueues.js +26 -0
- package/dist/runtime/app/composables/useQueuesLive.d.ts +16 -0
- package/dist/runtime/app/composables/useQueuesLive.js +62 -0
- package/dist/runtime/app/composables/useQueuesWebSocket.d.ts +17 -0
- package/dist/runtime/app/composables/useQueuesWebSocket.js +159 -0
- package/dist/runtime/app/pages/flows/index.d.vue.ts +3 -0
- package/dist/runtime/app/pages/flows/index.vue +683 -0
- package/dist/runtime/app/pages/flows/index.vue.d.ts +3 -0
- package/dist/runtime/app/pages/index.d.vue.ts +3 -0
- package/dist/runtime/app/pages/index.vue +34 -0
- package/dist/runtime/app/pages/index.vue.d.ts +3 -0
- package/dist/runtime/app/pages/queues/index.d.vue.ts +3 -0
- package/dist/runtime/app/pages/queues/index.vue +229 -0
- package/dist/runtime/app/pages/queues/index.vue.d.ts +3 -0
- package/dist/runtime/app/pages/queues/job.d.vue.ts +3 -0
- package/dist/runtime/app/pages/queues/job.vue +262 -0
- package/dist/runtime/app/pages/queues/job.vue.d.ts +3 -0
- package/dist/runtime/app/pages/queues/jobs.d.vue.ts +3 -0
- package/dist/runtime/app/pages/queues/jobs.vue +291 -0
- package/dist/runtime/app/pages/queues/jobs.vue.d.ts +3 -0
- package/dist/runtime/app/plugins/vueflow.client.d.ts +2 -0
- package/dist/runtime/app/plugins/vueflow.client.js +11 -0
- package/dist/types.d.mts +7 -0
- package/package.json +47 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ref, useFetch } from "#imports";
|
|
2
|
+
export function useQueueJobs(queueName, state = ref(null)) {
|
|
3
|
+
return useFetch(
|
|
4
|
+
() => {
|
|
5
|
+
const params = new URLSearchParams();
|
|
6
|
+
if (state.value) {
|
|
7
|
+
params.append("state", state.value);
|
|
8
|
+
}
|
|
9
|
+
const queryString = params.toString();
|
|
10
|
+
return `/api/_queues/${encodeURIComponent(queueName.value)}/job${queryString ? `?${queryString}` : ""}`;
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
key: () => `queue-jobs-${queueName.value}-${state.value || "all"}`,
|
|
14
|
+
watch: [queueName, state],
|
|
15
|
+
immediate: true,
|
|
16
|
+
server: false
|
|
17
|
+
// Client-only
|
|
18
|
+
}
|
|
19
|
+
);
|
|
20
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type Ref } from '#imports';
|
|
2
|
+
/**
|
|
3
|
+
* Composable for real-time queue updates
|
|
4
|
+
*/
|
|
5
|
+
export declare function useQueueUpdates(queueName: Ref<string>): {
|
|
6
|
+
isConnected: Ref<boolean, boolean>;
|
|
7
|
+
isReconnecting: Ref<boolean, boolean>;
|
|
8
|
+
counts: import("vue").ComputedRef<{
|
|
9
|
+
active: number;
|
|
10
|
+
completed: number;
|
|
11
|
+
failed: number;
|
|
12
|
+
delayed: number;
|
|
13
|
+
waiting: number;
|
|
14
|
+
paused: number;
|
|
15
|
+
} | null>;
|
|
16
|
+
lastEvent: import("vue").ComputedRef<{
|
|
17
|
+
[x: string]: any;
|
|
18
|
+
eventType: "waiting" | "active" | "completed" | "failed" | "progress";
|
|
19
|
+
jobId?: string | undefined;
|
|
20
|
+
} | null>;
|
|
21
|
+
countsUpdatedAt: import("vue").ComputedRef<number | null>;
|
|
22
|
+
shouldRefreshJobs: import("vue").ComputedRef<boolean>;
|
|
23
|
+
resetRefreshFlag: () => void;
|
|
24
|
+
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ref, computed, watch, onUnmounted } from "#imports";
|
|
2
|
+
import { useQueuesWebSocket } from "./useQueuesWebSocket.js";
|
|
3
|
+
export function useQueueUpdates(queueName) {
|
|
4
|
+
const queueWs = useQueuesWebSocket();
|
|
5
|
+
const state = ref({
|
|
6
|
+
counts: null,
|
|
7
|
+
lastEvent: null,
|
|
8
|
+
countsUpdatedAt: null,
|
|
9
|
+
shouldRefreshJobs: false
|
|
10
|
+
});
|
|
11
|
+
let subscriptionId = null;
|
|
12
|
+
const subscribe = (name) => {
|
|
13
|
+
if (!import.meta.client || !name) return;
|
|
14
|
+
subscriptionId = queueWs.subscribe(
|
|
15
|
+
name,
|
|
16
|
+
(counts) => {
|
|
17
|
+
state.value.counts = counts;
|
|
18
|
+
state.value.countsUpdatedAt = Date.now();
|
|
19
|
+
},
|
|
20
|
+
(event) => {
|
|
21
|
+
state.value.lastEvent = event;
|
|
22
|
+
if (["waiting", "active", "completed", "failed"].includes(event?.eventType)) {
|
|
23
|
+
state.value.shouldRefreshJobs = true;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
if (import.meta.client && queueName.value) {
|
|
29
|
+
subscribe(queueName.value);
|
|
30
|
+
}
|
|
31
|
+
watch(queueName, (newName, oldName) => {
|
|
32
|
+
if (oldName && subscriptionId) {
|
|
33
|
+
queueWs.unsubscribe(oldName, subscriptionId);
|
|
34
|
+
}
|
|
35
|
+
if (newName) subscribe(newName);
|
|
36
|
+
});
|
|
37
|
+
onUnmounted(() => {
|
|
38
|
+
if (queueName.value && subscriptionId) {
|
|
39
|
+
queueWs.unsubscribe(queueName.value, subscriptionId);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
const resetRefreshFlag = () => {
|
|
43
|
+
state.value.shouldRefreshJobs = false;
|
|
44
|
+
};
|
|
45
|
+
return {
|
|
46
|
+
isConnected: queueWs.connected,
|
|
47
|
+
isReconnecting: queueWs.reconnecting,
|
|
48
|
+
counts: computed(() => state.value.counts),
|
|
49
|
+
lastEvent: computed(() => state.value.lastEvent),
|
|
50
|
+
countsUpdatedAt: computed(() => state.value.countsUpdatedAt),
|
|
51
|
+
shouldRefreshJobs: computed(() => state.value.shouldRefreshJobs),
|
|
52
|
+
resetRefreshFlag
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { type Ref } from '#imports';
|
|
2
|
+
import type { FetchError } from 'ofetch';
|
|
3
|
+
export interface QueueCounts {
|
|
4
|
+
active: number;
|
|
5
|
+
completed: number;
|
|
6
|
+
failed: number;
|
|
7
|
+
delayed: number;
|
|
8
|
+
waiting: number;
|
|
9
|
+
paused: number;
|
|
10
|
+
}
|
|
11
|
+
export interface QueueConfig {
|
|
12
|
+
queue: {
|
|
13
|
+
prefix?: string;
|
|
14
|
+
defaultJobOptions?: Record<string, any>;
|
|
15
|
+
limiter?: {
|
|
16
|
+
max?: number;
|
|
17
|
+
duration?: number;
|
|
18
|
+
groupKey?: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
worker: {
|
|
22
|
+
concurrency?: number;
|
|
23
|
+
lockDurationMs?: number;
|
|
24
|
+
maxStalledCount?: number;
|
|
25
|
+
drainDelayMs?: number;
|
|
26
|
+
autorun?: boolean;
|
|
27
|
+
pollingIntervalMs?: number;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export interface QueueInfo {
|
|
31
|
+
name: string;
|
|
32
|
+
counts: QueueCounts;
|
|
33
|
+
isPaused: boolean;
|
|
34
|
+
config?: QueueConfig;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Composable for fetching queue list with job counts
|
|
38
|
+
* Client-only to avoid hydration mismatches
|
|
39
|
+
*/
|
|
40
|
+
export declare function useQueues(): {
|
|
41
|
+
queues: Ref<QueueInfo[] | null | undefined>;
|
|
42
|
+
refresh: () => Promise<void>;
|
|
43
|
+
status: Ref<'idle' | 'pending' | 'success' | 'error'>;
|
|
44
|
+
error: Ref<FetchError | null | undefined>;
|
|
45
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ref, useFetch } from "#imports";
|
|
2
|
+
export function useQueues() {
|
|
3
|
+
const refreshCounter = ref(0);
|
|
4
|
+
const { data: queues, refresh: _refresh, status, error } = useFetch(
|
|
5
|
+
() => `/api/_queues?_t=${refreshCounter.value}`,
|
|
6
|
+
{
|
|
7
|
+
immediate: false,
|
|
8
|
+
watch: false,
|
|
9
|
+
server: false
|
|
10
|
+
// Client-only
|
|
11
|
+
}
|
|
12
|
+
);
|
|
13
|
+
const refresh = async () => {
|
|
14
|
+
refreshCounter.value++;
|
|
15
|
+
await _refresh();
|
|
16
|
+
};
|
|
17
|
+
if (import.meta.client) {
|
|
18
|
+
refresh();
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
queues,
|
|
22
|
+
refresh,
|
|
23
|
+
status,
|
|
24
|
+
error
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type Ref } from '#imports';
|
|
2
|
+
import type { QueueInfo, QueueCounts } from './useQueues.js';
|
|
3
|
+
/**
|
|
4
|
+
* Composable for live queue updates across all queues
|
|
5
|
+
*/
|
|
6
|
+
export declare function useQueuesLive(queues: Ref<QueueInfo[] | null | undefined>): {
|
|
7
|
+
queues: import("vue").ComputedRef<{
|
|
8
|
+
counts: QueueCounts;
|
|
9
|
+
name: string;
|
|
10
|
+
isPaused: boolean;
|
|
11
|
+
config?: import("#imports").QueueConfig;
|
|
12
|
+
}[] | null>;
|
|
13
|
+
isConnected: Ref<boolean, boolean>;
|
|
14
|
+
isReconnecting: Ref<boolean, boolean>;
|
|
15
|
+
liveCounts: Ref<Record<string, QueueCounts>, Record<string, QueueCounts>>;
|
|
16
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { ref, computed, watch, onUnmounted } from "#imports";
|
|
2
|
+
import { useQueuesWebSocket } from "./useQueuesWebSocket.js";
|
|
3
|
+
export function useQueuesLive(queues) {
|
|
4
|
+
const queueWs = useQueuesWebSocket();
|
|
5
|
+
const liveCounts = ref({});
|
|
6
|
+
const subscriptionIds = /* @__PURE__ */ new Map();
|
|
7
|
+
const subscribeToQueues = (queueNames) => {
|
|
8
|
+
for (const queueName of queueNames) {
|
|
9
|
+
if (!subscriptionIds.has(queueName)) {
|
|
10
|
+
const id = queueWs.subscribe(
|
|
11
|
+
queueName,
|
|
12
|
+
(counts) => {
|
|
13
|
+
liveCounts.value[queueName] = counts;
|
|
14
|
+
}
|
|
15
|
+
);
|
|
16
|
+
subscriptionIds.set(queueName, id);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const unsubscribeFromQueues = (queueNames) => {
|
|
21
|
+
for (const queueName of queueNames) {
|
|
22
|
+
const id = subscriptionIds.get(queueName);
|
|
23
|
+
if (id) {
|
|
24
|
+
queueWs.unsubscribe(queueName, id);
|
|
25
|
+
subscriptionIds.delete(queueName);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
if (import.meta.client && queues.value) {
|
|
30
|
+
subscribeToQueues(queues.value.map((q) => q.name));
|
|
31
|
+
}
|
|
32
|
+
watch(
|
|
33
|
+
() => queues.value,
|
|
34
|
+
(newQueues, oldQueues) => {
|
|
35
|
+
if (!newQueues) return;
|
|
36
|
+
const oldNames = new Set(oldQueues?.map((q) => q.name) || []);
|
|
37
|
+
const newNames = newQueues.map((q) => q.name);
|
|
38
|
+
const toSubscribe = newNames.filter((name) => !oldNames.has(name));
|
|
39
|
+
const toUnsubscribe = Array.from(oldNames).filter((name) => !newNames.includes(name));
|
|
40
|
+
if (toUnsubscribe.length > 0) unsubscribeFromQueues(toUnsubscribe);
|
|
41
|
+
if (toSubscribe.length > 0) subscribeToQueues(toSubscribe);
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
onUnmounted(() => {
|
|
45
|
+
if (queues.value) {
|
|
46
|
+
unsubscribeFromQueues(queues.value.map((q) => q.name));
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
const queuesWithLiveCounts = computed(() => {
|
|
50
|
+
if (!queues.value) return null;
|
|
51
|
+
return queues.value.map((queue) => ({
|
|
52
|
+
...queue,
|
|
53
|
+
counts: liveCounts.value[queue.name] || queue.counts
|
|
54
|
+
}));
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
queues: queuesWithLiveCounts,
|
|
58
|
+
isConnected: queueWs.connected,
|
|
59
|
+
isReconnecting: queueWs.reconnecting,
|
|
60
|
+
liveCounts
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { QueueCounts } from './useQueues.js';
|
|
2
|
+
export interface QueueEvent {
|
|
3
|
+
eventType: 'waiting' | 'active' | 'completed' | 'failed' | 'progress';
|
|
4
|
+
jobId?: string;
|
|
5
|
+
[key: string]: any;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Shared WebSocket for queue updates
|
|
9
|
+
* All instances share the same connection
|
|
10
|
+
*/
|
|
11
|
+
export declare function useQueuesWebSocket(): {
|
|
12
|
+
subscribe: (queueName: string, onCounts?: (counts: QueueCounts) => void, onEvent?: (event: QueueEvent) => void) => string;
|
|
13
|
+
unsubscribe: (queueName: string, id?: string) => void;
|
|
14
|
+
stop: () => void;
|
|
15
|
+
connected: import("vue").Ref<boolean, boolean>;
|
|
16
|
+
reconnecting: import("vue").Ref<boolean, boolean>;
|
|
17
|
+
};
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { ref } from "#imports";
|
|
2
|
+
let ws = null;
|
|
3
|
+
const connected = ref(false);
|
|
4
|
+
const reconnecting = ref(false);
|
|
5
|
+
let retry = 0;
|
|
6
|
+
let reconnectTimer = null;
|
|
7
|
+
const subscriptions = /* @__PURE__ */ new Map();
|
|
8
|
+
const clearTimers = () => {
|
|
9
|
+
if (reconnectTimer) {
|
|
10
|
+
clearTimeout(reconnectTimer);
|
|
11
|
+
reconnectTimer = null;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const send = (data) => {
|
|
15
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
16
|
+
ws.send(JSON.stringify(data));
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
const stop = () => {
|
|
20
|
+
clearTimers();
|
|
21
|
+
if (ws) {
|
|
22
|
+
try {
|
|
23
|
+
ws.close(1e3, "Client closing");
|
|
24
|
+
} catch (err) {
|
|
25
|
+
console.warn("[useQueuesWebSocket] Error closing:", err);
|
|
26
|
+
}
|
|
27
|
+
ws = null;
|
|
28
|
+
}
|
|
29
|
+
connected.value = false;
|
|
30
|
+
reconnecting.value = false;
|
|
31
|
+
retry = 0;
|
|
32
|
+
subscriptions.clear();
|
|
33
|
+
};
|
|
34
|
+
const attemptReconnect = () => {
|
|
35
|
+
if (retry >= 10) {
|
|
36
|
+
console.error("[useQueuesWebSocket] Max retries reached");
|
|
37
|
+
stop();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
retry++;
|
|
41
|
+
reconnecting.value = true;
|
|
42
|
+
const delay = Math.min(1e3 * Math.pow(2, retry), 1e4);
|
|
43
|
+
clearTimers();
|
|
44
|
+
reconnectTimer = setTimeout(() => {
|
|
45
|
+
connect();
|
|
46
|
+
}, delay);
|
|
47
|
+
};
|
|
48
|
+
const connect = () => {
|
|
49
|
+
if (import.meta.server || typeof WebSocket === "undefined") return;
|
|
50
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
51
|
+
for (const queueName of subscriptions.keys()) {
|
|
52
|
+
send({ type: "subscribe", queueName });
|
|
53
|
+
}
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (ws && ws.readyState === WebSocket.CONNECTING) {
|
|
57
|
+
console.log("[useQueuesWebSocket] Connection in progress, waiting...");
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (ws) {
|
|
61
|
+
try {
|
|
62
|
+
ws.close();
|
|
63
|
+
} catch {
|
|
64
|
+
}
|
|
65
|
+
ws = null;
|
|
66
|
+
}
|
|
67
|
+
try {
|
|
68
|
+
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
|
69
|
+
const wsUrl = `${protocol}//${window.location.host}/api/_queues/ws`;
|
|
70
|
+
const socket = new WebSocket(wsUrl);
|
|
71
|
+
ws = socket;
|
|
72
|
+
socket.onopen = () => {
|
|
73
|
+
console.log("[useQueuesWebSocket] Connected");
|
|
74
|
+
connected.value = true;
|
|
75
|
+
reconnecting.value = false;
|
|
76
|
+
retry = 0;
|
|
77
|
+
for (const queueName of subscriptions.keys()) {
|
|
78
|
+
send({ type: "subscribe", queueName });
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
socket.onmessage = (event) => {
|
|
82
|
+
try {
|
|
83
|
+
const data = JSON.parse(event.data);
|
|
84
|
+
if (data.type === "counts" && data.queueName) {
|
|
85
|
+
const subs = subscriptions.get(data.queueName);
|
|
86
|
+
if (subs) {
|
|
87
|
+
for (const sub of subs) {
|
|
88
|
+
sub.onCounts?.(data.counts);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
} else if (data.type === "event" && data.queueName) {
|
|
92
|
+
const subs = subscriptions.get(data.queueName);
|
|
93
|
+
if (subs) {
|
|
94
|
+
for (const sub of subs) {
|
|
95
|
+
sub.onEvent?.(data.event);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} catch (err) {
|
|
100
|
+
console.error("[useQueuesWebSocket] Parse error:", err);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
socket.onerror = (err) => {
|
|
104
|
+
console.error("[useQueuesWebSocket] Error:", err);
|
|
105
|
+
};
|
|
106
|
+
socket.onclose = (event) => {
|
|
107
|
+
console.log("[useQueuesWebSocket] Closed:", event.code);
|
|
108
|
+
connected.value = false;
|
|
109
|
+
ws = null;
|
|
110
|
+
if (event.code !== 1e3 && subscriptions.size > 0) {
|
|
111
|
+
attemptReconnect();
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
} catch (err) {
|
|
115
|
+
console.error("[useQueuesWebSocket] Connection error:", err);
|
|
116
|
+
attemptReconnect();
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
const subscribe = (queueName, onCounts, onEvent) => {
|
|
120
|
+
const id = `${queueName}_${Date.now()}_${Math.random()}`;
|
|
121
|
+
const existing = subscriptions.get(queueName) || [];
|
|
122
|
+
existing.push({ id, onCounts, onEvent });
|
|
123
|
+
subscriptions.set(queueName, existing);
|
|
124
|
+
const shouldSubscribe = existing.length === 1;
|
|
125
|
+
if (shouldSubscribe) {
|
|
126
|
+
if (ws && ws.readyState === WebSocket.OPEN) {
|
|
127
|
+
send({ type: "subscribe", queueName });
|
|
128
|
+
} else if (ws && ws.readyState === WebSocket.CONNECTING) {
|
|
129
|
+
} else {
|
|
130
|
+
connect();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return id;
|
|
134
|
+
};
|
|
135
|
+
const unsubscribe = (queueName, id) => {
|
|
136
|
+
const existing = subscriptions.get(queueName);
|
|
137
|
+
if (!existing) return;
|
|
138
|
+
if (id) {
|
|
139
|
+
const filtered = existing.filter((sub) => sub.id !== id);
|
|
140
|
+
if (filtered.length > 0) {
|
|
141
|
+
subscriptions.set(queueName, filtered);
|
|
142
|
+
} else {
|
|
143
|
+
subscriptions.delete(queueName);
|
|
144
|
+
send({ type: "unsubscribe", queueName });
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
subscriptions.delete(queueName);
|
|
148
|
+
send({ type: "unsubscribe", queueName });
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
export function useQueuesWebSocket() {
|
|
152
|
+
return {
|
|
153
|
+
subscribe,
|
|
154
|
+
unsubscribe,
|
|
155
|
+
stop,
|
|
156
|
+
connected,
|
|
157
|
+
reconnecting
|
|
158
|
+
};
|
|
159
|
+
}
|
|
@@ -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;
|