queen-mq 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/API.md +862 -752
  2. package/AUTH.md +2044 -0
  3. package/LICENSE.md +202 -0
  4. package/README.md +1705 -1051
  5. package/WEBAPP.md +1889 -0
  6. package/assets/dashboard-01.png +0 -0
  7. package/assets/queen-logo-blue.svg +210 -0
  8. package/assets/queen-logo-cyan.svg +210 -0
  9. package/assets/queen-logo-indigo.svg +210 -0
  10. package/assets/queen-logo-orange.svg +210 -0
  11. package/assets/queen-logo-pink.svg +210 -0
  12. package/assets/queen-logo-purple.svg +210 -0
  13. package/assets/queen-logo-rose.svg +239 -0
  14. package/assets/queen-logo.svg +263 -0
  15. package/examples/batch-processing.js +58 -0
  16. package/examples/test-complete-client.js +260 -0
  17. package/examples/test-dashboard-api.js +200 -0
  18. package/examples/test-traceid.js +147 -0
  19. package/package.json +17 -4
  20. package/server.log +1 -0
  21. package/src/benchmark/consumer.js +207 -0
  22. package/src/benchmark/consumer_multi.js +216 -0
  23. package/src/benchmark/producer.js +75 -0
  24. package/src/benchmark/producer_multi.js +115 -0
  25. package/src/client/client.js +300 -31
  26. package/src/client/queenClient.js +5 -0
  27. package/src/cluster-server.js +242 -0
  28. package/src/config.js +19 -5
  29. package/src/database/connection.js +42 -16
  30. package/src/database/poolManager.js +7 -0
  31. package/src/database/schema-v2.sql +194 -130
  32. package/src/managers/queueManagerOptimized.js +823 -933
  33. package/src/managers/systemEventManager.js +8 -3
  34. package/src/routes/messages.js +127 -57
  35. package/src/routes/pop.js +27 -43
  36. package/src/routes/resources.js +61 -27
  37. package/src/routes/status.js +1037 -0
  38. package/src/server.js +308 -272
  39. package/src/services/evictionService.js +57 -28
  40. package/src/services/retentionService.js +44 -11
  41. package/src/test/MIGRATION_ISSUES.md +174 -0
  42. package/src/test/README.md +203 -0
  43. package/src/test/advanced-pattern-tests.js +1137 -0
  44. package/src/test/bus-mode-tests.js +361 -0
  45. package/src/test/core-tests.js +342 -0
  46. package/src/test/edge-case-tests.js +561 -0
  47. package/src/test/enterprise-tests.js +637 -0
  48. package/src/test/partition-locking-tests.js +545 -0
  49. package/src/test/test-new.js +278 -0
  50. package/src/test/test.js +6 -3
  51. package/src/test/utils.js +169 -0
  52. package/src/utils/streaming.js +231 -0
  53. package/src/utils/uuid.js +2 -2
  54. package/src/websocket/wsServer.js +10 -3
  55. package/test-keepalive-v2.sh +22 -0
  56. package/webapp/COLOR_GUIDE.md +118 -0
  57. package/webapp/README.md +143 -0
  58. package/webapp/index.html +14 -0
  59. package/webapp/package-lock.json +3184 -0
  60. package/webapp/package.json +25 -0
  61. package/webapp/postcss.config.js +7 -0
  62. package/webapp/public/assets/queen-logo-blue.svg +210 -0
  63. package/webapp/public/assets/queen-logo-cyan.svg +210 -0
  64. package/webapp/public/assets/queen-logo-indigo.svg +210 -0
  65. package/webapp/public/assets/queen-logo-orange.svg +210 -0
  66. package/webapp/public/assets/queen-logo-pink.svg +210 -0
  67. package/webapp/public/assets/queen-logo-purple.svg +210 -0
  68. package/webapp/public/assets/queen-logo-rose.svg +239 -0
  69. package/webapp/public/assets/queen-logo.svg +263 -0
  70. package/webapp/src/App.vue +19 -0
  71. package/webapp/src/api/analytics.js +10 -0
  72. package/webapp/src/api/client.js +29 -0
  73. package/webapp/src/api/consumers.js +52 -0
  74. package/webapp/src/api/health.js +7 -0
  75. package/webapp/src/api/messages.js +26 -0
  76. package/webapp/src/api/queues.js +14 -0
  77. package/webapp/src/api/resources.js +8 -0
  78. package/webapp/src/assets/styles/main.css +357 -0
  79. package/webapp/src/components/analytics/AnalyticsFilters.vue +87 -0
  80. package/webapp/src/components/analytics/AnalyticsMetrics.vue +57 -0
  81. package/webapp/src/components/analytics/MessageDistributionChart.vue +111 -0
  82. package/webapp/src/components/analytics/MessageFlowChart.vue +173 -0
  83. package/webapp/src/components/analytics/TimeRangeSelector.vue +27 -0
  84. package/webapp/src/components/analytics/TopQueuesChart.vue +132 -0
  85. package/webapp/src/components/common/ConfirmDialog.vue +56 -0
  86. package/webapp/src/components/common/LoadingSpinner.vue +6 -0
  87. package/webapp/src/components/common/MetricCard.vue +43 -0
  88. package/webapp/src/components/common/StatusBadge.vue +45 -0
  89. package/webapp/src/components/dashboard/MessageStatusCard.vue +50 -0
  90. package/webapp/src/components/dashboard/PerformanceCard.vue +38 -0
  91. package/webapp/src/components/dashboard/ThroughputChart.vue +182 -0
  92. package/webapp/src/components/dashboard/TopQueuesTable.vue +53 -0
  93. package/webapp/src/components/layout/AppLayout.vue +110 -0
  94. package/webapp/src/components/layout/AppSidebar.vue +304 -0
  95. package/webapp/src/components/messages/MessageDetailPanel.vue +242 -0
  96. package/webapp/src/components/messages/MessageFilters.vue +114 -0
  97. package/webapp/src/components/queue-detail/PartitionList.vue +79 -0
  98. package/webapp/src/components/queue-detail/PushMessageModal.vue +175 -0
  99. package/webapp/src/components/queue-detail/QueueConfig.vue +63 -0
  100. package/webapp/src/components/queue-detail/QueueDetailHeader.vue +53 -0
  101. package/webapp/src/components/queue-detail/RecentMessages.vue +76 -0
  102. package/webapp/src/components/queues/CreateQueueModal.vue +193 -0
  103. package/webapp/src/components/queues/QueueFilters.vue +90 -0
  104. package/webapp/src/composables/useApi.js +34 -0
  105. package/webapp/src/composables/useTheme.js +36 -0
  106. package/webapp/src/main.js +11 -0
  107. package/webapp/src/router/index.js +42 -0
  108. package/webapp/src/utils/colors.js +96 -0
  109. package/webapp/src/utils/formatters.js +49 -0
  110. package/webapp/src/views/Analytics.vue +377 -0
  111. package/webapp/src/views/ConsumerGroups.vue +433 -0
  112. package/webapp/src/views/Dashboard.vue +418 -0
  113. package/webapp/src/views/Messages.vue +361 -0
  114. package/webapp/src/views/QueueDetail.vue +582 -0
  115. package/webapp/src/views/Queues.vue +496 -0
  116. package/webapp/tailwind.config.js +25 -0
  117. package/webapp/vite.config.js +10 -0
  118. package/CACHE.md +0 -519
  119. package/DASHBOARD-V3.md +0 -478
  120. package/DASHBOARD.md +0 -382
  121. package/MOD_QUEUE.md +0 -453
  122. package/PARTITION_LOCKING_DESIGN.md +0 -989
  123. package/PLAN.md +0 -707
  124. package/QUERY_ANALSYS.md +0 -72
  125. package/QUEUE_BUS.md +0 -334
  126. package/V2-PLAN.md +0 -236
  127. package/dashboard/.vscode/extensions.json +0 -3
  128. package/dashboard/README.md +0 -5
  129. package/dashboard/index.html +0 -14
  130. package/dashboard/package-lock.json +0 -1458
  131. package/dashboard/package.json +0 -25
  132. package/dashboard/public/vite.svg +0 -1
  133. package/dashboard/src/App.vue +0 -29
  134. package/dashboard/src/assets/styles/main.css +0 -908
  135. package/dashboard/src/assets/vue.svg +0 -1
  136. package/dashboard/src/components/cards/MetricCard.vue +0 -298
  137. package/dashboard/src/components/charts/QueueDepthChart.vue +0 -276
  138. package/dashboard/src/components/charts/QueueLagChart.vue +0 -436
  139. package/dashboard/src/components/charts/ThroughputChart.vue +0 -302
  140. package/dashboard/src/components/common/ActivityFeed.vue +0 -251
  141. package/dashboard/src/components/layout/AppHeader.vue +0 -208
  142. package/dashboard/src/components/layout/AppLayout.vue +0 -88
  143. package/dashboard/src/components/layout/AppSidebar.vue +0 -261
  144. package/dashboard/src/main.js +0 -44
  145. package/dashboard/src/router.js +0 -54
  146. package/dashboard/src/services/api.js +0 -187
  147. package/dashboard/src/services/websocket.js +0 -167
  148. package/dashboard/src/utils/constants.js +0 -56
  149. package/dashboard/src/utils/helpers.js +0 -118
  150. package/dashboard/src/views/Analytics.vue +0 -912
  151. package/dashboard/src/views/Dashboard.vue +0 -906
  152. package/dashboard/src/views/Messages.vue +0 -437
  153. package/dashboard/src/views/QueueDetail.vue +0 -501
  154. package/dashboard/src/views/Queues.vue +0 -333
  155. package/dashboard/vite.config.js +0 -30
  156. package/debug-namespace.js +0 -110
  157. package/docs/long-polling.md +0 -159
  158. package/docs/multi-server-cache-solutions.md +0 -185
  159. package/docs/performance-tuning.md +0 -222
  160. package/src/routes/analytics.js +0 -812
