@zintrust/workers 0.1.27
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/README.md +861 -0
- package/dist/AnomalyDetection.d.ts +102 -0
- package/dist/AnomalyDetection.js +321 -0
- package/dist/AutoScaler.d.ts +127 -0
- package/dist/AutoScaler.js +425 -0
- package/dist/BroadcastWorker.d.ts +21 -0
- package/dist/BroadcastWorker.js +24 -0
- package/dist/CanaryController.d.ts +103 -0
- package/dist/CanaryController.js +380 -0
- package/dist/ChaosEngineering.d.ts +79 -0
- package/dist/ChaosEngineering.js +216 -0
- package/dist/CircuitBreaker.d.ts +106 -0
- package/dist/CircuitBreaker.js +374 -0
- package/dist/ClusterLock.d.ts +90 -0
- package/dist/ClusterLock.js +385 -0
- package/dist/ComplianceManager.d.ts +177 -0
- package/dist/ComplianceManager.js +556 -0
- package/dist/DatacenterOrchestrator.d.ts +133 -0
- package/dist/DatacenterOrchestrator.js +404 -0
- package/dist/DeadLetterQueue.d.ts +122 -0
- package/dist/DeadLetterQueue.js +539 -0
- package/dist/HealthMonitor.d.ts +42 -0
- package/dist/HealthMonitor.js +301 -0
- package/dist/MultiQueueWorker.d.ts +89 -0
- package/dist/MultiQueueWorker.js +277 -0
- package/dist/NotificationWorker.d.ts +21 -0
- package/dist/NotificationWorker.js +23 -0
- package/dist/Observability.d.ts +153 -0
- package/dist/Observability.js +530 -0
- package/dist/PluginManager.d.ts +123 -0
- package/dist/PluginManager.js +392 -0
- package/dist/PriorityQueue.d.ts +117 -0
- package/dist/PriorityQueue.js +244 -0
- package/dist/ResourceMonitor.d.ts +164 -0
- package/dist/ResourceMonitor.js +605 -0
- package/dist/SLAMonitor.d.ts +110 -0
- package/dist/SLAMonitor.js +274 -0
- package/dist/WorkerFactory.d.ts +193 -0
- package/dist/WorkerFactory.js +1507 -0
- package/dist/WorkerInit.d.ts +85 -0
- package/dist/WorkerInit.js +223 -0
- package/dist/WorkerMetrics.d.ts +114 -0
- package/dist/WorkerMetrics.js +509 -0
- package/dist/WorkerRegistry.d.ts +145 -0
- package/dist/WorkerRegistry.js +319 -0
- package/dist/WorkerShutdown.d.ts +61 -0
- package/dist/WorkerShutdown.js +159 -0
- package/dist/WorkerVersioning.d.ts +107 -0
- package/dist/WorkerVersioning.js +300 -0
- package/dist/build-manifest.json +462 -0
- package/dist/config/workerConfig.d.ts +3 -0
- package/dist/config/workerConfig.js +19 -0
- package/dist/createQueueWorker.d.ts +23 -0
- package/dist/createQueueWorker.js +113 -0
- package/dist/dashboard/index.d.ts +1 -0
- package/dist/dashboard/index.js +1 -0
- package/dist/dashboard/types.d.ts +117 -0
- package/dist/dashboard/types.js +1 -0
- package/dist/dashboard/workers-api.d.ts +4 -0
- package/dist/dashboard/workers-api.js +638 -0
- package/dist/dashboard/workers-dashboard-ui.d.ts +3 -0
- package/dist/dashboard/workers-dashboard-ui.js +1026 -0
- package/dist/dashboard/workers-dashboard.d.ts +4 -0
- package/dist/dashboard/workers-dashboard.js +904 -0
- package/dist/helper/index.d.ts +5 -0
- package/dist/helper/index.js +10 -0
- package/dist/http/WorkerApiController.d.ts +38 -0
- package/dist/http/WorkerApiController.js +312 -0
- package/dist/http/WorkerController.d.ts +374 -0
- package/dist/http/WorkerController.js +1351 -0
- package/dist/http/middleware/CustomValidation.d.ts +92 -0
- package/dist/http/middleware/CustomValidation.js +270 -0
- package/dist/http/middleware/DatacenterValidator.d.ts +3 -0
- package/dist/http/middleware/DatacenterValidator.js +94 -0
- package/dist/http/middleware/EditWorkerValidation.d.ts +7 -0
- package/dist/http/middleware/EditWorkerValidation.js +55 -0
- package/dist/http/middleware/FeaturesValidator.d.ts +3 -0
- package/dist/http/middleware/FeaturesValidator.js +60 -0
- package/dist/http/middleware/InfrastructureValidator.d.ts +31 -0
- package/dist/http/middleware/InfrastructureValidator.js +226 -0
- package/dist/http/middleware/OptionsValidator.d.ts +3 -0
- package/dist/http/middleware/OptionsValidator.js +112 -0
- package/dist/http/middleware/PayloadSanitizer.d.ts +7 -0
- package/dist/http/middleware/PayloadSanitizer.js +42 -0
- package/dist/http/middleware/ProcessorPathSanitizer.d.ts +3 -0
- package/dist/http/middleware/ProcessorPathSanitizer.js +74 -0
- package/dist/http/middleware/QueueNameSanitizer.d.ts +3 -0
- package/dist/http/middleware/QueueNameSanitizer.js +45 -0
- package/dist/http/middleware/ValidateDriver.d.ts +7 -0
- package/dist/http/middleware/ValidateDriver.js +20 -0
- package/dist/http/middleware/VersionSanitizer.d.ts +3 -0
- package/dist/http/middleware/VersionSanitizer.js +25 -0
- package/dist/http/middleware/WorkerNameSanitizer.d.ts +3 -0
- package/dist/http/middleware/WorkerNameSanitizer.js +46 -0
- package/dist/http/middleware/WorkerValidationChain.d.ts +27 -0
- package/dist/http/middleware/WorkerValidationChain.js +185 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.js +48 -0
- package/dist/routes/workers.d.ts +12 -0
- package/dist/routes/workers.js +81 -0
- package/dist/storage/WorkerStore.d.ts +45 -0
- package/dist/storage/WorkerStore.js +195 -0
- package/dist/type.d.ts +76 -0
- package/dist/type.js +1 -0
- package/dist/ui/router/ui.d.ts +3 -0
- package/dist/ui/router/ui.js +83 -0
- package/dist/ui/types/worker-ui.d.ts +229 -0
- package/dist/ui/types/worker-ui.js +5 -0
- package/package.json +53 -0
- package/src/AnomalyDetection.ts +434 -0
- package/src/AutoScaler.ts +654 -0
- package/src/BroadcastWorker.ts +34 -0
- package/src/CanaryController.ts +531 -0
- package/src/ChaosEngineering.ts +301 -0
- package/src/CircuitBreaker.ts +495 -0
- package/src/ClusterLock.ts +499 -0
- package/src/ComplianceManager.ts +815 -0
- package/src/DatacenterOrchestrator.ts +561 -0
- package/src/DeadLetterQueue.ts +733 -0
- package/src/HealthMonitor.ts +390 -0
- package/src/MultiQueueWorker.ts +431 -0
- package/src/NotificationWorker.ts +33 -0
- package/src/Observability.ts +696 -0
- package/src/PluginManager.ts +551 -0
- package/src/PriorityQueue.ts +351 -0
- package/src/ResourceMonitor.ts +769 -0
- package/src/SLAMonitor.ts +408 -0
- package/src/WorkerFactory.ts +2108 -0
- package/src/WorkerInit.ts +313 -0
- package/src/WorkerMetrics.ts +709 -0
- package/src/WorkerRegistry.ts +443 -0
- package/src/WorkerShutdown.ts +210 -0
- package/src/WorkerVersioning.ts +422 -0
- package/src/config/workerConfig.ts +25 -0
- package/src/createQueueWorker.ts +174 -0
- package/src/dashboard/index.ts +6 -0
- package/src/dashboard/types.ts +141 -0
- package/src/dashboard/workers-api.ts +785 -0
- package/src/dashboard/zintrust.svg +30 -0
- package/src/helper/index.ts +11 -0
- package/src/http/WorkerApiController.ts +369 -0
- package/src/http/WorkerController.ts +1512 -0
- package/src/http/middleware/CustomValidation.ts +360 -0
- package/src/http/middleware/DatacenterValidator.ts +124 -0
- package/src/http/middleware/EditWorkerValidation.ts +74 -0
- package/src/http/middleware/FeaturesValidator.ts +82 -0
- package/src/http/middleware/InfrastructureValidator.ts +295 -0
- package/src/http/middleware/OptionsValidator.ts +144 -0
- package/src/http/middleware/PayloadSanitizer.ts +52 -0
- package/src/http/middleware/ProcessorPathSanitizer.ts +86 -0
- package/src/http/middleware/QueueNameSanitizer.ts +55 -0
- package/src/http/middleware/ValidateDriver.ts +29 -0
- package/src/http/middleware/VersionSanitizer.ts +30 -0
- package/src/http/middleware/WorkerNameSanitizer.ts +56 -0
- package/src/http/middleware/WorkerValidationChain.ts +230 -0
- package/src/index.ts +98 -0
- package/src/routes/workers.ts +154 -0
- package/src/storage/WorkerStore.ts +240 -0
- package/src/type.ts +89 -0
- package/src/types/queue-monitor.d.ts +38 -0
- package/src/types/queue-redis.d.ts +38 -0
- package/src/ui/README.md +13 -0
- package/src/ui/components/JsonEditor.js +670 -0
- package/src/ui/components/JsonViewer.js +387 -0
- package/src/ui/components/WorkerCard.js +178 -0
- package/src/ui/components/WorkerExpandPanel.js +257 -0
- package/src/ui/components/fetcher.js +42 -0
- package/src/ui/components/sla-scorecard.js +32 -0
- package/src/ui/components/styles.css +30 -0
- package/src/ui/components/table-expander.js +34 -0
- package/src/ui/integration/worker-ui-integration.js +565 -0
- package/src/ui/router/ui.ts +99 -0
- package/src/ui/services/workerApi.js +240 -0
- package/src/ui/types/worker-ui.ts +283 -0
- package/src/ui/utils/jsonValidator.js +444 -0
- package/src/ui/workers/index.html +202 -0
- package/src/ui/workers/main.js +1781 -0
- package/src/ui/workers/styles.css +1350 -0
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
3
|
+
/* eslint-disable no-restricted-imports */
|
|
4
|
+
/* eslint-disable no-undef */
|
|
5
|
+
/**
|
|
6
|
+
* Worker UI Integration
|
|
7
|
+
* Integrates new WorkerCard components with existing main.js
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Import the new components
|
|
11
|
+
import { WorkerCard } from '../components/WorkerCard.js';
|
|
12
|
+
import { WorkerExpandPanel } from '../components/WorkerExpandPanel.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Enhanced worker rendering using new components
|
|
16
|
+
*/
|
|
17
|
+
function renderWorkersEnhanced(data) {
|
|
18
|
+
const tbody = document.getElementById('workers-tbody');
|
|
19
|
+
if (!tbody) return;
|
|
20
|
+
|
|
21
|
+
// Clear existing content safely
|
|
22
|
+
while (tbody.firstChild) {
|
|
23
|
+
tbody.firstChild.remove();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!data.workers || data.workers.length === 0) {
|
|
27
|
+
const noWorkersRow = document.createElement('tr');
|
|
28
|
+
const noWorkersCell = document.createElement('td');
|
|
29
|
+
noWorkersCell.colSpan = '7';
|
|
30
|
+
noWorkersCell.className = 'text-center p-4';
|
|
31
|
+
noWorkersCell.textContent = 'No workers found';
|
|
32
|
+
noWorkersRow.appendChild(noWorkersCell);
|
|
33
|
+
tbody.appendChild(noWorkersRow);
|
|
34
|
+
|
|
35
|
+
updateQueueSummary(data.queueData);
|
|
36
|
+
updateDriverFilter(data.drivers);
|
|
37
|
+
updateDriversList(data.drivers);
|
|
38
|
+
updatePagination(data.pagination);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Create a container for our new worker cards
|
|
43
|
+
const cardsContainer = document.createElement('div');
|
|
44
|
+
cardsContainer.className = 'workers-cards-container';
|
|
45
|
+
cardsContainer.style.cssText = `
|
|
46
|
+
display: grid;
|
|
47
|
+
gap: 16px;
|
|
48
|
+
padding: 16px;
|
|
49
|
+
`;
|
|
50
|
+
|
|
51
|
+
data.workers.forEach((worker) => {
|
|
52
|
+
// Create a table row that contains the worker card
|
|
53
|
+
const row = document.createElement('tr');
|
|
54
|
+
const cell = document.createElement('td');
|
|
55
|
+
cell.colSpan = '7';
|
|
56
|
+
cell.style.padding = '0';
|
|
57
|
+
|
|
58
|
+
// Create worker card container
|
|
59
|
+
const cardContainer = document.createElement('div');
|
|
60
|
+
cardContainer.className = 'worker-card-wrapper';
|
|
61
|
+
|
|
62
|
+
// Ensure worker has an ID for the expand functionality
|
|
63
|
+
if (!worker.id) {
|
|
64
|
+
worker.id = worker.name.replaceAll(/[^a-z0-9]/gi, '-');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Initialize the new WorkerCard component
|
|
68
|
+
WorkerCard.create(worker, cardContainer);
|
|
69
|
+
|
|
70
|
+
cell.appendChild(cardContainer);
|
|
71
|
+
row.appendChild(cell);
|
|
72
|
+
tbody.appendChild(row);
|
|
73
|
+
|
|
74
|
+
// Create expandable detail row for this worker
|
|
75
|
+
const detailsId = `details-${worker.id}`;
|
|
76
|
+
const detailRow = createDetailRowEnhanced(worker, detailsId);
|
|
77
|
+
tbody.appendChild(detailRow);
|
|
78
|
+
|
|
79
|
+
// Connect the WorkerCard expand button to the table row toggle
|
|
80
|
+
// Use a more reliable approach without setTimeout
|
|
81
|
+
const observer = new MutationObserver(() => {
|
|
82
|
+
const expandBtn = cardContainer.querySelector('.expand-btn');
|
|
83
|
+
if (expandBtn && !expandBtn.hasAttribute('data-connected')) {
|
|
84
|
+
expandBtn.setAttribute('data-connected', 'true');
|
|
85
|
+
expandBtn.addEventListener('click', (e) => {
|
|
86
|
+
e.stopPropagation();
|
|
87
|
+
// Toggle the detail row instead of internal expand
|
|
88
|
+
globalThis.window.toggleDetails(detailsId);
|
|
89
|
+
});
|
|
90
|
+
observer.disconnect(); // Clean up observer
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
observer.observe(cardContainer, { childList: true, subtree: true });
|
|
95
|
+
|
|
96
|
+
// Fallback: try immediately in case the button already exists
|
|
97
|
+
const expandBtn = cardContainer.querySelector('.expand-btn');
|
|
98
|
+
if (expandBtn && !expandBtn.hasAttribute('data-connected')) {
|
|
99
|
+
expandBtn.setAttribute('data-connected', 'true');
|
|
100
|
+
expandBtn.addEventListener('click', (e) => {
|
|
101
|
+
e.stopPropagation();
|
|
102
|
+
globalThis.window.toggleDetails(detailsId);
|
|
103
|
+
});
|
|
104
|
+
observer.disconnect();
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
updateQueueSummary(data.queueData);
|
|
109
|
+
updateDriverFilter(data.drivers);
|
|
110
|
+
updateDriversList(data.drivers);
|
|
111
|
+
updatePagination(data.pagination);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Enhanced detail row with new components
|
|
116
|
+
*/
|
|
117
|
+
function createDetailRowEnhanced(worker, detailsId) {
|
|
118
|
+
const detailRow = document.createElement('tr');
|
|
119
|
+
detailRow.id = `details-${detailsId}`;
|
|
120
|
+
detailRow.className = 'expandable-row';
|
|
121
|
+
detailRow.style.display = 'none';
|
|
122
|
+
|
|
123
|
+
const detailCell = document.createElement('td');
|
|
124
|
+
detailCell.colSpan = '7';
|
|
125
|
+
detailCell.style.padding = '0';
|
|
126
|
+
detailCell.style.backgroundColor = '#f8f9fa';
|
|
127
|
+
|
|
128
|
+
// Create enhanced detail panel container
|
|
129
|
+
const detailPanelContainer = document.createElement('div');
|
|
130
|
+
detailPanelContainer.className = 'detail-panel-container';
|
|
131
|
+
detailPanelContainer.style.cssText = `
|
|
132
|
+
padding: 20px;
|
|
133
|
+
min-height: 200px;
|
|
134
|
+
`;
|
|
135
|
+
|
|
136
|
+
// Initialize the new WorkerExpandPanel component
|
|
137
|
+
WorkerExpandPanel.create(worker, detailPanelContainer);
|
|
138
|
+
|
|
139
|
+
detailCell.appendChild(detailPanelContainer);
|
|
140
|
+
detailRow.appendChild(detailCell);
|
|
141
|
+
|
|
142
|
+
return detailRow;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Enhanced worker row with new styling
|
|
147
|
+
*/
|
|
148
|
+
function createWorkerRowEnhanced(worker) {
|
|
149
|
+
const row = document.createElement('tr');
|
|
150
|
+
const detailsId = worker.name.replaceAll(/[^a-z0-9]/gi, '-');
|
|
151
|
+
|
|
152
|
+
// Status cell with enhanced styling
|
|
153
|
+
const statusCell = document.createElement('td');
|
|
154
|
+
const statusBadge = document.createElement('span');
|
|
155
|
+
statusBadge.className = `status-badge status-${worker.status}`;
|
|
156
|
+
statusBadge.textContent = worker.status;
|
|
157
|
+
statusBadge.style.cssText = `
|
|
158
|
+
padding: 4px 8px;
|
|
159
|
+
border-radius: 12px;
|
|
160
|
+
font-size: 12px;
|
|
161
|
+
font-weight: 500;
|
|
162
|
+
text-transform: uppercase;
|
|
163
|
+
`;
|
|
164
|
+
statusCell.appendChild(statusBadge);
|
|
165
|
+
|
|
166
|
+
// Name cell
|
|
167
|
+
const nameCell = document.createElement('td');
|
|
168
|
+
nameCell.textContent = worker.name;
|
|
169
|
+
nameCell.style.fontWeight = '500';
|
|
170
|
+
|
|
171
|
+
// Queue cell
|
|
172
|
+
const queueCell = document.createElement('td');
|
|
173
|
+
queueCell.textContent = worker.queueName;
|
|
174
|
+
|
|
175
|
+
// Driver cell
|
|
176
|
+
const driverCell = document.createElement('td');
|
|
177
|
+
driverCell.textContent = worker.driver;
|
|
178
|
+
|
|
179
|
+
// Concurrency cell
|
|
180
|
+
const concurrencyCell = document.createElement('td');
|
|
181
|
+
concurrencyCell.textContent = worker.concurrency || 1;
|
|
182
|
+
|
|
183
|
+
// Auto-start cell
|
|
184
|
+
const autoStartCell = document.createElement('td');
|
|
185
|
+
const autoStartBadge = document.createElement('span');
|
|
186
|
+
autoStartBadge.className = `badge ${worker.autoStart ? 'badge-success' : 'badge-secondary'}`;
|
|
187
|
+
autoStartBadge.textContent = worker.autoStart ? 'Yes' : 'No';
|
|
188
|
+
autoStartBadge.style.cssText = `
|
|
189
|
+
padding: 2px 6px;
|
|
190
|
+
border-radius: 4px;
|
|
191
|
+
font-size: 11px;
|
|
192
|
+
`;
|
|
193
|
+
autoStartCell.appendChild(autoStartBadge);
|
|
194
|
+
|
|
195
|
+
// Actions cell with expand button
|
|
196
|
+
const actionsCell = document.createElement('td');
|
|
197
|
+
const expandBtn = document.createElement('button');
|
|
198
|
+
expandBtn.className = 'btn btn-sm btn-outline-primary expand-btn';
|
|
199
|
+
expandBtn.style.cssText = `
|
|
200
|
+
padding: 4px 8px;
|
|
201
|
+
font-size: 12px;
|
|
202
|
+
`;
|
|
203
|
+
|
|
204
|
+
// Create icon element safely instead of using innerHTML
|
|
205
|
+
const icon = document.createElement('i');
|
|
206
|
+
icon.className = 'fas fa-chevron-down';
|
|
207
|
+
expandBtn.appendChild(icon);
|
|
208
|
+
|
|
209
|
+
expandBtn.addEventListener('click', () => toggleWorkerDetails(detailsId));
|
|
210
|
+
actionsCell.appendChild(expandBtn);
|
|
211
|
+
|
|
212
|
+
row.appendChild(statusCell);
|
|
213
|
+
row.appendChild(nameCell);
|
|
214
|
+
row.appendChild(queueCell);
|
|
215
|
+
row.appendChild(driverCell);
|
|
216
|
+
row.appendChild(concurrencyCell);
|
|
217
|
+
row.appendChild(autoStartCell);
|
|
218
|
+
row.appendChild(actionsCell);
|
|
219
|
+
|
|
220
|
+
return { row, detailsId };
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Toggle worker details with enhanced animation
|
|
225
|
+
*/
|
|
226
|
+
function toggleWorkerDetails(detailsId) {
|
|
227
|
+
const detailRow = document.getElementById(`details-${detailsId}`);
|
|
228
|
+
if (!detailRow) return;
|
|
229
|
+
|
|
230
|
+
const expandBtn =
|
|
231
|
+
document.querySelector(`[onclick*="${detailsId}"]`) || document.querySelector(`.expand-btn`);
|
|
232
|
+
|
|
233
|
+
if (detailRow.style.display === 'none') {
|
|
234
|
+
detailRow.style.display = 'table-row';
|
|
235
|
+
detailRow.classList.add('open');
|
|
236
|
+
if (expandBtn) {
|
|
237
|
+
// Clear existing content safely and add chevron-up icon
|
|
238
|
+
expandBtn.textContent = '';
|
|
239
|
+
const upIcon = document.createElement('i');
|
|
240
|
+
upIcon.className = 'fas fa-chevron-up';
|
|
241
|
+
expandBtn.appendChild(upIcon);
|
|
242
|
+
}
|
|
243
|
+
} else {
|
|
244
|
+
detailRow.style.display = 'none';
|
|
245
|
+
detailRow.classList.remove('open');
|
|
246
|
+
if (expandBtn) {
|
|
247
|
+
// Clear existing content safely and add chevron-down icon
|
|
248
|
+
expandBtn.textContent = '';
|
|
249
|
+
const downIcon = document.createElement('i');
|
|
250
|
+
downIcon.className = 'fas fa-chevron-down';
|
|
251
|
+
expandBtn.appendChild(downIcon);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Get worker card styles
|
|
258
|
+
*/
|
|
259
|
+
function getWorkerCardStyles() {
|
|
260
|
+
return `
|
|
261
|
+
.worker-card {
|
|
262
|
+
border: 1px solid #e5e7eb;
|
|
263
|
+
border-radius: 8px;
|
|
264
|
+
margin-bottom: 8px;
|
|
265
|
+
background: white;
|
|
266
|
+
transition: all 0.2s ease;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.worker-card:hover {
|
|
270
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
.worker-header {
|
|
274
|
+
display: flex;
|
|
275
|
+
justify-content: space-between;
|
|
276
|
+
align-items: center;
|
|
277
|
+
padding: 16px;
|
|
278
|
+
cursor: pointer;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
.worker-info {
|
|
282
|
+
display: flex;
|
|
283
|
+
align-items: center;
|
|
284
|
+
gap: 12px;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.worker-name {
|
|
288
|
+
margin: 0;
|
|
289
|
+
font-size: 16px;
|
|
290
|
+
font-weight: 600;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.worker-status {
|
|
294
|
+
padding: 4px 8px;
|
|
295
|
+
border-radius: 12px;
|
|
296
|
+
font-size: 12px;
|
|
297
|
+
font-weight: 500;
|
|
298
|
+
text-transform: uppercase;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
.status-running { background: #d1fae5; color: #065f46; }
|
|
302
|
+
.status-stopped { background: #fee2e2; color: #991b1b; }
|
|
303
|
+
.status-failed { background: #fef2f2; color: #7f1d1d; }
|
|
304
|
+
.status-paused { background: #fef3c7; color: #92400e; }
|
|
305
|
+
`;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Get worker actions and expand panel styles
|
|
310
|
+
*/
|
|
311
|
+
function getWorkerActionsStyles() {
|
|
312
|
+
return `
|
|
313
|
+
.worker-actions {
|
|
314
|
+
display: flex;
|
|
315
|
+
gap: 8px;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.expand-btn {
|
|
319
|
+
background: none;
|
|
320
|
+
border: none;
|
|
321
|
+
cursor: pointer;
|
|
322
|
+
padding: 4px;
|
|
323
|
+
border-radius: 4px;
|
|
324
|
+
transition: transform 0.2s ease;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
.expand-btn:hover {
|
|
328
|
+
background: #f3f4f6;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.expand-btn.expanded {
|
|
332
|
+
transform: rotate(180deg);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.worker-expand-panel {
|
|
336
|
+
border-top: 1px solid #e5e7eb;
|
|
337
|
+
background: #f9fafb;
|
|
338
|
+
padding: 16px;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.config-summary,
|
|
342
|
+
.worker-metrics {
|
|
343
|
+
margin-bottom: 16px;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.config-grid,
|
|
347
|
+
.metrics-grid {
|
|
348
|
+
display: grid;
|
|
349
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
350
|
+
gap: 12px;
|
|
351
|
+
margin-top: 8px;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.config-item,
|
|
355
|
+
.metric-item {
|
|
356
|
+
display: flex;
|
|
357
|
+
justify-content: space-between;
|
|
358
|
+
padding: 8px;
|
|
359
|
+
background: white;
|
|
360
|
+
border-radius: 4px;
|
|
361
|
+
border: 1px solid #e5e7eb;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.config-label,
|
|
365
|
+
.metric-label {
|
|
366
|
+
font-weight: 500;
|
|
367
|
+
color: #374151;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.config-value,
|
|
371
|
+
.metric-value {
|
|
372
|
+
color: #6b7280;
|
|
373
|
+
}
|
|
374
|
+
`;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Get modal styles for JSON viewer/editor
|
|
379
|
+
*/
|
|
380
|
+
function getModalStyles() {
|
|
381
|
+
return `
|
|
382
|
+
.modal-overlay {
|
|
383
|
+
position: fixed;
|
|
384
|
+
top: 0;
|
|
385
|
+
left: 0;
|
|
386
|
+
right: 0;
|
|
387
|
+
bottom: 0;
|
|
388
|
+
background: rgba(0, 0, 0, 0.5);
|
|
389
|
+
display: flex;
|
|
390
|
+
align-items: center;
|
|
391
|
+
justify-content: center;
|
|
392
|
+
z-index: 1000;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.modal {
|
|
396
|
+
background: white;
|
|
397
|
+
border-radius: 8px;
|
|
398
|
+
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
|
|
399
|
+
max-width: 90vw;
|
|
400
|
+
max-height: 90vh;
|
|
401
|
+
overflow: hidden;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.modal-header {
|
|
405
|
+
display: flex;
|
|
406
|
+
justify-content: space-between;
|
|
407
|
+
align-items: center;
|
|
408
|
+
padding: 16px;
|
|
409
|
+
border-bottom: 1px solid #e5e7eb;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.modal-title {
|
|
413
|
+
margin: 0;
|
|
414
|
+
font-size: 18px;
|
|
415
|
+
font-weight: 600;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.modal-body {
|
|
419
|
+
padding: 16px;
|
|
420
|
+
overflow-y: auto;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
.modal-footer {
|
|
424
|
+
display: flex;
|
|
425
|
+
justify-content: flex-end;
|
|
426
|
+
gap: 8px;
|
|
427
|
+
padding: 16px;
|
|
428
|
+
border-top: 1px solid #e5e7eb;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.json-viewer-modal,
|
|
432
|
+
.json-editor-modal {
|
|
433
|
+
font-family: Monaco, Menlo, 'Ubuntu Mono', monospace;
|
|
434
|
+
}
|
|
435
|
+
`;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Get JSON syntax highlighting styles
|
|
440
|
+
*/
|
|
441
|
+
function getJsonHighlightStyles() {
|
|
442
|
+
return `
|
|
443
|
+
.json-string { color: #0d9488; }
|
|
444
|
+
.json-number { color: #2563eb; }
|
|
445
|
+
.json-boolean { color: #dc2626; }
|
|
446
|
+
.json-null { color: #6b7280; }
|
|
447
|
+
.json-key { color: #7c3aed; }
|
|
448
|
+
|
|
449
|
+
mark {
|
|
450
|
+
background: #fef3c7;
|
|
451
|
+
padding: 1px 2px;
|
|
452
|
+
border-radius: 2px;
|
|
453
|
+
}
|
|
454
|
+
`;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* Get button and notification styles
|
|
459
|
+
*/
|
|
460
|
+
function getButtonAndNotificationStyles() {
|
|
461
|
+
return `
|
|
462
|
+
.btn {
|
|
463
|
+
padding: 8px 16px;
|
|
464
|
+
border: 1px solid #d1d5db;
|
|
465
|
+
border-radius: 4px;
|
|
466
|
+
background: white;
|
|
467
|
+
cursor: pointer;
|
|
468
|
+
font-size: 14px;
|
|
469
|
+
transition: all 0.2s ease;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
.btn:hover {
|
|
473
|
+
background: #f9fafb;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
.btn-primary {
|
|
477
|
+
background: #3b82f6;
|
|
478
|
+
color: white;
|
|
479
|
+
border-color: #3b82f6;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
.btn-primary:hover {
|
|
483
|
+
background: #2563eb;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
.btn-secondary {
|
|
487
|
+
background: #6b7280;
|
|
488
|
+
color: white;
|
|
489
|
+
border-color: #6b7280;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
.btn-secondary:hover {
|
|
493
|
+
background: #4b5563;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.btn-sm {
|
|
497
|
+
padding: 4px 8px;
|
|
498
|
+
font-size: 12px;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
.notification {
|
|
502
|
+
position: fixed;
|
|
503
|
+
top: 20px;
|
|
504
|
+
right: 20px;
|
|
505
|
+
padding: 12px 16px;
|
|
506
|
+
border-radius: 4px;
|
|
507
|
+
z-index: 2000;
|
|
508
|
+
animation: slideIn 0.3s ease;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
@keyframes slideIn {
|
|
512
|
+
from { transform: translateX(100%); opacity: 0; }
|
|
513
|
+
to { transform: translateX(0); opacity: 1; }
|
|
514
|
+
}
|
|
515
|
+
`;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Add CSS styles for the enhanced components
|
|
520
|
+
*/
|
|
521
|
+
function addEnhancedStyles() {
|
|
522
|
+
const styleId = 'worker-ui-enhanced-styles';
|
|
523
|
+
if (document.getElementById(styleId)) return;
|
|
524
|
+
|
|
525
|
+
const style = document.createElement('style');
|
|
526
|
+
style.id = styleId;
|
|
527
|
+
style.textContent = [
|
|
528
|
+
getWorkerCardStyles(),
|
|
529
|
+
getWorkerActionsStyles(),
|
|
530
|
+
getModalStyles(),
|
|
531
|
+
getJsonHighlightStyles(),
|
|
532
|
+
getButtonAndNotificationStyles(),
|
|
533
|
+
].join('\n');
|
|
534
|
+
|
|
535
|
+
document.head.appendChild(style);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Initialize the enhanced UI
|
|
540
|
+
*/
|
|
541
|
+
function initializeEnhancedUI() {
|
|
542
|
+
// Add enhanced styles
|
|
543
|
+
addEnhancedStyles();
|
|
544
|
+
|
|
545
|
+
// Override the createDetailRow function
|
|
546
|
+
globalThis.window.createDetailRow = createDetailRowEnhanced;
|
|
547
|
+
|
|
548
|
+
// Override the createWorkerRow function
|
|
549
|
+
globalThis.window.createWorkerRow = createWorkerRowEnhanced;
|
|
550
|
+
|
|
551
|
+
// Make renderWorkersEnhanced globally available
|
|
552
|
+
globalThis.window.renderWorkersEnhanced = renderWorkersEnhanced;
|
|
553
|
+
|
|
554
|
+
console.log('Enhanced Worker UI initialized');
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// Auto-initialize when DOM is ready
|
|
558
|
+
if (document.readyState === 'loading') {
|
|
559
|
+
document.addEventListener('DOMContentLoaded', initializeEnhancedUI);
|
|
560
|
+
} else {
|
|
561
|
+
initializeEnhancedUI();
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// Export for manual initialization
|
|
565
|
+
export { initializeEnhancedUI, renderWorkersEnhanced };
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import type { IRouter } from '@zintrust/core';
|
|
2
|
+
import { Logger, MIME_TYPES, NodeSingletons, Router } from '@zintrust/core';
|
|
3
|
+
|
|
4
|
+
export const uiResolver = async (uiBasePath: string): Promise<string> => {
|
|
5
|
+
// Resolve base path for UI assets
|
|
6
|
+
// const __filename = NodeSingletons.url.fileURLToPath(import.meta.url);
|
|
7
|
+
// const __dirname = NodeSingletons.path.dirname(__filename);
|
|
8
|
+
const uiPath = NodeSingletons.path.resolve(uiBasePath, 'workers/index.html');
|
|
9
|
+
const html = await NodeSingletons.fs.readFile(uiPath, 'utf8');
|
|
10
|
+
|
|
11
|
+
return html;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// MIME type mapping for static files
|
|
15
|
+
const getMimeType = (filePath: string): string => {
|
|
16
|
+
const ext = NodeSingletons.path.extname(filePath).toLowerCase();
|
|
17
|
+
const mimeTypes: Record<string, string> = {
|
|
18
|
+
'.css': MIME_TYPES.CSS,
|
|
19
|
+
'.js': MIME_TYPES.JS,
|
|
20
|
+
'.html': MIME_TYPES.HTML,
|
|
21
|
+
'.json': MIME_TYPES.JSON,
|
|
22
|
+
'.png': MIME_TYPES.PNG,
|
|
23
|
+
'.jpg': MIME_TYPES.JPG,
|
|
24
|
+
'.jpeg': MIME_TYPES.JPG,
|
|
25
|
+
'.gif': MIME_TYPES.GIF,
|
|
26
|
+
'.svg': MIME_TYPES.SVG,
|
|
27
|
+
'.ico': MIME_TYPES.ICO,
|
|
28
|
+
'.ipa': MIME_TYPES.IPA,
|
|
29
|
+
};
|
|
30
|
+
return mimeTypes[ext] || MIME_TYPES.IPA;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
let uiBasePath = '';
|
|
34
|
+
const getUiBase = (): string => {
|
|
35
|
+
// Resolve base path for UI assets
|
|
36
|
+
if (uiBasePath.length > 0) return uiBasePath;
|
|
37
|
+
|
|
38
|
+
const __filename = NodeSingletons.url.fileURLToPath(import.meta.url);
|
|
39
|
+
const __dirname = NodeSingletons.path.dirname(__filename);
|
|
40
|
+
uiBasePath = NodeSingletons.path.resolve(__dirname, '../');
|
|
41
|
+
return uiBasePath;
|
|
42
|
+
};
|
|
43
|
+
const serveStaticFile = async (
|
|
44
|
+
req: { getPath: () => string },
|
|
45
|
+
res: {
|
|
46
|
+
setHeader: (name: string, value: string) => void;
|
|
47
|
+
send: (data: Buffer) => void;
|
|
48
|
+
setStatus: (code: number) => void;
|
|
49
|
+
}
|
|
50
|
+
): Promise<void> => {
|
|
51
|
+
try {
|
|
52
|
+
const filePath = req.getPath();
|
|
53
|
+
const fullPath = NodeSingletons.path.resolve(getUiBase(), filePath.replace(/^\//, ''));
|
|
54
|
+
|
|
55
|
+
// Security check - prevent directory traversal
|
|
56
|
+
if (!fullPath.startsWith(uiBasePath)) {
|
|
57
|
+
res.setStatus(403);
|
|
58
|
+
res.send(Buffer.from('Forbidden'));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const content = await NodeSingletons.fs.readFile(fullPath);
|
|
63
|
+
const mimeType = getMimeType(filePath);
|
|
64
|
+
|
|
65
|
+
res.setHeader('Content-Type', mimeType);
|
|
66
|
+
res.setHeader('Cache-Control', 'public, max-age=3600'); // 1 hour cache
|
|
67
|
+
res.send(content);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
Logger.warn(`Static file not found: ${req.getPath()}`, err);
|
|
70
|
+
res.setStatus(404);
|
|
71
|
+
res.send(Buffer.from('Not Found'));
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Static file serving for workers assets
|
|
76
|
+
export const registerStaticAssets = (router: IRouter, middleware: ReadonlyArray<string>): void => {
|
|
77
|
+
const handler = async (_req: unknown, res: { html: (value: string) => void }): Promise<void> => {
|
|
78
|
+
try {
|
|
79
|
+
const html = await uiResolver(getUiBase());
|
|
80
|
+
res.html(html);
|
|
81
|
+
} catch (err) {
|
|
82
|
+
Logger.error('Failed to load static UI page', err);
|
|
83
|
+
// Fallback to generated dashboard if static file unavailable
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
Router.group(router, '/workers', (r: IRouter) => {
|
|
88
|
+
Router.get(r, '/', handler, { middleware });
|
|
89
|
+
// Serve workers CSS and JS files
|
|
90
|
+
Router.get(r, '/styles.css', serveStaticFile);
|
|
91
|
+
Router.get(r, '/main.js', serveStaticFile);
|
|
92
|
+
Router.get(r, '/:filename', serveStaticFile);
|
|
93
|
+
Router.get(r, '/integration/:filename', serveStaticFile);
|
|
94
|
+
|
|
95
|
+
// Serve components CSS files
|
|
96
|
+
Router.get(r, '/components/styles.css', serveStaticFile);
|
|
97
|
+
Router.get(r, '/components/:filename', serveStaticFile);
|
|
98
|
+
});
|
|
99
|
+
};
|