@alepha/devtools 0.11.3 → 0.11.4
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/dist/index.d.mts +370 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +360 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +26 -16
- package/src/DevCollectorProvider.ts +29 -29
- package/src/index.ts +4 -1
- package/src/ui/AppRouter.tsx +61 -0
- package/src/ui/DevLogs.tsx +143 -0
- package/src/ui/main.ts +4 -0
- package/src/ui/styles.css +7 -0
- package/src/ui/wotfardregular/stylesheet.css +12 -0
- package/src/ui/wotfardregular/wotfard-regular-webfont.eot +0 -0
- package/src/ui/wotfardregular/wotfard-regular-webfont.ttf +0 -0
- package/src/ui/wotfardregular/wotfard-regular-webfont.woff2 +0 -0
- package/dist/index.d.ts +0 -368
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -1678
- package/dist/index.js.map +0 -1
- package/src/constants/ui.ts +0 -1317
- package/src/schemas/DevLogEntry.ts +0 -11
package/src/constants/ui.ts
DELETED
|
@@ -1,1317 +0,0 @@
|
|
|
1
|
-
// language=HTML
|
|
2
|
-
export const ui = `<!DOCTYPE html>
|
|
3
|
-
<html lang="en">
|
|
4
|
-
<head>
|
|
5
|
-
<meta charset="UTF-8" />
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
-
<title>Alepha DevTools</title>
|
|
8
|
-
<style>
|
|
9
|
-
:root {
|
|
10
|
-
--primary: #3b82f6;
|
|
11
|
-
--primary-dark: #2563eb;
|
|
12
|
-
--success: #10b981;
|
|
13
|
-
--warning: #f59e0b;
|
|
14
|
-
--danger: #ef4444;
|
|
15
|
-
--bg-primary: #0f172a;
|
|
16
|
-
--bg-secondary: #1e293b;
|
|
17
|
-
--bg-tertiary: #334155;
|
|
18
|
-
--text-primary: #f8fafc;
|
|
19
|
-
--text-secondary: #cbd5e1;
|
|
20
|
-
--text-muted: #94a3b8;
|
|
21
|
-
--border: #334155;
|
|
22
|
-
--code-bg: #1e293b;
|
|
23
|
-
--shadow: rgba(0, 0, 0, 0.3);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
* {
|
|
27
|
-
box-sizing: border-box;
|
|
28
|
-
margin: 0;
|
|
29
|
-
padding: 0;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
body {
|
|
33
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
34
|
-
background: linear-gradient(135deg, var(--bg-primary) 0%, #0c1222 100%);
|
|
35
|
-
color: var(--text-primary);
|
|
36
|
-
min-height: 100vh;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/* Header */
|
|
40
|
-
.header {
|
|
41
|
-
background: var(--bg-secondary);
|
|
42
|
-
border-bottom: 1px solid var(--border);
|
|
43
|
-
padding: 1.5rem 2rem;
|
|
44
|
-
position: sticky;
|
|
45
|
-
top: 0;
|
|
46
|
-
z-index: 1000;
|
|
47
|
-
box-shadow: 0 4px 6px var(--shadow);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
.header-content {
|
|
51
|
-
max-width: 1600px;
|
|
52
|
-
margin: 0 auto;
|
|
53
|
-
display: flex;
|
|
54
|
-
justify-content: space-between;
|
|
55
|
-
align-items: center;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
.logo {
|
|
59
|
-
font-size: 1.5rem;
|
|
60
|
-
font-weight: 700;
|
|
61
|
-
background: linear-gradient(135deg, var(--primary), #8b5cf6);
|
|
62
|
-
-webkit-background-clip: text;
|
|
63
|
-
-webkit-text-fill-color: transparent;
|
|
64
|
-
background-clip: text;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
.header-stats {
|
|
68
|
-
display: flex;
|
|
69
|
-
gap: 2rem;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
.stat {
|
|
73
|
-
text-align: center;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
.stat-value {
|
|
77
|
-
font-size: 1.5rem;
|
|
78
|
-
font-weight: 700;
|
|
79
|
-
color: var(--primary);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.stat-label {
|
|
83
|
-
font-size: 0.75rem;
|
|
84
|
-
color: var(--text-muted);
|
|
85
|
-
text-transform: uppercase;
|
|
86
|
-
letter-spacing: 0.05em;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/* Navigation */
|
|
90
|
-
.nav {
|
|
91
|
-
background: var(--bg-secondary);
|
|
92
|
-
border-bottom: 1px solid var(--border);
|
|
93
|
-
position: sticky;
|
|
94
|
-
top: 73px;
|
|
95
|
-
z-index: 999;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
.nav-container {
|
|
99
|
-
max-width: 1600px;
|
|
100
|
-
margin: 0 auto;
|
|
101
|
-
padding: 0 2rem;
|
|
102
|
-
display: flex;
|
|
103
|
-
gap: 0.5rem;
|
|
104
|
-
overflow-x: auto;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.nav-tab {
|
|
108
|
-
padding: 1rem 1.5rem;
|
|
109
|
-
background: transparent;
|
|
110
|
-
border: none;
|
|
111
|
-
color: var(--text-secondary);
|
|
112
|
-
cursor: pointer;
|
|
113
|
-
font-size: 0.875rem;
|
|
114
|
-
font-weight: 600;
|
|
115
|
-
border-bottom: 2px solid transparent;
|
|
116
|
-
transition: all 0.2s;
|
|
117
|
-
white-space: nowrap;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
.nav-tab:hover {
|
|
121
|
-
color: var(--text-primary);
|
|
122
|
-
background: rgba(255, 255, 255, 0.05);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
.nav-tab.active {
|
|
126
|
-
color: var(--primary);
|
|
127
|
-
border-bottom-color: var(--primary);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/* Main Container */
|
|
131
|
-
.container {
|
|
132
|
-
max-width: 1600px;
|
|
133
|
-
margin: 0 auto;
|
|
134
|
-
padding: 2rem;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
.tab-content {
|
|
138
|
-
display: none;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
.tab-content.active {
|
|
142
|
-
display: block;
|
|
143
|
-
animation: fadeIn 0.3s;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
@keyframes fadeIn {
|
|
147
|
-
from { opacity: 0; transform: translateY(10px); }
|
|
148
|
-
to { opacity: 1; transform: translateY(0); }
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/* Search and Filters */
|
|
152
|
-
.controls {
|
|
153
|
-
background: var(--bg-secondary);
|
|
154
|
-
border: 1px solid var(--border);
|
|
155
|
-
border-radius: 8px;
|
|
156
|
-
padding: 1.5rem;
|
|
157
|
-
margin-bottom: 1.5rem;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
.search-box {
|
|
161
|
-
display: flex;
|
|
162
|
-
gap: 1rem;
|
|
163
|
-
margin-bottom: 1rem;
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
.search-input {
|
|
167
|
-
flex: 1;
|
|
168
|
-
padding: 0.75rem 1rem;
|
|
169
|
-
background: var(--bg-tertiary);
|
|
170
|
-
border: 1px solid var(--border);
|
|
171
|
-
border-radius: 6px;
|
|
172
|
-
color: var(--text-primary);
|
|
173
|
-
font-size: 0.875rem;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
.search-input:focus {
|
|
177
|
-
outline: none;
|
|
178
|
-
border-color: var(--primary);
|
|
179
|
-
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
.filter-buttons {
|
|
183
|
-
display: flex;
|
|
184
|
-
gap: 0.5rem;
|
|
185
|
-
flex-wrap: wrap;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
.filter-btn {
|
|
189
|
-
padding: 0.5rem 1rem;
|
|
190
|
-
background: var(--bg-tertiary);
|
|
191
|
-
border: 1px solid var(--border);
|
|
192
|
-
border-radius: 6px;
|
|
193
|
-
color: var(--text-secondary);
|
|
194
|
-
font-size: 0.75rem;
|
|
195
|
-
cursor: pointer;
|
|
196
|
-
transition: all 0.2s;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
.filter-btn:hover {
|
|
200
|
-
background: var(--bg-primary);
|
|
201
|
-
border-color: var(--primary);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
.filter-btn.active {
|
|
205
|
-
background: var(--primary);
|
|
206
|
-
color: white;
|
|
207
|
-
border-color: var(--primary);
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/* Cards */
|
|
211
|
-
.card-grid {
|
|
212
|
-
display: grid;
|
|
213
|
-
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
|
214
|
-
gap: 1.5rem;
|
|
215
|
-
margin-bottom: 2rem;
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
.card {
|
|
219
|
-
background: var(--bg-secondary);
|
|
220
|
-
border: 1px solid var(--border);
|
|
221
|
-
border-radius: 8px;
|
|
222
|
-
padding: 1.5rem;
|
|
223
|
-
transition: all 0.2s;
|
|
224
|
-
cursor: pointer;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
.card:hover {
|
|
228
|
-
border-color: var(--primary);
|
|
229
|
-
box-shadow: 0 4px 12px var(--shadow);
|
|
230
|
-
transform: translateY(-2px);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
.card-header {
|
|
234
|
-
display: flex;
|
|
235
|
-
justify-content: space-between;
|
|
236
|
-
align-items: start;
|
|
237
|
-
margin-bottom: 1rem;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
.card-title {
|
|
241
|
-
font-size: 1.125rem;
|
|
242
|
-
font-weight: 600;
|
|
243
|
-
color: var(--text-primary);
|
|
244
|
-
word-break: break-word;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
.badge {
|
|
248
|
-
padding: 0.25rem 0.75rem;
|
|
249
|
-
border-radius: 12px;
|
|
250
|
-
font-size: 0.75rem;
|
|
251
|
-
font-weight: 600;
|
|
252
|
-
text-transform: uppercase;
|
|
253
|
-
white-space: nowrap;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
.badge-get { background: #10b981; color: white; }
|
|
257
|
-
.badge-post { background: #3b82f6; color: white; }
|
|
258
|
-
.badge-put { background: #f59e0b; color: white; }
|
|
259
|
-
.badge-delete { background: #ef4444; color: white; }
|
|
260
|
-
.badge-patch { background: #8b5cf6; color: white; }
|
|
261
|
-
.badge-secure { background: #dc2626; color: white; }
|
|
262
|
-
.badge-internal { background: #3b82f6; color: white; }
|
|
263
|
-
.badge-external { background: #8b5cf6; color: white; }
|
|
264
|
-
|
|
265
|
-
.card-description {
|
|
266
|
-
color: var(--text-secondary);
|
|
267
|
-
font-size: 0.875rem;
|
|
268
|
-
margin-bottom: 1rem;
|
|
269
|
-
line-height: 1.5;
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
.card-meta {
|
|
273
|
-
display: flex;
|
|
274
|
-
flex-wrap: wrap;
|
|
275
|
-
gap: 1rem;
|
|
276
|
-
font-size: 0.75rem;
|
|
277
|
-
color: var(--text-muted);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
.card-meta-item {
|
|
281
|
-
display: flex;
|
|
282
|
-
align-items: center;
|
|
283
|
-
gap: 0.5rem;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
.card-path {
|
|
287
|
-
background: var(--code-bg);
|
|
288
|
-
padding: 0.5rem;
|
|
289
|
-
border-radius: 4px;
|
|
290
|
-
font-family: 'Courier New', monospace;
|
|
291
|
-
font-size: 0.875rem;
|
|
292
|
-
word-break: break-all;
|
|
293
|
-
margin-top: 0.5rem;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/* Table */
|
|
297
|
-
.table-container {
|
|
298
|
-
background: var(--bg-secondary);
|
|
299
|
-
border: 1px solid var(--border);
|
|
300
|
-
border-radius: 8px;
|
|
301
|
-
overflow: hidden;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
table {
|
|
305
|
-
width: 100%;
|
|
306
|
-
border-collapse: collapse;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
thead {
|
|
310
|
-
background: var(--bg-tertiary);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
th {
|
|
314
|
-
padding: 1rem;
|
|
315
|
-
text-align: left;
|
|
316
|
-
font-weight: 600;
|
|
317
|
-
font-size: 0.75rem;
|
|
318
|
-
color: var(--text-secondary);
|
|
319
|
-
text-transform: uppercase;
|
|
320
|
-
letter-spacing: 0.05em;
|
|
321
|
-
border-bottom: 1px solid var(--border);
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
td {
|
|
325
|
-
padding: 1rem;
|
|
326
|
-
border-bottom: 1px solid var(--border);
|
|
327
|
-
color: var(--text-primary);
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
tbody tr {
|
|
331
|
-
transition: background 0.2s;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
tbody tr:hover {
|
|
335
|
-
background: var(--bg-tertiary);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
/* Code Block */
|
|
339
|
-
.code-block {
|
|
340
|
-
background: var(--code-bg);
|
|
341
|
-
border: 1px solid var(--border);
|
|
342
|
-
border-radius: 8px;
|
|
343
|
-
padding: 1rem;
|
|
344
|
-
overflow-x: auto;
|
|
345
|
-
font-family: 'Courier New', monospace;
|
|
346
|
-
font-size: 0.875rem;
|
|
347
|
-
line-height: 1.6;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
/* Logs */
|
|
351
|
-
.log-container {
|
|
352
|
-
background: var(--code-bg);
|
|
353
|
-
border: 1px solid var(--border);
|
|
354
|
-
border-radius: 8px;
|
|
355
|
-
max-height: 600px;
|
|
356
|
-
overflow-y: auto;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
.log-entry {
|
|
360
|
-
padding: 0.75rem 1rem;
|
|
361
|
-
border-bottom: 1px solid var(--border);
|
|
362
|
-
font-family: 'Courier New', monospace;
|
|
363
|
-
font-size: 0.875rem;
|
|
364
|
-
white-space: pre-wrap;
|
|
365
|
-
word-break: break-word;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
.log-entry:last-child {
|
|
369
|
-
border-bottom: none;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
.log-error { background: rgba(239, 68, 68, 0.1); color: #fca5a5; }
|
|
373
|
-
.log-warn { background: rgba(245, 158, 11, 0.1); color: #fcd34d; }
|
|
374
|
-
.log-info { background: rgba(59, 130, 246, 0.1); color: #93c5fd; }
|
|
375
|
-
.log-debug { background: rgba(156, 163, 175, 0.1); color: #d1d5db; }
|
|
376
|
-
|
|
377
|
-
/* Empty State */
|
|
378
|
-
.empty-state {
|
|
379
|
-
text-align: center;
|
|
380
|
-
padding: 4rem 2rem;
|
|
381
|
-
color: var(--text-muted);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
.empty-icon {
|
|
385
|
-
font-size: 4rem;
|
|
386
|
-
margin-bottom: 1rem;
|
|
387
|
-
opacity: 0.3;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
/* Detail View */
|
|
391
|
-
.detail-section {
|
|
392
|
-
background: var(--bg-secondary);
|
|
393
|
-
border: 1px solid var(--border);
|
|
394
|
-
border-radius: 8px;
|
|
395
|
-
padding: 1.5rem;
|
|
396
|
-
margin-bottom: 1.5rem;
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
.detail-title {
|
|
400
|
-
font-size: 0.875rem;
|
|
401
|
-
font-weight: 600;
|
|
402
|
-
color: var(--text-muted);
|
|
403
|
-
text-transform: uppercase;
|
|
404
|
-
letter-spacing: 0.05em;
|
|
405
|
-
margin-bottom: 1rem;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
.property-list {
|
|
409
|
-
display: grid;
|
|
410
|
-
gap: 0.75rem;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
.property {
|
|
414
|
-
display: grid;
|
|
415
|
-
grid-template-columns: 150px 1fr;
|
|
416
|
-
gap: 1rem;
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
.property-key {
|
|
420
|
-
color: var(--text-muted);
|
|
421
|
-
font-size: 0.875rem;
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
.property-value {
|
|
425
|
-
color: var(--text-primary);
|
|
426
|
-
font-size: 0.875rem;
|
|
427
|
-
word-break: break-word;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
.property-value code {
|
|
431
|
-
background: var(--code-bg);
|
|
432
|
-
padding: 0.125rem 0.5rem;
|
|
433
|
-
border-radius: 4px;
|
|
434
|
-
font-family: 'Courier New', monospace;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
/* Loading */
|
|
438
|
-
.loading {
|
|
439
|
-
display: flex;
|
|
440
|
-
justify-content: center;
|
|
441
|
-
align-items: center;
|
|
442
|
-
padding: 4rem;
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
.spinner {
|
|
446
|
-
width: 40px;
|
|
447
|
-
height: 40px;
|
|
448
|
-
border: 3px solid var(--border);
|
|
449
|
-
border-top-color: var(--primary);
|
|
450
|
-
border-radius: 50%;
|
|
451
|
-
animation: spin 0.8s linear infinite;
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
@keyframes spin {
|
|
455
|
-
to { transform: rotate(360deg); }
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
/* Utility */
|
|
459
|
-
.hidden {
|
|
460
|
-
display: none !important;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
.text-muted {
|
|
464
|
-
color: var(--text-muted);
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
.text-code {
|
|
468
|
-
font-family: 'Courier New', monospace;
|
|
469
|
-
background: var(--code-bg);
|
|
470
|
-
padding: 0.125rem 0.5rem;
|
|
471
|
-
border-radius: 4px;
|
|
472
|
-
font-size: 0.875rem;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
/* Scrollbar */
|
|
476
|
-
::-webkit-scrollbar {
|
|
477
|
-
width: 8px;
|
|
478
|
-
height: 8px;
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
::-webkit-scrollbar-track {
|
|
482
|
-
background: var(--bg-primary);
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
::-webkit-scrollbar-thumb {
|
|
486
|
-
background: var(--border);
|
|
487
|
-
border-radius: 4px;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
::-webkit-scrollbar-thumb:hover {
|
|
491
|
-
background: var(--text-muted);
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
/* Responsive */
|
|
495
|
-
@media (max-width: 768px) {
|
|
496
|
-
.header-stats {
|
|
497
|
-
display: none;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
.card-grid {
|
|
501
|
-
grid-template-columns: 1fr;
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
.property {
|
|
505
|
-
grid-template-columns: 1fr;
|
|
506
|
-
gap: 0.25rem;
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
</style>
|
|
510
|
-
</head>
|
|
511
|
-
<body>
|
|
512
|
-
<!-- Header -->
|
|
513
|
-
<div class="header">
|
|
514
|
-
<div class="header-content">
|
|
515
|
-
<div class="logo">⚡ Alepha DevTools</div>
|
|
516
|
-
<div class="header-stats">
|
|
517
|
-
<div class="stat">
|
|
518
|
-
<div class="stat-value" id="stat-actions">0</div>
|
|
519
|
-
<div class="stat-label">Actions</div>
|
|
520
|
-
</div>
|
|
521
|
-
<div class="stat">
|
|
522
|
-
<div class="stat-value" id="stat-pages">0</div>
|
|
523
|
-
<div class="stat-label">Pages</div>
|
|
524
|
-
</div>
|
|
525
|
-
<div class="stat">
|
|
526
|
-
<div class="stat-value" id="stat-modules">0</div>
|
|
527
|
-
<div class="stat-label">Modules</div>
|
|
528
|
-
</div>
|
|
529
|
-
<div class="stat">
|
|
530
|
-
<div class="stat-value" id="stat-providers">0</div>
|
|
531
|
-
<div class="stat-label">Providers</div>
|
|
532
|
-
</div>
|
|
533
|
-
</div>
|
|
534
|
-
</div>
|
|
535
|
-
</div>
|
|
536
|
-
|
|
537
|
-
<!-- Navigation -->
|
|
538
|
-
<div class="nav">
|
|
539
|
-
<div class="nav-container">
|
|
540
|
-
<button class="nav-tab active" data-tab="overview">Overview</button>
|
|
541
|
-
<button class="nav-tab" data-tab="actions">Actions</button>
|
|
542
|
-
<button class="nav-tab" data-tab="pages">Pages</button>
|
|
543
|
-
<button class="nav-tab" data-tab="queues">Queues</button>
|
|
544
|
-
<button class="nav-tab" data-tab="schedulers">Schedulers</button>
|
|
545
|
-
<button class="nav-tab" data-tab="topics">Topics</button>
|
|
546
|
-
<button class="nav-tab" data-tab="buckets">Buckets</button>
|
|
547
|
-
<button class="nav-tab" data-tab="caches">Caches</button>
|
|
548
|
-
<button class="nav-tab" data-tab="realms">Realms</button>
|
|
549
|
-
<button class="nav-tab" data-tab="providers">Providers</button>
|
|
550
|
-
<button class="nav-tab" data-tab="modules">Modules</button>
|
|
551
|
-
<button class="nav-tab" data-tab="logs">Logs</button>
|
|
552
|
-
</div>
|
|
553
|
-
</div>
|
|
554
|
-
|
|
555
|
-
<!-- Main Container -->
|
|
556
|
-
<div class="container">
|
|
557
|
-
<!-- Overview Tab -->
|
|
558
|
-
<div class="tab-content active" id="tab-overview">
|
|
559
|
-
<div class="detail-section">
|
|
560
|
-
<h2 class="detail-title">System Overview</h2>
|
|
561
|
-
<div id="overview-content" class="loading">
|
|
562
|
-
<div class="spinner"></div>
|
|
563
|
-
</div>
|
|
564
|
-
</div>
|
|
565
|
-
</div>
|
|
566
|
-
|
|
567
|
-
<!-- Actions Tab -->
|
|
568
|
-
<div class="tab-content" id="tab-actions">
|
|
569
|
-
<div class="controls">
|
|
570
|
-
<div class="search-box">
|
|
571
|
-
<input type="text" class="search-input" id="search-actions" placeholder="Search actions by name, path, or group..." />
|
|
572
|
-
</div>
|
|
573
|
-
<div class="filter-buttons" id="filter-actions-methods"></div>
|
|
574
|
-
</div>
|
|
575
|
-
<div id="actions-content" class="loading">
|
|
576
|
-
<div class="spinner"></div>
|
|
577
|
-
</div>
|
|
578
|
-
</div>
|
|
579
|
-
|
|
580
|
-
<!-- Pages Tab -->
|
|
581
|
-
<div class="tab-content" id="tab-pages">
|
|
582
|
-
<div class="controls">
|
|
583
|
-
<div class="search-box">
|
|
584
|
-
<input type="text" class="search-input" id="search-pages" placeholder="Search pages by name or path..." />
|
|
585
|
-
</div>
|
|
586
|
-
</div>
|
|
587
|
-
<div id="pages-content" class="loading">
|
|
588
|
-
<div class="spinner"></div>
|
|
589
|
-
</div>
|
|
590
|
-
</div>
|
|
591
|
-
|
|
592
|
-
<!-- Queues Tab -->
|
|
593
|
-
<div class="tab-content" id="tab-queues">
|
|
594
|
-
<div class="controls">
|
|
595
|
-
<div class="search-box">
|
|
596
|
-
<input type="text" class="search-input" id="search-queues" placeholder="Search queues..." />
|
|
597
|
-
</div>
|
|
598
|
-
</div>
|
|
599
|
-
<div id="queues-content" class="loading">
|
|
600
|
-
<div class="spinner"></div>
|
|
601
|
-
</div>
|
|
602
|
-
</div>
|
|
603
|
-
|
|
604
|
-
<!-- Schedulers Tab -->
|
|
605
|
-
<div class="tab-content" id="tab-schedulers">
|
|
606
|
-
<div class="controls">
|
|
607
|
-
<div class="search-box">
|
|
608
|
-
<input type="text" class="search-input" id="search-schedulers" placeholder="Search schedulers..." />
|
|
609
|
-
</div>
|
|
610
|
-
</div>
|
|
611
|
-
<div id="schedulers-content" class="loading">
|
|
612
|
-
<div class="spinner"></div>
|
|
613
|
-
</div>
|
|
614
|
-
</div>
|
|
615
|
-
|
|
616
|
-
<!-- Topics Tab -->
|
|
617
|
-
<div class="tab-content" id="tab-topics">
|
|
618
|
-
<div class="controls">
|
|
619
|
-
<div class="search-box">
|
|
620
|
-
<input type="text" class="search-input" id="search-topics" placeholder="Search topics..." />
|
|
621
|
-
</div>
|
|
622
|
-
</div>
|
|
623
|
-
<div id="topics-content" class="loading">
|
|
624
|
-
<div class="spinner"></div>
|
|
625
|
-
</div>
|
|
626
|
-
</div>
|
|
627
|
-
|
|
628
|
-
<!-- Buckets Tab -->
|
|
629
|
-
<div class="tab-content" id="tab-buckets">
|
|
630
|
-
<div class="controls">
|
|
631
|
-
<div class="search-box">
|
|
632
|
-
<input type="text" class="search-input" id="search-buckets" placeholder="Search buckets..." />
|
|
633
|
-
</div>
|
|
634
|
-
</div>
|
|
635
|
-
<div id="buckets-content" class="loading">
|
|
636
|
-
<div class="spinner"></div>
|
|
637
|
-
</div>
|
|
638
|
-
</div>
|
|
639
|
-
|
|
640
|
-
<!-- Caches Tab -->
|
|
641
|
-
<div class="tab-content" id="tab-caches">
|
|
642
|
-
<div class="controls">
|
|
643
|
-
<div class="search-box">
|
|
644
|
-
<input type="text" class="search-input" id="search-caches" placeholder="Search caches..." />
|
|
645
|
-
</div>
|
|
646
|
-
</div>
|
|
647
|
-
<div id="caches-content" class="loading">
|
|
648
|
-
<div class="spinner"></div>
|
|
649
|
-
</div>
|
|
650
|
-
</div>
|
|
651
|
-
|
|
652
|
-
<!-- Realms Tab -->
|
|
653
|
-
<div class="tab-content" id="tab-realms">
|
|
654
|
-
<div class="controls">
|
|
655
|
-
<div class="search-box">
|
|
656
|
-
<input type="text" class="search-input" id="search-realms" placeholder="Search realms..." />
|
|
657
|
-
</div>
|
|
658
|
-
</div>
|
|
659
|
-
<div id="realms-content" class="loading">
|
|
660
|
-
<div class="spinner"></div>
|
|
661
|
-
</div>
|
|
662
|
-
</div>
|
|
663
|
-
|
|
664
|
-
<!-- Providers Tab -->
|
|
665
|
-
<div class="tab-content" id="tab-providers">
|
|
666
|
-
<div class="controls">
|
|
667
|
-
<div class="search-box">
|
|
668
|
-
<input type="text" class="search-input" id="search-providers" placeholder="Search providers..." />
|
|
669
|
-
</div>
|
|
670
|
-
</div>
|
|
671
|
-
<div id="providers-content" class="loading">
|
|
672
|
-
<div class="spinner"></div>
|
|
673
|
-
</div>
|
|
674
|
-
</div>
|
|
675
|
-
|
|
676
|
-
<!-- Modules Tab -->
|
|
677
|
-
<div class="tab-content" id="tab-modules">
|
|
678
|
-
<div class="controls">
|
|
679
|
-
<div class="search-box">
|
|
680
|
-
<input type="text" class="search-input" id="search-modules" placeholder="Search modules..." />
|
|
681
|
-
</div>
|
|
682
|
-
</div>
|
|
683
|
-
<div id="modules-content" class="loading">
|
|
684
|
-
<div class="spinner"></div>
|
|
685
|
-
</div>
|
|
686
|
-
</div>
|
|
687
|
-
|
|
688
|
-
<!-- Logs Tab -->
|
|
689
|
-
<div class="tab-content" id="tab-logs">
|
|
690
|
-
<div class="controls">
|
|
691
|
-
<div class="search-box">
|
|
692
|
-
<input type="text" class="search-input" id="search-logs" placeholder="Search logs..." />
|
|
693
|
-
</div>
|
|
694
|
-
<div class="filter-buttons">
|
|
695
|
-
<button class="filter-btn active" data-level="all">All</button>
|
|
696
|
-
<button class="filter-btn" data-level="error">Errors</button>
|
|
697
|
-
<button class="filter-btn" data-level="warn">Warnings</button>
|
|
698
|
-
<button class="filter-btn" data-level="info">Info</button>
|
|
699
|
-
<button class="filter-btn" data-level="debug">Debug</button>
|
|
700
|
-
</div>
|
|
701
|
-
</div>
|
|
702
|
-
<div id="logs-content" class="loading">
|
|
703
|
-
<div class="spinner"></div>
|
|
704
|
-
</div>
|
|
705
|
-
</div>
|
|
706
|
-
</div>
|
|
707
|
-
|
|
708
|
-
<script>
|
|
709
|
-
let metadata = null;
|
|
710
|
-
let activeFilters = {
|
|
711
|
-
actions: { methods: new Set() },
|
|
712
|
-
logs: { level: 'all' }
|
|
713
|
-
};
|
|
714
|
-
|
|
715
|
-
// Tab Navigation
|
|
716
|
-
document.querySelectorAll('.nav-tab').forEach(tab => {
|
|
717
|
-
tab.addEventListener('click', () => {
|
|
718
|
-
const tabName = tab.dataset.tab;
|
|
719
|
-
document.querySelectorAll('.nav-tab').forEach(t => t.classList.remove('active'));
|
|
720
|
-
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
|
|
721
|
-
tab.classList.add('active');
|
|
722
|
-
document.getElementById(\`tab-\${tabName}\`).classList.add('active');
|
|
723
|
-
renderTab(tabName);
|
|
724
|
-
});
|
|
725
|
-
});
|
|
726
|
-
|
|
727
|
-
// Utility Functions
|
|
728
|
-
function escapeHtml(text) {
|
|
729
|
-
const div = document.createElement('div');
|
|
730
|
-
div.textContent = text;
|
|
731
|
-
return div.innerHTML;
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
function formatJson(obj) {
|
|
735
|
-
return JSON.stringify(obj, null, 2);
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
function getLogLevel(formatted) {
|
|
739
|
-
const lower = formatted.toLowerCase();
|
|
740
|
-
if (lower.includes('error')) return 'error';
|
|
741
|
-
if (lower.includes('warn')) return 'warn';
|
|
742
|
-
if (lower.includes('info')) return 'info';
|
|
743
|
-
return 'debug';
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
// Search Functions
|
|
747
|
-
function setupSearch(inputId, renderFn) {
|
|
748
|
-
const input = document.getElementById(inputId);
|
|
749
|
-
if (!input) return;
|
|
750
|
-
|
|
751
|
-
let debounceTimer;
|
|
752
|
-
input.addEventListener('input', () => {
|
|
753
|
-
clearTimeout(debounceTimer);
|
|
754
|
-
debounceTimer = setTimeout(renderFn, 300);
|
|
755
|
-
});
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
function matchesSearch(item, searchTerm, fields) {
|
|
759
|
-
if (!searchTerm) return true;
|
|
760
|
-
const term = searchTerm.toLowerCase();
|
|
761
|
-
return fields.some(field => {
|
|
762
|
-
const value = field.split('.').reduce((obj, key) => obj?.[key], item);
|
|
763
|
-
return value && String(value).toLowerCase().includes(term);
|
|
764
|
-
});
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
// Render Functions
|
|
768
|
-
function renderOverview() {
|
|
769
|
-
if (!metadata) return;
|
|
770
|
-
|
|
771
|
-
const content = document.getElementById('overview-content');
|
|
772
|
-
const stats = {
|
|
773
|
-
'Total Actions': metadata.actions?.length || 0,
|
|
774
|
-
'Total Pages': metadata.pages?.length || 0,
|
|
775
|
-
'Total Queues': metadata.queues?.length || 0,
|
|
776
|
-
'Total Schedulers': metadata.schedulers?.length || 0,
|
|
777
|
-
'Total Topics': metadata.topics?.length || 0,
|
|
778
|
-
'Total Buckets': metadata.buckets?.length || 0,
|
|
779
|
-
'Total Caches': metadata.caches?.length || 0,
|
|
780
|
-
'Total Realms': metadata.realms?.length || 0,
|
|
781
|
-
'Total Providers': metadata.providers?.length || 0,
|
|
782
|
-
'Total Modules': metadata.modules?.length || 0,
|
|
783
|
-
'Log Entries': metadata.logs?.length || 0,
|
|
784
|
-
};
|
|
785
|
-
|
|
786
|
-
const methodCounts = {};
|
|
787
|
-
metadata.actions?.forEach(action => {
|
|
788
|
-
methodCounts[action.method] = (methodCounts[action.method] || 0) + 1;
|
|
789
|
-
});
|
|
790
|
-
|
|
791
|
-
content.innerHTML = \`
|
|
792
|
-
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1rem; margin-bottom: 2rem;">
|
|
793
|
-
\${Object.entries(stats).map(([key, value]) => \`
|
|
794
|
-
<div style="background: var(--bg-tertiary); padding: 1.5rem; border-radius: 8px; text-align: center;">
|
|
795
|
-
<div style="font-size: 2rem; font-weight: 700; color: var(--primary);">\${value}</div>
|
|
796
|
-
<div style="font-size: 0.875rem; color: var(--text-muted); margin-top: 0.5rem;">\${escapeHtml(key)}</div>
|
|
797
|
-
</div>
|
|
798
|
-
\`).join('')}
|
|
799
|
-
</div>
|
|
800
|
-
|
|
801
|
-
\${Object.keys(methodCounts).length > 0 ? \`
|
|
802
|
-
<div class="detail-section">
|
|
803
|
-
<h3 class="detail-title">HTTP Methods Distribution</h3>
|
|
804
|
-
<div style="display: flex; gap: 1rem; flex-wrap: wrap;">
|
|
805
|
-
\${Object.entries(methodCounts).map(([method, count]) => \`
|
|
806
|
-
<div class="badge badge-\${method.toLowerCase()}">\${method}: \${count}</div>
|
|
807
|
-
\`).join('')}
|
|
808
|
-
</div>
|
|
809
|
-
</div>
|
|
810
|
-
\` : ''}
|
|
811
|
-
|
|
812
|
-
<div class="detail-section">
|
|
813
|
-
<h3 class="detail-title">Raw Metadata</h3>
|
|
814
|
-
<div class="code-block">\${escapeHtml(formatJson(metadata))}</div>
|
|
815
|
-
</div>
|
|
816
|
-
\`;
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
function renderActions() {
|
|
820
|
-
if (!metadata?.actions) return;
|
|
821
|
-
|
|
822
|
-
const searchTerm = document.getElementById('search-actions')?.value || '';
|
|
823
|
-
const filteredActions = metadata.actions.filter(action => {
|
|
824
|
-
const matchesMethod = activeFilters.actions.methods.size === 0 ||
|
|
825
|
-
activeFilters.actions.methods.has(action.method);
|
|
826
|
-
const matchesSearchTerm = matchesSearch(action, searchTerm, ['name', 'path', 'group', 'fullPath']);
|
|
827
|
-
return matchesMethod && matchesSearchTerm;
|
|
828
|
-
});
|
|
829
|
-
|
|
830
|
-
const content = document.getElementById('actions-content');
|
|
831
|
-
|
|
832
|
-
if (filteredActions.length === 0) {
|
|
833
|
-
content.innerHTML = \`
|
|
834
|
-
<div class="empty-state">
|
|
835
|
-
<div class="empty-icon">🔍</div>
|
|
836
|
-
<div>No actions found</div>
|
|
837
|
-
</div>
|
|
838
|
-
\`;
|
|
839
|
-
return;
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
content.innerHTML = \`
|
|
843
|
-
<div class="card-grid">
|
|
844
|
-
\${filteredActions.map(action => \`
|
|
845
|
-
<div class="card">
|
|
846
|
-
<div class="card-header">
|
|
847
|
-
<div class="card-title">\${escapeHtml(action.name)}</div>
|
|
848
|
-
<div style="display: flex; gap: 0.5rem; flex-wrap: wrap;">
|
|
849
|
-
<span class="badge badge-\${action.method.toLowerCase()}">\${action.method}</span>
|
|
850
|
-
\${action.secure ? '<span class="badge badge-secure">🔒 Secure</span>' : ''}
|
|
851
|
-
</div>
|
|
852
|
-
</div>
|
|
853
|
-
\${action.description ? \`<div class="card-description">\${escapeHtml(action.description)}</div>\` : ''}
|
|
854
|
-
<div class="card-path">\${escapeHtml(action.fullPath)}</div>
|
|
855
|
-
<div class="card-meta">
|
|
856
|
-
<div class="card-meta-item">
|
|
857
|
-
<span>📁</span>
|
|
858
|
-
<span>\${escapeHtml(action.group)}</span>
|
|
859
|
-
</div>
|
|
860
|
-
\${action.disabled ? '<div class="card-meta-item"><span>⚠️</span><span>Disabled</span></div>' : ''}
|
|
861
|
-
\${action.hide ? '<div class="card-meta-item"><span>👁️</span><span>Hidden</span></div>' : ''}
|
|
862
|
-
</div>
|
|
863
|
-
</div>
|
|
864
|
-
\`).join('')}
|
|
865
|
-
</div>
|
|
866
|
-
\`;
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
function renderPages() {
|
|
870
|
-
if (!metadata?.pages) return;
|
|
871
|
-
|
|
872
|
-
const searchTerm = document.getElementById('search-pages')?.value || '';
|
|
873
|
-
const filteredPages = metadata.pages.filter(page =>
|
|
874
|
-
matchesSearch(page, searchTerm, ['name', 'path'])
|
|
875
|
-
);
|
|
876
|
-
|
|
877
|
-
const content = document.getElementById('pages-content');
|
|
878
|
-
|
|
879
|
-
if (filteredPages.length === 0) {
|
|
880
|
-
content.innerHTML = \`<div class="empty-state"><div class="empty-icon">🔍</div><div>No pages found</div></div>\`;
|
|
881
|
-
return;
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
content.innerHTML = \`
|
|
885
|
-
<div class="card-grid">
|
|
886
|
-
\${filteredPages.map(page => \`
|
|
887
|
-
<div class="card">
|
|
888
|
-
<div class="card-header">
|
|
889
|
-
<div class="card-title">\${escapeHtml(page.name)}</div>
|
|
890
|
-
\${page.static ? '<span class="badge" style="background: var(--success);">Static</span>' : ''}
|
|
891
|
-
</div>
|
|
892
|
-
\${page.description ? \`<div class="card-description">\${escapeHtml(page.description)}</div>\` : ''}
|
|
893
|
-
\${page.path ? \`<div class="card-path">\${escapeHtml(page.path)}</div>\` : ''}
|
|
894
|
-
<div class="card-meta">
|
|
895
|
-
\${page.hasComponent ? '<div class="card-meta-item"><span>✓</span><span>Component</span></div>' : ''}
|
|
896
|
-
\${page.hasLazy ? '<div class="card-meta-item"><span>⚡</span><span>Lazy</span></div>' : ''}
|
|
897
|
-
\${page.hasResolve ? '<div class="card-meta-item"><span>🔄</span><span>Resolve</span></div>' : ''}
|
|
898
|
-
\${page.hasChildren ? '<div class="card-meta-item"><span>👶</span><span>Children</span></div>' : ''}
|
|
899
|
-
\${page.hasErrorHandler ? '<div class="card-meta-item"><span>⚠️</span><span>Error Handler</span></div>' : ''}
|
|
900
|
-
</div>
|
|
901
|
-
</div>
|
|
902
|
-
\`).join('')}
|
|
903
|
-
</div>
|
|
904
|
-
\`;
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
function renderQueues() {
|
|
908
|
-
if (!metadata?.queues) return;
|
|
909
|
-
|
|
910
|
-
const searchTerm = document.getElementById('search-queues')?.value || '';
|
|
911
|
-
const filteredQueues = metadata.queues.filter(queue =>
|
|
912
|
-
matchesSearch(queue, searchTerm, ['name', 'provider'])
|
|
913
|
-
);
|
|
914
|
-
|
|
915
|
-
const content = document.getElementById('queues-content');
|
|
916
|
-
|
|
917
|
-
if (filteredQueues.length === 0) {
|
|
918
|
-
content.innerHTML = \`<div class="empty-state"><div class="empty-icon">🔍</div><div>No queues found</div></div>\`;
|
|
919
|
-
return;
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
content.innerHTML = \`
|
|
923
|
-
<div class="card-grid">
|
|
924
|
-
\${filteredQueues.map(queue => \`
|
|
925
|
-
<div class="card">
|
|
926
|
-
<div class="card-header">
|
|
927
|
-
<div class="card-title">\${escapeHtml(queue.name)}</div>
|
|
928
|
-
<span class="badge" style="background: var(--primary);">\${escapeHtml(queue.provider)}</span>
|
|
929
|
-
</div>
|
|
930
|
-
\${queue.description ? \`<div class="card-description">\${escapeHtml(queue.description)}</div>\` : ''}
|
|
931
|
-
\${queue.schema ? \`<div class="detail-section" style="margin-top: 1rem;"><div class="detail-title">Schema</div><div class="code-block">\${escapeHtml(formatJson(queue.schema))}</div></div>\` : ''}
|
|
932
|
-
</div>
|
|
933
|
-
\`).join('')}
|
|
934
|
-
</div>
|
|
935
|
-
\`;
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
function renderSchedulers() {
|
|
939
|
-
if (!metadata?.schedulers) return;
|
|
940
|
-
|
|
941
|
-
const searchTerm = document.getElementById('search-schedulers')?.value || '';
|
|
942
|
-
const filteredSchedulers = metadata.schedulers.filter(scheduler =>
|
|
943
|
-
matchesSearch(scheduler, searchTerm, ['name', 'cron'])
|
|
944
|
-
);
|
|
945
|
-
|
|
946
|
-
const content = document.getElementById('schedulers-content');
|
|
947
|
-
|
|
948
|
-
if (filteredSchedulers.length === 0) {
|
|
949
|
-
content.innerHTML = \`<div class="empty-state"><div class="empty-icon">🔍</div><div>No schedulers found</div></div>\`;
|
|
950
|
-
return;
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
content.innerHTML = \`
|
|
954
|
-
<div class="card-grid">
|
|
955
|
-
\${filteredSchedulers.map(scheduler => \`
|
|
956
|
-
<div class="card">
|
|
957
|
-
<div class="card-header">
|
|
958
|
-
<div class="card-title">\${escapeHtml(scheduler.name)}</div>
|
|
959
|
-
\${scheduler.lock ? '<span class="badge" style="background: var(--warning);">🔒 Locked</span>' : ''}
|
|
960
|
-
</div>
|
|
961
|
-
\${scheduler.description ? \`<div class="card-description">\${escapeHtml(scheduler.description)}</div>\` : ''}
|
|
962
|
-
<div class="card-meta">
|
|
963
|
-
\${scheduler.cron ? \`<div class="card-meta-item"><span>⏰</span><span class="text-code">\${escapeHtml(scheduler.cron)}</span></div>\` : ''}
|
|
964
|
-
\${scheduler.interval ? \`<div class="card-meta-item"><span>🔄</span><span>\${JSON.stringify(scheduler.interval)}</span></div>\` : ''}
|
|
965
|
-
</div>
|
|
966
|
-
</div>
|
|
967
|
-
\`).join('')}
|
|
968
|
-
</div>
|
|
969
|
-
\`;
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
function renderTopics() {
|
|
973
|
-
if (!metadata?.topics) return;
|
|
974
|
-
|
|
975
|
-
const searchTerm = document.getElementById('search-topics')?.value || '';
|
|
976
|
-
const filteredTopics = metadata.topics.filter(topic =>
|
|
977
|
-
matchesSearch(topic, searchTerm, ['name', 'provider'])
|
|
978
|
-
);
|
|
979
|
-
|
|
980
|
-
const content = document.getElementById('topics-content');
|
|
981
|
-
|
|
982
|
-
if (filteredTopics.length === 0) {
|
|
983
|
-
content.innerHTML = \`<div class="empty-state"><div class="empty-icon">🔍</div><div>No topics found</div></div>\`;
|
|
984
|
-
return;
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
content.innerHTML = \`
|
|
988
|
-
<div class="card-grid">
|
|
989
|
-
\${filteredTopics.map(topic => \`
|
|
990
|
-
<div class="card">
|
|
991
|
-
<div class="card-header">
|
|
992
|
-
<div class="card-title">\${escapeHtml(topic.name)}</div>
|
|
993
|
-
<span class="badge" style="background: var(--primary);">\${escapeHtml(topic.provider)}</span>
|
|
994
|
-
</div>
|
|
995
|
-
\${topic.description ? \`<div class="card-description">\${escapeHtml(topic.description)}</div>\` : ''}
|
|
996
|
-
\${topic.schema ? \`<div class="detail-section" style="margin-top: 1rem;"><div class="detail-title">Schema</div><div class="code-block">\${escapeHtml(formatJson(topic.schema))}</div></div>\` : ''}
|
|
997
|
-
</div>
|
|
998
|
-
\`).join('')}
|
|
999
|
-
</div>
|
|
1000
|
-
\`;
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
function renderBuckets() {
|
|
1004
|
-
if (!metadata?.buckets) return;
|
|
1005
|
-
|
|
1006
|
-
const searchTerm = document.getElementById('search-buckets')?.value || '';
|
|
1007
|
-
const filteredBuckets = metadata.buckets.filter(bucket =>
|
|
1008
|
-
matchesSearch(bucket, searchTerm, ['name', 'provider'])
|
|
1009
|
-
);
|
|
1010
|
-
|
|
1011
|
-
const content = document.getElementById('buckets-content');
|
|
1012
|
-
|
|
1013
|
-
if (filteredBuckets.length === 0) {
|
|
1014
|
-
content.innerHTML = \`<div class="empty-state"><div class="empty-icon">🔍</div><div>No buckets found</div></div>\`;
|
|
1015
|
-
return;
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
content.innerHTML = \`
|
|
1019
|
-
<div class="card-grid">
|
|
1020
|
-
\${filteredBuckets.map(bucket => \`
|
|
1021
|
-
<div class="card">
|
|
1022
|
-
<div class="card-header">
|
|
1023
|
-
<div class="card-title">\${escapeHtml(bucket.name)}</div>
|
|
1024
|
-
<span class="badge" style="background: var(--primary);">\${escapeHtml(bucket.provider)}</span>
|
|
1025
|
-
</div>
|
|
1026
|
-
\${bucket.description ? \`<div class="card-description">\${escapeHtml(bucket.description)}</div>\` : ''}
|
|
1027
|
-
<div class="card-meta">
|
|
1028
|
-
\${bucket.maxSize ? \`<div class="card-meta-item"><span>📦</span><span>Max: \${bucket.maxSize} bytes</span></div>\` : ''}
|
|
1029
|
-
\${bucket.mimeTypes?.length ? \`<div class="card-meta-item"><span>📄</span><span>\${bucket.mimeTypes.length} mime types</span></div>\` : ''}
|
|
1030
|
-
</div>
|
|
1031
|
-
</div>
|
|
1032
|
-
\`).join('')}
|
|
1033
|
-
</div>
|
|
1034
|
-
\`;
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
function renderCaches() {
|
|
1038
|
-
if (!metadata?.caches) return;
|
|
1039
|
-
|
|
1040
|
-
const searchTerm = document.getElementById('search-caches')?.value || '';
|
|
1041
|
-
const filteredCaches = metadata.caches.filter(cache =>
|
|
1042
|
-
matchesSearch(cache, searchTerm, ['name', 'provider'])
|
|
1043
|
-
);
|
|
1044
|
-
|
|
1045
|
-
const content = document.getElementById('caches-content');
|
|
1046
|
-
|
|
1047
|
-
if (filteredCaches.length === 0) {
|
|
1048
|
-
content.innerHTML = \`<div class="empty-state"><div class="empty-icon">🔍</div><div>No caches found</div></div>\`;
|
|
1049
|
-
return;
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
content.innerHTML = \`
|
|
1053
|
-
<div class="card-grid">
|
|
1054
|
-
\${filteredCaches.map(cache => \`
|
|
1055
|
-
<div class="card">
|
|
1056
|
-
<div class="card-header">
|
|
1057
|
-
<div class="card-title">\${escapeHtml(cache.name)}</div>
|
|
1058
|
-
<div style="display: flex; gap: 0.5rem;">
|
|
1059
|
-
<span class="badge" style="background: var(--primary);">\${escapeHtml(cache.provider)}</span>
|
|
1060
|
-
\${cache.disabled ? '<span class="badge" style="background: var(--danger);">Disabled</span>' : ''}
|
|
1061
|
-
</div>
|
|
1062
|
-
</div>
|
|
1063
|
-
<div class="card-meta">
|
|
1064
|
-
\${cache.ttl ? \`<div class="card-meta-item"><span>⏱️</span><span>TTL: \${JSON.stringify(cache.ttl)}</span></div>\` : ''}
|
|
1065
|
-
</div>
|
|
1066
|
-
</div>
|
|
1067
|
-
\`).join('')}
|
|
1068
|
-
</div>
|
|
1069
|
-
\`;
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
function renderRealms() {
|
|
1073
|
-
if (!metadata?.realms) return;
|
|
1074
|
-
|
|
1075
|
-
const searchTerm = document.getElementById('search-realms')?.value || '';
|
|
1076
|
-
const filteredRealms = metadata.realms.filter(realm =>
|
|
1077
|
-
matchesSearch(realm, searchTerm, ['name', 'type'])
|
|
1078
|
-
);
|
|
1079
|
-
|
|
1080
|
-
const content = document.getElementById('realms-content');
|
|
1081
|
-
|
|
1082
|
-
if (filteredRealms.length === 0) {
|
|
1083
|
-
content.innerHTML = \`<div class="empty-state"><div class="empty-icon">🔍</div><div>No realms found</div></div>\`;
|
|
1084
|
-
return;
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
content.innerHTML = \`
|
|
1088
|
-
<div class="card-grid">
|
|
1089
|
-
\${filteredRealms.map(realm => \`
|
|
1090
|
-
<div class="card">
|
|
1091
|
-
<div class="card-header">
|
|
1092
|
-
<div class="card-title">\${escapeHtml(realm.name)}</div>
|
|
1093
|
-
<span class="badge badge-\${realm.type}">\${escapeHtml(realm.type)}</span>
|
|
1094
|
-
</div>
|
|
1095
|
-
\${realm.description ? \`<div class="card-description">\${escapeHtml(realm.description)}</div>\` : ''}
|
|
1096
|
-
\${realm.roles?.length ? \`<div class="card-meta"><div class="card-meta-item"><span>👥</span><span>\${realm.roles.length} roles</span></div></div>\` : ''}
|
|
1097
|
-
\${realm.settings ? \`
|
|
1098
|
-
<div class="detail-section" style="margin-top: 1rem;">
|
|
1099
|
-
<div class="detail-title">Settings</div>
|
|
1100
|
-
<div class="property-list">
|
|
1101
|
-
\${realm.settings.accessTokenExpiration ? \`<div class="property"><div class="property-key">Access Token</div><div class="property-value">\${JSON.stringify(realm.settings.accessTokenExpiration)}</div></div>\` : ''}
|
|
1102
|
-
\${realm.settings.refreshTokenExpiration ? \`<div class="property"><div class="property-key">Refresh Token</div><div class="property-value">\${JSON.stringify(realm.settings.refreshTokenExpiration)}</div></div>\` : ''}
|
|
1103
|
-
\${realm.settings.hasOnCreateSession ? \`<div class="property"><div class="property-key">On Create</div><div class="property-value">✓</div></div>\` : ''}
|
|
1104
|
-
\${realm.settings.hasOnRefreshSession ? \`<div class="property"><div class="property-key">On Refresh</div><div class="property-value">✓</div></div>\` : ''}
|
|
1105
|
-
\${realm.settings.hasOnDeleteSession ? \`<div class="property"><div class="property-key">On Delete</div><div class="property-value">✓</div></div>\` : ''}
|
|
1106
|
-
</div>
|
|
1107
|
-
</div>
|
|
1108
|
-
\` : ''}
|
|
1109
|
-
</div>
|
|
1110
|
-
\`).join('')}
|
|
1111
|
-
</div>
|
|
1112
|
-
\`;
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
function renderProviders() {
|
|
1116
|
-
if (!metadata?.providers) return;
|
|
1117
|
-
|
|
1118
|
-
const searchTerm = document.getElementById('search-providers')?.value || '';
|
|
1119
|
-
const filteredProviders = metadata.providers.filter(provider =>
|
|
1120
|
-
matchesSearch(provider, searchTerm, ['name', 'module'])
|
|
1121
|
-
);
|
|
1122
|
-
|
|
1123
|
-
const content = document.getElementById('providers-content');
|
|
1124
|
-
|
|
1125
|
-
if (filteredProviders.length === 0) {
|
|
1126
|
-
content.innerHTML = \`<div class="empty-state"><div class="empty-icon">🔍</div><div>No providers found</div></div>\`;
|
|
1127
|
-
return;
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
content.innerHTML = \`
|
|
1131
|
-
<div class="card-grid">
|
|
1132
|
-
\${filteredProviders.map(provider => \`
|
|
1133
|
-
<div class="card">
|
|
1134
|
-
<div class="card-header">
|
|
1135
|
-
<div class="card-title">\${escapeHtml(provider.name)}</div>
|
|
1136
|
-
</div>
|
|
1137
|
-
\${provider.module ? \`<div class="card-description">📦 \${escapeHtml(provider.module)}</div>\` : ''}
|
|
1138
|
-
<div class="card-meta">
|
|
1139
|
-
\${provider.dependencies?.length ? \`<div class="card-meta-item"><span>🔗</span><span>\${provider.dependencies.length} dependencies</span></div>\` : ''}
|
|
1140
|
-
\${provider.aliases?.length ? \`<div class="card-meta-item"><span>🏷️</span><span>\${provider.aliases.length} aliases</span></div>\` : ''}
|
|
1141
|
-
</div>
|
|
1142
|
-
\${provider.dependencies?.length ? \`
|
|
1143
|
-
<div class="detail-section" style="margin-top: 1rem;">
|
|
1144
|
-
<div class="detail-title">Dependencies</div>
|
|
1145
|
-
<div style="display: flex; flex-wrap: wrap; gap: 0.5rem;">
|
|
1146
|
-
\${provider.dependencies.map(dep => \`<span class="text-code">\${escapeHtml(dep)}</span>\`).join('')}
|
|
1147
|
-
</div>
|
|
1148
|
-
</div>
|
|
1149
|
-
\` : ''}
|
|
1150
|
-
</div>
|
|
1151
|
-
\`).join('')}
|
|
1152
|
-
</div>
|
|
1153
|
-
\`;
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
|
-
function renderModules() {
|
|
1157
|
-
if (!metadata?.modules) return;
|
|
1158
|
-
|
|
1159
|
-
const searchTerm = document.getElementById('search-modules')?.value || '';
|
|
1160
|
-
const filteredModules = metadata.modules.filter(module =>
|
|
1161
|
-
matchesSearch(module, searchTerm, ['name'])
|
|
1162
|
-
);
|
|
1163
|
-
|
|
1164
|
-
const content = document.getElementById('modules-content');
|
|
1165
|
-
|
|
1166
|
-
if (filteredModules.length === 0) {
|
|
1167
|
-
content.innerHTML = \`<div class="empty-state"><div class="empty-icon">🔍</div><div>No modules found</div></div>\`;
|
|
1168
|
-
return;
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
|
-
content.innerHTML = \`
|
|
1172
|
-
<div class="card-grid">
|
|
1173
|
-
\${filteredModules.map(module => \`
|
|
1174
|
-
<div class="card">
|
|
1175
|
-
<div class="card-header">
|
|
1176
|
-
<div class="card-title">\${escapeHtml(module.name)}</div>
|
|
1177
|
-
<span class="badge" style="background: var(--success);">\${module.providers?.length || 0} providers</span>
|
|
1178
|
-
</div>
|
|
1179
|
-
\${module.providers?.length ? \`
|
|
1180
|
-
<div class="detail-section" style="margin-top: 1rem;">
|
|
1181
|
-
<div class="detail-title">Providers</div>
|
|
1182
|
-
<div style="display: flex; flex-wrap: wrap; gap: 0.5rem;">
|
|
1183
|
-
\${module.providers.map(prov => \`<span class="text-code">\${escapeHtml(prov)}</span>\`).join('')}
|
|
1184
|
-
</div>
|
|
1185
|
-
</div>
|
|
1186
|
-
\` : ''}
|
|
1187
|
-
</div>
|
|
1188
|
-
\`).join('')}
|
|
1189
|
-
</div>
|
|
1190
|
-
\`;
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
function renderLogs() {
|
|
1194
|
-
if (!metadata?.logs) return;
|
|
1195
|
-
|
|
1196
|
-
const searchTerm = document.getElementById('search-logs')?.value || '';
|
|
1197
|
-
const level = activeFilters.logs.level;
|
|
1198
|
-
|
|
1199
|
-
const filteredLogs = metadata.logs.filter(log => {
|
|
1200
|
-
const matchesLevel = level === 'all' || getLogLevel(log.formatted) === level;
|
|
1201
|
-
const matchesSearchTerm = !searchTerm || log.formatted.toLowerCase().includes(searchTerm.toLowerCase());
|
|
1202
|
-
return matchesLevel && matchesSearchTerm;
|
|
1203
|
-
});
|
|
1204
|
-
|
|
1205
|
-
const content = document.getElementById('logs-content');
|
|
1206
|
-
|
|
1207
|
-
if (filteredLogs.length === 0) {
|
|
1208
|
-
content.innerHTML = \`<div class="empty-state"><div class="empty-icon">📋</div><div>No logs found</div></div>\`;
|
|
1209
|
-
return;
|
|
1210
|
-
}
|
|
1211
|
-
|
|
1212
|
-
content.innerHTML = \`
|
|
1213
|
-
<div class="log-container">
|
|
1214
|
-
\${filteredLogs.map(log => {
|
|
1215
|
-
const level = getLogLevel(log.formatted);
|
|
1216
|
-
return \`<div class="log-entry log-\${level}">\${escapeHtml(log.formatted)}</div>\`;
|
|
1217
|
-
}).join('')}
|
|
1218
|
-
</div>
|
|
1219
|
-
\`;
|
|
1220
|
-
}
|
|
1221
|
-
|
|
1222
|
-
function renderTab(tabName) {
|
|
1223
|
-
if (!metadata) return;
|
|
1224
|
-
|
|
1225
|
-
switch(tabName) {
|
|
1226
|
-
case 'overview': renderOverview(); break;
|
|
1227
|
-
case 'actions': renderActions(); break;
|
|
1228
|
-
case 'pages': renderPages(); break;
|
|
1229
|
-
case 'queues': renderQueues(); break;
|
|
1230
|
-
case 'schedulers': renderSchedulers(); break;
|
|
1231
|
-
case 'topics': renderTopics(); break;
|
|
1232
|
-
case 'buckets': renderBuckets(); break;
|
|
1233
|
-
case 'caches': renderCaches(); break;
|
|
1234
|
-
case 'realms': renderRealms(); break;
|
|
1235
|
-
case 'providers': renderProviders(); break;
|
|
1236
|
-
case 'modules': renderModules(); break;
|
|
1237
|
-
case 'logs': renderLogs(); break;
|
|
1238
|
-
}
|
|
1239
|
-
}
|
|
1240
|
-
|
|
1241
|
-
// Initialize
|
|
1242
|
-
async function init() {
|
|
1243
|
-
try {
|
|
1244
|
-
const res = await fetch('/_devtools/metadata');
|
|
1245
|
-
metadata = await res.json();
|
|
1246
|
-
|
|
1247
|
-
// Update header stats
|
|
1248
|
-
document.getElementById('stat-actions').textContent = metadata.actions?.length || 0;
|
|
1249
|
-
document.getElementById('stat-pages').textContent = metadata.pages?.length || 0;
|
|
1250
|
-
document.getElementById('stat-modules').textContent = metadata.modules?.length || 0;
|
|
1251
|
-
document.getElementById('stat-providers').textContent = metadata.providers?.length || 0;
|
|
1252
|
-
|
|
1253
|
-
// Setup method filters for actions
|
|
1254
|
-
const methods = [...new Set(metadata.actions?.map(a => a.method) || [])];
|
|
1255
|
-
const filterContainer = document.getElementById('filter-actions-methods');
|
|
1256
|
-
filterContainer.innerHTML = methods.map(method =>
|
|
1257
|
-
\`<button class="filter-btn" data-method="\${method}">\${method}</button>\`
|
|
1258
|
-
).join('');
|
|
1259
|
-
|
|
1260
|
-
filterContainer.querySelectorAll('.filter-btn').forEach(btn => {
|
|
1261
|
-
btn.addEventListener('click', () => {
|
|
1262
|
-
const method = btn.dataset.method;
|
|
1263
|
-
if (activeFilters.actions.methods.has(method)) {
|
|
1264
|
-
activeFilters.actions.methods.delete(method);
|
|
1265
|
-
btn.classList.remove('active');
|
|
1266
|
-
} else {
|
|
1267
|
-
activeFilters.actions.methods.add(method);
|
|
1268
|
-
btn.classList.add('active');
|
|
1269
|
-
}
|
|
1270
|
-
renderActions();
|
|
1271
|
-
});
|
|
1272
|
-
});
|
|
1273
|
-
|
|
1274
|
-
// Setup log level filters
|
|
1275
|
-
document.querySelectorAll('[data-level]').forEach(btn => {
|
|
1276
|
-
btn.addEventListener('click', () => {
|
|
1277
|
-
document.querySelectorAll('[data-level]').forEach(b => b.classList.remove('active'));
|
|
1278
|
-
btn.classList.add('active');
|
|
1279
|
-
activeFilters.logs.level = btn.dataset.level;
|
|
1280
|
-
renderLogs();
|
|
1281
|
-
});
|
|
1282
|
-
});
|
|
1283
|
-
|
|
1284
|
-
// Setup search handlers
|
|
1285
|
-
setupSearch('search-actions', renderActions);
|
|
1286
|
-
setupSearch('search-pages', renderPages);
|
|
1287
|
-
setupSearch('search-queues', renderQueues);
|
|
1288
|
-
setupSearch('search-schedulers', renderSchedulers);
|
|
1289
|
-
setupSearch('search-topics', renderTopics);
|
|
1290
|
-
setupSearch('search-buckets', renderBuckets);
|
|
1291
|
-
setupSearch('search-caches', renderCaches);
|
|
1292
|
-
setupSearch('search-realms', renderRealms);
|
|
1293
|
-
setupSearch('search-providers', renderProviders);
|
|
1294
|
-
setupSearch('search-modules', renderModules);
|
|
1295
|
-
setupSearch('search-logs', renderLogs);
|
|
1296
|
-
|
|
1297
|
-
// Render initial tab
|
|
1298
|
-
renderTab('overview');
|
|
1299
|
-
|
|
1300
|
-
} catch (error) {
|
|
1301
|
-
console.error('Failed to load metadata:', error);
|
|
1302
|
-
document.querySelectorAll('.loading').forEach(el => {
|
|
1303
|
-
el.innerHTML = \`
|
|
1304
|
-
<div class="empty-state">
|
|
1305
|
-
<div class="empty-icon">⚠️</div>
|
|
1306
|
-
<div>Failed to load metadata</div>
|
|
1307
|
-
<div style="margin-top: 0.5rem; color: var(--text-muted);">\${escapeHtml(error.message)}</div>
|
|
1308
|
-
</div>
|
|
1309
|
-
\`;
|
|
1310
|
-
});
|
|
1311
|
-
}
|
|
1312
|
-
}
|
|
1313
|
-
|
|
1314
|
-
init();
|
|
1315
|
-
</script>
|
|
1316
|
-
</body>
|
|
1317
|
-
</html>`;
|