@@ -0,0 +1,173 @@
1
+ <template>
2
+ <div class="chart-container">
3
+ <Bar v-if="chartData" :data="chartData" :options="chartOptions" />
4
+ <div v-else class="flex items-center justify-center h-full text-gray-500 text-sm">
5
+ No data available for this time range
6
+ </div>
7
+ </div>
8
+ </template>
9
+
10
+ <script setup>
11
+ import { computed } from 'vue';
12
+ import { Bar } from 'vue-chartjs';
13
+ import {
14
+ Chart as ChartJS,
15
+ CategoryScale,
16
+ LinearScale,
17
+ BarElement,
18
+ Title,
19
+ Tooltip,
20
+ Legend,
21
+ } from 'chart.js';
22
+ import { colors } from '../../utils/colors';
23
+
24
+ ChartJS.register(
25
+ CategoryScale,
26
+ LinearScale,
27
+ BarElement,
28
+ Title,
29
+ Tooltip,
30
+ Legend
31
+ );
32
+
33
+ const props = defineProps({
34
+ data: Object,
35
+ });
36
+
37
+ const chartData = computed(() => {
38
+ if (!props.data?.throughput?.length) return null;
39
+
40
+ const throughput = [...props.data.throughput].reverse();
41
+
42
+ return {
43
+ labels: throughput.map(t => {
44
+ const date = new Date(t.timestamp);
45
+ return date.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' });
46
+ }),
47
+ datasets: [
48
+ {
49
+ label: 'Ingested',
50
+ data: throughput.map(t => t.ingested || t.ingestedPerSecond || 0),
51
+ backgroundColor: createGradientBars('rose'),
52
+ borderColor: 'transparent',
53
+ borderWidth: 0,
54
+ borderRadius: 4,
55
+ barPercentage: 0.9,
56
+ categoryPercentage: 0.95,
57
+ },
58
+ {
59
+ label: 'Processed',
60
+ data: throughput.map(t => t.processed || t.processedPerSecond || 0),
61
+ backgroundColor: createGradientBars('purple'),
62
+ borderColor: 'transparent',
63
+ borderWidth: 0,
64
+ borderRadius: 4,
65
+ barPercentage: 0.9,
66
+ categoryPercentage: 0.95,
67
+ },
68
+ ],
69
+ };
70
+ });
71
+
72
+ function createGradientBars(color) {
73
+ return (context) => {
74
+ const chart = context.chart;
75
+ const {ctx, chartArea} = chart;
76
+
77
+ if (!chartArea) {
78
+ return color === 'rose' ? colors.charts.ingested.border : colors.charts.processed.border;
79
+ }
80
+
81
+ const gradient = ctx.createLinearGradient(0, chartArea.top, 0, chartArea.bottom);
82
+
83
+ if (color === 'rose') {
84
+ gradient.addColorStop(0, 'rgba(244, 63, 94, 0.9)');
85
+ gradient.addColorStop(1, 'rgba(244, 63, 94, 0.5)');
86
+ } else if (color === 'purple') {
87
+ gradient.addColorStop(0, 'rgba(168, 85, 247, 0.9)');
88
+ gradient.addColorStop(1, 'rgba(168, 85, 247, 0.5)');
89
+ }
90
+
91
+ return gradient;
92
+ };
93
+ }
94
+
95
+ const chartOptions = {
96
+ responsive: true,
97
+ maintainAspectRatio: false,
98
+ interaction: {
99
+ mode: 'index',
100
+ intersect: false,
101
+ },
102
+ scales: {
103
+ x: {
104
+ stacked: false,
105
+ grid: {
106
+ display: false,
107
+ },
108
+ border: {
109
+ display: false,
110
+ },
111
+ ticks: {
112
+ maxRotation: 0,
113
+ autoSkipPadding: 20,
114
+ font: {
115
+ size: 10,
116
+ },
117
+ color: '#9ca3af',
118
+ },
119
+ },
120
+ y: {
121
+ stacked: false,
122
+ beginAtZero: true,
123
+ border: {
124
+ display: false,
125
+ },
126
+ grid: {
127
+ display: false,
128
+ },
129
+ ticks: {
130
+ font: {
131
+ size: 11,
132
+ },
133
+ color: '#9ca3af',
134
+ padding: 8,
135
+ },
136
+ },
137
+ },
138
+ plugins: {
139
+ legend: {
140
+ display: true,
141
+ position: 'top',
142
+ align: 'end',
143
+ labels: {
144
+ boxWidth: 12,
145
+ boxHeight: 12,
146
+ padding: 15,
147
+ usePointStyle: true,
148
+ pointStyle: 'circle',
149
+ font: {
150
+ size: 12,
151
+ weight: '500',
152
+ },
153
+ color: '#6b7280',
154
+ },
155
+ },
156
+ tooltip: {
157
+ enabled: true,
158
+ backgroundColor: 'rgba(0, 0, 0, 0.9)',
159
+ padding: 12,
160
+ cornerRadius: 8,
161
+ titleFont: {
162
+ size: 13,
163
+ weight: '600',
164
+ },
165
+ bodyFont: {
166
+ size: 12,
167
+ },
168
+ bodySpacing: 6,
169
+ usePointStyle: true,
170
+ },
171
+ },
172
+ };
173
+ </script>
@@ -0,0 +1,27 @@
1
+ <template>
2
+ <div class="flex items-center gap-3">
3
+ <label class="text-sm font-medium text-gray-700 dark:text-gray-300">Time Range:</label>
4
+ <select
5
+ :value="modelValue"
6
+ @change="$emit('update:modelValue', $event.target.value)"
7
+ class="input w-40"
8
+ >
9
+ <option value="1h">Last Hour</option>
10
+ <option value="6h">Last 6 Hours</option>
11
+ <option value="24h">Last 24 Hours</option>
12
+ <option value="7d">Last 7 Days</option>
13
+ </select>
14
+ </div>
15
+ </template>
16
+
17
+ <script setup>
18
+ defineProps({
19
+ modelValue: {
20
+ type: String,
21
+ default: '1h',
22
+ },
23
+ });
24
+
25
+ defineEmits(['update:modelValue']);
26
+ </script>
27
+
@@ -0,0 +1,132 @@
1
+ <template>
2
+ <div class="h-80">
3
+ <Bar v-if="chartData" :data="chartData" :options="chartOptions" />
4
+ <div v-else class="flex items-center justify-center h-full text-gray-500 text-sm">
5
+ No queue data available
6
+ </div>
7
+ </div>
8
+ </template>
9
+
10
+ <script setup>
11
+ import { computed } from 'vue';
12
+ import { Bar } from 'vue-chartjs';
13
+ import {
14
+ Chart as ChartJS,
15
+ CategoryScale,
16
+ LinearScale,
17
+ BarElement,
18
+ Title,
19
+ Tooltip,
20
+ Legend,
21
+ } from 'chart.js';
22
+ import { colors } from '../../utils/colors';
23
+
24
+ ChartJS.register(
25
+ CategoryScale,
26
+ LinearScale,
27
+ BarElement,
28
+ Title,
29
+ Tooltip,
30
+ Legend
31
+ );
32
+
33
+ const props = defineProps({
34
+ queues: Array,
35
+ });
36
+
37
+ const chartData = computed(() => {
38
+ if (!props.queues?.length) return null;
39
+
40
+ // Take top 10 queues by total messages
41
+ const topQueues = [...props.queues]
42
+ .sort((a, b) => (b.messages?.total || 0) - (a.messages?.total || 0))
43
+ .slice(0, 10);
44
+
45
+ return {
46
+ labels: topQueues.map(q => q.name),
47
+ datasets: [
48
+ {
49
+ label: 'Total Messages',
50
+ data: topQueues.map(q => q.messages?.total || 0),
51
+ backgroundColor: createGradientBars(),
52
+ borderColor: 'transparent',
53
+ borderWidth: 0,
54
+ borderRadius: 8,
55
+ barThickness: 24,
56
+ },
57
+ ],
58
+ };
59
+ });
60
+
61
+ // Create gradient for bars
62
+ function createGradientBars() {
63
+ return (context) => {
64
+ const chart = context.chart;
65
+ const {ctx, chartArea} = chart;
66
+
67
+ if (!chartArea) {
68
+ return colors.secondary.rgba(0.8);
69
+ }
70
+
71
+ const gradient = ctx.createLinearGradient(chartArea.left, 0, chartArea.right, 0);
72
+ gradient.addColorStop(0, 'rgba(244, 63, 94, 0.8)');
73
+ gradient.addColorStop(0.5, 'rgba(236, 72, 153, 0.8)');
74
+ gradient.addColorStop(1, 'rgba(168, 85, 247, 0.8)');
75
+
76
+ return gradient;
77
+ };
78
+ }
79
+
80
+ const chartOptions = {
81
+ responsive: true,
82
+ maintainAspectRatio: false,
83
+ indexAxis: 'y',
84
+ scales: {
85
+ x: {
86
+ beginAtZero: true,
87
+ grid: {
88
+ display: false,
89
+ },
90
+ border: {
91
+ display: false,
92
+ },
93
+ ticks: {
94
+ font: {
95
+ size: 11,
96
+ },
97
+ color: '#9ca3af',
98
+ },
99
+ },
100
+ y: {
101
+ grid: {
102
+ display: false,
103
+ },
104
+ border: {
105
+ display: false,
106
+ },
107
+ ticks: {
108
+ font: {
109
+ size: 11,
110
+ },
111
+ color: '#6b7280',
112
+ },
113
+ },
114
+ },
115
+ plugins: {
116
+ legend: {
117
+ display: false,
118
+ },
119
+ tooltip: {
120
+ backgroundColor: 'rgba(0, 0, 0, 0.9)',
121
+ padding: 12,
122
+ cornerRadius: 8,
123
+ titleFont: {
124
+ size: 13,
125
+ },
126
+ bodyFont: {
127
+ size: 12,
128
+ },
129
+ },
130
+ },
131
+ };
132
+ </script>
@@ -0,0 +1,56 @@
1
+ <template>
2
+ <div v-if="isOpen" class="fixed inset-0 z-50 overflow-y-auto">
3
+ <div class="flex items-center justify-center min-h-screen px-4">
4
+ <!-- Backdrop with blur -->
5
+ <div
6
+ class="fixed inset-0 bg-black bg-opacity-50 backdrop-blur-sm transition-opacity animate-fade-in"
7
+ @click="$emit('cancel')"
8
+ ></div>
9
+
10
+ <!-- Modal -->
11
+ <div class="relative bg-white dark:bg-slate-800 rounded-xl shadow-2xl max-w-md w-full p-6 animate-scale-in border border-gray-200 dark:border-gray-700">
12
+ <div class="mb-4">
13
+ <h3 class="text-lg font-bold mb-2">{{ title }}</h3>
14
+ <p class="text-sm text-gray-600 dark:text-gray-400">{{ message }}</p>
15
+ </div>
16
+
17
+ <div class="flex gap-3">
18
+ <button @click="$emit('cancel')" class="btn btn-secondary flex-1">
19
+ {{ cancelText }}
20
+ </button>
21
+ <button @click="$emit('confirm')" :class="`btn ${confirmClass} flex-1`">
22
+ {{ confirmText }}
23
+ </button>
24
+ </div>
25
+ </div>
26
+ </div>
27
+ </div>
28
+ </template>
29
+
30
+ <script setup>
31
+ defineProps({
32
+ isOpen: Boolean,
33
+ title: {
34
+ type: String,
35
+ default: 'Confirm Action',
36
+ },
37
+ message: {
38
+ type: String,
39
+ default: 'Are you sure you want to proceed?',
40
+ },
41
+ confirmText: {
42
+ type: String,
43
+ default: 'Confirm',
44
+ },
45
+ cancelText: {
46
+ type: String,
47
+ default: 'Cancel',
48
+ },
49
+ confirmClass: {
50
+ type: String,
51
+ default: 'btn-primary',
52
+ },
53
+ });
54
+
55
+ defineEmits(['confirm', 'cancel']);
56
+ </script>
@@ -0,0 +1,6 @@
1
+ <template>
2
+ <div class="flex items-center justify-center p-8">
3
+ <div class="animate-spin rounded-full h-12 w-12 border-b-2 border-rose-600"></div>
4
+ </div>
5
+ </template>
6
+
@@ -0,0 +1,43 @@
1
+ <template>
2
+ <div class="metric-card animate-fade-in">
3
+ <p class="metric-label">{{ title }}</p>
4
+ <p class="metric-value">{{ formattedValue }}</p>
5
+ <p v-if="subtitle || (secondaryValue !== undefined && secondaryValue !== null)" class="text-xs text-gray-500 dark:text-gray-400 mt-1.5">
6
+ <span v-if="subtitle">{{ subtitle }}</span>
7
+ <span v-else>
8
+ {{ secondaryLabel }}: <span class="font-semibold">{{ formattedSecondary }}</span>
9
+ </span>
10
+ </p>
11
+ </div>
12
+ </template>
13
+
14
+ <script setup>
15
+ import { computed } from 'vue';
16
+ import { formatNumber } from '../../utils/formatters';
17
+
18
+ const props = defineProps({
19
+ title: String,
20
+ value: [String, Number],
21
+ subtitle: String,
22
+ secondaryValue: [String, Number],
23
+ secondaryLabel: String,
24
+ });
25
+
26
+ const formattedValue = computed(() => {
27
+ if (typeof props.value === 'number') {
28
+ return formatNumber(props.value);
29
+ }
30
+ return props.value;
31
+ });
32
+
33
+ const formattedSecondary = computed(() => {
34
+ if (props.secondaryValue !== undefined && props.secondaryValue !== null) {
35
+ if (typeof props.secondaryValue === 'number') {
36
+ return formatNumber(props.secondaryValue);
37
+ }
38
+ return props.secondaryValue;
39
+ }
40
+ return '';
41
+ });
42
+ </script>
43
+
@@ -0,0 +1,45 @@
1
+ <template>
2
+ <span :class="badgeClass" class="flex items-center badge-glow">
3
+ <span v-if="showDot" class="w-2 h-2 rounded-full mr-1.5" :class="dotClass"></span>
4
+ {{ label }}
5
+ </span>
6
+ </template>
7
+
8
+ <script setup>
9
+ import { computed } from 'vue';
10
+
11
+ const props = defineProps({
12
+ status: {
13
+ type: String,
14
+ required: true,
15
+ },
16
+ showDot: {
17
+ type: Boolean,
18
+ default: true,
19
+ },
20
+ });
21
+
22
+ const statusConfig = {
23
+ healthy: { class: 'badge-success', dot: 'bg-green-500', label: 'Healthy' },
24
+ stable: { class: 'badge-success', dot: 'bg-green-500', label: 'Stable' },
25
+ warning: { class: 'badge-warning', dot: 'bg-yellow-500', label: 'Warning' },
26
+ error: { class: 'badge-danger', dot: 'bg-red-500', label: 'Error' },
27
+ unhealthy: { class: 'badge-danger', dot: 'bg-red-500', label: 'Unhealthy' },
28
+ pending: { class: 'badge-warning', dot: 'bg-yellow-500', label: 'Pending' },
29
+ processing: { class: 'bg-purple-100 text-purple-800 dark:bg-purple-900/30 dark:text-purple-400', dot: 'bg-purple-500 animate-pulse', label: 'Processing' },
30
+ completed: { class: 'badge-success', dot: 'bg-green-500', label: 'Completed' },
31
+ failed: { class: 'badge-danger', dot: 'bg-red-500', label: 'Failed' },
32
+ dead_letter: { class: 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300', dot: 'bg-gray-500', label: 'Dead Letter' },
33
+ };
34
+
35
+ const config = computed(() => statusConfig[props.status.toLowerCase()] || statusConfig.pending);
36
+ const badgeClass = computed(() => `badge ${config.value.class}`);
37
+ const dotClass = computed(() => config.value.dot);
38
+ const label = computed(() => config.value.label);
39
+ </script>
40
+
41
+ <style scoped>
42
+ .badge-glow {
43
+ transition: all 0.2s ease;
44
+ }
45
+ </style>
@@ -0,0 +1,50 @@
1
+ <template>
2
+ <div>
3
+ <div class="space-y-2.5">
4
+ <div class="flex items-center justify-between text-sm">
5
+ <span class="text-gray-600 dark:text-gray-400">Pending</span>
6
+ <span class="font-semibold">{{ formatNumber(calculatedPending) }}</span>
7
+ </div>
8
+ <div class="flex items-center justify-between text-sm">
9
+ <span class="text-gray-600 dark:text-gray-400">Processing</span>
10
+ <span class="font-semibold">{{ formatNumber(data?.processing || 0) }}</span>
11
+ </div>
12
+ <div class="flex items-center justify-between text-sm">
13
+ <span class="text-gray-600 dark:text-gray-400">Completed</span>
14
+ <span class="font-semibold text-green-600 dark:text-green-400">
15
+ {{ formatNumber(data?.completed || 0) }}
16
+ </span>
17
+ </div>
18
+ <div class="flex items-center justify-between text-sm">
19
+ <span class="text-gray-600 dark:text-gray-400">Failed</span>
20
+ <span class="font-semibold text-red-600 dark:text-red-400">
21
+ {{ formatNumber(data?.failed || 0) }}
22
+ </span>
23
+ </div>
24
+ <div class="flex items-center justify-between text-sm">
25
+ <span class="text-gray-600 dark:text-gray-400">Dead Letter</span>
26
+ <span class="font-semibold text-gray-600 dark:text-gray-400">
27
+ {{ formatNumber(data?.deadLetter || 0) }}
28
+ </span>
29
+ </div>
30
+ <div class="flex items-center justify-between text-sm pt-2 border-t border-gray-200 dark:border-gray-700">
31
+ <span class="text-gray-600 dark:text-gray-400">Total in DB</span>
32
+ <span class="font-semibold text-gray-500 dark:text-gray-400">
33
+ {{ formatNumber(data?.total || 0) }}
34
+ </span>
35
+ </div>
36
+ </div>
37
+ </div>
38
+ </template>
39
+
40
+ <script setup>
41
+ import { formatNumber } from '../../utils/formatters';
42
+
43
+ defineProps({
44
+ data: Object,
45
+ calculatedPending: {
46
+ type: Number,
47
+ default: 0,
48
+ },
49
+ });
50
+ </script>
@@ -0,0 +1,38 @@
1
+ <template>
2
+ <div>
3
+ <div class="space-y-2.5">
4
+ <div class="flex items-center justify-between text-sm">
5
+ <span class="text-gray-600 dark:text-gray-400">Requests/sec</span>
6
+ <span class="font-semibold font-mono">{{ data?.requests?.rate?.toFixed(2) || '0.00' }}</span>
7
+ </div>
8
+ <div class="flex items-center justify-between text-sm">
9
+ <span class="text-gray-600 dark:text-gray-400">Messages/sec</span>
10
+ <span class="font-semibold font-mono">{{ data?.messages?.rate?.toFixed(2) || '0.00' }}</span>
11
+ </div>
12
+ <div class="flex items-center justify-between text-sm">
13
+ <span class="text-gray-600 dark:text-gray-400">DB Connections</span>
14
+ <span class="font-semibold font-mono">
15
+ {{ (data?.database?.poolSize || 0) - (data?.database?.idleConnections || 0) }}/{{ data?.database?.poolSize || 0 }}
16
+ </span>
17
+ </div>
18
+ <div class="flex items-center justify-between text-sm">
19
+ <span class="text-gray-600 dark:text-gray-400">Memory (Heap)</span>
20
+ <span class="font-semibold font-mono">{{ formatBytes(data?.memory?.heapUsed || 0) }}</span>
21
+ </div>
22
+ <div class="flex items-center justify-between text-sm">
23
+ <span class="text-gray-600 dark:text-gray-400">CPU Time</span>
24
+ <span class="font-semibold font-mono">
25
+ {{ formatDuration(((data?.cpu?.user || 0) + (data?.cpu?.system || 0)) / 1000) }}
26
+ </span>
27
+ </div>
28
+ </div>
29
+ </div>
30
+ </template>
31
+
32
+ <script setup>
33
+ import { formatBytes, formatDuration } from '../../utils/formatters';
34
+
35
+ defineProps({
36
+ data: Object,
37
+ });
38
+ </script>