@nvent-addon/app 0.4.5 → 0.5.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.
Files changed (153) hide show
  1. package/dist/module.d.mts +19 -1
  2. package/dist/module.mjs +20 -8
  3. package/dist/runtime/app/components/{nhealth/component-router.d.vue.ts → ComponentRouter.d.vue.ts} +1 -5
  4. package/dist/runtime/app/components/{nhealth/component-router.vue.d.ts → ComponentRouter.vue.d.ts} +1 -5
  5. package/dist/runtime/app/components/{nhealth/component-shell.d.vue.ts → ComponentShell.d.vue.ts} +4 -9
  6. package/dist/runtime/app/components/ComponentShell.vue +87 -0
  7. package/dist/runtime/app/components/{nhealth/component-shell.vue.d.ts → ComponentShell.vue.d.ts} +4 -9
  8. package/dist/runtime/app/components/ConfirmDialog.d.vue.ts +1 -6
  9. package/dist/runtime/app/components/ConfirmDialog.vue.d.ts +1 -6
  10. package/dist/runtime/app/components/ListItem.d.vue.ts +3 -6
  11. package/dist/runtime/app/components/ListItem.vue.d.ts +3 -6
  12. package/dist/runtime/app/components/LiveIndicator.d.vue.ts +7 -0
  13. package/dist/runtime/app/components/LiveIndicator.vue +30 -0
  14. package/dist/runtime/app/components/LiveIndicator.vue.d.ts +7 -0
  15. package/dist/runtime/app/components/{QueueConfigDetails.d.vue.ts → QueueConfiguration.d.vue.ts} +1 -10
  16. package/dist/runtime/app/components/QueueConfiguration.vue +387 -0
  17. package/dist/runtime/app/components/{QueueConfigDetails.vue.d.ts → QueueConfiguration.vue.d.ts} +1 -10
  18. package/dist/runtime/app/components/StatCard.d.vue.ts +9 -0
  19. package/dist/runtime/app/components/StatCard.vue +57 -0
  20. package/dist/runtime/app/components/StatCard.vue.d.ts +9 -0
  21. package/dist/runtime/app/components/TimelineList.vue +67 -0
  22. package/dist/runtime/app/components/flow/AwaitNode.d.vue.ts +18 -0
  23. package/dist/runtime/app/components/flow/AwaitNode.vue +91 -0
  24. package/dist/runtime/app/components/flow/AwaitNode.vue.d.ts +18 -0
  25. package/dist/runtime/app/components/{FlowDiagram.d.vue.ts → flow/Diagram.d.vue.ts} +12 -1
  26. package/dist/runtime/app/components/{FlowDiagram.vue → flow/Diagram.vue} +92 -11
  27. package/dist/runtime/app/components/{FlowDiagram.vue.d.ts → flow/Diagram.vue.d.ts} +12 -1
  28. package/dist/runtime/app/components/{FlowRunOverview.d.vue.ts → flow/RunOverview.d.vue.ts} +3 -0
  29. package/dist/runtime/app/components/{FlowRunOverview.vue → flow/RunOverview.vue} +94 -8
  30. package/dist/runtime/app/components/{FlowRunOverview.vue.d.ts → flow/RunOverview.vue.d.ts} +3 -0
  31. package/dist/runtime/app/components/{FlowRunStatusBadge.d.vue.ts → flow/RunStatusBadge.d.vue.ts} +2 -8
  32. package/dist/runtime/app/components/{FlowRunStatusBadge.vue → flow/RunStatusBadge.vue} +8 -1
  33. package/dist/runtime/app/components/{FlowRunStatusBadge.vue.d.ts → flow/RunStatusBadge.vue.d.ts} +2 -8
  34. package/dist/runtime/app/components/{FlowRunTimeline.vue → flow/RunTimeline.vue} +1 -1
  35. package/dist/runtime/app/components/{FlowStepSelector.d.vue.ts → flow/StepSelector.d.vue.ts} +1 -0
  36. package/dist/runtime/app/components/flow/StepSelector.vue +553 -0
  37. package/dist/runtime/app/components/{FlowStepSelector.vue.d.ts → flow/StepSelector.vue.d.ts} +1 -0
  38. package/dist/runtime/app/components/trigger/BasicInfoCard.d.vue.ts +33 -0
  39. package/dist/runtime/app/components/trigger/BasicInfoCard.vue +168 -0
  40. package/dist/runtime/app/components/trigger/BasicInfoCard.vue.d.ts +33 -0
  41. package/dist/runtime/app/components/{FlowSchedulesList.d.vue.ts → trigger/DangerZone.d.vue.ts} +4 -6
  42. package/dist/runtime/app/components/trigger/DangerZone.vue +46 -0
  43. package/dist/runtime/app/components/{FlowSchedulesList.vue.d.ts → trigger/DangerZone.vue.d.ts} +4 -6
  44. package/dist/runtime/app/components/trigger/EditHeader.d.vue.ts +15 -0
  45. package/dist/runtime/app/components/trigger/EditHeader.vue +55 -0
  46. package/dist/runtime/app/components/trigger/EditHeader.vue.d.ts +15 -0
  47. package/dist/runtime/app/components/trigger/EventConfig.d.vue.ts +24 -0
  48. package/dist/runtime/app/components/trigger/EventConfig.vue +68 -0
  49. package/dist/runtime/app/components/trigger/EventConfig.vue.d.ts +24 -0
  50. package/dist/runtime/app/components/trigger/FlowSubscriptions.d.vue.ts +14 -0
  51. package/dist/runtime/app/components/trigger/FlowSubscriptions.vue +128 -0
  52. package/dist/runtime/app/components/trigger/FlowSubscriptions.vue.d.ts +14 -0
  53. package/dist/runtime/app/components/trigger/ScheduleConfig.d.vue.ts +27 -0
  54. package/dist/runtime/app/components/trigger/ScheduleConfig.vue +375 -0
  55. package/dist/runtime/app/components/trigger/ScheduleConfig.vue.d.ts +27 -0
  56. package/dist/runtime/app/components/{FlowScheduleDialog.d.vue.ts → trigger/StatusConfig.d.vue.ts} +6 -6
  57. package/dist/runtime/app/components/trigger/StatusConfig.vue +78 -0
  58. package/dist/runtime/app/components/{FlowScheduleDialog.vue.d.ts → trigger/StatusConfig.vue.d.ts} +6 -6
  59. package/dist/runtime/app/components/trigger/WebhookConfig.d.vue.ts +30 -0
  60. package/dist/runtime/app/components/trigger/WebhookConfig.vue +97 -0
  61. package/dist/runtime/app/components/trigger/WebhookConfig.vue.d.ts +30 -0
  62. package/dist/runtime/app/composables/useAnalyzedFlows.d.ts +5 -0
  63. package/dist/runtime/app/composables/useAnalyzedFlows.js +15 -1
  64. package/dist/runtime/app/composables/useComponentRouter.d.ts +8 -0
  65. package/dist/runtime/app/composables/useComponentRouter.js +10 -2
  66. package/dist/runtime/app/composables/useFlowRunsInfinite.d.ts +1 -1
  67. package/dist/runtime/app/composables/useFlowState.js +65 -0
  68. package/dist/runtime/app/composables/useFlowWebSocket.d.ts +11 -2
  69. package/dist/runtime/app/composables/useFlowWebSocket.js +181 -65
  70. package/dist/runtime/app/composables/useQueueJobs.d.ts +12 -1
  71. package/dist/runtime/app/composables/useQueueJobs.js +13 -7
  72. package/dist/runtime/app/composables/useTrigger.d.ts +137 -0
  73. package/dist/runtime/app/composables/useTrigger.js +116 -0
  74. package/dist/runtime/app/composables/useTriggerWebSocket.d.ts +35 -0
  75. package/dist/runtime/app/composables/useTriggerWebSocket.js +333 -0
  76. package/dist/runtime/app/pages/dashboard.d.vue.ts +3 -0
  77. package/dist/runtime/app/pages/dashboard.vue +738 -0
  78. package/dist/runtime/app/pages/dashboard.vue.d.ts +3 -0
  79. package/dist/runtime/app/pages/flows/[name].d.vue.ts +3 -0
  80. package/dist/runtime/app/pages/flows/[name].vue +680 -0
  81. package/dist/runtime/app/pages/flows/[name].vue.d.ts +3 -0
  82. package/dist/runtime/app/pages/flows/index.vue +321 -620
  83. package/dist/runtime/app/pages/index.vue +39 -9
  84. package/dist/runtime/app/pages/queues/index.vue +202 -194
  85. package/dist/runtime/app/pages/queues/jobs.vue +534 -207
  86. package/dist/runtime/app/pages/settings/scheduler.d.vue.ts +3 -0
  87. package/dist/runtime/app/pages/settings/scheduler.vue +310 -0
  88. package/dist/runtime/app/pages/settings/scheduler.vue.d.ts +3 -0
  89. package/dist/runtime/app/pages/triggers/[name]/edit.d.vue.ts +3 -0
  90. package/dist/runtime/app/pages/triggers/[name]/edit.vue +429 -0
  91. package/dist/runtime/app/pages/triggers/[name]/edit.vue.d.ts +3 -0
  92. package/dist/runtime/app/pages/triggers/[name].d.vue.ts +3 -0
  93. package/dist/runtime/app/pages/triggers/[name].vue +898 -0
  94. package/dist/runtime/app/pages/triggers/[name].vue.d.ts +3 -0
  95. package/dist/runtime/app/pages/triggers/index.d.vue.ts +3 -0
  96. package/dist/runtime/app/pages/triggers/index.vue +528 -0
  97. package/dist/runtime/app/pages/triggers/index.vue.d.ts +3 -0
  98. package/dist/runtime/app/pages/triggers/new.d.vue.ts +3 -0
  99. package/dist/runtime/app/pages/triggers/new.vue +610 -0
  100. package/dist/runtime/app/pages/triggers/new.vue.d.ts +3 -0
  101. package/dist/runtime/server/api/_flows/[name]/clear-history.delete.d.ts +10 -0
  102. package/dist/runtime/server/api/_flows/[name]/clear-history.delete.js +49 -0
  103. package/dist/runtime/server/api/_flows/[name]/runs/[runId]/cancel.post.d.ts +2 -0
  104. package/dist/runtime/server/api/_flows/[name]/runs/[runId]/cancel.post.js +21 -0
  105. package/dist/runtime/server/api/_flows/[name]/runs.get.d.ts +17 -0
  106. package/dist/runtime/server/api/_flows/[name]/runs.get.js +64 -0
  107. package/dist/runtime/server/api/_flows/[name]/start.post.d.ts +2 -0
  108. package/dist/runtime/server/api/_flows/[name]/start.post.js +9 -0
  109. package/dist/runtime/server/api/_flows/index.get.d.ts +7 -0
  110. package/dist/runtime/server/api/_flows/index.get.js +5 -0
  111. package/dist/runtime/server/api/_flows/recent-runs.get.d.ts +15 -0
  112. package/dist/runtime/server/api/_flows/recent-runs.get.js +67 -0
  113. package/dist/runtime/server/api/_flows/ws.d.ts +80 -0
  114. package/dist/runtime/server/api/_flows/ws.js +309 -0
  115. package/dist/runtime/server/api/_queues/[name]/job/[id].get.d.ts +2 -0
  116. package/dist/runtime/server/api/_queues/[name]/job/[id].get.js +14 -0
  117. package/dist/runtime/server/api/_queues/[name]/job/index.get.d.ts +2 -0
  118. package/dist/runtime/server/api/_queues/[name]/job/index.get.js +39 -0
  119. package/dist/runtime/server/api/_queues/index.get.d.ts +2 -0
  120. package/dist/runtime/server/api/_queues/index.get.js +106 -0
  121. package/dist/runtime/server/api/_queues/ws.d.ts +48 -0
  122. package/dist/runtime/server/api/_queues/ws.js +215 -0
  123. package/dist/runtime/server/api/_scheduler/jobs.get.d.ts +19 -0
  124. package/dist/runtime/server/api/_scheduler/jobs.get.js +36 -0
  125. package/dist/runtime/server/api/_triggers/[name]/events.get.d.ts +6 -0
  126. package/dist/runtime/server/api/_triggers/[name]/events.get.js +43 -0
  127. package/dist/runtime/server/api/_triggers/[name]/index.get.d.ts +6 -0
  128. package/dist/runtime/server/api/_triggers/[name]/index.get.js +76 -0
  129. package/dist/runtime/server/api/_triggers/[name].delete.d.ts +7 -0
  130. package/dist/runtime/server/api/_triggers/[name].delete.js +37 -0
  131. package/dist/runtime/server/api/_triggers/[name].patch.d.ts +7 -0
  132. package/dist/runtime/server/api/_triggers/[name].patch.js +117 -0
  133. package/dist/runtime/server/api/_triggers/index.get.d.ts +6 -0
  134. package/dist/runtime/server/api/_triggers/index.get.js +44 -0
  135. package/dist/runtime/server/api/_triggers/index.post.d.ts +7 -0
  136. package/dist/runtime/server/api/_triggers/index.post.js +124 -0
  137. package/dist/runtime/server/api/_triggers/stats.get.d.ts +6 -0
  138. package/dist/runtime/server/api/_triggers/stats.get.js +41 -0
  139. package/dist/runtime/server/api/_triggers/ws.d.ts +74 -0
  140. package/dist/runtime/server/api/_triggers/ws.js +315 -0
  141. package/dist/runtime/server/tsconfig.json +7 -0
  142. package/package.json +8 -8
  143. package/dist/runtime/app/components/FlowScheduleDialog.vue +0 -226
  144. package/dist/runtime/app/components/FlowSchedulesList.vue +0 -99
  145. package/dist/runtime/app/components/FlowStepSelector.vue +0 -238
  146. package/dist/runtime/app/components/QueueConfigDetails.vue +0 -412
  147. package/dist/runtime/app/components/nhealth/component-shell.vue +0 -89
  148. /package/dist/runtime/app/components/{nhealth/component-router.vue → ComponentRouter.vue} +0 -0
  149. /package/dist/runtime/app/components/{FlowNodeCard.d.vue.ts → flow/NodeCard.d.vue.ts} +0 -0
  150. /package/dist/runtime/app/components/{FlowNodeCard.vue → flow/NodeCard.vue} +0 -0
  151. /package/dist/runtime/app/components/{FlowNodeCard.vue.d.ts → flow/NodeCard.vue.d.ts} +0 -0
  152. /package/dist/runtime/app/components/{FlowRunTimeline.d.vue.ts → flow/RunTimeline.d.vue.ts} +0 -0
  153. /package/dist/runtime/app/components/{FlowRunTimeline.vue.d.ts → flow/RunTimeline.vue.d.ts} +0 -0
