neoagent 2.4.1-beta.45 → 2.4.1-beta.47
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/.env.example +12 -0
- package/package.json +1 -1
- package/server/admin/access.js +198 -0
- package/server/admin/admin.js +2 -2
- package/server/admin/analytics.js +128 -0
- package/server/admin/index.html +484 -1
- package/server/admin/login.html +171 -45
- package/server/admin/sql.js +134 -0
- package/server/admin/users.js +147 -0
- package/server/db/database.js +19 -0
- package/server/http/static.js +20 -6
- package/server/middleware/adminAuth.js +37 -0
- package/server/public/.last_build_id +1 -1
- package/server/public/flutter_bootstrap.js +1 -1
- package/server/public/main.dart.js +4 -4
- package/server/routes/admin.js +316 -5
- package/server/services/account/admin_two_factor.js +132 -0
package/server/admin/index.html
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>NeoAgent Admin</title>
|
|
7
|
+
<link rel="icon" href="/admin/logo.svg" type="image/svg+xml">
|
|
7
8
|
<link rel="stylesheet" href="/admin/admin.css">
|
|
8
9
|
<style>
|
|
9
10
|
/* ── Layout ────────────────────────────────────────────────────── */
|
|
@@ -82,6 +83,22 @@
|
|
|
82
83
|
border-top: 1px solid var(--border);
|
|
83
84
|
}
|
|
84
85
|
|
|
86
|
+
.sidebar-legal {
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
gap: 6px;
|
|
90
|
+
padding: 4px 8px 8px;
|
|
91
|
+
font-size: 11px;
|
|
92
|
+
color: var(--text-muted, #666);
|
|
93
|
+
}
|
|
94
|
+
.sidebar-legal a {
|
|
95
|
+
color: var(--text-muted, #666);
|
|
96
|
+
text-decoration: none;
|
|
97
|
+
transition: color 0.15s;
|
|
98
|
+
}
|
|
99
|
+
.sidebar-legal a:hover { color: var(--text, #ccc); }
|
|
100
|
+
.sidebar-legal span { opacity: 0.4; }
|
|
101
|
+
|
|
85
102
|
.main {
|
|
86
103
|
margin-left: var(--sidebar-w);
|
|
87
104
|
flex: 1;
|
|
@@ -309,6 +326,367 @@
|
|
|
309
326
|
color: var(--text-muted) !important;
|
|
310
327
|
}
|
|
311
328
|
|
|
329
|
+
/* ── Stats grid ────────────────────────────────────────────── */
|
|
330
|
+
.stat-grid {
|
|
331
|
+
display: grid;
|
|
332
|
+
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
|
|
333
|
+
gap: 10px;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.stat-card {
|
|
337
|
+
background: var(--bg-secondary);
|
|
338
|
+
border: 1px solid var(--border);
|
|
339
|
+
border-radius: 8px;
|
|
340
|
+
padding: 18px 16px 14px;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.stat-value {
|
|
344
|
+
font-size: 28px;
|
|
345
|
+
font-weight: 700;
|
|
346
|
+
letter-spacing: -0.5px;
|
|
347
|
+
color: var(--text);
|
|
348
|
+
line-height: 1;
|
|
349
|
+
font-variant-numeric: tabular-nums;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.stat-label {
|
|
353
|
+
font-size: 11px;
|
|
354
|
+
font-weight: 600;
|
|
355
|
+
text-transform: uppercase;
|
|
356
|
+
letter-spacing: 0.06em;
|
|
357
|
+
color: var(--text-muted);
|
|
358
|
+
margin-top: 8px;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/* ── Analytics tables ──────────────────────────────────────── */
|
|
362
|
+
.analytics-table {
|
|
363
|
+
width: 100%;
|
|
364
|
+
border-collapse: collapse;
|
|
365
|
+
font-size: 13px;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.analytics-table th {
|
|
369
|
+
text-align: left;
|
|
370
|
+
font-size: 10px;
|
|
371
|
+
font-weight: 600;
|
|
372
|
+
text-transform: uppercase;
|
|
373
|
+
letter-spacing: 0.07em;
|
|
374
|
+
color: var(--text-muted);
|
|
375
|
+
padding: 6px 8px;
|
|
376
|
+
border-bottom: 1px solid var(--border);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.analytics-table td {
|
|
380
|
+
padding: 9px 8px;
|
|
381
|
+
border-bottom: 1px solid rgba(224,240,224,0.04);
|
|
382
|
+
color: var(--text-secondary);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.analytics-table tr:last-child td { border-bottom: none; }
|
|
386
|
+
.analytics-table tr:hover td { background: rgba(224,240,224,0.025); }
|
|
387
|
+
|
|
388
|
+
.cell-truncate {
|
|
389
|
+
max-width: 280px;
|
|
390
|
+
overflow: hidden;
|
|
391
|
+
text-overflow: ellipsis;
|
|
392
|
+
white-space: nowrap;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.run-badge {
|
|
396
|
+
display: inline-block;
|
|
397
|
+
padding: 2px 8px;
|
|
398
|
+
border-radius: 999px;
|
|
399
|
+
font-size: 10px;
|
|
400
|
+
font-weight: 600;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.run-completed { background: rgba(116,192,124,0.15); color: var(--success); }
|
|
404
|
+
.run-failed { background: rgba(222,138,120,0.15); color: var(--danger); }
|
|
405
|
+
.run-running { background: var(--accent-muted); color: var(--accent); }
|
|
406
|
+
.run-pending { background: rgba(126,136,119,0.15); color: var(--text-muted); }
|
|
407
|
+
|
|
408
|
+
/* ── User avatar ────────────────────────────────────────────── */
|
|
409
|
+
.user-avatar {
|
|
410
|
+
display: inline-flex;
|
|
411
|
+
align-items: center;
|
|
412
|
+
justify-content: center;
|
|
413
|
+
width: 28px;
|
|
414
|
+
height: 28px;
|
|
415
|
+
min-width: 28px;
|
|
416
|
+
border-radius: 50%;
|
|
417
|
+
background: var(--accent-muted);
|
|
418
|
+
color: var(--accent);
|
|
419
|
+
font-size: 12px;
|
|
420
|
+
font-weight: 700;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/* ── Mini bar ───────────────────────────────────────────────── */
|
|
424
|
+
.mini-bar {
|
|
425
|
+
height: 4px;
|
|
426
|
+
background: var(--bg-secondary);
|
|
427
|
+
border-radius: 999px;
|
|
428
|
+
width: 80px;
|
|
429
|
+
overflow: hidden;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
.mini-bar-fill {
|
|
433
|
+
height: 100%;
|
|
434
|
+
background: var(--accent);
|
|
435
|
+
border-radius: 999px;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/* ── Users table ────────────────────────────────────────────── */
|
|
439
|
+
.users-table {
|
|
440
|
+
width: 100%;
|
|
441
|
+
border-collapse: collapse;
|
|
442
|
+
font-size: 13px;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
.users-table th {
|
|
446
|
+
text-align: left;
|
|
447
|
+
font-size: 10px;
|
|
448
|
+
font-weight: 600;
|
|
449
|
+
text-transform: uppercase;
|
|
450
|
+
letter-spacing: 0.07em;
|
|
451
|
+
color: var(--text-muted);
|
|
452
|
+
padding: 6px 8px;
|
|
453
|
+
border-bottom: 1px solid var(--border);
|
|
454
|
+
white-space: nowrap;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
.users-table td {
|
|
458
|
+
padding: 10px 8px;
|
|
459
|
+
border-bottom: 1px solid rgba(224,240,224,0.04);
|
|
460
|
+
vertical-align: middle;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
.users-table tr:last-child td { border-bottom: none; }
|
|
464
|
+
.users-table tr:hover td { background: rgba(224,240,224,0.025); }
|
|
465
|
+
|
|
466
|
+
.gdpr-note {
|
|
467
|
+
font-size: 11px;
|
|
468
|
+
color: var(--text-muted);
|
|
469
|
+
margin-top: 14px;
|
|
470
|
+
padding: 10px 14px;
|
|
471
|
+
background: rgba(222, 138, 120, 0.05);
|
|
472
|
+
border: 1px solid rgba(222, 138, 120, 0.15);
|
|
473
|
+
border-radius: var(--radius-sm);
|
|
474
|
+
line-height: 1.5;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/* ── SQL editor ─────────────────────────────────────────────── */
|
|
478
|
+
.sql-toolbar {
|
|
479
|
+
display: flex;
|
|
480
|
+
align-items: center;
|
|
481
|
+
gap: 8px;
|
|
482
|
+
margin-bottom: 10px;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
.sql-textarea {
|
|
486
|
+
width: 100%;
|
|
487
|
+
min-height: 140px;
|
|
488
|
+
background: var(--bg-input);
|
|
489
|
+
border: 1px solid var(--border-light);
|
|
490
|
+
border-radius: var(--radius-sm);
|
|
491
|
+
padding: 12px 14px;
|
|
492
|
+
color: var(--text);
|
|
493
|
+
font-family: var(--font-mono);
|
|
494
|
+
font-size: 13px;
|
|
495
|
+
line-height: 1.6;
|
|
496
|
+
resize: vertical;
|
|
497
|
+
outline: none;
|
|
498
|
+
tab-size: 2;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
.sql-textarea:focus {
|
|
502
|
+
border-color: var(--accent);
|
|
503
|
+
box-shadow: 0 0 0 3px var(--accent-muted);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.sql-meta {
|
|
507
|
+
display: flex;
|
|
508
|
+
align-items: center;
|
|
509
|
+
gap: 8px;
|
|
510
|
+
font-size: 12px;
|
|
511
|
+
color: var(--text-muted);
|
|
512
|
+
margin: 12px 0 8px;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
.sql-result-wrap {
|
|
516
|
+
overflow-x: auto;
|
|
517
|
+
border: 1px solid var(--border);
|
|
518
|
+
border-radius: var(--radius-sm);
|
|
519
|
+
max-height: 420px;
|
|
520
|
+
overflow-y: auto;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
.sql-result-table {
|
|
524
|
+
width: 100%;
|
|
525
|
+
border-collapse: collapse;
|
|
526
|
+
font-size: 12px;
|
|
527
|
+
font-family: var(--font-mono);
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
.sql-result-table th {
|
|
531
|
+
background: var(--bg-secondary);
|
|
532
|
+
padding: 7px 12px;
|
|
533
|
+
text-align: left;
|
|
534
|
+
font-size: 10px;
|
|
535
|
+
font-weight: 700;
|
|
536
|
+
text-transform: uppercase;
|
|
537
|
+
letter-spacing: 0.05em;
|
|
538
|
+
color: var(--text-muted);
|
|
539
|
+
white-space: nowrap;
|
|
540
|
+
position: sticky;
|
|
541
|
+
top: 0;
|
|
542
|
+
z-index: 1;
|
|
543
|
+
border-bottom: 1px solid var(--border-light);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
.sql-result-table td {
|
|
547
|
+
padding: 6px 12px;
|
|
548
|
+
border-bottom: 1px solid rgba(224,240,224,0.04);
|
|
549
|
+
color: var(--text-secondary);
|
|
550
|
+
white-space: nowrap;
|
|
551
|
+
max-width: 320px;
|
|
552
|
+
overflow: hidden;
|
|
553
|
+
text-overflow: ellipsis;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
.sql-result-table tr:last-child td { border-bottom: none; }
|
|
557
|
+
.sql-result-table tr:hover td { background: rgba(224,240,224,0.03); }
|
|
558
|
+
|
|
559
|
+
.sql-error {
|
|
560
|
+
padding: 12px 14px;
|
|
561
|
+
margin-top: 10px;
|
|
562
|
+
background: rgba(222,138,120,0.08);
|
|
563
|
+
border: 1px solid rgba(222,138,120,0.2);
|
|
564
|
+
border-radius: var(--radius-sm);
|
|
565
|
+
color: var(--danger);
|
|
566
|
+
font-family: var(--font-mono);
|
|
567
|
+
font-size: 12px;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/* ── Access / toggle ───────────────────────────────────────── */
|
|
571
|
+
.access-row {
|
|
572
|
+
display: flex;
|
|
573
|
+
align-items: flex-start;
|
|
574
|
+
justify-content: space-between;
|
|
575
|
+
gap: 20px;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
.access-label {
|
|
579
|
+
font-size: 14px;
|
|
580
|
+
font-weight: 600;
|
|
581
|
+
color: var(--text);
|
|
582
|
+
margin-bottom: 4px;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
.access-desc {
|
|
586
|
+
font-size: 12px;
|
|
587
|
+
color: var(--text-muted);
|
|
588
|
+
line-height: 1.5;
|
|
589
|
+
max-width: 480px;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
.access-desc code {
|
|
593
|
+
font-family: var(--font-mono);
|
|
594
|
+
font-size: 11px;
|
|
595
|
+
background: var(--bg-secondary);
|
|
596
|
+
padding: 1px 5px;
|
|
597
|
+
border-radius: 4px;
|
|
598
|
+
color: var(--accent);
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
.access-hint-row {
|
|
602
|
+
display: flex;
|
|
603
|
+
align-items: center;
|
|
604
|
+
gap: 12px;
|
|
605
|
+
margin-top: 12px;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
.access-actions {
|
|
609
|
+
display: flex;
|
|
610
|
+
gap: 8px;
|
|
611
|
+
margin-top: 16px;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
.access-status {
|
|
615
|
+
font-size: 12px;
|
|
616
|
+
margin-top: 8px;
|
|
617
|
+
min-height: 16px;
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/* Toggle switch */
|
|
621
|
+
.toggle {
|
|
622
|
+
position: relative;
|
|
623
|
+
width: 40px;
|
|
624
|
+
height: 22px;
|
|
625
|
+
flex-shrink: 0;
|
|
626
|
+
cursor: pointer;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
.toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
|
|
630
|
+
|
|
631
|
+
.toggle-track {
|
|
632
|
+
position: absolute;
|
|
633
|
+
inset: 0;
|
|
634
|
+
background: var(--bg-secondary);
|
|
635
|
+
border: 1px solid var(--border-light);
|
|
636
|
+
border-radius: 999px;
|
|
637
|
+
transition: background 0.18s, border-color 0.18s;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
.toggle input:checked ~ .toggle-track {
|
|
641
|
+
background: var(--accent);
|
|
642
|
+
border-color: var(--accent);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
.toggle-thumb {
|
|
646
|
+
position: absolute;
|
|
647
|
+
top: 3px;
|
|
648
|
+
left: 3px;
|
|
649
|
+
width: 16px;
|
|
650
|
+
height: 16px;
|
|
651
|
+
background: #fff;
|
|
652
|
+
border-radius: 50%;
|
|
653
|
+
transition: transform 0.18s;
|
|
654
|
+
pointer-events: none;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
.toggle input:checked ~ .toggle-thumb { transform: translateX(18px); }
|
|
658
|
+
|
|
659
|
+
/* API key display */
|
|
660
|
+
.api-key-hint {
|
|
661
|
+
font-family: var(--font-mono);
|
|
662
|
+
font-size: 13px;
|
|
663
|
+
color: var(--text-secondary);
|
|
664
|
+
background: var(--bg-secondary);
|
|
665
|
+
padding: 4px 10px;
|
|
666
|
+
border-radius: 6px;
|
|
667
|
+
letter-spacing: 0.04em;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
.api-key-full {
|
|
671
|
+
font-family: var(--font-mono);
|
|
672
|
+
font-size: 12px;
|
|
673
|
+
color: var(--text);
|
|
674
|
+
background: var(--bg-secondary);
|
|
675
|
+
padding: 6px 10px;
|
|
676
|
+
border-radius: 6px;
|
|
677
|
+
word-break: break-all;
|
|
678
|
+
flex: 1;
|
|
679
|
+
user-select: all;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
.key-reveal-box {
|
|
683
|
+
background: rgba(225, 176, 82, 0.07);
|
|
684
|
+
border: 1px solid rgba(225, 176, 82, 0.25);
|
|
685
|
+
border-radius: var(--radius-sm);
|
|
686
|
+
padding: 12px 14px;
|
|
687
|
+
margin-top: 14px;
|
|
688
|
+
}
|
|
689
|
+
|
|
312
690
|
/* ── Provider rows ─────────────────────────────────────────── */
|
|
313
691
|
.provider-row {
|
|
314
692
|
display: grid;
|
|
@@ -379,7 +757,7 @@
|
|
|
379
757
|
</div>
|
|
380
758
|
|
|
381
759
|
<nav aria-label="Admin navigation">
|
|
382
|
-
<div class="nav-section-label">
|
|
760
|
+
<div class="nav-section-label">Monitor</div>
|
|
383
761
|
|
|
384
762
|
<button class="nav-item active" data-page="overview" onclick="showPage('overview',this)">
|
|
385
763
|
<svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
@@ -402,6 +780,38 @@
|
|
|
402
780
|
Updates
|
|
403
781
|
</button>
|
|
404
782
|
|
|
783
|
+
<div class="nav-section-label" style="margin-top:8px;">Manage</div>
|
|
784
|
+
|
|
785
|
+
<button class="nav-item" data-page="analytics" onclick="showPage('analytics',this)">
|
|
786
|
+
<svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
787
|
+
<path d="M2 11a1 1 0 011-1h2a1 1 0 011 1v5a1 1 0 01-1 1H3a1 1 0 01-1-1v-5zM8 7a1 1 0 011-1h2a1 1 0 011 1v9a1 1 0 01-1 1H9a1 1 0 01-1-1V7zM14 4a1 1 0 011-1h2a1 1 0 011 1v12a1 1 0 01-1 1h-2a1 1 0 01-1-1V4z"/>
|
|
788
|
+
</svg>
|
|
789
|
+
Analytics
|
|
790
|
+
</button>
|
|
791
|
+
|
|
792
|
+
<button class="nav-item" data-page="users" onclick="showPage('users',this)">
|
|
793
|
+
<svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
794
|
+
<path d="M9 6a3 3 0 11-6 0 3 3 0 016 0zM17 6a3 3 0 11-6 0 3 3 0 016 0zM12.93 17c.046-.327.07-.66.07-1a6.97 6.97 0 00-1.5-4.33A5 5 0 0119 16v1h-6.07zM6 11a5 5 0 015 5v1H1v-1a5 5 0 015-5z"/>
|
|
795
|
+
</svg>
|
|
796
|
+
Users
|
|
797
|
+
</button>
|
|
798
|
+
|
|
799
|
+
<button class="nav-item" data-page="sql" onclick="showPage('sql',this)">
|
|
800
|
+
<svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
801
|
+
<path fill-rule="evenodd" d="M3 5a2 2 0 012-2h10a2 2 0 012 2v10a2 2 0 01-2 2H5a2 2 0 01-2-2V5zm11 1H6v8l4-2 4 2V6z" clip-rule="evenodd"/>
|
|
802
|
+
</svg>
|
|
803
|
+
SQL Editor
|
|
804
|
+
</button>
|
|
805
|
+
|
|
806
|
+
<div class="nav-section-label" style="margin-top:8px;">Settings</div>
|
|
807
|
+
|
|
808
|
+
<button class="nav-item" data-page="access" onclick="showPage('access',this)">
|
|
809
|
+
<svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
810
|
+
<path fill-rule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clip-rule="evenodd"/>
|
|
811
|
+
</svg>
|
|
812
|
+
Access
|
|
813
|
+
</button>
|
|
814
|
+
|
|
405
815
|
<button class="nav-item" data-page="providers" onclick="showPage('providers',this)">
|
|
406
816
|
<svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
407
817
|
<path fill-rule="evenodd" d="M18 8a6 6 0 01-7.743 5.743L10 14l-1 1-1 1H6v2H2v-4l4.257-4.257A6 6 0 1118 8zm-6-4a1 1 0 100 2 2 2 0 012 2 1 1 0 102 0 4 4 0 00-4-4z" clip-rule="evenodd"/>
|
|
@@ -418,6 +828,11 @@
|
|
|
418
828
|
</nav>
|
|
419
829
|
|
|
420
830
|
<div class="sidebar-footer">
|
|
831
|
+
<div class="sidebar-legal">
|
|
832
|
+
<a href="/legal.html#overview" target="_blank" rel="noopener">Privacy Policy</a>
|
|
833
|
+
<span>·</span>
|
|
834
|
+
<a href="/legal.html#legal-notice" target="_blank" rel="noopener">Legal Notice</a>
|
|
835
|
+
</div>
|
|
421
836
|
<button class="nav-item btn-danger" onclick="signOut()">
|
|
422
837
|
<svg viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
|
423
838
|
<path fill-rule="evenodd" d="M3 3a1 1 0 00-1 1v12a1 1 0 102 0V4a1 1 0 00-1-1zm10.293 9.293a1 1 0 001.414 1.414l3-3a1 1 0 000-1.414l-3-3a1 1 0 10-1.414 1.414L14.586 9H7a1 1 0 100 2h7.586l-1.293 1.293z" clip-rule="evenodd"/>
|
|
@@ -493,6 +908,70 @@
|
|
|
493
908
|
</div>
|
|
494
909
|
</section>
|
|
495
910
|
|
|
911
|
+
<!-- Analytics -->
|
|
912
|
+
<section id="page-analytics" class="page" aria-label="Analytics">
|
|
913
|
+
<div class="page-header">
|
|
914
|
+
<div>
|
|
915
|
+
<h1 class="page-title">Analytics</h1>
|
|
916
|
+
<p class="page-subtitle">Usage statistics, top users, and recent activity</p>
|
|
917
|
+
</div>
|
|
918
|
+
<span class="refresh-hint" id="analytics-ts" aria-live="polite"></span>
|
|
919
|
+
</div>
|
|
920
|
+
<div class="content">
|
|
921
|
+
<div id="analytics-content"><div class="empty"><span class="spinner"></span></div></div>
|
|
922
|
+
</div>
|
|
923
|
+
</section>
|
|
924
|
+
|
|
925
|
+
<!-- Users -->
|
|
926
|
+
<section id="page-users" class="page" aria-label="User Management">
|
|
927
|
+
<div class="page-header">
|
|
928
|
+
<div>
|
|
929
|
+
<h1 class="page-title">Users</h1>
|
|
930
|
+
<p class="page-subtitle">Account management — force logout, GDPR data erasure</p>
|
|
931
|
+
</div>
|
|
932
|
+
<span class="toolbar-count" id="users-count" aria-live="polite" style="padding-top:6px;"></span>
|
|
933
|
+
</div>
|
|
934
|
+
<div class="content">
|
|
935
|
+
<div class="card">
|
|
936
|
+
<div class="toolbar" style="margin-bottom:14px;">
|
|
937
|
+
<input type="search" id="user-search" placeholder="Search by username or email…"
|
|
938
|
+
oninput="onUserSearch()" style="width:280px;padding:7px 12px;font-size:13px;" aria-label="Search users">
|
|
939
|
+
<span class="spacer"></span>
|
|
940
|
+
<button class="btn btn-ghost" onclick="loadUsers()">Refresh</button>
|
|
941
|
+
</div>
|
|
942
|
+
<div id="users-table-wrap"><div class="empty">Loading…</div></div>
|
|
943
|
+
</div>
|
|
944
|
+
</div>
|
|
945
|
+
</section>
|
|
946
|
+
|
|
947
|
+
<!-- SQL Editor -->
|
|
948
|
+
<section id="page-sql" class="page" aria-label="SQL Editor">
|
|
949
|
+
<div class="page-header">
|
|
950
|
+
<div>
|
|
951
|
+
<h1 class="page-title">SQL Editor</h1>
|
|
952
|
+
<p class="page-subtitle">Read-only SELECT queries against the live database — results capped at 500 rows</p>
|
|
953
|
+
</div>
|
|
954
|
+
</div>
|
|
955
|
+
<div class="content">
|
|
956
|
+
<div class="card">
|
|
957
|
+
<div id="sql-content"><div class="empty"><span class="spinner"></span></div></div>
|
|
958
|
+
</div>
|
|
959
|
+
</div>
|
|
960
|
+
</section>
|
|
961
|
+
|
|
962
|
+
<!-- Access -->
|
|
963
|
+
<section id="page-access" class="page" aria-label="Access Settings">
|
|
964
|
+
<div class="page-header">
|
|
965
|
+
<div>
|
|
966
|
+
<h1 class="page-title">Access</h1>
|
|
967
|
+
<p class="page-subtitle">Signup policy and programmatic API key management</p>
|
|
968
|
+
</div>
|
|
969
|
+
</div>
|
|
970
|
+
<div class="content">
|
|
971
|
+
<div id="access-content"><div class="empty"><span class="spinner"></span></div></div>
|
|
972
|
+
</div>
|
|
973
|
+
</section>
|
|
974
|
+
|
|
496
975
|
<!-- Providers -->
|
|
497
976
|
<section id="page-providers" class="page" aria-label="Providers">
|
|
498
977
|
<div class="page-header">
|
|
@@ -528,5 +1007,9 @@
|
|
|
528
1007
|
</main>
|
|
529
1008
|
|
|
530
1009
|
<script src="/admin/admin.js"></script>
|
|
1010
|
+
<script src="/admin/analytics.js"></script>
|
|
1011
|
+
<script src="/admin/users.js"></script>
|
|
1012
|
+
<script src="/admin/sql.js"></script>
|
|
1013
|
+
<script src="/admin/access.js"></script>
|
|
531
1014
|
</body>
|
|
532
1015
|
</html>
|