queen-mq 0.1.5 → 0.2.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.
Files changed (135) hide show
  1. package/README.md +467 -1775
  2. package/package.json +12 -14
  3. package/src/client/client.js +664 -5
  4. package/src/managers/queueManagerOptimized.js +250 -47
  5. package/src/routes/ack.js +3 -3
  6. package/src/server.js +131 -3
  7. package/src/test/advanced-client-tests.js +761 -0
  8. package/src/test/advanced-pattern-tests.js +2 -2
  9. package/src/test/bus-mode-tests.js +6 -6
  10. package/src/test/core-tests.js +1 -1
  11. package/src/test/edge-case-tests.js +2 -2
  12. package/src/test/test-new.js +36 -1
  13. package/src/webapp-dist/assets/Analytics-DJrE4Rz2.css +1 -0
  14. package/src/webapp-dist/assets/Analytics-HEMXKmfJ.js +1 -0
  15. package/src/webapp-dist/assets/ConfirmDialog-YEoCdE7x.js +1 -0
  16. package/src/webapp-dist/assets/ConsumerGroups-CC5VJywp.css +1 -0
  17. package/src/webapp-dist/assets/ConsumerGroups-D8Z20HhZ.js +1 -0
  18. package/src/webapp-dist/assets/Dashboard-BRFOz6it.css +1 -0
  19. package/src/webapp-dist/assets/Dashboard-Bpx9I32h.js +1 -0
  20. package/src/webapp-dist/assets/LoadingSpinner-BPttXcbs.js +1 -0
  21. package/src/webapp-dist/assets/Messages-BOfVHKma.css +1 -0
  22. package/src/webapp-dist/assets/Messages-EKURCbLl.js +1 -0
  23. package/src/webapp-dist/assets/QueueDetail-BXXA7xoZ.css +1 -0
  24. package/src/webapp-dist/assets/QueueDetail-Bmxg0KiA.js +1 -0
  25. package/src/webapp-dist/assets/Queues-CvrJkrZT.css +1 -0
  26. package/src/webapp-dist/assets/Queues-yUx9_3-9.js +1 -0
  27. package/src/webapp-dist/assets/StatusBadge-C1bBtXHh.css +1 -0
  28. package/src/webapp-dist/assets/StatusBadge-C6N84XmO.js +1 -0
  29. package/src/webapp-dist/assets/analytics-BapTekLM.js +1 -0
  30. package/src/webapp-dist/assets/colors-5z6Q_kUr.js +18 -0
  31. package/src/webapp-dist/assets/index-B7w2bKT6.css +1 -0
  32. package/src/webapp-dist/assets/index-CUSnwYTH.js +31 -0
  33. package/src/webapp-dist/assets/messages-CRV6E-xU.js +1 -0
  34. package/src/webapp-dist/assets/queues-BdUbxfBC.js +1 -0
  35. package/src/webapp-dist/assets/resources-Bs9U-ceF.js +1 -0
  36. package/{webapp → src/webapp-dist}/index.html +2 -1
  37. package/API.md +0 -1226
  38. package/AUTH.md +0 -2044
  39. package/CHANGELOG_STATIC_SERVING.md +0 -213
  40. package/DEPLOYMENT.md +0 -425
  41. package/PROGRAMMATIC_SERVER.md +0 -239
  42. package/WEBAPP.md +0 -1889
  43. package/assets/dashboard-01.png +0 -0
  44. package/assets/dashboard.png +0 -0
  45. package/examples/batch-processing.js +0 -58
  46. package/examples/bus-mode.js +0 -239
  47. package/examples/continuous-consumer-optimized.js +0 -215
  48. package/examples/continuous-consumer.js +0 -159
  49. package/examples/continuous-producer.js +0 -343
  50. package/examples/mixed-mode.js +0 -277
  51. package/examples/multi-server-test.js +0 -305
  52. package/examples/programmatic-server.js +0 -58
  53. package/examples/server-with-frontend.js +0 -46
  54. package/examples/single.js +0 -64
  55. package/examples/smartchat-dealyed.js +0 -42
  56. package/examples/smartchat.js +0 -52
  57. package/examples/test-cache-invalidation.js +0 -119
  58. package/examples/test-cache-multi-server.js +0 -245
  59. package/examples/test-complete-client.js +0 -260
  60. package/examples/test-connection-recovery.js +0 -66
  61. package/examples/test-dashboard-api.js +0 -200
  62. package/examples/test-minimal-client.js +0 -112
  63. package/examples/test-queue-creation-policy.js +0 -137
  64. package/examples/test-traceid.js +0 -147
  65. package/server.log +0 -1
  66. package/test-keepalive-v2.sh +0 -22
  67. package/webapp/COLOR_GUIDE.md +0 -118
  68. package/webapp/README.md +0 -143
  69. package/webapp/package-lock.json +0 -3184
  70. package/webapp/package.json +0 -25
  71. package/webapp/postcss.config.js +0 -7
  72. package/webapp/public/assets/queen-logo-blue.svg +0 -210
  73. package/webapp/public/assets/queen-logo-cyan.svg +0 -210
  74. package/webapp/public/assets/queen-logo-indigo.svg +0 -210
  75. package/webapp/public/assets/queen-logo-orange.svg +0 -210
  76. package/webapp/public/assets/queen-logo-pink.svg +0 -210
  77. package/webapp/public/assets/queen-logo-purple.svg +0 -210
  78. package/webapp/public/assets/queen-logo-rose.svg +0 -239
  79. package/webapp/public/assets/queen-logo.svg +0 -263
  80. package/webapp/src/App.vue +0 -19
  81. package/webapp/src/api/analytics.js +0 -10
  82. package/webapp/src/api/client.js +0 -34
  83. package/webapp/src/api/consumers.js +0 -52
  84. package/webapp/src/api/health.js +0 -7
  85. package/webapp/src/api/messages.js +0 -26
  86. package/webapp/src/api/queues.js +0 -14
  87. package/webapp/src/api/resources.js +0 -8
  88. package/webapp/src/assets/styles/main.css +0 -357
  89. package/webapp/src/components/analytics/AnalyticsFilters.vue +0 -87
  90. package/webapp/src/components/analytics/AnalyticsMetrics.vue +0 -57
  91. package/webapp/src/components/analytics/MessageDistributionChart.vue +0 -111
  92. package/webapp/src/components/analytics/MessageFlowChart.vue +0 -173
  93. package/webapp/src/components/analytics/TimeRangeSelector.vue +0 -27
  94. package/webapp/src/components/analytics/TopQueuesChart.vue +0 -132
  95. package/webapp/src/components/common/ConfirmDialog.vue +0 -56
  96. package/webapp/src/components/common/LoadingSpinner.vue +0 -6
  97. package/webapp/src/components/common/MetricCard.vue +0 -43
  98. package/webapp/src/components/common/StatusBadge.vue +0 -45
  99. package/webapp/src/components/dashboard/MessageStatusCard.vue +0 -50
  100. package/webapp/src/components/dashboard/PerformanceCard.vue +0 -38
  101. package/webapp/src/components/dashboard/ThroughputChart.vue +0 -182
  102. package/webapp/src/components/dashboard/TopQueuesTable.vue +0 -53
  103. package/webapp/src/components/layout/AppLayout.vue +0 -110
  104. package/webapp/src/components/layout/AppSidebar.vue +0 -304
  105. package/webapp/src/components/messages/MessageDetailPanel.vue +0 -242
  106. package/webapp/src/components/messages/MessageFilters.vue +0 -101
  107. package/webapp/src/components/queue-detail/PartitionList.vue +0 -79
  108. package/webapp/src/components/queue-detail/PushMessageModal.vue +0 -175
  109. package/webapp/src/components/queue-detail/QueueConfig.vue +0 -63
  110. package/webapp/src/components/queue-detail/QueueDetailHeader.vue +0 -53
  111. package/webapp/src/components/queue-detail/RecentMessages.vue +0 -76
  112. package/webapp/src/components/queues/CreateQueueModal.vue +0 -193
  113. package/webapp/src/components/queues/QueueFilters.vue +0 -90
  114. package/webapp/src/composables/useApi.js +0 -34
  115. package/webapp/src/composables/useTheme.js +0 -36
  116. package/webapp/src/main.js +0 -11
  117. package/webapp/src/router/index.js +0 -42
  118. package/webapp/src/utils/colors.js +0 -96
  119. package/webapp/src/utils/formatters.js +0 -49
  120. package/webapp/src/views/Analytics.vue +0 -377
  121. package/webapp/src/views/ConsumerGroups.vue +0 -433
  122. package/webapp/src/views/Dashboard.vue +0 -418
  123. package/webapp/src/views/Messages.vue +0 -363
  124. package/webapp/src/views/QueueDetail.vue +0 -582
  125. package/webapp/src/views/Queues.vue +0 -496
  126. package/webapp/tailwind.config.js +0 -25
  127. package/webapp/vite.config.js +0 -10
  128. /package/{assets → src/webapp-dist/assets}/queen-logo-blue.svg +0 -0
  129. /package/{assets → src/webapp-dist/assets}/queen-logo-cyan.svg +0 -0
  130. /package/{assets → src/webapp-dist/assets}/queen-logo-indigo.svg +0 -0
  131. /package/{assets → src/webapp-dist/assets}/queen-logo-orange.svg +0 -0
  132. /package/{assets → src/webapp-dist/assets}/queen-logo-pink.svg +0 -0
  133. /package/{assets → src/webapp-dist/assets}/queen-logo-purple.svg +0 -0
  134. /package/{assets → src/webapp-dist/assets}/queen-logo-rose.svg +0 -0
  135. /package/{assets → src/webapp-dist/assets}/queen-logo.svg +0 -0