@@ -1,34 +1,64 @@
1
1
  <template>
2
- <QueueNhealthComponentRouter
2
+ <NventComponentRouter
3
3
  v-slot="{ component }"
4
4
  :routes="routes"
5
5
  base="p"
6
6
  mode="query"
7
7
  >
8
- <QueueNhealthComponentShell
8
+ <NventComponentShell
9
9
  orientation="horizontal"
10
10
  :items="navItems"
11
11
  >
12
12
  <component :is="component" />
13
- </QueueNhealthComponentShell>
14
- </QueueNhealthComponentRouter>
13
+ </NventComponentShell>
14
+ </NventComponentRouter>
15
15
  </template>
16
16
 
17
17
  <script setup>
18
+ import Dashboard from "./dashboard.vue";
18
19
  import Queue from "./queues/index.vue";
19
20
  import QueueJobs from "./queues/jobs.vue";
20
21
  import QueueJob from "./queues/job.vue";
21
- import QueueFlows from "./flows/index.vue";
22
+ import Flows from "./flows/index.vue";
23
+ import FlowDetail from "./flows/[name].vue";
24
+ import Triggers from "./triggers/index.vue";
25
+ import TriggerDetail from "./triggers/[name].vue";
26
+ import TriggerNew from "./triggers/new.vue";
27
+ import TriggerEdit from "./triggers/[name]/edit.vue";
28
+ import SettingsScheduler from "./settings/scheduler.vue";
22
29
  const navItems = [
23
30
  [
24
- { label: "Queues", icon: "i-lucide-app-window", path: "/" },
25
- { label: "Flows", icon: "i-lucide-git-branch", path: "/flows" }
31
+ { label: "Dashboard", icon: "i-lucide-layout-dashboard", path: "/" },
32
+ { label: "Queues", icon: "i-lucide-app-window", path: "/queues" },
33
+ { label: "Flows", icon: "i-lucide-git-branch", path: "/flows" },
34
+ { label: "Triggers", icon: "i-lucide-zap", path: "/triggers" }
35
+ ],
36
+ [
37
+ {
38
+ label: "Settings",
39
+ icon: "i-lucide-settings",
40
+ children: [
41
+ {
42
+ label: "Scheduler",
43
+ description: "Monitor scheduled jobs and their execution",
44
+ icon: "i-lucide-clock",
45
+ path: "/settings/scheduler"
46
+ }
47
+ ]
48
+ }
26
49
  ]
27
50
  ];
