@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,257 @@
|
|
|
1
|
+
/* eslint-disable no-restricted-syntax */
|
|
2
|
+
/* eslint-disable no-undef */
|
|
3
|
+
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
4
|
+
/**
|
|
5
|
+
* Worker Expand Panel Component
|
|
6
|
+
* Displays detailed worker information with View JSON and Edit buttons
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Create configuration summary element
|
|
11
|
+
* @param {Object} worker - Worker data
|
|
12
|
+
* @returns {HTMLDivElement} Configuration summary element
|
|
13
|
+
*/
|
|
14
|
+
const createConfigSummaryElement = (worker) => {
|
|
15
|
+
const configSummary = document.createElement('div');
|
|
16
|
+
configSummary.className = 'config-summary';
|
|
17
|
+
|
|
18
|
+
const title = document.createElement('h4');
|
|
19
|
+
title.textContent = 'Configuration';
|
|
20
|
+
configSummary.appendChild(title);
|
|
21
|
+
|
|
22
|
+
const configGrid = document.createElement('div');
|
|
23
|
+
configGrid.className = 'config-grid';
|
|
24
|
+
|
|
25
|
+
const configItems = [
|
|
26
|
+
{ label: 'Driver:', value: worker.driver },
|
|
27
|
+
{ label: 'Concurrency:', value: worker.concurrency },
|
|
28
|
+
{ label: 'Auto Start:', value: worker.autoStart ? 'Yes' : 'No' },
|
|
29
|
+
{ label: 'Version:', value: worker.version || 'N/A' },
|
|
30
|
+
{ label: 'Region:', value: worker.region || 'N/A' },
|
|
31
|
+
{ label: 'Created:', value: new Date(worker.createdAt).toLocaleString() },
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
configItems.forEach((item) => {
|
|
35
|
+
const configItem = document.createElement('div');
|
|
36
|
+
configItem.className = 'config-item';
|
|
37
|
+
|
|
38
|
+
const label = document.createElement('label');
|
|
39
|
+
label.textContent = item.label;
|
|
40
|
+
|
|
41
|
+
const span = document.createElement('span');
|
|
42
|
+
span.textContent = item.value;
|
|
43
|
+
|
|
44
|
+
configItem.appendChild(label);
|
|
45
|
+
configItem.appendChild(span);
|
|
46
|
+
configGrid.appendChild(configItem);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
configSummary.appendChild(configGrid);
|
|
50
|
+
return configSummary;
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Create action buttons section
|
|
55
|
+
* @returns {HTMLDivElement} Action buttons element
|
|
56
|
+
*/
|
|
57
|
+
const createActionButtonsSection = () => {
|
|
58
|
+
const actionsSection = document.createElement('div');
|
|
59
|
+
actionsSection.className = 'worker-actions-section';
|
|
60
|
+
|
|
61
|
+
const viewJsonBtn = document.createElement('button');
|
|
62
|
+
viewJsonBtn.className = 'btn btn-secondary view-json-btn';
|
|
63
|
+
viewJsonBtn.textContent = 'View JSON';
|
|
64
|
+
|
|
65
|
+
const editJsonBtn = document.createElement('button');
|
|
66
|
+
editJsonBtn.className = 'btn btn-primary edit-json-btn';
|
|
67
|
+
editJsonBtn.textContent = 'Edit';
|
|
68
|
+
|
|
69
|
+
actionsSection.appendChild(viewJsonBtn);
|
|
70
|
+
actionsSection.appendChild(editJsonBtn);
|
|
71
|
+
|
|
72
|
+
return actionsSection;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Create panel element
|
|
77
|
+
* @param {Object} worker - Worker data
|
|
78
|
+
* @returns {HTMLDivElement} Panel element
|
|
79
|
+
*/
|
|
80
|
+
const createPanelElement = (worker) => {
|
|
81
|
+
const panelElement = document.createElement('div');
|
|
82
|
+
panelElement.className = 'worker-expand-panel';
|
|
83
|
+
|
|
84
|
+
const detailsSection = document.createElement('div');
|
|
85
|
+
detailsSection.className = 'worker-details';
|
|
86
|
+
|
|
87
|
+
const configSummary = createConfigSummaryElement(worker);
|
|
88
|
+
|
|
89
|
+
const actionsSection = createActionButtonsSection();
|
|
90
|
+
|
|
91
|
+
detailsSection.appendChild(configSummary);
|
|
92
|
+
detailsSection.appendChild(actionsSection);
|
|
93
|
+
panelElement.appendChild(detailsSection);
|
|
94
|
+
|
|
95
|
+
const metricsSection = document.createElement('div');
|
|
96
|
+
metricsSection.className = 'worker-metrics';
|
|
97
|
+
metricsSection.innerHTML = `
|
|
98
|
+
<h4>Performance Metrics</h4>
|
|
99
|
+
<div class="metrics-grid">
|
|
100
|
+
<div class="metric-item">
|
|
101
|
+
<label>Status:</label>
|
|
102
|
+
<span class="status-indicator status-${worker.status}">${worker.status}</span>
|
|
103
|
+
</div>
|
|
104
|
+
<div class="metric-item">
|
|
105
|
+
<label>Connection:</label>
|
|
106
|
+
<span class="connection-indicator">${worker.connectionState || 'Unknown'}</span>
|
|
107
|
+
</div>
|
|
108
|
+
<div class="metric-item">
|
|
109
|
+
<label>Last Health Check:</label>
|
|
110
|
+
<span>${worker.lastHealthCheck ? new Date(worker.lastHealthCheck).toLocaleString() : 'Never'}</span>
|
|
111
|
+
</div>
|
|
112
|
+
${
|
|
113
|
+
worker.lastError
|
|
114
|
+
? `
|
|
115
|
+
<div class="metric-item">
|
|
116
|
+
<label>Last Error:</label>
|
|
117
|
+
<span class="error-message">${worker.lastError}</span>
|
|
118
|
+
</div>
|
|
119
|
+
`
|
|
120
|
+
: ''
|
|
121
|
+
}
|
|
122
|
+
</div>
|
|
123
|
+
`;
|
|
124
|
+
panelElement.appendChild(metricsSection);
|
|
125
|
+
|
|
126
|
+
return panelElement;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Show notification message with proper timeout cleanup
|
|
131
|
+
* @param {string} message - Notification message
|
|
132
|
+
* @param {string} type - Notification type
|
|
133
|
+
* @returns {number} Timeout reference for cleanup
|
|
134
|
+
*/
|
|
135
|
+
const showNotification = (message, type = 'info') => {
|
|
136
|
+
const notification = document.createElement('div');
|
|
137
|
+
notification.className = `notification notification-${type}`;
|
|
138
|
+
notification.textContent = message;
|
|
139
|
+
|
|
140
|
+
document.body.appendChild(notification);
|
|
141
|
+
|
|
142
|
+
const timeoutId = setTimeout(() => {
|
|
143
|
+
notification.remove();
|
|
144
|
+
activeTimeouts.delete(timeoutId); // Clean up from global registry
|
|
145
|
+
}, 3000);
|
|
146
|
+
|
|
147
|
+
activeTimeouts.add(timeoutId); // Track timeout for cleanup
|
|
148
|
+
return timeoutId;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Create JSON viewer handler
|
|
153
|
+
* @param {Object} worker - Worker data
|
|
154
|
+
* @returns {Function} View JSON handler
|
|
155
|
+
*/
|
|
156
|
+
const createViewJsonHandler = (worker) => {
|
|
157
|
+
let jsonViewer = null;
|
|
158
|
+
|
|
159
|
+
return () => {
|
|
160
|
+
if (!jsonViewer) {
|
|
161
|
+
jsonViewer = JsonViewer.create();
|
|
162
|
+
}
|
|
163
|
+
jsonViewer.open(worker);
|
|
164
|
+
};
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Create JSON editor handler
|
|
169
|
+
* @param {Object} worker - Worker data
|
|
170
|
+
* @param {Function} render - Render function
|
|
171
|
+
* @returns {Function} Edit JSON handler
|
|
172
|
+
*/
|
|
173
|
+
const createEditJsonHandler = (worker, render) => {
|
|
174
|
+
let jsonEditor = null;
|
|
175
|
+
|
|
176
|
+
return async () => {
|
|
177
|
+
if (!jsonEditor) {
|
|
178
|
+
jsonEditor = JsonEditor.create({
|
|
179
|
+
onSave: async (updatedWorker) => {
|
|
180
|
+
try {
|
|
181
|
+
const response = await workerApi.updateWorker(worker.id, updatedWorker);
|
|
182
|
+
|
|
183
|
+
if (response.success) {
|
|
184
|
+
Object.assign(worker, response.data);
|
|
185
|
+
render();
|
|
186
|
+
showNotification('Worker updated successfully', 'success');
|
|
187
|
+
} else {
|
|
188
|
+
showNotification(response.error || 'Failed to update worker', 'error');
|
|
189
|
+
}
|
|
190
|
+
} catch (error) {
|
|
191
|
+
showNotification('Error updating worker: ' + error.message, 'error');
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
jsonEditor.open(worker);
|
|
197
|
+
};
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Create a worker expand panel
|
|
202
|
+
*/
|
|
203
|
+
const createWorkerExpandPanel = (worker, container) => {
|
|
204
|
+
let element;
|
|
205
|
+
const jsonViewer = null;
|
|
206
|
+
const jsonEditor = null;
|
|
207
|
+
|
|
208
|
+
const render = () => {
|
|
209
|
+
if (element) {
|
|
210
|
+
element.remove();
|
|
211
|
+
}
|
|
212
|
+
element = createPanelElement(worker);
|
|
213
|
+
container.appendChild(element);
|
|
214
|
+
|
|
215
|
+
// Create and attach event listeners after element is created
|
|
216
|
+
const handleViewJson = createViewJsonHandler(worker);
|
|
217
|
+
const handleEditJson = createEditJsonHandler(worker, render);
|
|
218
|
+
|
|
219
|
+
// Search within the current panel element, not the entire document
|
|
220
|
+
const viewJsonBtn = element?.querySelector('.view-json-btn');
|
|
221
|
+
const editJsonBtn = element?.querySelector('.edit-json-btn');
|
|
222
|
+
|
|
223
|
+
if (viewJsonBtn) {
|
|
224
|
+
viewJsonBtn.addEventListener('click', handleViewJson);
|
|
225
|
+
}
|
|
226
|
+
if (editJsonBtn) {
|
|
227
|
+
editJsonBtn.addEventListener('click', handleEditJson);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const destroy = () => {
|
|
232
|
+
if (jsonViewer) {
|
|
233
|
+
jsonViewer.destroy();
|
|
234
|
+
}
|
|
235
|
+
if (jsonEditor) {
|
|
236
|
+
jsonEditor.destroy();
|
|
237
|
+
}
|
|
238
|
+
element.remove();
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// Initialize
|
|
242
|
+
render();
|
|
243
|
+
|
|
244
|
+
return {
|
|
245
|
+
element,
|
|
246
|
+
worker,
|
|
247
|
+
render,
|
|
248
|
+
destroy,
|
|
249
|
+
};
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Sealed namespace for WorkerExpandPanel utilities
|
|
254
|
+
*/
|
|
255
|
+
export const WorkerExpandPanel = Object.freeze({
|
|
256
|
+
create: createWorkerExpandPanel,
|
|
257
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
2
|
+
/* eslint-disable no-restricted-syntax */
|
|
3
|
+
|
|
4
|
+
// Helper function for retry delay
|
|
5
|
+
function delay(ms) {
|
|
6
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function get(path, options = {}) {
|
|
10
|
+
const retries = options.retry ?? 2;
|
|
11
|
+
const backoff = options.backoff ?? 200;
|
|
12
|
+
|
|
13
|
+
async function fetchWithRetry(attempt = 0) {
|
|
14
|
+
try {
|
|
15
|
+
const res = await fetch(path, { cache: 'no-store' });
|
|
16
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
17
|
+
return await res.json();
|
|
18
|
+
} catch (err) {
|
|
19
|
+
if (attempt >= retries) throw err;
|
|
20
|
+
|
|
21
|
+
// Wait before retry (exponential backoff)
|
|
22
|
+
const waitTime = backoff * (attempt + 1);
|
|
23
|
+
await delay(waitTime);
|
|
24
|
+
|
|
25
|
+
// Recursive call for next attempt
|
|
26
|
+
return fetchWithRetry(attempt + 1);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return fetchWithRetry();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export async function post(path, body = {}, options = {}) {
|
|
34
|
+
const res = await fetch(path, {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
headers: { 'Content-Type': 'application/json' },
|
|
37
|
+
body: JSON.stringify(body),
|
|
38
|
+
...options,
|
|
39
|
+
});
|
|
40
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
41
|
+
return res.json().catch(() => ({ ok: res.ok }));
|
|
42
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
2
|
+
/* global document */
|
|
3
|
+
|
|
4
|
+
export function renderSlaScorecard(container, payload) {
|
|
5
|
+
if (!container) return;
|
|
6
|
+
const status = payload?.status || 'unknown';
|
|
7
|
+
const score = payload?.score ?? '-';
|
|
8
|
+
|
|
9
|
+
// Clear existing content safely
|
|
10
|
+
while (container.firstChild) {
|
|
11
|
+
container.firstChild.remove();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// Create main card element
|
|
15
|
+
const card = document.createElement('div');
|
|
16
|
+
card.className = `ui-sla-card sla-${status}`;
|
|
17
|
+
|
|
18
|
+
// Create score element
|
|
19
|
+
const scoreEl = document.createElement('div');
|
|
20
|
+
scoreEl.className = 'ui-sla-score';
|
|
21
|
+
scoreEl.textContent = score; // Safe: textContent doesn't execute HTML
|
|
22
|
+
|
|
23
|
+
// Create status element
|
|
24
|
+
const statusEl = document.createElement('div');
|
|
25
|
+
statusEl.className = 'ui-sla-status';
|
|
26
|
+
statusEl.textContent = String(status).toUpperCase(); // Safe: textContent
|
|
27
|
+
|
|
28
|
+
// Assemble the card
|
|
29
|
+
card.appendChild(scoreEl);
|
|
30
|
+
card.appendChild(statusEl);
|
|
31
|
+
container.appendChild(card);
|
|
32
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--zt-bg: #0b1220;
|
|
3
|
+
--zt-card: #0f1724;
|
|
4
|
+
--zt-text: #e6eef6;
|
|
5
|
+
--zt-muted: #94a3b8;
|
|
6
|
+
--zt-accent: #38bdf8;
|
|
7
|
+
}
|
|
8
|
+
.ui-loading {
|
|
9
|
+
color: var(--zt-muted);
|
|
10
|
+
padding: 12px;
|
|
11
|
+
}
|
|
12
|
+
.ui-detail-row td {
|
|
13
|
+
background: var(--zt-card);
|
|
14
|
+
padding: 12px;
|
|
15
|
+
border-top: 1px solid rgba(255, 255, 255, 0.03);
|
|
16
|
+
}
|
|
17
|
+
.ui-sla-card {
|
|
18
|
+
border-radius: 8px;
|
|
19
|
+
padding: 12px;
|
|
20
|
+
background: linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(0, 0, 0, 0.08));
|
|
21
|
+
display: inline-block;
|
|
22
|
+
}
|
|
23
|
+
.ui-sla-score {
|
|
24
|
+
font-size: 20px;
|
|
25
|
+
font-weight: 800;
|
|
26
|
+
}
|
|
27
|
+
.ui-sla-status {
|
|
28
|
+
font-size: 11px;
|
|
29
|
+
color: var(--zt-muted);
|
|
30
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/* eslint-disable no-restricted-syntax */
|
|
2
|
+
/* eslint-disable no-undef */
|
|
3
|
+
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
4
|
+
|
|
5
|
+
function removeDetail(detailsEl) {
|
|
6
|
+
if (detailsEl) detailsEl.remove();
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function renderRow(rowEl, detailHtml) {
|
|
10
|
+
const details = document.createElement('tr');
|
|
11
|
+
details.className = 'ui-detail-row';
|
|
12
|
+
const td = document.createElement('td');
|
|
13
|
+
td.colSpan = rowEl.children.length;
|
|
14
|
+
td.innerHTML = detailHtml || '';
|
|
15
|
+
details.appendChild(td);
|
|
16
|
+
rowEl.after(details);
|
|
17
|
+
return details;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function createTableExpander(container) {
|
|
21
|
+
if (!container) throw new Error('container required');
|
|
22
|
+
|
|
23
|
+
function toggle(rowEl, loader) {
|
|
24
|
+
const next = rowEl.nextElementSibling;
|
|
25
|
+
if (next && next.classList.contains('ui-detail-row')) {
|
|
26
|
+
removeDetail(next);
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const placeholder = renderRow(rowEl, loader || '<div class="ui-loading">Loading...</div>');
|
|
30
|
+
return placeholder;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return Object.freeze({ toggle, renderRow, removeDetail });
|
|
34
|
+
}
|