@cassius0924/dsh-usage-dashboard 0.4.0 → 0.5.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/lib/client.js +312 -69
- package/lib/client.js.map +4 -4
- package/lib/index.js +18 -3
- package/lib/index.js.map +2 -2
- package/lib/types/client/api.d.ts +2 -0
- package/lib/types/client/context.d.ts +3 -0
- package/lib/types/client/dashboard.d.ts +2 -0
- package/lib/types/client/dom.d.ts +5 -0
- package/lib/types/client/locales.d.ts +9 -1
- package/lib/types/client/message-cost.d.ts +10 -0
- package/lib/types/client/store.d.ts +4 -0
- package/lib/types/client/styles.d.ts +1 -1
- package/lib/types/client/views.d.ts +23 -0
- package/lib/types/client/widget.d.ts +10 -1
- package/lib/types/context.d.ts +7 -0
- package/lib/types/contract.d.ts +12 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -190,6 +190,26 @@ async function fetchUsage(force = false) {
|
|
|
190
190
|
return task;
|
|
191
191
|
}
|
|
192
192
|
var sessionUsageInflight = /* @__PURE__ */ new Map();
|
|
193
|
+
var sessionUsageCache = /* @__PURE__ */ new Map();
|
|
194
|
+
var sessionUsageListeners = /* @__PURE__ */ new Map();
|
|
195
|
+
var getCachedSessionUsage = (sessionId) => sessionUsageCache.get(sessionId) ?? null;
|
|
196
|
+
var subscribeSessionUsage = (sessionId, fn) => {
|
|
197
|
+
let listeners = sessionUsageListeners.get(sessionId);
|
|
198
|
+
if (listeners === void 0) {
|
|
199
|
+
listeners = /* @__PURE__ */ new Set();
|
|
200
|
+
sessionUsageListeners.set(sessionId, listeners);
|
|
201
|
+
}
|
|
202
|
+
listeners.add(fn);
|
|
203
|
+
return () => {
|
|
204
|
+
listeners?.delete(fn);
|
|
205
|
+
if (listeners?.size === 0) sessionUsageListeners.delete(sessionId);
|
|
206
|
+
};
|
|
207
|
+
};
|
|
208
|
+
var publishSessionUsage = (sessionId, response) => {
|
|
209
|
+
if (!response.ok) return;
|
|
210
|
+
sessionUsageCache.set(sessionId, response);
|
|
211
|
+
for (const listener of [...sessionUsageListeners.get(sessionId) ?? []]) listener();
|
|
212
|
+
};
|
|
193
213
|
async function fetchSessionUsage(sessionId, force = false) {
|
|
194
214
|
if (typeof sessionId !== "string" || sessionId === "") {
|
|
195
215
|
return { ok: false, error: "\u7F3A\u5C11\u4F1A\u8BDD id" };
|
|
@@ -198,7 +218,10 @@ async function fetchSessionUsage(sessionId, force = false) {
|
|
|
198
218
|
const inflight = sessionUsageInflight.get(sessionId);
|
|
199
219
|
if (inflight !== void 0) return inflight;
|
|
200
220
|
}
|
|
201
|
-
const task = getJson(`/api/dsh-usage-dashboard/session?id=${encodeURIComponent(sessionId)}`, "no-store")
|
|
221
|
+
const task = getJson(`/api/dsh-usage-dashboard/session?id=${encodeURIComponent(sessionId)}`, "no-store").then((response) => {
|
|
222
|
+
publishSessionUsage(sessionId, response);
|
|
223
|
+
return response;
|
|
224
|
+
});
|
|
202
225
|
if (force) return task;
|
|
203
226
|
const tracked = task.finally(() => {
|
|
204
227
|
if (sessionUsageInflight.get(sessionId) === tracked) sessionUsageInflight.delete(sessionId);
|
|
@@ -484,7 +507,10 @@ var zh = {
|
|
|
484
507
|
"links.status": "\u670D\u52A1\u72B6\u6001",
|
|
485
508
|
"settings.title": "\u8BBE\u7F6E",
|
|
486
509
|
"settings.widget": "\u5728\u5176\u4ED6\u9875\u9762\u663E\u793A\u53F3\u4E0B\u89D2\u60AC\u6D6E\u989D\u5EA6\u7A97\u53E3",
|
|
487
|
-
"settings.widgetHint": "\
|
|
510
|
+
"settings.widgetHint": "\u989D\u5EA6\u9875\u4F1A\u81EA\u52A8\u9690\u85CF\u6D6E\u7A97\uFF1B\u5176\u4ED6\u9875\u9762\u662F\u5426\u5C55\u793A\u7531\u4E0B\u65B9\u9009\u62E9\u51B3\u5B9A\u3002",
|
|
511
|
+
"settings.widgetTabs": "\u5C55\u793A\u6D6E\u7A97\u7684\u9875\u9762",
|
|
512
|
+
"settings.widgetTabsHint": "\u9875\u9762\u5217\u8868\u6765\u81EA DSH \u7684\u5B9E\u65F6 Tab \u6CE8\u518C\u8868\uFF1B\u5176\u4ED6\u63D2\u4EF6\u65B0\u589E\u7684 Tab \u4E5F\u4F1A\u81EA\u52A8\u51FA\u73B0\u5728\u8FD9\u91CC\u3002",
|
|
513
|
+
"settings.widgetTabsEmpty": "\u5F53\u524D\u6CA1\u6709\u53EF\u914D\u7F6E\u7684\u4F1A\u8BDD\u9875\u9762\u3002",
|
|
488
514
|
"settings.lowBalance": "\u4F59\u989D\u9884\u8B66\u7EBF",
|
|
489
515
|
"settings.lowBalanceOn": "\u4F59\u989D\u4F4E\u4E8E {amount} {currency} \u65F6\uFF0C\u8FD9\u91CC\u548C\u60AC\u6D6E\u7A97\u90FD\u4F1A\u8F6C\u4E3A\u8B66\u793A\u8272\u3002\u586B 0 \u5173\u95ED\u3002",
|
|
490
516
|
"settings.lowBalanceOff": "\u5DF2\u5173\u95ED\u4F59\u989D\u9884\u8B66\u3002\u586B\u4E00\u4E2A\u5927\u4E8E 0 \u7684\u6570\u5F00\u542F\u3002",
|
|
@@ -497,6 +523,8 @@ var zh = {
|
|
|
497
523
|
"widget.lowTitle": "\u4F59\u989D\u4F4E\u4E8E\u9884\u8B66\u7EBF {amount}",
|
|
498
524
|
"widget.todayCostTitle": "\u4ECA\u65E5\u6D88\u8017\uFF08\u4F30\u7B97\uFF09\xB7 {age}",
|
|
499
525
|
"widget.todayCost": "\u4ECA\u65E5\u6D88\u8017",
|
|
526
|
+
"widget.sessionCostTitle": "\u5F53\u524D\u4F1A\u8BDD\u7D2F\u8BA1\u6D88\u8017\uFF08\u4F30\u7B97\uFF09",
|
|
527
|
+
"widget.sessionCost": "\u5F53\u524D\u4F1A\u8BDD",
|
|
500
528
|
"widget.noBalance": "\u6682\u65E0\u4F59\u989D\u6570\u636E",
|
|
501
529
|
"widget.dragCard": "\u62D6\u52A8\u5230\u56DB\u4E2A\u89D2\u843D",
|
|
502
530
|
"widget.dragGrip": "\u62D6\u52A8\u4EE5\u79FB\u52A8",
|
|
@@ -505,6 +533,9 @@ var zh = {
|
|
|
505
533
|
"widget.collapse": "\u6536\u8D77",
|
|
506
534
|
"widget.expandAria": "\u5C55\u5F00\u989D\u5EA6\u7A97\u53E3",
|
|
507
535
|
"widget.collapseAria": "\u6536\u8D77\u989D\u5EA6\u7A97\u53E3",
|
|
536
|
+
"messageCost.label": "\u672C\u8F6E\u8D39\u7528",
|
|
537
|
+
"messageCost.tooltip": "\u7531 dsh-usage-dashboard \u63D0\u4F9B \xB7 \u672C\u8F6E\u5BF9\u8BDD\u8D39\u7528\u4E3A\u4F30\u7B97\u503C",
|
|
538
|
+
"messageCost.aria": "{amount}\uFF0C\u672C\u8F6E\u5BF9\u8BDD\u4F30\u7B97\u8D39\u7528\uFF0C\u7531 dsh-usage-dashboard \u63D0\u4F9B",
|
|
508
539
|
"boundary.title": "\u989D\u5EA6\u9762\u677F\u51FA\u9519\u4E86",
|
|
509
540
|
"boundary.body": "\u6E32\u67D3\u65F6\u629B\u4E86\u5F02\u5E38\uFF0C\u901A\u5E38\u662F\u6D4F\u89C8\u5668\u91CC\u5B58\u7740\u65E7\u7248\u672C\u7684\u7F13\u5B58\u6570\u636E\u3002\u6E05\u6389\u672C\u63D2\u4EF6\u7684\u672C\u5730\u6570\u636E\u518D\u91CD\u65B0\u52A0\u8F7D\u5C31\u80FD\u6062\u590D\u3002",
|
|
510
541
|
"boundary.reset": "\u6E05\u9664\u672C\u5730\u6570\u636E\u5E76\u91CD\u65B0\u52A0\u8F7D"
|
|
@@ -725,7 +756,10 @@ var en = {
|
|
|
725
756
|
"links.status": "Service status",
|
|
726
757
|
"settings.title": "Settings",
|
|
727
758
|
"settings.widget": "Show the floating balance widget on other views",
|
|
728
|
-
"settings.widgetHint": "The widget hides
|
|
759
|
+
"settings.widgetHint": "The widget always hides on Usage; choose its other views below.",
|
|
760
|
+
"settings.widgetTabs": "Show widget on",
|
|
761
|
+
"settings.widgetTabsHint": "This live list comes from DSH\u2019s tab registry, including tabs added by other plugins.",
|
|
762
|
+
"settings.widgetTabsEmpty": "There are no configurable conversation views right now.",
|
|
729
763
|
"settings.lowBalance": "Balance warning",
|
|
730
764
|
"settings.lowBalanceOn": "This page and the widget turn amber below {amount} {currency}. Enter 0 to disable.",
|
|
731
765
|
"settings.lowBalanceOff": "Balance warnings are off. Enter an amount above 0 to enable them.",
|
|
@@ -738,6 +772,8 @@ var en = {
|
|
|
738
772
|
"widget.lowTitle": "Balance below warning threshold {amount}",
|
|
739
773
|
"widget.todayCostTitle": "Today\u2019s spend (estimated) \xB7 {age}",
|
|
740
774
|
"widget.todayCost": "Today\u2019s spend",
|
|
775
|
+
"widget.sessionCostTitle": "Estimated spend for the current session",
|
|
776
|
+
"widget.sessionCost": "Current session",
|
|
741
777
|
"widget.noBalance": "No balance data",
|
|
742
778
|
"widget.dragCard": "Drag to any corner",
|
|
743
779
|
"widget.dragGrip": "Drag to move",
|
|
@@ -746,6 +782,9 @@ var en = {
|
|
|
746
782
|
"widget.collapse": "Collapse",
|
|
747
783
|
"widget.expandAria": "Expand balance widget",
|
|
748
784
|
"widget.collapseAria": "Collapse balance widget",
|
|
785
|
+
"messageCost.label": "Turn cost",
|
|
786
|
+
"messageCost.tooltip": "Provided by dsh-usage-dashboard \xB7 estimated cost for this turn",
|
|
787
|
+
"messageCost.aria": "{amount}, estimated cost for this turn, provided by dsh-usage-dashboard",
|
|
749
788
|
"boundary.title": "The usage dashboard crashed",
|
|
750
789
|
"boundary.body": "Rendering failed, usually because this browser still has cached data from an older version. Clear this plugin\u2019s local data and reload to recover.",
|
|
751
790
|
"boundary.reset": "Clear local data and reload"
|
|
@@ -1101,6 +1140,15 @@ function getComposerElement(frame) {
|
|
|
1101
1140
|
if (frame === null) return null;
|
|
1102
1141
|
return slotElement(frame, "conversation.composer.dock", "ancestor");
|
|
1103
1142
|
}
|
|
1143
|
+
function getActiveConversationViewId(frame, viewIds) {
|
|
1144
|
+
if (viewIds.length === 0) return null;
|
|
1145
|
+
const header = frame === null ? null : slotElement(frame, "conversation.session.header", "child");
|
|
1146
|
+
const tablist = header?.querySelector('[role="tablist"]') ?? null;
|
|
1147
|
+
if (tablist === null) return viewIds[0] ?? null;
|
|
1148
|
+
const tabs = [...tablist.querySelectorAll('[role="tab"]')];
|
|
1149
|
+
const activeIndex = tabs.findIndex((tab) => tab.getAttribute("aria-selected") === "true");
|
|
1150
|
+
return activeIndex < 0 ? viewIds[0] ?? null : viewIds[activeIndex] ?? null;
|
|
1151
|
+
}
|
|
1104
1152
|
|
|
1105
1153
|
// src/client/export.ts
|
|
1106
1154
|
var BEIJING_OFFSET_MS2 = 8 * 60 * 60 * 1e3;
|
|
@@ -1240,6 +1288,8 @@ function createStore(key, isValid, fallback) {
|
|
|
1240
1288
|
}
|
|
1241
1289
|
var isThreshold = (value) => typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
1242
1290
|
var widgetVisibleStore = createStore("widget.visible", isBoolean, true);
|
|
1291
|
+
var isWidgetTabIds = (value) => value === null || Array.isArray(value) && value.every((id) => typeof id === "string" && id !== "") && new Set(value).size === value.length;
|
|
1292
|
+
var widgetTabIdsStore = createStore("widget.tabIds", isWidgetTabIds, null);
|
|
1243
1293
|
var lowBalanceStore = createStore("alert.lowBalance", isThreshold, 10);
|
|
1244
1294
|
var monthlyBudgetStore = createStore("budget.monthly", isThreshold, 0);
|
|
1245
1295
|
var isUsageWindowDays = (value) => typeof value === "number" && USAGE_WINDOW_DAYS.some((days) => days === value);
|
|
@@ -1978,6 +2028,9 @@ function BalanceDashboard(props) {
|
|
|
1978
2028
|
const [freshnessNow, setFreshnessNow] = (0, import_react4.useState)(Date.now());
|
|
1979
2029
|
const hadDataRef = (0, import_react4.useRef)(cachedBalance !== null || cachedUsage !== null);
|
|
1980
2030
|
const [widgetOn, setWidgetOn] = (0, import_react4.useState)(widgetVisibleStore.get());
|
|
2031
|
+
const [widgetTabIds, setWidgetTabIds] = (0, import_react4.useState)(widgetTabIdsStore.get());
|
|
2032
|
+
const [viewTabs, setViewTabs] = (0, import_react4.useState)(() => props.views.list());
|
|
2033
|
+
(0, import_react4.useEffect)(() => props.views.subscribe(() => setViewTabs(props.views.list())), [props.views]);
|
|
1981
2034
|
const [lowBalance, setLowBalance] = (0, import_react4.useState)(lowBalanceStore.get());
|
|
1982
2035
|
const [monthlyBudget, setMonthlyBudget] = (0, import_react4.useState)(monthlyBudgetStore.get());
|
|
1983
2036
|
const [barMode, setBarMode] = (0, import_react4.useState)("daily");
|
|
@@ -1986,6 +2039,8 @@ function BalanceDashboard(props) {
|
|
|
1986
2039
|
const [chartMetric, setChartMetric] = (0, import_react4.useState)(chartMetricStore.get());
|
|
1987
2040
|
const [runwayHovering, setRunwayHovering] = (0, import_react4.useState)(false);
|
|
1988
2041
|
const [runwayManuallyOpened, setRunwayManuallyOpened] = (0, import_react4.useState)(false);
|
|
2042
|
+
const [remainingHovering, setRemainingHovering] = (0, import_react4.useState)(false);
|
|
2043
|
+
const [remainingManuallyOpened, setRemainingManuallyOpened] = (0, import_react4.useState)(false);
|
|
1989
2044
|
const budgetInputRef = (0, import_react4.useRef)(null);
|
|
1990
2045
|
const rootRef = (0, import_react4.useRef)(null);
|
|
1991
2046
|
const [composerHeight, setComposerHeight] = (0, import_react4.useState)(null);
|
|
@@ -2118,6 +2173,13 @@ function BalanceDashboard(props) {
|
|
|
2118
2173
|
setWidgetOn(next);
|
|
2119
2174
|
widgetVisibleStore.set(next);
|
|
2120
2175
|
};
|
|
2176
|
+
const widgetTabs = viewTabs.filter((tab) => tab.id !== "balance");
|
|
2177
|
+
const toggleWidgetTab = (id) => {
|
|
2178
|
+
const selected = widgetTabIds ?? widgetTabs.map((tab) => tab.id);
|
|
2179
|
+
const next = selected.includes(id) ? selected.filter((tabId) => tabId !== id) : [...selected, id];
|
|
2180
|
+
setWidgetTabIds(next);
|
|
2181
|
+
widgetTabIdsStore.set(next);
|
|
2182
|
+
};
|
|
2121
2183
|
const changeLowBalance = (value) => {
|
|
2122
2184
|
setLowBalance(value);
|
|
2123
2185
|
lowBalanceStore.set(value);
|
|
@@ -2273,17 +2335,36 @@ function BalanceDashboard(props) {
|
|
|
2273
2335
|
primary !== null ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dq-balance-grid", children: [
|
|
2274
2336
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dq-stat", children: [
|
|
2275
2337
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dq-stat-label", children: t("balance.remaining") }),
|
|
2276
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
" ",
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2338
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2339
|
+
"details",
|
|
2340
|
+
{
|
|
2341
|
+
className: "dq-stat-value dq-remaining",
|
|
2342
|
+
open: remainingHovering || remainingManuallyOpened,
|
|
2343
|
+
onPointerEnter: () => setRemainingHovering(true),
|
|
2344
|
+
onPointerLeave: () => setRemainingHovering(false),
|
|
2345
|
+
children: [
|
|
2346
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2347
|
+
"summary",
|
|
2348
|
+
{
|
|
2349
|
+
title: t("balance.breakdownTitle"),
|
|
2350
|
+
onClick: (e) => {
|
|
2351
|
+
e.preventDefault();
|
|
2352
|
+
setRemainingManuallyOpened((v) => !v);
|
|
2353
|
+
},
|
|
2354
|
+
children: [
|
|
2355
|
+
fmt(primary.total),
|
|
2356
|
+
" ",
|
|
2357
|
+
primary.currency
|
|
2358
|
+
]
|
|
2359
|
+
}
|
|
2360
|
+
),
|
|
2361
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dq-remaining-breakdown", children: [
|
|
2362
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: t("balance.toppedUp", { amount: fmt(primary.toppedUp) }) }),
|
|
2363
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dq-remaining-granted", children: t("balance.granted", { amount: fmt(primary.granted) }) })
|
|
2364
|
+
] })
|
|
2365
|
+
]
|
|
2366
|
+
}
|
|
2367
|
+
)
|
|
2287
2368
|
] }),
|
|
2288
2369
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dq-stat", children: [
|
|
2289
2370
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dq-stat-label", children: t("balance.runway") }),
|
|
@@ -2465,6 +2546,23 @@ function BalanceDashboard(props) {
|
|
|
2465
2546
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: t("settings.widget") })
|
|
2466
2547
|
] }),
|
|
2467
2548
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dq-toggle-hint", children: t("settings.widgetHint") }),
|
|
2549
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dq-setting dq-setting--tabs", children: [
|
|
2550
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dq-setting-label", id: "dq-widget-tabs-label", children: t("settings.widgetTabs") }),
|
|
2551
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dq-setting-control dq-widget-tabs", role: "group", "aria-labelledby": "dq-widget-tabs-label", children: [
|
|
2552
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dq-widget-tab-list", children: widgetTabs.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "dq-widget-tab", children: [
|
|
2553
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2554
|
+
"input",
|
|
2555
|
+
{
|
|
2556
|
+
type: "checkbox",
|
|
2557
|
+
checked: widgetTabIds === null || widgetTabIds.includes(tab.id),
|
|
2558
|
+
onChange: () => toggleWidgetTab(tab.id)
|
|
2559
|
+
}
|
|
2560
|
+
),
|
|
2561
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: tab.label })
|
|
2562
|
+
] }, tab.id)) }),
|
|
2563
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dq-setting-hint", children: widgetTabs.length === 0 ? t("settings.widgetTabsEmpty") : t("settings.widgetTabsHint") })
|
|
2564
|
+
] })
|
|
2565
|
+
] }),
|
|
2468
2566
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dq-setting", children: [
|
|
2469
2567
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("label", { className: "dq-setting-label", htmlFor: "dq-low-balance", children: t("settings.lowBalance") }),
|
|
2470
2568
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dq-setting-control", children: [
|
|
@@ -2507,10 +2605,50 @@ function BalanceDashboard(props) {
|
|
|
2507
2605
|
] });
|
|
2508
2606
|
}
|
|
2509
2607
|
|
|
2608
|
+
// src/client/message-cost.tsx
|
|
2609
|
+
var import_react5 = require("react");
|
|
2610
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
2611
|
+
var fmtTurnCost = (cost) => cost.toLocaleString(void 0, {
|
|
2612
|
+
minimumFractionDigits: cost > 0 && cost < 0.01 ? 4 : 2,
|
|
2613
|
+
maximumFractionDigits: cost > 0 && cost < 0.01 ? 6 : 4
|
|
2614
|
+
});
|
|
2615
|
+
var cachedData = (sessionId) => {
|
|
2616
|
+
const response = getCachedSessionUsage(sessionId);
|
|
2617
|
+
return response?.ok === true ? response.data ?? null : null;
|
|
2618
|
+
};
|
|
2619
|
+
function MessageCost({ sessionId, messageId }) {
|
|
2620
|
+
const { t } = useI18n();
|
|
2621
|
+
const [data, setData] = (0, import_react5.useState)(() => cachedData(sessionId));
|
|
2622
|
+
(0, import_react5.useEffect)(() => {
|
|
2623
|
+
setData(cachedData(sessionId));
|
|
2624
|
+
const unsubscribe = subscribeSessionUsage(sessionId, () => setData(cachedData(sessionId)));
|
|
2625
|
+
const hit = cachedData(sessionId)?.turns.some((turn2) => turn2.messageId === messageId) ?? false;
|
|
2626
|
+
if (!hit) void fetchSessionUsage(sessionId);
|
|
2627
|
+
return unsubscribe;
|
|
2628
|
+
}, [messageId, sessionId]);
|
|
2629
|
+
const turn = data?.turns.find((candidate) => candidate.messageId === messageId);
|
|
2630
|
+
if (turn === void 0) return null;
|
|
2631
|
+
const amount = `\xA5 ${fmtTurnCost(turn.cost)}`;
|
|
2632
|
+
const tooltip = t("messageCost.tooltip");
|
|
2633
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2634
|
+
"span",
|
|
2635
|
+
{
|
|
2636
|
+
className: "dq-message-cost",
|
|
2637
|
+
tabIndex: 0,
|
|
2638
|
+
"data-dq-tooltip": tooltip,
|
|
2639
|
+
"aria-label": t("messageCost.aria", { amount }),
|
|
2640
|
+
children: [
|
|
2641
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dq-message-cost-separator", "aria-hidden": true, children: "\xB7" }),
|
|
2642
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dq-message-cost-amount", children: amount })
|
|
2643
|
+
]
|
|
2644
|
+
}
|
|
2645
|
+
);
|
|
2646
|
+
}
|
|
2647
|
+
|
|
2510
2648
|
// src/client/styles.ts
|
|
2511
2649
|
var css = `
|
|
2512
2650
|
.dsh-quota-root{position:absolute;right:16px;bottom:16px;z-index:2147483000;pointer-events:auto;opacity:1;visibility:visible;font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-size:13px;line-height:1.45;color:var(--dsw-alias-label-primary,#1f2328);transition:left .28s cubic-bezier(.22,1,.36,1),top .28s cubic-bezier(.22,1,.36,1),opacity .16s ease-out,visibility 0s linear}
|
|
2513
|
-
.dsh-quota-root.dsh-quota-root--
|
|
2651
|
+
.dsh-quota-root.dsh-quota-root--hidden{opacity:0;visibility:hidden;pointer-events:none;transition:opacity .14s ease-out,visibility 0s linear .14s}
|
|
2514
2652
|
.dsh-quota-root.dsh-quota-dragging{transition:none}
|
|
2515
2653
|
.dsh-quota-card,.dsh-quota-card *{box-sizing:border-box}
|
|
2516
2654
|
.dsh-quota-card{background:var(--dsw-alias-bg-overlay,#ffffff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:12px;box-shadow:0 8px 24px rgba(0,0,0,.18);padding:12px 14px;min-width:208px;max-width:270px;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);cursor:grab;touch-action:none;user-select:none;-webkit-user-select:none}
|
|
@@ -2540,6 +2678,17 @@ var css = `
|
|
|
2540
2678
|
.dsh-quota-label{color:var(--dsw-alias-label-secondary,#59636e)}
|
|
2541
2679
|
.dsh-quota-value{color:var(--dsw-alias-label-primary,#1f2328);font-variant-numeric:tabular-nums}
|
|
2542
2680
|
.dsh-quota-error{color:var(--dsw-alias-state-error-primary,#cf222e)}
|
|
2681
|
+
.dq-message-cost{position:relative;display:inline-flex;align-items:center;order:10;gap:10px;height:28px;color:var(--dsw-alias-label-tertiary,#59636e);font-size:12px;line-height:20px;font-variant-numeric:tabular-nums;white-space:nowrap;cursor:help}
|
|
2682
|
+
.dq-message-cost-separator{cursor:default}
|
|
2683
|
+
.dq-message-cost-amount{text-decoration-line:underline;text-decoration-style:dotted;text-decoration-color:currentColor;text-underline-offset:4px}
|
|
2684
|
+
.dq-message-cost:hover{color:var(--dsw-alias-label-secondary,#3f4852)}
|
|
2685
|
+
.dq-message-cost:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px;border-radius:4px}
|
|
2686
|
+
.dq-message-cost::after{content:attr(data-dq-tooltip);position:absolute;left:0;top:calc(100% + 6px);z-index:2147483001;width:max-content;max-width:min(240px,calc(100vw - 24px));padding:6px 9px;border-radius:8px;background:var(--dsw-alias-bg-inverse,#1f2328);color:var(--dsw-alias-label-inverse,#fff);box-shadow:0 6px 18px rgba(0,0,0,.22);font-size:12px;font-weight:400;line-height:1.45;text-align:left;white-space:normal;pointer-events:none;opacity:0;visibility:hidden;transform:translateY(-3px);transition:opacity .12s ease-out,transform .12s cubic-bezier(.22,1,.36,1),visibility 0s linear .12s}
|
|
2687
|
+
.dq-message-cost:hover::after,.dq-message-cost:focus-visible::after{opacity:1;visibility:visible;transform:translateY(0);transition:opacity .12s ease-out,transform .12s cubic-bezier(.22,1,.36,1),visibility 0s linear}
|
|
2688
|
+
@media (hover:hover){
|
|
2689
|
+
[data-time-hover-root] .dq-message-cost{opacity:0;transition:opacity 80ms ease}
|
|
2690
|
+
[data-time-hover-root]:hover .dq-message-cost,[data-time-hover-root]:focus-within .dq-message-cost{opacity:1}
|
|
2691
|
+
}
|
|
2543
2692
|
/* \u5361\u7247\u95F4\u8DDD\uFF08\u6B64\u5904 gap\uFF09\u523B\u610F\u5927\u4E8E\u5361\u5185\u5C0F\u8282\u95F4\u8DDD\uFF08margin-top:12/14/16px \u90A3\u4E00\u6863\uFF09\uFF0C\u5236\u9020"\u5361\u7247\u5916\u758F\u3001\u5361\u7247\u5185\u5BC6"\u7684
|
|
2544
2693
|
\u758F\u5BC6\u5BF9\u6BD4\uFF1A24px \u76F8\u5BF9\u5361\u5185\u6700\u5927\u6863 16px \u4ECD\u6709 1.5 \u500D\u7EA7\u5DEE\uFF0C\u76F8\u5BF9\u5E38\u89C1\u6863 12px \u6709 2 \u500D\u7EA7\u5DEE\uFF0C\u4E0D\u4E0E .dq-card \u7684
|
|
2545
2694
|
padding\uFF0816px/20px\uFF0C\u5361\u7247\u5185\u90E8\u547C\u5438\u611F\uFF0C\u8F6E\u6B21 36 \u5DF2\u5B9A\uFF09\u6DF7\u540C\u3002 */
|
|
@@ -2606,12 +2755,15 @@ var css = `
|
|
|
2606
2755
|
.dq-runway[open] .dq-runway-detail{display:block}
|
|
2607
2756
|
/* hero number for the balance, matching .dq-period-cost; relies on cascade order (declared after
|
|
2608
2757
|
.dq-stat-value, same specificity) to win over the .dq-stat-value it's paired with in JSX \u2014 keep it below */
|
|
2758
|
+
/* \u8F6E\u6B21 47: .dq-remaining is a controlled <details> too now (see dashboard.tsx), same reason as
|
|
2759
|
+
.dq-runway above \u2014 an unopened <details>'s non-summary children don't actually render in current
|
|
2760
|
+
Chromium regardless of author display value, so the old :hover{display:flex} branch was dead code. */
|
|
2609
2761
|
.dq-remaining{position:relative;font-size:22px;font-weight:680;letter-spacing:-.01em;line-height:1.25}
|
|
2610
2762
|
.dq-remaining>summary{display:inline-block;list-style:none;border-radius:4px;cursor:pointer;text-decoration:underline dotted var(--dsw-alias-border-l2,rgba(0,0,0,.25));text-underline-offset:4px}
|
|
2611
2763
|
.dq-remaining>summary::-webkit-details-marker{display:none}
|
|
2612
2764
|
.dq-remaining>summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:3px}
|
|
2613
2765
|
.dq-remaining-breakdown{display:none;position:absolute;top:calc(100% + 6px);left:0;z-index:20;flex-direction:column;gap:4px;padding:8px 10px;background:var(--dsw-alias-bg-overlay,#ffffff);border:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.12));border-radius:8px;box-shadow:0 8px 24px rgba(0,0,0,.15);white-space:nowrap;font-size:12px;font-weight:500;color:var(--dsw-alias-label-primary,#1f2328)}
|
|
2614
|
-
.dq-remaining
|
|
2766
|
+
.dq-remaining[open] .dq-remaining-breakdown{display:flex}
|
|
2615
2767
|
.dq-remaining-granted{color:var(--dsw-alias-label-tertiary,#59636e);font-weight:400;font-size:11px}
|
|
2616
2768
|
/* narrow screens: .dq-balance-grid wraps its 3 stats onto separate lines, so the absolutely-positioned
|
|
2617
2769
|
.dq-remaining-breakdown/.dq-runway-detail popovers can float down over whichever stat now sits in the
|
|
@@ -2772,7 +2924,11 @@ p.dq-session-sub{margin:8px 0}
|
|
|
2772
2924
|
.dq-toggle{display:flex;align-items:center;gap:10px;cursor:pointer;font-size:13px;margin-top:14px;padding-top:14px;border-top:1px solid var(--dsw-alias-border-l1,rgba(0,0,0,.08))}
|
|
2773
2925
|
.dq-toggle input{width:16px;height:16px;accent-color:var(--dsw-alias-state-business-primary,#0969da);cursor:pointer}
|
|
2774
2926
|
.dq-toggle-hint{margin:5px 0 0 26px;font-size:12px;line-height:1.5;color:var(--dsw-alias-label-secondary,#59636e)}
|
|
2775
|
-
.dq-
|
|
2927
|
+
.dq-widget-tabs{align-items:flex-start;flex-direction:column;gap:7px}
|
|
2928
|
+
.dq-widget-tab-list{display:flex;align-items:center;flex-wrap:wrap;gap:6px 14px}
|
|
2929
|
+
.dq-widget-tab{display:inline-flex;align-items:center;gap:7px;min-height:28px;color:var(--dsw-alias-label-primary,#1f2328);font-size:12px;cursor:pointer}
|
|
2930
|
+
.dq-widget-tab input{width:14px;height:14px;margin:0;accent-color:var(--dsw-alias-state-business-primary,#0969da);cursor:pointer;flex:none}
|
|
2931
|
+
.dq-toggle input:focus-visible,.dq-model-item input:focus-visible,.dq-widget-tab input:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}
|
|
2776
2932
|
.dq-link:focus-visible,.dq-model-btn:focus-visible,.dq-chart-switch-btn:focus-visible,.dq-export-btn:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#0969da);outline-offset:2px}
|
|
2777
2933
|
.dq-usage-totals{display:flex;flex-wrap:wrap;gap:12px 24px;margin-bottom:16px}
|
|
2778
2934
|
/* value itself (number+unit, e.g. "9999.9\u4E07") must never break across lines inside its own column \u2014
|
|
@@ -2882,14 +3038,15 @@ p.dq-session-sub{margin:8px 0}
|
|
|
2882
3038
|
@media (prefers-reduced-motion:reduce){
|
|
2883
3039
|
.dsh-quota-root,.dsh-quota-root *,
|
|
2884
3040
|
.dsh-quota-root *::before,.dsh-quota-root *::after,
|
|
3041
|
+
.dq-message-cost,.dq-message-cost::after,
|
|
2885
3042
|
.dq-balance,.dq-balance *,
|
|
2886
3043
|
.dq-balance *::before,.dq-balance *::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}
|
|
2887
3044
|
}
|
|
2888
3045
|
`;
|
|
2889
3046
|
|
|
2890
3047
|
// src/client/widget.tsx
|
|
2891
|
-
var
|
|
2892
|
-
var
|
|
3048
|
+
var import_react6 = require("react");
|
|
3049
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
2893
3050
|
var MARGIN = 16;
|
|
2894
3051
|
var CORNER_KEY = "widget.corner";
|
|
2895
3052
|
var COLLAPSED_KEY = "widget.collapsed";
|
|
@@ -2937,30 +3094,68 @@ function cornerPos(corner, node, bounds) {
|
|
|
2937
3094
|
if (corner === "bl") return { x: xLeft, y: yBottom };
|
|
2938
3095
|
return { x: xRight, y: yBottom };
|
|
2939
3096
|
}
|
|
2940
|
-
function QuotaWidget() {
|
|
3097
|
+
function QuotaWidget(props) {
|
|
2941
3098
|
const { t } = useI18n();
|
|
2942
|
-
const
|
|
2943
|
-
(0,
|
|
2944
|
-
|
|
2945
|
-
(0,
|
|
2946
|
-
|
|
2947
|
-
(0,
|
|
3099
|
+
const sessionId = props.useSessions((state) => state.current);
|
|
3100
|
+
const [visible, setVisible] = (0, import_react6.useState)(widgetVisibleStore.get());
|
|
3101
|
+
(0, import_react6.useEffect)(() => widgetVisibleStore.subscribe(() => setVisible(widgetVisibleStore.get())), []);
|
|
3102
|
+
const [quotaViewActive2, setQuotaViewActive] = (0, import_react6.useState)(quotaViewActiveStore.get());
|
|
3103
|
+
(0, import_react6.useEffect)(() => quotaViewActiveStore.subscribe(() => setQuotaViewActive(quotaViewActiveStore.get())), []);
|
|
3104
|
+
const [lowBalance, setLowBalance] = (0, import_react6.useState)(lowBalanceStore.get());
|
|
3105
|
+
(0, import_react6.useEffect)(() => lowBalanceStore.subscribe(() => setLowBalance(lowBalanceStore.get())), []);
|
|
3106
|
+
const [selectedTabIds, setSelectedTabIds] = (0, import_react6.useState)(widgetTabIdsStore.get());
|
|
3107
|
+
(0, import_react6.useEffect)(() => widgetTabIdsStore.subscribe(() => setSelectedTabIds(widgetTabIdsStore.get())), []);
|
|
3108
|
+
const [viewTabs, setViewTabs] = (0, import_react6.useState)(() => props.views.list());
|
|
3109
|
+
(0, import_react6.useEffect)(() => props.views.subscribe(() => setViewTabs(props.views.list())), [props.views]);
|
|
3110
|
+
const [activeViewId, setActiveViewId] = (0, import_react6.useState)(null);
|
|
2948
3111
|
const cachedBalance = getCachedBalance();
|
|
2949
|
-
const [data, setData] = (0,
|
|
2950
|
-
const [error, setError] = (0,
|
|
2951
|
-
const [loading, setLoading] = (0,
|
|
2952
|
-
const [collapsed, setCollapsed] = (0,
|
|
2953
|
-
const [pos, setPos] = (0,
|
|
2954
|
-
const [corner, setCorner] = (0,
|
|
2955
|
-
const [dragging, setDragging] = (0,
|
|
2956
|
-
const rootRef = (0,
|
|
2957
|
-
const dragRef = (0,
|
|
3112
|
+
const [data, setData] = (0, import_react6.useState)(cachedBalance?.data ?? null);
|
|
3113
|
+
const [error, setError] = (0, import_react6.useState)(null);
|
|
3114
|
+
const [loading, setLoading] = (0, import_react6.useState)(cachedBalance === null);
|
|
3115
|
+
const [collapsed, setCollapsed] = (0, import_react6.useState)(() => loadPref(COLLAPSED_KEY, isBoolean, false));
|
|
3116
|
+
const [pos, setPos] = (0, import_react6.useState)(null);
|
|
3117
|
+
const [corner, setCorner] = (0, import_react6.useState)(() => loadPref(CORNER_KEY, isCorner, "br"));
|
|
3118
|
+
const [dragging, setDragging] = (0, import_react6.useState)(false);
|
|
3119
|
+
const rootRef = (0, import_react6.useRef)(null);
|
|
3120
|
+
const dragRef = (0, import_react6.useRef)(null);
|
|
2958
3121
|
const readUsage = () => {
|
|
2959
3122
|
const cached = getCachedUsage();
|
|
2960
3123
|
return { data: cached?.ok === true ? cached.data ?? null : null, at: getCachedUsageAt() };
|
|
2961
3124
|
};
|
|
2962
|
-
const [usage, setUsage] = (0,
|
|
2963
|
-
(0,
|
|
3125
|
+
const [usage, setUsage] = (0, import_react6.useState)(readUsage);
|
|
3126
|
+
(0, import_react6.useEffect)(() => subscribeUsage(() => setUsage(readUsage())), []);
|
|
3127
|
+
const readSessionUsage = (id) => {
|
|
3128
|
+
if (id === void 0) return null;
|
|
3129
|
+
const response = getCachedSessionUsage(id);
|
|
3130
|
+
return response?.ok === true ? response.data ?? null : null;
|
|
3131
|
+
};
|
|
3132
|
+
const [sessionUsage, setSessionUsage] = (0, import_react6.useState)(() => readSessionUsage(sessionId));
|
|
3133
|
+
(0, import_react6.useEffect)(() => {
|
|
3134
|
+
setSessionUsage(readSessionUsage(sessionId));
|
|
3135
|
+
if (sessionId === void 0) return;
|
|
3136
|
+
const unsubscribe = subscribeSessionUsage(sessionId, () => setSessionUsage(readSessionUsage(sessionId)));
|
|
3137
|
+
void fetchSessionUsage(sessionId);
|
|
3138
|
+
return unsubscribe;
|
|
3139
|
+
}, [sessionId]);
|
|
3140
|
+
(0, import_react6.useLayoutEffect)(() => {
|
|
3141
|
+
const viewIds = viewTabs.map((tab) => tab.id);
|
|
3142
|
+
const read = () => {
|
|
3143
|
+
const next = getActiveConversationViewId(getShellFrame(rootRef.current), viewIds);
|
|
3144
|
+
setActiveViewId((previous) => previous === next ? previous : next);
|
|
3145
|
+
};
|
|
3146
|
+
read();
|
|
3147
|
+
const frame = getShellFrame(rootRef.current);
|
|
3148
|
+
let observer = null;
|
|
3149
|
+
if (frame !== null && typeof MutationObserver === "function") {
|
|
3150
|
+
observer = new MutationObserver(read);
|
|
3151
|
+
observer.observe(frame, { subtree: true, childList: true, attributes: true, attributeFilter: ["aria-selected"] });
|
|
3152
|
+
}
|
|
3153
|
+
const poll = setInterval(read, 1e3);
|
|
3154
|
+
return () => {
|
|
3155
|
+
observer?.disconnect();
|
|
3156
|
+
clearInterval(poll);
|
|
3157
|
+
};
|
|
3158
|
+
}, [sessionId, viewTabs]);
|
|
2964
3159
|
const load = async (showLoading, force = false) => {
|
|
2965
3160
|
if (showLoading) setLoading(true);
|
|
2966
3161
|
try {
|
|
@@ -2979,14 +3174,14 @@ function QuotaWidget() {
|
|
|
2979
3174
|
setLoading(false);
|
|
2980
3175
|
}
|
|
2981
3176
|
};
|
|
2982
|
-
(0,
|
|
3177
|
+
(0, import_react6.useEffect)(() => {
|
|
2983
3178
|
void load(true);
|
|
2984
3179
|
const id = setInterval(() => {
|
|
2985
3180
|
void load(false);
|
|
2986
3181
|
}, 6e4);
|
|
2987
3182
|
return () => clearInterval(id);
|
|
2988
3183
|
}, []);
|
|
2989
|
-
(0,
|
|
3184
|
+
(0, import_react6.useLayoutEffect)(() => {
|
|
2990
3185
|
if (!visible || quotaViewActive2) return;
|
|
2991
3186
|
const node = rootRef.current;
|
|
2992
3187
|
if (node === null) return;
|
|
@@ -3106,49 +3301,68 @@ function QuotaWidget() {
|
|
|
3106
3301
|
endDrag(true);
|
|
3107
3302
|
};
|
|
3108
3303
|
if (!visible) return null;
|
|
3304
|
+
const allowedOnActiveView = activeViewId === null ? sessionId === void 0 : activeViewId !== "balance" && (selectedTabIds === null || selectedTabIds.includes(activeViewId));
|
|
3305
|
+
const hidden = quotaViewActive2 || !allowedOnActiveView;
|
|
3109
3306
|
const primary = data !== null && data.balances.length > 0 ? data.balances[0] : null;
|
|
3110
3307
|
const balanceValue = primary !== null ? Number(primary.total) : Number.NaN;
|
|
3111
3308
|
const low = lowBalance > 0 && Number.isFinite(balanceValue) && balanceValue < lowBalance;
|
|
3112
3309
|
const dotClass = primary === null ? "dsh-quota-dot dsh-quota-dot--idle" : data?.isAvailable === false ? "dsh-quota-dot dsh-quota-dot--error" : low ? "dsh-quota-dot dsh-quota-dot--warn" : "dsh-quota-dot";
|
|
3113
3310
|
const ageMinutes = usage.at === null ? null : Math.floor((Date.now() - usage.at) / 6e4);
|
|
3114
3311
|
const usageAgeText = ageMinutes === null || ageMinutes < 1 ? t("widget.updatedNow") : t("widget.stale", { minutes: ageMinutes });
|
|
3312
|
+
const sessionCostRow = sessionUsage === null ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-quota-row", title: t("widget.sessionCostTitle"), children: [
|
|
3313
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-quota-label", children: t("widget.sessionCost") }),
|
|
3314
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "dsh-quota-value", children: [
|
|
3315
|
+
"\xA5 ",
|
|
3316
|
+
fmtTurnCost(sessionUsage.cost)
|
|
3317
|
+
] })
|
|
3318
|
+
] });
|
|
3115
3319
|
let body = null;
|
|
3116
3320
|
if (!collapsed) {
|
|
3117
3321
|
if (loading && data === null && error === null) {
|
|
3118
|
-
body = /* @__PURE__ */ (0,
|
|
3322
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-quota-body", children: [
|
|
3323
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { children: t("widget.loading") }),
|
|
3324
|
+
sessionCostRow
|
|
3325
|
+
] });
|
|
3119
3326
|
} else if (error !== null && data === null) {
|
|
3120
|
-
body = /* @__PURE__ */ (0,
|
|
3327
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-quota-body", children: [
|
|
3328
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-quota-error", children: localizeApiError(error, t, "error.query") }),
|
|
3329
|
+
sessionCostRow
|
|
3330
|
+
] });
|
|
3121
3331
|
} else if (primary !== null) {
|
|
3122
|
-
body = /* @__PURE__ */ (0,
|
|
3123
|
-
/* @__PURE__ */ (0,
|
|
3124
|
-
/* @__PURE__ */ (0,
|
|
3125
|
-
/* @__PURE__ */ (0,
|
|
3126
|
-
/* @__PURE__ */ (0,
|
|
3332
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-quota-body", children: [
|
|
3333
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-quota-remaining-label", children: t("balance.remaining") }),
|
|
3334
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { title: low ? t("widget.lowTitle", { amount: fmt(lowBalance) }) : void 0, children: [
|
|
3335
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: `dsh-quota-total${low ? " dsh-quota-total--low" : ""}`, children: fmt(primary.total) }),
|
|
3336
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-quota-currency", children: primary.currency })
|
|
3127
3337
|
] }),
|
|
3128
|
-
usage.data !== null && /* @__PURE__ */ (0,
|
|
3129
|
-
/* @__PURE__ */ (0,
|
|
3130
|
-
/* @__PURE__ */ (0,
|
|
3338
|
+
usage.data !== null && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-quota-row", title: t("widget.todayCostTitle", { age: usageAgeText }), children: [
|
|
3339
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-quota-label", children: t("widget.todayCost") }),
|
|
3340
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "dsh-quota-value", children: [
|
|
3131
3341
|
"\xA5 ",
|
|
3132
3342
|
fmt(usage.data.summary.today.cost)
|
|
3133
3343
|
] })
|
|
3134
3344
|
] }),
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
/* @__PURE__ */ (0,
|
|
3345
|
+
sessionCostRow,
|
|
3346
|
+
data?.isAvailable === false && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-quota-row", children: [
|
|
3347
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-quota-label", children: t("common.status") }),
|
|
3348
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-quota-value dsh-quota-error", children: t("common.unavailable") })
|
|
3138
3349
|
] })
|
|
3139
3350
|
] });
|
|
3140
3351
|
} else {
|
|
3141
|
-
body = /* @__PURE__ */ (0,
|
|
3352
|
+
body = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-quota-body", children: [
|
|
3353
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-quota-error", children: t("widget.noBalance") }),
|
|
3354
|
+
sessionCostRow
|
|
3355
|
+
] });
|
|
3142
3356
|
}
|
|
3143
3357
|
}
|
|
3144
3358
|
const style = pos !== null ? { left: `${pos.x}px`, top: `${pos.y}px`, right: "auto", bottom: "auto" } : void 0;
|
|
3145
|
-
return /* @__PURE__ */ (0,
|
|
3359
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3146
3360
|
"div",
|
|
3147
3361
|
{
|
|
3148
|
-
className: `dsh-quota-root${dragging ? " dsh-quota-dragging" : ""}${
|
|
3362
|
+
className: `dsh-quota-root${dragging ? " dsh-quota-dragging" : ""}${hidden ? " dsh-quota-root--hidden" : ""}`,
|
|
3149
3363
|
style,
|
|
3150
|
-
"aria-hidden":
|
|
3151
|
-
children: /* @__PURE__ */ (0,
|
|
3364
|
+
"aria-hidden": hidden,
|
|
3365
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
3152
3366
|
"div",
|
|
3153
3367
|
{
|
|
3154
3368
|
ref: rootRef,
|
|
@@ -3160,14 +3374,14 @@ function QuotaWidget() {
|
|
|
3160
3374
|
onPointerCancel: () => endDrag(false),
|
|
3161
3375
|
onLostPointerCapture: () => endDrag(false),
|
|
3162
3376
|
children: [
|
|
3163
|
-
/* @__PURE__ */ (0,
|
|
3164
|
-
/* @__PURE__ */ (0,
|
|
3165
|
-
/* @__PURE__ */ (0,
|
|
3166
|
-
/* @__PURE__ */ (0,
|
|
3167
|
-
/* @__PURE__ */ (0,
|
|
3377
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-quota-header", children: [
|
|
3378
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-quota-title", children: [
|
|
3379
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-quota-grip", title: t("widget.dragGrip"), children: "\u2807" }),
|
|
3380
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: dotClass }),
|
|
3381
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-quota-name", children: t("widget.title") })
|
|
3168
3382
|
] }),
|
|
3169
|
-
/* @__PURE__ */ (0,
|
|
3170
|
-
/* @__PURE__ */ (0,
|
|
3383
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-quota-actions", children: [
|
|
3384
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3171
3385
|
"button",
|
|
3172
3386
|
{
|
|
3173
3387
|
className: "dsh-quota-btn",
|
|
@@ -3178,11 +3392,12 @@ function QuotaWidget() {
|
|
|
3178
3392
|
onClick: () => {
|
|
3179
3393
|
void load(true, true);
|
|
3180
3394
|
void fetchUsage(true);
|
|
3395
|
+
if (sessionId !== void 0) void fetchSessionUsage(sessionId, true);
|
|
3181
3396
|
},
|
|
3182
3397
|
children: "\u21BB"
|
|
3183
3398
|
}
|
|
3184
3399
|
),
|
|
3185
|
-
/* @__PURE__ */ (0,
|
|
3400
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3186
3401
|
"button",
|
|
3187
3402
|
{
|
|
3188
3403
|
className: "dsh-quota-btn",
|
|
@@ -3200,7 +3415,7 @@ function QuotaWidget() {
|
|
|
3200
3415
|
)
|
|
3201
3416
|
] })
|
|
3202
3417
|
] }),
|
|
3203
|
-
collapsed && primary !== null && /* @__PURE__ */ (0,
|
|
3418
|
+
collapsed && primary !== null && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-quota-collapsed-total-row", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: `dsh-quota-collapsed-total${low ? " dsh-quota-total--low" : ""}`, children: [
|
|
3204
3419
|
fmt(primary.total),
|
|
3205
3420
|
" ",
|
|
3206
3421
|
primary.currency
|
|
@@ -3213,13 +3428,31 @@ function QuotaWidget() {
|
|
|
3213
3428
|
);
|
|
3214
3429
|
}
|
|
3215
3430
|
|
|
3431
|
+
// src/client/views.ts
|
|
3432
|
+
var labelOf = (entry) => {
|
|
3433
|
+
const { id = "", label } = entry.options;
|
|
3434
|
+
try {
|
|
3435
|
+
const resolved = typeof label === "function" ? label() : label;
|
|
3436
|
+
return typeof resolved === "string" && resolved !== "" ? resolved : id;
|
|
3437
|
+
} catch {
|
|
3438
|
+
return id;
|
|
3439
|
+
}
|
|
3440
|
+
};
|
|
3441
|
+
function conversationViewsSource(slots) {
|
|
3442
|
+
return {
|
|
3443
|
+
list: () => slots.entries("conversation.view").flatMap((entry) => entry.options.id === void 0 ? [] : [{ id: entry.options.id, label: labelOf(entry) }]),
|
|
3444
|
+
subscribe: (fn) => slots.subscribe("conversation.view", fn)
|
|
3445
|
+
};
|
|
3446
|
+
}
|
|
3447
|
+
|
|
3216
3448
|
// src/client/index.tsx
|
|
3217
|
-
var
|
|
3449
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
3218
3450
|
var name = "dsh-usage-dashboard";
|
|
3219
3451
|
var inject = ["slots", "locale"];
|
|
3220
3452
|
function apply(ctx) {
|
|
3221
3453
|
ctx.effect(() => ctx.locale.register(NS, { zh, en }), "dsh-usage-dashboard: browser dictionaries");
|
|
3222
3454
|
const t = ctx.locale.bind(NS);
|
|
3455
|
+
const views = conversationViewsSource(ctx.slots);
|
|
3223
3456
|
if (typeof document !== "undefined") {
|
|
3224
3457
|
const tag = document.createElement("style");
|
|
3225
3458
|
tag.dataset.plugin = "dsh-usage-dashboard";
|
|
@@ -3232,7 +3465,17 @@ function apply(ctx) {
|
|
|
3232
3465
|
});
|
|
3233
3466
|
ctx.slots.inject("shell.overlay", () => ctx.slots.register(
|
|
3234
3467
|
{ name: "shell.overlay", id: "deepseek-quota", order: 1e3, locale: NS, label: () => t("widget.title") },
|
|
3235
|
-
({ t: slotT }) => /* @__PURE__ */ (0,
|
|
3468
|
+
({ t: slotT, useSessions }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(LocaleProvider, { t: slotT, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ErrorBoundary, { t: slotT, silent: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(QuotaWidget, { useSessions, views }) }) })
|
|
3469
|
+
));
|
|
3470
|
+
ctx.slots.inject("conversation.chat.assistant-actions", () => ctx.slots.register(
|
|
3471
|
+
{
|
|
3472
|
+
name: "conversation.chat.assistant-actions",
|
|
3473
|
+
id: "dsh-usage-turn-cost",
|
|
3474
|
+
order: 5,
|
|
3475
|
+
locale: NS,
|
|
3476
|
+
label: () => t("messageCost.label")
|
|
3477
|
+
},
|
|
3478
|
+
({ t: slotT, sessionId, messageId }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(LocaleProvider, { t: slotT, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ErrorBoundary, { t: slotT, silent: true, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MessageCost, { sessionId, messageId }) }) })
|
|
3236
3479
|
));
|
|
3237
3480
|
ctx.slots.inject("conversation.view", () => ctx.slots.register(
|
|
3238
3481
|
{ name: "conversation.view", id: "balance", order: 20, locale: NS, label: () => t("nav.quota") },
|
|
@@ -3243,7 +3486,7 @@ function apply(ctx) {
|
|
|
3243
3486
|
// `sessionId` is typed optional defensively even though the host is
|
|
3244
3487
|
// expected to always supply it: BalanceDashboard renders the current-
|
|
3245
3488
|
// session card only when it actually has one, never throws either way.
|
|
3246
|
-
({ t: slotT, sessionId }) => /* @__PURE__ */ (0,
|
|
3489
|
+
({ t: slotT, sessionId }) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(LocaleProvider, { t: slotT, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ErrorBoundary, { t: slotT, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(BalanceDashboard, { sessionId, views }) }) })
|
|
3247
3490
|
));
|
|
3248
3491
|
}
|
|
3249
3492
|
return module.exports; } });
|