28
51
  const routes = {
29
- "/": Queue,
52
+ "/": Dashboard,
53
+ "/queues": Queue,
30
54
  "/queues/:name/jobs": QueueJobs,
31
55
  "/queues/:name/jobs/:id": QueueJob,
32
- "/flows": QueueFlows
56
+ "/flows": Flows,
57
+ "/flows/:name": FlowDetail,
58
+ "/triggers": Triggers,
59
+ "/triggers/new": TriggerNew,
60
+ "/triggers/:name/edit": TriggerEdit,
61
+ "/triggers/:name": TriggerDetail,
62
+ "/settings/scheduler": SettingsScheduler
33
63
  };
34
64
  </script>
@@ -7,223 +7,231 @@
7
7
  <h1 class="text-lg font-semibold">
8
8
  Queues
9
9
  </h1>
10
- <div
11
- v-if="isConnected"
12
- class="flex items-center gap-1.5 text-xs text-emerald-600 dark:text-emerald-400"
13
- >
14
- <div class="w-2 h-2 rounded-full bg-emerald-500 animate-pulse" />
15
- <span>Live</span>
16
- </div>
17
- <div
18
- v-else-if="isReconnecting"
19
- class="flex items-center gap-1.5 text-xs text-amber-600 dark:text-amber-400"
20
- >
21
- <div class="w-2 h-2 rounded-full bg-amber-500 animate-pulse" />
22
- <span>Reconnecting...</span>
23
- </div>
24
- </div>
25
- <div class="flex items-center gap-3">
26
- <ClientOnly>
27
- <UButton
28
- icon="i-lucide-refresh-cw"
29
- size="xs"
30
- color="neutral"
31
- variant="ghost"
32
- :loading="status === 'pending'"
33
- @click="refresh"
34
- >
35
- Refresh
36
- </UButton>
37
- </ClientOnly>
38
10
  </div>
