dsh-token-total 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +145 -125
- package/lib/index.js +100 -27
- package/lib/types/client/format.d.ts +1 -1
- package/lib/types/client/session-usage-locales.d.ts +3 -0
- package/lib/types/client/use-session-detail.d.ts +4 -1
- package/lib/types/shared.d.ts +15 -0
- package/lib/types/wire.d.ts +5 -0
- package/package.json +1 -1
- package/src/client/SessionUsageView.module.css +29 -18
- package/src/client/SessionUsageView.tsx +41 -27
- package/src/client/format.ts +1 -1
- package/src/client/session-usage-locales.ts +3 -0
- package/src/client/use-session-detail.ts +16 -7
- package/src/model-names.ts +14 -4
- package/src/session-detail.ts +93 -25
- package/src/shared.ts +23 -0
- package/src/wire.ts +5 -0
package/lib/client.js
CHANGED
|
@@ -29650,6 +29650,20 @@ window.__ModuleLoader__.load({
|
|
|
29650
29650
|
}
|
|
29651
29651
|
return out;
|
|
29652
29652
|
}
|
|
29653
|
+
/** Decode throughput across rows: Σ(output tokens) / Σ(decode window), matching
|
|
29654
|
+
* the `sessionStats` projection's decodeTokens/decodeMs rate that the composer
|
|
29655
|
+
* bottom bar shows. Rows without a decode window (failed attempts, cancelled
|
|
29656
|
+
* steps, running requests) are excluded, so the card, the turn summaries and
|
|
29657
|
+
* the bottom bar all report one speed. */
|
|
29658
|
+
function decodeRateOf(rows) {
|
|
29659
|
+
let ms = 0;
|
|
29660
|
+
let tokens = 0;
|
|
29661
|
+
for (const row of rows) if (typeof row.decodeMs === "number" && Number.isFinite(row.decodeMs)) {
|
|
29662
|
+
ms += row.decodeMs;
|
|
29663
|
+
tokens += row.totals.outputTokens;
|
|
29664
|
+
}
|
|
29665
|
+
return ms > 0 ? tokens / (ms / 1e3) : null;
|
|
29666
|
+
}
|
|
29653
29667
|
/** Canonicalize a DISPLAY NAME, never a route id. Case and word separators
|
|
29654
29668
|
* do not distinguish models, but versions, punctuation and suffixes do:
|
|
29655
29669
|
* gpt-6.1-sol / GPT 6.1 sol -> gpt-6.1-sol, not gpt-6.1 or gpt-61-sol.
|
|
@@ -32638,6 +32652,7 @@ window.__ModuleLoader__.load({
|
|
|
32638
32652
|
(0, react.useEffect)(() => {
|
|
32639
32653
|
let active = true;
|
|
32640
32654
|
let pending = false;
|
|
32655
|
+
let wantedNow = false;
|
|
32641
32656
|
let timer;
|
|
32642
32657
|
let controller;
|
|
32643
32658
|
const request = () => {
|
|
@@ -32649,23 +32664,29 @@ window.__ModuleLoader__.load({
|
|
|
32649
32664
|
if (active) setReading({
|
|
32650
32665
|
sessionId,
|
|
32651
32666
|
detail,
|
|
32652
|
-
error: false
|
|
32667
|
+
error: false,
|
|
32668
|
+
updatedAt: Date.now()
|
|
32653
32669
|
});
|
|
32654
32670
|
}).catch(() => {
|
|
32655
32671
|
if (active) setReading((previous) => ({
|
|
32656
32672
|
sessionId,
|
|
32657
32673
|
detail: previous?.sessionId === sessionId ? previous.detail : null,
|
|
32658
|
-
error: true
|
|
32674
|
+
error: true,
|
|
32675
|
+
updatedAt: previous?.sessionId === sessionId ? previous.updatedAt : null
|
|
32659
32676
|
}));
|
|
32660
32677
|
}).finally(() => {
|
|
32661
32678
|
pending = false;
|
|
32662
|
-
if (active) timer = setTimeout(request, DETAIL_POLL_MS);
|
|
32679
|
+
if (active) timer = setTimeout(request, wantedNow ? 0 : DETAIL_POLL_MS);
|
|
32680
|
+
wantedNow = false;
|
|
32663
32681
|
});
|
|
32664
32682
|
};
|
|
32665
32683
|
const wake = () => {
|
|
32666
32684
|
if (document.visibilityState === "visible") request();
|
|
32667
32685
|
};
|
|
32668
|
-
refresh.current =
|
|
32686
|
+
refresh.current = () => {
|
|
32687
|
+
if (pending) wantedNow = true;
|
|
32688
|
+
else request();
|
|
32689
|
+
};
|
|
32669
32690
|
document.addEventListener("visibilitychange", wake);
|
|
32670
32691
|
request();
|
|
32671
32692
|
return () => {
|
|
@@ -32681,7 +32702,8 @@ window.__ModuleLoader__.load({
|
|
|
32681
32702
|
detail: current?.detail ?? null,
|
|
32682
32703
|
loading: current === null,
|
|
32683
32704
|
error: current?.error ?? false,
|
|
32684
|
-
|
|
32705
|
+
refresh: () => refresh.current?.(),
|
|
32706
|
+
updatedAt: current?.updatedAt ?? null
|
|
32685
32707
|
};
|
|
32686
32708
|
}
|
|
32687
32709
|
//#endregion
|
|
@@ -32854,7 +32876,7 @@ window.__ModuleLoader__.load({
|
|
|
32854
32876
|
}
|
|
32855
32877
|
//#endregion
|
|
32856
32878
|
//#region \0token-total-css:/home/runner/work/dsh-token-total/dsh-token-total/src/client/SessionUsageView.module.css?inline
|
|
32857
|
-
const css = "/* A light, self-contained Usage surface. Tables fit the available width:\n * no horizontal scroll containers, fixed column contracts, titles for names.\n * Stat cards follow the reference dashboard: tinted left edge + icon chip,\n * label, big value, small subtitle. Request log folds by conversation turn. */\n.scroll_900471699 { height:100%; min-height:0; overflow-y:auto; background:#ffffff; color:#252936; color-scheme:light; container-type:inline-size; }\n.page_900471699 { box-sizing:border-box; width:100%; max-width:1160px; margin:0 auto; padding:24px 26px 32px; font-family:system-ui,-apple-system,\"Segoe UI\",sans-serif; font-size:13px; }\n.page_900471699 * { box-sizing:border-box; }\n.scope_900471699 { color:#8790a3; font-size:11px; margin:0 0 14px; }\n.stats_900471699 { display:grid; gap:12px; margin-bottom:18px; }\n.statRow_900471699 { display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:12px; }\n.stat_900471699 { min-width:0; position:relative; overflow:hidden; background:#fff; border:1px solid #e4e7ee; border-left:4px solid var(--tone); border-radius:12px; padding:12px 16px 11px; }\n.statHead_900471699 { display:flex; align-items:center; gap:8px; margin-bottom:8px; }\n.statIcon_900471699 { display:flex; align-items:center; justify-content:center; width:32px; height:32px; border-radius:10px; color:#fff; background:linear-gradient(135deg, var(--tone), var(--tone-soft)); flex-shrink:0; box-shadow:0 3px 8px var(--tone-soft); }\n.statMark_900471699 { position:absolute; right:-14px; bottom:-18px; width:92px; height:92px; color:var(--tone); pointer-events:none; }\n.statLabel_900471699 { font-size:12px; color:#7d8495; }\n.statValue_900471699 { display:block; font-size:25px; font-weight:650; letter-spacing:-0.5px; white-space:nowrap; font-variant-numeric:tabular-nums; }\n.statSub_900471699 { display:block; margin-top:5px; font-size:11px; color:#939aac; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }\n.toneBlue_900471699 { --tone:#4f79f6; --tone-soft:#eaf0fe; }\n.tonePurple_900471699 { --tone:#8b5cf6; --tone-soft:#f1ebfe; }\n.toneGreen_900471699 { --tone:#18a97b; --tone-soft:#e5f6f0; }\n.toneOrange_900471699 { --tone:#e8892c; --tone-soft:#fcf1e4; }\n.toneTeal_900471699 { --tone:#16a4b8; --tone-soft:#e4f5f8; }\n.tonePink_900471699 { --tone:#d9538c; --tone-soft:#fbeaf1; }\n.card_900471699 { min-width:0; background:#fff; border:1px solid #e4e7ee; border-radius:12px; margin-bottom:18px; overflow:hidden; }\n.cardHead_900471699 { display:flex; align-items:center; justify-content:space-between; gap:10px; min-height:54px; padding:15px 18px; border-bottom:1px solid #eef0f4; }\n.cardHead_900471699 h2 { font-size:14px; font-weight:600; margin:0; }\n.cardHead_900471699 > span { display:flex; gap:7px; align-items:center; font-size:11px; }\n.count_900471699 { display:inline-flex; align-items:center; justify-content:center; min-width:21px; padding:2px 6px; font-size:10px; color:#8b93a3; background:#f3f5f8; border-radius:5px; margin-left:5px; font-weight:500; }\n.mid_900471699 { display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:18px; align-items:stretch; }\n.mid_900471699 .card_900471699 { height:100%; margin-bottom:0; }\n.mid_900471699 { margin-bottom:18px; }\n.table_900471699 { border-collapse:collapse; width:100%; table-layout:fixed; font-size:11px; }\n.table_900471699 th { color:#929aaa; font-weight:500; padding:12px 5px; text-align:right; vertical-align:middle; line-height:1.3; overflow-wrap:anywhere; }\n.table_900471699 td { padding:13px 5px; text-align:right; border-top:1px solid #eef0f4; color:#626c80; font-variant-numeric:tabular-nums; white-space:nowrap; }\n.table_900471699 th:first-child,.table_900471699 td:first-child { text-align:left; padding-left:16px; }\n.table_900471699 th:last-child,.table_900471699 td:last-child { padding-right:16px; }\n.childName_900471699 { width:28%; }\n.childRequests_900471699 { width:11%; }\n.modelName_900471699 { width:30%; }\n.modelRequests_900471699 { width:11%; }\n.modelHit_900471699 { width:16%; }\n.ellipsis_900471699 { display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:#394354; }\n/* By-model rows lead with the model's brand logo; the name keeps truncating\n * inside the flexible remainder of the cell. */\n.modelNameCell_900471699 { display:flex; align-items:center; gap:6px; min-width:0; }\n.modelNameCell_900471699 .ellipsis_900471699 { flex:1; min-width:0; }\n/* Gray provider label under a model name shown by several rows (同名模型). */\n.modelProvider_900471699 { display:block; margin-top:2px; font-size:10px; color:#939aaa; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }\n.number_900471699 { font-variant-numeric:tabular-nums; }\n.speedCell_900471699 { display:inline-flex; align-items:baseline; gap:3px; white-space:nowrap; }\n.speedCell_900471699 small { font-size:9px; color:#929aaa; }\n.good_900471699 { color:#21a17b; }\n.warn_900471699 { color:#d69a21; }\n.bad_900471699 { color:#e06571; }\n.live_900471699 { color:#169bb3; }\n.muted_900471699 { color:#939aaa; }\n.empty_900471699 { margin:0; padding:28px 18px; color:#9aa2b1; font-size:12px; text-align:center; }\n.action_900471699 { color:#818b9e; background:none; border:0; padding:3px 0; font:inherit; font-size:11px; cursor:pointer; }\n.action_900471699:hover { color:#279cb6; }\n.action_900471699:focus-visible,.turnHead_900471699:focus-visible { outline:2px solid #2ab1c6; outline-offset:-2px; }\n.turnList_900471699 { padding:0 14px 14px; }\n.turn_900471699 { margin-top:10px; border:1px solid #e7eaf0; border-radius:9px; background:#fff; overflow:hidden; }\n.turnHead_900471699 { display:grid; grid-template-columns:12px minmax(0,1fr) auto; align-items:center; gap:12px; padding:13px 14px; width:100%; text-align:left; background:#f8f9fc; border:0; cursor:pointer; color:#616c7f; font:inherit; font-size:11px; }\n.chevron_900471699 { color:#99a1af; transition:transform 0.2s; }\n.rotated_900471699 { transform:rotate(90deg); }\n.turnTitle_900471699 { display:flex; align-items:center; gap:6px; min-width:0; font-size:12px; font-weight:600; color:#394354; }\n/* Turn topic is the group title now (the page header owns the session name),\n * so it carries the primary text color and truncates before the metrics. */\n.turnTopic_900471699 { min-width:0; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }\n/* A subagent's turns look like this session's turns apart from the agent tag;\n * the tag keeps the full session name in its tooltip. */\n.turnAgent_900471699 { flex:none; padding:1px 6px; border-radius:5px; background:#e9edf4; color:#6f7889; font-size:10px; font-weight:500; }\n.turnSummary_900471699 { display:flex; gap:5px; align-items:center; white-space:nowrap; }\n.turnSummary_900471699 > span:last-child { margin-left:8px; }\n.turnBody_900471699 { border-top:1px solid #eef0f4; }\n.turnBody_900471699[hidden] { display:none; }\n/* A request row is one line: time, what answered, and its metrics pinned to the\n * row end. The metrics never wrap; they truncate with a tooltip before the head\n * gives up its model name. */\n.turnRequest_900471699 { display:grid; grid-template-columns:64px minmax(0,1fr) auto; align-items:center; gap:12px; padding:10px 16px; border-top:1px solid #f3f5f9; }\n.turnRequest_900471699:first-child { border-top:0; }\n.turnRequestHead_900471699 { display:flex; align-items:center; gap:8px; font-size:11px; color:#616c7f; min-width:0; }\n.requestTime_900471699 { color:#9aa3b3; font-variant-numeric:tabular-nums; flex-shrink:0; }\n.statusDot_900471699 { width:5px; height:5px; border-radius:50%; background:currentColor; flex-shrink:0; }\n/* Per-model brand logo: colors are baked into each logo's markup, only the\n * layout contract lives here. Unknown models get the neutral gray fallback. */\n.modelLogo_900471699 { flex-shrink:0; }\n.recordModel_900471699 { min-width:0; display:flex; align-items:center; gap:6px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; color:#394354; font-weight:500; }\n.routeText_900471699 { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; color:#8b93a4; flex-shrink:1; }\n.effort_900471699 { white-space:nowrap; color:#9aa3b3; background:#f1f3f7; border-radius:5px; padding:1px 6px; }\n.recordMeta_900471699 { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; text-align:right; font-size:10px; color:#949cab; font-variant-numeric:tabular-nums; }\n.note_900471699 { font-size:10px; line-height:1.7; color:#9aa3b3; margin:0; }\n.error_900471699 { background:#fff4f1; color:#b86751; border:1px solid #f4d8ce; border-radius:9px; padding:12px 16px; margin-bottom:16px; font-size:12px; display:flex; gap:16px; justify-content:space-between; }\n@container (max-width:1050px) {\n .mid_900471699 { grid-template-columns:minmax(0,1fr); }\n .statRow_900471699 { grid-template-columns:repeat(2,minmax(0,1fr)); }\n .statValue_900471699 { font-size:23px; }\n .table_900471699 { font-size:12px; }\n .childName_900471699 { width:34%; }\n}\n@container (max-width:700px) {\n .page_900471699 { padding:18px 14px 24px; }\n .stat_900471699 { padding:12px 12px 11px; }\n .statValue_900471699 { font-size:20px; }\n .table_900471699 { font-size:10px; }\n .table_900471699 th,.table_900471699 td { padding:10px 3px; }\n .table_900471699 th:first-child,.table_900471699 td:first-child { padding-left:10px; }\n .table_900471699 th:last-child,.table_900471699 td:last-child { padding-right:10px; }\n .childName_900471699 { width:25%; }\n .childRequests_900471699 { width:11%; }\n .modelName_900471699 { width:25%; }\n .modelRequests_900471699 { width:11%; }\n .modelHit_900471699 { width:17%; }\n .turnHead_900471699 { gap:8px; padding:11px 10px; }\n .turnSummary_900471699 { grid-column:2; font-size:10px; }\n .turnRequest_900471699 { grid-template-columns:56px minmax(120px,1fr) auto; gap:8px; padding:10px; }\n .turnRequestHead_900471699 { gap:6px; }\n .routeText_900471699 { display:none; }\n}\n@media (prefers-reduced-motion:reduce) {\n .chevron_900471699 { transition:none; }\n}\n";
|
|
32879
|
+
const css = "/* A light, self-contained Usage surface. Tables fit the available width:\n * no horizontal scroll containers, fixed column contracts, titles for names.\n * Six stat cards sit in one row (≤1050px: 3-up, ≤700px: 2-up) as quiet white\n * surfaces on a pale canvas: no accent edges or watermarks, a flat tone chip\n * leading each label, hierarchy from the type scale and a hairline above the\n * footnote. Request log folds by conversation turn. */\n.scroll_900471699 { height:100%; min-height:0; overflow-y:auto; background:#f6f7f9; color:#252936; color-scheme:light; container-type:inline-size; }\n.page_900471699 { box-sizing:border-box; width:100%; max-width:1160px; margin:0 auto; padding:24px 26px 32px; font-family:system-ui,-apple-system,\"Segoe UI\",sans-serif; font-size:13px; }\n.page_900471699 * { box-sizing:border-box; }\n/* Freshness header: live badge + last-read stamp on the left, manual refresh\n * pinned to the right edge. */\n.head_900471699 { display:flex; align-items:center; justify-content:space-between; gap:12px; margin:0 0 12px; }\n.headStatus_900471699 { display:flex; align-items:center; gap:7px; min-width:0; font-size:11px; color:#8790a3; }\n.liveDot_900471699 { width:6px; height:6px; border-radius:50%; background:#18a97b; box-shadow:0 0 0 3px #e5f6f0; flex-shrink:0; }\n.asOf_900471699 { color:#9aa3b3; font-variant-numeric:tabular-nums; white-space:nowrap; }\n.refresh_900471699 { display:inline-flex; align-items:center; gap:5px; flex:none; color:#6f7a8d; background:#fff; border:1px solid #e4e7ee; border-radius:8px; padding:5px 11px; font:inherit; font-size:11px; cursor:pointer; }\n.refresh_900471699:hover { color:#279cb6; border-color:#cbd3e0; }\n.refresh_900471699:disabled { opacity:.55; cursor:default; }\n.scope_900471699 { color:#8790a3; font-size:11px; margin:0 0 14px; }\n.stats_900471699 { display:grid; grid-template-columns:repeat(6,minmax(0,1fr)); gap:8px; margin-bottom:16px; }\n.stat_900471699 { min-width:0; position:relative; background:#fff; border:1px solid #e7eaf0; border-radius:12px; padding:12px 14px 11px; transition:border-color .18s ease, box-shadow .18s ease, transform .18s ease; }\n.stat_900471699:hover { border-color:#d9dfe9; box-shadow:0 14px 30px -22px rgba(23,32,54,.32); transform:translateY(-1px); }\n.statHead_900471699 { display:flex; align-items:center; gap:5px; margin-bottom:6px; }\n.statIcon_900471699 { display:flex; align-items:center; justify-content:center; width:20px; height:20px; border-radius:6px; color:var(--tone); background:var(--tone-soft); flex-shrink:0; }\n.statLabel_900471699 { font-size:12px; font-weight:500; color:#7b8494; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }\n.statValue_900471699 { display:block; font-size:21px; font-weight:650; letter-spacing:-0.4px; color:#1b2130; white-space:nowrap; font-variant-numeric:tabular-nums; }\n.statSub_900471699 { display:block; margin-top:8px; padding-top:7px; border-top:1px solid #f2f4f8; font-size:11px; color:#939aab; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }\n.toneBlue_900471699 { --tone:#4f79f6; --tone-soft:#eaf0fe; }\n.tonePurple_900471699 { --tone:#8b5cf6; --tone-soft:#f1ebfe; }\n.toneGreen_900471699 { --tone:#18a97b; --tone-soft:#e5f6f0; }\n.toneOrange_900471699 { --tone:#e8892c; --tone-soft:#fcf1e4; }\n.toneTeal_900471699 { --tone:#16a4b8; --tone-soft:#e4f5f8; }\n.card_900471699 { min-width:0; background:#fff; border:1px solid #e4e7ee; border-radius:12px; margin-bottom:18px; overflow:hidden; }\n.cardHead_900471699 { display:flex; align-items:center; justify-content:space-between; gap:10px; min-height:54px; padding:15px 18px; border-bottom:1px solid #eef0f4; }\n.cardHead_900471699 h2 { font-size:14px; font-weight:600; margin:0; }\n.cardHead_900471699 > span { display:flex; gap:7px; align-items:center; font-size:11px; }\n.count_900471699 { display:inline-flex; align-items:center; justify-content:center; min-width:21px; padding:2px 6px; font-size:10px; color:#8b93a3; background:#f3f5f8; border-radius:5px; margin-left:5px; font-weight:500; }\n.mid_900471699 { display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:18px; align-items:stretch; }\n.mid_900471699 .card_900471699 { height:100%; margin-bottom:0; }\n.mid_900471699 { margin-bottom:18px; }\n.table_900471699 { border-collapse:collapse; width:100%; table-layout:fixed; font-size:11px; }\n.table_900471699 th { color:#929aaa; font-weight:500; padding:12px 5px; text-align:right; vertical-align:middle; line-height:1.3; overflow-wrap:anywhere; }\n.table_900471699 td { padding:13px 5px; text-align:right; border-top:1px solid #eef0f4; color:#626c80; font-variant-numeric:tabular-nums; white-space:nowrap; }\n.table_900471699 th:first-child,.table_900471699 td:first-child { text-align:left; padding-left:16px; }\n.table_900471699 th:last-child,.table_900471699 td:last-child { padding-right:16px; }\n.childName_900471699 { width:28%; }\n.childRequests_900471699 { width:11%; }\n.modelName_900471699 { width:30%; }\n.modelRequests_900471699 { width:11%; }\n.modelHit_900471699 { width:16%; }\n.ellipsis_900471699 { display:block; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; color:#394354; }\n/* By-model rows lead with the model's brand logo; the name keeps truncating\n * inside the flexible remainder of the cell. */\n.modelNameCell_900471699 { display:flex; align-items:center; gap:6px; min-width:0; }\n.modelNameCell_900471699 .ellipsis_900471699 { flex:1; min-width:0; }\n/* Gray provider label under a model name shown by several rows (同名模型). */\n.modelProvider_900471699 { display:block; margin-top:2px; font-size:10px; color:#939aaa; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }\n.number_900471699 { font-variant-numeric:tabular-nums; }\n.speedCell_900471699 { display:inline-flex; align-items:baseline; gap:3px; white-space:nowrap; }\n.speedCell_900471699 small { font-size:9px; color:#929aaa; }\n.good_900471699 { color:#21a17b; }\n.warn_900471699 { color:#d69a21; }\n.bad_900471699 { color:#e06571; }\n.live_900471699 { color:#169bb3; }\n.muted_900471699 { color:#939aaa; }\n.empty_900471699 { margin:0; padding:28px 18px; color:#9aa2b1; font-size:12px; text-align:center; }\n.action_900471699 { color:#818b9e; background:none; border:0; padding:3px 0; font:inherit; font-size:11px; cursor:pointer; }\n.action_900471699:hover { color:#279cb6; }\n.action_900471699:focus-visible,.turnHead_900471699:focus-visible,.refresh_900471699:focus-visible { outline:2px solid #2ab1c6; outline-offset:-2px; }\n.turnList_900471699 { padding:0 14px 14px; }\n.turn_900471699 { margin-top:10px; border:1px solid #e7eaf0; border-radius:9px; background:#fff; overflow:hidden; }\n.turnHead_900471699 { display:grid; grid-template-columns:12px minmax(0,1fr) auto; align-items:center; gap:12px; padding:13px 14px; width:100%; text-align:left; background:#f8f9fc; border:0; cursor:pointer; color:#616c7f; font:inherit; font-size:11px; }\n.chevron_900471699 { color:#99a1af; transition:transform 0.2s; }\n.rotated_900471699 { transform:rotate(90deg); }\n.turnTitle_900471699 { display:flex; align-items:center; gap:6px; min-width:0; font-size:12px; font-weight:600; color:#394354; }\n/* Turn topic is the group title now (the page header owns the session name),\n * so it carries the primary text color and truncates before the metrics. */\n.turnTopic_900471699 { min-width:0; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }\n/* A subagent's turns look like this session's turns apart from the agent tag;\n * the tag keeps the full session name in its tooltip. */\n.turnAgent_900471699 { flex:none; padding:1px 6px; border-radius:5px; background:#e9edf4; color:#6f7889; font-size:10px; font-weight:500; }\n.turnSummary_900471699 { display:flex; gap:5px; align-items:center; white-space:nowrap; }\n.turnSummary_900471699 > span:last-child { margin-left:8px; }\n.turnBody_900471699 { border-top:1px solid #eef0f4; }\n.turnBody_900471699[hidden] { display:none; }\n/* A request row is one line: time, what answered, and its metrics pinned to the\n * row end. The metrics never wrap; they truncate with a tooltip before the head\n * gives up its model name. */\n.turnRequest_900471699 { display:grid; grid-template-columns:64px minmax(0,1fr) auto; align-items:center; gap:12px; padding:10px 16px; border-top:1px solid #f3f5f9; }\n.turnRequest_900471699:first-child { border-top:0; }\n.turnRequestHead_900471699 { display:flex; align-items:center; gap:8px; font-size:11px; color:#616c7f; min-width:0; }\n.requestTime_900471699 { color:#9aa3b3; font-variant-numeric:tabular-nums; flex-shrink:0; }\n.statusDot_900471699 { width:5px; height:5px; border-radius:50%; background:currentColor; flex-shrink:0; }\n/* Per-model brand logo: colors are baked into each logo's markup, only the\n * layout contract lives here. Unknown models get the neutral gray fallback. */\n.modelLogo_900471699 { flex-shrink:0; }\n.recordModel_900471699 { min-width:0; display:flex; align-items:center; gap:6px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; color:#394354; font-weight:500; }\n.routeText_900471699 { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; color:#8b93a4; flex-shrink:1; }\n.effort_900471699 { white-space:nowrap; color:#9aa3b3; background:#f1f3f7; border-radius:5px; padding:1px 6px; }\n.recordMeta_900471699 { min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; text-align:right; font-size:10px; color:#949cab; font-variant-numeric:tabular-nums; }\n.note_900471699 { font-size:10px; line-height:1.7; color:#9aa3b3; margin:0; }\n.error_900471699 { background:#fff4f1; color:#b86751; border:1px solid #f4d8ce; border-radius:9px; padding:12px 16px; margin-bottom:16px; font-size:12px; display:flex; gap:16px; justify-content:space-between; }\n@container (max-width:1050px) {\n .mid_900471699 { grid-template-columns:minmax(0,1fr); }\n .stats_900471699 { grid-template-columns:repeat(3,minmax(0,1fr)); }\n .table_900471699 { font-size:12px; }\n .childName_900471699 { width:34%; }\n}\n@container (max-width:700px) {\n .page_900471699 { padding:18px 14px 24px; }\n .stats_900471699 { grid-template-columns:repeat(2,minmax(0,1fr)); }\n .stat_900471699 { padding:10px 12px 9px; }\n .statValue_900471699 { font-size:18px; }\n .table_900471699 { font-size:10px; }\n .table_900471699 th,.table_900471699 td { padding:10px 3px; }\n .table_900471699 th:first-child,.table_900471699 td:first-child { padding-left:10px; }\n .table_900471699 th:last-child,.table_900471699 td:last-child { padding-right:10px; }\n .childName_900471699 { width:25%; }\n .childRequests_900471699 { width:11%; }\n .modelName_900471699 { width:25%; }\n .modelRequests_900471699 { width:11%; }\n .modelHit_900471699 { width:17%; }\n .turnHead_900471699 { gap:8px; padding:11px 10px; }\n .turnSummary_900471699 { grid-column:2; font-size:10px; }\n .turnRequest_900471699 { grid-template-columns:56px minmax(120px,1fr) auto; gap:8px; padding:10px; }\n .turnRequestHead_900471699 { gap:6px; }\n .routeText_900471699 { display:none; }\n}\n@media (prefers-reduced-motion:reduce) {\n .chevron_900471699 { transition:none; }\n .stat_900471699 { transition:none; }\n .stat_900471699:hover { transform:none; }\n}\n";
|
|
32858
32880
|
const tagId = "dsh-token-total/SessionUsageView.module.css";
|
|
32859
32881
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=\"" + tagId + "\"]") === null) {
|
|
32860
32882
|
const tag = document.createElement("style");
|
|
@@ -32866,13 +32888,16 @@ window.__ModuleLoader__.load({
|
|
|
32866
32888
|
var SessionUsageView_module_default = {
|
|
32867
32889
|
"scroll": "scroll_900471699",
|
|
32868
32890
|
"page": "page_900471699",
|
|
32891
|
+
"head": "head_900471699",
|
|
32892
|
+
"headStatus": "headStatus_900471699",
|
|
32893
|
+
"liveDot": "liveDot_900471699",
|
|
32894
|
+
"asOf": "asOf_900471699",
|
|
32895
|
+
"refresh": "refresh_900471699",
|
|
32869
32896
|
"scope": "scope_900471699",
|
|
32870
32897
|
"stats": "stats_900471699",
|
|
32871
|
-
"statRow": "statRow_900471699",
|
|
32872
32898
|
"stat": "stat_900471699",
|
|
32873
32899
|
"statHead": "statHead_900471699",
|
|
32874
32900
|
"statIcon": "statIcon_900471699",
|
|
32875
|
-
"statMark": "statMark_900471699",
|
|
32876
32901
|
"statLabel": "statLabel_900471699",
|
|
32877
32902
|
"statValue": "statValue_900471699",
|
|
32878
32903
|
"statSub": "statSub_900471699",
|
|
@@ -32881,7 +32906,6 @@ window.__ModuleLoader__.load({
|
|
|
32881
32906
|
"toneGreen": "toneGreen_900471699",
|
|
32882
32907
|
"toneOrange": "toneOrange_900471699",
|
|
32883
32908
|
"toneTeal": "toneTeal_900471699",
|
|
32884
|
-
"tonePink": "tonePink_900471699",
|
|
32885
32909
|
"card": "card_900471699",
|
|
32886
32910
|
"cardHead": "cardHead_900471699",
|
|
32887
32911
|
"count": "count_900471699",
|
|
@@ -32971,50 +32995,20 @@ window.__ModuleLoader__.load({
|
|
|
32971
32995
|
hit: "M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0ZM16 12a4 4 0 1 1-8 0 4 4 0 0 1 8 0Z",
|
|
32972
32996
|
speed: "M13 2 4 14h7l-1 8 9-12h-7l1-8Z",
|
|
32973
32997
|
input: "M12 3v12M7 10l5 5 5-5M4 21h16",
|
|
32974
|
-
output: "M12 21V9M7 14l5-5 5 5M4 3h16"
|
|
32975
|
-
read: "M2 12s4-7 10-7 10 7 10 7-4 7-10 7-10-7-10-7ZM15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z",
|
|
32976
|
-
write: "M12 20h9M16.5 3.5a2.1 2.1 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5Z"
|
|
32998
|
+
output: "M12 21V9M7 14l5-5 5 5M4 3h16"
|
|
32977
32999
|
};
|
|
32978
33000
|
function Stat({ tone, name, label, value, sub, title }) {
|
|
32979
33001
|
const icon = icons[name];
|
|
32980
33002
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
32981
33003
|
className: `${SessionUsageView_module_default.stat} ${tone}`,
|
|
32982
33004
|
children: [
|
|
32983
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
32984
|
-
className: SessionUsageView_module_default.statMark,
|
|
32985
|
-
viewBox: "0 0 24 24",
|
|
32986
|
-
"aria-hidden": "true",
|
|
32987
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("defs", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("linearGradient", {
|
|
32988
|
-
id: `usage-mark-${name}`,
|
|
32989
|
-
x1: "0",
|
|
32990
|
-
y1: "0",
|
|
32991
|
-
x2: "1",
|
|
32992
|
-
y2: "1",
|
|
32993
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("stop", {
|
|
32994
|
-
offset: "0",
|
|
32995
|
-
stopColor: "currentColor",
|
|
32996
|
-
stopOpacity: "0.3"
|
|
32997
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("stop", {
|
|
32998
|
-
offset: "1",
|
|
32999
|
-
stopColor: "currentColor",
|
|
33000
|
-
stopOpacity: "0.03"
|
|
33001
|
-
})]
|
|
33002
|
-
}) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
33003
|
-
d: icon,
|
|
33004
|
-
fill: `url(#usage-mark-${name})`,
|
|
33005
|
-
stroke: `url(#usage-mark-${name})`,
|
|
33006
|
-
strokeWidth: "1.1",
|
|
33007
|
-
strokeLinecap: "round",
|
|
33008
|
-
strokeLinejoin: "round"
|
|
33009
|
-
})]
|
|
33010
|
-
}),
|
|
33011
33005
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
33012
33006
|
className: SessionUsageView_module_default.statHead,
|
|
33013
33007
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
33014
33008
|
className: SessionUsageView_module_default.statIcon,
|
|
33015
33009
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
33016
|
-
width: "
|
|
33017
|
-
height: "
|
|
33010
|
+
width: "12",
|
|
33011
|
+
height: "12",
|
|
33018
33012
|
viewBox: "0 0 24 24",
|
|
33019
33013
|
fill: "none",
|
|
33020
33014
|
stroke: "currentColor",
|
|
@@ -33047,76 +33041,53 @@ window.__ModuleLoader__.load({
|
|
|
33047
33041
|
const failRate = detail.requests > 0 ? (failed / detail.requests * 100).toFixed(1) : "0.0";
|
|
33048
33042
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
33049
33043
|
className: SessionUsageView_module_default.stats,
|
|
33050
|
-
children: [
|
|
33051
|
-
|
|
33052
|
-
|
|
33053
|
-
|
|
33054
|
-
|
|
33055
|
-
|
|
33056
|
-
|
|
33057
|
-
|
|
33058
|
-
|
|
33059
|
-
|
|
33060
|
-
|
|
33061
|
-
|
|
33062
|
-
|
|
33063
|
-
|
|
33064
|
-
|
|
33065
|
-
|
|
33066
|
-
|
|
33067
|
-
|
|
33068
|
-
|
|
33069
|
-
|
|
33070
|
-
|
|
33071
|
-
|
|
33072
|
-
|
|
33073
|
-
|
|
33074
|
-
|
|
33075
|
-
|
|
33076
|
-
|
|
33077
|
-
|
|
33078
|
-
|
|
33079
|
-
|
|
33080
|
-
|
|
33081
|
-
|
|
33082
|
-
|
|
33083
|
-
|
|
33084
|
-
|
|
33085
|
-
|
|
33086
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
33087
|
-
|
|
33088
|
-
|
|
33089
|
-
|
|
33090
|
-
|
|
33091
|
-
|
|
33092
|
-
|
|
33093
|
-
|
|
33094
|
-
|
|
33095
|
-
|
|
33096
|
-
|
|
33097
|
-
label: t("outputFull"),
|
|
33098
|
-
value: formatCompact(detail.totals.outputTokens),
|
|
33099
|
-
title: formatTokens(detail.totals.outputTokens),
|
|
33100
|
-
sub: formatTokens(detail.totals.outputTokens)
|
|
33101
|
-
}),
|
|
33102
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stat, {
|
|
33103
|
-
tone: SessionUsageView_module_default.tonePurple,
|
|
33104
|
-
name: "read",
|
|
33105
|
-
label: t("readFull"),
|
|
33106
|
-
value: formatCompact(detail.totals.cacheReadTokens),
|
|
33107
|
-
title: formatTokens(detail.totals.cacheReadTokens),
|
|
33108
|
-
sub: formatTokens(detail.totals.cacheReadTokens)
|
|
33109
|
-
}),
|
|
33110
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stat, {
|
|
33111
|
-
tone: SessionUsageView_module_default.tonePink,
|
|
33112
|
-
name: "write",
|
|
33113
|
-
label: t("writeFull"),
|
|
33114
|
-
value: formatCompact(detail.totals.cacheWriteTokens),
|
|
33115
|
-
title: formatTokens(detail.totals.cacheWriteTokens),
|
|
33116
|
-
sub: formatTokens(detail.totals.cacheWriteTokens)
|
|
33117
|
-
})
|
|
33118
|
-
]
|
|
33119
|
-
})]
|
|
33044
|
+
children: [
|
|
33045
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stat, {
|
|
33046
|
+
tone: SessionUsageView_module_default.toneBlue,
|
|
33047
|
+
name: "requests",
|
|
33048
|
+
label: t("requestsCount"),
|
|
33049
|
+
value: formatTokens(detail.requests),
|
|
33050
|
+
sub: `${t("failed")} ${failed} · ${failRate}%`
|
|
33051
|
+
}),
|
|
33052
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stat, {
|
|
33053
|
+
tone: SessionUsageView_module_default.tonePurple,
|
|
33054
|
+
name: "tokens",
|
|
33055
|
+
label: t("tokens"),
|
|
33056
|
+
value: formatCompact(billed),
|
|
33057
|
+
title: formatTokens(billed),
|
|
33058
|
+
sub: `${formatTokens(billed)} tokens`
|
|
33059
|
+
}),
|
|
33060
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stat, {
|
|
33061
|
+
tone: SessionUsageView_module_default.toneTeal,
|
|
33062
|
+
name: "input",
|
|
33063
|
+
label: t("inputFull"),
|
|
33064
|
+
value: formatCompact(detail.totals.uncachedInputTokens),
|
|
33065
|
+
title: formatTokens(detail.totals.uncachedInputTokens),
|
|
33066
|
+
sub: formatTokens(detail.totals.uncachedInputTokens)
|
|
33067
|
+
}),
|
|
33068
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stat, {
|
|
33069
|
+
tone: SessionUsageView_module_default.toneOrange,
|
|
33070
|
+
name: "output",
|
|
33071
|
+
label: t("outputFull"),
|
|
33072
|
+
value: formatCompact(detail.totals.outputTokens),
|
|
33073
|
+
title: formatTokens(detail.totals.outputTokens),
|
|
33074
|
+
sub: formatTokens(detail.totals.outputTokens)
|
|
33075
|
+
}),
|
|
33076
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stat, {
|
|
33077
|
+
tone: SessionUsageView_module_default.toneGreen,
|
|
33078
|
+
name: "hit",
|
|
33079
|
+
label: t("hit"),
|
|
33080
|
+
value: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Hit, { totals: detail.totals }),
|
|
33081
|
+
sub: `${formatCompact(detail.totals.cacheReadTokens)} ${t("cacheHit")}`
|
|
33082
|
+
}),
|
|
33083
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Stat, {
|
|
33084
|
+
tone: SessionUsageView_module_default.toneOrange,
|
|
33085
|
+
name: "speed",
|
|
33086
|
+
label: t("speed"),
|
|
33087
|
+
value: speed(detail.tokensPerSecond),
|
|
33088
|
+
sub: `${t("first")} ${seconds(detail.averageFirstTokenMs)}`
|
|
33089
|
+
})
|
|
33090
|
+
]
|
|
33120
33091
|
});
|
|
33121
33092
|
}
|
|
33122
33093
|
function Tables({ detail, t }) {
|
|
@@ -33290,6 +33261,8 @@ window.__ModuleLoader__.load({
|
|
|
33290
33261
|
}
|
|
33291
33262
|
group.rows.push(record);
|
|
33292
33263
|
}
|
|
33264
|
+
const latest = (group) => group.rows.reduce((max, row) => Math.max(max, row.startedAt), 0);
|
|
33265
|
+
groups.sort((a, b) => latest(b) - latest(a));
|
|
33293
33266
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
33294
33267
|
className: SessionUsageView_module_default.card,
|
|
33295
33268
|
children: [
|
|
@@ -33316,8 +33289,8 @@ window.__ModuleLoader__.load({
|
|
|
33316
33289
|
const totals = sum(group.rows);
|
|
33317
33290
|
const billed = billedTotal(totals);
|
|
33318
33291
|
const running = group.rows.filter((row) => row.status === "running").length;
|
|
33319
|
-
const
|
|
33320
|
-
const avgRate =
|
|
33292
|
+
const rate = decodeRateOf(group.rows);
|
|
33293
|
+
const avgRate = rate === null ? null : Math.round(rate);
|
|
33321
33294
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
|
|
33322
33295
|
className: SessionUsageView_module_default.turn,
|
|
33323
33296
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
@@ -33388,7 +33361,7 @@ window.__ModuleLoader__.load({
|
|
|
33388
33361
|
id: `usage-turn-${encodeURIComponent(group.key)}`,
|
|
33389
33362
|
className: SessionUsageView_module_default.turnBody,
|
|
33390
33363
|
hidden: !open,
|
|
33391
|
-
children: group.rows.map((record) => {
|
|
33364
|
+
children: group.rows.slice().reverse().map((record) => {
|
|
33392
33365
|
const duration = record.finishedAt !== null ? record.finishedAt - record.startedAt : null;
|
|
33393
33366
|
const billed = billedTotal(record.totals);
|
|
33394
33367
|
const hit = cacheHitPercentOf(record.totals);
|
|
@@ -33431,14 +33404,14 @@ window.__ModuleLoader__.load({
|
|
|
33431
33404
|
modelShort(record.model) || "—"
|
|
33432
33405
|
]
|
|
33433
33406
|
}),
|
|
33434
|
-
statusText !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
33435
|
-
className: record.status === "running" ? SessionUsageView_module_default.live : record.status === "failed" ? SessionUsageView_module_default.bad : SessionUsageView_module_default.muted,
|
|
33436
|
-
children: statusText
|
|
33437
|
-
}),
|
|
33438
33407
|
record.effort ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
33439
33408
|
className: SessionUsageView_module_default.effort,
|
|
33440
33409
|
children: ["· ", record.effort]
|
|
33441
|
-
}) : null
|
|
33410
|
+
}) : null,
|
|
33411
|
+
statusText !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
33412
|
+
className: record.status === "running" ? SessionUsageView_module_default.live : record.status === "failed" ? SessionUsageView_module_default.bad : SessionUsageView_module_default.muted,
|
|
33413
|
+
children: statusText
|
|
33414
|
+
})
|
|
33442
33415
|
]
|
|
33443
33416
|
}),
|
|
33444
33417
|
record.finishedAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -33488,13 +33461,51 @@ window.__ModuleLoader__.load({
|
|
|
33488
33461
|
] });
|
|
33489
33462
|
}
|
|
33490
33463
|
function SessionUsageView({ sessionId, t }) {
|
|
33491
|
-
const { detail, loading, error,
|
|
33464
|
+
const { detail, loading, error, refresh, updatedAt } = useSessionDetail(sessionId);
|
|
33492
33465
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
33493
33466
|
className: SessionUsageView_module_default.scroll,
|
|
33494
33467
|
"data-dsh-session-usage": true,
|
|
33495
33468
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
33496
33469
|
className: SessionUsageView_module_default.page,
|
|
33497
33470
|
children: [
|
|
33471
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
33472
|
+
className: SessionUsageView_module_default.head,
|
|
33473
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
33474
|
+
className: SessionUsageView_module_default.headStatus,
|
|
33475
|
+
children: [
|
|
33476
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
33477
|
+
className: SessionUsageView_module_default.liveDot,
|
|
33478
|
+
"aria-hidden": "true"
|
|
33479
|
+
}),
|
|
33480
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("live") }),
|
|
33481
|
+
updatedAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
33482
|
+
className: SessionUsageView_module_default.asOf,
|
|
33483
|
+
children: [
|
|
33484
|
+
t("asOf"),
|
|
33485
|
+
" ",
|
|
33486
|
+
clock(updatedAt)
|
|
33487
|
+
]
|
|
33488
|
+
})
|
|
33489
|
+
]
|
|
33490
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
33491
|
+
type: "button",
|
|
33492
|
+
className: SessionUsageView_module_default.refresh,
|
|
33493
|
+
onClick: refresh,
|
|
33494
|
+
disabled: loading,
|
|
33495
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
33496
|
+
width: "12",
|
|
33497
|
+
height: "12",
|
|
33498
|
+
viewBox: "0 0 24 24",
|
|
33499
|
+
fill: "none",
|
|
33500
|
+
stroke: "currentColor",
|
|
33501
|
+
strokeWidth: "2",
|
|
33502
|
+
strokeLinecap: "round",
|
|
33503
|
+
strokeLinejoin: "round",
|
|
33504
|
+
"aria-hidden": "true",
|
|
33505
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M21 3v5h-5" })]
|
|
33506
|
+
}), t("refresh")]
|
|
33507
|
+
})]
|
|
33508
|
+
}),
|
|
33498
33509
|
loading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
33499
33510
|
className: SessionUsageView_module_default.empty,
|
|
33500
33511
|
role: "status",
|
|
@@ -33506,7 +33517,7 @@ window.__ModuleLoader__.load({
|
|
|
33506
33517
|
children: [t("failedLoad"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
33507
33518
|
type: "button",
|
|
33508
33519
|
className: SessionUsageView_module_default.action,
|
|
33509
|
-
onClick:
|
|
33520
|
+
onClick: refresh,
|
|
33510
33521
|
children: t("retry")
|
|
33511
33522
|
})]
|
|
33512
33523
|
}),
|
|
@@ -33577,7 +33588,10 @@ window.__ModuleLoader__.load({
|
|
|
33577
33588
|
cacheShort: "缓存",
|
|
33578
33589
|
avgCache: "平均缓存",
|
|
33579
33590
|
avgRate: "平均速率",
|
|
33580
|
-
inProgress: "个进行中"
|
|
33591
|
+
inProgress: "个进行中",
|
|
33592
|
+
live: "实时更新",
|
|
33593
|
+
asOf: "统计截至",
|
|
33594
|
+
refresh: "刷新"
|
|
33581
33595
|
};
|
|
33582
33596
|
const usageEn = {
|
|
33583
33597
|
tab: "Usage",
|
|
@@ -33634,7 +33648,10 @@ window.__ModuleLoader__.load({
|
|
|
33634
33648
|
cacheShort: "cache",
|
|
33635
33649
|
avgCache: "avg cache",
|
|
33636
33650
|
avgRate: "avg rate",
|
|
33637
|
-
inProgress: "in progress"
|
|
33651
|
+
inProgress: "in progress",
|
|
33652
|
+
live: "Live",
|
|
33653
|
+
asOf: "as of",
|
|
33654
|
+
refresh: "Refresh"
|
|
33638
33655
|
};
|
|
33639
33656
|
const usageZhTW = {
|
|
33640
33657
|
...usageZh,
|
|
@@ -33691,7 +33708,10 @@ window.__ModuleLoader__.load({
|
|
|
33691
33708
|
cacheShort: "快取",
|
|
33692
33709
|
avgCache: "平均快取",
|
|
33693
33710
|
avgRate: "平均速率",
|
|
33694
|
-
inProgress: "個進行中"
|
|
33711
|
+
inProgress: "個進行中",
|
|
33712
|
+
live: "即時更新",
|
|
33713
|
+
asOf: "統計截至",
|
|
33714
|
+
refresh: "重新整理"
|
|
33695
33715
|
};
|
|
33696
33716
|
//#endregion
|
|
33697
33717
|
//#region src/client/index.tsx
|