@auto-engineer/cli 0.7.5 → 0.7.7
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/CHANGELOG.md +8 -0
- package/LICENSE +10 -0
- package/dist/src/dsl/index.d.ts +28 -0
- package/dist/src/dsl/index.d.ts.map +1 -0
- package/dist/src/dsl/index.js +113 -0
- package/dist/src/dsl/index.js.map +1 -0
- package/dist/src/dsl/types.d.ts +19 -0
- package/dist/src/dsl/types.d.ts.map +1 -0
- package/dist/src/dsl/types.js +2 -0
- package/dist/src/dsl/types.js.map +1 -0
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +60 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/plugin-loader.d.ts +2 -0
- package/dist/src/plugin-loader.d.ts.map +1 -1
- package/dist/src/plugin-loader.js +11 -2
- package/dist/src/plugin-loader.js.map +1 -1
- package/dist/src/server/config-loader.d.ts +40 -0
- package/dist/src/server/config-loader.d.ts.map +1 -0
- package/dist/src/server/config-loader.js +141 -0
- package/dist/src/server/config-loader.js.map +1 -0
- package/dist/src/server/dashboard copy.html +1187 -0
- package/dist/src/server/dashboard-old.html +1187 -0
- package/dist/src/server/dashboard.html +1480 -0
- package/dist/src/server/file-syncer.d.ts +21 -0
- package/dist/src/server/file-syncer.d.ts.map +1 -0
- package/dist/src/server/file-syncer.js +101 -0
- package/dist/src/server/file-syncer.js.map +1 -0
- package/dist/src/server/logo-dark.svg +1 -0
- package/dist/src/server/logo-light.svg +24 -0
- package/dist/src/server/server.d.ts +88 -0
- package/dist/src/server/server.d.ts.map +1 -0
- package/dist/src/server/server.js +411 -0
- package/dist/src/server/server.js.map +1 -0
- package/dist/src/server/state-manager.d.ts +24 -0
- package/dist/src/server/state-manager.d.ts.map +1 -0
- package/dist/src/server/state-manager.js +56 -0
- package/dist/src/server/state-manager.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +29 -22
|
@@ -0,0 +1,1480 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Auto Engineer</title>
|
|
7
|
+
<style>
|
|
8
|
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
|
|
9
|
+
|
|
10
|
+
* {
|
|
11
|
+
margin: 0;
|
|
12
|
+
padding: 0;
|
|
13
|
+
box-sizing: border-box;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
:root {
|
|
17
|
+
/* Auto Brand Colors */
|
|
18
|
+
--brand-red: #ec3f4a;
|
|
19
|
+
--brand-orange: #ff8a1d;
|
|
20
|
+
--brand-green: #5ec72d;
|
|
21
|
+
--brand-blue: #42c3f7;
|
|
22
|
+
--brand-primary: #0057dd;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* Dark theme (default) */
|
|
26
|
+
[data-theme="dark"] {
|
|
27
|
+
--bg-primary: #1a1a1a;
|
|
28
|
+
--bg-secondary: #18181b;
|
|
29
|
+
--bg-tertiary: #27272a;
|
|
30
|
+
--bg-hover: #333337;
|
|
31
|
+
--border: #3a3a3d;
|
|
32
|
+
--border-light: #4a4a4d;
|
|
33
|
+
--text-primary: #ffffff;
|
|
34
|
+
--text-secondary: #a1a1aa;
|
|
35
|
+
--text-tertiary: #71717a;
|
|
36
|
+
--accent: #0057dd;
|
|
37
|
+
--accent-hover: #0046b5;
|
|
38
|
+
--success: #5ec72d;
|
|
39
|
+
--error: #ec3f4a;
|
|
40
|
+
--warning: #ff8a1d;
|
|
41
|
+
--code-bg: #0d0e11;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* Light theme */
|
|
45
|
+
[data-theme="light"] {
|
|
46
|
+
--bg-primary: #fafafa;
|
|
47
|
+
--bg-secondary: #ffffff;
|
|
48
|
+
--bg-tertiary: #f4f4f5;
|
|
49
|
+
--bg-hover: #e4e4e7;
|
|
50
|
+
--border: #e4e4e7;
|
|
51
|
+
--border-light: #d4d4d8;
|
|
52
|
+
--text-primary: #18181b;
|
|
53
|
+
--text-secondary: #52525b;
|
|
54
|
+
--text-tertiary: #71717a;
|
|
55
|
+
--accent: #0057dd;
|
|
56
|
+
--accent-hover: #0046b5;
|
|
57
|
+
--success: #5ec72d;
|
|
58
|
+
--error: #ec3f4a;
|
|
59
|
+
--warning: #ff8a1d;
|
|
60
|
+
--code-bg: #f4f4f5;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
body {
|
|
64
|
+
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
65
|
+
background: var(--bg-primary);
|
|
66
|
+
color: var(--text-primary);
|
|
67
|
+
min-height: 100vh;
|
|
68
|
+
font-size: 14px;
|
|
69
|
+
line-height: 1.6;
|
|
70
|
+
-webkit-font-smoothing: antialiased;
|
|
71
|
+
-moz-osx-font-smoothing: grayscale;
|
|
72
|
+
transition: background-color 0.3s ease, color 0.3s ease;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* Tab color indicators */
|
|
76
|
+
.tab-indicator {
|
|
77
|
+
display: inline-block;
|
|
78
|
+
width: 8px;
|
|
79
|
+
height: 8px;
|
|
80
|
+
border-radius: 2px;
|
|
81
|
+
margin-right: 8px;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.tab-indicator.command { background: var(--brand-primary); }
|
|
85
|
+
.tab-indicator.event { background: var(--brand-orange); }
|
|
86
|
+
.tab-indicator.state { background: var(--brand-green); }
|
|
87
|
+
|
|
88
|
+
.header {
|
|
89
|
+
background: var(--bg-secondary);
|
|
90
|
+
border-bottom: 1px solid var(--border);
|
|
91
|
+
padding: 0 24px;
|
|
92
|
+
height: 56px;
|
|
93
|
+
display: flex;
|
|
94
|
+
align-items: center;
|
|
95
|
+
justify-content: space-between;
|
|
96
|
+
position: relative;
|
|
97
|
+
transition: background-color 0.3s ease;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.header-logo {
|
|
101
|
+
display: flex;
|
|
102
|
+
align-items: center;
|
|
103
|
+
gap: 12px;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.logo-mark {
|
|
107
|
+
width: 40px;
|
|
108
|
+
height: 40px;
|
|
109
|
+
display: flex;
|
|
110
|
+
align-items: center;
|
|
111
|
+
justify-content: center;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.logo-mark svg {
|
|
115
|
+
width: 40px;
|
|
116
|
+
height: 40px;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.logo-text {
|
|
120
|
+
font-size: 18px;
|
|
121
|
+
font-weight: 600;
|
|
122
|
+
color: var(--text-primary);
|
|
123
|
+
letter-spacing: -0.02em;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.header-controls {
|
|
127
|
+
display: flex;
|
|
128
|
+
align-items: center;
|
|
129
|
+
gap: 24px;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/* Theme switcher dropdown */
|
|
133
|
+
.theme-switcher {
|
|
134
|
+
position: relative;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.theme-toggle {
|
|
138
|
+
display: flex;
|
|
139
|
+
align-items: center;
|
|
140
|
+
justify-content: center;
|
|
141
|
+
width: 36px;
|
|
142
|
+
height: 36px;
|
|
143
|
+
background: var(--bg-tertiary);
|
|
144
|
+
border: 1px solid var(--border);
|
|
145
|
+
border-radius: 8px;
|
|
146
|
+
cursor: pointer;
|
|
147
|
+
transition: all 0.2s ease;
|
|
148
|
+
padding: 0;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.theme-toggle:hover {
|
|
152
|
+
background: var(--bg-hover);
|
|
153
|
+
border-color: var(--border-light);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.theme-toggle:focus {
|
|
157
|
+
outline: none;
|
|
158
|
+
border-color: var(--accent);
|
|
159
|
+
box-shadow: 0 0 0 3px rgba(0, 87, 221, 0.1);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.theme-dropdown {
|
|
163
|
+
position: absolute;
|
|
164
|
+
top: calc(100% + 4px);
|
|
165
|
+
right: 0;
|
|
166
|
+
background: var(--bg-secondary);
|
|
167
|
+
border: 1px solid var(--border);
|
|
168
|
+
border-radius: 8px;
|
|
169
|
+
padding: 4px;
|
|
170
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
171
|
+
opacity: 0;
|
|
172
|
+
visibility: hidden;
|
|
173
|
+
transform: translateY(-4px);
|
|
174
|
+
transition: all 0.15s ease;
|
|
175
|
+
z-index: 1000;
|
|
176
|
+
min-width: 140px;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.theme-dropdown.open {
|
|
180
|
+
opacity: 1;
|
|
181
|
+
visibility: visible;
|
|
182
|
+
transform: translateY(0);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.theme-option {
|
|
186
|
+
display: flex;
|
|
187
|
+
align-items: center;
|
|
188
|
+
gap: 10px;
|
|
189
|
+
padding: 8px 12px;
|
|
190
|
+
border: none;
|
|
191
|
+
background: transparent;
|
|
192
|
+
color: var(--text-primary) !important;
|
|
193
|
+
font-size: 12px;
|
|
194
|
+
font-weight: 500;
|
|
195
|
+
cursor: pointer;
|
|
196
|
+
border-radius: 6px;
|
|
197
|
+
transition: all 0.15s ease;
|
|
198
|
+
width: 100%;
|
|
199
|
+
text-align: left;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.theme-option:hover {
|
|
203
|
+
background: var(--bg-tertiary);
|
|
204
|
+
color: var(--text-primary) !important;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.theme-option.active {
|
|
208
|
+
background: var(--bg-tertiary);
|
|
209
|
+
color: var(--text-primary) !important;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.theme-icon {
|
|
213
|
+
width: 16px;
|
|
214
|
+
height: 16px;
|
|
215
|
+
flex-shrink: 0;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/* New Layout */
|
|
219
|
+
.app-layout {
|
|
220
|
+
display: flex;
|
|
221
|
+
height: calc(100vh - 56px);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/* Left sidebar for registry */
|
|
225
|
+
.sidebar-left {
|
|
226
|
+
width: 280px;
|
|
227
|
+
background: var(--bg-secondary);
|
|
228
|
+
border-right: 1px solid var(--border);
|
|
229
|
+
overflow-y: auto;
|
|
230
|
+
transition: background-color 0.3s ease;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/* Center content area */
|
|
234
|
+
.center-content {
|
|
235
|
+
flex: 1;
|
|
236
|
+
display: flex;
|
|
237
|
+
flex-direction: column;
|
|
238
|
+
overflow: hidden;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* Request Bar (Postman-like) */
|
|
242
|
+
.request-bar {
|
|
243
|
+
background: var(--bg-secondary);
|
|
244
|
+
border-bottom: 1px solid var(--border);
|
|
245
|
+
padding: 16px 24px;
|
|
246
|
+
display: flex;
|
|
247
|
+
gap: 12px;
|
|
248
|
+
align-items: center;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.method-selector {
|
|
252
|
+
position: relative;
|
|
253
|
+
min-width: 200px;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.method-select {
|
|
257
|
+
width: 100%;
|
|
258
|
+
padding: 10px 40px 10px 12px;
|
|
259
|
+
background: var(--bg-tertiary);
|
|
260
|
+
border: 1px solid var(--border);
|
|
261
|
+
border-radius: 8px;
|
|
262
|
+
color: var(--text-primary);
|
|
263
|
+
font-size: 13px;
|
|
264
|
+
font-weight: 600;
|
|
265
|
+
cursor: pointer;
|
|
266
|
+
appearance: none;
|
|
267
|
+
-webkit-appearance: none;
|
|
268
|
+
-moz-appearance: none;
|
|
269
|
+
transition: all 0.15s ease;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.method-select:hover {
|
|
273
|
+
background: var(--bg-hover);
|
|
274
|
+
border-color: var(--border-light);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.method-select:focus {
|
|
278
|
+
outline: none;
|
|
279
|
+
border-color: var(--accent);
|
|
280
|
+
box-shadow: 0 0 0 3px rgba(0, 87, 221, 0.1);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.method-selector::after {
|
|
284
|
+
content: '▼';
|
|
285
|
+
position: absolute;
|
|
286
|
+
right: 12px;
|
|
287
|
+
top: 50%;
|
|
288
|
+
transform: translateY(-50%);
|
|
289
|
+
pointer-events: none;
|
|
290
|
+
color: var(--text-tertiary);
|
|
291
|
+
font-size: 10px;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.method-indicator {
|
|
295
|
+
display: inline-block;
|
|
296
|
+
width: 8px;
|
|
297
|
+
height: 8px;
|
|
298
|
+
border-radius: 2px;
|
|
299
|
+
margin-right: 8px;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.method-indicator.command { background: var(--brand-primary); }
|
|
303
|
+
.method-indicator.state { background: var(--brand-green); }
|
|
304
|
+
|
|
305
|
+
.endpoint-input {
|
|
306
|
+
flex: 1;
|
|
307
|
+
padding: 10px 14px;
|
|
308
|
+
background: var(--bg-tertiary);
|
|
309
|
+
border: 1px solid var(--border);
|
|
310
|
+
border-radius: 8px;
|
|
311
|
+
color: var(--text-primary);
|
|
312
|
+
font-size: 13px;
|
|
313
|
+
font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Code', monospace;
|
|
314
|
+
transition: all 0.15s ease;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.endpoint-input:focus {
|
|
318
|
+
outline: none;
|
|
319
|
+
border-color: var(--accent);
|
|
320
|
+
background: var(--bg-secondary);
|
|
321
|
+
box-shadow: 0 0 0 3px rgba(0, 87, 221, 0.1);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.send-button {
|
|
325
|
+
padding: 10px 24px;
|
|
326
|
+
background: var(--accent);
|
|
327
|
+
color: white;
|
|
328
|
+
border: none;
|
|
329
|
+
border-radius: 8px;
|
|
330
|
+
font-size: 13px;
|
|
331
|
+
font-weight: 600;
|
|
332
|
+
cursor: pointer;
|
|
333
|
+
transition: all 0.15s ease;
|
|
334
|
+
display: flex;
|
|
335
|
+
align-items: center;
|
|
336
|
+
gap: 8px;
|
|
337
|
+
text-transform: uppercase;
|
|
338
|
+
letter-spacing: 0.05em;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.send-button:hover:not(:disabled) {
|
|
342
|
+
background: var(--accent-hover);
|
|
343
|
+
transform: translateY(-1px);
|
|
344
|
+
box-shadow: 0 4px 12px rgba(0, 87, 221, 0.3);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.send-button:active:not(:disabled) {
|
|
348
|
+
transform: translateY(0);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.send-button:disabled {
|
|
352
|
+
opacity: 0.5;
|
|
353
|
+
cursor: not-allowed;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/* Request/Response Container */
|
|
357
|
+
.request-response-container {
|
|
358
|
+
flex: 1;
|
|
359
|
+
display: flex;
|
|
360
|
+
overflow: hidden;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/* Request Panel (left half) */
|
|
364
|
+
.request-panel {
|
|
365
|
+
flex: 1;
|
|
366
|
+
background: var(--bg-primary);
|
|
367
|
+
border-right: 1px solid var(--border);
|
|
368
|
+
display: flex;
|
|
369
|
+
flex-direction: column;
|
|
370
|
+
overflow: hidden;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.panel-tabs {
|
|
374
|
+
display: flex;
|
|
375
|
+
background: var(--bg-tertiary);
|
|
376
|
+
border-bottom: 1px solid var(--border);
|
|
377
|
+
padding: 0 16px;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.panel-tab {
|
|
381
|
+
padding: 12px 16px;
|
|
382
|
+
background: transparent;
|
|
383
|
+
border: none;
|
|
384
|
+
color: var(--text-tertiary);
|
|
385
|
+
font-size: 12px;
|
|
386
|
+
font-weight: 600;
|
|
387
|
+
cursor: pointer;
|
|
388
|
+
border-bottom: 2px solid transparent;
|
|
389
|
+
transition: all 0.15s ease;
|
|
390
|
+
text-transform: uppercase;
|
|
391
|
+
letter-spacing: 0.05em;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
.panel-tab:hover {
|
|
395
|
+
color: var(--text-secondary);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.panel-tab.active {
|
|
399
|
+
color: var(--text-primary);
|
|
400
|
+
border-bottom-color: var(--accent);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.panel-content {
|
|
404
|
+
flex: 1;
|
|
405
|
+
padding: 20px;
|
|
406
|
+
overflow-y: auto;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/* Response Panel (right half) */
|
|
410
|
+
.response-panel {
|
|
411
|
+
flex: 1;
|
|
412
|
+
background: var(--bg-primary);
|
|
413
|
+
display: flex;
|
|
414
|
+
flex-direction: column;
|
|
415
|
+
overflow: hidden;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.response-header {
|
|
419
|
+
display: flex;
|
|
420
|
+
align-items: center;
|
|
421
|
+
justify-content: space-between;
|
|
422
|
+
padding: 12px 20px;
|
|
423
|
+
background: var(--bg-tertiary);
|
|
424
|
+
border-bottom: 1px solid var(--border);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.response-status {
|
|
428
|
+
display: flex;
|
|
429
|
+
align-items: center;
|
|
430
|
+
gap: 8px;
|
|
431
|
+
font-size: 12px;
|
|
432
|
+
font-weight: 600;
|
|
433
|
+
text-transform: uppercase;
|
|
434
|
+
letter-spacing: 0.05em;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
.status-dot {
|
|
438
|
+
width: 8px;
|
|
439
|
+
height: 8px;
|
|
440
|
+
border-radius: 50%;
|
|
441
|
+
background: var(--text-tertiary);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
.status-dot.success {
|
|
445
|
+
background: var(--success);
|
|
446
|
+
box-shadow: 0 0 8px rgba(94, 199, 45, 0.5);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
.status-dot.error {
|
|
450
|
+
background: var(--error);
|
|
451
|
+
box-shadow: 0 0 8px rgba(236, 63, 74, 0.5);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.response-time {
|
|
455
|
+
color: var(--text-tertiary);
|
|
456
|
+
font-size: 11px;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
.response-content {
|
|
460
|
+
flex: 1;
|
|
461
|
+
padding: 20px;
|
|
462
|
+
overflow-y: auto;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/* Right sidebar for events */
|
|
466
|
+
.sidebar-right {
|
|
467
|
+
width: 360px;
|
|
468
|
+
background: var(--bg-secondary);
|
|
469
|
+
border-left: 1px solid var(--border);
|
|
470
|
+
display: flex;
|
|
471
|
+
flex-direction: column;
|
|
472
|
+
transition: background-color 0.3s ease;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
.events-header {
|
|
476
|
+
padding: 16px 20px;
|
|
477
|
+
background: var(--bg-tertiary);
|
|
478
|
+
border-bottom: 1px solid var(--border);
|
|
479
|
+
display: flex;
|
|
480
|
+
justify-content: space-between;
|
|
481
|
+
align-items: center;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.events-title {
|
|
485
|
+
font-size: 11px;
|
|
486
|
+
font-weight: 600;
|
|
487
|
+
text-transform: uppercase;
|
|
488
|
+
letter-spacing: 0.08em;
|
|
489
|
+
color: var(--text-secondary);
|
|
490
|
+
display: flex;
|
|
491
|
+
align-items: center;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
.events-controls {
|
|
495
|
+
display: flex;
|
|
496
|
+
gap: 8px;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
.events-list {
|
|
500
|
+
flex: 1;
|
|
501
|
+
overflow-y: auto;
|
|
502
|
+
padding: 12px;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
/* Registry sections in left sidebar */
|
|
506
|
+
.handlers-section {
|
|
507
|
+
flex: 1;
|
|
508
|
+
display: flex;
|
|
509
|
+
flex-direction: column;
|
|
510
|
+
overflow: hidden;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
.handlers-header {
|
|
514
|
+
padding: 14px 20px;
|
|
515
|
+
display: flex;
|
|
516
|
+
align-items: center;
|
|
517
|
+
justify-content: space-between;
|
|
518
|
+
background: var(--bg-tertiary);
|
|
519
|
+
border-bottom: 1px solid var(--border);
|
|
520
|
+
transition: background-color 0.3s ease;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
.handlers-title {
|
|
524
|
+
font-size: 11px;
|
|
525
|
+
font-weight: 600;
|
|
526
|
+
text-transform: uppercase;
|
|
527
|
+
letter-spacing: 0.08em;
|
|
528
|
+
color: var(--text-secondary);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
.handlers-count {
|
|
532
|
+
font-size: 11px;
|
|
533
|
+
padding: 3px 8px;
|
|
534
|
+
background: var(--bg-primary);
|
|
535
|
+
border-radius: 12px;
|
|
536
|
+
color: var(--text-tertiary);
|
|
537
|
+
font-weight: 500;
|
|
538
|
+
transition: background-color 0.3s ease;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
.handlers-list {
|
|
542
|
+
flex: 1;
|
|
543
|
+
overflow-y: auto;
|
|
544
|
+
padding: 0;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
.handler-group {
|
|
548
|
+
margin: 0;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
.handler-group-header {
|
|
552
|
+
padding: 8px 20px;
|
|
553
|
+
background: var(--bg-primary);
|
|
554
|
+
border-bottom: 1px solid var(--border);
|
|
555
|
+
font-size: 10px;
|
|
556
|
+
font-weight: 600;
|
|
557
|
+
text-transform: uppercase;
|
|
558
|
+
letter-spacing: 0.08em;
|
|
559
|
+
color: var(--text-tertiary);
|
|
560
|
+
position: sticky;
|
|
561
|
+
top: 0;
|
|
562
|
+
z-index: 10;
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
.handler-item {
|
|
566
|
+
display: flex;
|
|
567
|
+
align-items: center;
|
|
568
|
+
gap: 10px;
|
|
569
|
+
padding: 10px 20px;
|
|
570
|
+
border-bottom: 1px solid var(--border);
|
|
571
|
+
font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Code', monospace;
|
|
572
|
+
font-size: 12px;
|
|
573
|
+
color: var(--text-secondary);
|
|
574
|
+
transition: all 0.15s ease;
|
|
575
|
+
position: relative;
|
|
576
|
+
cursor: pointer;
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
.handler-item.selected {
|
|
580
|
+
background: var(--bg-tertiary);
|
|
581
|
+
color: var(--text-primary);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
.handler-item.selected::before {
|
|
585
|
+
background: var(--accent);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
.handler-item::before {
|
|
589
|
+
content: '';
|
|
590
|
+
position: absolute;
|
|
591
|
+
left: 0;
|
|
592
|
+
top: 0;
|
|
593
|
+
bottom: 0;
|
|
594
|
+
width: 3px;
|
|
595
|
+
background: transparent;
|
|
596
|
+
transition: background 0.15s ease;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
.handler-item:hover {
|
|
600
|
+
background: var(--bg-hover);
|
|
601
|
+
color: var(--text-primary);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
.handler-item:hover::before {
|
|
605
|
+
background: var(--accent);
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
.handler-type-indicator {
|
|
609
|
+
width: 8px;
|
|
610
|
+
height: 8px;
|
|
611
|
+
border-radius: 2px;
|
|
612
|
+
flex-shrink: 0;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
.handler-type-indicator.command {
|
|
616
|
+
background: #42c3f7; /* Blue from logo */
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
.handler-type-indicator.event {
|
|
620
|
+
background: #ff8a1d; /* Orange from logo */
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
.handler-type-indicator.state {
|
|
624
|
+
background: #5ec72d; /* Green from logo */
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
.handler-name {
|
|
628
|
+
flex: 1;
|
|
629
|
+
overflow: hidden;
|
|
630
|
+
text-overflow: ellipsis;
|
|
631
|
+
white-space: nowrap;
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
.empty {
|
|
635
|
+
padding: 32px;
|
|
636
|
+
text-align: center;
|
|
637
|
+
color: var(--text-tertiary);
|
|
638
|
+
font-size: 12px;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
/* Form elements */
|
|
642
|
+
.form-group {
|
|
643
|
+
margin-bottom: 20px;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
.form-group label {
|
|
647
|
+
display: block;
|
|
648
|
+
margin-bottom: 8px;
|
|
649
|
+
color: var(--text-secondary);
|
|
650
|
+
font-size: 11px;
|
|
651
|
+
font-weight: 600;
|
|
652
|
+
text-transform: uppercase;
|
|
653
|
+
letter-spacing: 0.08em;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
.input, .textarea {
|
|
657
|
+
width: 100%;
|
|
658
|
+
background: var(--bg-tertiary);
|
|
659
|
+
border: 1px solid var(--border);
|
|
660
|
+
border-radius: 8px;
|
|
661
|
+
padding: 10px 14px;
|
|
662
|
+
color: var(--text-primary);
|
|
663
|
+
font-size: 13px;
|
|
664
|
+
transition: all 0.15s ease;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
.input:focus, .textarea:focus {
|
|
668
|
+
outline: none;
|
|
669
|
+
border-color: var(--accent);
|
|
670
|
+
background: var(--bg-secondary);
|
|
671
|
+
box-shadow: 0 0 0 3px rgba(0, 87, 221, 0.1);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
.textarea {
|
|
675
|
+
font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Code', monospace;
|
|
676
|
+
font-size: 12px;
|
|
677
|
+
min-height: 120px;
|
|
678
|
+
resize: vertical;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
.button {
|
|
682
|
+
background: var(--accent);
|
|
683
|
+
color: white;
|
|
684
|
+
border: none;
|
|
685
|
+
padding: 10px 20px;
|
|
686
|
+
border-radius: 8px;
|
|
687
|
+
font-size: 13px;
|
|
688
|
+
font-weight: 600;
|
|
689
|
+
cursor: pointer;
|
|
690
|
+
transition: all 0.15s ease;
|
|
691
|
+
display: inline-flex;
|
|
692
|
+
align-items: center;
|
|
693
|
+
gap: 8px;
|
|
694
|
+
text-transform: uppercase;
|
|
695
|
+
letter-spacing: 0.05em;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
.button:hover {
|
|
699
|
+
background: var(--accent-hover);
|
|
700
|
+
transform: translateY(-1px);
|
|
701
|
+
box-shadow: 0 4px 12px rgba(0, 87, 221, 0.3);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
.button:active {
|
|
705
|
+
transform: translateY(0);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
.button-small {
|
|
709
|
+
padding: 6px 12px;
|
|
710
|
+
font-size: 11px;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
.button-secondary {
|
|
714
|
+
background: var(--bg-tertiary);
|
|
715
|
+
color: var(--text-primary);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
.button-secondary:hover {
|
|
719
|
+
background: var(--bg-hover);
|
|
720
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
.code-block {
|
|
724
|
+
background: var(--code-bg);
|
|
725
|
+
border: 1px solid var(--border);
|
|
726
|
+
border-radius: 8px;
|
|
727
|
+
padding: 16px;
|
|
728
|
+
font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Code', monospace;
|
|
729
|
+
font-size: 12px;
|
|
730
|
+
line-height: 1.6;
|
|
731
|
+
overflow: auto;
|
|
732
|
+
white-space: pre-wrap;
|
|
733
|
+
word-break: break-word;
|
|
734
|
+
transition: background-color 0.3s ease;
|
|
735
|
+
flex: 1;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
.response-header {
|
|
739
|
+
display: flex;
|
|
740
|
+
align-items: center;
|
|
741
|
+
justify-content: space-between;
|
|
742
|
+
margin-bottom: 16px;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
.response-status {
|
|
746
|
+
display: flex;
|
|
747
|
+
align-items: center;
|
|
748
|
+
gap: 8px;
|
|
749
|
+
font-size: 12px;
|
|
750
|
+
font-weight: 600;
|
|
751
|
+
text-transform: uppercase;
|
|
752
|
+
letter-spacing: 0.05em;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
.status-dot {
|
|
756
|
+
width: 8px;
|
|
757
|
+
height: 8px;
|
|
758
|
+
border-radius: 50%;
|
|
759
|
+
background: var(--text-tertiary);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
.status-dot.success {
|
|
763
|
+
background: var(--success);
|
|
764
|
+
box-shadow: 0 0 8px rgba(94, 199, 45, 0.5);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
.status-dot.error {
|
|
768
|
+
background: var(--error);
|
|
769
|
+
box-shadow: 0 0 8px rgba(236, 63, 74, 0.5);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
.response-time {
|
|
773
|
+
color: var(--text-tertiary);
|
|
774
|
+
font-size: 11px;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
.empty {
|
|
778
|
+
padding: 32px;
|
|
779
|
+
text-align: center;
|
|
780
|
+
color: var(--text-tertiary);
|
|
781
|
+
font-size: 12px;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
.divider {
|
|
785
|
+
height: 1px;
|
|
786
|
+
background: var(--border);
|
|
787
|
+
margin: 20px 0;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
.keyboard-shortcut {
|
|
791
|
+
display: inline-flex;
|
|
792
|
+
align-items: center;
|
|
793
|
+
gap: 2px;
|
|
794
|
+
padding: 2px 6px;
|
|
795
|
+
background: var(--bg-tertiary);
|
|
796
|
+
border: 1px solid var(--border);
|
|
797
|
+
border-radius: 4px;
|
|
798
|
+
font-size: 10px;
|
|
799
|
+
color: var(--text-tertiary);
|
|
800
|
+
font-family: 'SF Mono', monospace;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
/* Event items in right sidebar */
|
|
804
|
+
.event-item {
|
|
805
|
+
background: var(--bg-tertiary);
|
|
806
|
+
border: 1px solid var(--border);
|
|
807
|
+
border-radius: 8px;
|
|
808
|
+
padding: 12px;
|
|
809
|
+
margin-bottom: 8px;
|
|
810
|
+
transition: all 0.15s ease;
|
|
811
|
+
position: relative;
|
|
812
|
+
overflow: hidden;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
.event-item::before {
|
|
816
|
+
content: '';
|
|
817
|
+
position: absolute;
|
|
818
|
+
left: 0;
|
|
819
|
+
top: 0;
|
|
820
|
+
bottom: 0;
|
|
821
|
+
width: 3px;
|
|
822
|
+
background: var(--brand-orange);
|
|
823
|
+
opacity: 0.5;
|
|
824
|
+
transition: opacity 0.15s ease;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
.event-item:hover {
|
|
828
|
+
background: var(--bg-hover);
|
|
829
|
+
border-color: var(--border-light);
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
.event-item:hover::before {
|
|
833
|
+
opacity: 1;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
.event-header {
|
|
837
|
+
display: flex;
|
|
838
|
+
justify-content: space-between;
|
|
839
|
+
align-items: center;
|
|
840
|
+
margin-bottom: 8px;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
.event-type {
|
|
844
|
+
font-weight: 600;
|
|
845
|
+
color: var(--accent);
|
|
846
|
+
font-size: 12px;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
.event-time {
|
|
850
|
+
color: var(--text-tertiary);
|
|
851
|
+
font-size: 10px;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
.event-data {
|
|
855
|
+
background: var(--code-bg);
|
|
856
|
+
border: 1px solid var(--border);
|
|
857
|
+
border-radius: 4px;
|
|
858
|
+
padding: 8px;
|
|
859
|
+
font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Code', monospace;
|
|
860
|
+
font-size: 10px;
|
|
861
|
+
color: var(--text-secondary);
|
|
862
|
+
white-space: pre-wrap;
|
|
863
|
+
word-break: break-word;
|
|
864
|
+
max-height: 100px;
|
|
865
|
+
overflow-y: auto;
|
|
866
|
+
transition: background-color 0.3s ease;
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
/* WebSocket status indicator */
|
|
870
|
+
.ws-status {
|
|
871
|
+
position: fixed;
|
|
872
|
+
bottom: 24px;
|
|
873
|
+
right: 24px;
|
|
874
|
+
padding: 10px 16px;
|
|
875
|
+
background: var(--bg-tertiary);
|
|
876
|
+
border: 1px solid var(--border);
|
|
877
|
+
border-radius: 8px;
|
|
878
|
+
display: flex;
|
|
879
|
+
align-items: center;
|
|
880
|
+
gap: 10px;
|
|
881
|
+
font-size: 12px;
|
|
882
|
+
color: var(--text-secondary);
|
|
883
|
+
backdrop-filter: blur(10px);
|
|
884
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
885
|
+
transition: background-color 0.3s ease;
|
|
886
|
+
z-index: 1000;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
.ws-dot {
|
|
890
|
+
width: 8px;
|
|
891
|
+
height: 8px;
|
|
892
|
+
border-radius: 50%;
|
|
893
|
+
background: var(--text-tertiary);
|
|
894
|
+
animation: pulse 2s infinite;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
.ws-dot.connected {
|
|
898
|
+
background: var(--success);
|
|
899
|
+
box-shadow: 0 0 8px rgba(94, 199, 45, 0.5);
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
@keyframes pulse {
|
|
903
|
+
0%, 100% { opacity: 1; }
|
|
904
|
+
50% { opacity: 0.5; }
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
/* Scrollbar styling */
|
|
908
|
+
::-webkit-scrollbar {
|
|
909
|
+
width: 10px;
|
|
910
|
+
height: 10px;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
::-webkit-scrollbar-track {
|
|
914
|
+
background: var(--bg-secondary);
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
::-webkit-scrollbar-thumb {
|
|
918
|
+
background: var(--border-light);
|
|
919
|
+
border-radius: 5px;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
::-webkit-scrollbar-thumb:hover {
|
|
923
|
+
background: var(--text-tertiary);
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
@media (max-width: 1200px) {
|
|
927
|
+
.sidebar-left {
|
|
928
|
+
display: none;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
@media (max-width: 768px) {
|
|
933
|
+
.sidebar-right {
|
|
934
|
+
display: none;
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
</style>
|
|
938
|
+
</head>
|
|
939
|
+
<body data-theme="dark">
|
|
940
|
+
<div class="header">
|
|
941
|
+
<div class="header-logo">
|
|
942
|
+
<div class="logo-mark" id="logoMark">
|
|
943
|
+
</div>
|
|
944
|
+
<div>
|
|
945
|
+
<span class="logo-text">auto engineer</span>
|
|
946
|
+
</div>
|
|
947
|
+
</div>
|
|
948
|
+
<div class="header-controls">
|
|
949
|
+
<div class="theme-switcher">
|
|
950
|
+
<button class="theme-toggle" id="themeToggle" onclick="toggleThemeDropdown()">
|
|
951
|
+
<svg class="theme-icon" id="currentThemeIcon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
952
|
+
<!-- Icon will be set based on current theme -->
|
|
953
|
+
</svg>
|
|
954
|
+
</button>
|
|
955
|
+
<div class="theme-dropdown" id="themeDropdown">
|
|
956
|
+
<button class="theme-option" onclick="setTheme('light')">
|
|
957
|
+
<svg class="theme-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
958
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
|
|
959
|
+
</svg>
|
|
960
|
+
<span>Light</span>
|
|
961
|
+
</button>
|
|
962
|
+
<button class="theme-option" onclick="setTheme('dark')">
|
|
963
|
+
<svg class="theme-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
964
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
|
965
|
+
</svg>
|
|
966
|
+
<span>Dark</span>
|
|
967
|
+
</button>
|
|
968
|
+
<button class="theme-option" onclick="setTheme('system')">
|
|
969
|
+
<svg class="theme-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
970
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />
|
|
971
|
+
</svg>
|
|
972
|
+
<span>System</span>
|
|
973
|
+
</button>
|
|
974
|
+
</div>
|
|
975
|
+
</div>
|
|
976
|
+
</div>
|
|
977
|
+
</div>
|
|
978
|
+
|
|
979
|
+
<div class="app-layout">
|
|
980
|
+
<!-- Left Sidebar: Registry -->
|
|
981
|
+
<div class="sidebar-left">
|
|
982
|
+
<div class="handlers-section">
|
|
983
|
+
<div class="handlers-header">
|
|
984
|
+
<span class="handlers-title">Commands</span>
|
|
985
|
+
<span class="handlers-count" id="totalHandlersCount">0</span>
|
|
986
|
+
</div>
|
|
987
|
+
<div class="handlers-list" id="handlersList">
|
|
988
|
+
<div class="empty">No handlers registered</div>
|
|
989
|
+
</div>
|
|
990
|
+
</div>
|
|
991
|
+
</div>
|
|
992
|
+
|
|
993
|
+
<!-- Center Content -->
|
|
994
|
+
<div class="center-content">
|
|
995
|
+
<!-- Request Bar -->
|
|
996
|
+
<div class="request-bar">
|
|
997
|
+
<div style="flex: 1; display: flex; align-items: center; gap: 12px;">
|
|
998
|
+
<span style="color: var(--text-tertiary); font-size: 12px; text-transform: uppercase; letter-spacing: 0.05em;">Selected Command:</span>
|
|
999
|
+
<span id="selectedCommand" style="font-family: 'SF Mono', monospace; font-size: 14px; font-weight: 600; color: var(--text-primary);">None</span>
|
|
1000
|
+
</div>
|
|
1001
|
+
<input type="text" class="endpoint-input" id="requestIdInput" placeholder="Request ID (optional)" style="max-width: 200px;" />
|
|
1002
|
+
<button class="send-button" onclick="sendRequest()" id="sendButton" disabled>
|
|
1003
|
+
Send
|
|
1004
|
+
<span class="keyboard-shortcut">⌘ ↵</span>
|
|
1005
|
+
</button>
|
|
1006
|
+
</div>
|
|
1007
|
+
|
|
1008
|
+
<!-- Request/Response Container -->
|
|
1009
|
+
<div class="request-response-container">
|
|
1010
|
+
<!-- Request Panel -->
|
|
1011
|
+
<div class="request-panel">
|
|
1012
|
+
<div class="panel-content" style="display: flex; flex-direction: column; gap: 20px; padding: 20px;">
|
|
1013
|
+
<div id="paramsSection">
|
|
1014
|
+
<div class="section-header" style="background: transparent; padding: 0 0 12px 0; border-bottom: 1px solid var(--border);">
|
|
1015
|
+
<span class="section-title">Parameters</span>
|
|
1016
|
+
</div>
|
|
1017
|
+
<div id="paramsContainer" style="padding-top: 12px;">
|
|
1018
|
+
<div class="empty" id="emptyParams">No parameters required</div>
|
|
1019
|
+
<!-- Parameters will be added dynamically -->
|
|
1020
|
+
</div>
|
|
1021
|
+
</div>
|
|
1022
|
+
<div id="bodySection">
|
|
1023
|
+
<div class="section-header" style="background: transparent; padding: 0 0 12px 0; border-bottom: 1px solid var(--border);">
|
|
1024
|
+
<span class="section-title">Request Body (JSON)</span>
|
|
1025
|
+
</div>
|
|
1026
|
+
<div style="padding-top: 12px;">
|
|
1027
|
+
<textarea class="textarea" id="requestBody" style="min-height: 200px; font-family: 'SF Mono', monospace; width: 100%;">{}</textarea>
|
|
1028
|
+
</div>
|
|
1029
|
+
</div>
|
|
1030
|
+
</div>
|
|
1031
|
+
</div>
|
|
1032
|
+
|
|
1033
|
+
<!-- Response Panel -->
|
|
1034
|
+
<div class="response-panel">
|
|
1035
|
+
<div class="response-header">
|
|
1036
|
+
<div class="response-status">
|
|
1037
|
+
<div class="status-dot" id="statusDot"></div>
|
|
1038
|
+
<span id="statusText">Ready</span>
|
|
1039
|
+
</div>
|
|
1040
|
+
<span class="response-time" id="responseTime"></span>
|
|
1041
|
+
</div>
|
|
1042
|
+
<div class="response-content">
|
|
1043
|
+
<div class="code-block" id="responseContent" style="height: 100%;">No response yet</div>
|
|
1044
|
+
</div>
|
|
1045
|
+
</div>
|
|
1046
|
+
</div>
|
|
1047
|
+
</div>
|
|
1048
|
+
|
|
1049
|
+
<!-- Right Sidebar: Events -->
|
|
1050
|
+
<div class="sidebar-right">
|
|
1051
|
+
<div class="events-header">
|
|
1052
|
+
<div class="events-title">
|
|
1053
|
+
<span class="tab-indicator event"></span>
|
|
1054
|
+
Events
|
|
1055
|
+
</div>
|
|
1056
|
+
<div class="events-controls">
|
|
1057
|
+
<button class="button button-small button-secondary" onclick="loadEvents()">↻</button>
|
|
1058
|
+
<button class="button button-small button-secondary" onclick="clearEvents()">Clear</button>
|
|
1059
|
+
</div>
|
|
1060
|
+
</div>
|
|
1061
|
+
<div class="search-box" style="padding: 12px; border-bottom: 1px solid var(--border);">
|
|
1062
|
+
<span class="search-icon">🔍</span>
|
|
1063
|
+
<input type="text" class="search-input" id="eventSearch" placeholder="Search events..." style="background-color: var(--bg-secondary); color: var(--text-primary);">
|
|
1064
|
+
</div>
|
|
1065
|
+
<div class="events-list" id="eventsContainer">
|
|
1066
|
+
<div class="empty">No events yet</div>
|
|
1067
|
+
</div>
|
|
1068
|
+
</div>
|
|
1069
|
+
</div>
|
|
1070
|
+
|
|
1071
|
+
<div class="ws-status">
|
|
1072
|
+
<div class="ws-dot" id="wsDot"></div>
|
|
1073
|
+
<span id="wsText">Connecting...</span>
|
|
1074
|
+
</div>
|
|
1075
|
+
|
|
1076
|
+
<script>
|
|
1077
|
+
const API_BASE = window.location.origin;
|
|
1078
|
+
let currentState = {};
|
|
1079
|
+
let currentEvents = [];
|
|
1080
|
+
let responseStartTime;
|
|
1081
|
+
let availableCommands = [];
|
|
1082
|
+
let currentCommand = localStorage.getItem('lastCommand') || null;
|
|
1083
|
+
|
|
1084
|
+
// Logo SVGs - exact content from logo files
|
|
1085
|
+
const logoLight = `<svg width="637" height="637" viewBox="0 0 637 637" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
1086
|
+
<g clip-path="url(#clip0_1042_573)">
|
|
1087
|
+
<rect width="637" height="637"/>
|
|
1088
|
+
<path d="M693.161 -427.743L-623.632 1532.31L-591.107 1552.06L725.686 -407.988L693.161 -427.743Z" fill="#EC3F4A"/>
|
|
1089
|
+
<path d="M725.695 -407.962L-591.097 1552.09L-571.511 1563.98L745.281 -396.066L725.695 -407.962Z" fill="white"/>
|
|
1090
|
+
<path d="M745.281 -396.071L-571.511 1563.98L-538.986 1583.73L777.807 -376.315L745.281 -396.071Z" fill="#FF8A1D"/>
|
|
1091
|
+
<path d="M777.815 -376.302L-538.978 1583.75L-519.391 1595.64L797.402 -364.406L777.815 -376.302Z" fill="white"/>
|
|
1092
|
+
<path d="M797.394 -364.425L-519.399 1595.62L-486.874 1615.38L829.919 -344.67L797.394 -364.425Z" fill="#5EC72D"/>
|
|
1093
|
+
<path d="M829.913 -344.684L-486.879 1615.37L-467.293 1627.26L849.499 -332.787L829.913 -344.684Z" fill="white"/>
|
|
1094
|
+
<path d="M849.467 -332.791L-467.326 1627.26L-434.801 1647.01L881.992 -313.035L849.467 -332.791Z" fill="#42C3F7"/>
|
|
1095
|
+
<path d="M882 -313.038L-434.792 1647.01L-415.206 1658.91L901.587 -301.142L882 -313.038Z" fill="white"/>
|
|
1096
|
+
<path d="M673.55 -439.635L-643.242 1520.42L-623.656 1532.31L693.136 -427.738L673.55 -439.635Z" fill="white"/>
|
|
1097
|
+
<path d="M512.644 100H121.718C109.652 100 100 109.667 100 121.751V513.277C100 525.361 109.652 535.028 121.718 535.028H512.644C524.71 535.028 534.362 525.361 534.362 513.277V121.751C534.362 109.667 524.71 100 512.644 100Z" fill="#1A1A1A"/>
|
|
1098
|
+
<path d="M413.706 481.86C451.11 481.86 481.274 451.649 481.274 414.189C481.274 376.728 451.11 346.518 413.706 346.518C376.303 346.518 346.139 376.728 346.139 414.189C346.139 451.649 376.303 481.86 413.706 481.86Z" fill="white"/>
|
|
1099
|
+
<path d="M153.089 347.968C153.089 347.243 153.813 346.518 154.537 346.518H287.017C287.741 346.518 288.465 347.243 288.465 347.968V412.98C288.465 413.705 287.741 414.43 287.017 414.43H257.095C256.371 414.43 255.647 415.155 255.647 415.88V480.893C255.647 481.618 254.923 482.343 254.199 482.343H188.321C187.597 482.343 186.873 481.618 186.873 480.893V415.88C186.873 415.155 186.149 414.43 185.425 414.43H154.296C153.572 414.43 152.848 413.705 152.848 412.98V347.968H153.089Z" fill="white"/>
|
|
1100
|
+
<path d="M347.587 153.17C346.863 153.17 346.139 153.895 346.139 154.621V223.017C346.139 259.269 376.303 288.513 413.706 288.513C451.11 288.513 481.274 259.269 481.274 223.017V154.621C481.274 153.895 480.55 153.17 479.826 153.17H347.345H347.587Z" fill="white"/>
|
|
1101
|
+
<path d="M153.33 286.339C152.848 287.306 153.33 288.272 154.537 288.272H286.776C287.742 288.272 288.465 287.306 287.983 286.339L221.863 154.139C221.381 153.172 219.933 153.172 219.45 154.139L153.33 286.339Z" fill="white"/>
|
|
1102
|
+
</g>
|
|
1103
|
+
<defs>
|
|
1104
|
+
<clipPath id="clip0_1042_573">
|
|
1105
|
+
<rect width="637" height="637" fill="white"/>
|
|
1106
|
+
</clipPath>
|
|
1107
|
+
</defs>
|
|
1108
|
+
</svg>`;
|
|
1109
|
+
|
|
1110
|
+
const logoDark = `<svg width="637" height="637" viewBox="0 0 637 637" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
1111
|
+
<g clip-path="url(#clip0_1042_512)">
|
|
1112
|
+
<rect width="637" height="637"/>
|
|
1113
|
+
<path d="M693.161 -427.743L-623.632 1532.31L-591.107 1552.06L725.686 -407.988L693.161 -427.743Z" fill="#EC3F4A"/>
|
|
1114
|
+
<path d="M725.695 -407.962L-591.097 1552.09L-571.511 1563.98L745.281 -396.066L725.695 -407.962Z" fill="#1A1A1A"/>
|
|
1115
|
+
<path d="M745.281 -396.071L-571.511 1563.98L-538.986 1583.73L777.807 -376.315L745.281 -396.071Z" fill="#FF8A1D"/>
|
|
1116
|
+
<path d="M777.815 -376.302L-538.978 1583.75L-519.391 1595.64L797.402 -364.406L777.815 -376.302Z" fill="#1A1A1A"/>
|
|
1117
|
+
<path d="M797.394 -364.425L-519.399 1595.62L-486.874 1615.38L829.919 -344.67L797.394 -364.425Z" fill="#5EC72D"/>
|
|
1118
|
+
<path d="M829.913 -344.684L-486.879 1615.37L-467.293 1627.26L849.499 -332.787L829.913 -344.684Z" fill="#1A1A1A"/>
|
|
1119
|
+
<path d="M849.467 -332.791L-467.326 1627.26L-434.801 1647.01L881.992 -313.035L849.467 -332.791Z" fill="#42C3F7"/>
|
|
1120
|
+
<path d="M882 -313.038L-434.792 1647.01L-415.206 1658.91L901.587 -301.142L882 -313.038Z" fill="#1A1A1A"/>
|
|
1121
|
+
<path d="M673.55 -439.635L-643.242 1520.42L-623.656 1532.31L693.136 -427.738L673.55 -439.635Z" fill="#1A1A1A"/>
|
|
1122
|
+
<path d="M512.644 100H121.718C109.652 100 100 109.667 100 121.751V513.277C100 525.361 109.652 535.028 121.718 535.028H512.644C524.71 535.028 534.362 525.361 534.362 513.277V121.751C534.362 109.667 524.71 100 512.644 100Z" fill="white"/>
|
|
1123
|
+
<path d="M413.706 481.86C451.11 481.86 481.274 451.649 481.274 414.189C481.274 376.728 451.11 346.518 413.706 346.518C376.303 346.518 346.139 376.728 346.139 414.189C346.139 451.649 376.303 481.86 413.706 481.86Z" fill="#1A1A1A"/>
|
|
1124
|
+
<path d="M153.089 347.968C153.089 347.243 153.813 346.518 154.537 346.518H287.017C287.741 346.518 288.465 347.243 288.465 347.968V412.98C288.465 413.705 287.741 414.43 287.017 414.43H257.095C256.371 414.43 255.647 415.155 255.647 415.88V480.893C255.647 481.618 254.923 482.343 254.199 482.343H188.321C187.597 482.343 186.873 481.618 186.873 480.893V415.88C186.873 415.155 186.149 414.43 185.425 414.43H154.296C153.572 414.43 152.848 413.705 152.848 412.98V347.968H153.089Z" fill="#1A1A1A"/>
|
|
1125
|
+
<path d="M347.587 153.17C346.863 153.17 346.139 153.895 346.139 154.621V223.017C346.139 259.269 376.303 288.513 413.706 288.513C451.11 288.513 481.274 259.269 481.274 223.017V154.621C481.274 153.895 480.55 153.17 479.826 153.17H347.345H347.587Z" fill="#1A1A1A"/>
|
|
1126
|
+
<path d="M153.33 286.339C152.848 287.306 153.33 288.272 154.537 288.272H286.776C287.742 288.272 288.465 287.306 287.983 286.339L221.863 154.139C221.381 153.172 219.933 153.172 219.45 154.139L153.33 286.339Z" fill="#1A1A1A"/>
|
|
1127
|
+
</g>
|
|
1128
|
+
<defs>
|
|
1129
|
+
<clipPath id="clip0_1042_512">
|
|
1130
|
+
<rect width="637" height="637" fill="white"/>
|
|
1131
|
+
</clipPath>
|
|
1132
|
+
</defs>
|
|
1133
|
+
</svg>`;
|
|
1134
|
+
|
|
1135
|
+
// Theme management
|
|
1136
|
+
function getSystemTheme() {
|
|
1137
|
+
return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
function applyTheme(theme) {
|
|
1141
|
+
if (theme === 'system') {
|
|
1142
|
+
theme = getSystemTheme();
|
|
1143
|
+
}
|
|
1144
|
+
document.body.setAttribute('data-theme', theme);
|
|
1145
|
+
|
|
1146
|
+
// Update logo based on theme
|
|
1147
|
+
const logoMark = document.getElementById('logoMark');
|
|
1148
|
+
if (logoMark) {
|
|
1149
|
+
logoMark.innerHTML = theme === 'dark' ? logoDark : logoLight;
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
function getThemeIcon(theme) {
|
|
1154
|
+
const icons = {
|
|
1155
|
+
light: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />',
|
|
1156
|
+
dark: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />',
|
|
1157
|
+
system: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.75 17L9 20l-1 1h8l-1-1-.75-3M3 13h18M5 17h14a2 2 0 002-2V5a2 2 0 00-2-2H5a2 2 0 00-2 2v10a2 2 0 002 2z" />'
|
|
1158
|
+
};
|
|
1159
|
+
return icons[theme] || icons.system;
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
function updateThemeIcon(theme) {
|
|
1163
|
+
const iconElement = document.getElementById('currentThemeIcon');
|
|
1164
|
+
if (iconElement) {
|
|
1165
|
+
iconElement.innerHTML = getThemeIcon(theme);
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
function toggleThemeDropdown() {
|
|
1170
|
+
const dropdown = document.getElementById('themeDropdown');
|
|
1171
|
+
dropdown.classList.toggle('open');
|
|
1172
|
+
}
|
|
1173
|
+
|
|
1174
|
+
function setTheme(theme) {
|
|
1175
|
+
localStorage.setItem('theme', theme);
|
|
1176
|
+
applyTheme(theme);
|
|
1177
|
+
updateThemeIcon(theme);
|
|
1178
|
+
|
|
1179
|
+
// Update button states
|
|
1180
|
+
document.querySelectorAll('.theme-option').forEach(btn => {
|
|
1181
|
+
btn.classList.toggle('active', btn.getAttribute('data-theme') === theme);
|
|
1182
|
+
});
|
|
1183
|
+
|
|
1184
|
+
// Close dropdown
|
|
1185
|
+
document.getElementById('themeDropdown').classList.remove('open');
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
// Close dropdown when clicking outside
|
|
1189
|
+
document.addEventListener('click', (e) => {
|
|
1190
|
+
const switcher = document.querySelector('.theme-switcher');
|
|
1191
|
+
if (!switcher.contains(e.target)) {
|
|
1192
|
+
document.getElementById('themeDropdown').classList.remove('open');
|
|
1193
|
+
}
|
|
1194
|
+
});
|
|
1195
|
+
|
|
1196
|
+
// Initialize theme
|
|
1197
|
+
const savedTheme = localStorage.getItem('theme') || 'dark';
|
|
1198
|
+
setTheme(savedTheme);
|
|
1199
|
+
updateThemeIcon(savedTheme);
|
|
1200
|
+
|
|
1201
|
+
// Listen for system theme changes
|
|
1202
|
+
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
|
|
1203
|
+
if (localStorage.getItem('theme') === 'system') {
|
|
1204
|
+
applyTheme('system');
|
|
1205
|
+
}
|
|
1206
|
+
});
|
|
1207
|
+
|
|
1208
|
+
function selectCommand(command) {
|
|
1209
|
+
currentCommand = command;
|
|
1210
|
+
localStorage.setItem('lastCommand', command);
|
|
1211
|
+
|
|
1212
|
+
// Update selected command display
|
|
1213
|
+
document.getElementById('selectedCommand').textContent = command;
|
|
1214
|
+
|
|
1215
|
+
// Update sidebar selection
|
|
1216
|
+
document.querySelectorAll('.handler-item').forEach(item => {
|
|
1217
|
+
item.classList.toggle('selected', item.dataset.command === command);
|
|
1218
|
+
});
|
|
1219
|
+
|
|
1220
|
+
// Enable send button
|
|
1221
|
+
document.getElementById('sendButton').disabled = false;
|
|
1222
|
+
|
|
1223
|
+
// Clear response
|
|
1224
|
+
document.getElementById('responseContent').textContent = 'No response yet';
|
|
1225
|
+
document.getElementById('statusDot').className = 'status-dot';
|
|
1226
|
+
document.getElementById('statusText').textContent = 'Ready';
|
|
1227
|
+
document.getElementById('responseTime').textContent = '';
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
// Tab switching function removed - no longer needed
|
|
1231
|
+
|
|
1232
|
+
async function sendRequest() {
|
|
1233
|
+
if (!currentCommand) {
|
|
1234
|
+
alert('Please select a command first');
|
|
1235
|
+
return;
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1238
|
+
responseStartTime = Date.now();
|
|
1239
|
+
|
|
1240
|
+
try {
|
|
1241
|
+
const requestId = document.getElementById('requestIdInput').value;
|
|
1242
|
+
const bodyStr = document.getElementById('requestBody').value;
|
|
1243
|
+
|
|
1244
|
+
const commandData = JSON.parse(bodyStr);
|
|
1245
|
+
|
|
1246
|
+
const command = {
|
|
1247
|
+
type: currentCommand,
|
|
1248
|
+
data: commandData
|
|
1249
|
+
};
|
|
1250
|
+
|
|
1251
|
+
if (requestId) {
|
|
1252
|
+
command.requestId = requestId;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
const response = await fetch(`${API_BASE}/command`, {
|
|
1256
|
+
method: 'POST',
|
|
1257
|
+
headers: {
|
|
1258
|
+
'Content-Type': 'application/json'
|
|
1259
|
+
},
|
|
1260
|
+
body: JSON.stringify(command)
|
|
1261
|
+
});
|
|
1262
|
+
|
|
1263
|
+
const responseTime = Date.now() - responseStartTime;
|
|
1264
|
+
const result = await response.json();
|
|
1265
|
+
|
|
1266
|
+
document.getElementById('responseContent').textContent = JSON.stringify(result, null, 2);
|
|
1267
|
+
document.getElementById('responseTime').textContent = `${responseTime}ms`;
|
|
1268
|
+
|
|
1269
|
+
const statusDot = document.getElementById('statusDot');
|
|
1270
|
+
const statusText = document.getElementById('statusText');
|
|
1271
|
+
|
|
1272
|
+
if (response.ok && result.status === 'ack') {
|
|
1273
|
+
statusDot.className = 'status-dot success';
|
|
1274
|
+
statusText.textContent = 'Success';
|
|
1275
|
+
} else {
|
|
1276
|
+
statusDot.className = 'status-dot error';
|
|
1277
|
+
statusText.textContent = response.status === 404 ? 'Command Not Found' : 'Error';
|
|
1278
|
+
|
|
1279
|
+
// Show available commands if provided
|
|
1280
|
+
if (result.availableCommands) {
|
|
1281
|
+
const availableCommands = result.availableCommands.length > 0
|
|
1282
|
+
? `Available commands: ${result.availableCommands.join(', ')}`
|
|
1283
|
+
: 'No command handlers registered';
|
|
1284
|
+
result.availableCommands = availableCommands;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
} catch (error) {
|
|
1288
|
+
const responseTime = Date.now() - responseStartTime;
|
|
1289
|
+
|
|
1290
|
+
document.getElementById('responseContent').textContent = error.message;
|
|
1291
|
+
document.getElementById('responseTime').textContent = `${responseTime}ms`;
|
|
1292
|
+
|
|
1293
|
+
document.getElementById('statusDot').className = 'status-dot error';
|
|
1294
|
+
document.getElementById('statusText').textContent = 'Error';
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
async function loadRegistry() {
|
|
1299
|
+
try {
|
|
1300
|
+
const response = await fetch(`${API_BASE}/registry`);
|
|
1301
|
+
const data = await response.json();
|
|
1302
|
+
|
|
1303
|
+
const eventHandlers = data.eventHandlers || [];
|
|
1304
|
+
const folds = data.folds || [];
|
|
1305
|
+
const commandHandlers = data.commandHandlers || [];
|
|
1306
|
+
|
|
1307
|
+
// Update count in sidebar (only commands now)
|
|
1308
|
+
document.getElementById('totalHandlersCount').textContent = commandHandlers.length;
|
|
1309
|
+
|
|
1310
|
+
// Build unified handlers list
|
|
1311
|
+
const handlersListEl = document.getElementById('handlersList');
|
|
1312
|
+
|
|
1313
|
+
if (commandHandlers.length === 0) {
|
|
1314
|
+
handlersListEl.innerHTML = '<div class="empty">No handlers registered</div>';
|
|
1315
|
+
} else {
|
|
1316
|
+
let html = '';
|
|
1317
|
+
|
|
1318
|
+
// Only show Command Handlers
|
|
1319
|
+
if (commandHandlers.length > 0) {
|
|
1320
|
+
html += '<div class="handler-group">';
|
|
1321
|
+
commandHandlers.forEach(handler => {
|
|
1322
|
+
html += `<div class="handler-item" onclick="selectCommand('${handler}')" data-command="${handler}">
|
|
1323
|
+
<div class="handler-type-indicator command"></div>
|
|
1324
|
+
<span class="handler-name">${handler}</span>
|
|
1325
|
+
</div>`;
|
|
1326
|
+
});
|
|
1327
|
+
html += '</div>';
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
handlersListEl.innerHTML = html;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
// Store available commands
|
|
1334
|
+
availableCommands = commandHandlers;
|
|
1335
|
+
|
|
1336
|
+
// Restore last selected command if it's still available
|
|
1337
|
+
const lastCommand = localStorage.getItem('lastCommand');
|
|
1338
|
+
if (lastCommand && commandHandlers.includes(lastCommand)) {
|
|
1339
|
+
selectCommand(lastCommand);
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
} catch (error) {
|
|
1343
|
+
console.error('Failed to load registry:', error);
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
async function loadState() {
|
|
1348
|
+
try {
|
|
1349
|
+
const response = await fetch(`${API_BASE}/state`);
|
|
1350
|
+
currentState = await response.json();
|
|
1351
|
+
} catch (error) {
|
|
1352
|
+
console.error('Failed to load state:', error);
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
async function loadEvents() {
|
|
1357
|
+
try {
|
|
1358
|
+
const response = await fetch(`${API_BASE}/events`);
|
|
1359
|
+
currentEvents = await response.json();
|
|
1360
|
+
displayEvents();
|
|
1361
|
+
} catch (error) {
|
|
1362
|
+
console.error('Failed to load events:', error);
|
|
1363
|
+
document.getElementById('eventsContainer').innerHTML = '<div class="empty">Failed to load events</div>';
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
function displayEvents() {
|
|
1368
|
+
const searchTerm = document.getElementById('eventSearch').value.toLowerCase();
|
|
1369
|
+
const container = document.getElementById('eventsContainer');
|
|
1370
|
+
|
|
1371
|
+
if (currentEvents.length === 0) {
|
|
1372
|
+
container.innerHTML = '<div class="empty">No events yet</div>';
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1375
|
+
|
|
1376
|
+
let filteredEvents = currentEvents;
|
|
1377
|
+
if (searchTerm) {
|
|
1378
|
+
filteredEvents = currentEvents.filter(item => {
|
|
1379
|
+
const eventStr = JSON.stringify(item.event).toLowerCase();
|
|
1380
|
+
return eventStr.includes(searchTerm) || item.event.type.toLowerCase().includes(searchTerm);
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
if (filteredEvents.length === 0) {
|
|
1385
|
+
container.innerHTML = '<div class="empty">No matching events</div>';
|
|
1386
|
+
return;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
// Display events in reverse chronological order (newest first)
|
|
1390
|
+
const eventsHtml = filteredEvents
|
|
1391
|
+
.slice()
|
|
1392
|
+
.reverse()
|
|
1393
|
+
.map((item, index) => {
|
|
1394
|
+
const time = new Date(item.timestamp).toLocaleTimeString();
|
|
1395
|
+
return `
|
|
1396
|
+
<div class="event-item">
|
|
1397
|
+
<div class="event-header">
|
|
1398
|
+
<div class="event-type">${item.event.type}</div>
|
|
1399
|
+
<div class="event-time">${time}</div>
|
|
1400
|
+
</div>
|
|
1401
|
+
<div class="event-data">${JSON.stringify(item.event.data, null, 2)}</div>
|
|
1402
|
+
</div>
|
|
1403
|
+
`;
|
|
1404
|
+
})
|
|
1405
|
+
.join('');
|
|
1406
|
+
|
|
1407
|
+
container.innerHTML = eventsHtml;
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
document.getElementById('eventSearch').addEventListener('input', displayEvents);
|
|
1411
|
+
|
|
1412
|
+
async function clearEvents() {
|
|
1413
|
+
currentEvents = [];
|
|
1414
|
+
displayEvents();
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
|
|
1418
|
+
// Keyboard shortcut for send
|
|
1419
|
+
document.addEventListener('keydown', (e) => {
|
|
1420
|
+
if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') {
|
|
1421
|
+
sendRequest();
|
|
1422
|
+
}
|
|
1423
|
+
});
|
|
1424
|
+
|
|
1425
|
+
// WebSocket connection for real-time updates
|
|
1426
|
+
const ws = new WebSocket(`ws://${window.location.hostname}:${window.location.port}`);
|
|
1427
|
+
|
|
1428
|
+
ws.onopen = () => {
|
|
1429
|
+
console.log('WebSocket connected');
|
|
1430
|
+
document.getElementById('wsDot').classList.add('connected');
|
|
1431
|
+
document.getElementById('wsText').textContent = 'Connected';
|
|
1432
|
+
};
|
|
1433
|
+
|
|
1434
|
+
ws.onmessage = (event) => {
|
|
1435
|
+
const message = JSON.parse(event.data);
|
|
1436
|
+
if (message.type === 'event' || message.type === 'state') {
|
|
1437
|
+
// Reload state when events occur
|
|
1438
|
+
loadState();
|
|
1439
|
+
// Also reload events
|
|
1440
|
+
loadEvents();
|
|
1441
|
+
} else if (message.type === 'commandError') {
|
|
1442
|
+
// Show command error in response
|
|
1443
|
+
document.getElementById('responseContent').textContent = JSON.stringify({
|
|
1444
|
+
status: 'error',
|
|
1445
|
+
commandId: message.commandId,
|
|
1446
|
+
error: message.error,
|
|
1447
|
+
timestamp: message.timestamp
|
|
1448
|
+
}, null, 2);
|
|
1449
|
+
document.getElementById('statusDot').className = 'status-dot error';
|
|
1450
|
+
document.getElementById('statusText').textContent = 'Command Failed';
|
|
1451
|
+
document.getElementById('responseTime').textContent = 'Async Error';
|
|
1452
|
+
}
|
|
1453
|
+
};
|
|
1454
|
+
|
|
1455
|
+
ws.onerror = (error) => {
|
|
1456
|
+
console.error('WebSocket error:', error);
|
|
1457
|
+
document.getElementById('wsDot').classList.remove('connected');
|
|
1458
|
+
document.getElementById('wsText').textContent = 'Disconnected';
|
|
1459
|
+
};
|
|
1460
|
+
|
|
1461
|
+
ws.onclose = () => {
|
|
1462
|
+
document.getElementById('wsDot').classList.remove('connected');
|
|
1463
|
+
document.getElementById('wsText').textContent = 'Disconnected';
|
|
1464
|
+
};
|
|
1465
|
+
|
|
1466
|
+
// Initial load
|
|
1467
|
+
loadRegistry();
|
|
1468
|
+
loadState();
|
|
1469
|
+
loadEvents();
|
|
1470
|
+
|
|
1471
|
+
// Initial command will be restored when registry loads
|
|
1472
|
+
|
|
1473
|
+
// Refresh registry every 5 seconds
|
|
1474
|
+
setInterval(loadRegistry, 5000);
|
|
1475
|
+
|
|
1476
|
+
// Auto-refresh events every 2 seconds
|
|
1477
|
+
setInterval(loadEvents, 2000);
|
|
1478
|
+
</script>
|
|
1479
|
+
</body>
|
|
1480
|
+
</html>
|