11
+ <LiveIndicator
12
+ :is-connected="isConnected"
13
+ :is-reconnecting="isReconnecting"
14
+ />
39
15
  </div>
40
16
  </div>
41
17
 
42
18
  <!-- Main Content -->
43
- <div class="flex-1 min-h-0 overflow-hidden flex flex-col">
44
- <div
45
- v-if="!queuesWithLive || queuesWithLive.length === 0"
46
- class="flex-1 flex items-center justify-center text-sm text-gray-400"
47
- >
48
- No queues found
49
- </div>
50
- <template v-else>
51
- <div class="flex-1 min-h-0 p-4 overflow-auto">
52
- <UTable
53
- ref="table"
54
- v-model:pagination="pagination"
55
- :data="queuesWithLive"
56
- :columns="columns"
57
- :loading="status === 'pending'"
58
- :pagination-options="{
59
- getPaginationRowModel: getPaginationRowModel()
60
- }"
61
- :ui="{
62
- base: 'table-fixed border-separate border-spacing-0',
63
- thead: '[&>tr]:bg-elevated/50 [&>tr]:after:content-none',
64
- tbody: '[&>tr]:last:[&>td]:border-b-0',
65
- th: 'py-2 first:rounded-l-lg last:rounded-r-lg border-y border-default first:border-l last:border-r',
66
- td: 'border-b border-default',
67
- separator: 'h-0'
68
- }"
19
+ <div class="flex-1 min-h-0 overflow-y-auto">
20
+ <div class="max-w-7xl mx-auto p-6">
21
+ <!-- Stats Overview -->
22
+ <div class="grid grid-cols-2 md:grid-cols-5 gap-4 mb-6">
23
+ <StatCard
24
+ icon="i-lucide-inbox"
25
+ :count="queuesWithLive?.length || 0"
26
+ label="Total Queues"
27
+ variant="gray"
28
+ />
29
+ <StatCard
30
+ icon="i-lucide-clock"
31
+ :count="totalWaiting"
32
+ label="Waiting"
33
+ variant="blue"
34
+ />
35
+ <StatCard
36
+ icon="i-lucide-loader-2"
37
+ :count="totalActive"
38
+ label="Active"
39
+ variant="amber"
40
+ />
41
+ <StatCard
42
+ icon="i-lucide-check-circle"
43
+ :count="totalCompleted"
44
+ label="Completed"
45
+ variant="emerald"
46
+ />
47
+ <StatCard
48
+ icon="i-lucide-x-circle"
49
+ :count="totalFailed"
50
+ label="Failed"
51
+ variant="red"
69
52
  />
