@linxiraos/pi-stats 1.1.6 → 1.1.8
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 +2 -2
- package/dist/client/index.css +1 -1
- package/dist/client/index.js +101 -101
- package/dist/client/styles.css +362 -98
- package/dist/types/client/api.d.ts +7 -1
- package/dist/types/client/app/routes.d.ts +1 -1
- package/dist/types/client/data/useHashRoute.d.ts +2 -0
- package/dist/types/client/routes/TracesRoute.d.ts +11 -0
- package/dist/types/client/routes/index.d.ts +1 -0
- package/dist/types/client/traces/AggregatesPanel.d.ts +9 -0
- package/dist/types/client/traces/Minimap.d.ts +14 -0
- package/dist/types/client/traces/SpanDrawer.d.ts +14 -0
- package/dist/types/client/traces/SummaryStrip.d.ts +9 -0
- package/dist/types/client/traces/TimelineCanvas.d.ts +25 -0
- package/dist/types/client/traces/TraceView.d.ts +11 -0
- package/dist/types/client/traces/TranscriptList.d.ts +24 -0
- package/dist/types/client/traces/time-scale.d.ts +40 -0
- package/dist/types/client/traces/trace-colors.d.ts +31 -0
- package/dist/types/db.d.ts +24 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/parser.d.ts +8 -0
- package/dist/types/server.d.ts +3 -2
- package/dist/types/shared-types.d.ts +130 -0
- package/dist/types/trace.d.ts +33 -0
- package/dist/types/types.d.ts +35 -1
- package/package.json +4 -4
- package/src/client/App.tsx +11 -1
- package/src/client/api.ts +23 -0
- package/src/client/app/routes.ts +7 -0
- package/src/client/data/useHashRoute.ts +28 -10
- package/src/client/routes/ProvidersRoute.tsx +1 -0
- package/src/client/routes/TracesRoute.tsx +182 -0
- package/src/client/routes/index.ts +1 -0
- package/src/client/styles.css +433 -111
- package/src/client/traces/AggregatesPanel.tsx +88 -0
- package/src/client/traces/Minimap.tsx +177 -0
- package/src/client/traces/SpanDrawer.tsx +309 -0
- package/src/client/traces/SummaryStrip.tsx +37 -0
- package/src/client/traces/TimelineCanvas.tsx +768 -0
- package/src/client/traces/TraceView.tsx +344 -0
- package/src/client/traces/TranscriptList.tsx +166 -0
- package/src/client/traces/time-scale.ts +250 -0
- package/src/client/traces/trace-colors.ts +77 -0
- package/src/db.ts +77 -0
- package/src/index.ts +1 -6
- package/src/parser.ts +55 -2
- package/src/server.ts +69 -17
- package/src/shared-types.ts +138 -0
- package/src/trace.ts +1002 -0
- package/src/types.ts +45 -1
package/src/client/styles.css
CHANGED
|
@@ -1,46 +1,41 @@
|
|
|
1
1
|
@import "tailwindcss/index.css";
|
|
2
2
|
|
|
3
3
|
/* ==========================================================================
|
|
4
|
-
|
|
4
|
+
OMP Theme Variables & Color Scheme
|
|
5
5
|
========================================================================== */
|
|
6
6
|
:root {
|
|
7
7
|
color-scheme: dark;
|
|
8
|
-
/*
|
|
9
|
-
|
|
10
|
-
--
|
|
11
|
-
--
|
|
12
|
-
--
|
|
13
|
-
--
|
|
14
|
-
--
|
|
15
|
-
--
|
|
16
|
-
--
|
|
17
|
-
--
|
|
18
|
-
--
|
|
19
|
-
--
|
|
20
|
-
--accent:
|
|
21
|
-
--
|
|
22
|
-
--
|
|
23
|
-
--
|
|
24
|
-
--
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
/* Backward-compat aliases for existing class references */
|
|
30
|
-
--page: var(--bg);
|
|
31
|
-
--surface: var(--bg-panel);
|
|
32
|
-
--surface-2: var(--bg-hover);
|
|
33
|
-
--muted: var(--text-muted);
|
|
34
|
-
--dim: var(--text-dim);
|
|
35
|
-
|
|
36
|
-
/* Bridge view-component token vocabulary */
|
|
8
|
+
/* OMP brand palette — packages/collab-web/src/styles/tokens.css:
|
|
9
|
+
deep-purple surfaces (hue 307), pink accent #ed4abf, cyan focus ring #5ad8e6. */
|
|
10
|
+
--page: oklch(0.16 0.02 307);
|
|
11
|
+
--surface: oklch(0.19 0.022 307);
|
|
12
|
+
--surface-2: oklch(0.235 0.026 307);
|
|
13
|
+
--border: oklch(1 0 0 / 9%);
|
|
14
|
+
--border-strong: oklch(1 0 0 / 13%);
|
|
15
|
+
--text: oklch(0.92 0.01 307);
|
|
16
|
+
--muted: oklch(0.71 0.016 307);
|
|
17
|
+
--dim: oklch(0.53 0.018 307);
|
|
18
|
+
--accent: oklch(0.674 0.23 341); /* brand pink #ed4abf */
|
|
19
|
+
--accent-fg: oklch(0.2 0.07 341); /* ink on accent fills */
|
|
20
|
+
--accent-muted: oklch(0.674 0.23 341 / 18%);
|
|
21
|
+
--link: oklch(0.817 0.112 205); /* brand cyan #5ad8e6 */
|
|
22
|
+
--success: oklch(0.76 0.14 150);
|
|
23
|
+
--danger: oklch(0.66 0.19 25);
|
|
24
|
+
--warning: oklch(0.79 0.14 85);
|
|
25
|
+
|
|
26
|
+
/* Bridge the view components' token vocabulary to the OMP base tokens so
|
|
27
|
+
muted/secondary text and semantic accents resolve instead of silently
|
|
28
|
+
falling back to inherited text color. Re-resolve per theme via var(). */
|
|
37
29
|
--text-primary: var(--text);
|
|
38
|
-
--text-secondary: var(--
|
|
30
|
+
--text-secondary: var(--muted);
|
|
31
|
+
--text-muted: var(--dim);
|
|
39
32
|
--border-subtle: var(--border);
|
|
40
33
|
--accent-red: var(--danger);
|
|
41
34
|
--accent-green: var(--success);
|
|
42
35
|
--accent-cyan: var(--link);
|
|
43
|
-
--bg-
|
|
36
|
+
--bg-hover: var(--surface-2);
|
|
37
|
+
--bg-elevated: var(--surface-2);
|
|
38
|
+
--select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23999' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
|
|
44
39
|
|
|
45
40
|
--radius-sm: 3px;
|
|
46
41
|
--radius-md: 6px;
|
|
@@ -52,89 +47,44 @@
|
|
|
52
47
|
@media (prefers-color-scheme: light) {
|
|
53
48
|
:root:not([data-theme]) {
|
|
54
49
|
color-scheme: light;
|
|
55
|
-
--
|
|
56
|
-
--
|
|
57
|
-
--
|
|
58
|
-
--
|
|
59
|
-
--
|
|
60
|
-
--
|
|
61
|
-
--
|
|
62
|
-
--
|
|
63
|
-
--
|
|
64
|
-
--
|
|
65
|
-
--accent:
|
|
66
|
-
--
|
|
67
|
-
--
|
|
68
|
-
--
|
|
69
|
-
--
|
|
70
|
-
--
|
|
71
|
-
--danger: #dc2626;
|
|
72
|
-
--warning: #d97706;
|
|
73
|
-
/* Backward-compat aliases */
|
|
74
|
-
--page: var(--bg);
|
|
75
|
-
--surface: var(--bg-panel);
|
|
76
|
-
--surface-2: var(--bg-hover);
|
|
77
|
-
--muted: var(--text-muted);
|
|
78
|
-
--dim: var(--text-dim);
|
|
50
|
+
--page: oklch(0.985 0.004 307);
|
|
51
|
+
--surface: oklch(1 0 0);
|
|
52
|
+
--surface-2: oklch(0.965 0.006 307);
|
|
53
|
+
--border: oklch(0 0 0 / 10%);
|
|
54
|
+
--border-strong: oklch(0 0 0 / 15%);
|
|
55
|
+
--text: oklch(0.26 0.03 307);
|
|
56
|
+
--muted: oklch(0.46 0.03 307);
|
|
57
|
+
--dim: oklch(0.58 0.025 307);
|
|
58
|
+
--accent: oklch(0.62 0.23 341);
|
|
59
|
+
--accent-fg: oklch(0.99 0.01 341);
|
|
60
|
+
--accent-muted: oklch(0.62 0.23 341 / 14%);
|
|
61
|
+
--link: oklch(0.58 0.13 230);
|
|
62
|
+
--success: oklch(0.55 0.13 150);
|
|
63
|
+
--danger: oklch(0.55 0.19 25);
|
|
64
|
+
--select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23555' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
|
|
65
|
+
--warning: oklch(0.6 0.13 85);
|
|
79
66
|
}
|
|
80
67
|
}
|
|
81
68
|
|
|
82
69
|
/* Explicit theme override (toggle or persisted preference). */
|
|
83
70
|
[data-theme="light"] {
|
|
84
71
|
color-scheme: light;
|
|
85
|
-
--
|
|
86
|
-
--
|
|
87
|
-
--
|
|
88
|
-
--
|
|
89
|
-
--
|
|
90
|
-
--
|
|
91
|
-
--
|
|
92
|
-
--
|
|
93
|
-
--
|
|
94
|
-
--
|
|
95
|
-
--accent:
|
|
96
|
-
--
|
|
97
|
-
--
|
|
98
|
-
--
|
|
99
|
-
--
|
|
100
|
-
--
|
|
101
|
-
--danger: #dc2626;
|
|
102
|
-
--warning: #d97706;
|
|
103
|
-
/* Backward-compat aliases */
|
|
104
|
-
--page: var(--bg);
|
|
105
|
-
--surface: var(--bg-panel);
|
|
106
|
-
--surface-2: var(--bg-hover);
|
|
107
|
-
--muted: var(--text-muted);
|
|
108
|
-
--dim: var(--text-dim);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/* Zeta Starfield theme — NASA-punk deep-space HUD, aligned with web-ui globals.css */
|
|
112
|
-
[data-theme="starfield"] {
|
|
113
|
-
color-scheme: dark;
|
|
114
|
-
--bg: #08090d;
|
|
115
|
-
--bg-panel: #0d1117;
|
|
116
|
-
--bg-hover: #161d2e;
|
|
117
|
-
--bg-selected: #1a2540;
|
|
118
|
-
--bg-subtle: rgba(217,155,38,0.05);
|
|
119
|
-
--border: #1e2d45;
|
|
120
|
-
--border-strong: rgba(217,155,38,0.2);
|
|
121
|
-
--text: #e8eeff;
|
|
122
|
-
--text-muted: #8fa3c0;
|
|
123
|
-
--text-dim: #3d5070;
|
|
124
|
-
--accent: #d99b26; /* Zeta Starfield gold */
|
|
125
|
-
--accent-hover: #f0b840;
|
|
126
|
-
--accent-fg: #0f172a;
|
|
127
|
-
--accent-muted: rgba(217,155,38,0.18);
|
|
128
|
-
--link: #d99b26;
|
|
129
|
-
--success: #22c55e;
|
|
130
|
-
--danger: #c81d25;
|
|
131
|
-
--warning: #e05a2b;
|
|
132
|
-
/* Backward-compat aliases */
|
|
133
|
-
--page: var(--bg);
|
|
134
|
-
--surface: var(--bg-panel);
|
|
135
|
-
--surface-2: var(--bg-hover);
|
|
136
|
-
--muted: var(--text-muted);
|
|
137
|
-
--dim: var(--text-dim);
|
|
72
|
+
--page: oklch(0.985 0.004 307);
|
|
73
|
+
--surface: oklch(1 0 0);
|
|
74
|
+
--surface-2: oklch(0.965 0.006 307);
|
|
75
|
+
--border: oklch(0 0 0 / 10%);
|
|
76
|
+
--border-strong: oklch(0 0 0 / 15%);
|
|
77
|
+
--text: oklch(0.26 0.03 307);
|
|
78
|
+
--muted: oklch(0.46 0.03 307);
|
|
79
|
+
--dim: oklch(0.58 0.025 307);
|
|
80
|
+
--accent: oklch(0.62 0.23 341);
|
|
81
|
+
--accent-fg: oklch(0.99 0.01 341);
|
|
82
|
+
--accent-muted: oklch(0.62 0.23 341 / 14%);
|
|
83
|
+
--link: oklch(0.58 0.13 230);
|
|
84
|
+
--success: oklch(0.55 0.13 150);
|
|
85
|
+
--danger: oklch(0.55 0.19 25);
|
|
86
|
+
--select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23555' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
|
|
87
|
+
--warning: oklch(0.6 0.13 85);
|
|
138
88
|
}
|
|
139
89
|
|
|
140
90
|
/* ==========================================================================
|
|
@@ -517,6 +467,62 @@
|
|
|
517
467
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
|
|
518
468
|
}
|
|
519
469
|
|
|
470
|
+
/* Select (native <select>, themed to match RangeControl/Buttons) */
|
|
471
|
+
.stats-select {
|
|
472
|
+
appearance: none;
|
|
473
|
+
padding: 6px 28px 6px 12px;
|
|
474
|
+
font-size: 13px;
|
|
475
|
+
font-weight: 500;
|
|
476
|
+
font-family: inherit;
|
|
477
|
+
color: var(--text);
|
|
478
|
+
background-color: var(--surface-2);
|
|
479
|
+
/* Chevron follows theme: light stroke on dark, dark stroke on light. */
|
|
480
|
+
background-image: var(--select-chevron);
|
|
481
|
+
background-repeat: no-repeat;
|
|
482
|
+
background-position: right 10px center;
|
|
483
|
+
border: 1px solid var(--border);
|
|
484
|
+
border-radius: var(--radius-md);
|
|
485
|
+
cursor: pointer;
|
|
486
|
+
transition: border-color 0.15s ease, background-color 0.15s ease;
|
|
487
|
+
max-width: 100%;
|
|
488
|
+
text-overflow: ellipsis;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
.stats-select:hover:not(:disabled) {
|
|
492
|
+
border-color: var(--border-strong);
|
|
493
|
+
background-color: var(--bg-hover);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.stats-select:focus-visible {
|
|
497
|
+
outline: 2px solid var(--link);
|
|
498
|
+
outline-offset: 1px;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
.stats-select:disabled {
|
|
502
|
+
opacity: 0.5;
|
|
503
|
+
cursor: not-allowed;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/* Prevent iOS from zooming the viewport when a select receives focus. */
|
|
507
|
+
@media (pointer: coarse) {
|
|
508
|
+
.stats-select {
|
|
509
|
+
font-size: 16px;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/* Dropdown list itself follows the page theme via color-scheme. */
|
|
514
|
+
.stats-select option {
|
|
515
|
+
background-color: var(--surface);
|
|
516
|
+
color: var(--text);
|
|
517
|
+
}
|
|
518
|
+
/* Forced-colors (Windows High Contrast) suppresses background images, so the
|
|
519
|
+
custom chevron vanishes; restore the native indicator instead. */
|
|
520
|
+
@media (forced-colors: active) {
|
|
521
|
+
.stats-select {
|
|
522
|
+
appearance: auto;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
520
526
|
/* Sync Button & Container */
|
|
521
527
|
.stats-sync-container {
|
|
522
528
|
display: flex;
|
|
@@ -1287,7 +1293,7 @@
|
|
|
1287
1293
|
}
|
|
1288
1294
|
|
|
1289
1295
|
/* ==========================================================================
|
|
1290
|
-
Brand mark on the
|
|
1296
|
+
Brand mark on the OMP wordmark (both rail + mobile drawer headers)
|
|
1291
1297
|
========================================================================== */
|
|
1292
1298
|
.stats-logo-container {
|
|
1293
1299
|
display: grid;
|
|
@@ -1302,7 +1308,7 @@
|
|
|
1302
1308
|
width: 16px;
|
|
1303
1309
|
height: 16px;
|
|
1304
1310
|
border-radius: 4px;
|
|
1305
|
-
background: linear-gradient(135deg, #
|
|
1311
|
+
background: linear-gradient(135deg, #ed4abf 0%, #9b4dff 50%, #5ad8e6 100%); /* OMP brand gradient mark */
|
|
1306
1312
|
}
|
|
1307
1313
|
|
|
1308
1314
|
.stats-logo-text,
|
|
@@ -1382,3 +1388,319 @@
|
|
|
1382
1388
|
transition: none;
|
|
1383
1389
|
}
|
|
1384
1390
|
}
|
|
1391
|
+
|
|
1392
|
+
/* ==========================================================================
|
|
1393
|
+
Traces (session flamegraph)
|
|
1394
|
+
========================================================================== */
|
|
1395
|
+
.stats-trace-view {
|
|
1396
|
+
display: flex;
|
|
1397
|
+
flex-direction: column;
|
|
1398
|
+
gap: 14px;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
.stats-trace-header {
|
|
1402
|
+
display: flex;
|
|
1403
|
+
align-items: center;
|
|
1404
|
+
gap: 12px;
|
|
1405
|
+
flex-wrap: wrap;
|
|
1406
|
+
min-width: 0;
|
|
1407
|
+
}
|
|
1408
|
+
|
|
1409
|
+
.stats-trace-back {
|
|
1410
|
+
display: inline-flex;
|
|
1411
|
+
align-items: center;
|
|
1412
|
+
gap: 6px;
|
|
1413
|
+
padding: 6px 12px;
|
|
1414
|
+
font-size: 12px;
|
|
1415
|
+
color: var(--muted);
|
|
1416
|
+
background: var(--surface);
|
|
1417
|
+
border: 1px solid var(--border);
|
|
1418
|
+
border-radius: var(--radius-md);
|
|
1419
|
+
cursor: pointer;
|
|
1420
|
+
transition: color 0.14s ease, border-color 0.14s ease;
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
.stats-trace-back:hover {
|
|
1424
|
+
color: var(--text);
|
|
1425
|
+
border-color: var(--border-strong);
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
.stats-trace-back:focus-visible {
|
|
1429
|
+
outline: 2px solid var(--link);
|
|
1430
|
+
outline-offset: 2px;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
.stats-trace-title {
|
|
1434
|
+
font-size: 15px;
|
|
1435
|
+
font-weight: 600;
|
|
1436
|
+
color: var(--text);
|
|
1437
|
+
margin: 0;
|
|
1438
|
+
min-width: 0;
|
|
1439
|
+
overflow: hidden;
|
|
1440
|
+
text-overflow: ellipsis;
|
|
1441
|
+
white-space: nowrap;
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
.stats-trace-cwd {
|
|
1445
|
+
font-size: 11px;
|
|
1446
|
+
color: var(--dim);
|
|
1447
|
+
border: 1px solid var(--border);
|
|
1448
|
+
border-radius: 999px;
|
|
1449
|
+
padding: 3px 10px;
|
|
1450
|
+
max-width: 280px;
|
|
1451
|
+
overflow: hidden;
|
|
1452
|
+
text-overflow: ellipsis;
|
|
1453
|
+
white-space: nowrap;
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
/* Summary strip: one bordered card, hairline-divided stat columns. */
|
|
1457
|
+
.stats-trace-summary {
|
|
1458
|
+
display: flex;
|
|
1459
|
+
flex-wrap: wrap;
|
|
1460
|
+
background: var(--surface);
|
|
1461
|
+
border: 1px solid var(--border);
|
|
1462
|
+
border-radius: var(--radius-lg);
|
|
1463
|
+
overflow: hidden;
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
.stats-trace-summary-cell {
|
|
1467
|
+
display: flex;
|
|
1468
|
+
flex-direction: column;
|
|
1469
|
+
gap: 3px;
|
|
1470
|
+
padding: 10px 16px;
|
|
1471
|
+
border-right: 1px solid var(--border);
|
|
1472
|
+
min-width: 76px;
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1475
|
+
.stats-trace-summary-cell:last-child {
|
|
1476
|
+
border-right: none;
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
.stats-trace-summary-label {
|
|
1480
|
+
font-size: 9px;
|
|
1481
|
+
text-transform: uppercase;
|
|
1482
|
+
letter-spacing: 0.07em;
|
|
1483
|
+
color: var(--dim);
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1486
|
+
.stats-trace-summary-value {
|
|
1487
|
+
font-size: 13px;
|
|
1488
|
+
font-weight: 500;
|
|
1489
|
+
color: var(--text);
|
|
1490
|
+
font-variant-numeric: tabular-nums;
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
/* Toolbar row above the timeline. */
|
|
1494
|
+
.stats-trace-toolbar {
|
|
1495
|
+
display: flex;
|
|
1496
|
+
align-items: center;
|
|
1497
|
+
gap: 12px;
|
|
1498
|
+
flex-wrap: wrap;
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
.stats-trace-toolbar-hint {
|
|
1502
|
+
font-size: 10px;
|
|
1503
|
+
color: var(--dim);
|
|
1504
|
+
margin-left: auto;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
.stats-trace-input {
|
|
1508
|
+
background: var(--surface);
|
|
1509
|
+
border: 1px solid var(--border);
|
|
1510
|
+
border-radius: var(--radius-md);
|
|
1511
|
+
color: var(--text);
|
|
1512
|
+
font-size: 12px;
|
|
1513
|
+
padding: 6px 10px;
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
.stats-trace-input:focus-visible {
|
|
1517
|
+
outline: 2px solid var(--link);
|
|
1518
|
+
outline-offset: 1px;
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
.stats-trace-input::placeholder {
|
|
1522
|
+
color: var(--dim);
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
.stats-trace-check {
|
|
1526
|
+
display: inline-flex;
|
|
1527
|
+
align-items: center;
|
|
1528
|
+
gap: 6px;
|
|
1529
|
+
font-size: 12px;
|
|
1530
|
+
color: var(--muted);
|
|
1531
|
+
cursor: pointer;
|
|
1532
|
+
user-select: none;
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1535
|
+
.stats-trace-icon-btn {
|
|
1536
|
+
display: inline-flex;
|
|
1537
|
+
align-items: center;
|
|
1538
|
+
justify-content: center;
|
|
1539
|
+
width: 26px;
|
|
1540
|
+
height: 26px;
|
|
1541
|
+
background: transparent;
|
|
1542
|
+
border: 1px solid var(--border);
|
|
1543
|
+
border-radius: var(--radius-md);
|
|
1544
|
+
color: var(--muted);
|
|
1545
|
+
cursor: pointer;
|
|
1546
|
+
transition: color 0.14s ease, border-color 0.14s ease;
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
.stats-trace-icon-btn:hover:not(:disabled) {
|
|
1550
|
+
color: var(--text);
|
|
1551
|
+
border-color: var(--border-strong);
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
.stats-trace-icon-btn:focus-visible {
|
|
1555
|
+
outline: 2px solid var(--link);
|
|
1556
|
+
outline-offset: 2px;
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
.stats-trace-icon-btn:disabled {
|
|
1560
|
+
opacity: 0.4;
|
|
1561
|
+
cursor: default;
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
/* Timeline card: minimap + canvas share one bordered surface. */
|
|
1565
|
+
.stats-trace-timeline-card {
|
|
1566
|
+
background: var(--surface);
|
|
1567
|
+
border: 1px solid var(--border);
|
|
1568
|
+
border-radius: var(--radius-lg);
|
|
1569
|
+
padding: 12px;
|
|
1570
|
+
display: flex;
|
|
1571
|
+
flex-direction: column;
|
|
1572
|
+
gap: 10px;
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1575
|
+
.stats-trace-timeline {
|
|
1576
|
+
position: relative;
|
|
1577
|
+
display: flex;
|
|
1578
|
+
max-height: 560px;
|
|
1579
|
+
overflow-y: auto;
|
|
1580
|
+
overflow-x: hidden;
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
.stats-trace-canvas {
|
|
1584
|
+
cursor: grab;
|
|
1585
|
+
outline: none;
|
|
1586
|
+
touch-action: none;
|
|
1587
|
+
border-radius: var(--radius-sm);
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
.stats-trace-canvas:focus-visible {
|
|
1591
|
+
outline: 2px solid var(--link);
|
|
1592
|
+
outline-offset: 2px;
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
.stats-trace-canvas:active {
|
|
1596
|
+
cursor: grabbing;
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
.stats-trace-chevron {
|
|
1600
|
+
display: inline-flex;
|
|
1601
|
+
background: none;
|
|
1602
|
+
border: none;
|
|
1603
|
+
padding: 0;
|
|
1604
|
+
cursor: pointer;
|
|
1605
|
+
color: var(--muted);
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1608
|
+
.stats-trace-chevron:hover {
|
|
1609
|
+
color: var(--text);
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1612
|
+
.stats-trace-gutter-track {
|
|
1613
|
+
font-size: 11px;
|
|
1614
|
+
font-weight: 500;
|
|
1615
|
+
color: var(--text);
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
.stats-trace-gutter-model {
|
|
1619
|
+
font-size: 9px;
|
|
1620
|
+
color: var(--dim);
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
.stats-trace-gutter-lane {
|
|
1624
|
+
position: absolute;
|
|
1625
|
+
font-size: 8px;
|
|
1626
|
+
color: var(--dim);
|
|
1627
|
+
text-transform: uppercase;
|
|
1628
|
+
letter-spacing: 0.08em;
|
|
1629
|
+
}
|
|
1630
|
+
|
|
1631
|
+
/* Transcript list under the timeline. */
|
|
1632
|
+
.stats-trace-list {
|
|
1633
|
+
background: var(--surface);
|
|
1634
|
+
border: 1px solid var(--border);
|
|
1635
|
+
border-radius: var(--radius-lg);
|
|
1636
|
+
height: 340px;
|
|
1637
|
+
overflow-y: auto;
|
|
1638
|
+
}
|
|
1639
|
+
|
|
1640
|
+
.stats-trace-row {
|
|
1641
|
+
display: flex;
|
|
1642
|
+
align-items: center;
|
|
1643
|
+
gap: 10px;
|
|
1644
|
+
height: 28px;
|
|
1645
|
+
width: 100%;
|
|
1646
|
+
padding: 0 12px;
|
|
1647
|
+
background: transparent;
|
|
1648
|
+
border: none;
|
|
1649
|
+
border-bottom: 1px solid var(--border);
|
|
1650
|
+
text-align: left;
|
|
1651
|
+
cursor: pointer;
|
|
1652
|
+
transition: background 0.1s ease;
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
.stats-trace-row:hover {
|
|
1656
|
+
background: var(--bg-hover);
|
|
1657
|
+
}
|
|
1658
|
+
|
|
1659
|
+
.stats-trace-row:focus-visible {
|
|
1660
|
+
outline: 2px solid var(--link);
|
|
1661
|
+
outline-offset: -2px;
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1664
|
+
.stats-trace-row[data-selected="true"] {
|
|
1665
|
+
background: var(--accent-muted);
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
.stats-trace-row-static {
|
|
1669
|
+
cursor: default;
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
.stats-trace-row-static:hover {
|
|
1673
|
+
background: transparent;
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
.stats-trace-kind {
|
|
1677
|
+
flex-shrink: 0;
|
|
1678
|
+
width: 58px;
|
|
1679
|
+
font-size: 8px;
|
|
1680
|
+
text-transform: uppercase;
|
|
1681
|
+
letter-spacing: 0.06em;
|
|
1682
|
+
border-radius: 3px;
|
|
1683
|
+
padding: 2px 0;
|
|
1684
|
+
text-align: center;
|
|
1685
|
+
overflow: hidden;
|
|
1686
|
+
text-overflow: ellipsis;
|
|
1687
|
+
white-space: nowrap;
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
.stats-trace-row-meta {
|
|
1691
|
+
flex-shrink: 0;
|
|
1692
|
+
margin-left: auto;
|
|
1693
|
+
font-size: 10px;
|
|
1694
|
+
color: var(--dim);
|
|
1695
|
+
font-variant-numeric: tabular-nums;
|
|
1696
|
+
display: flex;
|
|
1697
|
+
gap: 10px;
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1701
|
+
.stats-trace-back,
|
|
1702
|
+
.stats-trace-icon-btn,
|
|
1703
|
+
.stats-trace-row {
|
|
1704
|
+
transition: none;
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collapsible per-tool duration aggregates for one trace, sorted by total
|
|
3
|
+
* time descending (as produced by the server).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ChevronDown, ChevronRight } from "lucide-react";
|
|
7
|
+
import { useMemo, useState } from "react";
|
|
8
|
+
import { formatDurationMs, formatInteger } from "../data/formatters";
|
|
9
|
+
import type { TraceToolStat } from "../types";
|
|
10
|
+
import { DataTable } from "../ui/DataTable";
|
|
11
|
+
|
|
12
|
+
export interface AggregatesPanelProps {
|
|
13
|
+
toolStats: TraceToolStat[];
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function AggregatesPanel({ toolStats }: AggregatesPanelProps) {
|
|
17
|
+
const [open, setOpen] = useState(false);
|
|
18
|
+
|
|
19
|
+
const columns = useMemo(
|
|
20
|
+
() => [
|
|
21
|
+
{ key: "tool", header: "Tool", render: (item: TraceToolStat) => item.tool },
|
|
22
|
+
{ key: "calls", header: "Calls", numeric: true, render: (item: TraceToolStat) => formatInteger(item.calls) },
|
|
23
|
+
{
|
|
24
|
+
key: "errors",
|
|
25
|
+
header: "Errors",
|
|
26
|
+
numeric: true,
|
|
27
|
+
render: (item: TraceToolStat) => formatInteger(item.errors),
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
key: "total",
|
|
31
|
+
header: "Total",
|
|
32
|
+
numeric: true,
|
|
33
|
+
render: (item: TraceToolStat) => formatDurationMs(item.totalMs),
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
key: "avg",
|
|
37
|
+
header: "Avg",
|
|
38
|
+
numeric: true,
|
|
39
|
+
render: (item: TraceToolStat) => formatDurationMs(item.calls > 0 ? item.totalMs / item.calls : 0),
|
|
40
|
+
},
|
|
41
|
+
{ key: "max", header: "Max", numeric: true, render: (item: TraceToolStat) => formatDurationMs(item.maxMs) },
|
|
42
|
+
],
|
|
43
|
+
[],
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
if (toolStats.length === 0) return null;
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div className="stats-panel">
|
|
50
|
+
<button
|
|
51
|
+
type="button"
|
|
52
|
+
onClick={() => setOpen(prev => !prev)}
|
|
53
|
+
aria-expanded={open}
|
|
54
|
+
style={{
|
|
55
|
+
display: "flex",
|
|
56
|
+
alignItems: "center",
|
|
57
|
+
gap: 6,
|
|
58
|
+
width: "100%",
|
|
59
|
+
background: "none",
|
|
60
|
+
border: "none",
|
|
61
|
+
padding: "10px 14px",
|
|
62
|
+
cursor: "pointer",
|
|
63
|
+
textAlign: "left",
|
|
64
|
+
}}
|
|
65
|
+
>
|
|
66
|
+
{open ? (
|
|
67
|
+
<ChevronDown size={14} className="stats-text-muted" aria-hidden="true" />
|
|
68
|
+
) : (
|
|
69
|
+
<ChevronRight size={14} className="stats-text-muted" aria-hidden="true" />
|
|
70
|
+
)}
|
|
71
|
+
<span className="stats-panel-title">Tool Aggregates</span>
|
|
72
|
+
<span className="stats-text-muted" style={{ fontSize: 11 }}>
|
|
73
|
+
{toolStats.length} tools
|
|
74
|
+
</span>
|
|
75
|
+
</button>
|
|
76
|
+
{open && (
|
|
77
|
+
<div className="stats-panel-body">
|
|
78
|
+
<DataTable
|
|
79
|
+
columns={columns}
|
|
80
|
+
data={toolStats}
|
|
81
|
+
keyExtractor={item => item.tool}
|
|
82
|
+
emptyText="No tool calls"
|
|
83
|
+
/>
|
|
84
|
+
</div>
|
|
85
|
+
)}
|
|
86
|
+
</div>
|
|
87
|
+
);
|
|
88
|
+
}
|