dsh-subscriptions 0.1.2 → 0.1.4
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 +92 -10
- package/lib/auth/rpc.d.ts +3 -1
- package/lib/auth/rpc.js +10 -1
- package/lib/client/ExternalUsageCards.d.ts +11 -1
- package/lib/client/ExternalUsageCards.js +18 -3
- package/lib/client/ProviderAccountManager.js +34 -41
- package/lib/client/ProviderModelEditor.js +5 -9
- package/lib/client/SpeedSelect.js +8 -7
- package/lib/client/SubscriptionUsageBadge.d.ts +19 -2
- package/lib/client/SubscriptionUsageBadge.js +65 -9
- package/lib/client/SubscriptionsSection.d.ts +22 -0
- package/lib/client/SubscriptionsSection.js +128 -38
- package/lib/client/UsageBadgeDisplaySetting.js +6 -10
- package/lib/client/UsageMeter.js +11 -6
- package/lib/client/host-contract.d.ts +1 -1
- package/lib/client/host-contract.js +22 -0
- package/lib/client/locales.d.ts +60 -0
- package/lib/client/locales.js +62 -2
- package/lib/client/provider-settings-styles.d.ts +3 -0
- package/lib/client/provider-settings-styles.js +206 -0
- package/lib/client/reset-action.d.ts +14 -0
- package/lib/client/reset-action.js +15 -0
- package/lib/client/reset-credits-view.d.ts +53 -0
- package/lib/client/reset-credits-view.js +103 -0
- package/lib/client/usage-badge-preferences.d.ts +7 -2
- package/lib/client/usage-badge-preferences.js +3 -2
- package/lib/client/usage-pace.d.ts +14 -1
- package/lib/client/usage-pace.js +14 -1
- package/lib/client.js +1036 -334
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +9 -0
- package/lib/index.js +1120 -602
- package/lib/providers/account-preferences.js +3 -2
- package/lib/providers/catalog-store.d.ts +3 -2
- package/lib/providers/catalog-store.js +57 -26
- package/lib/providers/claude.d.ts +22 -3
- package/lib/providers/claude.js +113 -15
- package/lib/providers/codex.d.ts +15 -2
- package/lib/providers/codex.js +72 -4
- package/lib/providers/common.d.ts +25 -0
- package/lib/providers/common.js +22 -18
- package/lib/providers/copilot.d.ts +2 -1
- package/lib/providers/copilot.js +10 -3
- package/lib/providers/grok.d.ts +2 -2
- package/lib/providers/grok.js +2 -2
- package/lib/providers/minimax-usage.d.ts +22 -1
- package/lib/providers/minimax-usage.js +37 -7
- package/lib/providers/pool-health.d.ts +2 -0
- package/lib/providers/pool-health.js +9 -0
- package/lib/providers/pool-usage.d.ts +13 -1
- package/lib/providers/pool-usage.js +39 -7
- package/lib/providers/pool.d.ts +7 -5
- package/lib/providers/pool.js +89 -12
- package/lib/providers/rate-limit.d.ts +0 -14
- package/lib/providers/rate-limit.js +0 -26
- package/lib/providers/replay.d.ts +4 -0
- package/lib/providers/replay.js +50 -0
- package/lib/providers/reset-redemption.d.ts +51 -0
- package/lib/providers/reset-redemption.js +102 -0
- package/lib/translate/anthropic.d.ts +21 -2
- package/lib/translate/anthropic.js +35 -11
- package/lib/translate/antigravity.js +13 -6
- package/lib/translate/chat-completions.js +1 -1
- package/lib/translate/resolved.d.ts +21 -0
- package/lib/translate/resolved.js +63 -3
- package/lib/translate/responses.js +8 -6
- package/lib/translate/sse.js +8 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -139,6 +139,35 @@ const en = {
|
|
|
139
139
|
usageColorPaceHint: "Yellow when usage leads elapsed time by {allowance} points; red at 90% used takes priority. Saved in this browser; only colors change.",
|
|
140
140
|
usageColorRemainingHint: "Red at 90% used; no yellow pace warnings. Reliable time markers remain visible. Saved in this browser.",
|
|
141
141
|
usagePlan: "Plan: {plan}",
|
|
142
|
+
resetCreditsTitle: "Usage limit resets",
|
|
143
|
+
resetCreditsAvailable: "{count} available",
|
|
144
|
+
resetCreditsError: "Usage limit resets unavailable: {message}",
|
|
145
|
+
resetCreditsErrorFixed: "Usage limit resets are unavailable. Refresh usage to try again.",
|
|
146
|
+
resetCreditReadOnly: "Read only. This page cannot spend a Claude reset.",
|
|
147
|
+
resetCreditReadOnlyLabel: "Read only",
|
|
148
|
+
resetCreditAvailable: "Available",
|
|
149
|
+
resetCreditNotUsable: "Not yet usable",
|
|
150
|
+
resetCreditPaused: "Paused",
|
|
151
|
+
resetCreditExhausted: "Exhausted",
|
|
152
|
+
resetCreditExpired: "Expired",
|
|
153
|
+
resetCreditRemaining: "{left} of {total} left",
|
|
154
|
+
resetCreditLeft: "{left} left",
|
|
155
|
+
resetCreditRemainingUnknown: "Remaining count unavailable",
|
|
156
|
+
resetCreditCooldownUntil: "Usable after {date}",
|
|
157
|
+
resetUseButton: "Use…",
|
|
158
|
+
resetUseChecking: "Checking…",
|
|
159
|
+
resetUseGuard: "You can use this reset when weekly usage reaches at least 80%.",
|
|
160
|
+
resetUseRestart: "Reset details are missing. Restart DSH, reload this page, then refresh usage.",
|
|
161
|
+
resetUseRefresh: "Refresh usage to verify current limits and reset availability.",
|
|
162
|
+
resetUseReady: "Use this reset — the earliest-expiring credit. Confirmation required.",
|
|
163
|
+
resetUseConfirmTitle: "Confirm full reset",
|
|
164
|
+
resetUseWarning: "This consumes one credit and resets weekly + 5-hour limits. This interface cannot undo it. Confirmation expires in 60 seconds.",
|
|
165
|
+
resetUseAcknowledge: "I understand that one credit will be consumed.",
|
|
166
|
+
resetUseConfirm: "Consume 1 reset",
|
|
167
|
+
resetUseSuccess: "Reset confirmed. Usage refreshed.",
|
|
168
|
+
resetCreditFull: "Full reset",
|
|
169
|
+
resetCreditExpires: "Expires {date}",
|
|
170
|
+
resetCreditExpiryUnknown: "Expiry date unavailable",
|
|
142
171
|
externalUsageTitle: "Built-in provider usage",
|
|
143
172
|
externalUsageConnected: "API key configured",
|
|
144
173
|
externalUsageNotConfigured: "Not configured",
|
|
@@ -190,8 +219,9 @@ const en = {
|
|
|
190
219
|
usageBadgeTitle: "Provider usage",
|
|
191
220
|
usageBadgeDisplay: "Status-bar quota display",
|
|
192
221
|
usageBadgeDisplayRecent: "Current / most recent provider with usage",
|
|
222
|
+
usageBadgeDisplayAlways: "Always show one provider, rotating through the rest",
|
|
193
223
|
usageBadgeDisplayHidden: "Hidden",
|
|
194
|
-
usageBadgeDisplayHint: "Saved automatically in this browser. One provider is shown at a time. Models without a quota source keep the most recent provider selected in this view, or show nothing. Hiding does not affect usage details here.",
|
|
224
|
+
usageBadgeDisplayHint: "Saved automatically in this browser. One provider is shown at a time. Models without a quota source keep the most recent provider selected in this view, or show nothing. Always show instead rotates through the providers with usage every 10 seconds while the current model has no quota source. Hiding does not affect usage details here.",
|
|
195
225
|
usageBadgeDisplaySaveFailed: "Could not save the display preference. Check browser storage permissions.",
|
|
196
226
|
usageBadgeCurrent: "current",
|
|
197
227
|
usageBadgeModelCount: "{count} model quotas",
|
|
@@ -310,6 +340,35 @@ const zh = {
|
|
|
310
340
|
usageColorPaceHint: "用量领先时间进度 {allowance} 个百分点时变黄;已用达到 90% 时优先变红。自动保存到当前浏览器,仅改变配色。",
|
|
311
341
|
usageColorRemainingHint: "已用达到 90% 时变红,不显示黄色节奏警告。可靠的时间标记仍保留,自动保存到当前浏览器。",
|
|
312
342
|
usagePlan: "计划:{plan}",
|
|
343
|
+
resetCreditsTitle: "用量限制重置",
|
|
344
|
+
resetCreditsAvailable: "可用 {count} 次",
|
|
345
|
+
resetCreditsError: "用量限制重置查询失败:{message}",
|
|
346
|
+
resetCreditsErrorFixed: "用量限制重置暂不可用,请刷新用量后重试。",
|
|
347
|
+
resetCreditReadOnly: "只读。此页面不能消耗 Claude 的重置额度。",
|
|
348
|
+
resetCreditReadOnlyLabel: "只读",
|
|
349
|
+
resetCreditAvailable: "可用",
|
|
350
|
+
resetCreditNotUsable: "暂不可用",
|
|
351
|
+
resetCreditPaused: "已暂停",
|
|
352
|
+
resetCreditExhausted: "已用尽",
|
|
353
|
+
resetCreditExpired: "已过期",
|
|
354
|
+
resetCreditRemaining: "剩余 {left} / {total}",
|
|
355
|
+
resetCreditLeft: "剩余 {left}",
|
|
356
|
+
resetCreditRemainingUnknown: "剩余次数不可用",
|
|
357
|
+
resetCreditCooldownUntil: "{date} 后可用",
|
|
358
|
+
resetUseButton: "使用…",
|
|
359
|
+
resetUseChecking: "正在检查…",
|
|
360
|
+
resetUseGuard: "每周用量达到 80% 后才可使用此重置。",
|
|
361
|
+
resetUseRestart: "缺少重置详情。请重启 DSH、重新加载页面并刷新用量。",
|
|
362
|
+
resetUseRefresh: "请刷新用量以验证当前限制和重置可用性。",
|
|
363
|
+
resetUseReady: "使用此最早到期的重置额度,操作前需要确认。",
|
|
364
|
+
resetUseConfirmTitle: "确认完整重置",
|
|
365
|
+
resetUseWarning: "将消耗一次额度并重置每周和 5 小时限制,无法撤销。确认将在 60 秒后过期。",
|
|
366
|
+
resetUseAcknowledge: "我理解将消耗一次额度。",
|
|
367
|
+
resetUseConfirm: "消耗一次重置",
|
|
368
|
+
resetUseSuccess: "重置已确认,用量已刷新。",
|
|
369
|
+
resetCreditFull: "完整重置",
|
|
370
|
+
resetCreditExpires: "{date} 到期",
|
|
371
|
+
resetCreditExpiryUnknown: "到期时间不可用",
|
|
313
372
|
externalUsageTitle: "内置供应商用量",
|
|
314
373
|
externalUsageConnected: "已配置 API 密钥",
|
|
315
374
|
externalUsageNotConfigured: "未配置",
|
|
@@ -361,8 +420,9 @@ const zh = {
|
|
|
361
420
|
usageBadgeTitle: "服务商用量",
|
|
362
421
|
usageBadgeDisplay: "状态栏额度显示",
|
|
363
422
|
usageBadgeDisplayRecent: "仅显示当前/最近使用的用量服务商",
|
|
423
|
+
usageBadgeDisplayAlways: "始终显示一家,其余服务商轮播",
|
|
364
424
|
usageBadgeDisplayHidden: "不显示",
|
|
365
|
-
usageBadgeDisplayHint: "
|
|
425
|
+
usageBadgeDisplayHint: "自动保存到当前浏览器。状态栏一次显示一家服务商;没有额度来源的模型沿用本视图最近选择的服务商,没有记录则隐藏。选择“始终显示”时,当前模型没有额度来源,就每 10 秒轮播一家有额度的服务商。关闭不影响本页的额度详情。",
|
|
366
426
|
usageBadgeDisplaySaveFailed: "显示设置保存失败,请检查浏览器存储权限。",
|
|
367
427
|
usageBadgeCurrent: "当前",
|
|
368
428
|
usageBadgeModelCount: "{count} 个模型配额",
|
|
@@ -377,6 +437,18 @@ const zh = {
|
|
|
377
437
|
commandFastUnavailable: "当前模型不支持快速档;/fast 仅对目录声明了 fast tier 的 Codex 模型可用"
|
|
378
438
|
};
|
|
379
439
|
|
|
440
|
+
//#endregion
|
|
441
|
+
//#region src/client/reset-action.ts
|
|
442
|
+
/** Explain client-side gating; the server independently revalidates before spending. */
|
|
443
|
+
function resetActionBlock(usage, now = Date.now()) {
|
|
444
|
+
const weekly = usage.windows?.find((w) => w.kind === "weekly" && w.scope === void 0);
|
|
445
|
+
if (!weekly || !Number.isFinite(weekly.usedPercent)) return "resetUseRefresh";
|
|
446
|
+
if (weekly.usedPercent < 80) return "resetUseGuard";
|
|
447
|
+
if (weekly.resetsAt === void 0 || weekly.resetsAt <= now || usage.resetCreditsError) return "resetUseRefresh";
|
|
448
|
+
if (!usage.resetCredits?.some((c) => c.id)) return "resetUseRestart";
|
|
449
|
+
if (!usage.resetCredits.some((c) => c.id && (c.expiresAt === void 0 || c.expiresAt > now))) return "resetUseRefresh";
|
|
450
|
+
}
|
|
451
|
+
|
|
380
452
|
//#endregion
|
|
381
453
|
//#region src/client/subscriptions-rpc.ts
|
|
382
454
|
/**
|
|
@@ -449,16 +521,7 @@ function mergeAccountChanges(latest, changes) {
|
|
|
449
521
|
|
|
450
522
|
//#endregion
|
|
451
523
|
//#region src/client/ProviderModelEditor.tsx
|
|
452
|
-
const border$1 = "
|
|
453
|
-
const control$1 = {
|
|
454
|
-
font: "inherit",
|
|
455
|
-
color: "inherit",
|
|
456
|
-
background: "transparent",
|
|
457
|
-
border: border$1,
|
|
458
|
-
borderRadius: 8,
|
|
459
|
-
padding: "6px 10px",
|
|
460
|
-
minWidth: 0
|
|
461
|
-
};
|
|
524
|
+
const border$1 = "0.5px solid var(--dsw-alias-border-l2, #ddd)";
|
|
462
525
|
const actions$1 = {
|
|
463
526
|
display: "flex",
|
|
464
527
|
flexWrap: "wrap",
|
|
@@ -567,10 +630,7 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
|
|
|
567
630
|
paddingTop: 12
|
|
568
631
|
},
|
|
569
632
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
570
|
-
style: {
|
|
571
|
-
margin: 0,
|
|
572
|
-
fontSize: 15
|
|
573
|
-
},
|
|
633
|
+
style: { margin: 0 },
|
|
574
634
|
children: t("modelsEdit")
|
|
575
635
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
576
636
|
style: {
|
|
@@ -580,22 +640,18 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
|
|
|
580
640
|
},
|
|
581
641
|
children: [
|
|
582
642
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
583
|
-
|
|
643
|
+
className: "dsh-subscription-hint",
|
|
584
644
|
children: t(provider === "cursor-subscription" ? "cursorManageHint" : "modelsHint")
|
|
585
645
|
}),
|
|
586
646
|
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
587
647
|
role: "alert",
|
|
588
|
-
style: {
|
|
589
|
-
margin: 0,
|
|
590
|
-
color: "var(--dsw-alias-state-error-primary, #b42318)"
|
|
591
|
-
},
|
|
592
648
|
children: error
|
|
593
649
|
}),
|
|
594
650
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
595
651
|
style: actions$1,
|
|
596
652
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
597
653
|
type: "button",
|
|
598
|
-
|
|
654
|
+
className: "dsh-subscription-quiet",
|
|
599
655
|
disabled: busy || disabled || dirty,
|
|
600
656
|
onClick: () => {
|
|
601
657
|
load(true);
|
|
@@ -635,10 +691,7 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
|
|
|
635
691
|
style: actions$1,
|
|
636
692
|
children: [
|
|
637
693
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
638
|
-
style: {
|
|
639
|
-
...control$1,
|
|
640
|
-
flex: "1 1 180px"
|
|
641
|
-
},
|
|
694
|
+
style: { flex: "1 1 180px" },
|
|
642
695
|
value: query,
|
|
643
696
|
onChange: (event) => setQuery(event.target.value),
|
|
644
697
|
placeholder: t("modelDefaultsFilterPlaceholder"),
|
|
@@ -646,7 +699,6 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
|
|
|
646
699
|
}),
|
|
647
700
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
648
701
|
type: "button",
|
|
649
|
-
style: control$1,
|
|
650
702
|
onClick: () => edit({
|
|
651
703
|
...draft,
|
|
652
704
|
visibleModels: allModels.map((model) => model.id)
|
|
@@ -655,7 +707,6 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
|
|
|
655
707
|
}),
|
|
656
708
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
657
709
|
type: "button",
|
|
658
|
-
style: control$1,
|
|
659
710
|
onClick: () => edit({
|
|
660
711
|
...draft,
|
|
661
712
|
visibleModels: []
|
|
@@ -703,7 +754,6 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
|
|
|
703
754
|
children: [(model.efforts?.length ?? 0) > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
704
755
|
style: actions$1,
|
|
705
756
|
children: [t("modelDefaultsTitle"), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
706
|
-
style: control$1,
|
|
707
757
|
"aria-label": `${model.name} ${t("modelDefaultsTitle")}`,
|
|
708
758
|
value: efforts[model.id] ?? "",
|
|
709
759
|
onChange: (event) => {
|
|
@@ -739,10 +789,7 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
|
|
|
739
789
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
740
790
|
style: actions$1,
|
|
741
791
|
children: [t("modelsContext"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
742
|
-
style: {
|
|
743
|
-
...control$1,
|
|
744
|
-
width: 140
|
|
745
|
-
},
|
|
792
|
+
style: { width: 140 },
|
|
746
793
|
inputMode: "numeric",
|
|
747
794
|
value: contexts[model.id] ?? "",
|
|
748
795
|
"aria-label": `${model.name} ${t("modelsContext")}`,
|
|
@@ -796,28 +843,218 @@ const ProviderModelEditor = (0, react.forwardRef)(function ProviderModelEditor$1
|
|
|
796
843
|
});
|
|
797
844
|
});
|
|
798
845
|
|
|
846
|
+
//#endregion
|
|
847
|
+
//#region src/client/provider-settings-styles.ts
|
|
848
|
+
/**
|
|
849
|
+
* The host loads one JS client bundle, so keep this small, scoped stylesheet
|
|
850
|
+
* with the dialog instead of relying on a separate CSS asset. Geometry and
|
|
851
|
+
* theme tokens follow the host's settings-form and ui-primitives controls.
|
|
852
|
+
*
|
|
853
|
+
* `color-scheme` is left to the host deliberately. Its boot script sets the
|
|
854
|
+
* property on `:root`, and it inherits, so native controls inside these panels
|
|
855
|
+
* follow the theme. Upstream also pins `color-scheme: light` here and flips it
|
|
856
|
+
* back under `body[data-ds-dark-theme]`; without that flip our scoped rules are
|
|
857
|
+
* more specific than `:root` and would force every native control light inside
|
|
858
|
+
* a dark theme.
|
|
859
|
+
*/
|
|
860
|
+
const formScope = ":is(.dsh-subscription-manager, .dsh-subscriptions-settings)";
|
|
861
|
+
const providerSettingsCss = `
|
|
862
|
+
.dsh-subscription-manager {
|
|
863
|
+
box-sizing: border-box;
|
|
864
|
+
padding: 0;
|
|
865
|
+
border: 0;
|
|
866
|
+
border-radius: var(--dsw-radius-panel, 16px);
|
|
867
|
+
background: var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-layer-1));
|
|
868
|
+
color: var(--dsw-alias-label-primary);
|
|
869
|
+
box-shadow: var(--dsw-elevation-prominent, 0 20px 70px #0004);
|
|
870
|
+
font-family: inherit;
|
|
871
|
+
font-size: 13px;
|
|
872
|
+
line-height: 1.5;
|
|
873
|
+
}
|
|
874
|
+
.dsh-subscriptions-settings {
|
|
875
|
+
font-family: inherit;
|
|
876
|
+
font-size: 13px;
|
|
877
|
+
line-height: 1.5;
|
|
878
|
+
}
|
|
879
|
+
.dsh-subscription-manager::backdrop {
|
|
880
|
+
background: var(--dsw-alias-bg-mask-1, #0006);
|
|
881
|
+
backdrop-filter: var(--dsw-mask-blur, none);
|
|
882
|
+
}
|
|
883
|
+
${formScope} h2 {
|
|
884
|
+
font-size: 16px;
|
|
885
|
+
line-height: 24px;
|
|
886
|
+
font-weight: 500;
|
|
887
|
+
}
|
|
888
|
+
${formScope} h3 {
|
|
889
|
+
font-size: 14px;
|
|
890
|
+
line-height: 22px;
|
|
891
|
+
font-weight: 500;
|
|
892
|
+
}
|
|
893
|
+
${formScope} strong,
|
|
894
|
+
${formScope} .dsh-subscription-label {
|
|
895
|
+
font-size: 13px;
|
|
896
|
+
line-height: 1.5;
|
|
897
|
+
font-weight: 500;
|
|
898
|
+
}
|
|
899
|
+
${formScope} legend {
|
|
900
|
+
font-size: 14px;
|
|
901
|
+
line-height: 22px;
|
|
902
|
+
font-weight: 500;
|
|
903
|
+
}
|
|
904
|
+
${formScope} small,
|
|
905
|
+
${formScope} .dsh-subscription-hint,
|
|
906
|
+
${formScope} [role="status"] {
|
|
907
|
+
margin: 0;
|
|
908
|
+
font-size: 12px;
|
|
909
|
+
line-height: 1.5;
|
|
910
|
+
color: var(--dsw-alias-label-tertiary);
|
|
911
|
+
}
|
|
912
|
+
${formScope} [role="alert"] {
|
|
913
|
+
margin: 0;
|
|
914
|
+
font-size: 12px;
|
|
915
|
+
line-height: 1.5;
|
|
916
|
+
color: var(--dsw-alias-state-error-primary, #b42318);
|
|
917
|
+
}
|
|
918
|
+
${formScope} input:not([type="checkbox"]),
|
|
919
|
+
${formScope} select {
|
|
920
|
+
box-sizing: border-box;
|
|
921
|
+
min-width: 0;
|
|
922
|
+
height: 34px;
|
|
923
|
+
padding: 0 12px;
|
|
924
|
+
border: 0.5px solid var(--dsw-alias-border-l4, var(--dsw-alias-border-l2));
|
|
925
|
+
border-radius: var(--dsw-radius-md, 8px);
|
|
926
|
+
background: var(--dsw-alias-bg-layer-3, var(--dsw-alias-bg-layer-1));
|
|
927
|
+
color: var(--dsw-alias-label-primary);
|
|
928
|
+
font: inherit;
|
|
929
|
+
font-size: 13px;
|
|
930
|
+
font-weight: 400;
|
|
931
|
+
line-height: 1.5;
|
|
932
|
+
}
|
|
933
|
+
${formScope} input::placeholder {
|
|
934
|
+
color: var(--dsw-alias-label-tertiary);
|
|
935
|
+
opacity: 1;
|
|
936
|
+
}
|
|
937
|
+
${formScope} input:not([type="checkbox"]):focus-visible,
|
|
938
|
+
${formScope} select:focus-visible {
|
|
939
|
+
outline: none;
|
|
940
|
+
border-color: var(--dsw-alias-state-business-primary, var(--dsw-alias-brand-primary));
|
|
941
|
+
}
|
|
942
|
+
${formScope} input:not([type="checkbox"]):disabled,
|
|
943
|
+
${formScope} select:disabled {
|
|
944
|
+
color: var(--dsw-alias-label-tertiary);
|
|
945
|
+
cursor: default;
|
|
946
|
+
}
|
|
947
|
+
${formScope} input[aria-invalid="true"] {
|
|
948
|
+
border-color: var(--dsw-alias-state-error-primary, #b42318);
|
|
949
|
+
}
|
|
950
|
+
${formScope} option {
|
|
951
|
+
background: var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-layer-1));
|
|
952
|
+
color: var(--dsw-alias-label-primary);
|
|
953
|
+
}
|
|
954
|
+
${formScope} label:has(> input[type="checkbox"]) {
|
|
955
|
+
display: flex;
|
|
956
|
+
align-items: flex-start;
|
|
957
|
+
gap: 6px;
|
|
958
|
+
font-size: 14px;
|
|
959
|
+
line-height: 20px;
|
|
960
|
+
cursor: pointer;
|
|
961
|
+
}
|
|
962
|
+
${formScope} input[type="checkbox"] {
|
|
963
|
+
flex: 0 0 auto;
|
|
964
|
+
width: 16px;
|
|
965
|
+
height: 16px;
|
|
966
|
+
margin: 2px 0;
|
|
967
|
+
accent-color: var(--dsw-alias-brand-primary);
|
|
968
|
+
cursor: inherit;
|
|
969
|
+
}
|
|
970
|
+
${formScope} label:has(> input[type="checkbox"]:disabled) {
|
|
971
|
+
cursor: default;
|
|
972
|
+
opacity: 0.5;
|
|
973
|
+
}
|
|
974
|
+
${formScope} button {
|
|
975
|
+
box-sizing: border-box;
|
|
976
|
+
display: inline-flex;
|
|
977
|
+
align-items: center;
|
|
978
|
+
justify-content: center;
|
|
979
|
+
flex-shrink: 0;
|
|
980
|
+
min-height: 28px;
|
|
981
|
+
padding: 0 10px;
|
|
982
|
+
border: 0.5px solid var(--dsw-alias-border-l3, var(--dsw-alias-border-l2));
|
|
983
|
+
border-radius: var(--dsw-radius-sm, 6px);
|
|
984
|
+
background: transparent;
|
|
985
|
+
color: var(--dsw-alias-label-primary);
|
|
986
|
+
font: inherit;
|
|
987
|
+
font-size: 12px;
|
|
988
|
+
line-height: 18px;
|
|
989
|
+
cursor: pointer;
|
|
990
|
+
}
|
|
991
|
+
${formScope} button:hover:not(:disabled) {
|
|
992
|
+
background: var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-3));
|
|
993
|
+
}
|
|
994
|
+
${formScope} button:active:not(:disabled) {
|
|
995
|
+
background: var(--dsw-alias-interactive-bg-active, var(--dsw-alias-bg-layer-3));
|
|
996
|
+
}
|
|
997
|
+
${formScope} button:disabled {
|
|
998
|
+
opacity: 0.4;
|
|
999
|
+
cursor: default;
|
|
1000
|
+
}
|
|
1001
|
+
${formScope} button.dsh-subscription-quiet {
|
|
1002
|
+
border-color: transparent;
|
|
1003
|
+
color: var(--dsw-alias-label-secondary, var(--dsw-alias-label-primary));
|
|
1004
|
+
}
|
|
1005
|
+
${formScope} :is(footer, .dsh-subscription-dialog-actions) button {
|
|
1006
|
+
min-height: 34px;
|
|
1007
|
+
padding: 0 14px;
|
|
1008
|
+
border-radius: var(--dsw-radius-md, 8px);
|
|
1009
|
+
font-size: 13px;
|
|
1010
|
+
line-height: 1.5;
|
|
1011
|
+
}
|
|
1012
|
+
${formScope} button.dsh-subscription-primary {
|
|
1013
|
+
border-color: transparent;
|
|
1014
|
+
background: var(--dsw-alias-button-primary-fill, var(--dsw-alias-label-primary));
|
|
1015
|
+
color: var(--dsw-alias-label-primary-foreground, var(--dsw-alias-bg-layer-1));
|
|
1016
|
+
font-weight: 500;
|
|
1017
|
+
}
|
|
1018
|
+
${formScope} button.dsh-subscription-primary:hover:not(:disabled) {
|
|
1019
|
+
background: var(--dsw-alias-button-primary-hover, var(--dsw-alias-label-secondary));
|
|
1020
|
+
}
|
|
1021
|
+
${formScope} button:focus-visible,
|
|
1022
|
+
${formScope} input[type="checkbox"]:focus-visible,
|
|
1023
|
+
${formScope} summary:focus-visible {
|
|
1024
|
+
outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
|
|
1025
|
+
outline-offset: 2px;
|
|
1026
|
+
}
|
|
1027
|
+
${formScope} summary {
|
|
1028
|
+
border-radius: var(--dsw-radius-sm, 6px);
|
|
1029
|
+
}
|
|
1030
|
+
${formScope} summary:hover {
|
|
1031
|
+
color: var(--dsw-alias-label-secondary, var(--dsw-alias-label-primary));
|
|
1032
|
+
}
|
|
1033
|
+
`;
|
|
1034
|
+
/** Composer controls retain their own geometry, separate from settings forms. */
|
|
1035
|
+
const subscriptionChromeCss = `
|
|
1036
|
+
.dsh-subscription-usage-pill { corner-shape: round; }
|
|
1037
|
+
.dsh-subscription-usage-panel {
|
|
1038
|
+
--dsw-elevation-stroke-color: var(--dsw-alias-border-l1);
|
|
1039
|
+
backdrop-filter: var(--dsw-menu-backdrop-filter, none);
|
|
1040
|
+
}
|
|
1041
|
+
.dsh-subscription-speed button:hover:not(:disabled) {
|
|
1042
|
+
--dsh-subscription-speed-hover: var(--dsw-alias-interactive-bg-hover);
|
|
1043
|
+
}
|
|
1044
|
+
.dsh-subscription-speed button:active:not(:disabled) {
|
|
1045
|
+
--dsh-subscription-speed-hover: var(--dsw-alias-interactive-bg-active);
|
|
1046
|
+
}
|
|
1047
|
+
.dsh-subscription-speed button:disabled { opacity: 0.4; cursor: default; }
|
|
1048
|
+
.dsh-subscription-speed button:focus-visible,
|
|
1049
|
+
.dsh-subscription-usage-pill:focus-visible {
|
|
1050
|
+
outline: var(--dsw-focus-ring-width, 2px) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
|
|
1051
|
+
outline-offset: 2px;
|
|
1052
|
+
}
|
|
1053
|
+
`;
|
|
1054
|
+
|
|
799
1055
|
//#endregion
|
|
800
1056
|
//#region src/client/ProviderAccountManager.tsx
|
|
801
|
-
const border = "
|
|
802
|
-
const control = {
|
|
803
|
-
font: "inherit",
|
|
804
|
-
color: "inherit",
|
|
805
|
-
background: "var(--dsw-alias-bg-layer-1)",
|
|
806
|
-
border,
|
|
807
|
-
borderRadius: 8,
|
|
808
|
-
padding: "7px 12px",
|
|
809
|
-
minWidth: 0
|
|
810
|
-
};
|
|
811
|
-
const button = {
|
|
812
|
-
...control,
|
|
813
|
-
cursor: "pointer"
|
|
814
|
-
};
|
|
815
|
-
const hint = {
|
|
816
|
-
margin: 0,
|
|
817
|
-
fontSize: 12,
|
|
818
|
-
lineHeight: 1.6,
|
|
819
|
-
color: "var(--dsw-alias-label-tertiary)"
|
|
820
|
-
};
|
|
1057
|
+
const border = "0.5px solid var(--dsw-alias-border-l2)";
|
|
821
1058
|
const stack = {
|
|
822
1059
|
display: "grid",
|
|
823
1060
|
gap: 12,
|
|
@@ -922,7 +1159,8 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
|
|
|
922
1159
|
if (alive.current) setSaving(false);
|
|
923
1160
|
}
|
|
924
1161
|
}
|
|
925
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.
|
|
1162
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dialog", {
|
|
1163
|
+
className: "dsh-subscription-manager",
|
|
926
1164
|
ref: dialog,
|
|
927
1165
|
"aria-labelledby": title,
|
|
928
1166
|
"aria-describedby": description,
|
|
@@ -934,16 +1172,9 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
|
|
|
934
1172
|
width: 620,
|
|
935
1173
|
maxWidth: "calc(100vw - 32px)",
|
|
936
1174
|
maxHeight: "calc(100dvh - 32px)",
|
|
937
|
-
boxSizing: "border-box",
|
|
938
|
-
padding: 0,
|
|
939
|
-
border,
|
|
940
|
-
borderRadius: 16,
|
|
941
|
-
color: "var(--dsw-alias-label-primary)",
|
|
942
|
-
background: "var(--dsw-alias-bg-layer-1)",
|
|
943
|
-
boxShadow: "0 20px 70px #0004",
|
|
944
1175
|
overflow: "auto"
|
|
945
1176
|
},
|
|
946
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1177
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: providerSettingsCss }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
947
1178
|
style: {
|
|
948
1179
|
...stack,
|
|
949
1180
|
padding: 20
|
|
@@ -956,15 +1187,11 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
|
|
|
956
1187
|
},
|
|
957
1188
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
958
1189
|
id: title,
|
|
959
|
-
style: {
|
|
960
|
-
margin: 0,
|
|
961
|
-
fontSize: 18
|
|
962
|
-
},
|
|
1190
|
+
style: { margin: 0 },
|
|
963
1191
|
children: t("accountsTitle", { provider: name })
|
|
964
1192
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
965
1193
|
type: "button",
|
|
966
1194
|
autoFocus: true,
|
|
967
|
-
style: button,
|
|
968
1195
|
disabled: saving,
|
|
969
1196
|
onClick: onClose,
|
|
970
1197
|
children: t("imageClose")
|
|
@@ -972,25 +1199,20 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
|
|
|
972
1199
|
}),
|
|
973
1200
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
974
1201
|
id: description,
|
|
975
|
-
|
|
1202
|
+
className: "dsh-subscription-hint",
|
|
976
1203
|
children: t(provider === "cursor-subscription" ? "cursorAccountsHint" : "accountsHint")
|
|
977
1204
|
}),
|
|
978
1205
|
error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
979
1206
|
role: "alert",
|
|
980
|
-
style: {
|
|
981
|
-
...hint,
|
|
982
|
-
color: "var(--dsw-alias-state-error-primary)"
|
|
983
|
-
},
|
|
984
1207
|
children: error
|
|
985
1208
|
}),
|
|
986
1209
|
loading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
987
1210
|
role: "status",
|
|
988
|
-
|
|
1211
|
+
className: "dsh-subscription-hint",
|
|
989
1212
|
children: t("accountsLoading")
|
|
990
1213
|
}),
|
|
991
1214
|
!loading && !catalog && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
992
1215
|
type: "button",
|
|
993
|
-
style: button,
|
|
994
1216
|
onClick: () => setAttempt((value) => value + 1),
|
|
995
1217
|
children: t("modelDefaultsRetry")
|
|
996
1218
|
}),
|
|
@@ -1004,24 +1226,20 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
|
|
|
1004
1226
|
},
|
|
1005
1227
|
children: [
|
|
1006
1228
|
catalog.accounts.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1007
|
-
|
|
1229
|
+
className: "dsh-subscription-hint",
|
|
1008
1230
|
children: t(provider === "cursor-subscription" ? "cursorManageSignIn" : "accountsEmpty")
|
|
1009
1231
|
}),
|
|
1010
1232
|
provider === "cursor-subscription" && catalog.accounts.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
|
|
1011
1233
|
style: {
|
|
1012
1234
|
border,
|
|
1013
|
-
borderRadius:
|
|
1235
|
+
borderRadius: "var(--dsw-radius-lg, 12px)",
|
|
1014
1236
|
padding: 14
|
|
1015
1237
|
},
|
|
1016
1238
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", {
|
|
1017
|
-
style: {
|
|
1018
|
-
padding: "0 6px",
|
|
1019
|
-
fontWeight: 600,
|
|
1020
|
-
fontSize: 14
|
|
1021
|
-
},
|
|
1239
|
+
style: { padding: "0 6px" },
|
|
1022
1240
|
children: name
|
|
1023
1241
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1024
|
-
|
|
1242
|
+
className: "dsh-subscription-hint",
|
|
1025
1243
|
children: t("cursorConnected")
|
|
1026
1244
|
})]
|
|
1027
1245
|
}),
|
|
@@ -1033,7 +1251,7 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
|
|
|
1033
1251
|
style: {
|
|
1034
1252
|
...stack,
|
|
1035
1253
|
border,
|
|
1036
|
-
borderRadius:
|
|
1254
|
+
borderRadius: "var(--dsw-radius-lg, 12px)",
|
|
1037
1255
|
padding: 14,
|
|
1038
1256
|
margin: 0
|
|
1039
1257
|
},
|
|
@@ -1041,15 +1259,13 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
|
|
|
1041
1259
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("legend", {
|
|
1042
1260
|
style: {
|
|
1043
1261
|
padding: "0 6px",
|
|
1044
|
-
fontWeight: 600,
|
|
1045
|
-
fontSize: 14,
|
|
1046
1262
|
overflowWrap: "anywhere",
|
|
1047
1263
|
maxWidth: "100%"
|
|
1048
1264
|
},
|
|
1049
1265
|
children: account.label
|
|
1050
1266
|
}),
|
|
1051
1267
|
account.unavailable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1052
|
-
|
|
1268
|
+
className: "dsh-subscription-hint",
|
|
1053
1269
|
children: t("accountsCatalogUnavailable")
|
|
1054
1270
|
}),
|
|
1055
1271
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
@@ -1058,10 +1274,9 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
|
|
|
1058
1274
|
gap: 6
|
|
1059
1275
|
},
|
|
1060
1276
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1061
|
-
|
|
1277
|
+
className: "dsh-subscription-label",
|
|
1062
1278
|
children: t("accountsAlias")
|
|
1063
1279
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1064
|
-
style: control,
|
|
1065
1280
|
value: preferences.alias ?? "",
|
|
1066
1281
|
placeholder: account.label,
|
|
1067
1282
|
onChange: (event) => {
|
|
@@ -1097,7 +1312,7 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
|
|
|
1097
1312
|
t("accountsIndependent")
|
|
1098
1313
|
] }),
|
|
1099
1314
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1100
|
-
|
|
1315
|
+
className: "dsh-subscription-hint",
|
|
1101
1316
|
children: t("accountsIndependentHint")
|
|
1102
1317
|
}),
|
|
1103
1318
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
|
|
@@ -1117,7 +1332,7 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
|
|
|
1117
1332
|
},
|
|
1118
1333
|
children: [
|
|
1119
1334
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1120
|
-
|
|
1335
|
+
className: "dsh-subscription-hint",
|
|
1121
1336
|
children: t("accountsModelsHint")
|
|
1122
1337
|
}),
|
|
1123
1338
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [
|
|
@@ -1138,7 +1353,6 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
|
|
|
1138
1353
|
style: actions,
|
|
1139
1354
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1140
1355
|
type: "button",
|
|
1141
|
-
style: button,
|
|
1142
1356
|
onClick: () => edit(account.key, {
|
|
1143
1357
|
...preferences,
|
|
1144
1358
|
poolModels: models.map((model) => model.id)
|
|
@@ -1146,7 +1360,6 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
|
|
|
1146
1360
|
children: t("modelsSelectAll")
|
|
1147
1361
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1148
1362
|
type: "button",
|
|
1149
|
-
style: button,
|
|
1150
1363
|
onClick: () => edit(account.key, {
|
|
1151
1364
|
...preferences,
|
|
1152
1365
|
poolModels: []
|
|
@@ -1162,10 +1375,7 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
|
|
|
1162
1375
|
overflowY: "auto"
|
|
1163
1376
|
},
|
|
1164
1377
|
children: [models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
1165
|
-
style: {
|
|
1166
|
-
fontSize: 13,
|
|
1167
|
-
overflowWrap: "anywhere"
|
|
1168
|
-
},
|
|
1378
|
+
style: { overflowWrap: "anywhere" },
|
|
1169
1379
|
children: [
|
|
1170
1380
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
1171
1381
|
type: "checkbox",
|
|
@@ -1185,7 +1395,7 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
|
|
|
1185
1395
|
model.unavailable && ` (${t("modelsUnavailable")})`
|
|
1186
1396
|
]
|
|
1187
1397
|
}, model.id)), models.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1188
|
-
|
|
1398
|
+
className: "dsh-subscription-hint",
|
|
1189
1399
|
children: t("accountsNoModels")
|
|
1190
1400
|
})]
|
|
1191
1401
|
})
|
|
@@ -1209,17 +1419,13 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
|
|
|
1209
1419
|
...stack,
|
|
1210
1420
|
gap: 8,
|
|
1211
1421
|
borderTop: border,
|
|
1212
|
-
padding: "14px 0
|
|
1422
|
+
padding: "14px 0 8px",
|
|
1213
1423
|
position: "sticky",
|
|
1214
1424
|
bottom: 0,
|
|
1215
|
-
background: "var(--dsw-alias-bg-layer-1)"
|
|
1425
|
+
background: "var(--dsw-alias-bg-layer-2, var(--dsw-alias-bg-layer-1))"
|
|
1216
1426
|
},
|
|
1217
1427
|
children: [saveError && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1218
1428
|
role: "alert",
|
|
1219
|
-
style: {
|
|
1220
|
-
...hint,
|
|
1221
|
-
color: "var(--dsw-alias-state-error-primary)"
|
|
1222
|
-
},
|
|
1223
1429
|
children: saveError
|
|
1224
1430
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1225
1431
|
style: {
|
|
@@ -1228,16 +1434,12 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
|
|
|
1228
1434
|
},
|
|
1229
1435
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1230
1436
|
type: "button",
|
|
1231
|
-
style: button,
|
|
1232
1437
|
disabled: saving,
|
|
1233
1438
|
onClick: onClose,
|
|
1234
1439
|
children: t("cancel")
|
|
1235
1440
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1236
1441
|
type: "button",
|
|
1237
|
-
|
|
1238
|
-
...button,
|
|
1239
|
-
fontWeight: 600
|
|
1240
|
-
},
|
|
1442
|
+
className: "dsh-subscription-primary",
|
|
1241
1443
|
disabled: loading || saving || !Object.keys(changes).length && !modelsDirty,
|
|
1242
1444
|
onClick: () => {
|
|
1243
1445
|
save();
|
|
@@ -1247,7 +1449,7 @@ function ProviderAccountManager({ provider, name, rpc, t, onClose }) {
|
|
|
1247
1449
|
})]
|
|
1248
1450
|
})
|
|
1249
1451
|
]
|
|
1250
|
-
})
|
|
1452
|
+
})]
|
|
1251
1453
|
});
|
|
1252
1454
|
}
|
|
1253
1455
|
|
|
@@ -1402,7 +1604,8 @@ const USAGE_BADGE_REFRESH_EVENT = "dsh:subscriptions:usage-refresh";
|
|
|
1402
1604
|
function readUsageBadgeMode() {
|
|
1403
1605
|
if (typeof window === "undefined") return "recent";
|
|
1404
1606
|
try {
|
|
1405
|
-
|
|
1607
|
+
const value = window.localStorage.getItem(MODE_KEY);
|
|
1608
|
+
return value === "hidden" || value === "always" ? value : "recent";
|
|
1406
1609
|
} catch (error) {
|
|
1407
1610
|
if (!(error instanceof DOMException) || error.name !== "SecurityError") throw error;
|
|
1408
1611
|
return "recent";
|
|
@@ -1410,7 +1613,7 @@ function readUsageBadgeMode() {
|
|
|
1410
1613
|
}
|
|
1411
1614
|
/** Save first, then notify; the settings control reports a rejected write. */
|
|
1412
1615
|
function setUsageBadgeMode(mode) {
|
|
1413
|
-
if (mode !== "recent" && mode !== "hidden") throw new TypeError("Invalid subscription usage display mode");
|
|
1616
|
+
if (mode !== "recent" && mode !== "always" && mode !== "hidden") throw new TypeError("Invalid subscription usage display mode");
|
|
1414
1617
|
window.localStorage.setItem(MODE_KEY, mode);
|
|
1415
1618
|
window.dispatchEvent(new Event(MODE_EVENT));
|
|
1416
1619
|
}
|
|
@@ -1466,10 +1669,23 @@ function resetCountdownParts(ms) {
|
|
|
1466
1669
|
}
|
|
1467
1670
|
].filter((part) => part.count > 0).slice(0, 2);
|
|
1468
1671
|
}
|
|
1672
|
+
/**
|
|
1673
|
+
* Whether the reported percentage still describes the window now. Only a fresh
|
|
1674
|
+
* reading may be compared with the current time (pace warnings); an old one
|
|
1675
|
+
* keeps its absolute color. This does not decide whether the time cursor is
|
|
1676
|
+
* drawn: where the window stands in time never depends on the reading.
|
|
1677
|
+
*/
|
|
1469
1678
|
function isUsageFresh(window$1, observation, now = Date.now()) {
|
|
1470
1679
|
return validUsage(window$1.usedPercent) && observation.stale !== true && observation.observedAt !== void 0 && Number.isFinite(observation.observedAt) && observation.observedAt <= now && now - observation.observedAt <= USAGE_FRESHNESS_MS && (window$1.resetsAt === void 0 || Number.isFinite(window$1.resetsAt) && window$1.resetsAt > now);
|
|
1471
1680
|
}
|
|
1472
|
-
/**
|
|
1681
|
+
/**
|
|
1682
|
+
* How far through its window the clock is, from the window's own timing alone.
|
|
1683
|
+
* It ignores the percentage and how recently it was read, so an unused,
|
|
1684
|
+
* stale, aged or unobserved reading keeps its cursor whenever the timing
|
|
1685
|
+
* places it. Returns undefined when the timing cannot: only an explicit
|
|
1686
|
+
* interval or a provider-verified fixed duration supports linear pace, and no
|
|
1687
|
+
* start is invented from a window's kind or label.
|
|
1688
|
+
*/
|
|
1473
1689
|
function elapsedPercent(window$1, now = Date.now()) {
|
|
1474
1690
|
const end = window$1.resetsAt;
|
|
1475
1691
|
if (end === void 0 || !Number.isFinite(end) || end <= now) return void 0;
|
|
@@ -1548,17 +1764,18 @@ function UsageMeter({ window: quota, t, style, observedAt, stale }) {
|
|
|
1548
1764
|
observedAt,
|
|
1549
1765
|
stale
|
|
1550
1766
|
}, current);
|
|
1551
|
-
const elapsed =
|
|
1552
|
-
const
|
|
1553
|
-
const
|
|
1767
|
+
const elapsed = elapsedPercent(quota, current);
|
|
1768
|
+
const pace = fresh ? elapsed : void 0;
|
|
1769
|
+
const state = usageColorState(quota.usedPercent, pace, preset, fresh);
|
|
1770
|
+
const lead = pace === void 0 ? 0 : Math.round(used - pace);
|
|
1554
1771
|
const label = [
|
|
1555
1772
|
valid ? t("usageMeterUsed", {
|
|
1556
1773
|
used: Math.round(used),
|
|
1557
1774
|
remaining: Math.round(100 - used)
|
|
1558
1775
|
}) : t("usageMeterInvalid"),
|
|
1559
|
-
!valid ? "" : !fresh ? t("usageMeterStale") : state === "red" ? t("usageMeterNearLimit") :
|
|
1776
|
+
!valid ? "" : !fresh ? t("usageMeterStale") : state === "red" ? t("usageMeterNearLimit") : pace === void 0 && preset !== "remaining" ? t("usageMeterUnknownTime") : state === "yellow" ? t("usageMeterAhead") : t("usageMeterNoWarning"),
|
|
1560
1777
|
elapsed === void 0 ? "" : t("usageMeterPace", { elapsed: Math.round(elapsed) }),
|
|
1561
|
-
|
|
1778
|
+
pace === void 0 ? "" : lead > 0 ? t("usageMeterPaceAhead", { points: lead }) : lead < 0 ? t("usageMeterPaceBehind", { points: -lead }) : t("usageMeterPaceEven"),
|
|
1562
1779
|
quota.resetsAt !== void 0 && quota.resetsAt > current ? t("usageMeterReset", { duration: resetCountdownParts(quota.resetsAt - current).map((part) => t(UNIT_KEYS[part.unit][part.count === 1 ? 0 : 1], { count: part.count })).join(" ") }) : ""
|
|
1563
1780
|
].filter(Boolean).join(" · ");
|
|
1564
1781
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -1579,7 +1796,7 @@ function UsageMeter({ window: quota, t, style, observedAt, stale }) {
|
|
|
1579
1796
|
height: "100%",
|
|
1580
1797
|
borderRadius: "inherit",
|
|
1581
1798
|
width: `${used}%`,
|
|
1582
|
-
background: usageBarColor(quota.usedPercent,
|
|
1799
|
+
background: usageBarColor(quota.usedPercent, pace, preset, fresh)
|
|
1583
1800
|
} }), elapsed !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1584
1801
|
"aria-hidden": "true",
|
|
1585
1802
|
"data-usage-time-marker": true,
|
|
@@ -1623,6 +1840,21 @@ const SOURCES = [
|
|
|
1623
1840
|
function errorText(error) {
|
|
1624
1841
|
return error instanceof Error ? error.message : String(error);
|
|
1625
1842
|
}
|
|
1843
|
+
/**
|
|
1844
|
+
* Row label of one window on an external usage card. A session or weekly
|
|
1845
|
+
* window appends the model it belongs to when the provider names one (MiniMax
|
|
1846
|
+
* reports a window per model), so two models' weekly rows stay distinguishable.
|
|
1847
|
+
* The monthly pool is a scope on an `other` window, not a model.
|
|
1848
|
+
* @param t - section translate.
|
|
1849
|
+
* @param window - the reported window.
|
|
1850
|
+
* @returns the localized label, e.g. "Weekly · general".
|
|
1851
|
+
*/
|
|
1852
|
+
function externalUsageWindowLabel(t, window$1) {
|
|
1853
|
+
const named = window$1.scope !== void 0 && window$1.scope !== "";
|
|
1854
|
+
if (window$1.kind === "other") return window$1.scope === "Monthly" ? t("usageMonthly") : named ? window$1.scope : t("usageWindow");
|
|
1855
|
+
const base = window$1.kind === "session" ? t("usageSession") : t("usageWeekly");
|
|
1856
|
+
return named ? `${base} · ${window$1.scope}` : base;
|
|
1857
|
+
}
|
|
1626
1858
|
/** Quota cards for API-key providers already available through DSH itself. */
|
|
1627
1859
|
function ExternalUsageCards({ rpc, t }) {
|
|
1628
1860
|
const [status, setStatus] = (0, react.useState)();
|
|
@@ -1755,7 +1987,7 @@ function ExternalUsageCards({ rpc, t }) {
|
|
|
1755
1987
|
}),
|
|
1756
1988
|
snapshot?.windows?.map((window$1, index) => {
|
|
1757
1989
|
const percent = displayUsedPercent(window$1.usedPercent);
|
|
1758
|
-
const label =
|
|
1990
|
+
const label = externalUsageWindowLabel(t, window$1);
|
|
1759
1991
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1760
1992
|
style: subscriptionCardStyles.usageRow,
|
|
1761
1993
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -2032,6 +2264,216 @@ function CursorCard({ rpc, t }) {
|
|
|
2032
2264
|
});
|
|
2033
2265
|
}
|
|
2034
2266
|
|
|
2267
|
+
//#endregion
|
|
2268
|
+
//#region src/client/reset-credits-view.tsx
|
|
2269
|
+
const STATE_KEYS = {
|
|
2270
|
+
available: "resetCreditAvailable",
|
|
2271
|
+
notUsable: "resetCreditNotUsable",
|
|
2272
|
+
paused: "resetCreditPaused",
|
|
2273
|
+
exhausted: "resetCreditExhausted",
|
|
2274
|
+
expired: "resetCreditExpired"
|
|
2275
|
+
};
|
|
2276
|
+
/**
|
|
2277
|
+
* Classify one grant. Expired outranks every other flag. A future
|
|
2278
|
+
* `cooldownUntil` or `usableNow: false` is not usable even when `claimable`
|
|
2279
|
+
* is true. `claimable` does not change the word: it is not an action.
|
|
2280
|
+
*/
|
|
2281
|
+
function resetCreditState(credit, now) {
|
|
2282
|
+
if (credit.expiresAt !== void 0 && credit.expiresAt <= now) return "expired";
|
|
2283
|
+
if (credit.paused === true) return "paused";
|
|
2284
|
+
if (credit.resetsLeft === 0) return "exhausted";
|
|
2285
|
+
if (credit.cooldownUntil !== void 0 && credit.cooldownUntil > now || credit.usableNow === false) return "notUsable";
|
|
2286
|
+
return "available";
|
|
2287
|
+
}
|
|
2288
|
+
/**
|
|
2289
|
+
* Headline count. Codex passes one entry per credit, so the count is the
|
|
2290
|
+
* list length. Claude passes one entry per grant, so the count is the sum of
|
|
2291
|
+
* `resetsLeft` on grants that are neither expired nor paused. A missing
|
|
2292
|
+
* `resetsLeft` adds nothing; the row says the count is unavailable.
|
|
2293
|
+
*/
|
|
2294
|
+
function resetCreditsAvailableCount(credits, now, mode) {
|
|
2295
|
+
if (mode === "credits") return credits.length;
|
|
2296
|
+
let sum = 0;
|
|
2297
|
+
for (const credit of credits) {
|
|
2298
|
+
const state = resetCreditState(credit, now);
|
|
2299
|
+
if (state === "expired" || state === "paused") continue;
|
|
2300
|
+
if (typeof credit.resetsLeft === "number" && Number.isFinite(credit.resetsLeft) && credit.resetsLeft > 0) sum += credit.resetsLeft;
|
|
2301
|
+
}
|
|
2302
|
+
return sum;
|
|
2303
|
+
}
|
|
2304
|
+
function expiryText(t, credit) {
|
|
2305
|
+
return credit.expiresAt === void 0 ? t("resetCreditExpiryUnknown") : t("resetCreditExpires", { date: new Date(credit.expiresAt).toLocaleString() });
|
|
2306
|
+
}
|
|
2307
|
+
function remainingText(t, credit) {
|
|
2308
|
+
const left = credit.resetsLeft;
|
|
2309
|
+
const total = credit.resetsTotal;
|
|
2310
|
+
const hasLeft = typeof left === "number" && Number.isFinite(left);
|
|
2311
|
+
if (hasLeft && typeof total === "number" && Number.isFinite(total)) return t("resetCreditRemaining", {
|
|
2312
|
+
left,
|
|
2313
|
+
total
|
|
2314
|
+
});
|
|
2315
|
+
if (hasLeft) return t("resetCreditLeft", { left });
|
|
2316
|
+
return t("resetCreditRemainingUnknown");
|
|
2317
|
+
}
|
|
2318
|
+
/** Accessible name of one Claude grant row: state, remaining, and expiry, not a control name. */
|
|
2319
|
+
function resetCreditRowName(t, credit, now) {
|
|
2320
|
+
const state = resetCreditState(credit, now);
|
|
2321
|
+
const parts = [
|
|
2322
|
+
t("resetCreditFull"),
|
|
2323
|
+
t(STATE_KEYS[state]),
|
|
2324
|
+
remainingText(t, credit),
|
|
2325
|
+
expiryText(t, credit)
|
|
2326
|
+
];
|
|
2327
|
+
if (state === "notUsable" && credit.cooldownUntil !== void 0 && credit.cooldownUntil > now) parts.push(t("resetCreditCooldownUntil", { date: new Date(credit.cooldownUntil).toLocaleString() }));
|
|
2328
|
+
return parts.join(", ");
|
|
2329
|
+
}
|
|
2330
|
+
/** Claude omits an empty grant list; Codex still shows a defined, possibly empty, list. */
|
|
2331
|
+
function showsResetCredits(provider, credits) {
|
|
2332
|
+
if (provider === "codex") return credits !== void 0;
|
|
2333
|
+
return (credits?.length ?? 0) > 0;
|
|
2334
|
+
}
|
|
2335
|
+
/** The error line the settings card mounts. Claude never interpolates provider text. */
|
|
2336
|
+
function ResetCreditsErrorLine({ provider, message: message$1, t }) {
|
|
2337
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2338
|
+
style: subscriptionCardStyles.error,
|
|
2339
|
+
children: resetCreditsErrorText(provider, message$1, t)
|
|
2340
|
+
});
|
|
2341
|
+
}
|
|
2342
|
+
/** Fixed sentence for Claude. Codex may include the lookup message; Claude must not. */
|
|
2343
|
+
function resetCreditsErrorText(provider, message$1, t) {
|
|
2344
|
+
return provider === "claude" ? t("resetCreditsErrorFixed") : t("resetCreditsError", { message: message$1 });
|
|
2345
|
+
}
|
|
2346
|
+
const summaryStyle = {
|
|
2347
|
+
...subscriptionCardStyles.usageMeta,
|
|
2348
|
+
cursor: "pointer",
|
|
2349
|
+
listStyle: "none",
|
|
2350
|
+
justifyContent: "flex-start",
|
|
2351
|
+
gap: 6
|
|
2352
|
+
};
|
|
2353
|
+
/**
|
|
2354
|
+
* The closed disclosure both providers share. Claude rows are plain text:
|
|
2355
|
+
* no button, no `role="button"`, and `cursor: default`, including when
|
|
2356
|
+
* `claimable` is true.
|
|
2357
|
+
*/
|
|
2358
|
+
function ResetCreditsDisclosure({ mode, credits, t, now = Date.now(), nextCredit, useAction, statusMessage }) {
|
|
2359
|
+
const count = resetCreditsAvailableCount(credits, now, mode);
|
|
2360
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("details", {
|
|
2361
|
+
className: "subscriptions-reset-credits",
|
|
2362
|
+
style: subscriptionCardStyles.usageRow,
|
|
2363
|
+
children: [
|
|
2364
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("summary", {
|
|
2365
|
+
style: summaryStyle,
|
|
2366
|
+
children: [
|
|
2367
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
2368
|
+
"aria-hidden": "true",
|
|
2369
|
+
width: "12",
|
|
2370
|
+
height: "12",
|
|
2371
|
+
viewBox: "0 0 16 16",
|
|
2372
|
+
style: { flexShrink: 0 },
|
|
2373
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
2374
|
+
d: "m6 3 5 5-5 5",
|
|
2375
|
+
fill: "none",
|
|
2376
|
+
stroke: "currentColor",
|
|
2377
|
+
strokeWidth: "1.5",
|
|
2378
|
+
strokeLinecap: "round",
|
|
2379
|
+
strokeLinejoin: "round"
|
|
2380
|
+
})
|
|
2381
|
+
}),
|
|
2382
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("resetCreditsTitle") }),
|
|
2383
|
+
mode === "grants" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("resetCreditReadOnlyLabel") }),
|
|
2384
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2385
|
+
style: { marginLeft: "auto" },
|
|
2386
|
+
children: t("resetCreditsAvailable", { count })
|
|
2387
|
+
})
|
|
2388
|
+
]
|
|
2389
|
+
}),
|
|
2390
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: ".subscriptions-reset-credits > summary::-webkit-details-marker { display: none; }.subscriptions-reset-credits[open] > summary > svg { transform: rotate(90deg); }" }),
|
|
2391
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2392
|
+
style: {
|
|
2393
|
+
paddingLeft: 18,
|
|
2394
|
+
marginTop: 6
|
|
2395
|
+
},
|
|
2396
|
+
children: [
|
|
2397
|
+
mode === "grants" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2398
|
+
style: subscriptionCardStyles.status,
|
|
2399
|
+
children: t("resetCreditReadOnly")
|
|
2400
|
+
}),
|
|
2401
|
+
credits.map((credit, index) => {
|
|
2402
|
+
const state = resetCreditState(credit, now);
|
|
2403
|
+
const showUse = mode === "credits" && useAction !== void 0 && credit === nextCredit;
|
|
2404
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2405
|
+
"data-reset-state": mode === "grants" ? state : void 0,
|
|
2406
|
+
"data-reset-claimable": mode === "grants" && credit.claimable === true ? "true" : void 0,
|
|
2407
|
+
role: mode === "grants" ? "group" : void 0,
|
|
2408
|
+
"aria-label": mode === "grants" ? resetCreditRowName(t, credit, now) : void 0,
|
|
2409
|
+
style: {
|
|
2410
|
+
...subscriptionCardStyles.usageMeta,
|
|
2411
|
+
minHeight: 28,
|
|
2412
|
+
gap: 12,
|
|
2413
|
+
cursor: mode === "grants" ? "default" : void 0
|
|
2414
|
+
},
|
|
2415
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2416
|
+
style: {
|
|
2417
|
+
display: "inline-flex",
|
|
2418
|
+
alignItems: "center",
|
|
2419
|
+
gap: 8,
|
|
2420
|
+
flexShrink: 0
|
|
2421
|
+
},
|
|
2422
|
+
children: [
|
|
2423
|
+
t("resetCreditFull"),
|
|
2424
|
+
mode === "grants" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2425
|
+
"aria-hidden": "true",
|
|
2426
|
+
"data-reset-state-word": state,
|
|
2427
|
+
children: t(STATE_KEYS[state])
|
|
2428
|
+
}),
|
|
2429
|
+
showUse && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2430
|
+
type: "button",
|
|
2431
|
+
"aria-disabled": useAction.disabled,
|
|
2432
|
+
title: useAction.title,
|
|
2433
|
+
style: {
|
|
2434
|
+
minHeight: 22,
|
|
2435
|
+
height: 22,
|
|
2436
|
+
padding: "0 7px",
|
|
2437
|
+
borderRadius: 6,
|
|
2438
|
+
opacity: useAction.disabled ? .35 : 1,
|
|
2439
|
+
cursor: useAction.disabled ? "not-allowed" : "pointer"
|
|
2440
|
+
},
|
|
2441
|
+
onClick: () => {
|
|
2442
|
+
if (!useAction.disabled) useAction.onUse();
|
|
2443
|
+
},
|
|
2444
|
+
children: useAction.busy ? t("resetUseChecking") : useAction.label
|
|
2445
|
+
})
|
|
2446
|
+
]
|
|
2447
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2448
|
+
style: { textAlign: "right" },
|
|
2449
|
+
children: [
|
|
2450
|
+
mode === "grants" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2451
|
+
"aria-hidden": "true",
|
|
2452
|
+
children: [remainingText(t, credit), " · "]
|
|
2453
|
+
}),
|
|
2454
|
+
mode === "grants" && state === "notUsable" && credit.cooldownUntil !== void 0 && credit.cooldownUntil > now && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2455
|
+
"aria-hidden": "true",
|
|
2456
|
+
children: [t("resetCreditCooldownUntil", { date: new Date(credit.cooldownUntil).toLocaleString() }), " · "]
|
|
2457
|
+
}),
|
|
2458
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2459
|
+
"aria-hidden": mode === "grants" ? true : void 0,
|
|
2460
|
+
children: expiryText(t, credit)
|
|
2461
|
+
})
|
|
2462
|
+
]
|
|
2463
|
+
})]
|
|
2464
|
+
}, credit.id ?? index);
|
|
2465
|
+
}),
|
|
2466
|
+
statusMessage !== void 0 && statusMessage !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2467
|
+
role: "status",
|
|
2468
|
+
style: subscriptionCardStyles.status,
|
|
2469
|
+
children: statusMessage
|
|
2470
|
+
})
|
|
2471
|
+
]
|
|
2472
|
+
})
|
|
2473
|
+
]
|
|
2474
|
+
});
|
|
2475
|
+
}
|
|
2476
|
+
|
|
2035
2477
|
//#endregion
|
|
2036
2478
|
//#region src/client/UsageBadgeDisplaySetting.tsx
|
|
2037
2479
|
/** Browser-local display preference; never changes provider or account settings. */
|
|
@@ -2050,7 +2492,7 @@ function UsageBadgeDisplaySetting({ t }) {
|
|
|
2050
2492
|
value: mode,
|
|
2051
2493
|
onChange: (event) => {
|
|
2052
2494
|
const value = event.currentTarget.value;
|
|
2053
|
-
if (value !== "recent" && value !== "hidden") return;
|
|
2495
|
+
if (value !== "recent" && value !== "always" && value !== "hidden") return;
|
|
2054
2496
|
try {
|
|
2055
2497
|
setUsageBadgeMode(value);
|
|
2056
2498
|
setFailed(false);
|
|
@@ -2059,13 +2501,20 @@ function UsageBadgeDisplaySetting({ t }) {
|
|
|
2059
2501
|
setFailed(true);
|
|
2060
2502
|
}
|
|
2061
2503
|
},
|
|
2062
|
-
children: [
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2504
|
+
children: [
|
|
2505
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2506
|
+
value: "recent",
|
|
2507
|
+
children: t("usageBadgeDisplayRecent")
|
|
2508
|
+
}),
|
|
2509
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2510
|
+
value: "always",
|
|
2511
|
+
children: t("usageBadgeDisplayAlways")
|
|
2512
|
+
}),
|
|
2513
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
2514
|
+
value: "hidden",
|
|
2515
|
+
children: t("usageBadgeDisplayHidden")
|
|
2516
|
+
})
|
|
2517
|
+
]
|
|
2069
2518
|
})]
|
|
2070
2519
|
}),
|
|
2071
2520
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
@@ -2122,8 +2571,9 @@ function UsageBadgeDisplaySetting({ t }) {
|
|
|
2122
2571
|
}
|
|
2123
2572
|
const styles$6 = {
|
|
2124
2573
|
card: {
|
|
2125
|
-
border: "
|
|
2126
|
-
borderRadius:
|
|
2574
|
+
border: "0.5px solid var(--dsw-alias-settings-card-stroke, var(--dsw-alias-border-l4))",
|
|
2575
|
+
borderRadius: "var(--dsw-radius-xl, 20px)",
|
|
2576
|
+
background: "var(--dsw-alias-settings-card-fill, var(--dsw-alias-bg-layer-2))",
|
|
2127
2577
|
padding: "12px 14px",
|
|
2128
2578
|
display: "flex",
|
|
2129
2579
|
flexDirection: "column",
|
|
@@ -2132,21 +2582,12 @@ const styles$6 = {
|
|
|
2132
2582
|
field: {
|
|
2133
2583
|
display: "flex",
|
|
2134
2584
|
flexDirection: "column",
|
|
2135
|
-
gap:
|
|
2136
|
-
fontSize:
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
select: {
|
|
2140
|
-
height: 32,
|
|
2141
|
-
width: "100%",
|
|
2142
|
-
boxSizing: "border-box",
|
|
2143
|
-
border: "1px solid var(--dsw-alias-border-l2)",
|
|
2144
|
-
borderRadius: 8,
|
|
2145
|
-
padding: "0 10px",
|
|
2146
|
-
font: "inherit",
|
|
2147
|
-
background: "var(--dsw-alias-bg-layer-1)",
|
|
2148
|
-
color: "var(--dsw-alias-label-primary)"
|
|
2585
|
+
gap: 6,
|
|
2586
|
+
fontSize: 13,
|
|
2587
|
+
fontWeight: 500,
|
|
2588
|
+
lineHeight: "20px"
|
|
2149
2589
|
},
|
|
2590
|
+
select: { width: "100%" },
|
|
2150
2591
|
hint: {
|
|
2151
2592
|
margin: 0,
|
|
2152
2593
|
fontSize: 12,
|
|
@@ -2226,7 +2667,12 @@ const styles$5 = {
|
|
|
2226
2667
|
fontSize: 14,
|
|
2227
2668
|
lineHeight: "22px"
|
|
2228
2669
|
},
|
|
2229
|
-
card:
|
|
2670
|
+
card: {
|
|
2671
|
+
...subscriptionCardStyles.card,
|
|
2672
|
+
border: "0.5px solid var(--dsw-alias-settings-card-stroke, var(--dsw-alias-border-l4))",
|
|
2673
|
+
borderRadius: "var(--dsw-radius-xl, 20px)",
|
|
2674
|
+
background: "var(--dsw-alias-settings-card-fill, var(--dsw-alias-bg-layer-2))"
|
|
2675
|
+
},
|
|
2230
2676
|
cardHeader: subscriptionCardStyles.header,
|
|
2231
2677
|
dot: subscriptionCardStyles.dot,
|
|
2232
2678
|
name: subscriptionCardStyles.name,
|
|
@@ -2239,21 +2685,32 @@ const styles$5 = {
|
|
|
2239
2685
|
},
|
|
2240
2686
|
errorLine: subscriptionCardStyles.error,
|
|
2241
2687
|
actions: subscriptionCardStyles.actions,
|
|
2242
|
-
|
|
2243
|
-
|
|
2688
|
+
usage: {
|
|
2689
|
+
...subscriptionCardStyles.usage,
|
|
2690
|
+
borderTop: "0.5px solid var(--dsw-alias-border-l2)"
|
|
2691
|
+
},
|
|
2244
2692
|
usageHeader: subscriptionCardStyles.usageHeader,
|
|
2245
2693
|
usageTitle: subscriptionCardStyles.usageTitle,
|
|
2246
2694
|
usagePlan: subscriptionCardStyles.usagePlan,
|
|
2247
|
-
usageRefresh:
|
|
2695
|
+
usageRefresh: {
|
|
2696
|
+
minHeight: 22,
|
|
2697
|
+
height: 22,
|
|
2698
|
+
padding: "0 8px",
|
|
2699
|
+
marginLeft: "auto"
|
|
2700
|
+
},
|
|
2248
2701
|
usageRow: subscriptionCardStyles.usageRow,
|
|
2249
2702
|
usageMeta: subscriptionCardStyles.usageMeta,
|
|
2250
|
-
accountRow:
|
|
2703
|
+
accountRow: {
|
|
2704
|
+
...subscriptionCardStyles.account,
|
|
2705
|
+
border: "0.5px solid var(--dsw-alias-border-l2)",
|
|
2706
|
+
borderRadius: "var(--dsw-radius-lg, 16px)"
|
|
2707
|
+
},
|
|
2251
2708
|
accountHeader: subscriptionCardStyles.accountHeader,
|
|
2252
2709
|
accountName: subscriptionCardStyles.accountName,
|
|
2253
2710
|
starButton: {
|
|
2254
2711
|
border: "none",
|
|
2255
|
-
background: "transparent",
|
|
2256
2712
|
padding: 0,
|
|
2713
|
+
width: 28,
|
|
2257
2714
|
font: "inherit",
|
|
2258
2715
|
fontSize: 14,
|
|
2259
2716
|
lineHeight: "20px",
|
|
@@ -2265,8 +2722,8 @@ const styles$5 = {
|
|
|
2265
2722
|
display: "flex",
|
|
2266
2723
|
flexDirection: "column",
|
|
2267
2724
|
gap: 6,
|
|
2268
|
-
border: "
|
|
2269
|
-
borderRadius:
|
|
2725
|
+
border: "0.5px solid var(--dsw-alias-border-l2)",
|
|
2726
|
+
borderRadius: "var(--dsw-radius-lg, 16px)",
|
|
2270
2727
|
padding: "10px 12px",
|
|
2271
2728
|
background: "var(--dsw-alias-bg-layer-1)"
|
|
2272
2729
|
},
|
|
@@ -2278,6 +2735,21 @@ const styles$5 = {
|
|
|
2278
2735
|
color: "var(--dsw-alias-label-primary)",
|
|
2279
2736
|
userSelect: "all"
|
|
2280
2737
|
},
|
|
2738
|
+
manual: {
|
|
2739
|
+
fontSize: 13,
|
|
2740
|
+
lineHeight: "20px"
|
|
2741
|
+
},
|
|
2742
|
+
manualRow: {
|
|
2743
|
+
display: "flex",
|
|
2744
|
+
flexWrap: "wrap",
|
|
2745
|
+
gap: 8,
|
|
2746
|
+
alignItems: "center",
|
|
2747
|
+
marginTop: 8
|
|
2748
|
+
},
|
|
2749
|
+
manualInput: {
|
|
2750
|
+
flex: "1 1 200px",
|
|
2751
|
+
minWidth: 0
|
|
2752
|
+
},
|
|
2281
2753
|
modalOverlay: {
|
|
2282
2754
|
position: "fixed",
|
|
2283
2755
|
inset: 0,
|
|
@@ -2286,7 +2758,8 @@ const styles$5 = {
|
|
|
2286
2758
|
alignItems: "center",
|
|
2287
2759
|
justifyContent: "center",
|
|
2288
2760
|
padding: 16,
|
|
2289
|
-
background: "
|
|
2761
|
+
background: "var(--dsw-alias-bg-mask-1, #0006)",
|
|
2762
|
+
backdropFilter: "var(--dsw-mask-blur, none)"
|
|
2290
2763
|
},
|
|
2291
2764
|
modal: {
|
|
2292
2765
|
width: 460,
|
|
@@ -2298,9 +2771,10 @@ const styles$5 = {
|
|
|
2298
2771
|
flexDirection: "column",
|
|
2299
2772
|
gap: 12,
|
|
2300
2773
|
padding: "16px 18px",
|
|
2301
|
-
borderRadius:
|
|
2302
|
-
background: "var(--dsw-alias-bg-layer-
|
|
2303
|
-
border:
|
|
2774
|
+
borderRadius: "var(--dsw-radius-panel, 28px)",
|
|
2775
|
+
background: "var(--dsw-alias-bg-layer-2)",
|
|
2776
|
+
border: 0,
|
|
2777
|
+
boxShadow: "var(--dsw-elevation-prominent)"
|
|
2304
2778
|
},
|
|
2305
2779
|
modalHeader: {
|
|
2306
2780
|
display: "flex",
|
|
@@ -2308,9 +2782,9 @@ const styles$5 = {
|
|
|
2308
2782
|
gap: 8
|
|
2309
2783
|
},
|
|
2310
2784
|
modalTitle: {
|
|
2311
|
-
fontWeight:
|
|
2312
|
-
fontSize:
|
|
2313
|
-
lineHeight: "
|
|
2785
|
+
fontWeight: 500,
|
|
2786
|
+
fontSize: 16,
|
|
2787
|
+
lineHeight: "24px",
|
|
2314
2788
|
color: "var(--dsw-alias-label-primary)"
|
|
2315
2789
|
}
|
|
2316
2790
|
};
|
|
@@ -2380,10 +2854,22 @@ function SubscriptionsSection(props) {
|
|
|
2380
2854
|
const [observedAt, setObservedAt] = (0, react.useState)({});
|
|
2381
2855
|
const [usageErrors, setUsageErrors] = (0, react.useState)({});
|
|
2382
2856
|
const [usageLoading, setUsageLoading] = (0, react.useState)({});
|
|
2857
|
+
const [resetConfirmation, setResetConfirmation] = (0, react.useState)();
|
|
2858
|
+
const [resetBusy, setResetBusy] = (0, react.useState)(false);
|
|
2859
|
+
const [resetAcknowledged, setResetAcknowledged] = (0, react.useState)(false);
|
|
2860
|
+
const [resetMessage, setResetMessage] = (0, react.useState)("");
|
|
2861
|
+
const [resetAccount, setResetAccount] = (0, react.useState)();
|
|
2862
|
+
const resetDialogRef = (0, react.useRef)(null);
|
|
2863
|
+
(0, react.useEffect)(() => {
|
|
2864
|
+
if (resetConfirmation) resetDialogRef.current?.showModal();
|
|
2865
|
+
else resetDialogRef.current?.close();
|
|
2866
|
+
}, [resetConfirmation]);
|
|
2867
|
+
const resetInflight = (0, react.useRef)(false);
|
|
2383
2868
|
const mountedRef = (0, react.useRef)(true);
|
|
2384
2869
|
const pollersRef = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
2385
2870
|
/** Accounts with a `usage` call in flight; guards the auto-fetch effect against re-entry. */
|
|
2386
|
-
|
|
2871
|
+
/** In-flight usage reads per key, holding the promise so a forced read can wait one out. */
|
|
2872
|
+
const usageInflightRef = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
2387
2873
|
const usageRosterSignatureRef = (0, react.useRef)();
|
|
2388
2874
|
const [managedProvider, setManagedProvider] = (0, react.useState)();
|
|
2389
2875
|
const setProviderError = (0, react.useCallback)((provider, message$1) => {
|
|
@@ -2460,47 +2946,97 @@ function SubscriptionsSection(props) {
|
|
|
2460
2946
|
};
|
|
2461
2947
|
}, [refresh, startPolling]);
|
|
2462
2948
|
const loadUsage = (0, react.useCallback)(async (provider, account, force = false) => {
|
|
2949
|
+
if (rpc === void 0) return;
|
|
2463
2950
|
const key = `${provider}:${account}`;
|
|
2951
|
+
const pending = usageInflightRef.current.get(key);
|
|
2952
|
+
if (pending !== void 0) {
|
|
2953
|
+
if (!force) return;
|
|
2954
|
+
await pending;
|
|
2955
|
+
}
|
|
2464
2956
|
if (rpc === void 0 || usageInflightRef.current.has(key)) return;
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
...prev,
|
|
2468
|
-
[key]: true
|
|
2469
|
-
}));
|
|
2470
|
-
try {
|
|
2471
|
-
const usage = await callSubscriptionsAuth(rpc, "usage", {
|
|
2472
|
-
provider,
|
|
2473
|
-
account,
|
|
2474
|
-
...force ? { force: true } : {}
|
|
2475
|
-
});
|
|
2476
|
-
if (!mountedRef.current) return;
|
|
2477
|
-
setUsages((prev) => ({
|
|
2957
|
+
const read = (async () => {
|
|
2958
|
+
setUsageLoading((prev) => ({
|
|
2478
2959
|
...prev,
|
|
2479
|
-
[key]:
|
|
2960
|
+
[key]: true
|
|
2480
2961
|
}));
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2962
|
+
try {
|
|
2963
|
+
const usage = await callSubscriptionsAuth(rpc, "usage", {
|
|
2964
|
+
provider,
|
|
2965
|
+
account,
|
|
2966
|
+
...force ? { force: true } : {}
|
|
2967
|
+
});
|
|
2968
|
+
if (!mountedRef.current) return;
|
|
2969
|
+
setUsages((prev) => ({
|
|
2970
|
+
...prev,
|
|
2971
|
+
[key]: usage
|
|
2972
|
+
}));
|
|
2973
|
+
setObservedAt((prev) => ({
|
|
2974
|
+
...prev,
|
|
2975
|
+
[key]: usage.observedAt ?? Date.now()
|
|
2976
|
+
}));
|
|
2977
|
+
window.dispatchEvent(new Event(USAGE_BADGE_REFRESH_EVENT));
|
|
2978
|
+
setUsageErrors((prev) => {
|
|
2979
|
+
const next = { ...prev };
|
|
2980
|
+
delete next[key];
|
|
2981
|
+
return next;
|
|
2982
|
+
});
|
|
2983
|
+
} catch (error) {
|
|
2984
|
+
if (mountedRef.current) setUsageErrors((prev) => ({
|
|
2985
|
+
...prev,
|
|
2986
|
+
[key]: messageOf(error)
|
|
2987
|
+
}));
|
|
2988
|
+
} finally {
|
|
2989
|
+
usageInflightRef.current.delete(key);
|
|
2990
|
+
if (mountedRef.current) setUsageLoading((prev) => ({
|
|
2991
|
+
...prev,
|
|
2992
|
+
[key]: false
|
|
2993
|
+
}));
|
|
2994
|
+
}
|
|
2995
|
+
})();
|
|
2996
|
+
usageInflightRef.current.set(key, read);
|
|
2997
|
+
await read;
|
|
2998
|
+
}, [rpc]);
|
|
2999
|
+
async function prepareReset(account) {
|
|
3000
|
+
if (!rpc || resetInflight.current) return;
|
|
3001
|
+
resetInflight.current = true;
|
|
3002
|
+
setResetBusy(true);
|
|
3003
|
+
setResetAccount(account);
|
|
3004
|
+
setResetConfirmation(void 0);
|
|
3005
|
+
setResetMessage("");
|
|
3006
|
+
try {
|
|
3007
|
+
const result = await callSubscriptionsAuth(rpc, "prepareReset", { account });
|
|
3008
|
+
setResetAcknowledged(false);
|
|
3009
|
+
setResetConfirmation({
|
|
3010
|
+
...result,
|
|
3011
|
+
account
|
|
2490
3012
|
});
|
|
2491
3013
|
} catch (error) {
|
|
2492
|
-
|
|
2493
|
-
...prev,
|
|
2494
|
-
[key]: messageOf(error)
|
|
2495
|
-
}));
|
|
3014
|
+
setResetMessage(messageOf(error));
|
|
2496
3015
|
} finally {
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
...prev,
|
|
2500
|
-
[key]: false
|
|
2501
|
-
}));
|
|
3016
|
+
resetInflight.current = false;
|
|
3017
|
+
setResetBusy(false);
|
|
2502
3018
|
}
|
|
2503
|
-
}
|
|
3019
|
+
}
|
|
3020
|
+
async function consumeReset() {
|
|
3021
|
+
if (!rpc || !resetConfirmation || !resetAcknowledged || resetInflight.current) return;
|
|
3022
|
+
const { account, ticket } = resetConfirmation;
|
|
3023
|
+
resetInflight.current = true;
|
|
3024
|
+
setResetBusy(true);
|
|
3025
|
+
setResetConfirmation(void 0);
|
|
3026
|
+
try {
|
|
3027
|
+
await callSubscriptionsAuth(rpc, "consumeReset", {
|
|
3028
|
+
account,
|
|
3029
|
+
ticket
|
|
3030
|
+
});
|
|
3031
|
+
setResetMessage(t("resetUseSuccess"));
|
|
3032
|
+
} catch (error) {
|
|
3033
|
+
setResetMessage(messageOf(error));
|
|
3034
|
+
} finally {
|
|
3035
|
+
await loadUsage("codex", account, true);
|
|
3036
|
+
resetInflight.current = false;
|
|
3037
|
+
setResetBusy(false);
|
|
3038
|
+
}
|
|
3039
|
+
}
|
|
2504
3040
|
(0, react.useEffect)(() => {
|
|
2505
3041
|
const live = /* @__PURE__ */ new Set();
|
|
2506
3042
|
for (const { id } of PROVIDERS) for (const account of statuses[id]?.accounts ?? []) {
|
|
@@ -2648,8 +3184,10 @@ function SubscriptionsSection(props) {
|
|
|
2648
3184
|
children: t("unavailable")
|
|
2649
3185
|
});
|
|
2650
3186
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3187
|
+
className: "dsh-subscriptions-settings",
|
|
2651
3188
|
style: styles$5.section,
|
|
2652
3189
|
children: [
|
|
3190
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: providerSettingsCss }),
|
|
2653
3191
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
2654
3192
|
style: styles$5.intro,
|
|
2655
3193
|
children: t("intro")
|
|
@@ -2698,6 +3236,10 @@ function SubscriptionsSection(props) {
|
|
|
2698
3236
|
const usage = usages[usageKey];
|
|
2699
3237
|
const usageError = usageErrors[usageKey];
|
|
2700
3238
|
const display = account.account ?? account.key;
|
|
3239
|
+
const sortedCredits = [...usage?.resetCredits ?? []].sort((a, b) => (a.expiresAt ?? Infinity) - (b.expiresAt ?? Infinity));
|
|
3240
|
+
const nextReset = sortedCredits.find((c) => c.expiresAt === void 0 || c.expiresAt > Date.now());
|
|
3241
|
+
const resetBlock = usage ? resetActionBlock(usage) : "resetUseRefresh";
|
|
3242
|
+
const resetDisabled = resetBusy || resetBlock !== void 0;
|
|
2701
3243
|
const showUsage = usage?.supported !== false && (usage !== void 0 || usageError !== void 0 || usageLoading[usageKey] === true);
|
|
2702
3244
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
2703
3245
|
style: styles$5.accountRow,
|
|
@@ -2728,7 +3270,6 @@ function SubscriptionsSection(props) {
|
|
|
2728
3270
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2729
3271
|
type: "button",
|
|
2730
3272
|
style: {
|
|
2731
|
-
...styles$5.button,
|
|
2732
3273
|
marginLeft: "auto",
|
|
2733
3274
|
flexShrink: 0
|
|
2734
3275
|
},
|
|
@@ -2754,13 +3295,7 @@ function SubscriptionsSection(props) {
|
|
|
2754
3295
|
}),
|
|
2755
3296
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2756
3297
|
type: "button",
|
|
2757
|
-
style:
|
|
2758
|
-
...styles$5.usageRefresh,
|
|
2759
|
-
...usageLoading[usageKey] === true ? {
|
|
2760
|
-
opacity: .5,
|
|
2761
|
-
cursor: "default"
|
|
2762
|
-
} : {}
|
|
2763
|
-
},
|
|
3298
|
+
style: styles$5.usageRefresh,
|
|
2764
3299
|
disabled: usageLoading[usageKey] === true,
|
|
2765
3300
|
onClick: () => {
|
|
2766
3301
|
loadUsage(id, account.key, true);
|
|
@@ -2795,6 +3330,28 @@ function SubscriptionsSection(props) {
|
|
|
2795
3330
|
stale: usageError !== void 0 || usage.stale === true
|
|
2796
3331
|
})]
|
|
2797
3332
|
}, index);
|
|
3333
|
+
}),
|
|
3334
|
+
(id === "codex" || id === "claude") && usage?.resetCreditsError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetCreditsErrorLine, {
|
|
3335
|
+
provider: id,
|
|
3336
|
+
message: usage.resetCreditsError,
|
|
3337
|
+
t
|
|
3338
|
+
}),
|
|
3339
|
+
(id === "codex" || id === "claude") && showsResetCredits(id, usage?.resetCredits) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ResetCreditsDisclosure, {
|
|
3340
|
+
mode: id === "claude" ? "grants" : "credits",
|
|
3341
|
+
credits: sortedCredits,
|
|
3342
|
+
t,
|
|
3343
|
+
...nextReset !== void 0 ? { nextCredit: nextReset } : {},
|
|
3344
|
+
...id === "codex" ? { useAction: {
|
|
3345
|
+
accountKey: account.key,
|
|
3346
|
+
busy: resetBusy && resetAccount === account.key,
|
|
3347
|
+
disabled: resetDisabled,
|
|
3348
|
+
title: t(resetBusy ? "resetUseChecking" : resetBlock ?? "resetUseReady"),
|
|
3349
|
+
label: t("resetUseButton"),
|
|
3350
|
+
onUse: () => {
|
|
3351
|
+
if (!resetDisabled) prepareReset(account.key);
|
|
3352
|
+
}
|
|
3353
|
+
} } : {},
|
|
3354
|
+
...resetAccount === account.key && resetMessage !== "" ? { statusMessage: resetMessage } : {}
|
|
2798
3355
|
})
|
|
2799
3356
|
]
|
|
2800
3357
|
})]
|
|
@@ -2805,7 +3362,6 @@ function SubscriptionsSection(props) {
|
|
|
2805
3362
|
children: [
|
|
2806
3363
|
!busy && accounts.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2807
3364
|
type: "button",
|
|
2808
|
-
style: styles$5.button,
|
|
2809
3365
|
onClick: () => {
|
|
2810
3366
|
login(id);
|
|
2811
3367
|
},
|
|
@@ -2813,14 +3369,12 @@ function SubscriptionsSection(props) {
|
|
|
2813
3369
|
}),
|
|
2814
3370
|
!busy && accounts.length > 0 && id === "claude" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2815
3371
|
type: "button",
|
|
2816
|
-
style: styles$5.button,
|
|
2817
3372
|
onClick: () => {
|
|
2818
3373
|
login(id, "oauth");
|
|
2819
3374
|
},
|
|
2820
3375
|
children: t("addAccountOAuth")
|
|
2821
3376
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2822
3377
|
type: "button",
|
|
2823
|
-
style: styles$5.button,
|
|
2824
3378
|
onClick: () => {
|
|
2825
3379
|
login(id, "keychain");
|
|
2826
3380
|
},
|
|
@@ -2828,7 +3382,6 @@ function SubscriptionsSection(props) {
|
|
|
2828
3382
|
})] }),
|
|
2829
3383
|
!busy && accounts.length > 0 && id !== "claude" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2830
3384
|
type: "button",
|
|
2831
|
-
style: styles$5.button,
|
|
2832
3385
|
onClick: () => {
|
|
2833
3386
|
login(id);
|
|
2834
3387
|
},
|
|
@@ -2836,7 +3389,6 @@ function SubscriptionsSection(props) {
|
|
|
2836
3389
|
}),
|
|
2837
3390
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2838
3391
|
type: "button",
|
|
2839
|
-
style: styles$5.button,
|
|
2840
3392
|
"aria-haspopup": "dialog",
|
|
2841
3393
|
onClick: () => setManagedProvider({
|
|
2842
3394
|
id,
|
|
@@ -2846,7 +3398,6 @@ function SubscriptionsSection(props) {
|
|
|
2846
3398
|
}),
|
|
2847
3399
|
busy && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2848
3400
|
type: "button",
|
|
2849
|
-
style: styles$5.button,
|
|
2850
3401
|
onClick: () => {
|
|
2851
3402
|
cancel(id);
|
|
2852
3403
|
},
|
|
@@ -2873,14 +3424,12 @@ function SubscriptionsSection(props) {
|
|
|
2873
3424
|
style: styles$5.actions,
|
|
2874
3425
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2875
3426
|
type: "button",
|
|
2876
|
-
style: styles$5.button,
|
|
2877
3427
|
onClick: () => {
|
|
2878
3428
|
copyDeviceCode(id, deviceCode.userCode);
|
|
2879
3429
|
},
|
|
2880
3430
|
children: copiedCode === id ? t("deviceCodeCopied") : t("deviceCodeCopy")
|
|
2881
3431
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2882
3432
|
type: "button",
|
|
2883
|
-
style: styles$5.button,
|
|
2884
3433
|
onClick: () => {
|
|
2885
3434
|
window.open(deviceCode.verificationUrl, "_blank", "noopener");
|
|
2886
3435
|
},
|
|
@@ -2903,7 +3452,6 @@ function SubscriptionsSection(props) {
|
|
|
2903
3452
|
}))
|
|
2904
3453
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2905
3454
|
type: "button",
|
|
2906
|
-
style: styles$5.button,
|
|
2907
3455
|
onClick: () => {
|
|
2908
3456
|
submitManual(id);
|
|
2909
3457
|
},
|
|
@@ -2928,6 +3476,90 @@ function SubscriptionsSection(props) {
|
|
|
2928
3476
|
rpc,
|
|
2929
3477
|
t,
|
|
2930
3478
|
onClose: () => setManagedProvider(void 0)
|
|
3479
|
+
}),
|
|
3480
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: ".subscriptions-reset-dialog::backdrop { background: var(--dsw-alias-bg-mask-1, #0006); backdrop-filter: var(--dsw-mask-blur, none); }" }),
|
|
3481
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dialog", {
|
|
3482
|
+
ref: resetDialogRef,
|
|
3483
|
+
className: "subscriptions-reset-dialog",
|
|
3484
|
+
"aria-labelledby": "subscriptions-reset-title",
|
|
3485
|
+
onCancel: () => setResetConfirmation(void 0),
|
|
3486
|
+
onClose: () => setResetConfirmation(void 0),
|
|
3487
|
+
style: {
|
|
3488
|
+
...styles$5.modal,
|
|
3489
|
+
display: resetConfirmation ? "flex" : "none",
|
|
3490
|
+
margin: "auto",
|
|
3491
|
+
color: "var(--dsw-alias-label-primary)"
|
|
3492
|
+
},
|
|
3493
|
+
children: resetConfirmation && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
3494
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
3495
|
+
id: "subscriptions-reset-title",
|
|
3496
|
+
style: {
|
|
3497
|
+
...styles$5.modalTitle,
|
|
3498
|
+
margin: 0
|
|
3499
|
+
},
|
|
3500
|
+
children: t("resetUseConfirmTitle")
|
|
3501
|
+
}),
|
|
3502
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3503
|
+
style: {
|
|
3504
|
+
...styles$5.statusLine,
|
|
3505
|
+
overflowWrap: "anywhere"
|
|
3506
|
+
},
|
|
3507
|
+
children: statuses.codex?.accounts.find((a) => a.key === resetConfirmation.account)?.account ?? resetConfirmation.account
|
|
3508
|
+
}),
|
|
3509
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3510
|
+
style: {
|
|
3511
|
+
...styles$5.usageMeta,
|
|
3512
|
+
gap: 12
|
|
3513
|
+
},
|
|
3514
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("usageWeekly") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("strong", { children: [Math.round(resetConfirmation.weeklyUsedPercent), "%"] })]
|
|
3515
|
+
}),
|
|
3516
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3517
|
+
style: styles$5.usageMeta,
|
|
3518
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: resetConfirmation.creditExpiresAt === void 0 ? t("resetCreditExpiryUnknown") : t("resetCreditExpires", { date: new Date(resetConfirmation.creditExpiresAt).toLocaleString() }) })
|
|
3519
|
+
}),
|
|
3520
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
3521
|
+
style: {
|
|
3522
|
+
...styles$5.statusLine,
|
|
3523
|
+
margin: "4px 0"
|
|
3524
|
+
},
|
|
3525
|
+
children: t("resetUseWarning")
|
|
3526
|
+
}),
|
|
3527
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
|
|
3528
|
+
style: {
|
|
3529
|
+
display: "flex",
|
|
3530
|
+
gap: 8,
|
|
3531
|
+
alignItems: "flex-start",
|
|
3532
|
+
fontSize: 12
|
|
3533
|
+
},
|
|
3534
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3535
|
+
type: "checkbox",
|
|
3536
|
+
checked: resetAcknowledged,
|
|
3537
|
+
onChange: (e) => setResetAcknowledged(e.target.checked)
|
|
3538
|
+
}), t("resetUseAcknowledge")]
|
|
3539
|
+
}),
|
|
3540
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3541
|
+
className: "dsh-subscription-dialog-actions",
|
|
3542
|
+
style: {
|
|
3543
|
+
...styles$5.actions,
|
|
3544
|
+
justifyContent: "flex-end",
|
|
3545
|
+
marginTop: 8
|
|
3546
|
+
},
|
|
3547
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3548
|
+
type: "button",
|
|
3549
|
+
autoFocus: true,
|
|
3550
|
+
onClick: () => setResetConfirmation(void 0),
|
|
3551
|
+
children: t("cancel")
|
|
3552
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3553
|
+
type: "button",
|
|
3554
|
+
className: "dsh-subscription-primary",
|
|
3555
|
+
disabled: !resetAcknowledged || resetBusy,
|
|
3556
|
+
onClick: () => {
|
|
3557
|
+
consumeReset();
|
|
3558
|
+
},
|
|
3559
|
+
children: t("resetUseConfirm")
|
|
3560
|
+
})]
|
|
3561
|
+
})
|
|
3562
|
+
] })
|
|
2931
3563
|
})
|
|
2932
3564
|
]
|
|
2933
3565
|
});
|
|
@@ -3214,20 +3846,42 @@ const HOST_CONTRACT = {
|
|
|
3214
3846
|
package: "@deepseek-ai/dsh-client-ui-theme",
|
|
3215
3847
|
names: [
|
|
3216
3848
|
"--dsw-alias-bg-layer-1",
|
|
3849
|
+
"--dsw-alias-bg-layer-2",
|
|
3850
|
+
"--dsw-alias-bg-layer-3",
|
|
3851
|
+
"--dsw-alias-bg-mask-1",
|
|
3217
3852
|
"--dsw-alias-bg-skeleton",
|
|
3853
|
+
"--dsw-alias-border-l1",
|
|
3218
3854
|
"--dsw-alias-border-l2",
|
|
3219
3855
|
"--dsw-alias-border-l2-darkmode-thin",
|
|
3856
|
+
"--dsw-alias-border-l3",
|
|
3857
|
+
"--dsw-alias-border-l4",
|
|
3858
|
+
"--dsw-alias-brand-primary",
|
|
3859
|
+
"--dsw-alias-button-primary-fill",
|
|
3860
|
+
"--dsw-alias-button-primary-hover",
|
|
3861
|
+
"--dsw-alias-interactive-bg-active",
|
|
3220
3862
|
"--dsw-alias-interactive-bg-hover",
|
|
3221
3863
|
"--dsw-alias-interactive-bg-hover-solid",
|
|
3222
3864
|
"--dsw-alias-label-dimmed",
|
|
3223
3865
|
"--dsw-alias-label-primary",
|
|
3866
|
+
"--dsw-alias-label-primary-foreground",
|
|
3224
3867
|
"--dsw-alias-label-secondary",
|
|
3225
3868
|
"--dsw-alias-label-tertiary",
|
|
3869
|
+
"--dsw-alias-settings-card-fill",
|
|
3870
|
+
"--dsw-alias-settings-card-stroke",
|
|
3871
|
+
"--dsw-alias-state-business-primary",
|
|
3226
3872
|
"--dsw-alias-state-error-primary",
|
|
3227
3873
|
"--dsw-alias-state-success-primary",
|
|
3228
3874
|
"--dsw-alias-state-warn-label",
|
|
3229
3875
|
"--dsw-elevation-prominent",
|
|
3876
|
+
"--dsw-focus-ring-color",
|
|
3877
|
+
"--dsw-focus-ring-width",
|
|
3878
|
+
"--dsw-mask-blur",
|
|
3230
3879
|
"--dsw-menu-backdrop-filter",
|
|
3880
|
+
"--dsw-radius-lg",
|
|
3881
|
+
"--dsw-radius-md",
|
|
3882
|
+
"--dsw-radius-panel",
|
|
3883
|
+
"--dsw-radius-sm",
|
|
3884
|
+
"--dsw-radius-xl",
|
|
3231
3885
|
"--dsw-specific-menu"
|
|
3232
3886
|
]
|
|
3233
3887
|
}
|
|
@@ -3765,6 +4419,7 @@ function SpeedSelect({ loadSpeed, setSpeed, t }) {
|
|
|
3765
4419
|
const triggerLabel = `${translate("speed")} · ${tierName(state.tier)}`;
|
|
3766
4420
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3767
4421
|
ref: rootRef,
|
|
4422
|
+
className: "dsh-subscription-speed",
|
|
3768
4423
|
style: styles$1.root,
|
|
3769
4424
|
onKeyDown: (event) => {
|
|
3770
4425
|
if (event.key === "Escape" && open) {
|
|
@@ -3772,46 +4427,50 @@ function SpeedSelect({ loadSpeed, setSpeed, t }) {
|
|
|
3772
4427
|
setOpen(false);
|
|
3773
4428
|
}
|
|
3774
4429
|
},
|
|
3775
|
-
children: [
|
|
3776
|
-
style:
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
4430
|
+
children: [
|
|
4431
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: subscriptionChromeCss }),
|
|
4432
|
+
open && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4433
|
+
style: styles$1.menu,
|
|
4434
|
+
role: "menu",
|
|
4435
|
+
"aria-label": translate("speed"),
|
|
4436
|
+
children: TIERS.map((tier) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
4437
|
+
type: "button",
|
|
4438
|
+
role: "menuitemradio",
|
|
4439
|
+
"aria-checked": tier === state.tier,
|
|
4440
|
+
style: styles$1.item,
|
|
4441
|
+
disabled: busy,
|
|
4442
|
+
onClick: () => {
|
|
4443
|
+
choose(tier);
|
|
4444
|
+
},
|
|
4445
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4446
|
+
style: styles$1.itemCheck,
|
|
4447
|
+
children: tier === state.tier ? "✓" : ""
|
|
4448
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4449
|
+
style: styles$1.itemText,
|
|
4450
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4451
|
+
style: styles$1.itemName,
|
|
4452
|
+
children: tierName(tier)
|
|
4453
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4454
|
+
style: styles$1.itemDescription,
|
|
4455
|
+
children: tierDescription(tier)
|
|
4456
|
+
})]
|
|
4457
|
+
})]
|
|
4458
|
+
}, tier))
|
|
4459
|
+
}),
|
|
4460
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3780
4461
|
type: "button",
|
|
3781
|
-
|
|
3782
|
-
"aria-
|
|
3783
|
-
|
|
4462
|
+
style: styles$1.trigger,
|
|
4463
|
+
"aria-haspopup": "menu",
|
|
4464
|
+
"aria-expanded": open,
|
|
4465
|
+
title: triggerLabel,
|
|
3784
4466
|
disabled: busy,
|
|
3785
4467
|
onClick: () => {
|
|
3786
|
-
|
|
4468
|
+
if (open) setOpen(false);
|
|
4469
|
+
else show();
|
|
3787
4470
|
},
|
|
3788
|
-
children:
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
3792
|
-
style: styles$1.itemText,
|
|
3793
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3794
|
-
style: styles$1.itemName,
|
|
3795
|
-
children: tierName(tier)
|
|
3796
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3797
|
-
style: styles$1.itemDescription,
|
|
3798
|
-
children: tierDescription(tier)
|
|
3799
|
-
})]
|
|
3800
|
-
})]
|
|
3801
|
-
}, tier))
|
|
3802
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3803
|
-
type: "button",
|
|
3804
|
-
style: styles$1.trigger,
|
|
3805
|
-
"aria-haspopup": "menu",
|
|
3806
|
-
"aria-expanded": open,
|
|
3807
|
-
title: triggerLabel,
|
|
3808
|
-
disabled: busy,
|
|
3809
|
-
onClick: () => {
|
|
3810
|
-
if (open) setOpen(false);
|
|
3811
|
-
else show();
|
|
3812
|
-
},
|
|
3813
|
-
children: triggerLabel
|
|
3814
|
-
})]
|
|
4471
|
+
children: triggerLabel
|
|
4472
|
+
})
|
|
4473
|
+
]
|
|
3815
4474
|
});
|
|
3816
4475
|
}
|
|
3817
4476
|
const styles$1 = {
|
|
@@ -3820,9 +4479,9 @@ const styles$1 = {
|
|
|
3820
4479
|
display: "inline-flex"
|
|
3821
4480
|
},
|
|
3822
4481
|
trigger: {
|
|
3823
|
-
border: "
|
|
3824
|
-
borderRadius:
|
|
3825
|
-
background: "transparent",
|
|
4482
|
+
border: "0.5px solid var(--dsw-alias-border-l3)",
|
|
4483
|
+
borderRadius: "var(--dsw-radius-sm, 8px)",
|
|
4484
|
+
background: "var(--dsh-subscription-speed-hover, transparent)",
|
|
3826
4485
|
color: "var(--dsw-alias-label-secondary)",
|
|
3827
4486
|
font: "inherit",
|
|
3828
4487
|
fontSize: 12,
|
|
@@ -3839,9 +4498,10 @@ const styles$1 = {
|
|
|
3839
4498
|
minWidth: 180,
|
|
3840
4499
|
padding: 4,
|
|
3841
4500
|
zIndex: 20,
|
|
3842
|
-
background: "var(--dsw-alias-bg-layer-
|
|
3843
|
-
border:
|
|
3844
|
-
|
|
4501
|
+
background: "var(--dsw-specific-menu, var(--dsw-alias-bg-layer-2))",
|
|
4502
|
+
border: 0,
|
|
4503
|
+
boxShadow: "var(--dsw-elevation-prominent)",
|
|
4504
|
+
borderRadius: "var(--dsw-radius-lg, 16px)",
|
|
3845
4505
|
display: "flex",
|
|
3846
4506
|
flexDirection: "column",
|
|
3847
4507
|
gap: 2
|
|
@@ -3852,8 +4512,8 @@ const styles$1 = {
|
|
|
3852
4512
|
gap: 6,
|
|
3853
4513
|
width: "100%",
|
|
3854
4514
|
border: "none",
|
|
3855
|
-
borderRadius:
|
|
3856
|
-
background: "transparent",
|
|
4515
|
+
borderRadius: "var(--dsw-radius-sm, 8px)",
|
|
4516
|
+
background: "var(--dsh-subscription-speed-hover, transparent)",
|
|
3857
4517
|
padding: "6px 8px",
|
|
3858
4518
|
cursor: "pointer",
|
|
3859
4519
|
font: "inherit",
|
|
@@ -3893,6 +4553,8 @@ const UsageBadgeIcon = usageBadgeIcon(__deepseek_ai_dsh_client_ui_primitives);
|
|
|
3893
4553
|
const USAGE_POLL_INTERVAL_MS = 15 * 6e4;
|
|
3894
4554
|
/** How often the badge re-reads the session's current model (model switches arrive only by asking). */
|
|
3895
4555
|
const MODEL_POLL_INTERVAL_MS = 3e3;
|
|
4556
|
+
/** How long the rotation holds one provider in `always` mode (a display cadence, not a data poll). */
|
|
4557
|
+
const BADGE_ROTATION_INTERVAL_MS = 1e4;
|
|
3896
4558
|
/** Distance between the trigger's top edge and the dialog's bottom (host stat dialogs use the same). */
|
|
3897
4559
|
const PANEL_GAP = 8;
|
|
3898
4560
|
/** Distance kept between the dialog and each viewport edge. */
|
|
@@ -4092,6 +4754,24 @@ function collapsedDisplays(displays, current) {
|
|
|
4092
4754
|
const match = displays.find((d) => d.provider === current);
|
|
4093
4755
|
return match === void 0 ? [] : [match];
|
|
4094
4756
|
}
|
|
4757
|
+
/**
|
|
4758
|
+
* `always` mode: the current model's provider while it reports usage,
|
|
4759
|
+
* otherwise the rotation steps through the providers that do, in display
|
|
4760
|
+
* order, wrapping around. The index is taken modulo the current provider
|
|
4761
|
+
* count, so providers appearing or dropping out stay inside range; the
|
|
4762
|
+
* sequence itself may shift when the roster changes. Unlike `recent`, the
|
|
4763
|
+
* retained subscription does not pin the pill — that retention is exactly
|
|
4764
|
+
* what this mode exists to escape.
|
|
4765
|
+
* @param displays - providers with usage, in display order.
|
|
4766
|
+
* @param current - the provider of the session's current model.
|
|
4767
|
+
* @param step - rotation tick; consecutive ticks advance one provider.
|
|
4768
|
+
*/
|
|
4769
|
+
function rotatingDisplay(displays, current, step) {
|
|
4770
|
+
if (displays.length === 0) return [];
|
|
4771
|
+
const match = displays.find((d) => d.provider === current);
|
|
4772
|
+
if (match !== void 0) return [match];
|
|
4773
|
+
return [displays[((Number.isFinite(step) ? Math.floor(step) : 0) % displays.length + displays.length) % displays.length]];
|
|
4774
|
+
}
|
|
4095
4775
|
/** Order for the expanded dialog: the current provider first, the rest in poll order. */
|
|
4096
4776
|
function expandedDisplays(displays, current) {
|
|
4097
4777
|
const match = displays.find((d) => d.provider === current);
|
|
@@ -4125,7 +4805,7 @@ function usageWindowLabel(t, window$1) {
|
|
|
4125
4805
|
* every provider's accounts and their windows. Returns null when no data is
|
|
4126
4806
|
* available.
|
|
4127
4807
|
*/
|
|
4128
|
-
function SubscriptionUsageBadge({ rpc, currentModel, t }) {
|
|
4808
|
+
function SubscriptionUsageBadge({ rpc, currentModel, t, rotationMs }) {
|
|
4129
4809
|
const translate = t ?? fallbackTranslate;
|
|
4130
4810
|
const [displays, setDisplays] = (0, react.useState)([]);
|
|
4131
4811
|
const [selection, setSelection] = (0, react.useState)(void 0);
|
|
@@ -4135,6 +4815,8 @@ function SubscriptionUsageBadge({ rpc, currentModel, t }) {
|
|
|
4135
4815
|
const badgeSelection = retainSubscriptionSelection(lastSubscription, selection);
|
|
4136
4816
|
const [open, setOpen] = (0, react.useState)(false);
|
|
4137
4817
|
const [hover, setHover] = (0, react.useState)(false);
|
|
4818
|
+
const [rotation, setRotation] = (0, react.useState)(0);
|
|
4819
|
+
const [dialogLead, setDialogLead] = (0, react.useState)(void 0);
|
|
4138
4820
|
const inflightRef = (0, react.useRef)(false);
|
|
4139
4821
|
const mountedRef = (0, react.useRef)(true);
|
|
4140
4822
|
const rootRef = (0, react.useRef)(null);
|
|
@@ -4298,99 +4980,119 @@ function SubscriptionUsageBadge({ rpc, currentModel, t }) {
|
|
|
4298
4980
|
(0, react.useEffect)(() => {
|
|
4299
4981
|
if (displayMode === "hidden") setOpen(false);
|
|
4300
4982
|
}, [displayMode]);
|
|
4983
|
+
(0, react.useEffect)(() => {
|
|
4984
|
+
if (displayMode !== "always") return;
|
|
4985
|
+
const interval = rotationMs !== void 0 && Number.isFinite(rotationMs) && rotationMs > 0 ? rotationMs : BADGE_ROTATION_INTERVAL_MS;
|
|
4986
|
+
const timer = setInterval(() => {
|
|
4987
|
+
setRotation((step) => step + 1);
|
|
4988
|
+
}, interval);
|
|
4989
|
+
return () => {
|
|
4990
|
+
clearInterval(timer);
|
|
4991
|
+
};
|
|
4992
|
+
}, [displayMode, rotationMs]);
|
|
4301
4993
|
const seat = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
4302
4994
|
ref: seatRef,
|
|
4303
4995
|
style: styles.seat,
|
|
4304
4996
|
"aria-hidden": true
|
|
4305
4997
|
});
|
|
4306
|
-
const collapsed = collapsedDisplays(displays, badgeSelection?.provider);
|
|
4998
|
+
const collapsed = displayMode === "always" ? rotatingDisplay(displays, current, rotation) : collapsedDisplays(displays, badgeSelection?.provider);
|
|
4307
4999
|
if (displayMode === "hidden" || collapsed.length === 0) return seat;
|
|
4308
|
-
const
|
|
4309
|
-
const
|
|
5000
|
+
const pillModel = displayMode === "always" ? current === collapsed[0]?.provider ? selection?.model : void 0 : badgeSelection?.model;
|
|
5001
|
+
const label = compactSegment(collapsed[0], pillModel, translate);
|
|
5002
|
+
const dialogProvider = open && displayMode === "always" ? dialogLead : badgeSelection?.provider;
|
|
5003
|
+
const dialogModel = open && displayMode === "always" ? dialogLead === current ? selection?.model : void 0 : badgeSelection?.model;
|
|
5004
|
+
const expanded = expandedDisplays(displays, dialogProvider);
|
|
4310
5005
|
const title = translate("usageBadgeTitle");
|
|
4311
5006
|
const toggle = () => {
|
|
4312
5007
|
const next = !open;
|
|
5008
|
+
setDialogLead(collapsed[0]?.provider);
|
|
4313
5009
|
setOpen(next);
|
|
4314
5010
|
if (next) refresh();
|
|
4315
5011
|
};
|
|
4316
5012
|
const pill = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
4317
5013
|
ref: rootRef,
|
|
4318
5014
|
style: styles.anchor,
|
|
4319
|
-
children: [
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
5015
|
+
children: [
|
|
5016
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: subscriptionChromeCss }),
|
|
5017
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
5018
|
+
type: "button",
|
|
5019
|
+
className: "dsh-subscription-usage-pill",
|
|
5020
|
+
style: {
|
|
5021
|
+
...styles.pill,
|
|
5022
|
+
...hover || open ? styles.pillActive : {}
|
|
5023
|
+
},
|
|
5024
|
+
"aria-haspopup": "dialog",
|
|
5025
|
+
"aria-expanded": open,
|
|
5026
|
+
"aria-label": `${title} · ${label}`,
|
|
5027
|
+
title,
|
|
5028
|
+
onMouseEnter: () => {
|
|
5029
|
+
setHover(true);
|
|
5030
|
+
},
|
|
5031
|
+
onMouseLeave: () => {
|
|
5032
|
+
setHover(false);
|
|
5033
|
+
},
|
|
5034
|
+
onClick: toggle,
|
|
5035
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageBadgeIcon, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5036
|
+
style: styles.label,
|
|
5037
|
+
children: label
|
|
5038
|
+
})]
|
|
5039
|
+
}),
|
|
5040
|
+
open && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5041
|
+
ref: panelRef,
|
|
5042
|
+
role: "dialog",
|
|
5043
|
+
"aria-label": title,
|
|
5044
|
+
className: "dsh-subscription-usage-panel",
|
|
5045
|
+
style: {
|
|
5046
|
+
...styles.panel,
|
|
5047
|
+
...pos ?? MEASURE_STYLE
|
|
5048
|
+
},
|
|
5049
|
+
children: [
|
|
5050
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5051
|
+
style: styles.title,
|
|
5052
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
5053
|
+
style: styles.titleLabel,
|
|
5054
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageBadgeIcon, {}), title]
|
|
5055
|
+
})
|
|
5056
|
+
}),
|
|
5057
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5058
|
+
style: styles.titleRule,
|
|
5059
|
+
"aria-hidden": true
|
|
5060
|
+
}),
|
|
5061
|
+
expanded.map((d, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
5062
|
+
style: index === 0 ? void 0 : styles.section,
|
|
5063
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5064
|
+
style: styles.providerRow,
|
|
5065
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
5066
|
+
style: styles.providerName,
|
|
5067
|
+
children: [d.name, d.provider === current && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
5068
|
+
style: styles.currentTag,
|
|
5069
|
+
children: translate("usageBadgeCurrent")
|
|
5070
|
+
})]
|
|
5071
|
+
}), d.accounts.length === 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountMeta, {
|
|
5072
|
+
account: d.accounts[0],
|
|
5073
|
+
translate
|
|
4369
5074
|
})]
|
|
4370
|
-
}), d.accounts.
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
account,
|
|
5075
|
+
}), d.accounts.map((account, accountIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
5076
|
+
style: accountIndex === 0 ? void 0 : styles.accountBlock,
|
|
5077
|
+
children: [d.accounts.length > 1 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5078
|
+
style: styles.accountRow,
|
|
5079
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountMeta, {
|
|
5080
|
+
account,
|
|
5081
|
+
translate
|
|
5082
|
+
})
|
|
5083
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountWindows, {
|
|
5084
|
+
windows: account.windows,
|
|
5085
|
+
observedAt: account.observedAt,
|
|
5086
|
+
stale: account.stale,
|
|
5087
|
+
model: d.provider === dialogProvider ? dialogModel : void 0,
|
|
5088
|
+
provider: d.provider,
|
|
4380
5089
|
translate
|
|
4381
|
-
})
|
|
4382
|
-
}
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
provider: d.provider,
|
|
4388
|
-
translate
|
|
4389
|
-
}, `${d.provider}:${badgeSelection?.model ?? ""}`)]
|
|
4390
|
-
}, account.key))]
|
|
4391
|
-
}, d.provider))
|
|
4392
|
-
]
|
|
4393
|
-
}), document.body)]
|
|
5090
|
+
}, `${d.provider}:${dialogModel ?? ""}`)]
|
|
5091
|
+
}, account.key))]
|
|
5092
|
+
}, d.provider))
|
|
5093
|
+
]
|
|
5094
|
+
}), document.body)
|
|
5095
|
+
]
|
|
4394
5096
|
});
|
|
4395
5097
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [seat, statsRow !== null && statsRow.isConnected ? (0, react_dom.createPortal)(pill, statsRow) : pill] });
|
|
4396
5098
|
}
|
|
@@ -4490,13 +5192,13 @@ const styles = {
|
|
|
4490
5192
|
maxWidth: "100%",
|
|
4491
5193
|
color: "var(--dsw-alias-label-tertiary)",
|
|
4492
5194
|
font: "inherit",
|
|
4493
|
-
fontSize: "var(--dsh-content-font-size-secondary, 13px)",
|
|
5195
|
+
fontSize: "calc(var(--dsh-content-font-size-secondary, 13px) - 1px)",
|
|
4494
5196
|
fontVariantNumeric: "tabular-nums",
|
|
4495
|
-
lineHeight: "20px",
|
|
5197
|
+
lineHeight: "calc(20px + var(--dsh-content-font-delta-secondary, 0px))",
|
|
4496
5198
|
whiteSpace: "nowrap",
|
|
4497
5199
|
background: "transparent",
|
|
4498
5200
|
border: "none",
|
|
4499
|
-
borderRadius:
|
|
5201
|
+
borderRadius: 999,
|
|
4500
5202
|
alignItems: "center",
|
|
4501
5203
|
gap: 6,
|
|
4502
5204
|
padding: "1px 8px",
|
|
@@ -4528,7 +5230,7 @@ const styles = {
|
|
|
4528
5230
|
color: "var(--dsw-alias-label-secondary)",
|
|
4529
5231
|
cursor: "default",
|
|
4530
5232
|
border: 0,
|
|
4531
|
-
borderRadius:
|
|
5233
|
+
borderRadius: "var(--dsw-radius-lg, 16px)",
|
|
4532
5234
|
padding: 16,
|
|
4533
5235
|
fontSize: 12,
|
|
4534
5236
|
lineHeight: "18px"
|