70
53
  </div>
71
54
 
72
- <div class="flex items-center justify-between gap-3 border-t border-default p-4 mt-4 shrink-0">
73
- <div class="text-sm text-muted">
74
- {{ queuesWithLive.length }} queue{{ queuesWithLive.length === 1 ? "" : "s" }}
55
+ <!-- Queues List -->
56
+ <div
57
+ v-if="!queuesWithLive || queuesWithLive.length === 0"
58
+ class="bg-white dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-800 p-8 text-center text-gray-500"
59
+ >
60
+ <UIcon
61
+ name="i-lucide-inbox"
62
+ class="w-12 h-12 mx-auto mb-3 opacity-50"
63
+ />
64
+ <div>No queues found</div>
65
+ </div>
66
+ <div
67
+ v-else
68
+ class="bg-white dark:bg-gray-900 rounded-lg border border-gray-200 dark:border-gray-800 overflow-hidden"
69
+ >
70
+ <div class="divide-y divide-gray-100 dark:divide-gray-800">
71
+ <div
72
+ v-for="queue in paginatedQueues"
73
+ :key="queue.name"
74
+ class="px-6 py-4 hover:bg-gray-50 dark:hover:bg-gray-900/50 transition-colors cursor-pointer"
75
+ @click="selectQueue(queue.name)"
76
+ >
77
+ <div class="flex items-start justify-between gap-4">
78
+ <!-- Left: Queue Info -->
79
+ <div class="flex-1 min-w-0">
80
+ <div class="flex items-center gap-2 mb-2">
81
+ <UIcon
82
+ name="i-lucide-inbox"
83
+ class="w-4 h-4 shrink-0 text-blue-500"
84
+ />
85
+ <h3 class="text-sm font-semibold text-gray-900 dark:text-gray-100 truncate">
86
+ {{ queue.name }}
87
+ </h3>
88
+ <UBadge
89
+ :label="queue.isPaused ? 'Paused' : 'Running'"
90
+ :color="queue.isPaused ? 'warning' : 'success'"
91
+ variant="subtle"
92
+ size="xs"
93
+ />
94
+ </div>
95
+
96
+ <div class="flex items-center gap-4 text-xs">
97
+ <div
98
+ class="flex items-center gap-1"
99
+ :class="queue.counts.waiting > 0 ? 'text-blue-600 dark:text-blue-400' : 'text-gray-400 dark:text-gray-600'"
100
+ >
101
+ <UIcon
102
+ name="i-lucide-clock"
103
+ class="w-3 h-3"
104
+ />
105
+ <span>{{ queue.counts.waiting }} waiting</span>
106
+ </div>
107
+ <div
108
+ class="flex items-center gap-1"
109
+ :class="queue.counts.active > 0 ? 'text-amber-600 dark:text-amber-400' : 'text-gray-400 dark:text-gray-600'"
110
+ >
111
+ <UIcon
112
+ name="i-lucide-loader-2"
113
+ class="w-3 h-3"
114
+ />
115
+ <span>{{ queue.counts.active }} active</span>
116
+ </div>
117
+ <div
118
+ class="flex items-center gap-1"
119
+ :class="queue.counts.completed > 0 ? 'text-emerald-600 dark:text-emerald-400' : 'text-gray-400 dark:text-gray-600'"
120
+ >
121
+ <UIcon
122
+ name="i-lucide-check-circle"
123
+ class="w-3 h-3"
124
+ />
125
+ <span>{{ queue.counts.completed }} completed</span>
126
+ </div>
127
+ <div
128
+ class="flex items-center gap-1"
129
+ :class="queue.counts.failed > 0 ? 'text-red-600 dark:text-red-400' : 'text-gray-400 dark:text-gray-600'"
130
+ >
131
+ <UIcon
132
+ name="i-lucide-x-circle"
133
+ class="w-3 h-3"
134
+ />
135
+ <span>{{ queue.counts.failed }} failed</span>
136
+ </div>
137
+ <div
138
+ class="flex items-center gap-1"
139
+ :class="queue.counts.delayed > 0 ? 'text-purple-600 dark:text-purple-400' : 'text-gray-400 dark:text-gray-600'"
140
+ >
141
+ <UIcon
142
+ name="i-lucide-timer"
143
+ class="w-3 h-3"
144
+ />
145
+ <span>{{ queue.counts.delayed }} delayed</span>
146
+ </div>
147
+ </div>
148
+ </div>
149
+
150
+ <!-- Right: Actions -->
151
+ <div class="flex items-center gap-3">
152
+ <!-- Arrow Button -->
153
+ <UButton
154
+ icon="i-lucide-arrow-right"
155
+ size="xs"
156
+ color="neutral"
157
+ variant="ghost"
158
+ square
159
+ />
160
+ </div>
161
+ </div>
162
+ </div>
75
163
  </div>