@@ -1,242 +0,0 @@
1
- <template>
2
- <div
3
- v-if="isOpen"
4
- class="fixed inset-y-0 right-0 w-full sm:w-[32rem] bg-white dark:bg-slate-800 shadow-2xl z-40 overflow-y-auto scrollbar-thin transform transition-all duration-300 border-l border-gray-200 dark:border-gray-700"
5
- :class="isOpen ? 'translate-x-0' : 'translate-x-full'"
6
- >
7
- <!-- Backdrop for mobile -->
8
- <div
9
- v-if="isOpen"
10
- class="sm:hidden fixed inset-0 bg-black bg-opacity-50 backdrop-blur-sm -z-10 animate-fade-in"
11
- @click="close"
12
- ></div>
13
-
14
- <div class="p-6">
15
- <!-- Header -->
16
- <div class="flex items-start justify-between mb-6">
17
- <div class="flex-1 min-w-0">
18
- <h3 class="text-lg font-bold mb-1">Message Details</h3>
19
- <p class="text-xs font-mono text-gray-500 dark:text-gray-400 break-all">
20
- {{ message?.transactionId }}
21
- </p>
22
- </div>
23
- <button @click="close" class="text-gray-400 hover:text-gray-600 p-1">
24
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
25
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
26
- </svg>
27
- </button>
28
- </div>
29
-
30
- <LoadingSpinner v-if="loading" />
31
-
32
- <div v-else-if="error" class="text-sm text-red-600 dark:text-red-400">
33
- {{ error }}
34
- </div>
35
-
36
- <template v-else-if="messageDetail">
37
- <!-- Status Badge -->
38
- <div class="mb-6">
39
- <StatusBadge :status="messageDetail.status" />
40
- </div>
41
-
42
- <!-- Info Grid -->
43
- <div class="space-y-4 mb-6">
44
- <div>
45
- <label class="text-xs text-gray-500 dark:text-gray-400 block mb-1">Queue</label>
46
- <p class="text-sm font-medium">{{ messageDetail.queue }} / {{ messageDetail.partition }}</p>
47
- </div>
48
-
49
- <div>
50
- <label class="text-xs text-gray-500 dark:text-gray-400 block mb-1">Created</label>
51
- <p class="text-sm">{{ formatDate(messageDetail.createdAt) }}</p>
52
- </div>
53
-
54
- <div v-if="messageDetail.traceId">
55
- <label class="text-xs text-gray-500 dark:text-gray-400 block mb-1">Trace ID</label>
56
- <p class="text-xs font-mono break-all">{{ messageDetail.traceId }}</p>
57
- </div>
58
-
59
- <div v-if="messageDetail.errorMessage">
60
- <label class="text-xs text-gray-500 dark:text-gray-400 block mb-1">Error Message</label>
61
- <p class="text-sm text-red-600 dark:text-red-400">{{ messageDetail.errorMessage }}</p>
62
- </div>
63
-
64
- <div v-if="messageDetail.retryCount">
65
- <label class="text-xs text-gray-500 dark:text-gray-400 block mb-1">Retry Count</label>
66
- <p class="text-sm">{{ messageDetail.retryCount }}</p>
67
- </div>
68
- </div>
69
-
70
- <!-- Payload -->
71
- <div class="mb-6">
72
- <label class="text-xs text-gray-500 dark:text-gray-400 block mb-2">Payload</label>
73
- <div class="bg-gray-50 dark:bg-slate-900 rounded-lg p-4 overflow-x-auto scrollbar-thin">
74
- <pre class="text-xs font-mono">{{ JSON.stringify(messageDetail.payload, null, 2) }}</pre>
75
- </div>
76
- </div>
77
-
78
- <!-- Actions -->
79
- <div class="space-y-2">
80
- <!-- Completed message info -->
81
- <div v-if="messageDetail.status === 'completed'" class="card bg-green-50 dark:bg-green-900/20 text-green-800 dark:text-green-200 text-sm">
82
- <div class="flex gap-2">
83
- <svg class="w-5 h-5 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
84
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
85
- </svg>
86
- <p>This message has been successfully consumed and acknowledged.</p>
87
- </div>
88
- </div>
89
-
90
- <button
91
- v-if="messageDetail.status === 'dead_letter'"
92
- @click="retryMessage"
93
- :disabled="actionLoading"
94
- class="btn btn-primary w-full"
95
- >
96
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
97
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
98
- </svg>
99
- Retry Message
100
- </button>
101
-
102
- <button
103
- v-if="messageDetail.status === 'pending'"
104
- @click="moveToDLQ"
105
- :disabled="actionLoading"
106
- class="btn btn-secondary w-full"
107
- >
108
- Move to Dead Letter Queue
109
- </button>
110
-
111
- <button
112
- @click="confirmDelete"
113
- :disabled="actionLoading"
114
- class="btn btn-danger w-full"
115
- >
116
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
117
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
118
- </svg>
119
- Delete Message
120
- </button>
121
- </div>
122
-
123
- <div v-if="actionError" class="text-sm text-red-600 dark:text-red-400 mt-4">
124
- {{ actionError }}
125
- </div>
126
- </template>
127
- </div>
128
-
129
- <!-- Delete Confirmation -->
130
- <ConfirmDialog
131
- :is-open="showDeleteConfirm"
132
- title="Delete Message"
133
- message="Are you sure you want to delete this message? This action cannot be undone."
134
- confirm-text="Delete"
135
- confirm-class="btn-danger"
136
- @confirm="deleteMessage"
137
- @cancel="showDeleteConfirm = false"
138
- />
139
- </div>
140
- </template>
141
-
142
- <script setup>
143
- import { ref, watch } from 'vue';
144
- import { messagesApi } from '../../api/messages';
145
- import { formatDate } from '../../utils/formatters';
146
-
147
- import StatusBadge from '../common/StatusBadge.vue';
148
- import LoadingSpinner from '../common/LoadingSpinner.vue';
149
- import ConfirmDialog from '../common/ConfirmDialog.vue';
150
-
151
- const props = defineProps({
152
- isOpen: Boolean,
153
- message: Object,
154
- });
155
-
156
- const emit = defineEmits(['close', 'action-complete']);
157
-
158
- const loading = ref(false);
159
- const error = ref(null);
160
- const actionLoading = ref(false);
161
- const actionError = ref(null);
162
- const messageDetail = ref(null);
163
- const showDeleteConfirm = ref(false);
164
-
165
- watch(() => props.message, async (newMessage) => {
166
- if (newMessage) {
167
- await loadMessageDetail();
168
- }
169
- });
170
-
171
- async function loadMessageDetail() {
172
- if (!props.message?.transactionId) return;
173
-
174
- loading.value = true;
175
- error.value = null;
176
-
177
- try {
178
- const response = await messagesApi.getMessage(props.message.transactionId);
179
- messageDetail.value = response.data;
180
- } catch (err) {
181
- error.value = err.response?.data?.error || err.message;
182
- } finally {
183
- loading.value = false;
184
- }
185
- }
186
-
187
- async function retryMessage() {
188
- actionLoading.value = true;
189
- actionError.value = null;
190
-
191
- try {
192
- await messagesApi.retryMessage(messageDetail.value.transactionId);
193
- emit('action-complete');
194
- close();
195
- } catch (err) {
196
- actionError.value = err.response?.data?.error || err.message;
197
- } finally {
198
- actionLoading.value = false;
199
- }
200
- }
201
-
202
- async function moveToDLQ() {
203
- actionLoading.value = true;
204
- actionError.value = null;
205
-
206
- try {
207
- await messagesApi.moveToDLQ(messageDetail.value.transactionId);
208
- emit('action-complete');
209
- close();
210
- } catch (err) {
211
- actionError.value = err.response?.data?.error || err.message;
212
- } finally {
213
- actionLoading.value = false;
214
- }
215
- }
216
-
217
- function confirmDelete() {
218
- showDeleteConfirm.value = true;
219
- }
220
-
221
- async function deleteMessage() {
222
- actionLoading.value = true;
223
- actionError.value = null;
224
- showDeleteConfirm.value = false;
225
-
226
- try {
227
- await messagesApi.deleteMessage(messageDetail.value.transactionId);
228
- emit('action-complete');
229
- close();
230
- } catch (err) {
231
- actionError.value = err.response?.data?.error || err.message;
232
- } finally {
233
- actionLoading.value = false;
234
- }
235
- }
236
-
237
- function close() {
238
- emit('close');
239
- messageDetail.value = null;
240
- }
241
- </script>
242
-
@@ -1,101 +0,0 @@
1
- <template>
2
- <div>
3
- <div class="flex flex-col sm:flex-row gap-3">
4
- <!-- Search by Transaction ID -->
5
- <div class="flex-1">
6
- <input
7
- v-model="localSearch"
8
- @input="onSearchChange"
9
- type="text"
10
- placeholder="Search by transaction ID..."
11
- class="input font-mono text-xs"
12
- />
13
- </div>
14
-
15
- <!-- Queue Filter -->
16
- <select
17
- v-model="localQueue"
18
- @change="onQueueChange"
19
- class="input sm:w-48"
20
- >
21
- <option value="">All Queues</option>
22
- <option v-for="queue in queues" :key="queue.id" :value="queue.name">
23
- {{ queue.name }}
24
- </option>
25
- </select>
26
-
27
- <!-- Status Filter -->
28
- <select
29
- v-model="localStatus"
30
- @change="onStatusChange"
31
- class="input sm:w-40"
32
- >
33
- <option value="">All Status</option>
34
- <option value="pending">Pending</option>
35
- <option value="processing">Processing</option>
36
- <option value="completed">Completed</option>
37
- <option value="dead_letter">Dead Letter</option>
38
- </select>
39
-
40
- <!-- Clear Filters -->
41
- <button
42
- v-if="localSearch || localQueue || localStatus"
43
- @click="clearFilters"
44
- class="btn btn-secondary whitespace-nowrap"
45
- >
46
- Clear Filters
47
- </button>
48
- </div>
49
- </div>
50
- </template>
51
-
52
-
53
- <script setup>
54
- import { ref, watch } from 'vue';
55
-
56
- const props = defineProps({
57
- search: String,
58
- queue: String,
59
- status: String,
60
- queues: Array,
61
- });
62
-
63
- const emit = defineEmits(['update:search', 'update:queue', 'update:status']);
64
-
65
- const localSearch = ref(props.search || '');
66
- const localQueue = ref(props.queue || '');
67
- const localStatus = ref(props.status || '');
68
-
69
- watch(() => props.search, (newVal) => {
70
- localSearch.value = newVal || '';
71
- });
72
-
73
- watch(() => props.queue, (newVal) => {
74
- localQueue.value = newVal || '';
75
- });
76
-
77
- watch(() => props.status, (newVal) => {
78
- localStatus.value = newVal || '';
79
- });
80
-
81
- function onSearchChange() {
82
- emit('update:search', localSearch.value);
83
- }
84
-
85
- function onQueueChange() {
86
- emit('update:queue', localQueue.value);
87
- }
88
-
89
- function onStatusChange() {
90
- emit('update:status', localStatus.value);
91
- }
92
-
93
- function clearFilters() {
94
- localSearch.value = '';
95
- localQueue.value = '';
96
- localStatus.value = '';
97
- emit('update:search', '');
98
- emit('update:queue', '');
99
- emit('update:status', '');
100
- }
101
- </script>
@@ -1,79 +0,0 @@
1
- <template>
2
- <div class="partition-container">
3
- <h3 class="text-base font-semibold mb-4">Partitions</h3>
4
- <div class="space-y-3">
5
- <div
6
- v-for="partition in partitions"
7
- :key="partition.id"
8
- class="p-4 bg-gray-50 dark:bg-slate-700/50 rounded-lg"
9
- >
10
- <div class="flex items-center justify-between mb-2">
11
- <h4 class="font-semibold">{{ partition.name }}</h4>
12
- <span class="text-xs text-gray-500">{{ formatDate(partition.createdAt) }}</span>
13
- </div>
14
-
15
- <div class="grid grid-cols-2 sm:grid-cols-4 gap-3 text-sm">
16
- <div>
17
- <span class="text-gray-500 dark:text-gray-400 block">Pending</span>
18
- <span class="font-semibold">{{ formatNumber(partition.messages?.pending || 0) }}</span>
19
- </div>
20
- <div>
21
- <span class="text-gray-500 dark:text-gray-400 block">Processing</span>
22
- <span class="font-semibold">{{ formatNumber(partition.messages?.processing || 0) }}</span>
23
- </div>
24
- <div>
25
- <span class="text-gray-500 dark:text-gray-400 block">Completed</span>
26
- <span class="font-semibold text-green-600">{{ formatNumber(partition.messages?.completed || 0) }}</span>
27
- </div>
28
- <div>
29
- <span class="text-gray-500 dark:text-gray-400 block">Failed</span>
30
- <span class="font-semibold text-red-600">{{ formatNumber(partition.messages?.failed || 0) }}</span>
31
- </div>
32
- </div>
33
-
34
- <div v-if="partition.cursor" class="mt-3 pt-3 border-t border-gray-200 dark:border-gray-600 text-xs text-gray-600 dark:text-gray-400">
35
- <div class="flex items-center justify-between">
36
- <span>Consumed: {{ formatNumber(partition.cursor.totalConsumed || 0) }} messages in {{ partition.cursor.batchesConsumed || 0 }} batches</span>
37
- <span v-if="partition.lastActivity">Last: {{ formatTime(partition.lastActivity) }}</span>
38
- </div>
39
- </div>
40
- </div>
41
- </div>
42
-
43
- <div v-if="!partitions?.length" class="text-center py-8 text-gray-500 text-sm">
44
- No partitions found
45
- </div>
46
- </div>
47
- </template>
48
-
49
- <style scoped>
50
- .partition-container {
51
- background: #ffffff;
52
- border: none;
53
- box-shadow: none;
54
- border-radius: 0.75rem;
55
- padding: 1rem;
56
- transition: all 0.3s ease;
57
- }
58
-
59
- .dark .partition-container {
60
- background: #0a0d14;
61
- }
62
-
63
- .partition-container:hover {
64
- background: #fafafa;
65
- }
66
-
67
- .dark .partition-container:hover {
68
- background: #0d1117;
69
- }
70
- </style>
71
-
72
- <script setup>
73
- import { formatNumber, formatDate, formatTime } from '../../utils/formatters';
74
-
75
- defineProps({
76
- partitions: Array,
77
- });
78
- </script>
79
-
@@ -1,175 +0,0 @@
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="close"
8
- ></div>
9
-
10
- <!-- Modal -->
11
- <div class="relative bg-white dark:bg-slate-800 rounded-xl shadow-2xl max-w-2xl w-full p-6 animate-scale-in border border-gray-200 dark:border-gray-700">
12
- <div class="flex items-center justify-between mb-4">
13
- <h3 class="text-lg font-bold">Push Message to {{ queueName }}</h3>
14
- <button @click="close" class="text-gray-400 hover:text-gray-600">
15
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
16
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
17
- </svg>
18
- </button>
19
- </div>
20
-
21
- <form @submit.prevent="pushMessage" class="space-y-4">
22
- <div>
23
- <label class="block text-sm font-medium mb-1">Partition</label>
24
- <input
25
- v-model="form.partition"
26
- type="text"
27
- placeholder="Default"
28
- class="input"
29
- />
30
- </div>
31
-
32
- <div>
33
- <label class="block text-sm font-medium mb-1">Payload (JSON) *</label>
34
- <textarea
35
- v-model="form.payload"
36
- rows="10"
37
- placeholder='{"key": "value", "message": "Hello World"}'
38
- class="input font-mono text-xs"
39
- required
40
- ></textarea>
41
- <p v-if="jsonError" class="text-xs text-red-600 mt-1">{{ jsonError }}</p>
42
- </div>
43
-
44
- <div class="grid grid-cols-2 gap-3">
45
- <div>
46
- <label class="block text-sm font-medium mb-1">TTL (seconds)</label>
47
- <input
48
- v-model.number="form.ttl"
49
- type="number"
50
- placeholder="3600"
51
- class="input"
52
- />
53
- </div>
54
-
55
- <div>
56
- <label class="block text-sm font-medium mb-1">Priority</label>
57
- <input
58
- v-model.number="form.priority"
59
- type="number"
60
- placeholder="0"
61
- class="input"
62
- />
63
- </div>
64
- </div>
65
-
66
- <div>
67
- <label class="block text-sm font-medium mb-1">Trace ID (optional)</label>
68
- <input
69
- v-model="form.traceId"
70
- type="text"
71
- placeholder="trace-id-for-distributed-tracing"
72
- class="input"
73
- />
74
- </div>
75
-
76
- <div v-if="error" class="text-sm text-red-600 dark:text-red-400">
77
- {{ error }}
78
- </div>
79
-
80
- <div class="flex gap-3 pt-2">
81
- <button type="submit" :disabled="loading || !!jsonError" class="btn btn-primary flex-1">
82
- <span v-if="loading">Pushing...</span>
83
- <span v-else>Push Message</span>
84
- </button>
85
- <button type="button" @click="close" class="btn btn-secondary">
86
- Cancel
87
- </button>
88
- </div>
89
- </form>
90
- </div>
91
- </div>
92
- </div>
93
- </template>
94
-
95
- <script setup>
96
- import { ref, watch, computed } from 'vue';
97
- import { messagesApi } from '../../api/messages';
98
-
99
- const props = defineProps({
100
- isOpen: Boolean,
101
- queueName: String,
102
- });
103
-
104
- const emit = defineEmits(['close', 'pushed']);
105
-
106
- const loading = ref(false);
107
- const error = ref(null);
108
- const form = ref({
109
- partition: 'Default',
110
- payload: '',
111
- ttl: null,
112
- priority: null,
113
- traceId: '',
114
- });
115
-
116
- const jsonError = computed(() => {
117
- if (!form.value.payload) return null;
118
-
119
- try {
120
- JSON.parse(form.value.payload);
121
- return null;
122
- } catch (e) {
123
- return 'Invalid JSON format';
124
- }
125
- });
126
-
127
- watch(() => props.isOpen, (newVal) => {
128
- if (newVal) {
129
- resetForm();
130
- }
131
- });
132
-
133
- function resetForm() {
134
- form.value = {
135
- partition: 'Default',
136
- payload: '',
137
- ttl: null,
138
- priority: null,
139
- traceId: '',
140
- };
141
- error.value = null;
142
- }
143
-
144
- async function pushMessage() {
145
- loading.value = true;
146
- error.value = null;
147
-
148
- try {
149
- const payload = JSON.parse(form.value.payload);
150
-
151
- const item = {
152
- queue: props.queueName,
153
- partition: form.value.partition || 'Default',
154
- payload: payload,
155
- };
156
-
157
- if (form.value.ttl) item.ttl = form.value.ttl;
158
- if (form.value.priority) item.priority = form.value.priority;
159
- if (form.value.traceId) item.traceId = form.value.traceId;
160
-
161
- await messagesApi.pushMessages({ items: [item] });
162
- emit('pushed');
163
- close();
164
- } catch (err) {
165
- error.value = err.response?.data?.error || err.message;
166
- } finally {
167
- loading.value = false;
168
- }
169
- }
170
-
171
- function close() {
172
- emit('close');
173
- }
174
- </script>
175
-
@@ -1,63 +0,0 @@
1
- <template>
2
- <div class="config-container">
3
- <h3 class="text-base font-semibold mb-4">Queue Configuration</h3>
4
- <div class="grid grid-cols-2 md:grid-cols-3 gap-4 text-sm">
5
- <div>
6
- <span class="text-gray-500 dark:text-gray-400 block mb-1">Lease Time</span>
7
- <span class="font-semibold">{{ config?.leaseTime || 0 }}s</span>
8
- </div>
9
- <div>
10
- <span class="text-gray-500 dark:text-gray-400 block mb-1">TTL</span>
11
- <span class="font-semibold">{{ formatDuration((config?.ttl || 0) * 1000) }}</span>
12
- </div>
13
- <div>
14
- <span class="text-gray-500 dark:text-gray-400 block mb-1">Max Queue Size</span>
15
- <span class="font-semibold">{{ formatNumber(config?.maxQueueSize || 0) }}</span>
16
- </div>
17
- <div>
18
- <span class="text-gray-500 dark:text-gray-400 block mb-1">Retry Limit</span>
19
- <span class="font-semibold">{{ config?.retryLimit || 0 }}</span>
20
- </div>
21
- <div>
22
- <span class="text-gray-500 dark:text-gray-400 block mb-1">Retry Delay</span>
23
- <span class="font-semibold">{{ config?.retryDelay || 0 }}ms</span>
24
- </div>
25
- <div>
26
- <span class="text-gray-500 dark:text-gray-400 block mb-1">DLQ Enabled</span>
27
- <span class="font-semibold">{{ config?.deadLetterQueue ? 'Yes' : 'No' }}</span>
28
- </div>
29
- </div>
30
- </div>
31
- </template>
32
-
33
- <style scoped>
34
- .config-container {
35
- background: #ffffff;
36
- border: none;
37
- box-shadow: none;
38
- border-radius: 0.75rem;
39
- padding: 1rem;
40
- transition: all 0.3s ease;
41
- }
42
-
43
- .dark .config-container {
44
- background: #0a0d14;
45
- }
46
-
47
- .config-container:hover {
48
- background: #fafafa;
49
- }
50
-
51
- .dark .config-container:hover {
52
- background: #0d1117;
53
- }
54
- </style>
55
-
56
- <script setup>
57
- import { formatNumber, formatDuration } from '../../utils/formatters';
58
-
59
- defineProps({
60
- config: Object,
61
- });
62
- </script>
63
-