@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,670 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
|
3
|
+
/* eslint-disable no-undef */
|
|
4
|
+
/**
|
|
5
|
+
* JSON Editor Modal Component
|
|
6
|
+
* Allows editing JSON data with real-time validation
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Create modal element with header, body, and footer
|
|
11
|
+
* @param {Object} config - Configuration object
|
|
12
|
+
* @param {Function} formatJson - Format JSON function
|
|
13
|
+
* @param {Function} validateJson - Validate JSON function
|
|
14
|
+
* @param {Function} handleSave - Save handler function
|
|
15
|
+
* @param {Function} handleClose - Close handler function
|
|
16
|
+
* @returns {HTMLDivElement} Modal element
|
|
17
|
+
*/
|
|
18
|
+
const createModalElement = (config, formatJson, validateJson, handleSave, handleClose) => {
|
|
19
|
+
const modal = document.createElement('div');
|
|
20
|
+
modal.className = `json-editor-modal json-editor-${config.theme}`;
|
|
21
|
+
modal.style.display = 'none';
|
|
22
|
+
modal.style.position = 'fixed';
|
|
23
|
+
modal.style.top = '0';
|
|
24
|
+
modal.style.left = '0';
|
|
25
|
+
modal.style.width = '100%';
|
|
26
|
+
modal.style.height = '100%';
|
|
27
|
+
modal.style.zIndex = '1000';
|
|
28
|
+
|
|
29
|
+
const modalContent = document.createElement('div');
|
|
30
|
+
modalContent.className = 'modal-content';
|
|
31
|
+
modalContent.style.position = 'relative';
|
|
32
|
+
modalContent.style.backgroundColor = '#fff';
|
|
33
|
+
modalContent.style.width = config.width;
|
|
34
|
+
modalContent.style.height = config.height;
|
|
35
|
+
modalContent.style.margin = '30px auto';
|
|
36
|
+
modalContent.style.borderRadius = '8px';
|
|
37
|
+
modalContent.style.boxShadow = '0 4px 20px rgba(0,0,0,0.15)';
|
|
38
|
+
modalContent.style.display = 'flex';
|
|
39
|
+
modalContent.style.flexDirection = 'column';
|
|
40
|
+
|
|
41
|
+
// Create header
|
|
42
|
+
const modalHeader = createModalHeader(config, formatJson, handleClose);
|
|
43
|
+
modalContent.appendChild(modalHeader);
|
|
44
|
+
|
|
45
|
+
// Create body
|
|
46
|
+
const modalBody = createModalBody(config, validateJson);
|
|
47
|
+
modalContent.appendChild(modalBody);
|
|
48
|
+
|
|
49
|
+
// Create footer
|
|
50
|
+
const modalFooter = createModalFooter(handleSave, handleClose);
|
|
51
|
+
modalContent.appendChild(modalFooter);
|
|
52
|
+
|
|
53
|
+
modal.appendChild(modalContent);
|
|
54
|
+
return modal;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Create modal header with title and actions
|
|
59
|
+
* @param {Object} config - Configuration object
|
|
60
|
+
* @param {Function} formatJson - Format JSON function
|
|
61
|
+
* @param {Function} handleClose - Close handler function
|
|
62
|
+
* @returns {HTMLDivElement} Modal header element
|
|
63
|
+
*/
|
|
64
|
+
const createModalHeader = (config, formatJson, handleClose) => {
|
|
65
|
+
const modalHeader = document.createElement('div');
|
|
66
|
+
modalHeader.className = 'modal-header';
|
|
67
|
+
modalHeader.style.padding = '16px 20px';
|
|
68
|
+
modalHeader.style.borderBottom = '1px solid #e5e7eb';
|
|
69
|
+
modalHeader.style.display = 'flex';
|
|
70
|
+
modalHeader.style.justifyContent = 'space-between';
|
|
71
|
+
modalHeader.style.alignItems = 'center';
|
|
72
|
+
|
|
73
|
+
const title = document.createElement('h3');
|
|
74
|
+
title.textContent = config.title;
|
|
75
|
+
title.style.margin = '0';
|
|
76
|
+
title.style.fontSize = '18px';
|
|
77
|
+
title.style.fontWeight = '600';
|
|
78
|
+
|
|
79
|
+
const headerActions = document.createElement('div');
|
|
80
|
+
headerActions.style.display = 'flex';
|
|
81
|
+
headerActions.style.gap = '8px';
|
|
82
|
+
|
|
83
|
+
const formatBtn = document.createElement('button');
|
|
84
|
+
formatBtn.className = 'btn btn-sm btn-secondary format-btn';
|
|
85
|
+
|
|
86
|
+
const formatIcon = document.createElement('i');
|
|
87
|
+
formatIcon.className = 'fas fa-code';
|
|
88
|
+
formatBtn.appendChild(formatIcon);
|
|
89
|
+
formatBtn.appendChild(document.createTextNode(' Format'));
|
|
90
|
+
formatBtn.addEventListener('click', formatJson);
|
|
91
|
+
|
|
92
|
+
const validateBtn = document.createElement('button');
|
|
93
|
+
validateBtn.className = 'btn btn-sm btn-info validate-btn';
|
|
94
|
+
|
|
95
|
+
const validateIcon = document.createElement('i');
|
|
96
|
+
validateIcon.className = 'fas fa-check';
|
|
97
|
+
validateBtn.appendChild(validateIcon);
|
|
98
|
+
validateBtn.appendChild(document.createTextNode(' Validate'));
|
|
99
|
+
validateBtn.addEventListener('click', validateJson);
|
|
100
|
+
|
|
101
|
+
if (config.closable) {
|
|
102
|
+
const closeBtn = document.createElement('button');
|
|
103
|
+
closeBtn.className = 'btn btn-sm btn-secondary close-btn';
|
|
104
|
+
|
|
105
|
+
const closeIcon = document.createElement('i');
|
|
106
|
+
closeIcon.className = 'fas fa-times';
|
|
107
|
+
closeBtn.appendChild(closeIcon);
|
|
108
|
+
closeBtn.addEventListener('click', handleClose);
|
|
109
|
+
headerActions.appendChild(closeBtn);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
headerActions.appendChild(formatBtn);
|
|
113
|
+
headerActions.appendChild(validateBtn);
|
|
114
|
+
|
|
115
|
+
modalHeader.appendChild(title);
|
|
116
|
+
modalHeader.appendChild(headerActions);
|
|
117
|
+
|
|
118
|
+
return modalHeader;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Create modal body with textarea and validation container
|
|
123
|
+
* @param {Object} config - Configuration object
|
|
124
|
+
* @param {Function} validateJson - Validate JSON function
|
|
125
|
+
* @returns {HTMLDivElement} Modal body element
|
|
126
|
+
*/
|
|
127
|
+
const createModalBody = (config, validateJson) => {
|
|
128
|
+
const modalBody = document.createElement('div');
|
|
129
|
+
modalBody.className = 'modal-body';
|
|
130
|
+
modalBody.style.padding = '16px';
|
|
131
|
+
modalBody.style.flex = '1';
|
|
132
|
+
modalBody.style.overflow = 'hidden';
|
|
133
|
+
modalBody.style.display = 'flex';
|
|
134
|
+
modalBody.style.flexDirection = 'column';
|
|
135
|
+
|
|
136
|
+
const textarea = document.createElement('textarea');
|
|
137
|
+
textarea.className = 'json-editor-textarea';
|
|
138
|
+
textarea.style.width = '100%';
|
|
139
|
+
textarea.style.height = '100%';
|
|
140
|
+
textarea.style.padding = '12px';
|
|
141
|
+
textarea.style.border = '1px solid #d1d5db';
|
|
142
|
+
textarea.style.borderRadius = '4px';
|
|
143
|
+
textarea.style.fontFamily = 'Monaco, Menlo, "Ubuntu Mono", monospace';
|
|
144
|
+
textarea.style.fontSize = `${config.fontSize}px`;
|
|
145
|
+
textarea.style.lineHeight = '1.4';
|
|
146
|
+
textarea.style.resize = 'vertical';
|
|
147
|
+
textarea.style.outline = 'none';
|
|
148
|
+
textarea.style.wordWrap = config.wordWrap ? 'break-word' : 'normal';
|
|
149
|
+
|
|
150
|
+
if (config.validateOnChange) {
|
|
151
|
+
textarea.addEventListener('input', validateJson);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const validationContainer = document.createElement('div');
|
|
155
|
+
validationContainer.className = 'validation-container';
|
|
156
|
+
validationContainer.style.marginTop = '12px';
|
|
157
|
+
validationContainer.style.padding = '12px';
|
|
158
|
+
validationContainer.style.borderRadius = '4px';
|
|
159
|
+
validationContainer.style.border = '1px solid #d1d5db';
|
|
160
|
+
validationContainer.style.display = 'none';
|
|
161
|
+
|
|
162
|
+
const validationContent = document.createElement('div');
|
|
163
|
+
validationContent.className = 'validation-content';
|
|
164
|
+
validationContent.style.fontSize = '13px';
|
|
165
|
+
validationContent.style.lineHeight = '1.4';
|
|
166
|
+
|
|
167
|
+
validationContainer.appendChild(validationContent);
|
|
168
|
+
modalBody.appendChild(textarea);
|
|
169
|
+
modalBody.appendChild(validationContainer);
|
|
170
|
+
|
|
171
|
+
return modalBody;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Create modal footer with action buttons
|
|
176
|
+
* @param {Function} handleSave - Save handler function
|
|
177
|
+
* @param {Function} handleClose - Close handler function
|
|
178
|
+
* @returns {HTMLDivElement} Modal footer element
|
|
179
|
+
*/
|
|
180
|
+
const createModalFooter = (handleSave, handleClose) => {
|
|
181
|
+
const modalFooter = document.createElement('div');
|
|
182
|
+
modalFooter.className = 'modal-footer';
|
|
183
|
+
modalFooter.style.display = 'flex';
|
|
184
|
+
modalFooter.style.justifyContent = 'flex-end';
|
|
185
|
+
modalFooter.style.gap = '8px';
|
|
186
|
+
modalFooter.style.padding = '16px';
|
|
187
|
+
modalFooter.style.borderTop = '1px solid #e5e7eb';
|
|
188
|
+
|
|
189
|
+
const cancelBtn = document.createElement('button');
|
|
190
|
+
cancelBtn.className = 'btn btn-secondary';
|
|
191
|
+
cancelBtn.textContent = 'Cancel';
|
|
192
|
+
cancelBtn.addEventListener('click', handleClose);
|
|
193
|
+
|
|
194
|
+
const saveBtn = document.createElement('button');
|
|
195
|
+
saveBtn.className = 'btn btn-primary save-btn';
|
|
196
|
+
|
|
197
|
+
const saveIcon = document.createElement('i');
|
|
198
|
+
saveIcon.className = 'fas fa-save';
|
|
199
|
+
saveBtn.appendChild(saveIcon);
|
|
200
|
+
saveBtn.appendChild(document.createTextNode(' Save'));
|
|
201
|
+
saveBtn.addEventListener('click', handleSave);
|
|
202
|
+
|
|
203
|
+
modalFooter.appendChild(cancelBtn);
|
|
204
|
+
modalFooter.appendChild(saveBtn);
|
|
205
|
+
|
|
206
|
+
return modalFooter;
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Create validation success message
|
|
211
|
+
* @param {HTMLElement} validationContent - Validation content element
|
|
212
|
+
* @returns {void}
|
|
213
|
+
*/
|
|
214
|
+
const createValidationSuccess = (validationContent) => {
|
|
215
|
+
const successDiv = document.createElement('div');
|
|
216
|
+
successDiv.style.color = '#10b981';
|
|
217
|
+
successDiv.style.fontWeight = '600';
|
|
218
|
+
|
|
219
|
+
const successIcon = document.createElement('i');
|
|
220
|
+
successIcon.className = 'fas fa-check-circle';
|
|
221
|
+
successDiv.appendChild(successIcon);
|
|
222
|
+
successDiv.appendChild(document.createTextNode(' Valid JSON and worker data'));
|
|
223
|
+
|
|
224
|
+
validationContent.appendChild(successDiv);
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Create validation error messages
|
|
229
|
+
* @param {HTMLElement} validationContent - Validation content element
|
|
230
|
+
* @param {Array} errors - Array of error objects
|
|
231
|
+
* @returns {void}
|
|
232
|
+
*/
|
|
233
|
+
const createValidationErrors = (validationContent, errors) => {
|
|
234
|
+
const errorHeader = document.createElement('div');
|
|
235
|
+
errorHeader.style.color = '#ef4444';
|
|
236
|
+
errorHeader.style.fontWeight = '600';
|
|
237
|
+
errorHeader.style.marginBottom = '8px';
|
|
238
|
+
|
|
239
|
+
const errorIcon = document.createElement('i');
|
|
240
|
+
errorIcon.className = 'fas fa-exclamation-triangle';
|
|
241
|
+
errorHeader.appendChild(errorIcon);
|
|
242
|
+
errorHeader.appendChild(document.createTextNode(' Validation Errors:'));
|
|
243
|
+
|
|
244
|
+
validationContent.appendChild(errorHeader);
|
|
245
|
+
|
|
246
|
+
errors.forEach((error) => {
|
|
247
|
+
const errorDiv = document.createElement('div');
|
|
248
|
+
errorDiv.style.color = '#ef4444';
|
|
249
|
+
errorDiv.style.marginBottom = '4px';
|
|
250
|
+
errorDiv.textContent = `• ${error.path}: ${error.message}`;
|
|
251
|
+
validationContent.appendChild(errorDiv);
|
|
252
|
+
});
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Create JSON parse error message
|
|
257
|
+
* @param {HTMLElement} validationContent - Validation content element
|
|
258
|
+
* @param {string} errorMessage - Error message
|
|
259
|
+
* @returns {void}
|
|
260
|
+
*/
|
|
261
|
+
const createParseError = (validationContent, errorMessage) => {
|
|
262
|
+
const invalidDiv = document.createElement('div');
|
|
263
|
+
invalidDiv.style.color = '#ef4444';
|
|
264
|
+
invalidDiv.style.fontWeight = '600';
|
|
265
|
+
|
|
266
|
+
const invalidIcon = document.createElement('i');
|
|
267
|
+
invalidIcon.className = 'fas fa-exclamation-circle';
|
|
268
|
+
invalidDiv.appendChild(invalidIcon);
|
|
269
|
+
invalidDiv.appendChild(document.createTextNode(` Invalid JSON: ${errorMessage}`));
|
|
270
|
+
|
|
271
|
+
validationContent.appendChild(invalidDiv);
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Clear validation content
|
|
276
|
+
* @param {HTMLElement} validationContent - Validation content element
|
|
277
|
+
* @returns {void}
|
|
278
|
+
*/
|
|
279
|
+
const clearValidationContent = (validationContent) => {
|
|
280
|
+
while (validationContent.firstChild) {
|
|
281
|
+
validationContent.firstChild.remove();
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Format JSON in textarea
|
|
287
|
+
* @param {HTMLElement} element - Modal element
|
|
288
|
+
* @param {Function} validateJson - Validate function
|
|
289
|
+
* @returns {void}
|
|
290
|
+
*/
|
|
291
|
+
const createFormatHandler = (element, validateJson) => {
|
|
292
|
+
return () => {
|
|
293
|
+
const textarea = element.querySelector('.json-editor-textarea');
|
|
294
|
+
try {
|
|
295
|
+
const data = JSON.parse(textarea.value);
|
|
296
|
+
textarea.value = JSON.stringify(data, null, 2);
|
|
297
|
+
} catch (error) {
|
|
298
|
+
console.log('error :', error);
|
|
299
|
+
// Show validation error
|
|
300
|
+
validateJson();
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Create JSON validator function
|
|
307
|
+
* @param {HTMLElement} element - Modal element
|
|
308
|
+
* @returns {Function} Validator function
|
|
309
|
+
*/
|
|
310
|
+
const createValidator = (element) => {
|
|
311
|
+
return () => {
|
|
312
|
+
const textarea = element.querySelector('.json-editor-textarea');
|
|
313
|
+
const validationContainer = element.querySelector('.validation-container');
|
|
314
|
+
const validationContent = element.querySelector('.validation-content');
|
|
315
|
+
|
|
316
|
+
try {
|
|
317
|
+
const data = JSON.parse(textarea.value);
|
|
318
|
+
const validationResult = validateWorkerData(data);
|
|
319
|
+
|
|
320
|
+
validationContainer.style.display = 'block';
|
|
321
|
+
clearValidationContent(validationContent);
|
|
322
|
+
|
|
323
|
+
if (validationResult.isValid) {
|
|
324
|
+
createValidationSuccess(validationContent);
|
|
325
|
+
} else {
|
|
326
|
+
createValidationErrors(validationContent, validationResult.errors);
|
|
327
|
+
}
|
|
328
|
+
} catch (error) {
|
|
329
|
+
validationContainer.style.display = 'block';
|
|
330
|
+
clearValidationContent(validationContent);
|
|
331
|
+
createParseError(validationContent, error.message);
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Create save handler
|
|
338
|
+
* @param {HTMLElement} element - Modal element
|
|
339
|
+
* @param {Function} onSaveCallback - Save callback function
|
|
340
|
+
* @param {Function} validateJson - Validate function
|
|
341
|
+
* @param {Function} close - Close function
|
|
342
|
+
* @returns {Function} Save handler function
|
|
343
|
+
*/
|
|
344
|
+
const createSaveHandler = (element, onSaveCallback, validateJson, close) => {
|
|
345
|
+
return () => {
|
|
346
|
+
const textarea = element.querySelector('.json-editor-textarea');
|
|
347
|
+
try {
|
|
348
|
+
const data = JSON.parse(textarea.value);
|
|
349
|
+
const validationResult = validateWorkerData(data);
|
|
350
|
+
|
|
351
|
+
if (validationResult.isValid) {
|
|
352
|
+
if (onSaveCallback) {
|
|
353
|
+
onSaveCallback(data);
|
|
354
|
+
}
|
|
355
|
+
close();
|
|
356
|
+
} else {
|
|
357
|
+
validateJson();
|
|
358
|
+
}
|
|
359
|
+
} catch {
|
|
360
|
+
validateJson();
|
|
361
|
+
}
|
|
362
|
+
};
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Create close handler
|
|
367
|
+
* @param {Function} close - Close function
|
|
368
|
+
* @returns {Function} Close handler function
|
|
369
|
+
*/
|
|
370
|
+
const createCloseHandler = (close) => {
|
|
371
|
+
return () => {
|
|
372
|
+
close();
|
|
373
|
+
};
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Create modal management functions
|
|
378
|
+
* @param {HTMLElement} element - Modal element
|
|
379
|
+
* @param {Object} config - Configuration object
|
|
380
|
+
* @param {Function} formatJson - Format function
|
|
381
|
+
* @param {Function} validateJson - Validate function
|
|
382
|
+
* @param {Function} handleSave - Save handler
|
|
383
|
+
* @param {Function} handleClose - Close handler
|
|
384
|
+
* @returns {Object} Modal management functions
|
|
385
|
+
*/
|
|
386
|
+
const createModalManagement = (
|
|
387
|
+
element,
|
|
388
|
+
config,
|
|
389
|
+
formatJson,
|
|
390
|
+
validateJson,
|
|
391
|
+
handleSave,
|
|
392
|
+
handleClose
|
|
393
|
+
) => {
|
|
394
|
+
let isOpen = false;
|
|
395
|
+
let backdrop = null;
|
|
396
|
+
|
|
397
|
+
const close = () => {
|
|
398
|
+
if (isOpen) {
|
|
399
|
+
isOpen = false;
|
|
400
|
+
|
|
401
|
+
if (element) {
|
|
402
|
+
element.style.display = 'none';
|
|
403
|
+
element.remove();
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (backdrop) {
|
|
407
|
+
backdrop.remove();
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Clean up state
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
const open = (data) => {
|
|
415
|
+
isOpen = true;
|
|
416
|
+
|
|
417
|
+
if (!element) {
|
|
418
|
+
const modalElement = createModalElement(
|
|
419
|
+
config,
|
|
420
|
+
formatJson,
|
|
421
|
+
validateJson,
|
|
422
|
+
handleSave,
|
|
423
|
+
handleClose
|
|
424
|
+
);
|
|
425
|
+
// Replace the element reference
|
|
426
|
+
Object.assign(element, modalElement);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
if (!backdrop && config.backdrop) {
|
|
430
|
+
backdrop = createBackdropElement();
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
const textarea = element.querySelector('.json-editor-textarea');
|
|
434
|
+
textarea.value = JSON.stringify(data, null, 2);
|
|
435
|
+
|
|
436
|
+
if (backdrop) {
|
|
437
|
+
document.body.appendChild(backdrop);
|
|
438
|
+
}
|
|
439
|
+
document.body.appendChild(element);
|
|
440
|
+
|
|
441
|
+
element.style.display = 'block';
|
|
442
|
+
textarea.focus();
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
return {
|
|
446
|
+
open,
|
|
447
|
+
close,
|
|
448
|
+
/** @returns {boolean} Whether the modal is currently open */
|
|
449
|
+
isOpen: () => isOpen,
|
|
450
|
+
};
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Create JSON data management functions
|
|
455
|
+
* @param {HTMLElement} element - Modal element
|
|
456
|
+
* @returns {Object} Data management functions
|
|
457
|
+
*/
|
|
458
|
+
const createDataManagement = (element) => {
|
|
459
|
+
const getJsonData = () => {
|
|
460
|
+
const textarea = element.querySelector('.json-editor-textarea');
|
|
461
|
+
try {
|
|
462
|
+
return JSON.parse(textarea.value);
|
|
463
|
+
} catch {
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
|
|
468
|
+
const setJsonData = (data) => {
|
|
469
|
+
const textarea = element.querySelector('.json-editor-textarea');
|
|
470
|
+
textarea.value = JSON.stringify(data, null, 2);
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
const validate = () => {
|
|
474
|
+
const textarea = element.querySelector('.json-editor-textarea');
|
|
475
|
+
try {
|
|
476
|
+
const data = JSON.parse(textarea.value);
|
|
477
|
+
return validateWorkerData(data);
|
|
478
|
+
} catch (error) {
|
|
479
|
+
return {
|
|
480
|
+
isValid: false,
|
|
481
|
+
errors: [{ path: 'json', message: error.message }],
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
return {
|
|
487
|
+
getJsonData,
|
|
488
|
+
setJsonData,
|
|
489
|
+
validate,
|
|
490
|
+
};
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Create JSON editor event handlers
|
|
495
|
+
* @param {HTMLElement} element - Modal element
|
|
496
|
+
* @param {Object} config - Configuration object
|
|
497
|
+
* @param {Function} onSaveCallback - Save callback function
|
|
498
|
+
* @returns {Object} Event handlers object
|
|
499
|
+
*/
|
|
500
|
+
const createEventHandlers = (element, config, onSaveCallback) => {
|
|
501
|
+
// Create local copy to avoid parameter reassignment
|
|
502
|
+
let callbackRef = onSaveCallback;
|
|
503
|
+
|
|
504
|
+
const validateJson = createValidator(element);
|
|
505
|
+
const formatJson = createFormatHandler(element, validateJson);
|
|
506
|
+
|
|
507
|
+
const handleSave = createSaveHandler(element, callbackRef, validateJson, () => {});
|
|
508
|
+
const handleClose = createCloseHandler(() => {});
|
|
509
|
+
|
|
510
|
+
const modalManagement = createModalManagement(
|
|
511
|
+
element,
|
|
512
|
+
config,
|
|
513
|
+
formatJson,
|
|
514
|
+
validateJson,
|
|
515
|
+
handleSave,
|
|
516
|
+
handleClose
|
|
517
|
+
);
|
|
518
|
+
const dataManagement = createDataManagement(element);
|
|
519
|
+
|
|
520
|
+
// Update handlers with actual close function
|
|
521
|
+
const actualHandleSave = createSaveHandler(
|
|
522
|
+
element,
|
|
523
|
+
callbackRef,
|
|
524
|
+
validateJson,
|
|
525
|
+
modalManagement.close
|
|
526
|
+
);
|
|
527
|
+
const actualHandleClose = createCloseHandler(modalManagement.close);
|
|
528
|
+
|
|
529
|
+
const destroy = () => {
|
|
530
|
+
modalManagement.close();
|
|
531
|
+
// Note: element and backdrop cleanup handled in modalManagement
|
|
532
|
+
callbackRef = null;
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
return {
|
|
536
|
+
...modalManagement,
|
|
537
|
+
...dataManagement,
|
|
538
|
+
formatJson,
|
|
539
|
+
validateJson,
|
|
540
|
+
handleSave: actualHandleSave,
|
|
541
|
+
handleClose: actualHandleClose,
|
|
542
|
+
destroy,
|
|
543
|
+
};
|
|
544
|
+
};
|
|
545
|
+
|
|
546
|
+
/**
|
|
547
|
+
* Create backdrop element
|
|
548
|
+
* @returns {HTMLDivElement} Backdrop element
|
|
549
|
+
*/
|
|
550
|
+
const createBackdropElement = () => {
|
|
551
|
+
const backdrop = document.createElement('div');
|
|
552
|
+
backdrop.style.position = 'fixed';
|
|
553
|
+
backdrop.style.top = '0';
|
|
554
|
+
backdrop.style.left = '0';
|
|
555
|
+
backdrop.style.width = '100%';
|
|
556
|
+
backdrop.style.height = '100%';
|
|
557
|
+
backdrop.style.backgroundColor = 'rgba(0, 0, 0, 0.5)';
|
|
558
|
+
backdrop.style.zIndex = '999';
|
|
559
|
+
return backdrop;
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* Create JSON editor lifecycle functions
|
|
564
|
+
* @param {HTMLElement} element - Modal element
|
|
565
|
+
* @param {Object} config - Configuration object
|
|
566
|
+
* @param {Object} eventHandlers - Event handlers object
|
|
567
|
+
* @returns {Object} Lifecycle functions
|
|
568
|
+
*/
|
|
569
|
+
const createEditorLifecycle = (element, config, eventHandlers) => {
|
|
570
|
+
let isOpen = false;
|
|
571
|
+
let backdrop = null;
|
|
572
|
+
let modalElement = element; // Use local variable to avoid parameter reassignment
|
|
573
|
+
|
|
574
|
+
const open = (data) => {
|
|
575
|
+
isOpen = true;
|
|
576
|
+
|
|
577
|
+
if (!modalElement) {
|
|
578
|
+
modalElement = createModalElement(
|
|
579
|
+
config,
|
|
580
|
+
eventHandlers.formatJson,
|
|
581
|
+
eventHandlers.validateJson,
|
|
582
|
+
eventHandlers.handleSave,
|
|
583
|
+
eventHandlers.handleClose
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
if (!backdrop && config.backdrop) {
|
|
588
|
+
backdrop = createBackdropElement();
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
const textarea = modalElement.querySelector('.json-editor-textarea');
|
|
592
|
+
textarea.value = JSON.stringify(data, null, 2);
|
|
593
|
+
|
|
594
|
+
if (backdrop) {
|
|
595
|
+
document.body.appendChild(backdrop);
|
|
596
|
+
}
|
|
597
|
+
document.body.appendChild(modalElement);
|
|
598
|
+
|
|
599
|
+
modalElement.style.display = 'block';
|
|
600
|
+
textarea.focus();
|
|
601
|
+
};
|
|
602
|
+
|
|
603
|
+
const close = () => {
|
|
604
|
+
if (isOpen) {
|
|
605
|
+
isOpen = false;
|
|
606
|
+
|
|
607
|
+
if (modalElement) {
|
|
608
|
+
modalElement.style.display = 'none';
|
|
609
|
+
modalElement.remove();
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
if (backdrop) {
|
|
613
|
+
backdrop.remove();
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
// Clean up state
|
|
617
|
+
}
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
const destroy = () => {
|
|
621
|
+
close();
|
|
622
|
+
modalElement = null;
|
|
623
|
+
backdrop = null;
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
return {
|
|
627
|
+
open,
|
|
628
|
+
close,
|
|
629
|
+
destroy,
|
|
630
|
+
/** @returns {boolean} Whether the modal is currently open */
|
|
631
|
+
isOpen: () => isOpen,
|
|
632
|
+
};
|
|
633
|
+
};
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Create JSON editor instance
|
|
637
|
+
* @param {Object} config - Configuration object
|
|
638
|
+
* @param {Function} onSaveCallback - Save callback function
|
|
639
|
+
* @returns {Object} JSON editor instance with methods
|
|
640
|
+
*/
|
|
641
|
+
const createJsonEditor = (config, onSaveCallback) => {
|
|
642
|
+
const element = null;
|
|
643
|
+
|
|
644
|
+
const eventHandlers = createEventHandlers(
|
|
645
|
+
{
|
|
646
|
+
querySelector: (selector) => element?.querySelector(selector),
|
|
647
|
+
},
|
|
648
|
+
config,
|
|
649
|
+
onSaveCallback
|
|
650
|
+
);
|
|
651
|
+
|
|
652
|
+
const lifecycle = createEditorLifecycle(element, config, eventHandlers);
|
|
653
|
+
const data = createDataManagement(element);
|
|
654
|
+
|
|
655
|
+
return {
|
|
656
|
+
...lifecycle,
|
|
657
|
+
...data,
|
|
658
|
+
formatJson: eventHandlers.formatJson,
|
|
659
|
+
validateJson: eventHandlers.validateJson,
|
|
660
|
+
handleSave: eventHandlers.handleSave,
|
|
661
|
+
handleClose: eventHandlers.handleClose,
|
|
662
|
+
};
|
|
663
|
+
};
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* Sealed namespace for JsonEditor utilities
|
|
667
|
+
*/
|
|
668
|
+
export const JsonEditor = Object.freeze({
|
|
669
|
+
create: createJsonEditor,
|
|
670
|
+
});
|