76
- <div class="flex items-center gap-1.5">
164
+
165
+ <!-- Pagination -->
166
+ <div
167
+ v-if="totalPages > 1"
168
+ class="border-t border-gray-200 dark:border-gray-800 px-6 py-4 flex items-center justify-center"
169
+ >
77
170
  <UPagination
78
- :default-page="(table?.tableApi?.getState().pagination.pageIndex || 0) + 1"
79
- :items-per-page="table?.tableApi?.getState().pagination.pageSize"
171
+ v-model="currentPage"
80
172
  :total="queuesWithLive.length"
81
- @update:page="(p) => table?.tableApi?.setPageIndex(p - 1)"
173
+ :items-per-page="itemsPerPage"
82
174
  />
83
175
  </div>
84
176
  </div>
85
- </template>
86
- </div>
87
177
 
88
- <!-- Config Details Slideover -->
89
- <QueueConfigDetails
90
- v-if="selectedQueueForConfig"
91
- v-model:open="configDetailsOpen"
92
- :queue-name="selectedQueueForConfig.name"
93
- :queue-config="selectedQueueForConfig.config?.queue"
94
- :worker-config="selectedQueueForConfig.config?.worker"
95
- />
178
+ <!-- Footer Info -->
179
+ <div
180
+ v-if="queuesWithLive && queuesWithLive.length > 0"
181
+ class="mt-4 text-center text-sm text-gray-500 dark:text-gray-400"
182
+ >
183
+ Showing {{ startIndex + 1 }}-{{ endIndex }} of {{ queuesWithLive.length }} queue{{ queuesWithLive.length === 1 ? "" : "s" }}
184
+ </div>
185
+ </div>
186
+ </div>
96
187
  </div>
