@hina114514/chaite 1.9.3 → 1.9.5
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/{adapters-BeZFg37c.mjs → adapters-BtoEz02k.mjs} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/{src-BjDIhdKO.mjs → src-DpLgiiEQ.mjs} +3 -3
- package/dist/{types-6jzst6Q4.mjs → types-kzT5dZX7.mjs} +1 -1
- package/frontend/build/index.html +533 -537
- package/package.json +70 -70
|
@@ -1,537 +1,533 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="zh-CN">
|
|
3
|
-
<head>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
if (
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
<
|
|
416
|
-
</
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
<
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
<
|
|
436
|
-
</
|
|
437
|
-
</div>
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
</
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
</
|
|
487
|
-
<
|
|
488
|
-
|
|
489
|
-
</
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
</div>
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
<
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
}).mount('#app')
|
|
535
|
-
</script>
|
|
536
|
-
</body>
|
|
537
|
-
</html>
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8"/>
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
|
6
|
+
<title>Chaite Dashboard</title>
|
|
7
|
+
<style>
|
|
8
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
9
|
+
:root{
|
|
10
|
+
--bg:#0c0e14;--surface:#141720;--surface2:#1a1e2a;--surface3:#222738;
|
|
11
|
+
--border:#2a2f42;--text:#e0e4ef;--text2:#8b92a8;--accent:#6c8cff;--accent2:#4a6aef;
|
|
12
|
+
--green:#4ade80;--red:#f87171;--yellow:#facc15;--purple:#a78bfa;
|
|
13
|
+
--radius:10px;--shadow:0 2px 12px rgba(0,0,0,.4);
|
|
14
|
+
}
|
|
15
|
+
body{background:var(--bg);color:var(--text);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;line-height:1.6;min-height:100vh}
|
|
16
|
+
a{color:var(--accent);text-decoration:none}
|
|
17
|
+
a:hover{text-decoration:underline}
|
|
18
|
+
.app{max-width:1280px;margin:0 auto;padding:20px}
|
|
19
|
+
|
|
20
|
+
/* Login */
|
|
21
|
+
.login-wrap{display:flex;align-items:center;justify-content:center;min-height:100vh}
|
|
22
|
+
.login-box{background:var(--surface);border:1px solid var(--border);border-radius:16px;padding:48px 40px;width:380px;text-align:center;box-shadow:var(--shadow)}
|
|
23
|
+
.login-box h1{font-size:24px;margin-bottom:8px}
|
|
24
|
+
.login-box p{color:var(--text2);font-size:14px;margin-bottom:32px}
|
|
25
|
+
.login-box .spinner{display:inline-block;width:18px;height:18px;border:2px solid var(--text2);border-top-color:var(--accent);border-radius:50%;animation:spin .6s linear infinite}
|
|
26
|
+
.login-box .err{color:var(--red);font-size:13px;margin-bottom:12px;min-height:20px}
|
|
27
|
+
@keyframes spin{to{transform:rotate(360deg)}}
|
|
28
|
+
|
|
29
|
+
/* Header */
|
|
30
|
+
.header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px;margin-bottom:24px}
|
|
31
|
+
.header h1{font-size:20px;display:flex;align-items:center;gap:8px}
|
|
32
|
+
.header h1 span{color:var(--accent)}
|
|
33
|
+
.header .meta{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
|
34
|
+
.badge{background:var(--surface2);border:1px solid var(--border);border-radius:20px;padding:3px 12px;font-size:12px;color:var(--text2)}
|
|
35
|
+
.badge.ok{border-color:var(--green);color:var(--green)}
|
|
36
|
+
.badge.err{border-color:var(--red);color:var(--red)}
|
|
37
|
+
|
|
38
|
+
/* Buttons */
|
|
39
|
+
.btn{background:var(--surface2);border:1px solid var(--border);border-radius:8px;color:var(--text);padding:6px 14px;font-size:13px;cursor:pointer;display:inline-flex;align-items:center;gap:6px;transition:all .15s}
|
|
40
|
+
.btn:hover{background:var(--surface3);border-color:var(--accent)}
|
|
41
|
+
.btn:disabled{opacity:.5;cursor:not-allowed}
|
|
42
|
+
.btn.primary{background:var(--accent2);border-color:var(--accent);color:#fff}
|
|
43
|
+
.btn.primary:hover{background:var(--accent)}
|
|
44
|
+
.btn.danger{border-color:var(--red);color:var(--red)}
|
|
45
|
+
.btn.danger:hover{background:rgba(248,113,113,.15)}
|
|
46
|
+
.btn.sm{padding:3px 10px;font-size:12px}
|
|
47
|
+
|
|
48
|
+
/* Cards */
|
|
49
|
+
.card{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:20px;margin-bottom:16px;box-shadow:var(--shadow)}
|
|
50
|
+
.card h3{font-size:15px;margin-bottom:14px;display:flex;align-items:center;gap:8px}
|
|
51
|
+
.card h3 .dot{width:8px;height:8px;border-radius:50%}
|
|
52
|
+
|
|
53
|
+
/* Stat cards */
|
|
54
|
+
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:12px;margin-bottom:20px}
|
|
55
|
+
.stat{background:var(--surface);border:1px solid var(--border);border-radius:var(--radius);padding:16px;text-align:center}
|
|
56
|
+
.stat .val{font-size:28px;font-weight:700;color:var(--accent)}
|
|
57
|
+
.stat .label{font-size:12px;color:var(--text2);margin-top:4px}
|
|
58
|
+
|
|
59
|
+
/* Table */
|
|
60
|
+
.tbl{width:100%;border-collapse:collapse;font-size:13px}
|
|
61
|
+
.tbl th{text-align:left;padding:10px 12px;color:var(--text2);font-weight:600;border-bottom:1px solid var(--border);font-size:12px;text-transform:uppercase;letter-spacing:.5px}
|
|
62
|
+
.tbl td{padding:10px 12px;border-bottom:1px solid var(--border)}
|
|
63
|
+
.tbl tr:hover td{background:var(--surface2)}
|
|
64
|
+
.pill{display:inline-block;padding:2px 10px;border-radius:12px;font-size:11px;font-weight:600}
|
|
65
|
+
.pill.on{background:rgba(74,222,128,.15);color:var(--green)}
|
|
66
|
+
.pill.off{background:rgba(248,113,113,.12);color:var(--red)}
|
|
67
|
+
.pill.model{background:rgba(108,140,255,.12);color:var(--accent);margin:2px 3px 2px 0}
|
|
68
|
+
|
|
69
|
+
/* Tabs */
|
|
70
|
+
.tabs{display:flex;gap:0;margin-bottom:20px;border-bottom:1px solid var(--border)}
|
|
71
|
+
.tab{padding:10px 20px;font-size:13px;cursor:pointer;color:var(--text2);border-bottom:2px solid transparent;transition:all .15s}
|
|
72
|
+
.tab:hover{color:var(--text)}
|
|
73
|
+
.tab.active{color:var(--accent);border-bottom-color:var(--accent)}
|
|
74
|
+
|
|
75
|
+
/* Modal */
|
|
76
|
+
.modal-mask{position:fixed;inset:0;background:rgba(0,0,0,.6);display:flex;align-items:center;justify-content:center;z-index:100}
|
|
77
|
+
.modal{background:var(--surface);border:1px solid var(--border);border-radius:14px;padding:28px;width:520px;max-height:85vh;overflow-y:auto;box-shadow:0 8px 32px rgba(0,0,0,.5)}
|
|
78
|
+
.modal h3{margin-bottom:20px;font-size:17px}
|
|
79
|
+
.form-row{margin-bottom:14px}
|
|
80
|
+
.form-row label{display:block;font-size:12px;color:var(--text2);margin-bottom:5px}
|
|
81
|
+
.form-row input,.form-row select,.form-row textarea{width:100%;padding:8px 12px;background:var(--surface2);border:1px solid var(--border);border-radius:6px;color:var(--text);font-size:13px;font-family:inherit}
|
|
82
|
+
.form-row textarea{min-height:80px;resize:vertical}
|
|
83
|
+
.form-row input:focus,.form-row select:focus,.form-row textarea:focus{outline:none;border-color:var(--accent)}
|
|
84
|
+
.modal-btns{display:flex;justify-content:flex-end;gap:8px;margin-top:20px}
|
|
85
|
+
|
|
86
|
+
/* Toast */
|
|
87
|
+
.toast{position:fixed;top:20px;right:20px;padding:10px 20px;border-radius:8px;font-size:13px;z-index:200;animation:slideIn .3s}
|
|
88
|
+
.toast.ok{background:var(--green);color:#000}
|
|
89
|
+
.toast.err{background:var(--red);color:#fff}
|
|
90
|
+
@keyframes slideIn{from{opacity:0;transform:translateX(40px)}to{opacity:1;transform:none}}
|
|
91
|
+
|
|
92
|
+
/* Responsive */
|
|
93
|
+
@media(max-width:768px){
|
|
94
|
+
.stats{grid-template-columns:repeat(2,1fr)}
|
|
95
|
+
.modal{width:95%;margin:10px}
|
|
96
|
+
.header{flex-direction:column;align-items:flex-start}
|
|
97
|
+
}
|
|
98
|
+
</style>
|
|
99
|
+
</head>
|
|
100
|
+
<body>
|
|
101
|
+
<div id="app"></div>
|
|
102
|
+
<script>
|
|
103
|
+
const{createApp,ref,reactive,computed,onMounted,onUnmounted,watch}=Vue
|
|
104
|
+
|
|
105
|
+
const API=(path,opt={})=>{
|
|
106
|
+
const t=localStorage.getItem('chaite_jwt')
|
|
107
|
+
return fetch(path,{...opt,headers:{'Content-Type':'application/json','Authorization':t?'Bearer '+t:'',...(opt.headers||{})}}).then(async r=>{
|
|
108
|
+
if(r.status===401){localStorage.removeItem('chaite_jwt');location.reload()}
|
|
109
|
+
return r.json()
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
createApp({
|
|
114
|
+
setup(){
|
|
115
|
+
// Auth
|
|
116
|
+
const jwt=ref(localStorage.getItem('chaite_jwt')||'')
|
|
117
|
+
const loggedIn=ref(!!jwt.value)
|
|
118
|
+
const loginLoading=ref(false)
|
|
119
|
+
const loginError=ref('')
|
|
120
|
+
|
|
121
|
+
// State
|
|
122
|
+
const tab=ref('overview')
|
|
123
|
+
const health=ref(null)
|
|
124
|
+
const stats=ref(null)
|
|
125
|
+
const channels=ref([])
|
|
126
|
+
const tools=ref([])
|
|
127
|
+
const presets=ref([])
|
|
128
|
+
const processors=ref([])
|
|
129
|
+
const triggers=ref([])
|
|
130
|
+
const toolGroups=ref([])
|
|
131
|
+
const loading=ref(true)
|
|
132
|
+
const refreshTime=ref('')
|
|
133
|
+
let timer=null
|
|
134
|
+
|
|
135
|
+
// Modal
|
|
136
|
+
const modal=ref(null) // 'channel'|'preset'|'tool'|'processor'|'trigger'|'toolGroup'|null
|
|
137
|
+
const editing=ref(null) // object being edited
|
|
138
|
+
const form=ref({})
|
|
139
|
+
|
|
140
|
+
// Toast
|
|
141
|
+
const toastMsg=ref('')
|
|
142
|
+
const toastType=ref('ok')
|
|
143
|
+
let toastTimer=null
|
|
144
|
+
function toast(msg,type='ok'){toastMsg.value=msg;toastType.value=type;clearTimeout(toastTimer);toastTimer=setTimeout(()=>toastMsg.value='',3000)}
|
|
145
|
+
|
|
146
|
+
// Login
|
|
147
|
+
async function doLogin(){
|
|
148
|
+
loginError.value='';loginLoading.value=true
|
|
149
|
+
try{
|
|
150
|
+
const url=new URL(location.href)
|
|
151
|
+
const urlToken=url.searchParams.get('token')
|
|
152
|
+
const token=urlToken||prompt('Enter access token:')
|
|
153
|
+
if(!token){loginLoading.value=false;return}
|
|
154
|
+
const d=await fetch('/api/auth/login',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({token})}).then(r=>r.json())
|
|
155
|
+
if(d.data?.token){
|
|
156
|
+
jwt.value=d.data.token;localStorage.setItem('chaite_jwt',d.data.token);loggedIn.value=true
|
|
157
|
+
url.searchParams.delete('token');history.replaceState(null,'',url.pathname+url.search)
|
|
158
|
+
refreshAll()
|
|
159
|
+
}else{loginError.value=d.message||'Login failed'}
|
|
160
|
+
}catch(e){loginError.value='Network error'}
|
|
161
|
+
finally{loginLoading.value=false}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function logout(){jwt.value='';localStorage.removeItem('chaite_jwt');loggedIn.value=false;clearInterval(timer)}
|
|
165
|
+
|
|
166
|
+
// Data fetching
|
|
167
|
+
async function refreshAll(){
|
|
168
|
+
loading.value=true
|
|
169
|
+
try{
|
|
170
|
+
const[h,s,c,t,p,pr,tr,tg]=await Promise.all([
|
|
171
|
+
API('/api/system/health').catch(()=>({})),
|
|
172
|
+
API('/api/system/stats').catch(()=>({})),
|
|
173
|
+
API('/api/channels/list').catch(()=>({})),
|
|
174
|
+
API('/api/tools/list').catch(()=>({})),
|
|
175
|
+
API('/api/preset/list').catch(()=>({})),
|
|
176
|
+
API('/api/processors/list').catch(()=>({})),
|
|
177
|
+
API('/api/triggers/list').catch(()=>({})),
|
|
178
|
+
API('/api/toolGroups/list').catch(()=>({})),
|
|
179
|
+
])
|
|
180
|
+
health.value=h.data||null
|
|
181
|
+
stats.value=s.data||null
|
|
182
|
+
channels.value=c.data||[]
|
|
183
|
+
tools.value=t.data||[]
|
|
184
|
+
presets.value=p.data||[]
|
|
185
|
+
processors.value=pr.data||[]
|
|
186
|
+
triggers.value=tr.data||[]
|
|
187
|
+
toolGroups.value=tg.data||[]
|
|
188
|
+
refreshTime.value=new Date().toLocaleTimeString()
|
|
189
|
+
}catch(e){console.error(e)}
|
|
190
|
+
finally{loading.value=false}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// CRUD helpers
|
|
194
|
+
async function testChannel(id){
|
|
195
|
+
const d=await API('/api/system/test-channel',{method:'POST',body:JSON.stringify({channelId:id})})
|
|
196
|
+
if(d.data?.status==='ok')toast(`✅ ${d.data.channelName} — ${d.data.latency}ms`)
|
|
197
|
+
else toast(`❌ ${d.data?.error||d.message}`,'err')
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function openModal(type,item=null){
|
|
201
|
+
modal.value=type
|
|
202
|
+
editing.value=item
|
|
203
|
+
if(item)form.value=JSON.parse(JSON.stringify(item))
|
|
204
|
+
else{
|
|
205
|
+
const defaults={
|
|
206
|
+
channel:{name:'',adapterType:'openai',type:'openai',models:[''],options:{baseUrl:'',apiKey:''},status:'enabled',weight:1,priority:0},
|
|
207
|
+
preset:{name:'',prefix:'',sendMessageOption:{model:'',temperature:0.8,maxToken:4096,systemOverride:''}},
|
|
208
|
+
tool:{name:'',description:'',code:''},
|
|
209
|
+
processor:{name:'',type:'pre',description:'',code:''},
|
|
210
|
+
trigger:{name:'',description:'',code:''},
|
|
211
|
+
toolGroup:{name:'',description:'',toolIds:[],status:'enabled',isDefault:false},
|
|
212
|
+
}
|
|
213
|
+
form.value=defaults[type]||{}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
function closeModal(){modal.value=null;editing.value=null;form.value={}}
|
|
217
|
+
|
|
218
|
+
async function saveItem(){
|
|
219
|
+
const type=modal.value
|
|
220
|
+
const apiMap={channel:'/api/channels',preset:'/api/preset',tool:'/api/tools',processor:'/api/processors',trigger:'/api/triggers',toolGroup:'/api/toolGroups'}
|
|
221
|
+
try{
|
|
222
|
+
const id=editing.value?.id
|
|
223
|
+
const url=apiMap[type]+(id?'/'+id:'')
|
|
224
|
+
const method=id?'PUT':'POST'
|
|
225
|
+
const d=await API(url,{method,body:JSON.stringify(form.value)})
|
|
226
|
+
if(d.data!==undefined){toast('Saved');closeModal();refreshAll()}
|
|
227
|
+
else toast(d.message||'Error','err')
|
|
228
|
+
}catch(e){toast(e.message,'err')}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
async function deleteItem(type,id){
|
|
232
|
+
if(!confirm('Delete this item?'))return
|
|
233
|
+
const apiMap={channel:'/api/channels',preset:'/api/preset',tool:'/api/tools',processor:'/api/processors',trigger:'/api/triggers',toolGroup:'/api/toolGroups'}
|
|
234
|
+
try{
|
|
235
|
+
await API(apiMap[type]+'/'+id,{method:'DELETE'})
|
|
236
|
+
toast('Deleted');refreshAll()
|
|
237
|
+
}catch(e){toast(e.message,'err')}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function uptimeStr(s){
|
|
241
|
+
if(!s)return '-'
|
|
242
|
+
const h=Math.floor(s/3600),m=Math.floor(s%3600/60),sec=s%60
|
|
243
|
+
return h>0?`${h}h ${m}m ${sec}s`:`${m}m ${sec}s`
|
|
244
|
+
}
|
|
245
|
+
function fmtNum(n){if(n>=1e6)return(n/1e6).toFixed(1)+'M';if(n>=1e3)return(n/1e3).toFixed(1)+'K';return String(n||0)}
|
|
246
|
+
|
|
247
|
+
onMounted(()=>{
|
|
248
|
+
if(loggedIn.value)refreshAll()
|
|
249
|
+
timer=setInterval(()=>{if(logged.value)refreshAll()},30000)
|
|
250
|
+
})
|
|
251
|
+
onUnmounted(()=>clearInterval(timer))
|
|
252
|
+
|
|
253
|
+
const loggedIn=computed(()=>!!jwt.value)
|
|
254
|
+
|
|
255
|
+
return{
|
|
256
|
+
jwt,loggedIn,loginLoading,loginError,doLogin,logout,
|
|
257
|
+
tab,health,stats,channels,tools,presets,processors,triggers,toolGroups,loading,refreshTime,
|
|
258
|
+
modal,editing,form,openModal,closeModal,saveItem,deleteItem,testChannel,
|
|
259
|
+
toastMsg,toastType,uptimeStr,fmtNum,refreshAll,
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
template:`
|
|
263
|
+
<!-- Toast -->
|
|
264
|
+
<div v-if="toastMsg" :class="['toast',toastType]">{{toastMsg}}</div>
|
|
265
|
+
|
|
266
|
+
<!-- Login -->
|
|
267
|
+
<div v-if="!loggedIn" class="login-wrap">
|
|
268
|
+
<div class="login-box">
|
|
269
|
+
<h1>⚡ <span style="color:var(--accent)">Chaite</span></h1>
|
|
270
|
+
<p>Management Dashboard</p>
|
|
271
|
+
<div v-if="!loginLoading">
|
|
272
|
+
<div style="margin-bottom:16px">
|
|
273
|
+
<input v-model="loginInput" type="password" placeholder="Paste access token here..."
|
|
274
|
+
@keyup.enter="doLogin" autofocus
|
|
275
|
+
style="width:100%;padding:10px 14px;border-radius:8px;border:1px solid var(--border);background:var(--surface2);color:var(--text);font-size:14px;outline:none"/>
|
|
276
|
+
</div>
|
|
277
|
+
<div class="err">{{loginError}}</div>
|
|
278
|
+
<button class="btn primary" @click="doLogin" style="width:100%;padding:10px">Login</button>
|
|
279
|
+
<p style="margin-top:16px;font-size:12px;color:var(--text2)">Or append <code>?token=xxx</code> to URL</p>
|
|
280
|
+
</div>
|
|
281
|
+
<div v-else><div class="spinner"></div></div>
|
|
282
|
+
</div>
|
|
283
|
+
</div>
|
|
284
|
+
|
|
285
|
+
<!-- Dashboard -->
|
|
286
|
+
<div v-else class="app">
|
|
287
|
+
<!-- Header -->
|
|
288
|
+
<div class="header">
|
|
289
|
+
<h1>⚡ <span>Chaite</span> Dashboard</h1>
|
|
290
|
+
<div class="meta">
|
|
291
|
+
<span class="badge" v-if="refreshTime">↻ {{refreshTime}}</span>
|
|
292
|
+
<span class="badge ok" v-if="health?.status==='ok'">Healthy</span>
|
|
293
|
+
<span class="badge err" v-else-if="health">Error</span>
|
|
294
|
+
<button class="btn" @click="refreshAll" :disabled="loading">
|
|
295
|
+
<span v-if="loading" style="display:inline-block;width:14px;height:14px;border:2px solid var(--text2);border-top-color:var(--accent);border-radius:50%;animation:spin .6s linear infinite"></span>
|
|
296
|
+
<span v-else>↻ Refresh</span>
|
|
297
|
+
</button>
|
|
298
|
+
<button class="btn" @click="logout">Logout</button>
|
|
299
|
+
</div>
|
|
300
|
+
</div>
|
|
301
|
+
|
|
302
|
+
<!-- Stats -->
|
|
303
|
+
<div class="stats" v-if="health">
|
|
304
|
+
<div class="stat"><div class="val">{{uptimeStr(health.uptime)}}</div><div class="label">Uptime</div></div>
|
|
305
|
+
<div class="stat"><div class="val">{{health.channels?.total||0}}</div><div class="label">Channels</div></div>
|
|
306
|
+
<div class="stat"><div class="val">{{health.models?.count||0}}</div><div class="label">Models</div></div>
|
|
307
|
+
<div class="stat"><div class="val">{{health.tools?.count||0}}</div><div class="label">Tools</div></div>
|
|
308
|
+
<div class="stat"><div class="val">{{health.system?.processMemory||0}}MB</div><div class="label">Memory</div></div>
|
|
309
|
+
<div class="stat"><div class="val">{{fmtNum(stats?.summary?.totalCalls)}}</div><div class="label">Total Calls</div></div>
|
|
310
|
+
</div>
|
|
311
|
+
|
|
312
|
+
<!-- Tabs -->
|
|
313
|
+
<div class="tabs">
|
|
314
|
+
<div :class="['tab',tab==='overview'&&'active']" @click="tab='overview'">Overview</div>
|
|
315
|
+
<div :class="['tab',tab==='channels'&&'active']" @click="tab='channels'">Channels</div>
|
|
316
|
+
<div :class="['tab',tab==='tools'&&'active']" @click="tab='tools'">Tools</div>
|
|
317
|
+
<div :class="['tab',tab==='presets'&&'active']" @click="tab='presets'">Presets</div>
|
|
318
|
+
<div :class="['tab',tab==='processors'&&'active']" @click="tab='processors'">Processors</div>
|
|
319
|
+
<div :class="['tab',tab==='triggers'&&'active']" @click="tab='triggers'">Triggers</div>
|
|
320
|
+
<div :class="['tab',tab==='groups'&&'active']" @click="tab='groups'">Groups</div>
|
|
321
|
+
</div>
|
|
322
|
+
|
|
323
|
+
<!-- Overview -->
|
|
324
|
+
<div v-if="tab==='overview'">
|
|
325
|
+
<div class="card" v-if="health">
|
|
326
|
+
<h3><span class="dot" style="background:var(--green)"></span> System</h3>
|
|
327
|
+
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;font-size:13px">
|
|
328
|
+
<div><span style="color:var(--text2)">Version:</span> {{health.version}}</div>
|
|
329
|
+
<div><span style="color:var(--text2)">Node:</span> {{health.system?.nodeVersion}}</div>
|
|
330
|
+
<div><span style="color:var(--text2)">Platform:</span> {{health.system?.platform}} {{health.system?.arch}}</div>
|
|
331
|
+
<div><span style="color:var(--text2)">CPUs:</span> {{health.system?.cpus}}</div>
|
|
332
|
+
<div><span style="color:var(--text2)">Heap:</span> {{health.system?.heapUsed}}MB / {{health.system?.processMemory}}MB</div>
|
|
333
|
+
<div><span style="color:var(--text2)">System Mem:</span> {{health.system?.freeMemory}}MB free / {{health.system?.totalMemory}}MB</div>
|
|
334
|
+
</div>
|
|
335
|
+
</div>
|
|
336
|
+
|
|
337
|
+
<div class="card" v-if="health?.models?.list?.length">
|
|
338
|
+
<h3>Available Models</h3>
|
|
339
|
+
<div><span v-for="m in health.models.list" class="pill model">{{m}}</span></div>
|
|
340
|
+
</div>
|
|
341
|
+
|
|
342
|
+
<div class="card" v-if="stats">
|
|
343
|
+
<h3>Usage by Model</h3>
|
|
344
|
+
<table class="tbl">
|
|
345
|
+
<tr><th>Model</th><th>Calls</th><th>Tokens</th></tr>
|
|
346
|
+
<tr v-for="(v,k) in stats.perModel" :key="k">
|
|
347
|
+
<td><span class="pill model">{{k}}</span></td>
|
|
348
|
+
<td>{{fmtNum(v.calls)}}</td>
|
|
349
|
+
<td>{{fmtNum(v.tokens)}}</td>
|
|
350
|
+
</tr>
|
|
351
|
+
<tr v-if="!Object.keys(stats.perModel||{}).length"><td colspan="3" style="color:var(--text2)">No usage data</td></tr>
|
|
352
|
+
</table>
|
|
353
|
+
</div>
|
|
354
|
+
</div>
|
|
355
|
+
|
|
356
|
+
<!-- Channels -->
|
|
357
|
+
<div v-if="tab==='channels'">
|
|
358
|
+
<div class="card">
|
|
359
|
+
<h3 style="justify-content:space-between">Channels <button class="btn primary sm" @click="openModal('channel')">+ New</button></h3>
|
|
360
|
+
<table class="tbl">
|
|
361
|
+
<tr><th>Status</th><th>Name</th><th>Adapter</th><th>Models</th><th>Priority</th><th>Calls</th><th>Actions</th></tr>
|
|
362
|
+
<tr v-for="ch in channels" :key="ch.id">
|
|
363
|
+
<td><span :class="['pill',ch.status==='enabled'?'on':'off']">{{ch.status}}</span></td>
|
|
364
|
+
<td>{{ch.name}}</td>
|
|
365
|
+
<td>{{ch.adapterType}}</td>
|
|
366
|
+
<td><span v-for="m in (ch.models||[])" class="pill model">{{m}}</span></td>
|
|
367
|
+
<td>{{ch.priority}}</td>
|
|
368
|
+
<td>{{fmtNum(ch.statistics?.callTimes)}}</td>
|
|
369
|
+
<td>
|
|
370
|
+
<button class="btn sm" @click="testChannel(ch.id)">Test</button>
|
|
371
|
+
<button class="btn sm" @click="openModal('channel',ch)">Edit</button>
|
|
372
|
+
<button class="btn sm danger" @click="deleteItem('channel',ch.id)">Del</button>
|
|
373
|
+
</td>
|
|
374
|
+
</tr>
|
|
375
|
+
<tr v-if="!channels.length"><td colspan="7" style="color:var(--text2)">No channels</td></tr>
|
|
376
|
+
</table>
|
|
377
|
+
</div>
|
|
378
|
+
</div>
|
|
379
|
+
|
|
380
|
+
<!-- Tools -->
|
|
381
|
+
<div v-if="tab==='tools'">
|
|
382
|
+
<div class="card">
|
|
383
|
+
<h3 style="justify-content:space-between">Tools <button class="btn primary sm" @click="openModal('tool')">+ New</button></h3>
|
|
384
|
+
<table class="tbl">
|
|
385
|
+
<tr><th>Name</th><th>Description</th><th>Actions</th></tr>
|
|
386
|
+
<tr v-for="t in tools" :key="t.id">
|
|
387
|
+
<td>{{t.name||t.id}}</td>
|
|
388
|
+
<td style="max-width:400px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">{{t.description}}</td>
|
|
389
|
+
<td>
|
|
390
|
+
<button class="btn sm" @click="openModal('tool',t)">Edit</button>
|
|
391
|
+
<button class="btn sm danger" @click="deleteItem('tool',t.id)">Del</button>
|
|
392
|
+
</td>
|
|
393
|
+
</tr>
|
|
394
|
+
<tr v-if="!tools.length"><td colspan="3" style="color:var(--text2)">No tools</td></tr>
|
|
395
|
+
</table>
|
|
396
|
+
</div>
|
|
397
|
+
</div>
|
|
398
|
+
|
|
399
|
+
<!-- Presets -->
|
|
400
|
+
<div v-if="tab==='presets'">
|
|
401
|
+
<div class="card">
|
|
402
|
+
<h3 style="justify-content:space-between">Presets <button class="btn primary sm" @click="openModal('preset')">+ New</button></h3>
|
|
403
|
+
<table class="tbl">
|
|
404
|
+
<tr><th>Name</th><th>Prefix</th><th>Model</th><th>Temp</th><th>Actions</th></tr>
|
|
405
|
+
<tr v-for="p in presets" :key="p.id">
|
|
406
|
+
<td>{{p.name}}</td>
|
|
407
|
+
<td><code>{{p.prefix}}</code></td>
|
|
408
|
+
<td><span class="pill model">{{p.sendMessageOption?.model||'-'}}</span></td>
|
|
409
|
+
<td>{{p.sendMessageOption?.temperature}}</td>
|
|
410
|
+
<td>
|
|
411
|
+
<button class="btn sm" @click="openModal('preset',p)">Edit</button>
|
|
412
|
+
<button class="btn sm danger" @click="deleteItem('preset',p.id)">Del</button>
|
|
413
|
+
</td>
|
|
414
|
+
</tr>
|
|
415
|
+
<tr v-if="!presets.length"><td colspan="5" style="color:var(--text2)">No presets</td></tr>
|
|
416
|
+
</table>
|
|
417
|
+
</div>
|
|
418
|
+
</div>
|
|
419
|
+
|
|
420
|
+
<!-- Processors -->
|
|
421
|
+
<div v-if="tab==='processors'">
|
|
422
|
+
<div class="card">
|
|
423
|
+
<h3 style="justify-content:space-between">Processors <button class="btn primary sm" @click="openModal('processor')">+ New</button></h3>
|
|
424
|
+
<table class="tbl">
|
|
425
|
+
<tr><th>Name</th><th>Type</th><th>Description</th><th>Actions</th></tr>
|
|
426
|
+
<tr v-for="p in processors" :key="p.id">
|
|
427
|
+
<td>{{p.name}}</td>
|
|
428
|
+
<td><span class="pill" :style="{background:p.type==='pre'?'rgba(167,139,250,.15)':'rgba(250,204,21,.15)',color:p.type==='pre'?'var(--purple)':'var(--yellow)'}">{{p.type}}</span></td>
|
|
429
|
+
<td>{{p.description}}</td>
|
|
430
|
+
<td>
|
|
431
|
+
<button class="btn sm" @click="openModal('processor',p)">Edit</button>
|
|
432
|
+
<button class="btn sm danger" @click="deleteItem('processor',p.id)">Del</button>
|
|
433
|
+
</td>
|
|
434
|
+
</tr>
|
|
435
|
+
<tr v-if="!processors.length"><td colspan="4" style="color:var(--text2)">No processors</td></tr>
|
|
436
|
+
</table>
|
|
437
|
+
</div>
|
|
438
|
+
</div>
|
|
439
|
+
|
|
440
|
+
<!-- Triggers -->
|
|
441
|
+
<div v-if="tab==='triggers'">
|
|
442
|
+
<div class="card">
|
|
443
|
+
<h3 style="justify-content:space-between">Triggers <button class="btn primary sm" @click="openModal('trigger')">+ New</button></h3>
|
|
444
|
+
<table class="tbl">
|
|
445
|
+
<tr><th>Name</th><th>Description</th><th>Actions</th></tr>
|
|
446
|
+
<tr v-for="t in triggers" :key="t.id">
|
|
447
|
+
<td>{{t.name||t.id}}</td>
|
|
448
|
+
<td>{{t.description}}</td>
|
|
449
|
+
<td>
|
|
450
|
+
<button class="btn sm" @click="openModal('trigger',t)">Edit</button>
|
|
451
|
+
<button class="btn sm danger" @click="deleteItem('trigger',t.id)">Del</button>
|
|
452
|
+
</td>
|
|
453
|
+
</tr>
|
|
454
|
+
<tr v-if="!triggers.length"><td colspan="3" style="color:var(--text2)">No triggers</td></tr>
|
|
455
|
+
</table>
|
|
456
|
+
</div>
|
|
457
|
+
</div>
|
|
458
|
+
|
|
459
|
+
<!-- Tool Groups -->
|
|
460
|
+
<div v-if="tab==='groups'">
|
|
461
|
+
<div class="card">
|
|
462
|
+
<h3 style="justify-content:space-between">Tool Groups <button class="btn primary sm" @click="openModal('toolGroup')">+ New</button></h3>
|
|
463
|
+
<table class="tbl">
|
|
464
|
+
<tr><th>Name</th><th>Description</th><th>Default</th><th>Actions</th></tr>
|
|
465
|
+
<tr v-for="g in toolGroups" :key="g.id">
|
|
466
|
+
<td>{{g.name}}</td>
|
|
467
|
+
<td>{{g.description}}</td>
|
|
468
|
+
<td><span v-if="g.isDefault" class="pill on">Default</span></td>
|
|
469
|
+
<td>
|
|
470
|
+
<button class="btn sm" @click="openModal('toolGroup',g)">Edit</button>
|
|
471
|
+
<button class="btn sm danger" @click="deleteItem('toolGroup',g.id)">Del</button>
|
|
472
|
+
</td>
|
|
473
|
+
</tr>
|
|
474
|
+
<tr v-if="!toolGroups.length"><td colspan="4" style="color:var(--text2)">No groups</td></tr>
|
|
475
|
+
</table>
|
|
476
|
+
</div>
|
|
477
|
+
</div>
|
|
478
|
+
|
|
479
|
+
<!-- Modal -->
|
|
480
|
+
<div v-if="modal" class="modal-mask" @click.self="closeModal">
|
|
481
|
+
<div class="modal">
|
|
482
|
+
<h3>{{editing?'Edit':'New'}} {{modal}}</h3>
|
|
483
|
+
|
|
484
|
+
<!-- Channel form -->
|
|
485
|
+
<template v-if="modal==='channel'">
|
|
486
|
+
<div class="form-row"><label>Name</label><input v-model="form.name"/></div>
|
|
487
|
+
<div class="form-row"><label>Adapter Type</label><select v-model="form.adapterType"><option>openai</option><option>gemini</option><option>claude</option></select></div>
|
|
488
|
+
<div class="form-row"><label>Models (comma separated)</label><input v-model="form._models" :placeholder="(form.models||[]).join(', ')"/></div>
|
|
489
|
+
<div class="form-row"><label>Base URL</label><input v-model="form.options.baseUrl"/></div>
|
|
490
|
+
<div class="form-row"><label>API Key</label><input v-model="form.options.apiKey" type="password"/></div>
|
|
491
|
+
<div class="form-row"><label>Priority</label><input v-model.number="form.priority" type="number"/></div>
|
|
492
|
+
<div class="form-row"><label>Weight</label><input v-model.number="form.weight" type="number"/></div>
|
|
493
|
+
<div class="form-row"><label>Status</label><select v-model="form.status"><option>enabled</option><option>disabled</option></select></div>
|
|
494
|
+
</template>
|
|
495
|
+
|
|
496
|
+
<!-- Preset form -->
|
|
497
|
+
<template v-if="modal==='preset'">
|
|
498
|
+
<div class="form-row"><label>Name</label><input v-model="form.name"/></div>
|
|
499
|
+
<div class="form-row"><label>Prefix</label><input v-model="form.prefix"/></div>
|
|
500
|
+
<div class="form-row"><label>Model</label><input v-model="form.sendMessageOption.model"/></div>
|
|
501
|
+
<div class="form-row"><label>Temperature</label><input v-model.number="form.sendMessageOption.temperature" type="number" step="0.1"/></div>
|
|
502
|
+
<div class="form-row"><label>Max Token</label><input v-model.number="form.sendMessageOption.maxToken" type="number"/></div>
|
|
503
|
+
<div class="form-row"><label>System Prompt</label><textarea v-model="form.sendMessageOption.systemOverride"></textarea></div>
|
|
504
|
+
</template>
|
|
505
|
+
|
|
506
|
+
<!-- Tool / Processor / Trigger form -->
|
|
507
|
+
<template v-if="modal==='tool'||modal==='processor'||modal==='trigger'">
|
|
508
|
+
<div class="form-row"><label>Name</label><input v-model="form.name"/></div>
|
|
509
|
+
<div class="form-row" v-if="modal==='processor'"><label>Type</label><select v-model="form.type"><option>pre</option><option>post</option></select></div>
|
|
510
|
+
<div class="form-row"><label>Description</label><input v-model="form.description"/></div>
|
|
511
|
+
<div class="form-row"><label>Code</label><textarea v-model="form.code" style="min-height:200px;font-family:monospace;font-size:12px"></textarea></div>
|
|
512
|
+
</template>
|
|
513
|
+
|
|
514
|
+
<!-- Tool Group form -->
|
|
515
|
+
<template v-if="modal==='toolGroup'">
|
|
516
|
+
<div class="form-row"><label>Name</label><input v-model="form.name"/></div>
|
|
517
|
+
<div class="form-row"><label>Description</label><input v-model="form.description"/></div>
|
|
518
|
+
<div class="form-row"><label>Tool IDs (comma separated)</label><input v-model="form._toolIds" :placeholder="(form.toolIds||[]).join(', ')"/></div>
|
|
519
|
+
<div class="form-row"><label>Status</label><select v-model="form.status"><option>enabled</option><option>disabled</option></select></div>
|
|
520
|
+
</template>
|
|
521
|
+
|
|
522
|
+
<div class="modal-btns">
|
|
523
|
+
<button class="btn" @click="closeModal">Cancel</button>
|
|
524
|
+
<button class="btn primary" @click="saveItem">Save</button>
|
|
525
|
+
</div>
|
|
526
|
+
</div>
|
|
527
|
+
</div>
|
|
528
|
+
</div>
|
|
529
|
+
`
|
|
530
|
+
}).mount('#app')
|
|
531
|
+
</script>
|
|
532
|
+
</body>
|
|
533
|
+
</html>
|