dsh-context 0.62.3 → 0.64.0
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/README.md +6 -6
- package/lib/client.js +689 -437
- package/lib/index.d.ts +48 -0
- package/lib/index.js +92 -19
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -108,6 +108,7 @@ window.__ModuleLoader__.load({
|
|
|
108
108
|
"insightsEntry.hide": "隐藏",
|
|
109
109
|
"settings.gran": "趋势图 · 默认粒度",
|
|
110
110
|
"settings.mode": "趋势图 · 默认展示方式",
|
|
111
|
+
"settings.durationCurve": "趋势图 · 耗时曲线",
|
|
111
112
|
"settings.deltaBase": "上下文浏览器 · 对比基线",
|
|
112
113
|
"settings.toolSort": "工具定义 · 默认排序",
|
|
113
114
|
"settings.fileSort": "文件活动 · 默认排序",
|
|
@@ -117,9 +118,10 @@ window.__ModuleLoader__.load({
|
|
|
117
118
|
"gran.total": "全量",
|
|
118
119
|
"gran.delta": "增量",
|
|
119
120
|
"gran.modeHint": "全量:累计构成;增量:相对上一条请求的变化量",
|
|
120
|
-
"trend.focus": "仅展示 {cat}",
|
|
121
121
|
"trend.adaptive": "自适应",
|
|
122
122
|
"trend.adaptiveHint": "按当前可视范围内的柱子重新缩放高度,滚动时随之变化",
|
|
123
|
+
"trend.duration": "耗时",
|
|
124
|
+
"trend.durationTip": "在柱子上叠加每步的活跃耗时曲线(步骤开始至结束,含模型与工具调用,不含等待你决策或回答的时间),按图中右侧的四分位坐标轴读数;轮次粒度下为一轮各步耗时之和",
|
|
123
125
|
"trend.dna": "DNA 模式",
|
|
124
126
|
"trend.dnaTip": "把每根柱子画成该次请求的上下文指纹:按模型读取顺序逐条铺色,配合增量模式逐条展示每次请求的增减;悬停查看条目,点击让上下文浏览器定位到该条目,同一条目在所有柱子中亮出其存续变化",
|
|
125
127
|
"trend.dnaItem": "{label}:{n}",
|
|
@@ -255,6 +257,7 @@ window.__ModuleLoader__.load({
|
|
|
255
257
|
"tip.total": "合计 ≈ {n}",
|
|
256
258
|
"tip.cat": "{cat} ≈ {n}",
|
|
257
259
|
"tip.delta": "Δ {n}",
|
|
260
|
+
"tip.duration": "耗时 {n}",
|
|
258
261
|
"ev.compaction": "压缩上下文(摘要替换 {n} 条消息)",
|
|
259
262
|
"ev.prune": "剪枝工具输出",
|
|
260
263
|
"ev.skill": "Skill 注入({name})",
|
|
@@ -354,7 +357,6 @@ window.__ModuleLoader__.load({
|
|
|
354
357
|
"attach.sent": "发送",
|
|
355
358
|
"attach.token": "Token",
|
|
356
359
|
"attach.tokensTip": "按 DeepSeek 官方图片尺寸换算(单图上限 384 tokens)估算的 token 消耗",
|
|
357
|
-
"ov.entry": "上下文洞察",
|
|
358
360
|
"ov.title": "上下文洞察",
|
|
359
361
|
"ov.unavailable": "会话列表暂不可用",
|
|
360
362
|
"ov.range.label": "统计范围",
|
|
@@ -506,6 +508,7 @@ window.__ModuleLoader__.load({
|
|
|
506
508
|
"insightsEntry.hide": "Hide",
|
|
507
509
|
"settings.gran": "Trend Chart · Default granularity",
|
|
508
510
|
"settings.mode": "Trend Chart · Default display",
|
|
511
|
+
"settings.durationCurve": "Trend Chart · Duration curve",
|
|
509
512
|
"settings.deltaBase": "Context Browser · Diff baseline",
|
|
510
513
|
"settings.toolSort": "Tool Schemas · Default sort",
|
|
511
514
|
"settings.fileSort": "File Activity · Default sort",
|
|
@@ -515,9 +518,10 @@ window.__ModuleLoader__.load({
|
|
|
515
518
|
"gran.total": "Total",
|
|
516
519
|
"gran.delta": "Delta",
|
|
517
520
|
"gran.modeHint": "Total: cumulative makeup; Delta: change vs the previous request",
|
|
518
|
-
"trend.focus": "Showing {cat} only",
|
|
519
521
|
"trend.adaptive": "Adaptive",
|
|
520
522
|
"trend.adaptiveHint": "Rescale bar heights to the visible range, following the scroll",
|
|
523
|
+
"trend.duration": "Duration",
|
|
524
|
+
"trend.durationTip": "Overlay each step’s active time (step start to end — model and tool calls, excluding waits for your decisions or answers) as a curve over the bars, read off the quartile axis on the chart’s right; turn granularity sums a turn’s steps",
|
|
521
525
|
"trend.dna": "DNA Mode",
|
|
522
526
|
"trend.dnaTip": "Draw each bar as that request’s context fingerprint — one band per item in the order the model reads it; with Delta, each band shows that item’s change against the previous bar. Hover for the item, click to reveal it in the Context browser, and every bar lights the same item’s lifetime",
|
|
523
527
|
"trend.dnaItem": "{label}: {n}",
|
|
@@ -653,6 +657,7 @@ window.__ModuleLoader__.load({
|
|
|
653
657
|
"tip.total": "Total ≈ {n}",
|
|
654
658
|
"tip.cat": "{cat} ≈ {n}",
|
|
655
659
|
"tip.delta": "Δ {n}",
|
|
660
|
+
"tip.duration": "Duration {n}",
|
|
656
661
|
"ev.compaction": "Context compacted (summary replaced {n} messages)",
|
|
657
662
|
"ev.prune": "Tool output pruned",
|
|
658
663
|
"ev.skill": "Skill injected ({name})",
|
|
@@ -752,7 +757,6 @@ window.__ModuleLoader__.load({
|
|
|
752
757
|
"attach.sent": "Sent",
|
|
753
758
|
"attach.token": "Token",
|
|
754
759
|
"attach.tokensTip": "Estimated token cost via DeepSeek's official image-size conversion (384-token cap per image)",
|
|
755
|
-
"ov.entry": "Context Insights",
|
|
756
760
|
"ov.title": "Context Insights",
|
|
757
761
|
"ov.unavailable": "The session list is unavailable",
|
|
758
762
|
"ov.range.label": "Range",
|
|
@@ -841,11 +845,11 @@ window.__ModuleLoader__.load({
|
|
|
841
845
|
* it to the Plugins page's package cards. The client bundle inlines the
|
|
842
846
|
* file's markup at build time (the `?raw` channel in tsdown.config.ts) and
|
|
843
847
|
* re-renders it at every requested size. The identity seats (tab chip,
|
|
844
|
-
* command, sidebar registration
|
|
848
|
+
* command, sidebar registration) keep the sheet's fixed fills —
|
|
845
849
|
* deliberately polychrome on both light and dark chrome — while the
|
|
846
|
-
* sidebar-
|
|
847
|
-
* every fill for `currentColor` so the glyph
|
|
848
|
-
*
|
|
850
|
+
* sidebar's panel-list seat (insightPage.ts) opts into `mono`, trading
|
|
851
|
+
* every fill for `currentColor` so the glyph follows the shell-owned row's
|
|
852
|
+
* own state colors, exactly as the shipped panel glyphs do.
|
|
849
853
|
*/
|
|
850
854
|
/** Everything between the file's `<svg>` tags: the sheet's strokes in paint order, whitespace-folded. */
|
|
851
855
|
const SHEET_MARKUP = icon_default.slice(icon_default.indexOf(">") + 1, icon_default.lastIndexOf("</svg>")).trim().replace(/>\s+</g, "><");
|
|
@@ -864,6 +868,19 @@ window.__ModuleLoader__.load({
|
|
|
864
868
|
});
|
|
865
869
|
}
|
|
866
870
|
/**
|
|
871
|
+
* The sidebar panel-list glyph (`sidebar.panellist`): the emblem in `mono` at
|
|
872
|
+
* the size the shell asks for, so the shell-owned row's hover/active colors
|
|
873
|
+
* paint it like the shipped panel glyphs. The shell owns the row's label,
|
|
874
|
+
* and the row's selected state its own styling, so — as on the shipped
|
|
875
|
+
* glyphs — the owner props' `active` goes unread.
|
|
876
|
+
*/
|
|
877
|
+
function InsightPanelIcon({ size = 18 }) {
|
|
878
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContextIcon, {
|
|
879
|
+
size,
|
|
880
|
+
mono: true
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
867
884
|
* The tab chip's title seat (`sidebar.right.pane.tab.title`): the emblem before
|
|
868
885
|
* the label, so the chip reads as the files chip does. The label comes from the
|
|
869
886
|
* plugin's own bound translate — read at render, so the chip follows the active
|
|
@@ -2201,9 +2218,9 @@ window.__ModuleLoader__.load({
|
|
|
2201
2218
|
* The no-stale-content guarantees: the store is per session and shared by
|
|
2202
2219
|
* the tab and the modal; a refetch is single-flight with a trailing edge
|
|
2203
2220
|
* (a rev bumped mid-flight re-reads after settle); responses race-safe by
|
|
2204
|
-
* revision (
|
|
2205
|
-
*
|
|
2206
|
-
*
|
|
2221
|
+
* generation and revision (a host refold invalidates reads started before
|
|
2222
|
+
* its revisions restarted, and latest wins within a generation); a
|
|
2223
|
+
* transport failure keeps the last good
|
|
2207
2224
|
* detail and backs off; an absent answer (the session left the live set)
|
|
2208
2225
|
* stops the trailing until the head moves again. With no detail at all,
|
|
2209
2226
|
* failure surfaces as a retryable note on the detail cards instead of an
|
|
@@ -2292,6 +2309,7 @@ window.__ModuleLoader__.load({
|
|
|
2292
2309
|
targetRev = -1;
|
|
2293
2310
|
/** The head rev seen last — a DECREASE means the host refolded (revisions restart). */
|
|
2294
2311
|
lastHeadRev = -1;
|
|
2312
|
+
generation = 0;
|
|
2295
2313
|
failed = false;
|
|
2296
2314
|
inFlight = false;
|
|
2297
2315
|
timer = null;
|
|
@@ -2315,6 +2333,7 @@ window.__ModuleLoader__.load({
|
|
|
2315
2333
|
*/
|
|
2316
2334
|
request(rev) {
|
|
2317
2335
|
if (rev < this.lastHeadRev) {
|
|
2336
|
+
this.generation++;
|
|
2318
2337
|
this.acceptedRev = -1;
|
|
2319
2338
|
this.wantedRev = -1;
|
|
2320
2339
|
this.detail = null;
|
|
@@ -2352,9 +2371,11 @@ window.__ModuleLoader__.load({
|
|
|
2352
2371
|
}
|
|
2353
2372
|
this.inFlight = true;
|
|
2354
2373
|
this.targetRev = this.wantedRev;
|
|
2374
|
+
const generation = this.generation;
|
|
2355
2375
|
this.emit();
|
|
2356
2376
|
try {
|
|
2357
2377
|
const d = await this.fetcher();
|
|
2378
|
+
if (generation !== this.generation) return;
|
|
2358
2379
|
if (d !== null) {
|
|
2359
2380
|
if (d.rev >= this.acceptedRev || d.rev === this.targetRev) {
|
|
2360
2381
|
this.detail = d;
|
|
@@ -2368,12 +2389,15 @@ window.__ModuleLoader__.load({
|
|
|
2368
2389
|
this.failures++;
|
|
2369
2390
|
}
|
|
2370
2391
|
} catch {
|
|
2371
|
-
|
|
2372
|
-
|
|
2392
|
+
if (generation === this.generation) {
|
|
2393
|
+
this.failed = this.detail === null;
|
|
2394
|
+
this.failures++;
|
|
2395
|
+
}
|
|
2396
|
+
} finally {
|
|
2397
|
+
this.inFlight = false;
|
|
2398
|
+
if (this.wantedRev > this.acceptedRev) this.schedule();
|
|
2399
|
+
this.emit();
|
|
2373
2400
|
}
|
|
2374
|
-
this.inFlight = false;
|
|
2375
|
-
if (this.wantedRev > this.acceptedRev) this.schedule();
|
|
2376
|
-
this.emit();
|
|
2377
2401
|
}
|
|
2378
2402
|
emit() {
|
|
2379
2403
|
const pending = this.timer !== null || this.inFlight;
|
|
@@ -3003,21 +3027,31 @@ window.__ModuleLoader__.load({
|
|
|
3003
3027
|
*/
|
|
3004
3028
|
/**
|
|
3005
3029
|
* Collapse per-step requests into one bar per turn — each turn is represented by its LAST step's record, tagged `stepCount` for the bar's
|
|
3006
|
-
* column width; the log keeps one turn's requests consecutive, so a run of equal turns collapses to its final record.
|
|
3030
|
+
* column width; the log keeps one turn's requests consecutive, so a run of equal turns collapses to its final record. The duration
|
|
3031
|
+
* overlay's `activeMs` is the run's steps SUMMED (the turn's total step active time), absent only when no step of the run carried one.
|
|
3007
3032
|
*/
|
|
3008
3033
|
function aggregateByTurn(requests) {
|
|
3009
3034
|
const out = [];
|
|
3010
3035
|
let runSteps = 0;
|
|
3036
|
+
let runActiveMs = 0;
|
|
3037
|
+
let runHasActiveMs = false;
|
|
3011
3038
|
for (const req of requests) {
|
|
3012
3039
|
const last = out.length > 0 ? out[out.length - 1] : null;
|
|
3013
3040
|
if (last !== null && (last.turn ?? 0) === (req.turn ?? 0)) {
|
|
3014
3041
|
runSteps++;
|
|
3042
|
+
if (req.activeMs !== void 0) {
|
|
3043
|
+
runActiveMs += req.activeMs;
|
|
3044
|
+
runHasActiveMs = true;
|
|
3045
|
+
}
|
|
3015
3046
|
out[out.length - 1] = {
|
|
3016
3047
|
...req,
|
|
3017
|
-
stepCount: runSteps
|
|
3048
|
+
stepCount: runSteps,
|
|
3049
|
+
...runHasActiveMs ? { activeMs: runActiveMs } : {}
|
|
3018
3050
|
};
|
|
3019
3051
|
} else {
|
|
3020
3052
|
runSteps = 1;
|
|
3053
|
+
runActiveMs = req.activeMs ?? 0;
|
|
3054
|
+
runHasActiveMs = req.activeMs !== void 0;
|
|
3021
3055
|
out.push({
|
|
3022
3056
|
...req,
|
|
3023
3057
|
stepCount: 1
|
|
@@ -3064,7 +3098,7 @@ window.__ModuleLoader__.load({
|
|
|
3064
3098
|
return requests.length > 0 ? requests[0] : null;
|
|
3065
3099
|
}
|
|
3066
3100
|
function makeTrendChart(kit) {
|
|
3067
|
-
const { t, fmt, eventLabel, eventAt, catLabel } = kit;
|
|
3101
|
+
const { t, fmt, fmtDuration, eventLabel, eventAt, catLabel } = kit;
|
|
3068
3102
|
const CHART_H = 112;
|
|
3069
3103
|
const fmtSigned = (v) => (v > 0 ? "+" : "") + fmt(v);
|
|
3070
3104
|
const BAR_W = 14;
|
|
@@ -3335,6 +3369,7 @@ window.__ModuleLoader__.load({
|
|
|
3335
3369
|
const dnaOn = dnaBands !== null;
|
|
3336
3370
|
const delta = props.mode === "delta";
|
|
3337
3371
|
const dnaDeltaOn = dnaOn && delta;
|
|
3372
|
+
const durationOn = props.durationCurve === true;
|
|
3338
3373
|
const focus = !dnaOn && props.focusCat !== null && props.focusCat !== void 0 && CATS.some((c) => c.key === props.focusCat) ? props.focusCat : null;
|
|
3339
3374
|
const [dnaHit, setDnaHit] = (0, react.useState)(null);
|
|
3340
3375
|
const dnaDeltas = (0, react.useMemo)(() => dnaDeltaOn ? dnaBands.map((bands, i) => deltaBandsOf(bands, i > 0 ? dnaBands[i - 1] : null)) : null, [dnaDeltaOn, dnaBands]);
|
|
@@ -3359,12 +3394,15 @@ window.__ModuleLoader__.load({
|
|
|
3359
3394
|
let total = 0;
|
|
3360
3395
|
let up = 0;
|
|
3361
3396
|
let down = 0;
|
|
3397
|
+
let activeMs = 0;
|
|
3362
3398
|
const from = Math.max(0, Math.floor(sl / pitch));
|
|
3363
3399
|
const to = Math.min(n - 1, Math.max(from, Math.floor((vr - 1) / pitch)));
|
|
3364
3400
|
for (let i = from; i <= to; i++) {
|
|
3365
3401
|
const col = i * pitch;
|
|
3366
3402
|
if (col >= vr || col + BAR_W <= sl) continue;
|
|
3367
3403
|
const req = requests[i];
|
|
3404
|
+
const m = req.activeMs ?? 0;
|
|
3405
|
+
if (m > activeMs) activeMs = m;
|
|
3368
3406
|
if (dnaDeltaOn && dnaDeltas !== null) {
|
|
3369
3407
|
let bu = 0;
|
|
3370
3408
|
let bd = 0;
|
|
@@ -3384,10 +3422,11 @@ window.__ModuleLoader__.load({
|
|
|
3384
3422
|
if (bd > down) down = bd;
|
|
3385
3423
|
} else if (req.total > total) total = req.total;
|
|
3386
3424
|
}
|
|
3387
|
-
setVisMax((prev) => prev !== null && prev.total === total && prev.up === up && prev.down === down ? prev : {
|
|
3425
|
+
setVisMax((prev) => prev !== null && prev.total === total && prev.up === up && prev.down === down && prev.activeMs === activeMs ? prev : {
|
|
3388
3426
|
total,
|
|
3389
3427
|
up,
|
|
3390
|
-
down
|
|
3428
|
+
down,
|
|
3429
|
+
activeMs
|
|
3391
3430
|
});
|
|
3392
3431
|
};
|
|
3393
3432
|
let maxTotal = 1;
|
|
@@ -3421,6 +3460,34 @@ window.__ModuleLoader__.load({
|
|
|
3421
3460
|
}
|
|
3422
3461
|
} else maxTotal = Math.max(1, visMax.total);
|
|
3423
3462
|
}
|
|
3463
|
+
let maxActiveMs = 0;
|
|
3464
|
+
if (durationOn) {
|
|
3465
|
+
for (const req of requests) {
|
|
3466
|
+
const m = req.activeMs ?? 0;
|
|
3467
|
+
if (m > maxActiveMs) maxActiveMs = m;
|
|
3468
|
+
}
|
|
3469
|
+
if (adaptive && visMax !== null) maxActiveMs = visMax.activeMs;
|
|
3470
|
+
}
|
|
3471
|
+
const durationRuns = [];
|
|
3472
|
+
const durationDots = [];
|
|
3473
|
+
if (durationOn) {
|
|
3474
|
+
const scale = CHART_H / Math.max(1, maxActiveMs);
|
|
3475
|
+
let run = [];
|
|
3476
|
+
const flushRun = () => {
|
|
3477
|
+
if (run.length >= 2) durationRuns.push(run.map((p) => `${p[0]},${p[1]}`).join(" "));
|
|
3478
|
+
else if (run.length === 1) durationDots.push(run[0]);
|
|
3479
|
+
run = [];
|
|
3480
|
+
};
|
|
3481
|
+
for (let i = 0; i < requests.length; i++) {
|
|
3482
|
+
const m = requests[i].activeMs;
|
|
3483
|
+
if (m === void 0) {
|
|
3484
|
+
flushRun();
|
|
3485
|
+
continue;
|
|
3486
|
+
}
|
|
3487
|
+
run.push([i * 16 + BAR_W / 2, Math.round((CHART_H - m * scale) * 100) / 100]);
|
|
3488
|
+
}
|
|
3489
|
+
flushRun();
|
|
3490
|
+
}
|
|
3424
3491
|
const span = Math.max(1, maxUp + maxDown);
|
|
3425
3492
|
const deltaScale = CHART_H / span;
|
|
3426
3493
|
const upPx = Math.round(maxUp * deltaScale);
|
|
@@ -3468,6 +3535,8 @@ window.__ModuleLoader__.load({
|
|
|
3468
3535
|
const lastGranRef = (0, react.useRef)(props.granularity);
|
|
3469
3536
|
const lastSeqRef = (0, react.useRef)(0);
|
|
3470
3537
|
const prevScrollWidthRef = (0, react.useRef)(0);
|
|
3538
|
+
const cwRef = (0, react.useRef)(0);
|
|
3539
|
+
const slRef = (0, react.useRef)(0);
|
|
3471
3540
|
/**
|
|
3472
3541
|
* Keep each turn label centered within its block's VISIBLE slice, then thin colliding labels: a label wider
|
|
3473
3542
|
* than its block overflows it, so consecutive narrow turns would smear into each other — walking left→right
|
|
@@ -3538,6 +3607,8 @@ window.__ModuleLoader__.load({
|
|
|
3538
3607
|
} else if (grew && el.scrollLeft + el.clientWidth >= widthBeforeAppend - 24) el.scrollLeft = el.scrollWidth;
|
|
3539
3608
|
lastSeqRef.current = newestSeq;
|
|
3540
3609
|
prevScrollWidthRef.current = el.scrollWidth;
|
|
3610
|
+
slRef.current = el.scrollLeft;
|
|
3611
|
+
cwRef.current = el.clientWidth;
|
|
3541
3612
|
updateTurnLabels(el);
|
|
3542
3613
|
syncTip(el);
|
|
3543
3614
|
measureVisible(el);
|
|
@@ -3559,6 +3630,7 @@ window.__ModuleLoader__.load({
|
|
|
3559
3630
|
if (el === null) return;
|
|
3560
3631
|
if (typeof ResizeObserver !== "function") return;
|
|
3561
3632
|
const observer = new ResizeObserver(() => {
|
|
3633
|
+
cwRef.current = el.clientWidth;
|
|
3562
3634
|
measureRef.current(el);
|
|
3563
3635
|
});
|
|
3564
3636
|
observer.observe(el);
|
|
@@ -3624,35 +3696,40 @@ window.__ModuleLoader__.load({
|
|
|
3624
3696
|
n: stepsOf(req.turn)
|
|
3625
3697
|
});
|
|
3626
3698
|
const band = hitBand ?? hoveredDelta;
|
|
3627
|
-
|
|
3699
|
+
let metric;
|
|
3700
|
+
if (band !== null) metric = t("trend.dnaItem", {
|
|
3628
3701
|
label: dnaBaseLabel(band, t, catLabel),
|
|
3629
3702
|
n: dnaDeltaOn ? fmtSigned(band.tokens) : fmt(band.tokens)
|
|
3630
|
-
})
|
|
3631
|
-
if (delta)
|
|
3703
|
+
});
|
|
3704
|
+
else if (delta)
|
|
3632
3705
|
/* v8 ignore next 1 -- delta mode only receives records from
|
|
3633
3706
|
deltaOf, which always assigns net; the fallback is defensive. */
|
|
3634
|
-
|
|
3635
|
-
|
|
3707
|
+
metric = t("tip.delta", { n: fmtSigned(req.net ?? 0) });
|
|
3708
|
+
else metric = focus !== null ? t("tip.cat", {
|
|
3636
3709
|
cat: catLabel(focus),
|
|
3637
3710
|
n: fmt(req.total)
|
|
3638
|
-
}) : t("tip.total", { n: fmt(req.total) })
|
|
3711
|
+
}) : t("tip.total", { n: fmt(req.total) });
|
|
3712
|
+
const rows = [head, metric];
|
|
3713
|
+
if (durationOn && req.activeMs !== void 0) rows.push(t("tip.duration", { n: fmtDuration(req.activeMs) }));
|
|
3714
|
+
return rows;
|
|
3639
3715
|
};
|
|
3640
3716
|
const tipColRef = (0, react.useRef)(0);
|
|
3641
3717
|
/**
|
|
3642
3718
|
* Glue the hover tip to its bar's VISIBLE slice. The tip deliberately does NOT live inside the scrolling
|
|
3643
3719
|
* content: an absolutely-positioned child of a scroller contributes to its scrollable overflow, so a wide
|
|
3644
3720
|
* reply preview on a right-edge bar used to inflate scrollWidth on every hover and flap the horizontal
|
|
3645
|
-
* scrollbar open/closed — jumping the whole card.
|
|
3646
|
-
*
|
|
3721
|
+
* scrollbar open/closed — jumping the whole card. The only layout read left is the tip's own width (its
|
|
3722
|
+
* subtree is the thing that just changed); the scroller's width/offset ride the cached refs, so this never
|
|
3723
|
+
* forces a document-scope layout flush on the hover path. Unchanged transforms write nothing.
|
|
3647
3724
|
*/
|
|
3648
3725
|
const syncTip = (el) => {
|
|
3649
3726
|
/* v8 ignore next 1 -- the scroll div renders unconditionally while mounted, so its parent exists. */
|
|
3650
3727
|
const tip = (el.parentElement ?? document.body).querySelector(".lc-chart-tip");
|
|
3651
3728
|
if (tip === null) return;
|
|
3652
3729
|
const lw = tip.offsetWidth;
|
|
3653
|
-
const cw =
|
|
3730
|
+
const cw = cwRef.current;
|
|
3654
3731
|
const half = Math.min(lw / 2, cw / 2);
|
|
3655
|
-
const cx = Math.min(Math.max(tipColRef.current -
|
|
3732
|
+
const cx = Math.min(Math.max(tipColRef.current - slRef.current, half), cw - half);
|
|
3656
3733
|
const next = `translate(${Math.round(cx - lw / 2)}px, 0)`;
|
|
3657
3734
|
if (tip.style.transform !== next) tip.style.transform = next;
|
|
3658
3735
|
};
|
|
@@ -3665,134 +3742,175 @@ window.__ModuleLoader__.load({
|
|
|
3665
3742
|
});
|
|
3666
3743
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3667
3744
|
className: "lc-chartrow",
|
|
3668
|
-
children: [
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
className: "lc-chart-
|
|
3718
|
-
ref: scrollRef,
|
|
3719
|
-
onScroll: (e) => {
|
|
3720
|
-
updateTurnLabels(e.currentTarget);
|
|
3721
|
-
syncTip(e.currentTarget);
|
|
3722
|
-
measureVisible(e.currentTarget);
|
|
3723
|
-
},
|
|
3745
|
+
children: [
|
|
3746
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3747
|
+
className: "lc-axis",
|
|
3748
|
+
children: delta ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
3749
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3750
|
+
className: "lc-axis-top",
|
|
3751
|
+
children: fmtSigned(maxUp)
|
|
3752
|
+
}),
|
|
3753
|
+
q3Clear ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3754
|
+
className: "lc-axis-q3",
|
|
3755
|
+
children: fmtSigned(Math.round(maxUp - span / 4))
|
|
3756
|
+
}) : null,
|
|
3757
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3758
|
+
className: "lc-axis-mid",
|
|
3759
|
+
style: { top: `${13 + upPx}px` },
|
|
3760
|
+
children: "0"
|
|
3761
|
+
}),
|
|
3762
|
+
q1Clear ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3763
|
+
className: "lc-axis-q1",
|
|
3764
|
+
children: fmtSigned(Math.round(maxUp - 3 * span / 4))
|
|
3765
|
+
}) : null,
|
|
3766
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3767
|
+
className: "lc-axis-bot",
|
|
3768
|
+
children: fmtSigned(-maxDown)
|
|
3769
|
+
})
|
|
3770
|
+
] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
3771
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3772
|
+
className: "lc-axis-top",
|
|
3773
|
+
children: fmt(maxTotal)
|
|
3774
|
+
}),
|
|
3775
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3776
|
+
className: "lc-axis-q3",
|
|
3777
|
+
children: fmt(Math.round(maxTotal * 3 / 4))
|
|
3778
|
+
}),
|
|
3779
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3780
|
+
className: "lc-axis-mid",
|
|
3781
|
+
children: fmt(Math.round(maxTotal / 2))
|
|
3782
|
+
}),
|
|
3783
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3784
|
+
className: "lc-axis-q1",
|
|
3785
|
+
children: fmt(Math.round(maxTotal / 4))
|
|
3786
|
+
}),
|
|
3787
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3788
|
+
className: "lc-axis-bot",
|
|
3789
|
+
children: "0"
|
|
3790
|
+
})
|
|
3791
|
+
] })
|
|
3792
|
+
}),
|
|
3793
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3794
|
+
className: "lc-chart-wrap",
|
|
3724
3795
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3725
|
-
className: "lc-chart",
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
!delta || q3Clear ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "lc-grid lc-grid-q3" }) : null,
|
|
3734
|
-
!delta || q1Clear ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "lc-grid lc-grid-q1" }) : null,
|
|
3735
|
-
!delta ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "lc-grid lc-grid-mid" }) : null,
|
|
3736
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3737
|
-
className: "lc-grid lc-grid-zero",
|
|
3738
|
-
style: delta ? { top: `${18 + upPx}px` } : void 0
|
|
3739
|
-
}),
|
|
3740
|
-
requests.map((req, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChartBar, {
|
|
3741
|
-
req,
|
|
3742
|
-
marker: markers[i],
|
|
3743
|
-
selected: props.selectedSeq === req.seq,
|
|
3744
|
-
hovered: props.hoveredSeq === req.seq,
|
|
3745
|
-
inTurn: props.activeTurn !== null && (req.turn ?? 0) === props.activeTurn,
|
|
3746
|
-
flag: props.granularity === "step" && (i + 1) % STEP_FLAG_EVERY === 0 ? i + 1 : null,
|
|
3747
|
-
maxTotal,
|
|
3748
|
-
upPx: delta ? upPx : void 0,
|
|
3749
|
-
downPx: delta ? downPx : void 0,
|
|
3750
|
-
deltaScale: delta ? deltaScale : void 0,
|
|
3751
|
-
enterIndex: i,
|
|
3752
|
-
dna: dnaOn ? dnaBands[i] : null,
|
|
3753
|
-
dnaDelta: dnaDeltaOn && dnaDeltas !== null ? dnaDeltas[i] : null,
|
|
3754
|
-
dnaScale: dnaDeltaOn ? deltaScale : void 0,
|
|
3755
|
-
zeroBottom: dnaDeltaOn ? downPx : void 0,
|
|
3756
|
-
onDnaHit: setDnaHit,
|
|
3757
|
-
onPickBand: props.onPickBand,
|
|
3758
|
-
onSelect: props.onSelect,
|
|
3759
|
-
onHover: props.onHover
|
|
3760
|
-
}, `${req.seq}:${props.granularity}`)),
|
|
3761
|
-
dnaOn ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DnaHighlights, { slices: dnaSlices }) : null
|
|
3762
|
-
]
|
|
3763
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3764
|
-
className: "lc-turns",
|
|
3765
|
-
style: labelFont !== "" ? { fontSize: labelFont } : void 0,
|
|
3766
|
-
onMouseLeave: () => {
|
|
3767
|
-
props.onHoverTurn(null);
|
|
3796
|
+
className: "lc-chart-scroll" + (props.activeTurn !== null ? " lc-chart-dim" : ""),
|
|
3797
|
+
ref: scrollRef,
|
|
3798
|
+
onScroll: (e) => {
|
|
3799
|
+
slRef.current = e.currentTarget.scrollLeft;
|
|
3800
|
+
cwRef.current = e.currentTarget.clientWidth;
|
|
3801
|
+
updateTurnLabels(e.currentTarget);
|
|
3802
|
+
syncTip(e.currentTarget);
|
|
3803
|
+
measureVisible(e.currentTarget);
|
|
3768
3804
|
},
|
|
3769
|
-
children:
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
},
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3805
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3806
|
+
className: "lc-chart",
|
|
3807
|
+
"data-catdim": props.hoverCat ?? void 0,
|
|
3808
|
+
onMouseLeave: () => {
|
|
3809
|
+
props.onHover(null);
|
|
3810
|
+
setDnaHit(null);
|
|
3811
|
+
},
|
|
3812
|
+
children: [
|
|
3813
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "lc-grid lc-grid-top" }),
|
|
3814
|
+
!delta || q3Clear ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "lc-grid lc-grid-q3" }) : null,
|
|
3815
|
+
!delta || q1Clear ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "lc-grid lc-grid-q1" }) : null,
|
|
3816
|
+
!delta ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: "lc-grid lc-grid-mid" }) : null,
|
|
3817
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3818
|
+
className: "lc-grid lc-grid-zero",
|
|
3819
|
+
style: delta ? { top: `${18 + upPx}px` } : void 0
|
|
3820
|
+
}),
|
|
3821
|
+
requests.map((req, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChartBar, {
|
|
3822
|
+
req,
|
|
3823
|
+
marker: markers[i],
|
|
3824
|
+
selected: props.selectedSeq === req.seq,
|
|
3825
|
+
hovered: props.hoveredSeq === req.seq,
|
|
3826
|
+
inTurn: props.activeTurn !== null && (req.turn ?? 0) === props.activeTurn,
|
|
3827
|
+
flag: props.granularity === "step" && (i + 1) % STEP_FLAG_EVERY === 0 ? i + 1 : null,
|
|
3828
|
+
maxTotal,
|
|
3829
|
+
upPx: delta ? upPx : void 0,
|
|
3830
|
+
downPx: delta ? downPx : void 0,
|
|
3831
|
+
deltaScale: delta ? deltaScale : void 0,
|
|
3832
|
+
enterIndex: i,
|
|
3833
|
+
dna: dnaOn ? dnaBands[i] : null,
|
|
3834
|
+
dnaDelta: dnaDeltaOn && dnaDeltas !== null ? dnaDeltas[i] : null,
|
|
3835
|
+
dnaScale: dnaDeltaOn ? deltaScale : void 0,
|
|
3836
|
+
zeroBottom: dnaDeltaOn ? downPx : void 0,
|
|
3837
|
+
onDnaHit: setDnaHit,
|
|
3838
|
+
onPickBand: props.onPickBand,
|
|
3839
|
+
onSelect: props.onSelect,
|
|
3840
|
+
onHover: props.onHover
|
|
3841
|
+
}, `${req.seq}:${props.granularity}`)),
|
|
3842
|
+
dnaOn ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DnaHighlights, { slices: dnaSlices }) : null,
|
|
3843
|
+
durationOn && (durationRuns.length > 0 || durationDots.length > 0) ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
3844
|
+
className: "lc-duration",
|
|
3845
|
+
width: requests.length * 16 - BAR_GAP,
|
|
3846
|
+
height: CHART_H,
|
|
3847
|
+
"aria-hidden": "true",
|
|
3848
|
+
children: [durationRuns.map((pts, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("polyline", { points: pts }, i)), durationDots.map((p, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
3849
|
+
cx: p[0],
|
|
3850
|
+
cy: p[1],
|
|
3851
|
+
r: 1.5
|
|
3852
|
+
}, i))]
|
|
3853
|
+
}) : null
|
|
3854
|
+
]
|
|
3855
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3856
|
+
className: "lc-turns",
|
|
3857
|
+
style: labelFont !== "" ? { fontSize: labelFont } : void 0,
|
|
3858
|
+
onMouseLeave: () => {
|
|
3859
|
+
props.onHoverTurn(null);
|
|
3860
|
+
},
|
|
3861
|
+
children: groups.map((grp, gi) => {
|
|
3862
|
+
const on = props.activeTurn === grp.turn;
|
|
3863
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3864
|
+
className: "lc-turn" + (on ? " lc-turn-on" : ""),
|
|
3865
|
+
style: {
|
|
3866
|
+
width: `${turnWidths[gi]}px`,
|
|
3867
|
+
background: TURN_FILLS[gi % TURN_FILLS.length]
|
|
3868
|
+
},
|
|
3869
|
+
title: `T${grp.turn}`,
|
|
3870
|
+
onMouseEnter: () => {
|
|
3871
|
+
props.onHoverTurn(grp.turn);
|
|
3872
|
+
},
|
|
3873
|
+
onClick: () => {
|
|
3874
|
+
props.onPickTurn(grp.turn);
|
|
3875
|
+
},
|
|
3876
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3877
|
+
className: "lc-turn-label",
|
|
3878
|
+
children: `${grp.turn}`
|
|
3879
|
+
})
|
|
3880
|
+
}, `turn-${gi}`);
|
|
3881
|
+
})
|
|
3882
|
+
})]
|
|
3883
|
+
}), hoveredReq !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3884
|
+
className: "lc-chart-tip",
|
|
3885
|
+
children: tipRowsOf(hoveredReq).map((row, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: row }, i))
|
|
3886
|
+
}) : null]
|
|
3887
|
+
}),
|
|
3888
|
+
durationOn ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3889
|
+
className: "lc-axis lc-axis-r",
|
|
3890
|
+
children: [
|
|
3891
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3892
|
+
className: "lc-axis-top",
|
|
3893
|
+
children: fmtDuration(maxActiveMs)
|
|
3894
|
+
}),
|
|
3895
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3896
|
+
className: "lc-axis-q3",
|
|
3897
|
+
children: fmtDuration(Math.round(maxActiveMs * 3 / 4))
|
|
3898
|
+
}),
|
|
3899
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3900
|
+
className: "lc-axis-mid",
|
|
3901
|
+
children: fmtDuration(Math.round(maxActiveMs / 2))
|
|
3902
|
+
}),
|
|
3903
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3904
|
+
className: "lc-axis-q1",
|
|
3905
|
+
children: fmtDuration(Math.round(maxActiveMs / 4))
|
|
3906
|
+
}),
|
|
3907
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3908
|
+
className: "lc-axis-bot",
|
|
3909
|
+
children: "0"
|
|
3789
3910
|
})
|
|
3790
|
-
|
|
3791
|
-
})
|
|
3792
|
-
|
|
3793
|
-
children: tipRowsOf(hoveredReq).map((row, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: row }, i))
|
|
3794
|
-
}) : null]
|
|
3795
|
-
})]
|
|
3911
|
+
]
|
|
3912
|
+
}) : null
|
|
3913
|
+
]
|
|
3796
3914
|
});
|
|
3797
3915
|
};
|
|
3798
3916
|
}
|
|
@@ -3937,10 +4055,17 @@ window.__ModuleLoader__.load({
|
|
|
3937
4055
|
const scaled = Math.trunc(reads / billed * 100 * factor + 1e-9);
|
|
3938
4056
|
return `${Math.floor(scaled / factor)}.${String(scaled % factor).padStart(decimals, "0")}`;
|
|
3939
4057
|
}
|
|
4058
|
+
/** One shared formatter: building an Intl formatter per call costs ~50x the format itself (issue #116). */
|
|
4059
|
+
const TIME_FMT = new Intl.DateTimeFormat("en-GB", {
|
|
4060
|
+
hour12: false,
|
|
4061
|
+
hour: "2-digit",
|
|
4062
|
+
minute: "2-digit",
|
|
4063
|
+
second: "2-digit"
|
|
4064
|
+
});
|
|
3940
4065
|
function fmtTime(t) {
|
|
3941
4066
|
const d = new Date(t);
|
|
3942
4067
|
if (isNaN(d.getTime())) return "—";
|
|
3943
|
-
return
|
|
4068
|
+
return TIME_FMT.format(d);
|
|
3944
4069
|
}
|
|
3945
4070
|
/**
|
|
3946
4071
|
* Share of a whole as a compact leading percentage for the slice rows:
|
|
@@ -5930,71 +6055,6 @@ window.__ModuleLoader__.load({
|
|
|
5930
6055
|
};
|
|
5931
6056
|
}
|
|
5932
6057
|
//#endregion
|
|
5933
|
-
//#region src/client/overviewStore.ts
|
|
5934
|
-
function createStore() {
|
|
5935
|
-
let open = false;
|
|
5936
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
5937
|
-
return {
|
|
5938
|
-
subscribe: (listener) => {
|
|
5939
|
-
listeners.add(listener);
|
|
5940
|
-
return () => {
|
|
5941
|
-
listeners.delete(listener);
|
|
5942
|
-
};
|
|
5943
|
-
},
|
|
5944
|
-
getSnapshot: () => open,
|
|
5945
|
-
set: (next) => {
|
|
5946
|
-
if (next === open) return;
|
|
5947
|
-
open = next;
|
|
5948
|
-
for (const listener of listeners) listener();
|
|
5949
|
-
}
|
|
5950
|
-
};
|
|
5951
|
-
}
|
|
5952
|
-
const overviewStore = createStore();
|
|
5953
|
-
//#endregion
|
|
5954
|
-
//#region src/client/components/overviewButton.tsx
|
|
5955
|
-
/**
|
|
5956
|
-
* The Context Dashboard's sidebar entry: a footer action stacked directly
|
|
5957
|
-
* above Settings (the harness's own foot layout: footer actions, then the
|
|
5958
|
-
* settings row), mirroring the Settings trigger's geometry in both column
|
|
5959
|
-
* widths. The button carries the plugin emblem — in the mono seat, so the
|
|
5960
|
-
* glyph matches the harness's own footer rows rather than shouting over
|
|
5961
|
-
* them — and, on the wide column, its label. Clicking opens the overview
|
|
5962
|
-
* overlay through the shared module store (overviewStore.ts).
|
|
5963
|
-
*
|
|
5964
|
-
* The per-user `insightsEntry` preference takes the entry down (renders
|
|
5965
|
-
* null) without unregistering the seat. The subscription fails open: an
|
|
5966
|
-
* absent settings store, an unserved namespace, or a value the plugin
|
|
5967
|
-
* cannot understand all leave the entry visible.
|
|
5968
|
-
*/
|
|
5969
|
-
/** Stable subscription faces for the settings-less degrade (no re-subscribes). */
|
|
5970
|
-
const subscribeNever = () => () => {};
|
|
5971
|
-
const entryShown = () => "show";
|
|
5972
|
-
function makeOverviewButton(kit, settings) {
|
|
5973
|
-
const { t } = kit;
|
|
5974
|
-
const subscribeEntry = settings === void 0 ? subscribeNever : (listener) => settings.store.subscribe(listener);
|
|
5975
|
-
const getEntry = settings === void 0 ? entryShown : () => settings.insightsEntry();
|
|
5976
|
-
return function OverviewButton(props) {
|
|
5977
|
-
if ((0, react.useSyncExternalStore)(subscribeEntry, getEntry) === "hide") return null;
|
|
5978
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
5979
|
-
type: "button",
|
|
5980
|
-
className: props.wide === true ? "lc-ov-entry" : "lc-ov-entry lc-ov-entry-rail",
|
|
5981
|
-
title: t("ov.entry"),
|
|
5982
|
-
"aria-label": t("ov.entry"),
|
|
5983
|
-
onClick: () => {
|
|
5984
|
-
overviewStore.set(true);
|
|
5985
|
-
},
|
|
5986
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ContextIcon, {
|
|
5987
|
-
size: props.wide === true ? 16 : 18,
|
|
5988
|
-
className: "lc-ov-entry-icon",
|
|
5989
|
-
mono: true
|
|
5990
|
-
}), props.wide === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5991
|
-
className: "lc-ov-entry-label",
|
|
5992
|
-
children: t("ov.entry")
|
|
5993
|
-
})]
|
|
5994
|
-
});
|
|
5995
|
-
};
|
|
5996
|
-
}
|
|
5997
|
-
//#endregion
|
|
5998
6058
|
//#region src/shared/providers.ts
|
|
5999
6059
|
/**
|
|
6000
6060
|
* The provider-id seam between dsh request envelopes and the models.dev
|
|
@@ -7340,14 +7400,15 @@ window.__ModuleLoader__.load({
|
|
|
7340
7400
|
//#region src/client/components/balanceCapsule.tsx
|
|
7341
7401
|
/**
|
|
7342
7402
|
* BalanceCapsule — the DeepSeek open-platform balance pill in the Context
|
|
7343
|
-
*
|
|
7403
|
+
* Insights page's heading (the plugin's one account-level figure, beside the
|
|
7344
7404
|
* session-level ones). Clicking it opens the platform's usage console in a
|
|
7345
|
-
* new tab. Mounted only by the
|
|
7405
|
+
* new tab. Mounted only by the page heading; it paints the figure the
|
|
7346
7406
|
* previous open remembered while client/balance.ts revalidates it in the
|
|
7347
7407
|
* background, and renders NOTHING when nothing is remembered and the route
|
|
7348
7408
|
* answers nothing — the pill exists only when there is a figure to show. The
|
|
7349
|
-
* non-zero parts of the breakdown (topped-up / granted) ride the
|
|
7350
|
-
*
|
|
7409
|
+
* non-zero parts of the breakdown (topped-up / granted) ride the page's
|
|
7410
|
+
* portaled hover tip (hoverTip.tsx, off the pill's `data-lc-tip`) —
|
|
7411
|
+
* immediate on hover, where a native `title` lags — in
|
|
7351
7412
|
* the entry's own currency (the pill itself carries the total); the entry
|
|
7352
7413
|
* follows the active locale (zh → CNY) with the account's first currency as
|
|
7353
7414
|
* the fallback.
|
|
@@ -7371,9 +7432,13 @@ window.__ModuleLoader__.load({
|
|
|
7371
7432
|
if (entry === null) return null;
|
|
7372
7433
|
const money = (amount) => symbolOf(entry.currency) + amount.toFixed(2);
|
|
7373
7434
|
const tipLines = [...entry.toppedUp > 0 ? [t("balance.tip.toppedUp") + ": " + money(entry.toppedUp)] : [], ...entry.granted > 0 ? [t("balance.tip.granted") + ": " + money(entry.granted)] : []];
|
|
7374
|
-
|
|
7435
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("a", {
|
|
7375
7436
|
className: "lc-ov-balance",
|
|
7376
7437
|
"aria-label": tipLines.length > 0 ? tipLines.join("\n") : void 0,
|
|
7438
|
+
...tipLines.length > 0 ? {
|
|
7439
|
+
"data-lc-tip": tipLines.join("\n"),
|
|
7440
|
+
"data-lc-tip-side": "bottom"
|
|
7441
|
+
} : {},
|
|
7377
7442
|
href: USAGE_URL,
|
|
7378
7443
|
target: "_blank",
|
|
7379
7444
|
rel: "noreferrer",
|
|
@@ -7385,11 +7450,6 @@ window.__ModuleLoader__.load({
|
|
|
7385
7450
|
children: money(entry.total)
|
|
7386
7451
|
})]
|
|
7387
7452
|
});
|
|
7388
|
-
return tipLines.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
|
|
7389
|
-
label: tipLines.join("\n"),
|
|
7390
|
-
side: "bottom",
|
|
7391
|
-
children: pill
|
|
7392
|
-
}) : pill;
|
|
7393
7453
|
};
|
|
7394
7454
|
}
|
|
7395
7455
|
//#endregion
|
|
@@ -7450,24 +7510,6 @@ window.__ModuleLoader__.load({
|
|
|
7450
7510
|
//#endregion
|
|
7451
7511
|
//#region src/client/components/heatmap.tsx
|
|
7452
7512
|
/**
|
|
7453
|
-
* The Context Dashboard's activity heatmap: a GitHub-style contribution grid
|
|
7454
|
-
* (weeks as columns, Sunday-first weekdays as rows, a month label over each
|
|
7455
|
-
* column where a month begins — the window's opening column always labeled —
|
|
7456
|
-
* and a Less→More key for the depth steps) over the merged daily
|
|
7457
|
-
* ledger (overview.ts). Cell depth is the selected metric's share of the
|
|
7458
|
-
* window's maximum — distinct active sessions or settlement steps; a session
|
|
7459
|
-
* can spread its steps thinly across many days while another day stacks a
|
|
7460
|
-
* run, so each metric scales on its OWN maximum — in four steps; a day with
|
|
7461
|
-
* data is a button whose click
|
|
7462
|
-
* pins the session list to that day (click again to release). Cells tip
|
|
7463
|
-
* through the harness's own Tooltip primitive (instant on hover; native
|
|
7464
|
-
* `title` lags a second behind), the bubble carrying the date, the day's
|
|
7465
|
-
* active sessions, and its steps. The grid is computed from the injected
|
|
7466
|
-
* `today` key, so
|
|
7467
|
-
* the layout is deterministic in tests and follows the browser's local
|
|
7468
|
-
* calendar at runtime.
|
|
7469
|
-
*/
|
|
7470
|
-
/**
|
|
7471
7513
|
* Lay out the grid: `weeks` columns ending at today's week, each seven
|
|
7472
7514
|
* Sunday-first cells (row 0 = Sunday). Returns null when `today` (or its
|
|
7473
7515
|
* week math) fails — a corrupt injected key degrades the card to its empty
|
|
@@ -7578,25 +7620,21 @@ window.__ModuleLoader__.load({
|
|
|
7578
7620
|
"aria-hidden": "true"
|
|
7579
7621
|
}, cell.key);
|
|
7580
7622
|
const level = cell.entry === void 0 ? 0 : levelOf(metricValueOf(cell.entry), max);
|
|
7581
|
-
if (cell.entry === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
7582
|
-
|
|
7583
|
-
|
|
7584
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "lc-heat-cell lc-heat-0" })
|
|
7623
|
+
if (cell.entry === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
7624
|
+
className: "lc-heat-cell lc-heat-0",
|
|
7625
|
+
"data-lc-tip": cell.key
|
|
7585
7626
|
}, cell.key);
|
|
7586
7627
|
const picked = props.selected === cell.key;
|
|
7587
7628
|
const label = `${cell.key}\n${t("ov.heat.sessions", { n: cell.entry.sessions })}\n${t("ov.heat.steps", { n: cell.entry.requests })}`;
|
|
7588
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
if (props.onSelect !== void 0) props.onSelect(picked ? null : cell.key);
|
|
7598
|
-
}
|
|
7599
|
-
})
|
|
7629
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
7630
|
+
type: "button",
|
|
7631
|
+
className: `lc-heat-cell lc-heat-${String(level)}${picked ? " lc-heat-on" : ""}`,
|
|
7632
|
+
"data-lc-tip": label,
|
|
7633
|
+
"aria-label": label,
|
|
7634
|
+
"aria-pressed": picked,
|
|
7635
|
+
onClick: () => {
|
|
7636
|
+
if (props.onSelect !== void 0) props.onSelect(picked ? null : cell.key);
|
|
7637
|
+
}
|
|
7600
7638
|
}, cell.key);
|
|
7601
7639
|
})]
|
|
7602
7640
|
}, wi);
|
|
@@ -7724,6 +7762,156 @@ window.__ModuleLoader__.load({
|
|
|
7724
7762
|
};
|
|
7725
7763
|
}
|
|
7726
7764
|
//#endregion
|
|
7765
|
+
//#region src/client/components/hoverTip.tsx
|
|
7766
|
+
/**
|
|
7767
|
+
* The dashboard's hover tips — one fixed bubble, portaled to <body>, driven
|
|
7768
|
+
* by event delegation off the page root.
|
|
7769
|
+
*
|
|
7770
|
+
* Why not the harness Tooltip: the Insights page is the `lc-ov` query
|
|
7771
|
+
* container, and inline-size containment makes the page the containing block
|
|
7772
|
+
* for FIXED descendants — an in-tree fixed bubble (the harness Tooltip's
|
|
7773
|
+
* unportaled spelling) would paint sidebar-width away from its anchor, while
|
|
7774
|
+
* the primitive's `portal` prop exists only on 0.1.7+. The plugin already
|
|
7775
|
+
* portals its own fixed overlays for exactly this trap (the image lightbox,
|
|
7776
|
+
* base.css), so the page's tips follow that precedent and stay correct on
|
|
7777
|
+
* every supported line.
|
|
7778
|
+
*
|
|
7779
|
+
* Anchors carry `data-lc-tip` (the label) and optional `data-lc-tip-side`
|
|
7780
|
+
* ('top' default, 'bottom'); the zone delegates `mouseover`/`mouseout` and
|
|
7781
|
+
* focus/blur capture, so anchors stay plain elements — no per-cell wrapper
|
|
7782
|
+
* components. One bubble at a time: it re-anchors on anchor switch, hides on
|
|
7783
|
+
* anchor leave, on any zone scroll, on a viewport resize (every anchor just
|
|
7784
|
+
* moved), and on unmount; while shown it sets the anchor's
|
|
7785
|
+
* `aria-describedby`.
|
|
7786
|
+
*
|
|
7787
|
+
* @module dsh-context/client/components/hoverTip
|
|
7788
|
+
*/
|
|
7789
|
+
/** The bubble's identity for the anchor's `aria-describedby` (one live bubble at a time). */
|
|
7790
|
+
const TIP_ID = "lc-hovertip-bubble";
|
|
7791
|
+
/** Anchor-to-bubble distance and the viewport margin the bubble clamps inside, in px. */
|
|
7792
|
+
const GAP = 6;
|
|
7793
|
+
const VIEWPORT_MARGIN = 8;
|
|
7794
|
+
/** The nearest tip anchor of an event target, if any. */
|
|
7795
|
+
function anchorOf(target) {
|
|
7796
|
+
return target instanceof Element ? target.closest("[data-lc-tip]") : null;
|
|
7797
|
+
}
|
|
7798
|
+
function tipOf(anchor) {
|
|
7799
|
+
const label = anchor.getAttribute("data-lc-tip");
|
|
7800
|
+
if (label === null || label === "") return null;
|
|
7801
|
+
const r = anchor.getBoundingClientRect();
|
|
7802
|
+
return {
|
|
7803
|
+
anchor,
|
|
7804
|
+
label,
|
|
7805
|
+
side: anchor.getAttribute("data-lc-tip-side") === "bottom" ? "bottom" : "top",
|
|
7806
|
+
rect: {
|
|
7807
|
+
left: r.left,
|
|
7808
|
+
top: r.top,
|
|
7809
|
+
width: r.width,
|
|
7810
|
+
height: r.height,
|
|
7811
|
+
bottom: r.bottom
|
|
7812
|
+
}
|
|
7813
|
+
};
|
|
7814
|
+
}
|
|
7815
|
+
/**
|
|
7816
|
+
* The zone hook: stable delegated handlers plus the portaled bubble. The
|
|
7817
|
+
* bubble renders hidden until the layout effect measures it, so it never
|
|
7818
|
+
* flashes at an unmeasured spot.
|
|
7819
|
+
*/
|
|
7820
|
+
function useHoverTip() {
|
|
7821
|
+
const [tip, setTip] = (0, react.useState)(null);
|
|
7822
|
+
const [measured, setMeasured] = (0, react.useState)(null);
|
|
7823
|
+
const bubbleRef = (0, react.useRef)(null);
|
|
7824
|
+
const show = (0, react.useCallback)((anchor) => {
|
|
7825
|
+
setTip((current) => {
|
|
7826
|
+
if (current?.anchor === anchor) return current;
|
|
7827
|
+
current?.anchor.removeAttribute("aria-describedby");
|
|
7828
|
+
const next = tipOf(anchor);
|
|
7829
|
+
if (next === null) return null;
|
|
7830
|
+
anchor.setAttribute("aria-describedby", TIP_ID);
|
|
7831
|
+
return next;
|
|
7832
|
+
});
|
|
7833
|
+
}, []);
|
|
7834
|
+
const hide = (0, react.useCallback)(() => {
|
|
7835
|
+
setTip((current) => {
|
|
7836
|
+
current?.anchor.removeAttribute("aria-describedby");
|
|
7837
|
+
return null;
|
|
7838
|
+
});
|
|
7839
|
+
}, []);
|
|
7840
|
+
const onMouseOver = (0, react.useCallback)((ev) => {
|
|
7841
|
+
const anchor = anchorOf(ev.target);
|
|
7842
|
+
if (anchor !== null) show(anchor);
|
|
7843
|
+
}, [show]);
|
|
7844
|
+
const onMouseOut = (0, react.useCallback)((ev) => {
|
|
7845
|
+
if (anchorOf(ev.target) !== null && anchorOf(ev.relatedTarget) === null) hide();
|
|
7846
|
+
}, [hide]);
|
|
7847
|
+
const onFocusCapture = (0, react.useCallback)((ev) => {
|
|
7848
|
+
const anchor = anchorOf(ev.target);
|
|
7849
|
+
if (anchor !== null) show(anchor);
|
|
7850
|
+
}, [show]);
|
|
7851
|
+
const onBlurCapture = (0, react.useCallback)((ev) => {
|
|
7852
|
+
if (anchorOf(ev.target) !== null && anchorOf(ev.relatedTarget) === null) hide();
|
|
7853
|
+
}, [hide]);
|
|
7854
|
+
const onScrollCapture = (0, react.useCallback)(() => {
|
|
7855
|
+
hide();
|
|
7856
|
+
}, [hide]);
|
|
7857
|
+
(0, react.useEffect)(() => {
|
|
7858
|
+
if (tip === null) return void 0;
|
|
7859
|
+
const retract = () => {
|
|
7860
|
+
hide();
|
|
7861
|
+
};
|
|
7862
|
+
window.addEventListener("resize", retract);
|
|
7863
|
+
return () => {
|
|
7864
|
+
window.removeEventListener("resize", retract);
|
|
7865
|
+
};
|
|
7866
|
+
}, [tip, hide]);
|
|
7867
|
+
(0, react.useLayoutEffect)(() => {
|
|
7868
|
+
if (tip === null || measured?.tip === tip) return;
|
|
7869
|
+
const el = bubbleRef.current;
|
|
7870
|
+
/* v8 ignore next -- the portal commits its ref before layout effects run,
|
|
7871
|
+
* so a null ref here is unreachable; kept as a guard so a future portal
|
|
7872
|
+
* change cannot crash the page. */
|
|
7873
|
+
if (el === null) return;
|
|
7874
|
+
const w = el.offsetWidth;
|
|
7875
|
+
const h = el.offsetHeight;
|
|
7876
|
+
const { rect } = tip;
|
|
7877
|
+
const left = Math.max(VIEWPORT_MARGIN, Math.min(rect.left + rect.width / 2 - w / 2, window.innerWidth - w - VIEWPORT_MARGIN));
|
|
7878
|
+
let top = tip.side === "top" ? rect.top - h - GAP : rect.bottom + GAP;
|
|
7879
|
+
if (tip.side === "top" && top < VIEWPORT_MARGIN) top = rect.bottom + GAP;
|
|
7880
|
+
else if (tip.side === "bottom" && top + h > window.innerHeight - VIEWPORT_MARGIN) top = rect.top - h - GAP;
|
|
7881
|
+
setMeasured({
|
|
7882
|
+
tip,
|
|
7883
|
+
left,
|
|
7884
|
+
top: Math.max(VIEWPORT_MARGIN, top)
|
|
7885
|
+
});
|
|
7886
|
+
}, [tip, measured]);
|
|
7887
|
+
const shown = measured !== null && measured.tip === tip ? measured : null;
|
|
7888
|
+
return {
|
|
7889
|
+
zoneProps: {
|
|
7890
|
+
onMouseOver,
|
|
7891
|
+
onMouseOut,
|
|
7892
|
+
onFocusCapture,
|
|
7893
|
+
onBlurCapture,
|
|
7894
|
+
onScrollCapture
|
|
7895
|
+
},
|
|
7896
|
+
bubble: tip === null ? null : (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
7897
|
+
ref: bubbleRef,
|
|
7898
|
+
id: TIP_ID,
|
|
7899
|
+
role: "tooltip",
|
|
7900
|
+
className: "lc-tip lc-hovertip",
|
|
7901
|
+
style: shown === null ? {
|
|
7902
|
+
left: 0,
|
|
7903
|
+
top: 0,
|
|
7904
|
+
visibility: "hidden"
|
|
7905
|
+
} : {
|
|
7906
|
+
left: shown.left,
|
|
7907
|
+
top: shown.top,
|
|
7908
|
+
opacity: 1
|
|
7909
|
+
},
|
|
7910
|
+
children: tip.label
|
|
7911
|
+
}), document.body)
|
|
7912
|
+
};
|
|
7913
|
+
}
|
|
7914
|
+
//#endregion
|
|
7727
7915
|
//#region src/client/components/sliceList.tsx
|
|
7728
7916
|
/**
|
|
7729
7917
|
* The stats cards' slice rows: the donut's legend with numbers, two tiers
|
|
@@ -7834,26 +8022,6 @@ window.__ModuleLoader__.load({
|
|
|
7834
8022
|
}
|
|
7835
8023
|
//#endregion
|
|
7836
8024
|
//#region src/client/components/overviewUsage.tsx
|
|
7837
|
-
/**
|
|
7838
|
-
* The Context Insights panel's first-row usage chart — the RIGHT half of the
|
|
7839
|
-
* KPI row. Seven day columns ending today, each pairing two bars priced off
|
|
7840
|
-
* the merged daily ledger (overview.ts aggregateDays): billed TOKENS (the
|
|
7841
|
-
* heatmap's own blue) and the day's estimated COST (green). The fee rides
|
|
7842
|
-
* the same per-day pricing records the host fold books at each turn's
|
|
7843
|
-
* initiation, priced by the same book and estimator as the KPI band's cost
|
|
7844
|
-
* cell — never a whole session's spend dumped on the day it was last
|
|
7845
|
-
* active. The two series scale on their OWN window maxima (a $2 week must
|
|
7846
|
-
* not flatten under a 169M-token week), so each bar reads as a share of its
|
|
7847
|
-
* series' peak; the tooltip carries the exact figures. The window is fixed
|
|
7848
|
-
* to the last 7 days — the range selector above scopes the KPI figures, not
|
|
7849
|
-
* this calendar.
|
|
7850
|
-
*
|
|
7851
|
-
* The plot is framed like a chart: hairline gridlines at 0/25/50/75/100% of
|
|
7852
|
-
* each series' own peak, a solid baseline at 0, and a tick rail on each
|
|
7853
|
-
* side — TOKENS on the left, COST on the right, computed from the same
|
|
7854
|
-
* maxima the bars scale to. The cost rail reads '—' until some day actually
|
|
7855
|
-
* prices.
|
|
7856
|
-
*/
|
|
7857
8025
|
/** The chart's window: today and the six days before it, oldest first. */
|
|
7858
8026
|
function usageWindowOf(today) {
|
|
7859
8027
|
const columns = [];
|
|
@@ -7934,21 +8102,18 @@ window.__ModuleLoader__.load({
|
|
|
7934
8102
|
const tokens = c.entry?.tokens ?? 0;
|
|
7935
8103
|
const cost = c.entry?.cost ?? null;
|
|
7936
8104
|
const label = `${c.key}\n${t("ov.usage.tokens")} ${fmt(tokens)}\n${t("ov.usage.costTip")} ${cost === null ? "—" : formatCost(cost, props.currency)}`;
|
|
7937
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
7938
|
-
|
|
7939
|
-
|
|
7940
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.
|
|
7941
|
-
className: "lc-ov-usage-
|
|
7942
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.
|
|
7943
|
-
className: "lc-ov-usage-
|
|
7944
|
-
|
|
7945
|
-
|
|
7946
|
-
|
|
7947
|
-
|
|
7948
|
-
|
|
7949
|
-
style: { height: cost === null ? "0%" : heightOf(cost, maxCost) }
|
|
7950
|
-
})]
|
|
7951
|
-
})
|
|
8105
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8106
|
+
className: "lc-ov-usage-col",
|
|
8107
|
+
"data-lc-tip": label,
|
|
8108
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8109
|
+
className: "lc-ov-usage-bars",
|
|
8110
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8111
|
+
className: "lc-ov-usage-bar lc-ov-usage-tokens",
|
|
8112
|
+
style: { height: heightOf(tokens, maxTokens) }
|
|
8113
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
8114
|
+
className: "lc-ov-usage-bar lc-ov-usage-cost",
|
|
8115
|
+
style: { height: cost === null ? "0%" : heightOf(cost, maxCost) }
|
|
8116
|
+
})]
|
|
7952
8117
|
})
|
|
7953
8118
|
}, c.key);
|
|
7954
8119
|
})
|
|
@@ -8440,27 +8605,37 @@ window.__ModuleLoader__.load({
|
|
|
8440
8605
|
//#endregion
|
|
8441
8606
|
//#region src/client/components/overviewPanel.tsx
|
|
8442
8607
|
/**
|
|
8443
|
-
* The Context
|
|
8444
|
-
*
|
|
8445
|
-
*
|
|
8446
|
-
*
|
|
8447
|
-
*
|
|
8448
|
-
*
|
|
8608
|
+
* The Context Insights page — the plugin's first-level panel, opened from
|
|
8609
|
+
* the sidebar's panel list (insightPage.ts), a sibling of the shipped
|
|
8610
|
+
* Plugins and Automation tasks pages. Registered on the layout's keyed
|
|
8611
|
+
* `main` slot, so the shell's center column mounts it when the panel is
|
|
8612
|
+
* selected and unmounts it on leave — the page's mount IS its open, and its
|
|
8613
|
+
* data rides the root-scope `useSessions`/`useWorkspaces` standard kit
|
|
8614
|
+
* (every list row's host-cached projection values), so the page draws every
|
|
8615
|
+
* session's insight without opening one log.
|
|
8616
|
+
*
|
|
8617
|
+
* The chrome mirrors the shipped first-level pages: one scroll region whose
|
|
8618
|
+
* centered content column (the Plugins page's 960px frame) opens with the
|
|
8619
|
+
* page heading — the title beside the range group (and the DeepSeek balance
|
|
8620
|
+
* capsule when it serves) — and the page element is the `lc-ov` query
|
|
8621
|
+
* container, so every fold keys off the pane's own width. Hover tips portal
|
|
8622
|
+
* to <body> (hoverTip.tsx) because the container would otherwise capture
|
|
8623
|
+
* their fixed positioning.
|
|
8449
8624
|
*
|
|
8450
|
-
* The
|
|
8625
|
+
* The body's first row is a 1:1 column pair: the KPI metrics band (the
|
|
8451
8626
|
* range's six figures — sessions, billed tokens, cost, cache hit, tool
|
|
8452
8627
|
* calls, active time — three per row) beside the last-7-days usage chart
|
|
8453
|
-
* (each day's billed tokens and estimated cost as a bar pair, folded off
|
|
8454
|
-
*
|
|
8455
|
-
*
|
|
8456
|
-
*
|
|
8457
|
-
*
|
|
8458
|
-
*
|
|
8459
|
-
*
|
|
8460
|
-
*
|
|
8461
|
-
*
|
|
8462
|
-
*
|
|
8463
|
-
*
|
|
8628
|
+
* (each day's billed tokens and estimated cost as a bar pair, folded off the
|
|
8629
|
+
* merged daily ledger). Below it, the aggregate stats row folds the same
|
|
8630
|
+
* range's sessions into the two donut cards the per-session Context tab
|
|
8631
|
+
* opens with — Token Stats (the composition-split billed volume) and Timing
|
|
8632
|
+
* Stats (the summed totals). The body is then a 3:7 column pair: the
|
|
8633
|
+
* insight column (the activity heatmap, then the preferences entry row)
|
|
8634
|
+
* beside the session column (search, group chips, and the card grid); the
|
|
8635
|
+
* heatmap keeps its own fixed 8-week window and PINs the list to a picked
|
|
8636
|
+
* day (the page's drill-down gesture). A session card click jumps to that
|
|
8637
|
+
* session through the harness's own selection verb (openSessionVia), whose
|
|
8638
|
+
* navigation returns the center column to the conversation.
|
|
8464
8639
|
*/
|
|
8465
8640
|
const RANGES = [
|
|
8466
8641
|
"24h",
|
|
@@ -8491,7 +8666,6 @@ window.__ModuleLoader__.load({
|
|
|
8491
8666
|
return (typeof locale.getLocale === "function" ? locale.getLocale().active : "en") === "zh" ? "cny" : "usd";
|
|
8492
8667
|
}
|
|
8493
8668
|
function OverviewBody(props) {
|
|
8494
|
-
const open = (0, react.useSyncExternalStore)(overviewStore.subscribe, overviewStore.getSnapshot);
|
|
8495
8669
|
const { book } = useModelPrices();
|
|
8496
8670
|
const snapshot = sessionsSnapshotOf(props);
|
|
8497
8671
|
const wsSnapshot = workspacesSnapshotOf(props);
|
|
@@ -8502,18 +8676,13 @@ window.__ModuleLoader__.load({
|
|
|
8502
8676
|
const [sort, setSort] = (0, react.useState)("recent");
|
|
8503
8677
|
const [metric, setMetric] = (0, react.useState)("steps");
|
|
8504
8678
|
const [page, setPage] = (0, react.useState)(0);
|
|
8505
|
-
const
|
|
8506
|
-
overviewStore.set(false);
|
|
8507
|
-
};
|
|
8508
|
-
useEscapeClose(open, close);
|
|
8679
|
+
const { zoneProps, bubble } = useHoverTip();
|
|
8509
8680
|
const rows = (0, react.useMemo)(() => rowsOfSnapshot(snapshot, wsSnapshot), [snapshot, wsSnapshot]);
|
|
8510
8681
|
const groups = (0, react.useMemo)(() => sessionGroupsOf(wsSnapshot), [wsSnapshot]);
|
|
8511
8682
|
(0, react.useEffect)(() => {
|
|
8512
|
-
|
|
8513
|
-
|
|
8514
|
-
|
|
8515
|
-
}
|
|
8516
|
-
}, [open]);
|
|
8683
|
+
requestActivityBackfill();
|
|
8684
|
+
refreshSessions(ctx);
|
|
8685
|
+
}, []);
|
|
8517
8686
|
(0, react.useEffect)(() => {
|
|
8518
8687
|
setPage(0);
|
|
8519
8688
|
}, [
|
|
@@ -8523,7 +8692,6 @@ window.__ModuleLoader__.load({
|
|
|
8523
8692
|
group,
|
|
8524
8693
|
sort
|
|
8525
8694
|
]);
|
|
8526
|
-
if (!open) return null;
|
|
8527
8695
|
const currency = activeCurrency();
|
|
8528
8696
|
const now = Date.now();
|
|
8529
8697
|
const allRows = rows ?? [];
|
|
@@ -8548,55 +8716,41 @@ window.__ModuleLoader__.load({
|
|
|
8548
8716
|
const days = aggregateDays(allRows, book, currency);
|
|
8549
8717
|
const openOne = (id) => {
|
|
8550
8718
|
openSessionVia(ctx, id);
|
|
8551
|
-
overviewStore.set(false);
|
|
8552
8719
|
};
|
|
8553
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
8554
|
-
className: "lc-ov-
|
|
8555
|
-
|
|
8556
|
-
|
|
8557
|
-
|
|
8558
|
-
|
|
8559
|
-
|
|
8560
|
-
|
|
8561
|
-
|
|
8562
|
-
|
|
8563
|
-
|
|
8564
|
-
|
|
8565
|
-
|
|
8566
|
-
|
|
8567
|
-
|
|
8568
|
-
|
|
8569
|
-
|
|
8570
|
-
|
|
8571
|
-
|
|
8572
|
-
|
|
8573
|
-
|
|
8574
|
-
|
|
8575
|
-
|
|
8576
|
-
|
|
8577
|
-
|
|
8578
|
-
|
|
8579
|
-
|
|
8580
|
-
|
|
8581
|
-
|
|
8582
|
-
|
|
8583
|
-
|
|
8584
|
-
|
|
8585
|
-
|
|
8586
|
-
|
|
8587
|
-
type: "button",
|
|
8588
|
-
className: "lc-modal-close hover:text-(--dsw-alias-label-primary) hover:bg-(--dsw-alias-bg-layer-2)",
|
|
8589
|
-
"aria-label": t("cmd.close"),
|
|
8590
|
-
onClick: close,
|
|
8591
|
-
children: "×"
|
|
8592
|
-
})
|
|
8593
|
-
]
|
|
8594
|
-
}), rows === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8595
|
-
className: "lc-empty",
|
|
8596
|
-
children: t("ov.unavailable")
|
|
8597
|
-
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8598
|
-
className: "lc-ov-scroll",
|
|
8599
|
-
children: [
|
|
8720
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
8721
|
+
className: "lc-ov-page",
|
|
8722
|
+
"aria-label": t("ov.title"),
|
|
8723
|
+
...zoneProps,
|
|
8724
|
+
children: [bubble, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8725
|
+
className: "lc-ov-pagescroll",
|
|
8726
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8727
|
+
className: "lc-ov-pagecontent",
|
|
8728
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8729
|
+
className: "lc-ov-pagehead",
|
|
8730
|
+
children: [
|
|
8731
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
|
|
8732
|
+
className: "lc-ov-pagetitle",
|
|
8733
|
+
children: t("ov.title")
|
|
8734
|
+
}),
|
|
8735
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(BalanceCapsule, {}),
|
|
8736
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8737
|
+
className: "lc-gran lc-ov-range",
|
|
8738
|
+
role: "group",
|
|
8739
|
+
"aria-label": t("ov.range.label"),
|
|
8740
|
+
children: RANGES.map((r) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8741
|
+
type: "button",
|
|
8742
|
+
className: "lc-gran-btn" + (range === r ? " lc-gran-on" : ""),
|
|
8743
|
+
onClick: () => {
|
|
8744
|
+
setRange(r);
|
|
8745
|
+
},
|
|
8746
|
+
children: t("ov.range." + r)
|
|
8747
|
+
}, r))
|
|
8748
|
+
})
|
|
8749
|
+
]
|
|
8750
|
+
}), rows === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
8751
|
+
className: "lc-empty",
|
|
8752
|
+
children: t("ov.unavailable")
|
|
8753
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
8600
8754
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
8601
8755
|
className: "lc-ov-first",
|
|
8602
8756
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -8764,7 +8918,6 @@ window.__ModuleLoader__.load({
|
|
|
8764
8918
|
className: "lc-ov-settings",
|
|
8765
8919
|
onClick: () => {
|
|
8766
8920
|
openPluginSettings();
|
|
8767
|
-
close();
|
|
8768
8921
|
},
|
|
8769
8922
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
8770
8923
|
className: "lc-ov-settings-label",
|
|
@@ -8897,9 +9050,9 @@ window.__ModuleLoader__.load({
|
|
|
8897
9050
|
]
|
|
8898
9051
|
})]
|
|
8899
9052
|
})
|
|
8900
|
-
]
|
|
8901
|
-
})
|
|
8902
|
-
})
|
|
9053
|
+
] })]
|
|
9054
|
+
})
|
|
9055
|
+
})]
|
|
8903
9056
|
});
|
|
8904
9057
|
}
|
|
8905
9058
|
return function OverviewPanel(props) {
|
|
@@ -8915,7 +9068,7 @@ window.__ModuleLoader__.load({
|
|
|
8915
9068
|
//#endregion
|
|
8916
9069
|
//#region src/client/components/settingsCard.tsx
|
|
8917
9070
|
/**
|
|
8918
|
-
* The dsh-context preference cards — two seats over the same
|
|
9071
|
+
* The dsh-context preference cards — two seats over the same eight rows. The
|
|
8919
9072
|
* settings-section card (`settings.plugin.item`, the older harness lines)
|
|
8920
9073
|
* renders a collapsible list item in Settings → Plugins → Plugin
|
|
8921
9074
|
* configuration; the Plugins-page card (`plugins.bundle.config`, the
|
|
@@ -9034,6 +9187,21 @@ window.__ModuleLoader__.load({
|
|
|
9034
9187
|
set?.("defaultTrendMode", id);
|
|
9035
9188
|
}
|
|
9036
9189
|
}),
|
|
9190
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PrefRow, {
|
|
9191
|
+
label: t("settings.durationCurve"),
|
|
9192
|
+
value: state.durationCurve,
|
|
9193
|
+
disabled,
|
|
9194
|
+
options: [{
|
|
9195
|
+
id: "show",
|
|
9196
|
+
label: t("insightsEntry.show")
|
|
9197
|
+
}, {
|
|
9198
|
+
id: "hide",
|
|
9199
|
+
label: t("insightsEntry.hide")
|
|
9200
|
+
}],
|
|
9201
|
+
onPick: (id) => {
|
|
9202
|
+
set?.("defaultDurationCurve", id);
|
|
9203
|
+
}
|
|
9204
|
+
}),
|
|
9037
9205
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PrefRow, {
|
|
9038
9206
|
label: t("settings.deltaBase"),
|
|
9039
9207
|
value: state.deltaBase,
|
|
@@ -9171,6 +9339,97 @@ window.__ModuleLoader__.load({
|
|
|
9171
9339
|
};
|
|
9172
9340
|
}
|
|
9173
9341
|
//#endregion
|
|
9342
|
+
//#region src/client/insightPage.ts
|
|
9343
|
+
/**
|
|
9344
|
+
* The Context Insights page — the plugin's first-level panel, a sibling of
|
|
9345
|
+
* the shipped Plugins and Automation tasks pages.
|
|
9346
|
+
*
|
|
9347
|
+
* Two registrations, one identity:
|
|
9348
|
+
* - the full page itself on the layout's root keyed `main` slot, under the
|
|
9349
|
+
* panel key — the shell's center column renders it whenever the panel is
|
|
9350
|
+
* selected (keyed entryKey switching mounts it on entry and unmounts it
|
|
9351
|
+
* on leave, so the page's mount IS its open);
|
|
9352
|
+
* - the sidebar entry on the root list `sidebar.panellist` under the same
|
|
9353
|
+
* id — the shell owns the row (button, label, active state, and the
|
|
9354
|
+
* click that selects the panel), the plugin contributes only the glyph
|
|
9355
|
+
* and the localized label thunk.
|
|
9356
|
+
*
|
|
9357
|
+
* Both seats ship on every supported line (the `main` conversation panel and
|
|
9358
|
+
* the panellist contract are present since 0.1.5-rc.1 — the compat matrix
|
|
9359
|
+
* pins both spellings per baseline), so the registrations ride plain
|
|
9360
|
+
* `slots.inject` declaration injects, like the conversation tab's.
|
|
9361
|
+
*
|
|
9362
|
+
* The per-user `insightsEntry` preference gates the pair: 'show' mounts both
|
|
9363
|
+
* registrations, 'hide' unwinds them (a hidden entry leaves the page no
|
|
9364
|
+
* opener). The watcher mirrors placement.ts's preference-glued mounting;
|
|
9365
|
+
* each mount owns its disposers so a preference flip takes down exactly what
|
|
9366
|
+
* it drops.
|
|
9367
|
+
*
|
|
9368
|
+
* @module dsh-context/client/insightPage
|
|
9369
|
+
*/
|
|
9370
|
+
/**
|
|
9371
|
+
* The id shared by the sidebar entry and the `main` panel it opens (the
|
|
9372
|
+
* layout's MainPanelId domain) — namespaced, like the right-Sidebar kind, so
|
|
9373
|
+
* no shipped or foreign panel collides with it.
|
|
9374
|
+
*/
|
|
9375
|
+
const INSIGHT_PANEL_ID = "dsh-context";
|
|
9376
|
+
/**
|
|
9377
|
+
* Mount the page and its sidebar entry while the preference shows them.
|
|
9378
|
+
* @param ctx - client root context carrying `slots` and the locale service.
|
|
9379
|
+
* @param settings - the preferences store; the gate re-reads on every publish.
|
|
9380
|
+
* @param page - the Insights page component (the root-scope standard kit
|
|
9381
|
+
* arrives on its props, as on every root seat).
|
|
9382
|
+
* @param t - the plugin-namespace translate; the label thunk reads it at call
|
|
9383
|
+
* time, so a language switch relabels the sidebar row.
|
|
9384
|
+
* @param ns - the plugin's locale namespace, put on both registrations so the
|
|
9385
|
+
* framework synthesizes the `t` seat for the page too.
|
|
9386
|
+
* @returns the watcher's disposer (unsubscribes and unwinds any live mount).
|
|
9387
|
+
*/
|
|
9388
|
+
function watchInsightPage(ctx, settings, page, t, ns) {
|
|
9389
|
+
let mounted = false;
|
|
9390
|
+
const disposers = [];
|
|
9391
|
+
const own = (result) => {
|
|
9392
|
+
if (typeof result === "function") disposers.push(result);
|
|
9393
|
+
};
|
|
9394
|
+
const mount = () => {
|
|
9395
|
+
own(ctx.slots.inject("main", () => ctx.slots.register({
|
|
9396
|
+
name: "main",
|
|
9397
|
+
key: INSIGHT_PANEL_ID,
|
|
9398
|
+
locale: ns
|
|
9399
|
+
}, page)));
|
|
9400
|
+
own(ctx.slots.inject("sidebar.panellist", () => ctx.slots.register({
|
|
9401
|
+
name: "sidebar.panellist",
|
|
9402
|
+
id: INSIGHT_PANEL_ID,
|
|
9403
|
+
order: 20,
|
|
9404
|
+
label: () => t("ov.title"),
|
|
9405
|
+
locale: ns
|
|
9406
|
+
}, (props) => (0, react.createElement)(InsightPanelIcon, { size: typeof props.size === "number" ? props.size : void 0 }))));
|
|
9407
|
+
};
|
|
9408
|
+
const unmount = () => {
|
|
9409
|
+
while (disposers.length > 0) disposers.pop()?.();
|
|
9410
|
+
};
|
|
9411
|
+
const applyEntry = (entry) => {
|
|
9412
|
+
if (entry === "show" && !mounted) {
|
|
9413
|
+
mounted = true;
|
|
9414
|
+
mount();
|
|
9415
|
+
} else if (entry === "hide" && mounted) {
|
|
9416
|
+
mounted = false;
|
|
9417
|
+
unmount();
|
|
9418
|
+
}
|
|
9419
|
+
};
|
|
9420
|
+
applyEntry(settings.insightsEntry());
|
|
9421
|
+
const unsubscribe = settings.store.subscribe(() => {
|
|
9422
|
+
applyEntry(settings.insightsEntry());
|
|
9423
|
+
});
|
|
9424
|
+
return () => {
|
|
9425
|
+
unsubscribe();
|
|
9426
|
+
if (mounted) {
|
|
9427
|
+
mounted = false;
|
|
9428
|
+
unmount();
|
|
9429
|
+
}
|
|
9430
|
+
};
|
|
9431
|
+
}
|
|
9432
|
+
//#endregion
|
|
9174
9433
|
//#region src/client/settings.ts
|
|
9175
9434
|
function prefsOf(value) {
|
|
9176
9435
|
if (value === null || typeof value !== "object") return {};
|
|
@@ -9182,7 +9441,8 @@ window.__ModuleLoader__.load({
|
|
|
9182
9441
|
...v.defaultDeltaBase === "step" || v.defaultDeltaBase === "turn" ? { deltaBase: v.defaultDeltaBase } : {},
|
|
9183
9442
|
...v.defaultToolSort === "size" || v.defaultToolSort === "count" || v.defaultToolSort === "name" ? { toolSort: v.defaultToolSort } : {},
|
|
9184
9443
|
...v.defaultFileSort === "count" || v.defaultFileSort === "latest" || v.defaultFileSort === "path" ? { fileSort: v.defaultFileSort } : {},
|
|
9185
|
-
...v.insightsEntry === "show" || v.insightsEntry === "hide" ? { insightsEntry: v.insightsEntry } : {}
|
|
9444
|
+
...v.insightsEntry === "show" || v.insightsEntry === "hide" ? { insightsEntry: v.insightsEntry } : {},
|
|
9445
|
+
...v.defaultDurationCurve === "show" || v.defaultDurationCurve === "hide" ? { durationCurve: v.defaultDurationCurve } : {}
|
|
9186
9446
|
};
|
|
9187
9447
|
}
|
|
9188
9448
|
function createContextSettings() {
|
|
@@ -9195,12 +9455,13 @@ window.__ModuleLoader__.load({
|
|
|
9195
9455
|
toolSort: "count",
|
|
9196
9456
|
fileSort: "count",
|
|
9197
9457
|
insightsEntry: "show",
|
|
9458
|
+
durationCurve: "show",
|
|
9198
9459
|
writable: false
|
|
9199
9460
|
};
|
|
9200
9461
|
let scope;
|
|
9201
9462
|
const listeners = /* @__PURE__ */ new Set();
|
|
9202
9463
|
const publish = (next) => {
|
|
9203
|
-
if (next.status === state.status && next.placement === state.placement && next.granularity === state.granularity && next.mode === state.mode && next.deltaBase === state.deltaBase && next.toolSort === state.toolSort && next.fileSort === state.fileSort && next.insightsEntry === state.insightsEntry && next.writable === state.writable) return;
|
|
9464
|
+
if (next.status === state.status && next.placement === state.placement && next.granularity === state.granularity && next.mode === state.mode && next.deltaBase === state.deltaBase && next.toolSort === state.toolSort && next.fileSort === state.fileSort && next.insightsEntry === state.insightsEntry && next.durationCurve === state.durationCurve && next.writable === state.writable) return;
|
|
9204
9465
|
state = next;
|
|
9205
9466
|
for (const listener of listeners) listener();
|
|
9206
9467
|
};
|
|
@@ -9217,6 +9478,7 @@ window.__ModuleLoader__.load({
|
|
|
9217
9478
|
toolSort: prefs.toolSort ?? state.toolSort,
|
|
9218
9479
|
fileSort: prefs.fileSort ?? state.fileSort,
|
|
9219
9480
|
insightsEntry: prefs.insightsEntry ?? (raw?.insightsEntry === void 0 ? state.insightsEntry : "show"),
|
|
9481
|
+
durationCurve: prefs.durationCurve ?? (raw?.defaultDurationCurve === void 0 ? state.durationCurve : "show"),
|
|
9220
9482
|
writable: snap.writable
|
|
9221
9483
|
});
|
|
9222
9484
|
return {
|
|
@@ -9241,6 +9503,7 @@ window.__ModuleLoader__.load({
|
|
|
9241
9503
|
defaultToolSort: () => state.toolSort,
|
|
9242
9504
|
defaultFileSort: () => state.fileSort,
|
|
9243
9505
|
insightsEntry: () => state.insightsEntry,
|
|
9506
|
+
defaultDurationCurve: () => state.durationCurve,
|
|
9244
9507
|
attach(bound) {
|
|
9245
9508
|
scope = bound;
|
|
9246
9509
|
sync(bound);
|
|
@@ -11404,7 +11667,7 @@ window.__ModuleLoader__.load({
|
|
|
11404
11667
|
return function PluginInfo() {
|
|
11405
11668
|
const [latest, setLatest] = (0, react.useState)(null);
|
|
11406
11669
|
(0, react.useEffect)(() => {
|
|
11407
|
-
if ("0.
|
|
11670
|
+
if ("0.64.0".includes("-dev")) return;
|
|
11408
11671
|
let on = true;
|
|
11409
11672
|
fetchLatestVersion().then((v) => {
|
|
11410
11673
|
if (on && v) setLatest(v);
|
|
@@ -11413,8 +11676,8 @@ window.__ModuleLoader__.load({
|
|
|
11413
11676
|
on = false;
|
|
11414
11677
|
};
|
|
11415
11678
|
}, []);
|
|
11416
|
-
const update = latest !== null && isNewerVersion(latest, "0.
|
|
11417
|
-
const nameText = "dsh-context (v0.
|
|
11679
|
+
const update = latest !== null && isNewerVersion(latest, "0.64.0") ? latest : null;
|
|
11680
|
+
const nameText = "dsh-context (v0.64.0)";
|
|
11418
11681
|
const nameValue = [nameText];
|
|
11419
11682
|
if (update) nameValue.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
11420
11683
|
className: "lc-pi-update",
|
|
@@ -12379,6 +12642,7 @@ window.__ModuleLoader__.load({
|
|
|
12379
12642
|
const [trendMode, setTrendMode] = (0, react.useState)(() => settings.defaultTrendMode());
|
|
12380
12643
|
const [dna, setDna] = (0, react.useState)(false);
|
|
12381
12644
|
const [adaptive, setAdaptive] = (0, react.useState)(false);
|
|
12645
|
+
const [durationCurve, setDurationCurve] = (0, react.useState)(() => settings.defaultDurationCurve() === "show");
|
|
12382
12646
|
const [focusTurn, setFocusTurn] = (0, react.useState)(null);
|
|
12383
12647
|
const [jumpSeq, setJumpSeq] = (0, react.useState)(null);
|
|
12384
12648
|
const [hoverCat, setHoverCat] = (0, react.useState)(null);
|
|
@@ -12619,36 +12883,39 @@ window.__ModuleLoader__.load({
|
|
|
12619
12883
|
className: "lc-card-title-text",
|
|
12620
12884
|
children: t("trend.title")
|
|
12621
12885
|
}),
|
|
12622
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
12623
|
-
className: "lc-gran lc-trend-
|
|
12624
|
-
role: "group",
|
|
12625
|
-
title: t("trend.dnaTip"),
|
|
12626
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
12627
|
-
type: "button",
|
|
12628
|
-
className: "lc-gran-btn" + (dna ? " lc-gran-on" : ""),
|
|
12629
|
-
onClick: () => {
|
|
12630
|
-
setDna((v) => !v);
|
|
12631
|
-
},
|
|
12632
|
-
children: t("trend.dna")
|
|
12633
|
-
})
|
|
12634
|
-
}),
|
|
12635
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
12636
|
-
className: "lc-gran lc-trend-adaptive",
|
|
12886
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
12887
|
+
className: "lc-gran lc-trend-mods",
|
|
12637
12888
|
role: "group",
|
|
12638
|
-
|
|
12639
|
-
|
|
12640
|
-
|
|
12641
|
-
|
|
12642
|
-
|
|
12643
|
-
|
|
12644
|
-
|
|
12645
|
-
|
|
12646
|
-
|
|
12889
|
+
children: [
|
|
12890
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
12891
|
+
type: "button",
|
|
12892
|
+
className: "lc-gran-btn" + (dna ? " lc-gran-on" : ""),
|
|
12893
|
+
title: t("trend.dnaTip"),
|
|
12894
|
+
onClick: () => {
|
|
12895
|
+
setDna((v) => !v);
|
|
12896
|
+
},
|
|
12897
|
+
children: t("trend.dna")
|
|
12898
|
+
}),
|
|
12899
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
12900
|
+
type: "button",
|
|
12901
|
+
className: "lc-gran-btn" + (adaptive ? " lc-gran-on" : ""),
|
|
12902
|
+
title: t("trend.adaptiveHint"),
|
|
12903
|
+
onClick: () => {
|
|
12904
|
+
setAdaptive((on) => !on);
|
|
12905
|
+
},
|
|
12906
|
+
children: t("trend.adaptive")
|
|
12907
|
+
}),
|
|
12908
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
12909
|
+
type: "button",
|
|
12910
|
+
className: "lc-gran-btn" + (durationCurve ? " lc-gran-on" : ""),
|
|
12911
|
+
title: t("trend.durationTip"),
|
|
12912
|
+
onClick: () => {
|
|
12913
|
+
setDurationCurve((on) => !on);
|
|
12914
|
+
},
|
|
12915
|
+
children: t("trend.duration")
|
|
12916
|
+
})
|
|
12917
|
+
]
|
|
12647
12918
|
}),
|
|
12648
|
-
focusCat !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
12649
|
-
className: "lc-card-sub",
|
|
12650
|
-
children: t("trend.focus", { cat: kit.catLabel(focusCat) })
|
|
12651
|
-
}) : null,
|
|
12652
12919
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
12653
12920
|
className: "lc-trend-ctl",
|
|
12654
12921
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -12703,6 +12970,7 @@ window.__ModuleLoader__.load({
|
|
|
12703
12970
|
hoverCat: trendHoverCat,
|
|
12704
12971
|
focusCat,
|
|
12705
12972
|
adaptive,
|
|
12973
|
+
durationCurve,
|
|
12706
12974
|
dna: dnaBands,
|
|
12707
12975
|
onPickBand: revealBand,
|
|
12708
12976
|
onSelect: setSelectedSeq,
|
|
@@ -13005,7 +13273,7 @@ window.__ModuleLoader__.load({
|
|
|
13005
13273
|
}
|
|
13006
13274
|
//#endregion
|
|
13007
13275
|
//#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/base.css.mjs
|
|
13008
|
-
const css$14 = ".lc-root{box-sizing:border-box;height:100%;color:var(--dsw-alias-label-primary);padding:16px 20px 32px;font-size:13px;overflow-y:auto}[data-sidebar-right-open] .lc-root,[data-sidebar-right-float-host] .lc-root{padding:12px}.lc-title-icon{flex:none}.lc-title-label{padding-right:30px}.lc-card{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;margin-bottom:14px;padding:14px 16px}.lc-root .lc-card{box-sizing:border-box;margin-bottom:7px;padding:7px 8px;container:lc-card/inline-size}.lc-root .lc-cols{gap:7px;margin-bottom:7px}.lc-card-title{flex-wrap:wrap;align-items:baseline;gap:8px;margin-bottom:10px;font-weight:600;display:flex}.lc-card-title-text{white-space:nowrap;flex:none}.lc-gran,.lc-kinds{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:6px;gap:2px;margin-left:auto;padding:1px;display:flex}.lc-trend-ctl,.lc-heat-ctl{align-items:center;gap:6px;margin-left:auto;display:flex}.lc-trend-ctl .lc-gran,.lc-heat-ctl .lc-gran,.lc-heat-ctl .lc-card-sub{margin-left:0}.lc-trend-
|
|
13276
|
+
const css$14 = ".lc-root{box-sizing:border-box;height:100%;color:var(--dsw-alias-label-primary);padding:16px 20px 32px;font-size:13px;overflow-y:auto}[data-sidebar-right-open] .lc-root,[data-sidebar-right-float-host] .lc-root{padding:12px}.lc-title-icon{flex:none}.lc-title-label{padding-right:30px}.lc-card{background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:10px;margin-bottom:14px;padding:14px 16px}.lc-root .lc-card{box-sizing:border-box;margin-bottom:7px;padding:7px 8px;container:lc-card/inline-size}.lc-root .lc-cols{gap:7px;margin-bottom:7px}.lc-card-title{flex-wrap:wrap;align-items:baseline;gap:8px;margin-bottom:10px;font-weight:600;display:flex}.lc-card-title-text{white-space:nowrap;flex:none}.lc-gran,.lc-kinds{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:6px;gap:2px;margin-left:auto;padding:1px;display:flex}.lc-trend-ctl,.lc-heat-ctl{align-items:center;gap:6px;margin-left:auto;display:flex}.lc-trend-ctl .lc-gran,.lc-heat-ctl .lc-gran,.lc-heat-ctl .lc-card-sub{margin-left:0}.lc-trend-mods{flex:none;margin-left:0}.lc-gran-btn{color:var(--dsw-alias-label-secondary);cursor:pointer;transition:color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border:0;border-radius:5px;padding:3px 8px;font-family:inherit;font-size:11px;line-height:1}.lc-gran-btn:hover{color:var(--dsw-alias-label-primary)}.lc-gran-btn:disabled{opacity:.4;cursor:not-allowed}.lc-gran-btn:disabled:hover{color:var(--dsw-alias-label-secondary)}.lc-gran-on,.lc-gran-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground)}.lc-kind-n{font-variant-numeric:tabular-nums;opacity:.65;margin-left:4px}.lc-gran-on .lc-kind-n{opacity:.85}.lc-tip{z-index:6;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);width:max-content;color:var(--dsw-alias-label-primary);box-shadow:var(--dsw-shadow-lv3,0 2px 8px #0000002e);pointer-events:none;opacity:0;transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:6px;padding:6px 10px;font-size:12px;position:absolute}.lc-events,.lc-fa-list{flex-direction:column;gap:2px;height:320px;display:flex;overflow-y:auto}.lc-cols{flex-wrap:wrap;gap:14px;margin-bottom:14px;display:flex}.lc-cols>.lc-card,.lc-col>.lc-card:last-child{margin-bottom:0}.lc-col-browser{flex-direction:column;display:flex}.lc-col-browser>.lc-card{flex:1}.lc-head>.lc-card:has(.lc-stats){flex-direction:column;display:flex}.lc-head .lc-stats{flex:1;align-content:stretch}.lc-head .lc-stat{justify-content:center}.lc-empty{color:var(--dsw-alias-label-secondary);text-align:center;padding:18px 0}.lc-error{flex-direction:column;align-items:center;gap:8px;padding:40px 16px;display:flex}.lc-error-msg{font-family:var(--ds-font-family-code,ui-monospace, SFMono-Regular, Menlo, monospace);color:var(--dsw-alias-state-error-primary);background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);overflow-wrap:anywhere;border-radius:6px;max-width:100%;padding:4px 8px;font-size:12px}.lc-error-retry{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;transition:border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:6px;padding:4px 14px;font-size:12px}.lc-foot{color:var(--dsw-alias-label-secondary);margin-top:4px;font-size:12px}[data-conversation-scroll]:has(.lc-root)>[data-composer-seat]:not(:has([data-approval-key],[data-question-key],[data-plan-review-key])),[data-conversation-scroll]:has(.lc-root,.lc-modal-backdrop)~[data-width-handle]{display:none}";
|
|
13009
13277
|
const tagId$14 = "dsh-context/base.css";
|
|
13010
13278
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$14) + "]") === null) {
|
|
13011
13279
|
const tag = document.createElement("style");
|
|
@@ -13016,7 +13284,7 @@ window.__ModuleLoader__.load({
|
|
|
13016
13284
|
}
|
|
13017
13285
|
//#endregion
|
|
13018
13286
|
//#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/stats.css.mjs
|
|
13019
|
-
const css$13 = ".lc-stat{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;flex-direction:column;gap:2px;min-width:0;padding:6px;display:flex}a.lc-stat{color:inherit;cursor:pointer;text-decoration:none}a.lc-stat:hover{border-color:var(--dsw-alias-label-secondary)}.lc-stats .lc-stat{padding:6px 3px}.lc-stats .lc-stat-q{margin:0;position:absolute;top:3px;right:4px}.lc-stat-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;font-weight:600;overflow:hidden}.lc-stat-value{color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;text-align:center;font-size:14px;font-weight:600;overflow:hidden}.lc-stat-sub{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;overflow:hidden}.lc-stat-tipped{position:relative}.lc-stat-q{text-align:center;width:11px;height:11px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);cursor:help;transition:color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:50%;margin-left:4px;font-size:9px;font-style:normal;font-weight:700;line-height:11px;display:inline-block}.lc-stat-tip{max-width:280px;font-weight:400;line-height:1.5;top:calc(100% + 6px);left:0}.lc-stat-tip-prices{border-top:1px dashed var(--dsw-alias-border-l1);margin-top:5px;padding-top:5px;display:block}.lc-stat-tip-head{font-weight:600;display:block}.lc-timing-tps{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);font-variant-numeric:tabular-nums;cursor:default;border-radius:999px;flex:none;margin-left:auto;padding:1px 8px;font-size:12px;line-height:18px}.lc-stat-tip-row{margin-top:2px;display:block}.lc-stat-tip-band{justify-content:space-between;gap:2rem;display:flex}.lc-stat-tip-band i{font-style:normal}.lc-stat-tip-by{color:var(--dsw-alias-label-secondary);margin-top:3px;display:block}.lc-card-sub{color:var(--dsw-alias-label-secondary);margin-left:auto;font-size:12px;font-weight:400}.lc-overview-num{align-items:baseline;gap:6px;margin-bottom:8px;display:flex}.lc-overview-num>b{font-size:20px}.lc-overview-num span{color:var(--dsw-alias-label-secondary)}.lc-overview-pct{margin-left:auto;font-size:11px}.lc-overview-pct b{color:var(--dsw-alias-label-primary);margin-right:4px;font-size:20px}.lc-stat-head{color:var(--dsw-alias-label-secondary);margin:12px 0 8px;font-size:11px;font-weight:600}.lc-col-donut{flex-direction:column;display:flex}.lc-col-donut .lc-donut-row{flex:1}.lc-donut{flex:none;position:relative}.lc-donut svg{display:block}.lc-donut-track{stroke:color-mix(in srgb, var(--color-neutral-500) 18%, transparent)}.lc-donut-seg{transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.lc-donut-dim .lc-donut-seg{opacity:.35}.lc-donut-dim .lc-donut-seg-on{opacity:1}.lc-donut-center{pointer-events:none;text-align:center;box-sizing:border-box;flex-direction:column;justify-content:center;align-items:center;gap:1px;padding:0 7px;display:flex;position:absolute;inset:0}.lc-donut-center b{white-space:nowrap;text-overflow:ellipsis;max-width:100%;line-height:1.15;overflow:hidden}.lc-donut-center span{color:var(--dsw-alias-label-secondary);white-space:nowrap}.lc-sl{grid-template-columns:repeat(auto-fill,minmax(
|
|
13287
|
+
const css$13 = ".lc-stat{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;flex-direction:column;gap:2px;min-width:0;padding:6px;display:flex}a.lc-stat{color:inherit;cursor:pointer;text-decoration:none}a.lc-stat:hover{border-color:var(--dsw-alias-label-secondary)}.lc-stats .lc-stat{padding:6px 3px}.lc-stats .lc-stat-q{margin:0;position:absolute;top:3px;right:4px}.lc-stat-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;font-weight:600;overflow:hidden}.lc-stat-value{color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;text-align:center;font-size:14px;font-weight:600;overflow:hidden}.lc-stat-sub{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;font-size:11px;overflow:hidden}.lc-stat-tipped{position:relative}.lc-stat-q{text-align:center;width:11px;height:11px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);cursor:help;transition:color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:50%;margin-left:4px;font-size:9px;font-style:normal;font-weight:700;line-height:11px;display:inline-block}.lc-stat-tip{max-width:280px;font-weight:400;line-height:1.5;top:calc(100% + 6px);left:0}.lc-stat-tip-prices{border-top:1px dashed var(--dsw-alias-border-l1);margin-top:5px;padding-top:5px;display:block}.lc-stat-tip-head{font-weight:600;display:block}.lc-timing-tps{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);font-variant-numeric:tabular-nums;cursor:default;border-radius:999px;flex:none;margin-left:auto;padding:1px 8px;font-size:12px;line-height:18px}.lc-stat-tip-row{margin-top:2px;display:block}.lc-stat-tip-band{justify-content:space-between;gap:2rem;display:flex}.lc-stat-tip-band i{font-style:normal}.lc-stat-tip-by{color:var(--dsw-alias-label-secondary);margin-top:3px;display:block}.lc-card-sub{color:var(--dsw-alias-label-secondary);margin-left:auto;font-size:12px;font-weight:400}.lc-overview-num{align-items:baseline;gap:6px;margin-bottom:8px;display:flex}.lc-overview-num>b{font-size:20px}.lc-overview-num span{color:var(--dsw-alias-label-secondary)}.lc-overview-pct{margin-left:auto;font-size:11px}.lc-overview-pct b{color:var(--dsw-alias-label-primary);margin-right:4px;font-size:20px}.lc-stat-head{color:var(--dsw-alias-label-secondary);margin:12px 0 8px;font-size:11px;font-weight:600}.lc-col-donut{flex-direction:column;display:flex}.lc-col-donut .lc-donut-row{flex:1}.lc-donut{flex:none;position:relative}.lc-donut svg{display:block}.lc-donut-track{stroke:color-mix(in srgb, var(--color-neutral-500) 18%, transparent)}.lc-donut-seg{transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.lc-donut-dim .lc-donut-seg{opacity:.35}.lc-donut-dim .lc-donut-seg-on{opacity:1}.lc-donut-center{pointer-events:none;text-align:center;box-sizing:border-box;flex-direction:column;justify-content:center;align-items:center;gap:1px;padding:0 7px;display:flex;position:absolute;inset:0}.lc-donut-center b{white-space:nowrap;text-overflow:ellipsis;max-width:100%;line-height:1.15;overflow:hidden}.lc-donut-center span{color:var(--dsw-alias-label-secondary);white-space:nowrap}.lc-sl{grid-template-columns:repeat(auto-fill,minmax(min(150px,100%),1fr));gap:4px 8px;min-width:0;display:grid;overflow:hidden}.lc-sl-row{min-width:0;transition:background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:6px;flex-direction:column;gap:1px;margin:0 -6px;padding:1px 6px;font-size:12px;display:flex}.lc-sl-row-on{background:var(--dsw-alias-interactive-bg-hover)}.lc-sl-row-dim{opacity:.55}.lc-sl-main{align-items:center;gap:6px;min-width:0;display:flex}.lc-sl-dot{border-radius:2px;flex:none;width:8px;height:8px}.lc-sl-label{white-space:nowrap;text-overflow:ellipsis;flex:auto;min-width:0;font-weight:600;line-height:1.25;overflow:hidden}.lc-sl-pct{text-align:right;font-variant-numeric:tabular-nums;flex:none;min-width:30px;font-weight:700}.lc-sl-sub{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;white-space:nowrap;text-overflow:ellipsis;margin-left:14px;font-size:11px;line-height:1.3;overflow:hidden}.lc-pi-grid{grid-template-columns:1fr;gap:8px;display:grid}.lc-pi-row-btn{appearance:none;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;width:100%;padding:0}.lc-pi-row{min-width:0;color:inherit;flex-direction:row;justify-content:space-between;align-items:baseline;gap:12px;text-decoration:none;display:flex}.lc-pi-hint{text-decoration:none}.lc-pi-update{color:var(--dsw-alias-state-warn-primary);white-space:nowrap;margin-left:6px;font-size:11px}.lc-pi-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;flex:none;font-size:11px;font-weight:600;overflow:hidden}.lc-pi-labelicon{vertical-align:-2px;margin-right:4px;display:inline-block}.lc-pi-value{min-width:0;color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;text-align:right;font-size:13px;font-weight:600;overflow:hidden}.lc-tstrip{margin-top:10px}.lc-tstrip-wrap{position:relative}.lc-tstrip-bar{background:color-mix(in srgb, var(--color-neutral-500) 18%, transparent);border-radius:4px;width:100%;height:12px;position:relative;overflow:hidden}.lc-tstrip-seg{transform-origin:0;height:100%;transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);position:absolute;top:0}.lc-tstrip-seg-on{filter:brightness(1.18)}.lc-tstrip-dim .lc-tstrip-seg{opacity:.35}.lc-tstrip-dim .lc-tstrip-seg-on{opacity:1}.lc-tstrip-axis{height:13px;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;margin-top:5px;font-size:10px;line-height:13px;position:relative}.lc-tstrip-tick{white-space:nowrap;position:absolute;transform:translate(-50%)}.lc-tstrip-tick:before{content:\"\";background:var(--dsw-alias-border-l1);width:1px;height:3px;position:absolute;top:-4px;left:50%}.lc-tstrip-tick-first{transform:none}.lc-tstrip-tick-first:before{left:0}.lc-tstrip-tick-last{transform:translate(-100%)}.lc-tstrip-tick-last:before{left:auto;right:0}";
|
|
13020
13288
|
const tagId$13 = "dsh-context/stats.css";
|
|
13021
13289
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$13) + "]") === null) {
|
|
13022
13290
|
const tag = document.createElement("style");
|
|
@@ -13060,7 +13328,7 @@ window.__ModuleLoader__.load({
|
|
|
13060
13328
|
}
|
|
13061
13329
|
//#endregion
|
|
13062
13330
|
//#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/trendChart.css.mjs
|
|
13063
|
-
const css$9 = ".lc-chartrow{align-items:stretch;gap:6px;display:flex}.lc-axis{box-sizing:border-box;width:40px;height:150px;color:var(--dsw-alias-label-secondary);padding-top:18px;font-size:11px;position:relative}.lc-axis span{line-height:1;position:absolute;right:0}.lc-axis-top{top:13px}.lc-axis-q3{top:41px}.lc-axis-mid{top:69px}.lc-axis-q1{top:97px}.lc-axis-bot{top:125px}.lc-chart-wrap{flex:1;min-width:0;position:relative}.lc-chart-scroll{overscroll-behavior-x:contain;scrollbar-gutter:stable;padding-bottom:var(--dsh-scrollbar-width,8px);overflow:auto hidden}.lc-chart{box-sizing:border-box;align-items:flex-end;gap:2px;width:max-content;min-width:100%;height:130px;padding:18px 2px 0;display:flex;position:relative}.lc-grid{border-top:1px dashed var(--dsw-alias-border-l2);pointer-events:none;position:absolute;left:0;right:0}.lc-grid-top{top:18px}.lc-grid-q3{top:46px}.lc-grid-mid{top:74px}.lc-grid-q1{top:102px}.lc-grid-zero{border-top-style:solid;border-top-color:color-mix(in srgb, var(--color-neutral-500) 50%, transparent);top:130px}.lc-bar{cursor:pointer;outline-offset:1px;width:14px;height:100%;transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), outline-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:2px;outline:1px dashed #0000;flex:none;align-items:flex-end;display:flex;position:relative}.lc-chart-dim .lc-bar{opacity:.35}.lc-chart-dim .lc-bar-in-turn{opacity:1}.lc-chart-dim .lc-turn{opacity:.35}.lc-chart-dim .lc-turn-on{opacity:1}.lc-chart-tip{z-index:5;box-sizing:border-box;overflow-wrap:break-word;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);max-width:100%;color:var(--dsw-alias-label-primary);pointer-events:none;border-radius:6px;flex-direction:column;gap:2px;padding:3px 8px;font-size:12px;display:flex;position:absolute;bottom:calc(100% + 4px);left:0;box-shadow:0 2px 8px #0000002e}.lc-chart-tip span+span{color:var(--dsw-alias-label-secondary)}.lc-bar-hovered{outline-color:var(--dsw-alias-brand-primary)}.lc-bar-selected{outline:2px solid var(--dsw-alias-label-primary);outline-offset:1px}.lc-bar-in-turn{background:color-mix(in srgb, var(--color-neutral-500) 14%, transparent)}.lc-bar-stack{flex-direction:column-reverse;width:100%;display:flex}.lc-bar-stack>div{width:100%}.lc-bar-dna{border-radius:2px;width:100%}.lc-bar-stack,.lc-bar-up,.lc-bar-down,.lc-bar-dna{transform-origin:50% 100%}.lc-bar-down{transform-origin:50% 0}.lc-bar-stack>div:first-child{border-radius:0 0 2px 2px}.lc-bar-stack>div:last-child{border-radius:2px 2px 0 0}.lc-bar-stack>div:only-child{border-radius:2px}.lc-bar-up,.lc-bar-down{width:100%;display:flex;position:absolute;left:0}.lc-bar-up{flex-direction:column-reverse}.lc-bar-down{flex-direction:column}.lc-bar-up>div,.lc-bar-down>div{width:100%}.lc-bar-up>div:last-child{border-radius:2px 2px 0 0}.lc-bar-down>div:last-child{border-radius:0 0 2px 2px}.lc-cat-seg{transition:
|
|
13331
|
+
const css$9 = ".lc-chartrow{align-items:stretch;gap:6px;display:flex}.lc-axis{box-sizing:border-box;width:40px;height:150px;color:var(--dsw-alias-label-secondary);padding-top:18px;font-size:11px;position:relative}.lc-axis span{line-height:1;position:absolute;right:0}.lc-axis-r{flex:none;width:34px}.lc-axis-r span{left:0;right:auto}.lc-axis-top{top:13px}.lc-axis-q3{top:41px}.lc-axis-mid{top:69px}.lc-axis-q1{top:97px}.lc-axis-bot{top:125px}.lc-chart-wrap{flex:1;min-width:0;position:relative}.lc-chart-scroll{overscroll-behavior-x:contain;scrollbar-gutter:stable;padding-bottom:var(--dsh-scrollbar-width,8px);overflow:auto hidden}.lc-chart{box-sizing:border-box;align-items:flex-end;gap:2px;width:max-content;min-width:100%;height:130px;padding:18px 2px 0;display:flex;position:relative}.lc-grid{border-top:1px dashed var(--dsw-alias-border-l2);pointer-events:none;position:absolute;left:0;right:0}.lc-grid-top{top:18px}.lc-grid-q3{top:46px}.lc-grid-mid{top:74px}.lc-grid-q1{top:102px}.lc-grid-zero{border-top-style:solid;border-top-color:color-mix(in srgb, var(--color-neutral-500) 50%, transparent);top:130px}.lc-bar{cursor:pointer;outline-offset:1px;width:14px;height:100%;transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), outline-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:2px;outline:1px dashed #0000;flex:none;align-items:flex-end;display:flex;position:relative}.lc-chart-dim .lc-bar{opacity:.35}.lc-chart-dim .lc-bar-in-turn{opacity:1}.lc-chart-dim .lc-turn{opacity:.35}.lc-chart-dim .lc-turn-on{opacity:1}.lc-chart-tip{z-index:5;box-sizing:border-box;overflow-wrap:break-word;background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l1);max-width:100%;color:var(--dsw-alias-label-primary);pointer-events:none;border-radius:6px;flex-direction:column;gap:2px;padding:3px 8px;font-size:12px;display:flex;position:absolute;bottom:calc(100% + 4px);left:0;box-shadow:0 2px 8px #0000002e}.lc-chart-tip span+span{color:var(--dsw-alias-label-secondary)}.lc-bar-hovered{outline-color:var(--dsw-alias-brand-primary)}.lc-bar-selected{outline:2px solid var(--dsw-alias-label-primary);outline-offset:1px}.lc-bar-in-turn{background:color-mix(in srgb, var(--color-neutral-500) 14%, transparent)}.lc-bar-stack{flex-direction:column-reverse;width:100%;display:flex}.lc-bar-stack>div{width:100%}.lc-bar-dna{border-radius:2px;width:100%}.lc-bar-stack,.lc-bar-up,.lc-bar-down,.lc-bar-dna{transform-origin:50% 100%}.lc-bar-down{transform-origin:50% 0}.lc-bar-stack>div:first-child{border-radius:0 0 2px 2px}.lc-bar-stack>div:last-child{border-radius:2px 2px 0 0}.lc-bar-stack>div:only-child{border-radius:2px}.lc-bar-up,.lc-bar-down{width:100%;display:flex;position:absolute;left:0}.lc-bar-up{flex-direction:column-reverse}.lc-bar-down{flex-direction:column}.lc-bar-up>div,.lc-bar-down>div{width:100%}.lc-bar-up>div:last-child{border-radius:2px 2px 0 0}.lc-bar-down>div:last-child{border-radius:0 0 2px 2px}.lc-cat-seg{transition:opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out)}.lc-chart[data-catdim] .lc-cat-seg{opacity:.35}.lc-chart[data-catdim=system] .lc-cat-seg[data-cat=system],.lc-chart[data-catdim=tools] .lc-cat-seg[data-cat=tools],.lc-chart[data-catdim=user] .lc-cat-seg[data-cat=user],.lc-chart[data-catdim=inject] .lc-cat-seg[data-cat=inject],.lc-chart[data-catdim=skill] .lc-cat-seg[data-cat=skill],.lc-chart[data-catdim=assistant] .lc-cat-seg[data-cat=assistant],.lc-chart[data-catdim=tool] .lc-cat-seg[data-cat=tool]{opacity:1}.lc-dna-hl{z-index:1;pointer-events:none;align-items:stretch;gap:2px;display:flex;position:absolute;inset:18px 2px 0}.lc-dna-cell{flex:none;width:14px;position:relative}.lc-dna-slice{box-sizing:border-box;border:1px solid var(--dsw-alias-brand-primary);background:color-mix(in srgb, var(--dsw-alias-brand-primary) 26%, transparent);border-radius:1px;width:100%;position:absolute;left:0}.lc-duration{z-index:1;pointer-events:none;position:absolute;top:18px;left:2px;overflow:visible}.lc-duration polyline,.lc-duration circle{fill:none;stroke:var(--dsw-alias-brand-primary);stroke-width:1.5px;stroke-linejoin:round;stroke-linecap:round}.lc-duration circle{fill:var(--dsw-alias-brand-primary)}.lc-chart-dim .lc-duration{opacity:.35}.lc-bar-marker{z-index:2;color:var(--dsw-alias-state-warn-primary);font-size:11px;position:absolute;top:-16px;left:50%;transform:translate(-50%)}.lc-step-flag{z-index:2;background:color-mix(in srgb, var(--color-neutral-500) 45%, transparent);pointer-events:none;width:1px;position:absolute;top:-17px;bottom:0;right:-1px}.lc-step-flag-label{box-sizing:border-box;border:1px solid color-mix(in srgb, var(--color-neutral-500) 45%, transparent);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:3px;padding:1px 3px;font-size:9px;font-weight:600;line-height:1;position:absolute;top:0;right:0}.lc-turns{box-sizing:border-box;gap:2px;width:max-content;min-width:100%;margin-top:4px;padding:0 2px;display:flex;overflow:hidden}.lc-turn{box-sizing:border-box;text-align:center;color:var(--dsw-alias-label-secondary);white-space:nowrap;cursor:pointer;height:14px;transition:filter var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), opacity var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:3px;flex:none;font-size:10px;font-weight:600;line-height:14px}.lc-turn-on{filter:brightness(1.35);color:var(--dsw-alias-label-primary)}.lc-turn-label{display:inline-block}";
|
|
13064
13332
|
const tagId$9 = "dsh-context/trendChart.css";
|
|
13065
13333
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$9) + "]") === null) {
|
|
13066
13334
|
const tag = document.createElement("style");
|
|
@@ -13159,7 +13427,7 @@ window.__ModuleLoader__.load({
|
|
|
13159
13427
|
}
|
|
13160
13428
|
//#endregion
|
|
13161
13429
|
//#region \0dsh-global-css:/home/runner/work/dsh-context/dsh-context/src/client/styles/overview.css.mjs
|
|
13162
|
-
const css = ".lc-ov-entry{box-sizing:border-box;width:calc(100% + 4px);height:42px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:8px;margin:0 -2px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.lc-ov-entry:hover{background:var(--dsw-alias-interactive-bg-hover)}.lc-ov-entry-rail{border-radius:50%;flex:none;justify-content:center;gap:0;width:36px;height:36px;margin:0;padding:0}.lc-ov-entry-icon{flex:none}.lc-ov-entry-label{text-align:left;white-space:nowrap;text-overflow:ellipsis;flex:auto;min-width:0;overflow:hidden}.lc-ov-backdrop{z-index:200;background:var(--dsw-alias-bg-mask-1,#00000073);justify-content:center;align-items:center;display:flex;position:fixed;inset:0;container:lc-ov/inline-size}.lc-ov-card{box-sizing:border-box;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);width:min(1120px,100vw - 32px);height:calc(100% - 80px);box-shadow:var(--dsw-shadow-lv3,0 12px 32px #0006);color:var(--dsw-alias-label-primary);border-radius:12px;flex-direction:column;padding:16px 18px 18px;font-size:13px;display:flex;overflow:hidden}.lc-ov-head{flex-wrap:wrap;flex:none;align-items:center;gap:10px;margin-bottom:14px;display:flex}.lc-ov-head-icon{flex:none}.lc-ov-title{white-space:nowrap;font-size:15px;font-weight:600}.lc-ov-balance{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);max-width:100%;color:inherit;border-radius:999px;flex:none;align-items:center;gap:6px;padding:2px 10px;font-size:12px;line-height:18px;text-decoration:none;display:inline-flex}.lc-ov-balance:hover .lc-ov-balance-value{text-decoration:underline}.lc-ov-balance-label{color:var(--dsw-alias-label-secondary);white-space:nowrap}.lc-ov-balance-value{font-variant-numeric:tabular-nums;white-space:nowrap;font-weight:600}.lc-ov-head .lc-modal-close{flex:none;margin-left:0}.lc-ov-scroll{scrollbar-gutter:stable;flex:auto;min-height:0;padding-right:8px;overflow-y:auto}.lc-ov-first{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-bottom:10px;display:grid}.lc-ov-kpis{grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;display:grid}.lc-ov-kpi{align-items:center;padding:8px}.lc-ov-kpi .lc-stat-value{font-size:20px}@container lc-ov (width<=932px){.lc-ov-first{grid-template-columns:minmax(0,1fr)}}@container lc-ov (width<=640px){.lc-ov-kpis{grid-template-columns:repeat(2,minmax(0,1fr))}}.lc-ov-usage{box-sizing:border-box;flex-direction:column;flex:auto;min-width:0;margin-bottom:0;display:flex}.lc-ov-usage .lc-card-title{margin-bottom:4px}.lc-ov-usage-plot{flex:auto;align-items:stretch;gap:6px;min-height:0;display:flex}.lc-ov-usage-rail{width:42px;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:9px;line-height:1.2;position:relative}.lc-ov-usage-rail-l .lc-ov-usage-tick{right:0}.lc-ov-usage-rail-r .lc-ov-usage-tick{left:0}.lc-ov-usage-tick{white-space:nowrap;position:absolute;transform:translateY(-50%)}.lc-ov-usage-grid{flex:auto;min-width:0;min-height:56px;display:flex;position:relative}.lc-ov-usage-line{background:color-mix(in srgb, var(--dsw-alias-border-l2) 70%, transparent);height:1px;position:absolute;left:0;right:0}.lc-ov-usage-line-0{background:var(--dsw-alias-border-l2)}.lc-ov-usage-cols{flex:auto;align-items:stretch;gap:6px;min-width:0;display:flex;position:relative}.lc-ov-usage-col{flex-direction:column;flex:1 1 0;min-width:0;display:flex}.lc-ov-usage-bars{flex:auto;justify-content:center;align-items:flex-end;gap:3px;width:100%;display:flex}.lc-ov-usage-bar{border-radius:3px 3px 0 0;flex:none;width:10px}.lc-ov-usage-tokens{background:color-mix(in srgb, var(--color-blue-500) 72%, transparent)}.lc-ov-usage-cost{background:color-mix(in srgb, var(--color-green-500) 72%, transparent)}.lc-ov-usage-days{flex:none;gap:6px;padding-top:3px;display:flex}.lc-ov-usage-day{text-align:center;min-width:0;color:var(--dsw-alias-label-secondary);white-space:nowrap;font-variant-numeric:tabular-nums;flex:1 1 0;font-size:9px;line-height:1.2}.lc-ov-usage-key{flex:none;justify-content:flex-end;align-items:center;gap:5px;padding-top:5px;display:flex}.lc-ov-usage-swatch{border-radius:2px;flex:none;width:10px;height:8px}.lc-ov-usage-key-label{color:var(--dsw-alias-label-secondary);font-size:9px}.lc-ov-stats{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-bottom:10px;display:grid}.lc-ov-stats>.lc-card{box-sizing:border-box;min-width:0;margin-bottom:0}@container lc-ov (width<=700px){.lc-ov-stats{grid-template-columns:minmax(0,1fr)}}.lc-ov-body{grid-template-columns:minmax(0,3fr) minmax(0,7fr);align-items:start;gap:10px;display:grid}.lc-ov-left{flex-direction:column;gap:10px;min-width:0;display:flex}.lc-ov-right{min-width:0}@container lc-ov (width<=932px){.lc-ov-body{display:block}.lc-ov-left{margin-bottom:12px}}.lc-ov-left>.lc-card{box-sizing:border-box;min-width:0;margin-bottom:0}.lc-ov-heat-card{flex-direction:column;display:flex}.lc-ov-settings{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:100%;font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;transition:border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:10px;flex:none;align-items:center;gap:8px;padding:9px 12px;font-size:12px;display:flex}.lc-ov-settings:hover{border-color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary)}.lc-ov-settings-label{white-space:nowrap;flex:none;align-items:center;gap:6px;display:inline-flex}.lc-ov-settings-hint{text-align:right;white-space:nowrap;text-overflow:ellipsis;flex:auto;min-width:0;overflow:hidden}.lc-heat-wrap{flex-direction:column;flex:1;display:flex}.lc-heat{flex:1;justify-content:center;align-items:center;gap:8px;display:flex}.lc-heat-wds,.lc-heat-col{padding-top:18px}.lc-heat-wds{flex-direction:column;gap:3px;display:flex}.lc-heat-wd{height:20px;color:var(--dsw-alias-label-secondary);text-align:center;white-space:nowrap;flex:none;justify-content:center;align-items:center;font-size:9px;display:flex}.lc-heat-cols{gap:3px;display:flex}.lc-heat-col{flex-direction:column;gap:3px;display:flex;position:relative}.lc-heat-mon{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:9px;line-height:18px;position:absolute;top:0;left:0}.lc-heat-cell{box-sizing:border-box;background:var(--dsw-alias-bg-layer-2);cursor:default;border:0;border-radius:20%;width:20px;height:20px;padding:0}button.lc-heat-cell{cursor:pointer}button.lc-heat-cell:hover{box-shadow:0 0 0 1.5px color-mix(in srgb, var(--color-blue-500) 70%, transparent)}.lc-heat-future{background:0 0}.lc-heat-0{background:color-mix(in srgb, var(--dsw-alias-label-secondary) 16%, transparent)}.lc-heat-1{background:color-mix(in srgb, var(--color-blue-500) 28%, transparent)}.lc-heat-2{background:color-mix(in srgb, var(--color-blue-500) 50%, transparent)}.lc-heat-3{background:color-mix(in srgb, var(--color-blue-500) 72%, transparent)}.lc-heat-4{background:color-mix(in srgb, var(--color-blue-500) 92%, transparent)}.lc-heat-on{box-shadow:0 0 0 1.5px var(--color-blue-500)}.lc-heat-legend{justify-content:flex-end;align-items:center;gap:3px;padding-top:6px;display:flex}.lc-heat-key{color:var(--dsw-alias-label-secondary);font-size:9px}.lc-ov-list-head{flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:10px;display:flex}.lc-ov-list-title{white-space:nowrap;font-weight:600}.lc-ov-list-count{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;background:var(--dsw-alias-bg-layer-2);border-radius:8px;padding:1px 7px;font-size:11px}.lc-ov-day-chip{border:1px solid color-mix(in srgb, var(--color-blue-500) 45%, transparent);color:var(--color-blue-500);background:color-mix(in srgb, var(--color-blue-500) 10%, transparent);cursor:pointer;white-space:nowrap;border-radius:999px;padding:1px 10px;font-family:inherit;font-size:11px;line-height:1.4}.lc-ov-search{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);min-width:110px;font:inherit;color:var(--dsw-alias-label-primary);transition:border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:6px;outline:none;flex:150px;padding:4px 10px;font-size:12px}.lc-ov-search:focus{border-color:var(--dsw-alias-label-secondary)}.lc-ov-search::placeholder{color:var(--dsw-alias-label-secondary)}.lc-ov-groups{flex-wrap:wrap;gap:6px;margin:-2px 0 10px;display:flex}.lc-ov-chip{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;white-space:nowrap;text-overflow:ellipsis;max-width:220px;transition:color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border-radius:999px;align-items:baseline;gap:5px;padding:2px 10px;font-size:11px;line-height:1.5;display:inline-flex;overflow:hidden}.lc-ov-chip:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-secondary)}.lc-ov-chip-on,.lc-ov-chip-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);border-color:#0000}.lc-ov-chip-n{font-variant-numeric:tabular-nums;opacity:.65;font-size:10px}.lc-ov-chip-on .lc-ov-chip-n{opacity:.85}.lc-ov-grid{grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:10px;display:grid}.lc-ov-session{text-align:left;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;font:inherit;color:inherit;transition:border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:10px;flex-direction:column;gap:6px;padding:10px 12px;display:flex}.lc-ov-session:hover{border-color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2)}.lc-ov-session-current{border-color:color-mix(in srgb, var(--color-blue-500) 65%, transparent)}.lc-ov-session-head{align-items:flex-start;gap:6px;min-width:0;display:flex}.lc-ov-running{background:var(--color-green-500);border-radius:50%;flex:none;width:7px;height:7px}.lc-ov-session-title{-webkit-line-clamp:2;overflow-wrap:anywhere;-webkit-box-orient:vertical;flex:auto;min-width:0;font-weight:600;display:-webkit-box;overflow:hidden}.lc-ov-current{color:var(--color-blue-500);border:1px solid color-mix(in srgb, var(--color-blue-500) 45%, transparent);border-radius:4px;flex:none;padding:0 4px;font-size:10px;line-height:1.5}.lc-ov-session-times{flex-direction:column;flex:none;align-items:flex-end;gap:1px;display:flex}.lc-ov-session-time{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:11px}.lc-ov-session-created{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-variant-numeric:tabular-nums;font-size:10px;line-height:1.4}.lc-ov-session-crumb{min-width:0;color:var(--dsw-alias-label-secondary);white-space:nowrap;align-items:center;gap:5px;font-size:11px;display:flex;overflow:hidden}.lc-ov-crumb-group{text-overflow:ellipsis;flex:none;max-width:55%;overflow:hidden}.lc-ov-crumb-sep{opacity:.55;flex:none}.lc-ov-crumb-project{text-overflow:ellipsis;min-width:0;font-family:var(--ds-font-family-code,ui-monospace, SFMono-Regular, Menlo, monospace);color:var(--dsw-alias-label-primary);background:color-mix(in srgb, var(--dsw-alias-label-secondary) 16%, transparent);border-radius:999px;flex:0 auto;padding:0 8px;font-size:10px;line-height:1.6;overflow:hidden}.lc-ov-session-body{align-items:center;gap:14px;min-width:0;display:flex}.lc-ov-mini-stats{flex-direction:column;flex:auto;gap:3px;min-width:0;display:flex}.lc-ov-mini-stat{justify-content:space-between;align-items:baseline;gap:10px;font-size:11px;display:flex}.lc-ov-mini-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;flex:none}.lc-ov-mini-value{font-variant-numeric:tabular-nums;white-space:nowrap;font-weight:600}.lc-ov-session-empty{color:var(--dsw-alias-label-secondary);padding:6px 0;font-size:11px;line-height:1.5}.lc-ov-session-preview{border-top:1px solid color-mix(in srgb, var(--dsw-alias-border-l2) 60%, transparent);align-items:baseline;gap:6px;min-width:0;margin-top:auto;padding-top:6px;display:flex}.lc-ov-session-preview-label{color:var(--dsw-alias-label-secondary);flex:none;font-size:10px}.lc-ov-session-preview-text{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);flex:0 auto;font-size:11px;line-height:1.5;overflow:hidden}.lc-ov-pager{justify-content:center;align-items:center;gap:10px;margin-top:12px;display:flex}.lc-ov-pager-btn{border:1px solid var(--dsw-alias-border-l2);width:26px;height:22px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;transition:border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border-radius:6px;flex:none;justify-content:center;align-items:center;line-height:1;display:flex}.lc-ov-pager-btn:hover:enabled{border-color:var(--dsw-alias-label-secondary)}.lc-ov-pager-btn:disabled{opacity:.4;cursor:default}.lc-ov-pager-n{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:11px}";
|
|
13430
|
+
const css = ".lc-ov-page{box-sizing:border-box;background:var(--dsw-alias-bg-base);width:100%;min-width:0;height:100%;min-height:0;color:var(--dsw-alias-label-primary);flex-direction:column;font-size:13px;display:flex;overflow:hidden;container:lc-ov/inline-size}.lc-ov-pagescroll{scrollbar-gutter:stable;flex:auto;min-height:0;overflow-y:auto}.lc-ov-pagecontent{max-width:960px;margin:0 auto;padding:0 clamp(24px,4vw,48px) 48px}.lc-ov-pagehead{flex-wrap:wrap;align-items:center;gap:16px;margin-bottom:24px;padding-top:28px;display:flex}[data-platform=darwin] .lc-ov-pagehead{padding-top:calc(28px + var(--dsh-frame-top-clearance,0px))}.lc-ov-pagetitle{flex:auto;min-width:0;margin:0;font-size:20px;font-weight:500;line-height:28px}.lc-ov-balance{background:var(--dsw-alias-bg-layer-2);border:1px solid var(--dsw-alias-border-l2);max-width:100%;color:inherit;border-radius:999px;flex:none;align-items:center;gap:6px;padding:2px 10px;font-size:12px;line-height:18px;text-decoration:none;display:inline-flex}.lc-ov-balance:hover .lc-ov-balance-value{text-decoration:underline}.lc-ov-balance-label{color:var(--dsw-alias-label-secondary);white-space:nowrap}.lc-ov-balance-value{font-variant-numeric:tabular-nums;white-space:nowrap;font-weight:600}.lc-hovertip{z-index:300;white-space:pre-line;max-width:min(320px,50vw);position:fixed}.lc-ov-first{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-bottom:10px;display:grid}.lc-ov-kpis{grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;display:grid}.lc-ov-kpi{align-items:center;padding:8px}.lc-ov-kpi .lc-stat-value{font-size:20px}@container lc-ov (width<=932px){.lc-ov-first{grid-template-columns:minmax(0,1fr)}}@container lc-ov (width<=640px){.lc-ov-kpis{grid-template-columns:repeat(2,minmax(0,1fr))}}.lc-ov-usage{box-sizing:border-box;flex-direction:column;flex:auto;min-width:0;margin-bottom:0;display:flex}.lc-ov-usage .lc-card-title{margin-bottom:4px}.lc-ov-usage-plot{flex:auto;align-items:stretch;gap:6px;min-height:0;display:flex}.lc-ov-usage-rail{width:42px;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;flex:none;font-size:9px;line-height:1.2;position:relative}.lc-ov-usage-rail-l .lc-ov-usage-tick{right:0}.lc-ov-usage-rail-r .lc-ov-usage-tick{left:0}.lc-ov-usage-tick{white-space:nowrap;position:absolute;transform:translateY(-50%)}.lc-ov-usage-grid{flex:auto;min-width:0;min-height:56px;display:flex;position:relative}.lc-ov-usage-line{background:color-mix(in srgb, var(--dsw-alias-border-l2) 70%, transparent);height:1px;position:absolute;left:0;right:0}.lc-ov-usage-line-0{background:var(--dsw-alias-border-l2)}.lc-ov-usage-cols{flex:auto;align-items:stretch;gap:6px;min-width:0;display:flex;position:relative}.lc-ov-usage-col{flex-direction:column;flex:1 1 0;min-width:0;display:flex}.lc-ov-usage-bars{flex:auto;justify-content:center;align-items:flex-end;gap:3px;width:100%;display:flex}.lc-ov-usage-bar{border-radius:3px 3px 0 0;flex:none;width:10px}.lc-ov-usage-tokens{background:color-mix(in srgb, var(--color-blue-500) 72%, transparent)}.lc-ov-usage-cost{background:color-mix(in srgb, var(--color-green-500) 72%, transparent)}.lc-ov-usage-days{flex:none;gap:6px;padding-top:3px;display:flex}.lc-ov-usage-day{text-align:center;min-width:0;color:var(--dsw-alias-label-secondary);white-space:nowrap;font-variant-numeric:tabular-nums;flex:1 1 0;font-size:9px;line-height:1.2}.lc-ov-usage-key{flex:none;justify-content:flex-end;align-items:center;gap:5px;padding-top:5px;display:flex}.lc-ov-usage-swatch{border-radius:2px;flex:none;width:10px;height:8px}.lc-ov-usage-key-label{color:var(--dsw-alias-label-secondary);font-size:9px}.lc-ov-stats{grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-bottom:10px;display:grid}.lc-ov-stats>.lc-card{box-sizing:border-box;min-width:0;margin-bottom:0}@container lc-ov (width<=700px){.lc-ov-stats{grid-template-columns:minmax(0,1fr)}}.lc-ov-body{grid-template-columns:minmax(0,3fr) minmax(0,7fr);align-items:start;gap:10px;display:grid}.lc-ov-left{flex-direction:column;gap:10px;min-width:0;display:flex}.lc-ov-right{min-width:0}@container lc-ov (width<=932px){.lc-ov-body{display:block}.lc-ov-left{margin-bottom:12px}}.lc-ov-left>.lc-card{box-sizing:border-box;min-width:0;margin-bottom:0}.lc-ov-heat-card{flex-direction:column;display:flex}.lc-ov-settings{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);width:100%;font:inherit;color:var(--dsw-alias-label-secondary);cursor:pointer;transition:border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:10px;flex:none;align-items:center;gap:8px;padding:9px 12px;font-size:12px;display:flex}.lc-ov-settings:hover{border-color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary)}.lc-ov-settings-label{white-space:nowrap;flex:none;align-items:center;gap:6px;display:inline-flex}.lc-ov-settings-hint{text-align:right;white-space:nowrap;text-overflow:ellipsis;flex:auto;min-width:0;overflow:hidden}.lc-heat-wrap{flex-direction:column;flex:1;display:flex}.lc-heat{flex:1;justify-content:center;align-items:center;gap:8px;display:flex}.lc-heat-wds,.lc-heat-col{padding-top:18px}.lc-heat-wds{flex-direction:column;gap:3px;display:flex}.lc-heat-wd{height:20px;color:var(--dsw-alias-label-secondary);text-align:center;white-space:nowrap;flex:none;justify-content:center;align-items:center;font-size:9px;display:flex}.lc-heat-cols{gap:3px;display:flex}.lc-heat-col{flex-direction:column;gap:3px;display:flex;position:relative}.lc-heat-mon{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:9px;line-height:18px;position:absolute;top:0;left:0}.lc-heat-cell{box-sizing:border-box;background:var(--dsw-alias-bg-layer-2);cursor:default;border:0;border-radius:20%;width:20px;height:20px;padding:0}button.lc-heat-cell{cursor:pointer}button.lc-heat-cell:hover{box-shadow:0 0 0 1.5px color-mix(in srgb, var(--color-blue-500) 70%, transparent)}.lc-heat-future{background:0 0}.lc-heat-0{background:color-mix(in srgb, var(--dsw-alias-label-secondary) 16%, transparent)}.lc-heat-1{background:color-mix(in srgb, var(--color-blue-500) 28%, transparent)}.lc-heat-2{background:color-mix(in srgb, var(--color-blue-500) 50%, transparent)}.lc-heat-3{background:color-mix(in srgb, var(--color-blue-500) 72%, transparent)}.lc-heat-4{background:color-mix(in srgb, var(--color-blue-500) 92%, transparent)}.lc-heat-on{box-shadow:0 0 0 1.5px var(--color-blue-500)}.lc-heat-legend{justify-content:flex-end;align-items:center;gap:3px;padding-top:6px;display:flex}.lc-heat-key{color:var(--dsw-alias-label-secondary);font-size:9px}.lc-ov-list-head{flex-wrap:wrap;align-items:center;gap:10px;margin-bottom:10px;display:flex}.lc-ov-list-title{white-space:nowrap;font-weight:600}.lc-ov-list-count{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;background:var(--dsw-alias-bg-layer-2);border-radius:8px;padding:1px 7px;font-size:11px}.lc-ov-day-chip{border:1px solid color-mix(in srgb, var(--color-blue-500) 45%, transparent);color:var(--color-blue-500);background:color-mix(in srgb, var(--color-blue-500) 10%, transparent);cursor:pointer;white-space:nowrap;border-radius:999px;padding:1px 10px;font-family:inherit;font-size:11px;line-height:1.4}.lc-ov-search{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);min-width:110px;font:inherit;color:var(--dsw-alias-label-primary);transition:border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:6px;outline:none;flex:150px;padding:4px 10px;font-size:12px}.lc-ov-search:focus{border-color:var(--dsw-alias-label-secondary)}.lc-ov-search::placeholder{color:var(--dsw-alias-label-secondary)}.lc-ov-groups{flex-wrap:wrap;gap:6px;margin:-2px 0 10px;display:flex}.lc-ov-chip{border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);font:inherit;cursor:pointer;white-space:nowrap;text-overflow:ellipsis;max-width:220px;transition:color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border-radius:999px;align-items:baseline;gap:5px;padding:2px 10px;font-size:11px;line-height:1.5;display:inline-flex;overflow:hidden}.lc-ov-chip:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-secondary)}.lc-ov-chip-on,.lc-ov-chip-on:hover{background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);border-color:#0000}.lc-ov-chip-n{font-variant-numeric:tabular-nums;opacity:.65;font-size:10px}.lc-ov-chip-on .lc-ov-chip-n{opacity:.85}.lc-ov-grid{grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:10px;display:grid}.lc-ov-session{text-align:left;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);cursor:pointer;font:inherit;color:inherit;transition:border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out), background-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);border-radius:10px;flex-direction:column;gap:6px;padding:10px 12px;display:flex}.lc-ov-session:hover{border-color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-2)}.lc-ov-session-current{border-color:color-mix(in srgb, var(--color-blue-500) 65%, transparent)}.lc-ov-session-head{align-items:flex-start;gap:6px;min-width:0;display:flex}.lc-ov-running{background:var(--color-green-500);border-radius:50%;flex:none;width:7px;height:7px}.lc-ov-session-title{-webkit-line-clamp:2;overflow-wrap:anywhere;-webkit-box-orient:vertical;flex:auto;min-width:0;font-weight:600;display:-webkit-box;overflow:hidden}.lc-ov-current{color:var(--color-blue-500);border:1px solid color-mix(in srgb, var(--color-blue-500) 45%, transparent);border-radius:4px;flex:none;padding:0 4px;font-size:10px;line-height:1.5}.lc-ov-session-times{flex-direction:column;flex:none;align-items:flex-end;gap:1px;display:flex}.lc-ov-session-time{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-size:11px}.lc-ov-session-created{color:var(--dsw-alias-label-secondary);white-space:nowrap;font-variant-numeric:tabular-nums;font-size:10px;line-height:1.4}.lc-ov-session-crumb{min-width:0;color:var(--dsw-alias-label-secondary);white-space:nowrap;align-items:center;gap:5px;font-size:11px;display:flex;overflow:hidden}.lc-ov-crumb-group{text-overflow:ellipsis;flex:none;max-width:55%;overflow:hidden}.lc-ov-crumb-sep{opacity:.55;flex:none}.lc-ov-crumb-project{text-overflow:ellipsis;min-width:0;font-family:var(--ds-font-family-code,ui-monospace, SFMono-Regular, Menlo, monospace);color:var(--dsw-alias-label-primary);background:color-mix(in srgb, var(--dsw-alias-label-secondary) 16%, transparent);border-radius:999px;flex:0 auto;padding:0 8px;font-size:10px;line-height:1.6;overflow:hidden}.lc-ov-session-body{align-items:center;gap:14px;min-width:0;display:flex}.lc-ov-mini-stats{flex-direction:column;flex:auto;gap:3px;min-width:0;display:flex}.lc-ov-mini-stat{justify-content:space-between;align-items:baseline;gap:10px;font-size:11px;display:flex}.lc-ov-mini-label{color:var(--dsw-alias-label-secondary);white-space:nowrap;flex:none}.lc-ov-mini-value{font-variant-numeric:tabular-nums;white-space:nowrap;font-weight:600}.lc-ov-session-empty{color:var(--dsw-alias-label-secondary);padding:6px 0;font-size:11px;line-height:1.5}.lc-ov-session-preview{border-top:1px solid color-mix(in srgb, var(--dsw-alias-border-l2) 60%, transparent);align-items:baseline;gap:6px;min-width:0;margin-top:auto;padding-top:6px;display:flex}.lc-ov-session-preview-label{color:var(--dsw-alias-label-secondary);flex:none;font-size:10px}.lc-ov-session-preview-text{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--dsw-alias-label-primary);flex:0 auto;font-size:11px;line-height:1.5;overflow:hidden}.lc-ov-pager{justify-content:center;align-items:center;gap:10px;margin-top:12px;display:flex}.lc-ov-pager-btn{border:1px solid var(--dsw-alias-border-l2);width:26px;height:22px;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;transition:border-color var(--ds-transition-duration,.2s) var(--ds-ease-in-out,ease-in-out);background:0 0;border-radius:6px;flex:none;justify-content:center;align-items:center;line-height:1;display:flex}.lc-ov-pager-btn:hover:enabled{border-color:var(--dsw-alias-label-secondary)}.lc-ov-pager-btn:disabled{opacity:.4;cursor:default}.lc-ov-pager-n{color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:11px}";
|
|
13163
13431
|
const tagId = "dsh-context/overview.css";
|
|
13164
13432
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
13165
13433
|
const tag = document.createElement("style");
|
|
@@ -13238,24 +13506,8 @@ window.__ModuleLoader__.load({
|
|
|
13238
13506
|
inject: (sessionId = "") => ({ hooks: { contextModal: modalStoreOf(sessionId) } })
|
|
13239
13507
|
}, (props) => (0, react.createElement)(ContextModal, props));
|
|
13240
13508
|
});
|
|
13241
|
-
const OverviewButton = makeOverviewButton(kit, settings);
|
|
13242
|
-
ctx.slots.inject("sidebar.footer.action", () => {
|
|
13243
|
-
return ctx.slots.register({
|
|
13244
|
-
name: "sidebar.footer.action",
|
|
13245
|
-
id: "context-overview",
|
|
13246
|
-
order: 10,
|
|
13247
|
-
locale: NS
|
|
13248
|
-
}, (props) => (0, react.createElement)(OverviewButton, props));
|
|
13249
|
-
});
|
|
13250
13509
|
const OverviewPanel = makeOverviewPanel(ctx, kit);
|
|
13251
|
-
ctx.
|
|
13252
|
-
return ctx.slots.register({
|
|
13253
|
-
name: "shell.overlay",
|
|
13254
|
-
id: "context-overview",
|
|
13255
|
-
order: 10,
|
|
13256
|
-
locale: NS
|
|
13257
|
-
}, (props) => (0, react.createElement)(OverviewPanel, props));
|
|
13258
|
-
});
|
|
13510
|
+
ctx.effect(() => watchInsightPage(ctx, settings, (props) => (0, react.createElement)(OverviewPanel, props), t, NS), "dsh-context: insight page");
|
|
13259
13511
|
/** The injected face both preference cards ride: the settings store as the
|
|
13260
13512
|
* framework's hooks-compartment `useContextSettings` seat, plus the set verb. */
|
|
13261
13513
|
const cardFace = () => ({
|