97
188
  </template>
98
189
 
99
190
  <script setup>
100
- import { ref, useTemplateRef, h } from "#imports";
101
- import { getPaginationRowModel } from "@tanstack/table-core";
102
- import { UTable, UButton, UPagination } from "#components";
191
+ import { ref, computed } from "#imports";
192
+ import { UIcon, UPagination, UButton, UBadge } from "#components";
103
193
  import { useQueues } from "../../composables/useQueues";
104
194
  import { useQueuesLive } from "../../composables/useQueuesLive";
105
195
  import { useComponentRouter } from "../../composables/useComponentRouter";
106
- import QueueConfigDetails from "../../components/QueueConfigDetails.vue";
107
- const UBadgeComponent = resolveComponent("UBadge");
108
- const UButtonComponent = resolveComponent("UButton");
109
- const { queues, refresh, status } = useQueues();
196
+ import StatCard from "../../components/StatCard.vue";
197
+ import LiveIndicator from "../../components/LiveIndicator.vue";
198
+ const { queues } = useQueues();
110
199
  const { queues: queuesWithLive, isConnected, isReconnecting } = useQueuesLive(queues);
111
200
  const router = useComponentRouter();
112
- const table = useTemplateRef("table");
113
- const pagination = ref({
114
- pageIndex: 0,
115
- pageSize: 10
116
- });
117
- const configDetailsOpen = ref(false);
118
- const selectedQueueForConfig = ref(null);
119
- const openConfigDetails = (queue) => {
120
- selectedQueueForConfig.value = queue;
121
- configDetailsOpen.value = true;
201
+ const selectQueue = (queueName) => {
202
+ router.push(`/queues/${queueName}/jobs`);
122
203
  };
123
- const columns = [
124
- {
125
- accessorKey: "name",
126
- header: "Queue Name",
127
- cell: ({ row }) => {
128
- return h("div", {
129
- class: "font-medium text-highlighted cursor-pointer hover:underline",
130
- onClick: () => router.push(`/queues/${row.original.name}/jobs`)
131
- }, row.original.name);
132
- }
133
- },
134
- {
135
- accessorKey: "counts.waiting",
136
- header: "Waiting",
137
- cell: ({ row }) => {
138
- const count = row.original.counts.waiting;
139
- return h("div", {
140
- class: `flex items-center justify-center w-12 h-7 rounded text-sm font-medium ${count > 0 ? "bg-blue-50 dark:bg-blue-950/50 text-blue-600 dark:text-blue-400" : "bg-gray-50 dark:bg-gray-900/50 text-gray-400 dark:text-gray-600"}`
141
- }, String(count));
142
- }
143
- },
144
- {
145
- accessorKey: "counts.active",
146
- header: "Active",
147
- cell: ({ row }) => {
148
- const count = row.original.counts.active;
149
- return h("div", {
150
- class: `flex items-center justify-center w-12 h-7 rounded text-sm font-medium ${count > 0 ? "bg-amber-50 dark:bg-amber-950/50 text-amber-600 dark:text-amber-400" : "bg-gray-50 dark:bg-gray-900/50 text-gray-400 dark:text-gray-600"}`
151
- }, String(count));
152
- }
153
- },
154
- {
155
- accessorKey: "counts.completed",
156
- header: "Completed",
157
- cell: ({ row }) => {
158
- const count = row.original.counts.completed;
159
- return h("div", {
160
- class: `flex items-center justify-center w-12 h-7 rounded text-sm font-medium ${count > 0 ? "bg-emerald-50 dark:bg-emerald-950/50 text-emerald-600 dark:text-emerald-400" : "bg-gray-50 dark:bg-gray-900/50 text-gray-400 dark:text-gray-600"}`
161
- }, String(count));
162
- }
163
- },
164
- {
165
- accessorKey: "counts.failed",
166
- header: "Failed",
167
- cell: ({ row }) => {
168
- const count = row.original.counts.failed;
169
- return h("div", {
170
- class: `flex items-center justify-center w-12 h-7 rounded text-sm font-medium ${count > 0 ? "bg-red-50 dark:bg-red-950/50 text-red-600 dark:text-red-400" : "bg-gray-50 dark:bg-gray-900/50 text-gray-400 dark:text-gray-600"}`
171
- }, String(count));
172
- }
173
- },
174
- {
175
- accessorKey: "counts.delayed",
176
- header: "Delayed",
177
- cell: ({ row }) => {
178
- const count = row.original.counts.delayed;
179
- return h("div", {
180
- class: `flex items-center justify-center w-12 h-7 rounded text-sm font-medium ${count > 0 ? "bg-purple-50 dark:bg-purple-950/50 text-purple-600 dark:text-purple-400" : "bg-gray-50 dark:bg-gray-900/50 text-gray-400 dark:text-gray-600"}`
181
- }, String(count));
182
- }
183
- },
184
- {
185
- accessorKey: "isPaused",
186
- header: "Status",
187
- cell: ({ row }) => {
188
- return h(UBadgeComponent, {
189
- label: row.original.isPaused ? "Paused" : "Running",
190
- color: row.original.isPaused ? "warning" : "success",
191
- variant: "subtle"
192
- });
193
- }
194
- },
195
- {
196
- id: "config",
197
- header: "Config",
198
- cell: ({ row }) => {
199
- return h(UButtonComponent, {
200
- icon: "i-lucide-settings",
201
- size: "xs",
202
- color: "neutral",
203
- variant: "ghost",
204
- square: true,
205
- title: "View configuration",
206
- onClick: () => {
207
- openConfigDetails(row.original);
208
- }
209
- });
210
- }
211
- },
212
- {
213
- id: "actions",
214
- header: "",
215
- cell: ({ row }) => {
216
- return h(UButtonComponent, {
217
- icon: "i-lucide-arrow-right",
218
- size: "xs",
219
- color: "neutral",
220
- variant: "ghost",
221
- square: true,
222
- onClick: () => {
223
- router.push(`/queues/${row.original.name}/jobs`);
224
- }
225
- });
226
- }
227
- }
228
- ];
204
+ const currentPage = ref(1);
205
+ const itemsPerPage = 10;
206
+ const totalPages = computed(() => {
207
+ if (!queuesWithLive.value) return 0;
208
+ return Math.ceil(queuesWithLive.value.length / itemsPerPage);
209
+ });
210
+ const startIndex = computed(() => {
211
+ return (currentPage.value - 1) * itemsPerPage;
212
+ });
213
+ const endIndex = computed(() => {
214
+ if (!queuesWithLive.value) return 0;
215
+ return Math.min(startIndex.value + itemsPerPage, queuesWithLive.value.length);
216
+ });
217
+ const paginatedQueues = computed(() => {
218
+ if (!queuesWithLive.value) return [];
219
+ return queuesWithLive.value.slice(startIndex.value, endIndex.value);
220
+ });
221
+ const totalWaiting = computed(() => {
222
+ if (!queuesWithLive.value) return 0;
223
+ return queuesWithLive.value.reduce((sum, q) => sum + q.counts.waiting, 0);
224
+ });
225
+ const totalActive = computed(() => {
226
+ if (!queuesWithLive.value) return 0;
227
+ return queuesWithLive.value.reduce((sum, q) => sum + q.counts.active, 0);
228
+ });
229
+ const totalCompleted = computed(() => {
230
+ if (!queuesWithLive.value) return 0;
231
+ return queuesWithLive.value.reduce((sum, q) => sum + q.counts.completed, 0);
232
+ });
233
+ const totalFailed = computed(() => {
234
+ if (!queuesWithLive.value) return 0;
235
+ return queuesWithLive.value.reduce((sum, q) => sum + q.counts.failed, 0);
236
+ });
229
237
  </script>