dsh-ds-balance 2.3.1 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +84 -178
- package/README_zh.md +140 -0
- package/lib/adapters/host-account.d.ts +22 -1
- package/lib/adapters/host-account.js +13 -0
- package/lib/client.js +619 -461
- package/lib/config.d.ts +28 -19
- package/lib/config.js +27 -19
- package/lib/domain/credential.d.ts +41 -0
- package/lib/domain/credential.js +52 -0
- package/lib/http/handlers.d.ts +33 -2
- package/lib/http/handlers.js +124 -31
- package/lib/http/routes.d.ts +5 -1
- package/lib/http/routes.js +2 -1
- package/lib/http/wire.d.ts +58 -1
- package/lib/http/wire.js +3 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +35 -6
- package/lib/ports/account.d.ts +25 -0
- package/lib/services/key-resolver.d.ts +33 -3
- package/lib/services/key-resolver.js +41 -12
- package/lib/services/source-readers.js +3 -3
- package/lib/services/source-selector.d.ts +10 -0
- package/lib/services/source-selector.js +14 -4
- package/lib/services/sources-service.d.ts +148 -0
- package/lib/services/sources-service.js +209 -0
- package/lib/types/client/api-types.d.ts +8 -0
- package/lib/types/client/data.d.ts +72 -0
- package/lib/types/client/icons/currency.d.ts +26 -0
- package/lib/types/client/icons.d.ts +92 -0
- package/lib/types/client/locales.d.ts +15 -13
- package/lib/types/client/model.d.ts +10 -0
- package/lib/types/client/settings/AccountAvatar.d.ts +27 -0
- package/lib/types/client/settings/BalanceSettingsCard.d.ts +8 -1
- package/lib/types/client/settings/fields.d.ts +70 -39
- package/lib/types/client/settings/source-status.d.ts +43 -0
- package/lib/types/client/settings/use-config-form.d.ts +1 -27
- package/lib/types/client/settings/use-sources.d.ts +38 -0
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +35 -35
- package/README_en.md +0 -237
- package/lib/types/client/settings/use-credential-state.d.ts +0 -36
package/lib/client.js
CHANGED
|
@@ -23,20 +23,19 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
23
23
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
24
24
|
|
|
25
25
|
// src/client/index.tsx
|
|
26
|
-
var
|
|
27
|
-
__export(
|
|
26
|
+
var index_exports = {};
|
|
27
|
+
__export(index_exports, {
|
|
28
28
|
BUNDLE_CONFIG_KEY: () => BUNDLE_CONFIG_KEY,
|
|
29
29
|
ENTRY_ID: () => ENTRY_ID,
|
|
30
30
|
SIDEBAR_ENTRY_ID: () => SIDEBAR_ENTRY_ID,
|
|
31
31
|
apply: () => apply,
|
|
32
32
|
inject: () => inject
|
|
33
33
|
});
|
|
34
|
-
module.exports = __toCommonJS(
|
|
35
|
-
var
|
|
34
|
+
module.exports = __toCommonJS(index_exports);
|
|
35
|
+
var import_react7 = require("react");
|
|
36
36
|
|
|
37
37
|
// src/client/settings/BalanceSettingsCard.tsx
|
|
38
|
-
var
|
|
39
|
-
var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
38
|
+
var import_react5 = require("react");
|
|
40
39
|
|
|
41
40
|
// src/client/locales.ts
|
|
42
41
|
var NS = "ds-balance";
|
|
@@ -50,6 +49,9 @@ var zh = {
|
|
|
50
49
|
// 代码里只做拼接,绝不写死括号字符。
|
|
51
50
|
"popover.source.key": "\uFF08API Key\uFF09",
|
|
52
51
|
"popover.source.account": "\uFF08\u8D26\u53F7\u767B\u5F55\uFF09",
|
|
52
|
+
// 有身份时用它替掉上面那两句:括号里直接放「哪一把凭据」。括号照旧在词典里
|
|
53
|
+
// (中文全角、英文半角带前置空格),`{identity}` 由 interpolate 填。
|
|
54
|
+
"popover.source.identity": "\uFF08{identity}\uFF09",
|
|
53
55
|
"popover.total": "\u4F59\u989D",
|
|
54
56
|
"popover.granted": "\u8D60\u9001",
|
|
55
57
|
"popover.toppedUp": "\u5145\u503C",
|
|
@@ -94,9 +96,6 @@ var zh = {
|
|
|
94
96
|
"settings.group.refresh": "\u5237\u65B0",
|
|
95
97
|
"settings.group.display": "\u5C55\u793A",
|
|
96
98
|
"settings.group.thresholds": "\u9608\u503C",
|
|
97
|
-
"settings.field.apiKey": "API Key",
|
|
98
|
-
"settings.field.apiKeyRef": "API \u5BC6\u94A5\u5F15\u7528\u540D",
|
|
99
|
-
"settings.field.baseUrl": "\u63A5\u53E3\u5730\u5740",
|
|
100
99
|
"settings.field.serverRefreshSeconds": "\u670D\u52A1\u7AEF\u5237\u65B0\u9891\u7387\uFF08\u79D2\uFF09",
|
|
101
100
|
"settings.field.clientPollSeconds": "\u5BA2\u6237\u7AEF\u8F6E\u8BE2\u9891\u7387\uFF08\u79D2\uFF09",
|
|
102
101
|
"settings.field.manualRefreshCooldownSeconds": "\u624B\u52A8\u5237\u65B0\u51B7\u5374\uFF08\u79D2\uFF09",
|
|
@@ -105,8 +104,35 @@ var zh = {
|
|
|
105
104
|
"settings.field.cnyCritical": "CNY \u544A\u6025",
|
|
106
105
|
"settings.field.usdWarn": "USD \u9884\u8B66",
|
|
107
106
|
"settings.field.usdCritical": "USD \u544A\u6025",
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
// ── 「连接」组:两条取数途径的只读状态 ──────────────────────────
|
|
108
|
+
// 措辞逐条对齐官方:账号那几句取自 ui-settings-account 的 signedIn / signedOut /
|
|
109
|
+
// profileUnavailable;密钥那几句取自 ui-settings-models 的 apiKeySet / apiKeyUnset。
|
|
110
|
+
// 官方那套词在 settings.account / settings.models 命名空间,别的插件拿不到,所以抄进来。
|
|
111
|
+
//
|
|
112
|
+
// **3.0 起这一段只剩两句话**:组级说明 + 每行第二行的「来历」。
|
|
113
|
+
// 状态徽章(已配置密钥。/ 未配置密钥。…)整套删了 —— 它与左边那盏灯说同一件事,
|
|
114
|
+
// 而「一个事实说两遍」正是本轮要消掉的东西。判据见 source-status.ts。
|
|
115
|
+
"settings.sources.title": "\u53D6\u6570\u9014\u5F84",
|
|
116
|
+
"settings.sources.key": "API Key",
|
|
117
|
+
"settings.sources.account": "\u8D26\u53F7\u767B\u5F55",
|
|
118
|
+
// 组级说明:一句替掉原来每行各一句的近义说明。
|
|
119
|
+
"settings.sources.groupNote": "\u4E24\u6761\u9014\u5F84\u90FD\u8DDF\u968F\u5B98\u65B9\uFF1A\u5BC6\u94A5\u7528\u5B98\u65B9\u6A21\u578B\u9875\u914D\u597D\u7684\u90A3\u4E00\u4EFD\uFF0C\u8D26\u53F7\u7528\u5BBF\u4E3B\u5DF2\u767B\u5F55\u7684\u90A3\u4E2A\u3002\u672C\u63D2\u4EF6\u4E0D\u81EA\u5DF1\u4FDD\u5B58\u51ED\u636E\u3002",
|
|
120
|
+
// 第二行的「来历」:这把凭据是从哪一层取到的。取值来自官方 describe() 的 source。
|
|
121
|
+
"settings.sources.sourceSaved": "\u53D6\u81EA\u5B98\u65B9\u6A21\u578B\u9875\u4FDD\u5B58\u7684\u51ED\u636E",
|
|
122
|
+
"settings.sources.sourceEnv": "\u53D6\u81EA\u542F\u52A8\u73AF\u5883\u53D8\u91CF {name}",
|
|
123
|
+
"settings.sources.sourceUnknown": "\u6765\u6E90\u672A\u786E\u8BA4",
|
|
124
|
+
// 账号那条唯一需要说出来的一句:那是**部署事实**,用户做什么都没用;
|
|
125
|
+
// 而整行留空会被读成「插件坏了」。未登录不说 —— 它是正常状态。
|
|
126
|
+
"settings.sources.accountNoService": "\u672C\u90E8\u7F72\u6CA1\u6709\u8D26\u53F7\u670D\u52A1\uFF0C\u8FD9\u6761\u9014\u5F84\u4E0D\u53EF\u7528\u3002",
|
|
127
|
+
// 测试。结果借每行右槽显示 4 秒(排在凭据身份**左边**,所以身份不会被顶掉),
|
|
128
|
+
// 所以文案要短。成败由**官方那对圆圈图标**表达(check-circle / close-circle),
|
|
129
|
+
// 不用 `✓` / `✗` 字符:字符的基线、字重、间距都跟着字体走,与旁边那行等宽掩码并排会歪。
|
|
130
|
+
"settings.test": "\u6D4B\u8BD5",
|
|
131
|
+
"settings.testing": "\u6B63\u5728\u6D4B\u8BD5\u2026",
|
|
132
|
+
"settings.test.ok": "{ms}ms",
|
|
133
|
+
"settings.test.noKey": "\u6CA1\u6709\u53EF\u7528\u51ED\u636E",
|
|
134
|
+
"settings.test.notSignedIn": "\u5C1A\u672A\u767B\u5F55",
|
|
135
|
+
"settings.test.fail": "\u8FDE\u63A5\u5931\u8D25\uFF1A{message}",
|
|
110
136
|
"settings.hint.displayCurrency": "\u6240\u9009\u5E01\u79CD\u4E0D\u5B58\u5728\u65F6\uFF0C\u56DE\u843D\u5230\u8D26\u6237\u5B9E\u9645\u6301\u6709\u7684\u5E01\u79CD\u3002",
|
|
111
137
|
"settings.hint.threshold": "\u540E\u7AEF\u5224\u5B9A\uFF1B\u754C\u9762\u989C\u8272\u8DDF\u968F\u8FD4\u56DE\u7684\u4E25\u91CD\u5EA6\u3002",
|
|
112
138
|
"settings.hint.thresholdPair": "\u544A\u6025\u503C\u5FC5\u987B\u4F4E\u4E8E\u9884\u8B66\u503C",
|
|
@@ -114,18 +140,6 @@ var zh = {
|
|
|
114
140
|
"settings.hint.clientPollSeconds": "\u5237\u65B0\u663E\u793A\u7684\u95F4\u9694\uFF1B\u6B63\u5E38\u65F6\u53EA\u8BFB\u7F13\u5B58\uFF0C\u8BFB\u4E0D\u5230\u65F6\u624D\u8BBF\u95EE\u4E0A\u6E38\u3002",
|
|
115
141
|
"settings.hint.manualRefreshCooldownSeconds": "\u4E24\u6B21\u624B\u52A8\u5237\u65B0\u4E4B\u95F4\u7684\u6700\u77ED\u95F4\u9694\u3002",
|
|
116
142
|
"settings.currency.auto": "\u81EA\u52A8\uFF08\u8DDF\u968F\u8D26\u6237\uFF09",
|
|
117
|
-
// 凭据行的**状态徽章**:两条逐字用官方措辞 —— 取自 ui-settings-plugins 的
|
|
118
|
-
// webSearchApiKeySet / webSearchApiKeyUnset(后者去掉搜索相关的后半句)。
|
|
119
|
-
"settings.credential.configured": "\u5DF2\u914D\u7F6E\u5BC6\u94A5\u3002",
|
|
120
|
-
"settings.credential.notConfigured": "\u672A\u914D\u7F6E\u5BC6\u94A5\u3002",
|
|
121
|
-
// 凭据行下方的说明。官方 webSearchApiKeyHint 是一句与状态无关的常量说明,这里照做:
|
|
122
|
-
// 状态由徽章交代,说明只讲字段契约。
|
|
123
|
-
"settings.hint.credential": "\u4E0D\u5199\u5165\u8BBE\u7F6E\u6587\u4EF6\u3002\u7559\u7A7A\u8868\u793A\u4FDD\u6301\u5F53\u524D\u5BC6\u94A5\u3002",
|
|
124
|
-
"settings.group.customized": "\u81EA\u5B9A\u4E49\u8BBE\u7F6E",
|
|
125
|
-
"settings.test": "\u6D4B\u8BD5\u8FDE\u63A5",
|
|
126
|
-
"settings.testing": "\u6D4B\u8BD5\u4E2D\u2026",
|
|
127
|
-
"settings.test.ok": "\u8FDE\u63A5\u6B63\u5E38\u3002",
|
|
128
|
-
"settings.test.fail": "\u8FDE\u63A5\u5931\u8D25\uFF1A{message}",
|
|
129
143
|
"settings.save": "\u4FDD\u5B58",
|
|
130
144
|
"settings.saving": "\u4FDD\u5B58\u4E2D\u2026",
|
|
131
145
|
"settings.failed": "\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002",
|
|
@@ -155,6 +169,7 @@ var en = {
|
|
|
155
169
|
"popover.title": "Account balance",
|
|
156
170
|
"popover.source.key": " (API key)",
|
|
157
171
|
"popover.source.account": " (account sign-in)",
|
|
172
|
+
"popover.source.identity": " ({identity})",
|
|
158
173
|
"popover.total": "Balance",
|
|
159
174
|
"popover.granted": "Granted",
|
|
160
175
|
"popover.toppedUp": "Topped up",
|
|
@@ -180,9 +195,6 @@ var en = {
|
|
|
180
195
|
"settings.group.refresh": "Refresh",
|
|
181
196
|
"settings.group.display": "Display",
|
|
182
197
|
"settings.group.thresholds": "Thresholds",
|
|
183
|
-
"settings.field.apiKey": "API key",
|
|
184
|
-
"settings.field.apiKeyRef": "API key reference",
|
|
185
|
-
"settings.field.baseUrl": "Endpoint",
|
|
186
198
|
"settings.field.serverRefreshSeconds": "Server refresh (seconds)",
|
|
187
199
|
"settings.field.clientPollSeconds": "Client poll (seconds)",
|
|
188
200
|
"settings.field.manualRefreshCooldownSeconds": "Manual refresh cooldown (seconds)",
|
|
@@ -191,8 +203,21 @@ var en = {
|
|
|
191
203
|
"settings.field.cnyCritical": "CNY critical",
|
|
192
204
|
"settings.field.usdWarn": "USD warning",
|
|
193
205
|
"settings.field.usdCritical": "USD critical",
|
|
194
|
-
|
|
195
|
-
"settings.
|
|
206
|
+
// 与 zh 逐条对应,理由写在 zh 那一段。
|
|
207
|
+
"settings.sources.title": "Balance sources",
|
|
208
|
+
"settings.sources.key": "API key",
|
|
209
|
+
"settings.sources.account": "Account sign-in",
|
|
210
|
+
"settings.sources.groupNote": "Both sources follow the official setup: the key comes from the official Models page, the account is the one signed in to the host. This plugin stores no credential of its own.",
|
|
211
|
+
"settings.sources.sourceSaved": "From the credential saved on the Models page",
|
|
212
|
+
"settings.sources.sourceEnv": "From the launch env var {name}",
|
|
213
|
+
"settings.sources.sourceUnknown": "Source unconfirmed",
|
|
214
|
+
"settings.sources.accountNoService": "This deployment ships no account service, so this source is unavailable.",
|
|
215
|
+
"settings.test": "Test",
|
|
216
|
+
"settings.testing": "Testing\u2026",
|
|
217
|
+
"settings.test.ok": "{ms}ms",
|
|
218
|
+
"settings.test.noKey": "No credential available",
|
|
219
|
+
"settings.test.notSignedIn": "Not signed in",
|
|
220
|
+
"settings.test.fail": "Connection failed: {message}",
|
|
196
221
|
"settings.hint.displayCurrency": "Falls back to a currency the account actually holds.",
|
|
197
222
|
"settings.hint.threshold": "Decided on the server; the UI colour follows the returned severity.",
|
|
198
223
|
"settings.hint.thresholdPair": "Critical must be lower than warning",
|
|
@@ -200,14 +225,6 @@ var en = {
|
|
|
200
225
|
"settings.hint.clientPollSeconds": "How often the display refreshes; cache-only while healthy.",
|
|
201
226
|
"settings.hint.manualRefreshCooldownSeconds": "Minimum gap between two manual refreshes.",
|
|
202
227
|
"settings.currency.auto": "Automatic (follow account)",
|
|
203
|
-
"settings.credential.configured": "A key is configured.",
|
|
204
|
-
"settings.credential.notConfigured": "No key is configured.",
|
|
205
|
-
"settings.hint.credential": "Stored outside the settings file. Leave blank to keep the current key.",
|
|
206
|
-
"settings.group.customized": "Customized settings",
|
|
207
|
-
"settings.test": "Test connection",
|
|
208
|
-
"settings.testing": "Testing\u2026",
|
|
209
|
-
"settings.test.ok": "Connection looks good.",
|
|
210
|
-
"settings.test.fail": "Connection failed: {message}",
|
|
211
228
|
"settings.save": "Save",
|
|
212
229
|
"settings.saving": "Saving\u2026",
|
|
213
230
|
"settings.failed": "Saving failed. Try again.",
|
|
@@ -229,10 +246,85 @@ function interpolate(template, params) {
|
|
|
229
246
|
);
|
|
230
247
|
}
|
|
231
248
|
|
|
232
|
-
// src/client/
|
|
249
|
+
// src/client/icons.ts
|
|
250
|
+
var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
251
|
+
|
|
252
|
+
// src/client/icons/currency.tsx
|
|
253
|
+
var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
254
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
255
|
+
function CurrencyOutlineIcon({ size = 14, className }) {
|
|
256
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
257
|
+
"svg",
|
|
258
|
+
{
|
|
259
|
+
width: size,
|
|
260
|
+
height: size,
|
|
261
|
+
className,
|
|
262
|
+
viewBox: "0 0 16 16",
|
|
263
|
+
fill: "none",
|
|
264
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
265
|
+
"aria-hidden": "true",
|
|
266
|
+
strokeWidth: import_dsh_client_ui_primitives.ICON_REGULAR_STROKE,
|
|
267
|
+
children: [
|
|
268
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4.6 3.4 8 7.6 11.4 3.4", stroke: "currentColor" }),
|
|
269
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 7.6V12.6", stroke: "currentColor" }),
|
|
270
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5.6 9.1H10.4", stroke: "currentColor" }),
|
|
271
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5.6 11H10.4", stroke: "currentColor" })
|
|
272
|
+
]
|
|
273
|
+
}
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// src/client/icons.ts
|
|
278
|
+
var GROUP_ICONS = {
|
|
279
|
+
connection: import_dsh_client_ui_primitives2.IconLinkOutlineRegular,
|
|
280
|
+
display: CurrencyOutlineIcon,
|
|
281
|
+
thresholds: import_dsh_client_ui_primitives2.IconWarningOutlineRegular,
|
|
282
|
+
refresh: import_dsh_client_ui_primitives2.IconRefreshOutlineRegular
|
|
283
|
+
};
|
|
284
|
+
var RESULT_ICONS = {
|
|
285
|
+
ok: import_dsh_client_ui_primitives2.IconCheckOutlineRegular,
|
|
286
|
+
fail: import_dsh_client_ui_primitives2.IconCloseOutlineRegular
|
|
287
|
+
};
|
|
288
|
+
var HEADER_CHEVRONS = {
|
|
289
|
+
closed: import_dsh_client_ui_primitives2.IconChevronDownOutlineRegular,
|
|
290
|
+
open: import_dsh_client_ui_primitives2.IconChevronUpOutlineRegular
|
|
291
|
+
};
|
|
292
|
+
var SELECTOR_ICON = import_dsh_client_ui_primitives2.IconChevronDownOutlineRegular;
|
|
293
|
+
|
|
294
|
+
// src/client/settings/AccountAvatar.tsx
|
|
233
295
|
var import_react = require("react");
|
|
234
296
|
|
|
235
|
-
//
|
|
297
|
+
// src/client/settings/AccountAvatar.module.css
|
|
298
|
+
var AccountAvatar_default = {
|
|
299
|
+
avatar: "AccountAvatar_avatar",
|
|
300
|
+
image: "AccountAvatar_image"
|
|
301
|
+
};
|
|
302
|
+
|
|
303
|
+
// src/client/settings/AccountAvatar.tsx
|
|
304
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
305
|
+
function AccountAvatar({ url }) {
|
|
306
|
+
const [failed, setFailed] = (0, import_react.useState)(false);
|
|
307
|
+
(0, import_react.useEffect)(() => {
|
|
308
|
+
setFailed(false);
|
|
309
|
+
}, [url]);
|
|
310
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: AccountAvatar_default.avatar, children: url === null || failed ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
311
|
+
"img",
|
|
312
|
+
{
|
|
313
|
+
className: AccountAvatar_default.image,
|
|
314
|
+
src: url,
|
|
315
|
+
alt: "",
|
|
316
|
+
referrerPolicy: "no-referrer",
|
|
317
|
+
onError: () => {
|
|
318
|
+
setFailed(true);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
) });
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// src/client/settings/fields.tsx
|
|
325
|
+
var import_react2 = require("react");
|
|
326
|
+
|
|
327
|
+
// node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
|
|
236
328
|
function r(e) {
|
|
237
329
|
var t, f, n = "";
|
|
238
330
|
if ("string" == typeof e || "number" == typeof e) n += e;
|
|
@@ -249,16 +341,35 @@ function clsx() {
|
|
|
249
341
|
var clsx_default = clsx;
|
|
250
342
|
|
|
251
343
|
// src/client/settings/fields.tsx
|
|
252
|
-
var
|
|
344
|
+
var import_dsh_client_ui_primitives3 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
253
345
|
|
|
254
346
|
// src/client/settings/fields.module.css
|
|
255
347
|
var fields_default = {
|
|
256
348
|
group: "fields_group",
|
|
349
|
+
groupHead: "fields_groupHead",
|
|
350
|
+
groupLeading: "fields_groupLeading",
|
|
351
|
+
groupIcon: "fields_groupIcon",
|
|
352
|
+
groupChevronClosed: "fields_groupChevronClosed",
|
|
353
|
+
groupChevronOpen: "fields_groupChevronOpen",
|
|
354
|
+
groupTitle: "fields_groupTitle",
|
|
257
355
|
groupLast: "fields_groupLast",
|
|
258
356
|
groupNote: "fields_groupNote",
|
|
259
357
|
fields: "fields_fields",
|
|
260
358
|
details: "fields_details",
|
|
261
359
|
detailsBody: "fields_detailsBody",
|
|
360
|
+
source: "fields_source",
|
|
361
|
+
sourceHead: "fields_sourceHead",
|
|
362
|
+
dot: "fields_dot",
|
|
363
|
+
dotOk: "fields_dotOk",
|
|
364
|
+
dotMissing: "fields_dotMissing",
|
|
365
|
+
sourceName: "fields_sourceName",
|
|
366
|
+
sourceSlot: "fields_sourceSlot",
|
|
367
|
+
sourceIdentity: "fields_sourceIdentity",
|
|
368
|
+
sourceLiveText: "fields_sourceLiveText",
|
|
369
|
+
sourceIdentityMono: "fields_sourceIdentityMono",
|
|
370
|
+
sourceLive: "fields_sourceLive",
|
|
371
|
+
sourceLiveIcon: "fields_sourceLiveIcon",
|
|
372
|
+
sourceDetail: "fields_sourceDetail",
|
|
262
373
|
field: "fields_field",
|
|
263
374
|
row: "fields_row",
|
|
264
375
|
rowText: "fields_rowText",
|
|
@@ -280,27 +391,46 @@ var fields_default = {
|
|
|
280
391
|
hint: "fields_hint",
|
|
281
392
|
pairNote: "fields_pairNote",
|
|
282
393
|
invalid: "fields_invalid",
|
|
283
|
-
actions: "fields_actions"
|
|
284
|
-
resultOk: "fields_resultOk",
|
|
285
|
-
resultFail: "fields_resultFail"
|
|
394
|
+
actions: "fields_actions"
|
|
286
395
|
};
|
|
287
396
|
|
|
288
397
|
// src/client/settings/fields.tsx
|
|
289
|
-
var
|
|
398
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
290
399
|
function FieldGroup(props) {
|
|
291
|
-
return /* @__PURE__ */ (0,
|
|
292
|
-
|
|
400
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
401
|
+
"div",
|
|
293
402
|
{
|
|
294
403
|
className: clsx_default(fields_default.group, props.last === true && fields_default.groupLast),
|
|
295
|
-
|
|
296
|
-
title: props.title,
|
|
297
|
-
open: props.open,
|
|
298
|
-
expandable: true,
|
|
299
|
-
expandOnRowClick: true,
|
|
300
|
-
onToggle: props.onToggle,
|
|
404
|
+
"data-open": props.open || void 0,
|
|
301
405
|
children: [
|
|
302
|
-
|
|
303
|
-
|
|
406
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
407
|
+
"div",
|
|
408
|
+
{
|
|
409
|
+
className: fields_default.groupHead,
|
|
410
|
+
"data-disclosure-row": true,
|
|
411
|
+
role: "button",
|
|
412
|
+
tabIndex: 0,
|
|
413
|
+
"aria-expanded": props.open,
|
|
414
|
+
onClick: props.onToggle,
|
|
415
|
+
onKeyDown: (event) => {
|
|
416
|
+
if (event.key !== "Enter" && event.key !== " ") return;
|
|
417
|
+
event.preventDefault();
|
|
418
|
+
props.onToggle();
|
|
419
|
+
},
|
|
420
|
+
children: [
|
|
421
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: fields_default.groupLeading, children: [
|
|
422
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: fields_default.groupIcon, children: props.icon }),
|
|
423
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(HEADER_CHEVRONS.closed, { className: fields_default.groupChevronClosed }),
|
|
424
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(HEADER_CHEVRONS.open, { className: fields_default.groupChevronOpen })
|
|
425
|
+
] }),
|
|
426
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: fields_default.groupTitle, children: props.title })
|
|
427
|
+
]
|
|
428
|
+
}
|
|
429
|
+
),
|
|
430
|
+
props.open ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
431
|
+
props.note === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: fields_default.groupNote, children: props.note }),
|
|
432
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: fields_default.fields, children: props.children })
|
|
433
|
+
] }) : null
|
|
304
434
|
]
|
|
305
435
|
}
|
|
306
436
|
);
|
|
@@ -308,10 +438,10 @@ function FieldGroup(props) {
|
|
|
308
438
|
function FieldBadges(props) {
|
|
309
439
|
const status = props.status ?? null;
|
|
310
440
|
if (status === null && !props.pending && !props.resettable) return null;
|
|
311
|
-
return /* @__PURE__ */ (0,
|
|
312
|
-
status === null ? null : /* @__PURE__ */ (0,
|
|
313
|
-
props.pending ? /* @__PURE__ */ (0,
|
|
314
|
-
props.resettable ? /* @__PURE__ */ (0,
|
|
441
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: fields_default.badges, children: [
|
|
442
|
+
status === null ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.Tag, { tone: status.tone, children: status.label }),
|
|
443
|
+
props.pending ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.Tag, { tone: "neutral", children: props.pendingLabel }) : null,
|
|
444
|
+
props.resettable ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
315
445
|
"button",
|
|
316
446
|
{
|
|
317
447
|
type: "button",
|
|
@@ -326,10 +456,10 @@ function FieldBadges(props) {
|
|
|
326
456
|
function FieldFrame(props) {
|
|
327
457
|
const note = props.invalid ? props.invalidNote ?? props.hint : props.hint;
|
|
328
458
|
const hasNote = note !== void 0 && note !== null && note !== "";
|
|
329
|
-
return /* @__PURE__ */ (0,
|
|
330
|
-
/* @__PURE__ */ (0,
|
|
331
|
-
/* @__PURE__ */ (0,
|
|
332
|
-
/* @__PURE__ */ (0,
|
|
459
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: fields_default.field, children: [
|
|
460
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: fields_default.head, children: [
|
|
461
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { className: fields_default.label, htmlFor: props.id, children: props.label }),
|
|
462
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
333
463
|
FieldBadges,
|
|
334
464
|
{
|
|
335
465
|
status: props.status ?? null,
|
|
@@ -343,12 +473,12 @@ function FieldFrame(props) {
|
|
|
343
473
|
)
|
|
344
474
|
] }),
|
|
345
475
|
props.children,
|
|
346
|
-
hasNote ? /* @__PURE__ */ (0,
|
|
476
|
+
hasNote ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: props.invalid ? fields_default.invalid : fields_default.hint, children: note }) : null
|
|
347
477
|
] });
|
|
348
478
|
}
|
|
349
479
|
function TextControl(props) {
|
|
350
|
-
return /* @__PURE__ */ (0,
|
|
351
|
-
|
|
480
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
481
|
+
import_dsh_client_ui_primitives3.Input,
|
|
352
482
|
{
|
|
353
483
|
id: props.id,
|
|
354
484
|
className: props.invalid ? fields_default.inputInvalid : void 0,
|
|
@@ -364,40 +494,55 @@ function TextControl(props) {
|
|
|
364
494
|
}
|
|
365
495
|
);
|
|
366
496
|
}
|
|
367
|
-
function
|
|
368
|
-
|
|
369
|
-
|
|
497
|
+
function SourceRow(props) {
|
|
498
|
+
const live = props.live ?? null;
|
|
499
|
+
const identity = props.status.identity === "" ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
500
|
+
"span",
|
|
370
501
|
{
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
value: "",
|
|
375
|
-
readOnly: true
|
|
502
|
+
className: clsx_default(fields_default.sourceIdentity, props.monoIdentity === true && fields_default.sourceIdentityMono),
|
|
503
|
+
title: props.status.identity,
|
|
504
|
+
children: props.status.identity
|
|
376
505
|
}
|
|
377
506
|
);
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
507
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: fields_default.source, children: [
|
|
508
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: fields_default.sourceHead, children: [
|
|
509
|
+
props.leading === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
510
|
+
"span",
|
|
511
|
+
{
|
|
512
|
+
className: clsx_default(fields_default.dot, props.status.tone === "ok" ? fields_default.dotOk : fields_default.dotMissing),
|
|
513
|
+
"aria-hidden": "true"
|
|
514
|
+
}
|
|
515
|
+
) : props.leading,
|
|
516
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: fields_default.sourceName, children: props.label }),
|
|
517
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { className: fields_default.sourceSlot, children: [
|
|
518
|
+
live === null ? null : (
|
|
519
|
+
// 成功只是通报(polite);失败要用户处理(assertive)。**不上色**,成败靠图标形状。
|
|
520
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
521
|
+
"span",
|
|
522
|
+
{
|
|
523
|
+
className: fields_default.sourceLive,
|
|
524
|
+
role: live.kind === "busy" ? void 0 : live.ok ? "status" : "alert",
|
|
525
|
+
children: live.kind === "busy" ? (
|
|
526
|
+
// 官方原语的转圈:`ongoing` 是它唯一带运动的档。
|
|
527
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.StateDot, { state: "ongoing", size: 14 })
|
|
528
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
529
|
+
live.ok ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(RESULT_ICONS.ok, { className: fields_default.sourceLiveIcon }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(RESULT_ICONS.fail, { className: fields_default.sourceLiveIcon }),
|
|
530
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: fields_default.sourceLiveText, title: live.text, children: live.text })
|
|
531
|
+
] })
|
|
532
|
+
}
|
|
533
|
+
)
|
|
534
|
+
),
|
|
535
|
+
identity
|
|
536
|
+
] })
|
|
537
|
+
] }),
|
|
538
|
+
props.status.detail === "" ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: fields_default.sourceDetail, children: props.status.detail })
|
|
539
|
+
] });
|
|
395
540
|
}
|
|
396
541
|
function SelectorControl(props) {
|
|
397
|
-
const [open, setOpen] = (0,
|
|
542
|
+
const [open, setOpen] = (0, import_react2.useState)(false);
|
|
398
543
|
const selected = props.options.find((option) => option.id === props.selectedId);
|
|
399
|
-
return /* @__PURE__ */ (0,
|
|
400
|
-
|
|
544
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
545
|
+
import_dsh_client_ui_primitives3.Menu,
|
|
401
546
|
{
|
|
402
547
|
open,
|
|
403
548
|
onClose: () => {
|
|
@@ -412,7 +557,7 @@ function SelectorControl(props) {
|
|
|
412
557
|
align: "end",
|
|
413
558
|
portal: true,
|
|
414
559
|
className: fields_default.selectorAnchor,
|
|
415
|
-
anchor: /* @__PURE__ */ (0,
|
|
560
|
+
anchor: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
416
561
|
"button",
|
|
417
562
|
{
|
|
418
563
|
id: props.id,
|
|
@@ -427,7 +572,7 @@ function SelectorControl(props) {
|
|
|
427
572
|
},
|
|
428
573
|
children: [
|
|
429
574
|
selected?.label ?? "",
|
|
430
|
-
/* @__PURE__ */ (0,
|
|
575
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SELECTOR_ICON, { className: fields_default.selectorChevron })
|
|
431
576
|
]
|
|
432
577
|
}
|
|
433
578
|
)
|
|
@@ -435,24 +580,11 @@ function SelectorControl(props) {
|
|
|
435
580
|
);
|
|
436
581
|
}
|
|
437
582
|
function ActionRow(props) {
|
|
438
|
-
return /* @__PURE__ */ (0,
|
|
439
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: fields_default.actions, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { type: "button", variant: "outline", disabled: props.disabled, onClick: props.onClick, children: props.label }) }),
|
|
440
|
-
props.result === null ? null : (
|
|
441
|
-
// 成功只是通报,用 polite 的 status;失败需要用户处理,按 06 §6.7 的「行内错误」用 alert。
|
|
442
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
443
|
-
"p",
|
|
444
|
-
{
|
|
445
|
-
className: props.result.ok ? fields_default.resultOk : fields_default.resultFail,
|
|
446
|
-
role: props.result.ok ? "status" : "alert",
|
|
447
|
-
children: props.result.text
|
|
448
|
-
}
|
|
449
|
-
)
|
|
450
|
-
)
|
|
451
|
-
] });
|
|
583
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: fields_default.actions, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.Button, { type: "button", variant: "outline", disabled: props.disabled, onClick: props.onClick, children: props.label }) });
|
|
452
584
|
}
|
|
453
585
|
|
|
454
586
|
// src/client/settings/use-config-form.ts
|
|
455
|
-
var
|
|
587
|
+
var import_react3 = require("react");
|
|
456
588
|
function isTextSpec(spec) {
|
|
457
589
|
return spec.kind === "text" || spec.kind === "secret" || spec.kind === "number";
|
|
458
590
|
}
|
|
@@ -532,15 +664,6 @@ var CONFIG_FIELDS = [
|
|
|
532
664
|
var SPEC_BY_FIELD = new Map(
|
|
533
665
|
CONFIG_FIELDS.map((spec) => [spec.field, spec])
|
|
534
666
|
);
|
|
535
|
-
var TEST_LATENCY_MS = 800;
|
|
536
|
-
function probeFailure(baseUrl, apiKey, apiKeyRef) {
|
|
537
|
-
const url = baseUrl.trim();
|
|
538
|
-
if (url !== "" && !/^https?:\/\//i.test(url))
|
|
539
|
-
return "base URL must start with http:// or https://";
|
|
540
|
-
if (apiKey.trim() === "" && apiKeyRef.trim() === "")
|
|
541
|
-
return "no API key or credential reference configured";
|
|
542
|
-
return null;
|
|
543
|
-
}
|
|
544
667
|
function isRecord(input) {
|
|
545
668
|
return typeof input === "object" && input !== null && !Array.isArray(input);
|
|
546
669
|
}
|
|
@@ -684,8 +807,8 @@ function fieldOf(snapshot, name, edit) {
|
|
|
684
807
|
return fieldStateOf(snapshot, spec, edit);
|
|
685
808
|
}
|
|
686
809
|
function useConfigForm(form) {
|
|
687
|
-
const cacheRef = (0,
|
|
688
|
-
const readSnapshot = (0,
|
|
810
|
+
const cacheRef = (0, import_react3.useRef)(null);
|
|
811
|
+
const readSnapshot = (0, import_react3.useCallback)(() => {
|
|
689
812
|
const raw = form.getSnapshot();
|
|
690
813
|
const value = asRecord(raw.value);
|
|
691
814
|
const user = asRecord(raw.user);
|
|
@@ -699,26 +822,15 @@ function useConfigForm(form) {
|
|
|
699
822
|
cacheRef.current = { value, user, writable, available, snapshot: snapshot2 };
|
|
700
823
|
return snapshot2;
|
|
701
824
|
}, [form]);
|
|
702
|
-
const subscribe = (0,
|
|
703
|
-
const snapshot = (0,
|
|
704
|
-
const [staged, setStaged] = (0,
|
|
705
|
-
const [saving, setSaving] = (0,
|
|
706
|
-
const [failed, setFailed] = (0,
|
|
707
|
-
const [blurred, setBlurred] = (0,
|
|
708
|
-
const savingRef = (0,
|
|
709
|
-
const
|
|
710
|
-
const
|
|
711
|
-
const testRunningRef = (0, import_react2.useRef)(false);
|
|
712
|
-
(0, import_react2.useEffect)(
|
|
713
|
-
() => () => {
|
|
714
|
-
if (testTimerRef.current !== null) clearTimeout(testTimerRef.current);
|
|
715
|
-
testTimerRef.current = null;
|
|
716
|
-
testRunningRef.current = false;
|
|
717
|
-
},
|
|
718
|
-
[]
|
|
719
|
-
);
|
|
720
|
-
const plan = (0, import_react2.useMemo)(() => planWrites(snapshot, staged), [snapshot, staged]);
|
|
721
|
-
const pairsInvalid = (0, import_react2.useMemo)(
|
|
825
|
+
const subscribe = (0, import_react3.useCallback)((listener) => form.subscribe(listener), [form]);
|
|
826
|
+
const snapshot = (0, import_react3.useSyncExternalStore)(subscribe, readSnapshot);
|
|
827
|
+
const [staged, setStaged] = (0, import_react3.useState)(() => /* @__PURE__ */ new Map());
|
|
828
|
+
const [saving, setSaving] = (0, import_react3.useState)(false);
|
|
829
|
+
const [failed, setFailed] = (0, import_react3.useState)(false);
|
|
830
|
+
const [blurred, setBlurred] = (0, import_react3.useState)(() => /* @__PURE__ */ new Set());
|
|
831
|
+
const savingRef = (0, import_react3.useRef)(false);
|
|
832
|
+
const plan = (0, import_react3.useMemo)(() => planWrites(snapshot, staged), [snapshot, staged]);
|
|
833
|
+
const pairsInvalid = (0, import_react3.useMemo)(
|
|
722
834
|
() => THRESHOLD_PAIRS.some(
|
|
723
835
|
(pair) => !thresholdsOk(
|
|
724
836
|
pair,
|
|
@@ -729,7 +841,7 @@ function useConfigForm(form) {
|
|
|
729
841
|
[snapshot, staged]
|
|
730
842
|
);
|
|
731
843
|
const invalid = plan.some((item) => item.write === void 0) || pairsInvalid;
|
|
732
|
-
const stage = (0,
|
|
844
|
+
const stage = (0, import_react3.useCallback)((field2, edit2) => {
|
|
733
845
|
setStaged((current) => {
|
|
734
846
|
const next = new Map(current);
|
|
735
847
|
if (edit2 === null) next.delete(field2);
|
|
@@ -737,46 +849,30 @@ function useConfigForm(form) {
|
|
|
737
849
|
return next;
|
|
738
850
|
});
|
|
739
851
|
setFailed(false);
|
|
740
|
-
if (testTimerRef.current !== null) {
|
|
741
|
-
clearTimeout(testTimerRef.current);
|
|
742
|
-
testTimerRef.current = null;
|
|
743
|
-
}
|
|
744
|
-
testRunningRef.current = false;
|
|
745
|
-
setTest(
|
|
746
|
-
(current) => current.running || current.ok !== null ? { running: false, ok: null, message: "" } : current
|
|
747
|
-
);
|
|
748
852
|
}, []);
|
|
749
|
-
const edit = (0,
|
|
853
|
+
const edit = (0, import_react3.useCallback)(
|
|
750
854
|
(field2, text) => {
|
|
751
855
|
stage(field2, { kind: "text", text });
|
|
752
856
|
},
|
|
753
857
|
[stage]
|
|
754
858
|
);
|
|
755
|
-
const setValue = (0,
|
|
859
|
+
const setValue = (0, import_react3.useCallback)(
|
|
756
860
|
(field2, value) => {
|
|
757
861
|
stage(field2, { kind: "value", value });
|
|
758
862
|
},
|
|
759
863
|
[stage]
|
|
760
864
|
);
|
|
761
|
-
const resetField = (0,
|
|
865
|
+
const resetField = (0, import_react3.useCallback)(
|
|
762
866
|
(field2) => {
|
|
763
867
|
stage(field2, { kind: "clear" });
|
|
764
868
|
},
|
|
765
869
|
[stage]
|
|
766
870
|
);
|
|
767
|
-
const discard = (0,
|
|
871
|
+
const discard = (0, import_react3.useCallback)(() => {
|
|
768
872
|
setStaged((current) => current.size === 0 ? current : /* @__PURE__ */ new Map());
|
|
769
873
|
setFailed(false);
|
|
770
|
-
if (testTimerRef.current !== null) {
|
|
771
|
-
clearTimeout(testTimerRef.current);
|
|
772
|
-
testTimerRef.current = null;
|
|
773
|
-
}
|
|
774
|
-
testRunningRef.current = false;
|
|
775
|
-
setTest(
|
|
776
|
-
(current) => current.running || current.ok !== null ? { running: false, ok: null, message: "" } : current
|
|
777
|
-
);
|
|
778
874
|
}, []);
|
|
779
|
-
const save = (0,
|
|
875
|
+
const save = (0, import_react3.useCallback)(async () => {
|
|
780
876
|
if (savingRef.current) return;
|
|
781
877
|
const writes = planWrites(readSnapshot(), staged);
|
|
782
878
|
if (writes.length === 0) return;
|
|
@@ -803,31 +899,11 @@ function useConfigForm(form) {
|
|
|
803
899
|
if (landed) setStaged(/* @__PURE__ */ new Map());
|
|
804
900
|
setFailed(!landed);
|
|
805
901
|
}, [form, readSnapshot, staged]);
|
|
806
|
-
const
|
|
807
|
-
if (testRunningRef.current) return;
|
|
808
|
-
const current = readSnapshot();
|
|
809
|
-
const draftOf = (field2) => {
|
|
810
|
-
const spec = SPEC_BY_FIELD.get(field2);
|
|
811
|
-
const edit2 = staged.get(field2);
|
|
812
|
-
if (edit2 !== void 0 && edit2.kind === "text") return edit2.text;
|
|
813
|
-
return spec !== void 0 && isTextSpec(spec) ? spec.format(current.value[field2]) : "";
|
|
814
|
-
};
|
|
815
|
-
const failure = probeFailure(draftOf("baseUrl"), draftOf("apiKey"), draftOf("apiKeyRef"));
|
|
816
|
-
testRunningRef.current = true;
|
|
817
|
-
setTest({ running: true, ok: null, message: "" });
|
|
818
|
-
testTimerRef.current = setTimeout(() => {
|
|
819
|
-
testTimerRef.current = null;
|
|
820
|
-
testRunningRef.current = false;
|
|
821
|
-
setTest(
|
|
822
|
-
failure === null ? { running: false, ok: true, message: "" } : { running: false, ok: false, message: failure }
|
|
823
|
-
);
|
|
824
|
-
}, TEST_LATENCY_MS);
|
|
825
|
-
}, [readSnapshot, staged]);
|
|
826
|
-
const field = (0, import_react2.useCallback)(
|
|
902
|
+
const field = (0, import_react3.useCallback)(
|
|
827
903
|
(name) => fieldOf(snapshot, name, staged.get(name)),
|
|
828
904
|
[snapshot, staged]
|
|
829
905
|
);
|
|
830
|
-
const thresholdPairOk = (0,
|
|
906
|
+
const thresholdPairOk = (0, import_react3.useCallback)(
|
|
831
907
|
(currency) => {
|
|
832
908
|
const pair = THRESHOLD_PAIRS.find((item) => item.currency === currency);
|
|
833
909
|
if (pair === void 0) return true;
|
|
@@ -839,10 +915,10 @@ function useConfigForm(form) {
|
|
|
839
915
|
},
|
|
840
916
|
[snapshot, staged]
|
|
841
917
|
);
|
|
842
|
-
const touch = (0,
|
|
918
|
+
const touch = (0, import_react3.useCallback)((name) => {
|
|
843
919
|
setBlurred((current) => current.has(name) ? current : new Set(current).add(name));
|
|
844
920
|
}, []);
|
|
845
|
-
const touched = (0,
|
|
921
|
+
const touched = (0, import_react3.useCallback)((name) => blurred.has(name), [blurred]);
|
|
846
922
|
return {
|
|
847
923
|
state: {
|
|
848
924
|
available: snapshot.available,
|
|
@@ -860,19 +936,25 @@ function useConfigForm(form) {
|
|
|
860
936
|
save,
|
|
861
937
|
thresholdPairOk,
|
|
862
938
|
touched,
|
|
863
|
-
touch
|
|
864
|
-
test,
|
|
865
|
-
runTest
|
|
939
|
+
touch
|
|
866
940
|
};
|
|
867
941
|
}
|
|
868
942
|
|
|
869
|
-
// src/client/settings/use-
|
|
870
|
-
var
|
|
943
|
+
// src/client/settings/use-sources.ts
|
|
944
|
+
var import_react4 = require("react");
|
|
871
945
|
|
|
872
946
|
// src/client/data.ts
|
|
873
947
|
var BALANCE_PATH = "/api/v1/balance";
|
|
874
948
|
var REFRESH_PATH = "/api/v1/balance/refresh";
|
|
875
|
-
var
|
|
949
|
+
var SOURCES_PATH = "/api/v1/sources";
|
|
950
|
+
var TEST_PATH = "/api/v1/test-connection";
|
|
951
|
+
function unknownSources() {
|
|
952
|
+
return {
|
|
953
|
+
revision: -1,
|
|
954
|
+
key: { ref: "", configured: false, source: null, masked: "", tag8: "" },
|
|
955
|
+
account: { available: false, signedIn: false, name: null, avatarUrl: null, contact: null }
|
|
956
|
+
};
|
|
957
|
+
}
|
|
876
958
|
var UNREACHABLE_CODE = "PLUGIN_UNREACHABLE";
|
|
877
959
|
function pendingView() {
|
|
878
960
|
return {
|
|
@@ -880,6 +962,8 @@ function pendingView() {
|
|
|
880
962
|
schemaVersion: 1,
|
|
881
963
|
// 占位视图没有取数路可言;处境为 checking / offline 时界面都不渲染来源标签。
|
|
882
964
|
source: "deepseek-http",
|
|
965
|
+
// 占位视图也就没有「哪一份凭据」可言;界面同样不渲染标签。
|
|
966
|
+
sourceIdentity: null,
|
|
883
967
|
situation: "checking",
|
|
884
968
|
state: "empty",
|
|
885
969
|
stale: false,
|
|
@@ -924,23 +1008,6 @@ async function requestBalance(options) {
|
|
|
924
1008
|
});
|
|
925
1009
|
return await readJson(response, BALANCE_PATH);
|
|
926
1010
|
}
|
|
927
|
-
function readCredential(value) {
|
|
928
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
|
|
929
|
-
const record = value;
|
|
930
|
-
if (typeof record.ref !== "string" || record.ref === "") return null;
|
|
931
|
-
return {
|
|
932
|
-
ref: record.ref,
|
|
933
|
-
configured: record.configured === true,
|
|
934
|
-
source: typeof record.source === "string" ? record.source : null,
|
|
935
|
-
writable: record.writable === true
|
|
936
|
-
};
|
|
937
|
-
}
|
|
938
|
-
async function requestConfig(options = {}) {
|
|
939
|
-
const fetchImpl = options.fetchImpl ?? ((input, init) => fetch(input, init));
|
|
940
|
-
const response = await fetchImpl(CONFIG_PATH, { headers: { accept: "application/json" } });
|
|
941
|
-
const body = await readJson(response, CONFIG_PATH);
|
|
942
|
-
return { ...body, credential: readCredential(body?.credential) };
|
|
943
|
-
}
|
|
944
1011
|
async function requestRefresh(options = {}) {
|
|
945
1012
|
const fetchImpl = options.fetchImpl ?? ((input, init) => fetch(input, init));
|
|
946
1013
|
const response = await fetchImpl(REFRESH_PATH, {
|
|
@@ -953,27 +1020,122 @@ async function requestRefresh(options = {}) {
|
|
|
953
1020
|
});
|
|
954
1021
|
return await readJson(response, REFRESH_PATH);
|
|
955
1022
|
}
|
|
1023
|
+
function stringOrNull(value) {
|
|
1024
|
+
return typeof value === "string" && value !== "" ? value : null;
|
|
1025
|
+
}
|
|
1026
|
+
function readKeySource(value) {
|
|
1027
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
1028
|
+
return unknownSources().key;
|
|
1029
|
+
}
|
|
1030
|
+
const record = value;
|
|
1031
|
+
return {
|
|
1032
|
+
ref: typeof record.ref === "string" ? record.ref : "",
|
|
1033
|
+
configured: record.configured === true,
|
|
1034
|
+
source: stringOrNull(record.source),
|
|
1035
|
+
masked: typeof record.masked === "string" ? record.masked : "",
|
|
1036
|
+
tag8: typeof record.tag8 === "string" ? record.tag8 : ""
|
|
1037
|
+
};
|
|
1038
|
+
}
|
|
1039
|
+
function readAccountSource(value) {
|
|
1040
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
1041
|
+
return unknownSources().account;
|
|
1042
|
+
}
|
|
1043
|
+
const record = value;
|
|
1044
|
+
return {
|
|
1045
|
+
available: record.available === true,
|
|
1046
|
+
signedIn: record.signedIn === true,
|
|
1047
|
+
name: stringOrNull(record.name),
|
|
1048
|
+
avatarUrl: stringOrNull(record.avatarUrl),
|
|
1049
|
+
contact: stringOrNull(record.contact)
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1052
|
+
async function requestSources(options = {}) {
|
|
1053
|
+
const fetchImpl = options.fetchImpl ?? ((input, init) => fetch(input, init));
|
|
1054
|
+
const url = options.refresh === true ? `${SOURCES_PATH}?refresh=1` : SOURCES_PATH;
|
|
1055
|
+
const response = await fetchImpl(url, { headers: { accept: "application/json" } });
|
|
1056
|
+
const body = await readJson(response, SOURCES_PATH);
|
|
1057
|
+
return {
|
|
1058
|
+
revision: typeof body?.revision === "number" ? body.revision : -1,
|
|
1059
|
+
key: readKeySource(body?.key),
|
|
1060
|
+
account: readAccountSource(body?.account)
|
|
1061
|
+
};
|
|
1062
|
+
}
|
|
1063
|
+
async function requestTest(source, options = {}) {
|
|
1064
|
+
const fetchImpl = options.fetchImpl ?? ((input, init) => fetch(input, init));
|
|
1065
|
+
const response = await fetchImpl(TEST_PATH, {
|
|
1066
|
+
method: "POST",
|
|
1067
|
+
headers: { "content-type": "application/json", accept: "application/json" },
|
|
1068
|
+
body: JSON.stringify({ source })
|
|
1069
|
+
});
|
|
1070
|
+
const body = await readJson(response, TEST_PATH);
|
|
1071
|
+
return { ...body, source };
|
|
1072
|
+
}
|
|
956
1073
|
|
|
957
|
-
// src/client/settings/use-
|
|
958
|
-
function
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
const [state, setState] = (0, import_react3.useState)(null);
|
|
965
|
-
(0, import_react3.useEffect)(() => {
|
|
966
|
-
let cancelled = false;
|
|
967
|
-
void requestConfig().then((body) => {
|
|
968
|
-
if (!cancelled) setState(body?.credential ?? null);
|
|
969
|
-
}).catch(() => {
|
|
970
|
-
if (!cancelled) setState(null);
|
|
971
|
-
});
|
|
1074
|
+
// src/client/settings/use-sources.ts
|
|
1075
|
+
function useSources(enabled) {
|
|
1076
|
+
const [sources, setSources] = (0, import_react4.useState)(unknownSources);
|
|
1077
|
+
const [loading, setLoading] = (0, import_react4.useState)(false);
|
|
1078
|
+
const aliveRef = (0, import_react4.useRef)(true);
|
|
1079
|
+
(0, import_react4.useEffect)(() => {
|
|
1080
|
+
aliveRef.current = true;
|
|
972
1081
|
return () => {
|
|
973
|
-
|
|
1082
|
+
aliveRef.current = false;
|
|
974
1083
|
};
|
|
975
|
-
}, [
|
|
976
|
-
|
|
1084
|
+
}, []);
|
|
1085
|
+
const load = (0, import_react4.useCallback)(async (force) => {
|
|
1086
|
+
setLoading(true);
|
|
1087
|
+
try {
|
|
1088
|
+
const next = await requestSources(force ? { refresh: true } : {});
|
|
1089
|
+
if (aliveRef.current) setSources(next);
|
|
1090
|
+
} catch {
|
|
1091
|
+
} finally {
|
|
1092
|
+
if (aliveRef.current) setLoading(false);
|
|
1093
|
+
}
|
|
1094
|
+
}, []);
|
|
1095
|
+
(0, import_react4.useEffect)(() => {
|
|
1096
|
+
if (!enabled) return;
|
|
1097
|
+
void load(false);
|
|
1098
|
+
}, [enabled, load]);
|
|
1099
|
+
(0, import_react4.useEffect)(() => {
|
|
1100
|
+
if (!enabled) return;
|
|
1101
|
+
const onFocus = () => {
|
|
1102
|
+
void load(true);
|
|
1103
|
+
};
|
|
1104
|
+
window.addEventListener("focus", onFocus);
|
|
1105
|
+
return () => {
|
|
1106
|
+
window.removeEventListener("focus", onFocus);
|
|
1107
|
+
};
|
|
1108
|
+
}, [enabled, load]);
|
|
1109
|
+
const refresh = (0, import_react4.useCallback)(async () => {
|
|
1110
|
+
await load(true);
|
|
1111
|
+
}, [load]);
|
|
1112
|
+
return { sources, loading, refresh };
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
// src/client/settings/source-status.ts
|
|
1116
|
+
function keyStatusOf(key, t) {
|
|
1117
|
+
if (!key.configured) return { tone: "missing", identity: "", detail: "" };
|
|
1118
|
+
return {
|
|
1119
|
+
tone: "ok",
|
|
1120
|
+
identity: key.masked,
|
|
1121
|
+
detail: sourceLabelOf(key, t)
|
|
1122
|
+
};
|
|
1123
|
+
}
|
|
1124
|
+
function sourceLabelOf(key, t) {
|
|
1125
|
+
if (key.source === "file") return t("settings.sources.sourceSaved");
|
|
1126
|
+
if (key.source === null) return t("settings.sources.sourceUnknown");
|
|
1127
|
+
return t("settings.sources.sourceEnv").replace("{name}", () => key.ref);
|
|
1128
|
+
}
|
|
1129
|
+
function accountStatusOf(account, t) {
|
|
1130
|
+
if (!account.available) {
|
|
1131
|
+
return { tone: "missing", identity: "", detail: t("settings.sources.accountNoService") };
|
|
1132
|
+
}
|
|
1133
|
+
if (!account.signedIn) return { tone: "missing", identity: "", detail: "" };
|
|
1134
|
+
return {
|
|
1135
|
+
tone: "ok",
|
|
1136
|
+
identity: account.name ?? "",
|
|
1137
|
+
detail: account.contact ?? ""
|
|
1138
|
+
};
|
|
977
1139
|
}
|
|
978
1140
|
|
|
979
1141
|
// src/client/settings/BalanceSettingsCard.module.css
|
|
@@ -981,38 +1143,27 @@ var BalanceSettingsCard_default = {
|
|
|
981
1143
|
form: "BalanceSettingsCard_form",
|
|
982
1144
|
readOnly: "BalanceSettingsCard_readOnly",
|
|
983
1145
|
footer: "BalanceSettingsCard_footer",
|
|
1146
|
+
save: "BalanceSettingsCard_save",
|
|
984
1147
|
failed: "BalanceSettingsCard_failed",
|
|
985
1148
|
notice: "BalanceSettingsCard_notice"
|
|
986
1149
|
};
|
|
987
1150
|
|
|
988
1151
|
// src/client/settings/BalanceSettingsCard.tsx
|
|
989
|
-
var
|
|
990
|
-
var
|
|
991
|
-
var CREDENTIAL_BADGE = {
|
|
992
|
-
// 官方那张卡右上角只有一句话:「已配置密钥。」——继承来的、自己填的、环境提供的都算配置好了。
|
|
993
|
-
// 四档判据留着,是因为「覆盖 / 未覆盖」决定二级折叠里那两个字段的状态;徽章本身不区分它们。
|
|
994
|
-
env: "settings.credential.configured",
|
|
995
|
-
configured: "settings.credential.configured",
|
|
996
|
-
notConfigured: "settings.credential.notConfigured",
|
|
997
|
-
overridden: "settings.credential.configured"
|
|
998
|
-
};
|
|
1152
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
1153
|
+
var RESULT_TTL_MS = 4e3;
|
|
999
1154
|
var DEFAULT_GROUP_OPEN = {
|
|
1000
|
-
connection:
|
|
1155
|
+
connection: true,
|
|
1001
1156
|
display: false,
|
|
1002
1157
|
thresholds: false,
|
|
1003
1158
|
refresh: false
|
|
1004
1159
|
};
|
|
1005
1160
|
var GROUP_FIELDS = {
|
|
1006
|
-
connection: [
|
|
1161
|
+
connection: [],
|
|
1007
1162
|
display: ["displayCurrency"],
|
|
1008
1163
|
thresholds: ["cnyWarn", "cnyCritical", "usdWarn", "usdCritical"],
|
|
1009
1164
|
refresh: ["serverRefreshSeconds", "clientPollSeconds", "manualRefreshCooldownSeconds"]
|
|
1010
1165
|
};
|
|
1011
1166
|
var FIELD_IDS = {
|
|
1012
|
-
apiKey: "ds-balance-api-key",
|
|
1013
|
-
apiKeyRef: "ds-balance-api-key-ref",
|
|
1014
|
-
apiKeyState: "ds-balance-api-key-state",
|
|
1015
|
-
baseUrl: "ds-balance-base-url",
|
|
1016
1167
|
serverRefreshSeconds: "ds-balance-server-refresh-seconds",
|
|
1017
1168
|
clientPollSeconds: "ds-balance-client-poll-seconds",
|
|
1018
1169
|
manualRefreshCooldownSeconds: "ds-balance-manual-refresh-cooldown-seconds",
|
|
@@ -1022,63 +1173,30 @@ var FIELD_IDS = {
|
|
|
1022
1173
|
usdWarn: "ds-balance-usd-warn",
|
|
1023
1174
|
usdCritical: "ds-balance-usd-critical"
|
|
1024
1175
|
};
|
|
1025
|
-
function isFilled(value) {
|
|
1026
|
-
if (value === void 0 || value === null) return false;
|
|
1027
|
-
return typeof value !== "string" || value.trim() !== "";
|
|
1028
|
-
}
|
|
1029
1176
|
function BalanceSettingsCard({ t, form: scopedForm }) {
|
|
1030
1177
|
const form = useConfigForm(scopedForm);
|
|
1031
|
-
const [groupOpen, setGroupOpen] = (0,
|
|
1178
|
+
const [groupOpen, setGroupOpen] = (0, import_react5.useState)(DEFAULT_GROUP_OPEN);
|
|
1179
|
+
const { available, writable, dirty, invalid, saving, failed } = form.state;
|
|
1180
|
+
const disabled = !writable || saving;
|
|
1181
|
+
const { sources, loading, refresh } = useSources(available);
|
|
1182
|
+
const [testing, setTesting] = (0, import_react5.useState)(false);
|
|
1183
|
+
const [outcomes, setOutcomes] = (0, import_react5.useState)(null);
|
|
1184
|
+
const outcomeTimer = (0, import_react5.useRef)(null);
|
|
1185
|
+
(0, import_react5.useEffect)(
|
|
1186
|
+
() => () => {
|
|
1187
|
+
if (outcomeTimer.current !== null) clearTimeout(outcomeTimer.current);
|
|
1188
|
+
outcomeTimer.current = null;
|
|
1189
|
+
},
|
|
1190
|
+
[]
|
|
1191
|
+
);
|
|
1032
1192
|
const toggleGroup = (key) => {
|
|
1033
1193
|
setGroupOpen((current) => ({ ...current, [key]: !current[key] }));
|
|
1034
1194
|
};
|
|
1035
1195
|
const groupOpenNow = (key) => groupOpen[key] || GROUP_FIELDS[key].some((name) => form.field(name).invalid) || // 成对校验不是字段级 invalid,得单独问一次:否则收起的阈值组会挡住「保存为什么是灰的」。
|
|
1036
1196
|
key === "thresholds" && THRESHOLD_PAIRS.some((pair) => !form.thresholdPairOk(pair.currency));
|
|
1037
|
-
const { available, writable, dirty, invalid, saving, failed } = form.state;
|
|
1038
|
-
const disabled = !writable || saving;
|
|
1039
|
-
const credentialStatus = (name) => {
|
|
1040
|
-
const state = form.field(name);
|
|
1041
|
-
if (state.stored) return { label: t("settings.overridden"), tone: "neutral" };
|
|
1042
|
-
if (isFilled(state.effective)) return { label: t("settings.configured"), tone: "neutral" };
|
|
1043
|
-
return { label: t("settings.notConfigured"), tone: "quiet" };
|
|
1044
|
-
};
|
|
1045
|
-
const textRow = (name, labelKey, hintKey, withStatus) => {
|
|
1046
|
-
const state = form.field(name);
|
|
1047
|
-
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1048
|
-
FieldFrame,
|
|
1049
|
-
{
|
|
1050
|
-
id: FIELD_IDS[name] ?? name,
|
|
1051
|
-
label: t(labelKey),
|
|
1052
|
-
status: withStatus ? credentialStatus(name) : null,
|
|
1053
|
-
pending: state.dirty,
|
|
1054
|
-
resettable: state.overridden || state.dirty,
|
|
1055
|
-
pendingLabel: t("settings.unsaved"),
|
|
1056
|
-
resetLabel: t("settings.reset"),
|
|
1057
|
-
invalid: state.invalid,
|
|
1058
|
-
hint: t(hintKey),
|
|
1059
|
-
disabled,
|
|
1060
|
-
onReset: () => {
|
|
1061
|
-
form.resetField(name);
|
|
1062
|
-
},
|
|
1063
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1064
|
-
TextControl,
|
|
1065
|
-
{
|
|
1066
|
-
id: FIELD_IDS[name] ?? name,
|
|
1067
|
-
text: state.text,
|
|
1068
|
-
numeric: false,
|
|
1069
|
-
invalid: state.invalid,
|
|
1070
|
-
disabled,
|
|
1071
|
-
onEdit: (text) => {
|
|
1072
|
-
form.edit(name, text);
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1075
|
-
)
|
|
1076
|
-
}
|
|
1077
|
-
);
|
|
1078
|
-
};
|
|
1079
1197
|
const numberRow = (name, labelKey, hintKey, note) => {
|
|
1080
1198
|
const state = form.field(name);
|
|
1081
|
-
return /* @__PURE__ */ (0,
|
|
1199
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1082
1200
|
FieldFrame,
|
|
1083
1201
|
{
|
|
1084
1202
|
id: FIELD_IDS[name] ?? name,
|
|
@@ -1095,7 +1213,7 @@ function BalanceSettingsCard({ t, form: scopedForm }) {
|
|
|
1095
1213
|
form.resetField(name);
|
|
1096
1214
|
},
|
|
1097
1215
|
children: [
|
|
1098
|
-
/* @__PURE__ */ (0,
|
|
1216
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1099
1217
|
TextControl,
|
|
1100
1218
|
{
|
|
1101
1219
|
id: FIELD_IDS[name] ?? name,
|
|
@@ -1121,40 +1239,20 @@ function BalanceSettingsCard({ t, form: scopedForm }) {
|
|
|
1121
1239
|
if (pair === void 0 || form.thresholdPairOk(currency2)) return null;
|
|
1122
1240
|
const drafting = form.field(pair.warn).dirty || form.field(pair.critical).dirty;
|
|
1123
1241
|
if (drafting && !form.touched(pair.warn) && !form.touched(pair.critical)) return null;
|
|
1124
|
-
return /* @__PURE__ */ (0,
|
|
1242
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: fields_default.pairNote, role: "alert", children: t("settings.hint.thresholdPair") });
|
|
1125
1243
|
};
|
|
1126
|
-
const apiKey = form.field("apiKey");
|
|
1127
|
-
const apiKeyRef = form.field("apiKeyRef");
|
|
1128
|
-
const effectiveRef = typeof apiKeyRef.effective === "string" && apiKeyRef.effective !== "" ? apiKeyRef.effective : DEFAULT_API_KEY_REF;
|
|
1129
|
-
const credential = useCredentialState(effectiveRef);
|
|
1130
|
-
const credentialView = credentialViewOf(credential, apiKey.stored || apiKeyRef.stored);
|
|
1131
1244
|
const currency = form.field("displayCurrency");
|
|
1132
1245
|
const currencyId = typeof currency.value === "string" && currency.value !== "" ? currency.value : AUTO_CURRENCY;
|
|
1133
1246
|
const currencyOptions = [
|
|
1134
1247
|
{ id: AUTO_CURRENCY, label: t("settings.currency.auto") },
|
|
1135
1248
|
...currencyCodes(currency.value, currency.effective).map((code) => ({ id: code, label: code }))
|
|
1136
1249
|
];
|
|
1137
|
-
const currencyRow = /* @__PURE__ */ (0,
|
|
1138
|
-
/* @__PURE__ */ (0,
|
|
1139
|
-
/* @__PURE__ */ (0,
|
|
1140
|
-
|
|
1141
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1142
|
-
FieldBadges,
|
|
1143
|
-
{
|
|
1144
|
-
pending: currency.dirty,
|
|
1145
|
-
resettable: currency.dirty,
|
|
1146
|
-
pendingLabel: t("settings.unsaved"),
|
|
1147
|
-
resetLabel: t("settings.reset"),
|
|
1148
|
-
disabled,
|
|
1149
|
-
onReset: () => {
|
|
1150
|
-
form.resetField("displayCurrency");
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
1153
|
-
)
|
|
1154
|
-
] }),
|
|
1155
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: fields_default.hint, children: t("settings.hint.displayCurrency") })
|
|
1250
|
+
const currencyRow = /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: fields_default.row, children: [
|
|
1251
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: fields_default.rowText, children: [
|
|
1252
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: fields_default.rowTitleLine, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: fields_default.rowTitle, children: t("settings.field.displayCurrency") }) }),
|
|
1253
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: fields_default.hint, children: t("settings.hint.displayCurrency") })
|
|
1156
1254
|
] }),
|
|
1157
|
-
/* @__PURE__ */ (0,
|
|
1255
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1158
1256
|
SelectorControl,
|
|
1159
1257
|
{
|
|
1160
1258
|
id: FIELD_IDS.displayCurrency ?? "displayCurrency",
|
|
@@ -1168,62 +1266,113 @@ function BalanceSettingsCard({ t, form: scopedForm }) {
|
|
|
1168
1266
|
}
|
|
1169
1267
|
)
|
|
1170
1268
|
] });
|
|
1171
|
-
const
|
|
1269
|
+
const runTest = () => {
|
|
1270
|
+
if (testing) return;
|
|
1271
|
+
setTesting(true);
|
|
1272
|
+
setOutcomes(null);
|
|
1273
|
+
if (outcomeTimer.current !== null) clearTimeout(outcomeTimer.current);
|
|
1274
|
+
void (async () => {
|
|
1275
|
+
const [keyResult, accountResult] = await Promise.all([
|
|
1276
|
+
runOne("deepseek-http"),
|
|
1277
|
+
runOne("deepseek-account")
|
|
1278
|
+
]);
|
|
1279
|
+
setOutcomes(
|
|
1280
|
+
/* @__PURE__ */ new Map([
|
|
1281
|
+
["key", keyResult],
|
|
1282
|
+
["account", accountResult]
|
|
1283
|
+
])
|
|
1284
|
+
);
|
|
1285
|
+
setTesting(false);
|
|
1286
|
+
outcomeTimer.current = setTimeout(() => {
|
|
1287
|
+
outcomeTimer.current = null;
|
|
1288
|
+
setOutcomes(null);
|
|
1289
|
+
}, RESULT_TTL_MS);
|
|
1290
|
+
await refresh();
|
|
1291
|
+
})();
|
|
1292
|
+
};
|
|
1293
|
+
const runOne = async (source) => {
|
|
1294
|
+
try {
|
|
1295
|
+
const result = await requestTest(source);
|
|
1296
|
+
if (result.ok) {
|
|
1297
|
+
return {
|
|
1298
|
+
ok: true,
|
|
1299
|
+
text: t("settings.test.ok").replace("{ms}", () => String(result.latencyMs))
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
if (result.code === "NO_KEY") {
|
|
1303
|
+
return {
|
|
1304
|
+
ok: false,
|
|
1305
|
+
text: source === "deepseek-account" ? t("settings.test.notSignedIn") : t("settings.test.noKey")
|
|
1306
|
+
};
|
|
1307
|
+
}
|
|
1308
|
+
return {
|
|
1309
|
+
ok: false,
|
|
1310
|
+
text: interpolate(t("settings.test.fail"), {
|
|
1311
|
+
message: result.message ?? result.code ?? ""
|
|
1312
|
+
})
|
|
1313
|
+
};
|
|
1314
|
+
} catch {
|
|
1315
|
+
return { ok: false, text: interpolate(t("settings.test.fail"), { message: "unreachable" }) };
|
|
1316
|
+
}
|
|
1317
|
+
};
|
|
1318
|
+
const liveOf = (row) => {
|
|
1319
|
+
if (testing) return { kind: "busy" };
|
|
1320
|
+
const outcome = outcomes?.get(row);
|
|
1321
|
+
if (outcome === void 0) return null;
|
|
1322
|
+
return { kind: "result", ok: outcome.ok, text: outcome.text };
|
|
1323
|
+
};
|
|
1172
1324
|
const footerNote = failed ? { text: t("settings.failed"), className: BalanceSettingsCard_default.failed } : invalid ? { text: t("settings.invalid"), className: BalanceSettingsCard_default.notice } : null;
|
|
1173
1325
|
if (!available) return null;
|
|
1326
|
+
const keyStatus = keyStatusOf(sources.key, t);
|
|
1327
|
+
const accountStatus = accountStatusOf(sources.account, t);
|
|
1174
1328
|
return (
|
|
1175
1329
|
// 页面把这一格渲染在自己的 <section> 里:无外框的一列控件,所以根节点是 div、不是 li。
|
|
1176
|
-
/* @__PURE__ */ (0,
|
|
1177
|
-
writable ? null : /* @__PURE__ */ (0,
|
|
1178
|
-
/* @__PURE__ */ (0,
|
|
1330
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: BalanceSettingsCard_default.form, children: [
|
|
1331
|
+
writable ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: BalanceSettingsCard_default.readOnly, role: "status", children: t("settings.readOnly") }),
|
|
1332
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1179
1333
|
FieldGroup,
|
|
1180
1334
|
{
|
|
1181
|
-
icon: /* @__PURE__ */ (0,
|
|
1335
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(GROUP_ICONS.connection, { size: 14 }),
|
|
1182
1336
|
title: t("settings.group.connection"),
|
|
1337
|
+
note: t("settings.sources.groupNote"),
|
|
1183
1338
|
open: groupOpenNow("connection"),
|
|
1184
1339
|
onToggle: () => {
|
|
1185
1340
|
toggleGroup("connection");
|
|
1186
1341
|
},
|
|
1187
|
-
children: [
|
|
1188
|
-
/* @__PURE__ */ (0,
|
|
1189
|
-
|
|
1342
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: fields_default.fields, children: [
|
|
1343
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1344
|
+
SourceRow,
|
|
1345
|
+
{
|
|
1346
|
+
label: t("settings.sources.key"),
|
|
1347
|
+
status: keyStatus,
|
|
1348
|
+
live: liveOf("key"),
|
|
1349
|
+
monoIdentity: true
|
|
1350
|
+
}
|
|
1351
|
+
),
|
|
1352
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1353
|
+
SourceRow,
|
|
1190
1354
|
{
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
tone: credentialView === "notConfigured" ? "quiet" : "neutral"
|
|
1196
|
-
},
|
|
1197
|
-
pending: false,
|
|
1198
|
-
resettable: false,
|
|
1199
|
-
pendingLabel: t("settings.unsaved"),
|
|
1200
|
-
resetLabel: t("settings.reset"),
|
|
1201
|
-
invalid: false,
|
|
1202
|
-
hint: t("settings.hint.credential"),
|
|
1203
|
-
disabled: true,
|
|
1204
|
-
onReset: () => {
|
|
1205
|
-
},
|
|
1206
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ReadOnlyControl, { id: FIELD_IDS.apiKeyState ?? "apiKeyState" })
|
|
1355
|
+
label: t("settings.sources.account"),
|
|
1356
|
+
status: accountStatus,
|
|
1357
|
+
live: liveOf("account"),
|
|
1358
|
+
...sources.account.signedIn ? { leading: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AccountAvatar, { url: sources.account.avatarUrl }) } : {}
|
|
1207
1359
|
}
|
|
1208
1360
|
),
|
|
1209
|
-
|
|
1210
|
-
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: fields_default.field, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1361
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: fields_default.field, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1211
1362
|
ActionRow,
|
|
1212
1363
|
{
|
|
1213
|
-
label:
|
|
1214
|
-
disabled: disabled ||
|
|
1215
|
-
|
|
1216
|
-
onClick: form.runTest
|
|
1364
|
+
label: testing ? t("settings.testing") : t("settings.test"),
|
|
1365
|
+
disabled: disabled || testing || loading,
|
|
1366
|
+
onClick: runTest
|
|
1217
1367
|
}
|
|
1218
|
-
) }
|
|
1219
|
-
|
|
1220
|
-
]
|
|
1368
|
+
) })
|
|
1369
|
+
] })
|
|
1221
1370
|
}
|
|
1222
1371
|
),
|
|
1223
|
-
/* @__PURE__ */ (0,
|
|
1372
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1224
1373
|
FieldGroup,
|
|
1225
1374
|
{
|
|
1226
|
-
icon: /* @__PURE__ */ (0,
|
|
1375
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(GROUP_ICONS.display, { size: 14 }),
|
|
1227
1376
|
title: t("settings.group.display"),
|
|
1228
1377
|
open: groupOpenNow("display"),
|
|
1229
1378
|
onToggle: () => {
|
|
@@ -1232,10 +1381,10 @@ function BalanceSettingsCard({ t, form: scopedForm }) {
|
|
|
1232
1381
|
children: currencyRow
|
|
1233
1382
|
}
|
|
1234
1383
|
),
|
|
1235
|
-
/* @__PURE__ */ (0,
|
|
1384
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1236
1385
|
FieldGroup,
|
|
1237
1386
|
{
|
|
1238
|
-
icon: /* @__PURE__ */ (0,
|
|
1387
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(GROUP_ICONS.thresholds, { size: 14 }),
|
|
1239
1388
|
title: t("settings.group.thresholds"),
|
|
1240
1389
|
note: t("settings.hint.threshold"),
|
|
1241
1390
|
open: groupOpenNow("thresholds"),
|
|
@@ -1250,10 +1399,10 @@ function BalanceSettingsCard({ t, form: scopedForm }) {
|
|
|
1250
1399
|
]
|
|
1251
1400
|
}
|
|
1252
1401
|
),
|
|
1253
|
-
/* @__PURE__ */ (0,
|
|
1402
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
1254
1403
|
FieldGroup,
|
|
1255
1404
|
{
|
|
1256
|
-
icon: /* @__PURE__ */ (0,
|
|
1405
|
+
icon: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(GROUP_ICONS.refresh, { size: 14 }),
|
|
1257
1406
|
title: t("settings.group.refresh"),
|
|
1258
1407
|
note: t("settings.hint.refreshAdvanced"),
|
|
1259
1408
|
open: groupOpenNow("refresh"),
|
|
@@ -1280,13 +1429,13 @@ function BalanceSettingsCard({ t, form: scopedForm }) {
|
|
|
1280
1429
|
]
|
|
1281
1430
|
}
|
|
1282
1431
|
),
|
|
1283
|
-
/* @__PURE__ */ (0,
|
|
1284
|
-
footerNote === null ? null : /* @__PURE__ */ (0,
|
|
1285
|
-
/* @__PURE__ */ (0,
|
|
1286
|
-
|
|
1432
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: BalanceSettingsCard_default.footer, children: [
|
|
1433
|
+
footerNote === null ? null : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: footerNote.className, role: "status", children: footerNote.text }),
|
|
1434
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
1435
|
+
"button",
|
|
1287
1436
|
{
|
|
1288
1437
|
type: "button",
|
|
1289
|
-
|
|
1438
|
+
className: BalanceSettingsCard_default.save,
|
|
1290
1439
|
disabled: !dirty || invalid || saving || !writable,
|
|
1291
1440
|
onClick: () => {
|
|
1292
1441
|
void form.save();
|
|
@@ -1300,9 +1449,9 @@ function BalanceSettingsCard({ t, form: scopedForm }) {
|
|
|
1300
1449
|
}
|
|
1301
1450
|
|
|
1302
1451
|
// src/client/sidebar/SidebarBalance.tsx
|
|
1303
|
-
var
|
|
1452
|
+
var import_react6 = require("react");
|
|
1304
1453
|
var import_react_dom = require("react-dom");
|
|
1305
|
-
var
|
|
1454
|
+
var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
1306
1455
|
|
|
1307
1456
|
// src/client/model.ts
|
|
1308
1457
|
function dotStateOf(severity) {
|
|
@@ -1404,6 +1553,12 @@ function sourceLabelKeyOf(source) {
|
|
|
1404
1553
|
if (source === "deepseek-account") return "popover.source.account";
|
|
1405
1554
|
return null;
|
|
1406
1555
|
}
|
|
1556
|
+
function sourceIdentityOf(response) {
|
|
1557
|
+
const value = response.sourceIdentity;
|
|
1558
|
+
if (typeof value !== "string") return null;
|
|
1559
|
+
const trimmed = value.trim();
|
|
1560
|
+
return trimmed === "" ? null : trimmed;
|
|
1561
|
+
}
|
|
1407
1562
|
function cooldownUntilOf(now, configuredSeconds, rejectedRemainingMs) {
|
|
1408
1563
|
const span = rejectedRemainingMs === null ? Math.max(0, configuredSeconds) * MS_PER_SECOND : Math.max(0, rejectedRemainingMs);
|
|
1409
1564
|
return now + span;
|
|
@@ -1572,6 +1727,8 @@ function make(patch) {
|
|
|
1572
1727
|
requestId: "req_mock",
|
|
1573
1728
|
schemaVersion: 1,
|
|
1574
1729
|
source: "deepseek-http",
|
|
1730
|
+
// 与后端同形:Key 那条路回首页片段掩码,账号那条路回账号名(下面 account 场景覆写)。
|
|
1731
|
+
sourceIdentity: "sk-c08d*****3b84",
|
|
1575
1732
|
situation: "ok",
|
|
1576
1733
|
state: "ok",
|
|
1577
1734
|
stale: false,
|
|
@@ -1592,7 +1749,7 @@ var scenarios = {
|
|
|
1592
1749
|
/** 正常。 */
|
|
1593
1750
|
ok: make({}),
|
|
1594
1751
|
/** 正常,但数字来自账号登录那条路(用来眼看「来源标签」)。 */
|
|
1595
|
-
account: make({ source: "deepseek-account" }),
|
|
1752
|
+
account: make({ source: "deepseek-account", sourceIdentity: "\u5F20\u4E09" }),
|
|
1596
1753
|
/** 余额偏低但可用。 */
|
|
1597
1754
|
warn: make({
|
|
1598
1755
|
situation: "low",
|
|
@@ -1848,7 +2005,7 @@ function createConfigSlotProbe(options = {}) {
|
|
|
1848
2005
|
}
|
|
1849
2006
|
|
|
1850
2007
|
// src/client/sidebar/BalancePopover.tsx
|
|
1851
|
-
var
|
|
2008
|
+
var import_dsh_client_ui_primitives4 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
1852
2009
|
|
|
1853
2010
|
// src/client/sidebar/BalancePopover.module.css
|
|
1854
2011
|
var BalancePopover_default = {
|
|
@@ -1871,7 +2028,7 @@ var BalancePopover_default = {
|
|
|
1871
2028
|
};
|
|
1872
2029
|
|
|
1873
2030
|
// src/client/sidebar/BalancePopover.tsx
|
|
1874
|
-
var
|
|
2031
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1875
2032
|
var BALANCE_PLACEHOLDER = "--";
|
|
1876
2033
|
var AGE_UNIT = {
|
|
1877
2034
|
seconds: "second",
|
|
@@ -1927,7 +2084,7 @@ function BalancePopover(props) {
|
|
|
1927
2084
|
const pluginsLabel = t(
|
|
1928
2085
|
pluginsAction?.reachesConfig === true ? "popover.action.openPluginConfig" : "popover.action.openPlugins"
|
|
1929
2086
|
);
|
|
1930
|
-
return /* @__PURE__ */ (0,
|
|
2087
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1931
2088
|
"section",
|
|
1932
2089
|
{
|
|
1933
2090
|
ref: panelRef,
|
|
@@ -1936,9 +2093,9 @@ function BalancePopover(props) {
|
|
|
1936
2093
|
role: "dialog",
|
|
1937
2094
|
"aria-label": t("popover.title"),
|
|
1938
2095
|
children: [
|
|
1939
|
-
/* @__PURE__ */ (0,
|
|
1940
|
-
/* @__PURE__ */ (0,
|
|
1941
|
-
/* @__PURE__ */ (0,
|
|
2096
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: BalancePopover_default.title, children: [
|
|
2097
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: BalancePopover_default.titleMain, children: [
|
|
2098
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
1942
2099
|
"a",
|
|
1943
2100
|
{
|
|
1944
2101
|
className: BalancePopover_default.titleLabel,
|
|
@@ -1946,37 +2103,37 @@ function BalancePopover(props) {
|
|
|
1946
2103
|
target: "_blank",
|
|
1947
2104
|
rel: "noopener noreferrer",
|
|
1948
2105
|
children: [
|
|
1949
|
-
/* @__PURE__ */ (0,
|
|
2106
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.FishLogo, { size: 14 }),
|
|
1950
2107
|
t("popover.title")
|
|
1951
2108
|
]
|
|
1952
2109
|
}
|
|
1953
2110
|
),
|
|
1954
|
-
sourceLabel === null ? null : /* @__PURE__ */ (0,
|
|
2111
|
+
sourceLabel === null ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: BalancePopover_default.sourceLabel, title: sourceLabel, children: sourceLabel })
|
|
1955
2112
|
] }),
|
|
1956
|
-
pluginsAction === void 0 ? null : /* @__PURE__ */ (0,
|
|
2113
|
+
pluginsAction === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.Tooltip, { label: pluginsLabel, side: "top", delayMs: 500, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1957
2114
|
"button",
|
|
1958
2115
|
{
|
|
1959
2116
|
type: "button",
|
|
1960
2117
|
className: BalancePopover_default.iconButton,
|
|
1961
2118
|
"aria-label": pluginsLabel,
|
|
1962
2119
|
onClick: pluginsAction.open,
|
|
1963
|
-
children: /* @__PURE__ */ (0,
|
|
2120
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.IconPluginPinwheelOutlineRegular, { size: 16 })
|
|
1964
2121
|
}
|
|
1965
2122
|
) })
|
|
1966
2123
|
] }),
|
|
1967
|
-
/* @__PURE__ */ (0,
|
|
1968
|
-
/* @__PURE__ */ (0,
|
|
1969
|
-
/* @__PURE__ */ (0,
|
|
1970
|
-
/* @__PURE__ */ (0,
|
|
1971
|
-
/* @__PURE__ */ (0,
|
|
1972
|
-
/* @__PURE__ */ (0,
|
|
1973
|
-
/* @__PURE__ */ (0,
|
|
1974
|
-
/* @__PURE__ */ (0,
|
|
2124
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: BalancePopover_default.titleRule, "aria-hidden": true }),
|
|
2125
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dl", { className: BalancePopover_default.details, children: [
|
|
2126
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: t("popover.total") }),
|
|
2127
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: totalText }),
|
|
2128
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: t("popover.granted") }),
|
|
2129
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: grantedText }),
|
|
2130
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: t("popover.toppedUp") }),
|
|
2131
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: toppedUpText })
|
|
1975
2132
|
] }),
|
|
1976
|
-
shown !== null && !selection.matchesPreference ? /* @__PURE__ */ (0,
|
|
1977
|
-
/* @__PURE__ */ (0,
|
|
1978
|
-
/* @__PURE__ */ (0,
|
|
1979
|
-
|
|
2133
|
+
shown !== null && !selection.matchesPreference ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: BalancePopover_default.notice, children: [
|
|
2134
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: BalancePopover_default.noticeText, children: interpolate(t("popover.mismatch"), { wanted: displayCurrency, shown: shown.currency }) }),
|
|
2135
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: BalancePopover_default.noticeActions, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2136
|
+
import_dsh_client_ui_primitives4.Button,
|
|
1980
2137
|
{
|
|
1981
2138
|
size: "sm",
|
|
1982
2139
|
variant: "outline",
|
|
@@ -1986,11 +2143,11 @@ function BalancePopover(props) {
|
|
|
1986
2143
|
}
|
|
1987
2144
|
) })
|
|
1988
2145
|
] }) : null,
|
|
1989
|
-
configSlotWarning === null ? null : /* @__PURE__ */ (0,
|
|
1990
|
-
/* @__PURE__ */ (0,
|
|
1991
|
-
/* @__PURE__ */ (0,
|
|
1992
|
-
/* @__PURE__ */ (0,
|
|
1993
|
-
/* @__PURE__ */ (0,
|
|
2146
|
+
configSlotWarning === null ? null : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: BalancePopover_default.notice, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: BalancePopover_default.noticeText, children: configSlotWarning }) }),
|
|
2147
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: BalancePopover_default.footer, children: [
|
|
2148
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: BalancePopover_default.updated, children: updatedText }),
|
|
2149
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: BalancePopover_default.status, role: "status", children: statusText }),
|
|
2150
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.Tooltip, { label: refreshLabel, side: "top", delayMs: 500, disabled: refreshing || cooling, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
1994
2151
|
"button",
|
|
1995
2152
|
{
|
|
1996
2153
|
type: "button",
|
|
@@ -2000,7 +2157,7 @@ function BalancePopover(props) {
|
|
|
2000
2157
|
"data-refreshing": refreshing || void 0,
|
|
2001
2158
|
"data-cooling": cooling || void 0,
|
|
2002
2159
|
onClick: onRefresh,
|
|
2003
|
-
children: /* @__PURE__ */ (0,
|
|
2160
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives4.IconRefreshOutlineRegular, { size: 16 })
|
|
2004
2161
|
}
|
|
2005
2162
|
) })
|
|
2006
2163
|
] })
|
|
@@ -2020,7 +2177,7 @@ var PercentRing_default = {
|
|
|
2020
2177
|
};
|
|
2021
2178
|
|
|
2022
2179
|
// src/client/sidebar/PercentRing.tsx
|
|
2023
|
-
var
|
|
2180
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
2024
2181
|
var VIEW = 16;
|
|
2025
2182
|
var STROKE = 1;
|
|
2026
2183
|
var RING_INSET = 1;
|
|
@@ -2042,7 +2199,7 @@ function PercentRing({
|
|
|
2042
2199
|
title
|
|
2043
2200
|
}) {
|
|
2044
2201
|
const clamped = Number.isFinite(ratio) ? Math.min(1, Math.max(0, ratio)) : 1;
|
|
2045
|
-
return /* @__PURE__ */ (0,
|
|
2202
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2046
2203
|
"svg",
|
|
2047
2204
|
{
|
|
2048
2205
|
className: PercentRing_default.ring,
|
|
@@ -2053,9 +2210,9 @@ function PercentRing({
|
|
|
2053
2210
|
"aria-hidden": "true",
|
|
2054
2211
|
focusable: "false",
|
|
2055
2212
|
children: [
|
|
2056
|
-
title === void 0 ? null : /* @__PURE__ */ (0,
|
|
2057
|
-
/* @__PURE__ */ (0,
|
|
2058
|
-
state === "ongoing" ? /* @__PURE__ */ (0,
|
|
2213
|
+
title === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("title", { children: title }),
|
|
2214
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("circle", { className: PercentRing_default.track, cx: CENTER, cy: CENTER, r: RADIUS }),
|
|
2215
|
+
state === "ongoing" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("g", { className: PercentRing_default.spin, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2059
2216
|
"circle",
|
|
2060
2217
|
{
|
|
2061
2218
|
className: PercentRing_default.fill,
|
|
@@ -2069,7 +2226,7 @@ function PercentRing({
|
|
|
2069
2226
|
/* dash 取弧长、gap 取整周长,于是只画出一条弧;rotate 让接缝落在 12 点而不是 3 点
|
|
2070
2227
|
(中心跟着 VIEW 走,16 格时是 rotate(-90 8 8))。
|
|
2071
2228
|
比例为 0 时整条弧不画:dash 长度为 0 配上圆头线帽会在 12 点留下一个点。 */
|
|
2072
|
-
clamped === 0 ? null : /* @__PURE__ */ (0,
|
|
2229
|
+
clamped === 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2073
2230
|
"circle",
|
|
2074
2231
|
{
|
|
2075
2232
|
className: PercentRing_default.fill,
|
|
@@ -2081,8 +2238,8 @@ function PercentRing({
|
|
|
2081
2238
|
}
|
|
2082
2239
|
)
|
|
2083
2240
|
),
|
|
2084
|
-
marker === null ? null : /* @__PURE__ */ (0,
|
|
2085
|
-
/* @__PURE__ */ (0,
|
|
2241
|
+
marker === null ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("g", { className: PercentRing_default.marker, children: marker === "cross" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2242
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2086
2243
|
"line",
|
|
2087
2244
|
{
|
|
2088
2245
|
x1: CENTER - MARK_ARM,
|
|
@@ -2091,7 +2248,7 @@ function PercentRing({
|
|
|
2091
2248
|
y2: CENTER + MARK_ARM
|
|
2092
2249
|
}
|
|
2093
2250
|
),
|
|
2094
|
-
/* @__PURE__ */ (0,
|
|
2251
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2095
2252
|
"line",
|
|
2096
2253
|
{
|
|
2097
2254
|
x1: CENTER + MARK_ARM,
|
|
@@ -2100,9 +2257,9 @@ function PercentRing({
|
|
|
2100
2257
|
y2: CENTER + MARK_ARM
|
|
2101
2258
|
}
|
|
2102
2259
|
)
|
|
2103
|
-
] }) : /* @__PURE__ */ (0,
|
|
2104
|
-
/* @__PURE__ */ (0,
|
|
2105
|
-
/* @__PURE__ */ (0,
|
|
2260
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
|
|
2261
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: CENTER, y1: CENTER - MARK_ARM, x2: CENTER, y2: CENTER + MARK_ARM }),
|
|
2262
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("line", { x1: CENTER - MARK_ARM, y1: CENTER, x2: CENTER + MARK_ARM, y2: CENTER })
|
|
2106
2263
|
] }) })
|
|
2107
2264
|
]
|
|
2108
2265
|
}
|
|
@@ -2119,7 +2276,7 @@ var SidebarBalance_default = {
|
|
|
2119
2276
|
};
|
|
2120
2277
|
|
|
2121
2278
|
// src/client/sidebar/SidebarBalance.tsx
|
|
2122
|
-
var
|
|
2279
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2123
2280
|
var REFRESH_SIMULATION_MS = 600;
|
|
2124
2281
|
var PANEL_GAP = 8;
|
|
2125
2282
|
var PANEL_MARGIN = 12;
|
|
@@ -2127,8 +2284,8 @@ var MEASURE_STYLE = { visibility: "hidden", left: 0, top: 0 };
|
|
|
2127
2284
|
var MS_PER_SECOND2 = 1e3;
|
|
2128
2285
|
var TICK_MS = MS_PER_SECOND2;
|
|
2129
2286
|
function useConfigSlotState(probe) {
|
|
2130
|
-
const [state, setState] = (0,
|
|
2131
|
-
(0,
|
|
2287
|
+
const [state, setState] = (0, import_react6.useState)(() => probe.getSnapshot());
|
|
2288
|
+
(0, import_react6.useEffect)(() => {
|
|
2132
2289
|
setState(probe.getSnapshot());
|
|
2133
2290
|
return probe.subscribe(() => {
|
|
2134
2291
|
setState(probe.getSnapshot());
|
|
@@ -2137,8 +2294,8 @@ function useConfigSlotState(probe) {
|
|
|
2137
2294
|
return state;
|
|
2138
2295
|
}
|
|
2139
2296
|
function usePluginsNavigation(navigation) {
|
|
2140
|
-
const [action, setAction] = (0,
|
|
2141
|
-
(0,
|
|
2297
|
+
const [action, setAction] = (0, import_react6.useState)(() => navigation?.getSnapshot());
|
|
2298
|
+
(0, import_react6.useEffect)(() => {
|
|
2142
2299
|
if (navigation === void 0) {
|
|
2143
2300
|
setAction(void 0);
|
|
2144
2301
|
return;
|
|
@@ -2154,8 +2311,8 @@ function ringSpecFor(presentation) {
|
|
|
2154
2311
|
return { state: presentation.ring, marker: presentation.marker };
|
|
2155
2312
|
}
|
|
2156
2313
|
function useRouteProvider(hint) {
|
|
2157
|
-
const [provider, setProvider] = (0,
|
|
2158
|
-
(0,
|
|
2314
|
+
const [provider, setProvider] = (0, import_react6.useState)(() => hint?.getSnapshot());
|
|
2315
|
+
(0, import_react6.useEffect)(() => {
|
|
2159
2316
|
if (hint === void 0) {
|
|
2160
2317
|
setProvider(void 0);
|
|
2161
2318
|
return;
|
|
@@ -2176,35 +2333,35 @@ function SidebarBalance({
|
|
|
2176
2333
|
pluginsNavigation,
|
|
2177
2334
|
routeHint
|
|
2178
2335
|
}) {
|
|
2179
|
-
const [view, setView] = (0,
|
|
2336
|
+
const [view, setView] = (0, import_react6.useState)(() => {
|
|
2180
2337
|
const response2 = resolveScenario() === null ? pendingView() : currentBalance();
|
|
2181
2338
|
return { response: response2, seenAt: Date.now(), seenAgeMs: response2.ageMs };
|
|
2182
2339
|
});
|
|
2183
2340
|
const response = view.response;
|
|
2184
|
-
const [mock, setMock] = (0,
|
|
2185
|
-
const loadedRef = (0,
|
|
2186
|
-
const [open, setOpen] = (0,
|
|
2187
|
-
const [refreshing, setRefreshing] = (0,
|
|
2188
|
-
const [cooldownUntil, setCooldownUntil] = (0,
|
|
2189
|
-
const [now, setNow] = (0,
|
|
2341
|
+
const [mock, setMock] = (0, import_react6.useState)(() => resolveScenario() !== null);
|
|
2342
|
+
const loadedRef = (0, import_react6.useRef)(false);
|
|
2343
|
+
const [open, setOpen] = (0, import_react6.useState)(false);
|
|
2344
|
+
const [refreshing, setRefreshing] = (0, import_react6.useState)(false);
|
|
2345
|
+
const [cooldownUntil, setCooldownUntil] = (0, import_react6.useState)(0);
|
|
2346
|
+
const [now, setNow] = (0, import_react6.useState)(() => Date.now());
|
|
2190
2347
|
const provider = useRouteProvider(routeHint);
|
|
2191
|
-
const rootRef = (0,
|
|
2192
|
-
const panelRef = (0,
|
|
2193
|
-
const refreshTimer = (0,
|
|
2194
|
-
const lastScenario = (0,
|
|
2195
|
-
const acceptBalance = (0,
|
|
2348
|
+
const rootRef = (0, import_react6.useRef)(null);
|
|
2349
|
+
const panelRef = (0, import_react6.useRef)(null);
|
|
2350
|
+
const refreshTimer = (0, import_react6.useRef)(void 0);
|
|
2351
|
+
const lastScenario = (0, import_react6.useRef)(null);
|
|
2352
|
+
const acceptBalance = (0, import_react6.useCallback)((next) => {
|
|
2196
2353
|
setView({ response: next, seenAt: Date.now(), seenAgeMs: next.ageMs });
|
|
2197
2354
|
}, []);
|
|
2198
|
-
const showUnreachable = (0,
|
|
2355
|
+
const showUnreachable = (0, import_react6.useCallback)((error) => {
|
|
2199
2356
|
const message = error instanceof Error ? error.message : String(error);
|
|
2200
2357
|
setView((current) => ({ ...current, response: unreachableView(message) }));
|
|
2201
2358
|
}, []);
|
|
2202
|
-
const markFresh = (0,
|
|
2359
|
+
const markFresh = (0, import_react6.useCallback)(() => {
|
|
2203
2360
|
setView((current) => ({ ...current, seenAt: Date.now(), seenAgeMs: 0 }));
|
|
2204
2361
|
}, []);
|
|
2205
2362
|
const preference = config.displayCurrency;
|
|
2206
|
-
const selection = (0,
|
|
2207
|
-
(0,
|
|
2363
|
+
const selection = (0, import_react6.useMemo)(() => selectionOf(response, preference), [response, preference]);
|
|
2364
|
+
(0, import_react6.useEffect)(
|
|
2208
2365
|
() => subscribeScenario((key) => {
|
|
2209
2366
|
const active = resolveScenario() !== null;
|
|
2210
2367
|
setMock(active);
|
|
@@ -2217,7 +2374,7 @@ function SidebarBalance({
|
|
|
2217
2374
|
}),
|
|
2218
2375
|
[acceptBalance]
|
|
2219
2376
|
);
|
|
2220
|
-
(0,
|
|
2377
|
+
(0, import_react6.useEffect)(() => {
|
|
2221
2378
|
if (mock) return;
|
|
2222
2379
|
let cancelled = false;
|
|
2223
2380
|
const load = async () => {
|
|
@@ -2251,19 +2408,19 @@ function SidebarBalance({
|
|
|
2251
2408
|
acceptBalance,
|
|
2252
2409
|
showUnreachable
|
|
2253
2410
|
]);
|
|
2254
|
-
(0,
|
|
2411
|
+
(0, import_react6.useEffect)(
|
|
2255
2412
|
() => () => {
|
|
2256
2413
|
if (refreshTimer.current !== void 0) window.clearTimeout(refreshTimer.current);
|
|
2257
2414
|
},
|
|
2258
2415
|
[]
|
|
2259
2416
|
);
|
|
2260
|
-
const closeNow = (0,
|
|
2417
|
+
const closeNow = (0, import_react6.useCallback)(() => {
|
|
2261
2418
|
setOpen(false);
|
|
2262
2419
|
}, []);
|
|
2263
|
-
const toggleOpen = (0,
|
|
2420
|
+
const toggleOpen = (0, import_react6.useCallback)(() => {
|
|
2264
2421
|
setOpen((value) => !value);
|
|
2265
2422
|
}, []);
|
|
2266
|
-
const pos = (0,
|
|
2423
|
+
const pos = (0, import_dsh_client_ui_primitives5.useAnchoredPosition)({
|
|
2267
2424
|
open,
|
|
2268
2425
|
anchorRef: rootRef,
|
|
2269
2426
|
panelRef,
|
|
@@ -2271,11 +2428,11 @@ function SidebarBalance({
|
|
|
2271
2428
|
gap: PANEL_GAP,
|
|
2272
2429
|
margin: PANEL_MARGIN
|
|
2273
2430
|
});
|
|
2274
|
-
(0,
|
|
2431
|
+
(0, import_react6.useLayoutEffect)(() => {
|
|
2275
2432
|
if (!open) return;
|
|
2276
2433
|
setNow(Date.now());
|
|
2277
2434
|
}, [open]);
|
|
2278
|
-
(0,
|
|
2435
|
+
(0, import_react6.useEffect)(() => {
|
|
2279
2436
|
if (!open) return;
|
|
2280
2437
|
const id = window.setInterval(() => {
|
|
2281
2438
|
setNow(Date.now());
|
|
@@ -2284,7 +2441,7 @@ function SidebarBalance({
|
|
|
2284
2441
|
window.clearInterval(id);
|
|
2285
2442
|
};
|
|
2286
2443
|
}, [open]);
|
|
2287
|
-
(0,
|
|
2444
|
+
(0, import_react6.useEffect)(() => {
|
|
2288
2445
|
if (cooldownUntil === 0) return;
|
|
2289
2446
|
const remaining = cooldownUntil - Date.now();
|
|
2290
2447
|
if (remaining <= 0) return;
|
|
@@ -2295,7 +2452,7 @@ function SidebarBalance({
|
|
|
2295
2452
|
window.clearTimeout(id);
|
|
2296
2453
|
};
|
|
2297
2454
|
}, [cooldownUntil]);
|
|
2298
|
-
(0,
|
|
2455
|
+
(0, import_react6.useEffect)(() => {
|
|
2299
2456
|
if (!open) return;
|
|
2300
2457
|
const onKeyDown = (event) => {
|
|
2301
2458
|
if (event.key === "Escape") closeNow();
|
|
@@ -2305,8 +2462,8 @@ function SidebarBalance({
|
|
|
2305
2462
|
document.removeEventListener("keydown", onKeyDown);
|
|
2306
2463
|
};
|
|
2307
2464
|
}, [open, closeNow]);
|
|
2308
|
-
(0,
|
|
2309
|
-
const handleRefresh = (0,
|
|
2465
|
+
(0, import_dsh_client_ui_primitives5.useDismissOnOutsidePointer)(rootRef, open, setOpen, panelRef);
|
|
2466
|
+
const handleRefresh = (0, import_react6.useCallback)(() => {
|
|
2310
2467
|
if (refreshing) return;
|
|
2311
2468
|
if (Date.now() < cooldownUntil) return;
|
|
2312
2469
|
setRefreshing(true);
|
|
@@ -2351,13 +2508,13 @@ function SidebarBalance({
|
|
|
2351
2508
|
showUnreachable,
|
|
2352
2509
|
markFresh
|
|
2353
2510
|
]);
|
|
2354
|
-
const handleUseShown = (0,
|
|
2511
|
+
const handleUseShown = (0, import_react6.useCallback)(() => {
|
|
2355
2512
|
const current = selection.shown;
|
|
2356
2513
|
if (current === null) return;
|
|
2357
2514
|
void onSelectCurrency(current.currency);
|
|
2358
2515
|
}, [selection, onSelectCurrency]);
|
|
2359
2516
|
const pluginsAction = usePluginsNavigation(pluginsNavigation);
|
|
2360
|
-
const popoverPluginsAction = (0,
|
|
2517
|
+
const popoverPluginsAction = (0, import_react6.useMemo)(
|
|
2361
2518
|
() => pluginsAction === void 0 ? void 0 : {
|
|
2362
2519
|
reachesConfig: pluginsAction.reachesConfig,
|
|
2363
2520
|
open: () => {
|
|
@@ -2395,10 +2552,11 @@ function SidebarBalance({
|
|
|
2395
2552
|
const ariaLabel = ariaParts.join(" ");
|
|
2396
2553
|
const cooldownSeconds = cooldownSecondsOf(cooldownUntil, now);
|
|
2397
2554
|
const sourceKey = shown === null ? null : sourceLabelKeyOf(response.source);
|
|
2398
|
-
const
|
|
2555
|
+
const sourceIdentity = shown === null ? null : sourceIdentityOf(response);
|
|
2556
|
+
const sourceLabel = shown === null ? null : sourceIdentity !== null ? interpolate(t("popover.source.identity"), { identity: sourceIdentity }) : sourceKey === null ? null : t(sourceKey);
|
|
2399
2557
|
const ageMs = currentAgeMs(view.seenAt, view.seenAgeMs, now);
|
|
2400
2558
|
const hoverText = hoverTextOf(shown, stateText);
|
|
2401
|
-
const trigger = /* @__PURE__ */ (0,
|
|
2559
|
+
const trigger = /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2402
2560
|
"button",
|
|
2403
2561
|
{
|
|
2404
2562
|
type: "button",
|
|
@@ -2406,11 +2564,11 @@ function SidebarBalance({
|
|
|
2406
2564
|
"aria-label": ariaLabel,
|
|
2407
2565
|
"aria-expanded": open,
|
|
2408
2566
|
onClick: toggleOpen,
|
|
2409
|
-
children: wide ? /* @__PURE__ */ (0,
|
|
2410
|
-
/* @__PURE__ */ (0,
|
|
2411
|
-
/* @__PURE__ */ (0,
|
|
2412
|
-
markerLabel === null ? null : /* @__PURE__ */ (0,
|
|
2413
|
-
] }) : /* @__PURE__ */ (0,
|
|
2567
|
+
children: wide ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
2568
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: SidebarBalance_default.icon, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PercentRing, { state: ring.state, marker: ring.marker, ratio: ringRatio, size: 16 }) }),
|
|
2569
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: SidebarBalance_default.label, children: t("sidebar.label") }),
|
|
2570
|
+
markerLabel === null ? null : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_dsh_client_ui_primitives5.Tooltip, { label: markerHint, side: "bottom", delayMs: 500, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: SidebarBalance_default.marker, role: "img", "aria-label": markerLabel, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_dsh_client_ui_primitives5.IconWarningOutlineRegular, { size: 12 }) }) })
|
|
2571
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2414
2572
|
PercentRing,
|
|
2415
2573
|
{
|
|
2416
2574
|
state: ring.state,
|
|
@@ -2422,10 +2580,10 @@ function SidebarBalance({
|
|
|
2422
2580
|
)
|
|
2423
2581
|
}
|
|
2424
2582
|
);
|
|
2425
|
-
return /* @__PURE__ */ (0,
|
|
2426
|
-
wide && hoverText !== null ? /* @__PURE__ */ (0,
|
|
2583
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { ref: rootRef, className: SidebarBalance_default.root, "data-mode": wide ? "wide" : "rail", tabIndex: -1, children: [
|
|
2584
|
+
wide && hoverText !== null ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_dsh_client_ui_primitives5.Tooltip, { label: hoverText, side: "right", delayMs: 500, disabled: open, children: trigger }) : trigger,
|
|
2427
2585
|
open ? (0, import_react_dom.createPortal)(
|
|
2428
|
-
/* @__PURE__ */ (0,
|
|
2586
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
2429
2587
|
BalancePopover,
|
|
2430
2588
|
{
|
|
2431
2589
|
t,
|
|
@@ -2510,7 +2668,7 @@ function createRouteHint(services) {
|
|
|
2510
2668
|
}
|
|
2511
2669
|
|
|
2512
2670
|
// src/client/index.tsx
|
|
2513
|
-
var
|
|
2671
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
2514
2672
|
var ENTRY_ID = "dsh-ds-balance";
|
|
2515
2673
|
var BUNDLE_CONFIG_KEY = "dsh-ds-balance";
|
|
2516
2674
|
var SIDEBAR_ENTRY_ID = "ds-balance";
|
|
@@ -2533,9 +2691,9 @@ function asRecord2(value) {
|
|
|
2533
2691
|
return isRecord2(value) ? value : {};
|
|
2534
2692
|
}
|
|
2535
2693
|
function useFormSnapshot(form) {
|
|
2536
|
-
const subscribe = (0,
|
|
2537
|
-
const getSnapshot = (0,
|
|
2538
|
-
return (0,
|
|
2694
|
+
const subscribe = (0, import_react7.useCallback)((listener) => form.subscribe(listener), [form]);
|
|
2695
|
+
const getSnapshot = (0, import_react7.useCallback)(() => form.getSnapshot(), [form]);
|
|
2696
|
+
return (0, import_react7.useSyncExternalStore)(subscribe, getSnapshot);
|
|
2539
2697
|
}
|
|
2540
2698
|
function useScopeValue(form) {
|
|
2541
2699
|
return asRecord2(useFormSnapshot(form).value);
|
|
@@ -2567,11 +2725,11 @@ function readSignature(value) {
|
|
|
2567
2725
|
function SidebarSeatComponent(props) {
|
|
2568
2726
|
const value = useScopeValue(props.form);
|
|
2569
2727
|
const writable = useScopeWritable(props.form);
|
|
2570
|
-
const selectCurrency = (0,
|
|
2728
|
+
const selectCurrency = (0, import_react7.useCallback)(
|
|
2571
2729
|
(currency) => writeFieldValue(props.form, "displayCurrency", currency),
|
|
2572
2730
|
[props.form]
|
|
2573
2731
|
);
|
|
2574
|
-
return /* @__PURE__ */ (0,
|
|
2732
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2575
2733
|
SidebarBalance,
|
|
2576
2734
|
{
|
|
2577
2735
|
wide: props.seat.wide,
|
|
@@ -2593,7 +2751,7 @@ function SidebarSeatComponent(props) {
|
|
|
2593
2751
|
}
|
|
2594
2752
|
function SettingsSeatComponent(props) {
|
|
2595
2753
|
const t = translateOf(props.seat.t);
|
|
2596
|
-
return /* @__PURE__ */ (0,
|
|
2754
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(BalanceSettingsCard, { t, form: props.form });
|
|
2597
2755
|
}
|
|
2598
2756
|
var PLUGINS_PANEL_ID = "plugins";
|
|
2599
2757
|
function createPluginsNavigation() {
|
|
@@ -2702,14 +2860,14 @@ function apply(ctx) {
|
|
|
2702
2860
|
CONFIG_SLOT,
|
|
2703
2861
|
() => ctx.slots.register(
|
|
2704
2862
|
{ name: CONFIG_SLOT, key: BUNDLE_CONFIG_KEY, locale: NS },
|
|
2705
|
-
(seat) => /* @__PURE__ */ (0,
|
|
2863
|
+
(seat) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SettingsSeatComponent, { seat, form })
|
|
2706
2864
|
)
|
|
2707
2865
|
);
|
|
2708
2866
|
ctx.slots.inject(
|
|
2709
2867
|
"sidebar.footer.action",
|
|
2710
2868
|
() => ctx.slots.register(
|
|
2711
2869
|
{ name: "sidebar.footer.action", id: SIDEBAR_ENTRY_ID, order: 0, locale: NS },
|
|
2712
|
-
(seat) => /* @__PURE__ */ (0,
|
|
2870
|
+
(seat) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
2713
2871
|
SidebarSeatComponent,
|
|
2714
2872
|
{
|
|
2715
2873
|
seat,
|
|
@@ -2723,7 +2881,7 @@ function apply(ctx) {
|
|
|
2723
2881
|
);
|
|
2724
2882
|
});
|
|
2725
2883
|
}
|
|
2726
|
-
var __dsbCss = "/* src/client/settings/fields.module.css */\n.fields_group {\n padding: 12px 0 0;\n}\n.fields_groupLast {\n padding-bottom: 12px;\n}\n.fields_groupNote {\n margin: 4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.fields_fields {\n display: flex;\n flex-direction: column;\n}\n.fields_fields > * + * {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n.fields_details {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n margin-top: 12px;\n padding-top: 12px;\n}\n.fields_detailsBody {\n padding-top: 10px;\n}\n.fields_field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px 0;\n}\n.fields_row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 0;\n}\n.fields_rowText {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding-right: 48px;\n}\n.fields_rowTitleLine {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_rowTitle {\n flex: 1;\n min-width: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_head {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_label {\n flex: 1;\n min-width: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_badges {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n.fields_reset {\n border: none;\n background: none;\n padding: 0;\n font: inherit;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n.fields_reset:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}\n.fields_reset:disabled {\n cursor: default;\n}\n.fields_inputStatic,\n.fields_inputStatic:hover {\n pointer-events: none;\n}\n.fields_inputStatic input,\n.fields_inputStatic input:hover,\n.fields_inputStatic input:focus,\n.fields_inputStatic input:focus-visible,\n.fields_inputStatic input:active {\n border-color: var(--dsw-alias-border-l4);\n background: var(--dsw-alias-bg-layer-3);\n outline: none;\n box-shadow: none;\n cursor: default;\n}\n.fields_inputInvalid input {\n border: 1px solid var(--dsw-alias-state-error-primary);\n}\n.fields_inputInvalid input:focus-visible {\n border-color: var(--dsw-alias-brand-primary);\n}\n.fields_inputWithAction {\n position: relative;\n display: flex;\n align-items: center;\n}\n.fields_inputWithAction .fields_input,\n.fields_inputWithAction .fields_inputInvalid {\n padding-right: 38px;\n}\n.fields_reveal {\n position: absolute;\n right: 4px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n padding: 0;\n border: none;\n border-radius: 50%;\n corner-shape: round;\n background: transparent;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n.fields_reveal:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n.fields_revealOn {\n color: var(--dsw-alias-label-primary);\n}\n.fields_reveal:disabled {\n cursor: default;\n opacity: 0.4;\n}\n.fields_selectorAnchor {\n flex: none;\n}\n.fields_selector {\n display: inline-flex;\n align-items: center;\n gap: 12px;\n flex: none;\n max-width: 100%;\n height: 36px;\n padding: 0 14px;\n border: none;\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-module-platform);\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n text-align: left;\n cursor: pointer;\n}\n.fields_selector:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.fields_selector:disabled {\n color: var(--dsw-alias-label-tertiary);\n cursor: default;\n}\n.fields_selectorChevron {\n flex: none;\n}\n.fields_hint {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.fields_pairNote {\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-warn-primary);\n}\n.fields_pairNote::before {\n content: \"\";\n flex: none;\n width: 5px;\n height: 5px;\n border-radius: 50%;\n corner-shape: round;\n background: currentColor;\n}\n.fields_invalid {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n.fields_actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_resultOk {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-success-primary);\n}\n.fields_resultFail {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n\n/* src/client/settings/BalanceSettingsCard.module.css */\n.BalanceSettingsCard_form {\n display: flex;\n flex-direction: column;\n}\n.BalanceSettingsCard_readOnly {\n margin: 0 0 12px;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalanceSettingsCard_footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding-top: 16px;\n}\n.BalanceSettingsCard_failed {\n flex: 1;\n min-width: 0;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n.BalanceSettingsCard_notice {\n flex: 1;\n min-width: 0;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n\n/* src/client/sidebar/BalancePopover.module.css */\n.BalancePopover_panel {\n position: fixed;\n isolation: isolate;\n z-index: 1100;\n box-sizing: border-box;\n width: max-content;\n min-width: min(300px, calc(100vw - 24px));\n max-width: min(440px, calc(100vw - 24px));\n padding: 16px;\n border: 0;\n border-radius: var(--dsw-radius-lg);\n --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);\n box-shadow: var(--dsw-elevation-prominent);\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n cursor: default;\n}\n.BalancePopover_panel::before {\n position: absolute;\n z-index: -1;\n inset: 0;\n border-radius: inherit;\n background: var(--dsw-specific-menu);\n backdrop-filter: var(--dsw-menu-backdrop-filter);\n content: \"\";\n pointer-events: none;\n}\n.BalancePopover_title {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n margin-bottom: 8px;\n color: var(--dsw-alias-label-primary);\n font-weight: 500;\n}\n.BalancePopover_titleMain {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n}\n.BalancePopover_titleLabel {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n cursor: pointer;\n color: inherit;\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n.BalancePopover_titleLabel:hover,\n.BalancePopover_titleLabel:visited {\n color: inherit;\n}\n.BalancePopover_sourceLabel {\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n font-weight: 400;\n}\n.BalancePopover_titleLabel svg {\n flex: none;\n width: 14px;\n height: auto;\n}\n.BalancePopover_iconButton {\n position: relative;\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n margin-block: -5px;\n border: none;\n border-radius: var(--dsw-radius-sm);\n padding: 0;\n background: transparent;\n cursor: pointer;\n color: var(--dsw-alias-label-secondary);\n}\n.BalancePopover_iconButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.BalancePopover_iconButton:focus-visible {\n outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color);\n outline-offset: -2px;\n}\n.BalancePopover_titleRule {\n margin-bottom: 10px;\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n.BalancePopover_details {\n display: grid;\n grid-template-columns: minmax(76px, auto) minmax(0, 1fr);\n gap: 6px 16px;\n margin: 0;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_details dt,\n.BalancePopover_details dd {\n min-width: 0;\n margin: 0;\n}\n.BalancePopover_details dd {\n color: var(--dsw-alias-label-secondary);\n font-variant-numeric: tabular-nums;\n text-align: right;\n}\n.BalancePopover_notice {\n margin-top: 12px;\n}\n.BalancePopover_noticeText {\n margin: 0 0 8px;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_noticeActions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n}\n.BalancePopover_footer {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 12px;\n}\n.BalancePopover_updated {\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_status {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: right;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_refresh {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: none;\n border-radius: var(--dsw-radius-sm);\n background: transparent;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n.BalancePopover_refresh:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n.BalancePopover_refresh:focus-visible {\n outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color);\n outline-offset: -2px;\n}\n.BalancePopover_refresh:disabled {\n opacity: 0.4;\n cursor: default;\n}\n.BalancePopover_refresh[data-cooling] {\n color: var(--dsw-alias-label-caption);\n}\n.BalancePopover_refresh[data-refreshing] svg {\n animation: BalancePopover_balance-refresh-spin 900ms linear infinite;\n}\n@keyframes BalancePopover_balance-refresh-spin {\n to {\n transform: rotate(360deg);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .BalancePopover_refresh[data-refreshing] svg {\n animation-duration: 2400ms;\n }\n}\n\n/* src/client/sidebar/PercentRing.module.css */\n.PercentRing_ring {\n display: block;\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n}\n.PercentRing_ring[data-state=done] {\n color: var(--dsw-alias-state-success-primary);\n}\n.PercentRing_ring[data-state=warning] {\n color: var(--dsw-alias-state-warn-primary);\n}\n.PercentRing_ring[data-state=error] {\n color: var(--dsw-alias-state-error-primary);\n}\n.PercentRing_ring[data-state=idle] {\n color: var(--dsw-alias-state-idle-primary);\n}\n.PercentRing_track {\n fill: none;\n stroke: var(--dsw-alias-border-l3);\n stroke-width: 1;\n}\n.PercentRing_fill {\n fill: none;\n stroke: currentColor;\n stroke-width: 1;\n stroke-linecap: round;\n}\n.PercentRing_marker {\n fill: none;\n stroke: currentColor;\n stroke-width: 1;\n stroke-linecap: round;\n}\n.PercentRing_spin {\n transform-origin: center;\n animation: PercentRing_dsb-ring-spin 1.5s linear infinite;\n}\n@keyframes PercentRing_dsb-ring-spin {\n to {\n transform: rotate(360deg);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .PercentRing_spin {\n animation: none;\n }\n}\n\n/* src/client/sidebar/SidebarBalance.module.css */\n.SidebarBalance_root {\n position: relative;\n display: flex;\n min-width: 0;\n}\n.SidebarBalance_root[data-mode=wide] {\n flex: none;\n width: calc(100% + 4px);\n margin: 4px -2px 0;\n}\n.SidebarBalance_root[data-mode=rail] {\n flex: none;\n margin: 8px 0 0;\n}\n.SidebarBalance_trigger {\n display: flex;\n align-items: center;\n box-sizing: border-box;\n border: none;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font-family: inherit;\n font-size: 14px;\n line-height: 22px;\n cursor: pointer;\n overflow: hidden;\n}\n.SidebarBalance_trigger:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.SidebarBalance_trigger:focus-visible {\n outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color);\n outline-offset: -2px;\n}\n.SidebarBalance_root[data-mode=wide] .SidebarBalance_trigger {\n flex: none;\n gap: 8px;\n width: 100%;\n height: 42px;\n padding: 0 10px 0 8px;\n border-radius: var(--dsw-radius-md);\n}\n.SidebarBalance_root[data-mode=rail] .SidebarBalance_trigger {\n flex: none;\n justify-content: center;\n width: 36px;\n height: 36px;\n padding: 0;\n border-radius: var(--dsw-radius-md);\n}\n.SidebarBalance_icon {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n}\n.SidebarBalance_label {\n flex: 0 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.SidebarBalance_marker {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n color: var(--dsw-alias-label-tertiary);\n position: relative;\n top: 1.63px;\n}\n\n/* src/client/sidebar/footer-stack.module.css */\ndiv:has(> [data-slot=\"sidebar.footer.action\"]) {\n flex-direction: column;\n}\n";
|
|
2884
|
+
var __dsbCss = "/* src/client/settings/AccountAvatar.module.css */\n.AccountAvatar_avatar {\n box-sizing: border-box;\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border-radius: 50%;\n corner-shape: round;\n overflow: hidden;\n background: var(--dsw-alias-bg-skeleton);\n}\n.AccountAvatar_image {\n display: block;\n width: 100%;\n height: 100%;\n border-radius: 50%;\n corner-shape: round;\n object-fit: cover;\n}\n\n/* src/client/settings/fields.module.css */\n.fields_group {\n display: flex;\n flex-direction: column;\n width: 100%;\n min-width: 0;\n padding: 12px 0 0;\n}\n.fields_groupHead {\n position: relative;\n display: flex;\n align-items: center;\n height: calc(24px + var(--dsh-content-font-delta, 0px));\n min-width: 0;\n color: var(--dsw-alias-label-tertiary);\n transition: color 100ms ease;\n cursor: pointer;\n}\n.fields_groupHead:hover {\n color: var(--dsw-alias-label-secondary);\n}\n.fields_groupLeading {\n position: relative;\n flex: none;\n width: calc(16px + var(--dsh-content-font-delta, 0px));\n height: calc(16px + var(--dsh-content-font-delta, 0px));\n display: inline-flex;\n align-items: center;\n justify-content: center;\n margin-right: 6px;\n}\n.fields_groupLeading svg {\n width: calc(14px + var(--dsh-content-font-delta, 0px));\n height: calc(14px + var(--dsh-content-font-delta, 0px));\n}\n.fields_groupIcon {\n display: inline-flex;\n opacity: 1;\n transition: opacity 100ms ease;\n}\n.fields_groupChevronClosed,\n.fields_groupChevronOpen {\n position: absolute;\n inset: 0;\n margin: auto;\n opacity: 0;\n pointer-events: none;\n transition: opacity 100ms ease;\n}\n.fields_groupHead[aria-expanded=false]:hover .fields_groupChevronClosed,\n.fields_groupHead[aria-expanded=false]:focus-visible .fields_groupChevronClosed,\n.fields_groupHead[aria-expanded=true]:hover .fields_groupChevronOpen,\n.fields_groupHead[aria-expanded=true]:focus-visible .fields_groupChevronOpen {\n opacity: 1;\n}\n.fields_groupHead:hover .fields_groupIcon,\n.fields_groupHead:focus-visible .fields_groupIcon {\n opacity: 0;\n}\n.fields_groupTitle {\n flex: none;\n font-size: var(--dsh-content-font-size-secondary, 13px);\n line-height: calc(24px + var(--dsh-content-font-delta, 0px));\n color: inherit;\n}\n@media (prefers-reduced-motion: reduce) {\n .fields_groupHead {\n transition: none;\n }\n .fields_groupIcon,\n .fields_groupChevronClosed,\n .fields_groupChevronOpen {\n transition: none;\n }\n}\n.fields_groupLast {\n padding-bottom: 12px;\n}\n.fields_groupNote {\n margin: 4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.fields_fields {\n display: flex;\n flex-direction: column;\n}\n.fields_fields > * + * {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n.fields_details {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n margin-top: 12px;\n padding-top: 12px;\n}\n.fields_detailsBody {\n padding-top: 10px;\n}\n.fields_source {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px 0;\n}\n.fields_sourceHead {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_dot {\n box-sizing: border-box;\n display: inline-block;\n flex: none;\n width: 8px;\n height: 8px;\n border-radius: 50%;\n corner-shape: round;\n}\n.fields_dotOk {\n background: var(--dsw-alias-state-success-primary);\n}\n.fields_dotMissing {\n background: var(--dsw-alias-state-error-primary);\n}\n.fields_sourceName {\n flex: none;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_sourceSlot {\n flex: 1 1 auto;\n min-width: 0;\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 6px;\n}\n.fields_sourceIdentity,\n.fields_sourceLiveText {\n min-width: 0;\n font-size: 12px;\n line-height: 1.5;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n color: var(--dsw-alias-label-tertiary);\n}\n.fields_sourceIdentityMono {\n font-family:\n ui-monospace,\n SFMono-Regular,\n Menlo,\n Consolas,\n monospace;\n}\n.fields_sourceLive {\n flex: 0 1 auto;\n min-width: 0;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n}\n.fields_sourceLiveIcon {\n flex: none;\n}\n.fields_sourceDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n}\n.fields_field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 12px 0;\n}\n.fields_row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px 0;\n}\n.fields_rowText {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n padding-right: 48px;\n}\n.fields_rowTitleLine {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_rowTitle {\n flex: 1;\n min-width: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_head {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.fields_label {\n flex: 1;\n min-width: 0;\n font-size: 13px;\n font-weight: 500;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n.fields_badges {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n.fields_reset {\n border: none;\n background: none;\n padding: 0;\n font: inherit;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n.fields_reset:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}\n.fields_reset:disabled {\n cursor: default;\n}\n.fields_inputStatic,\n.fields_inputStatic:hover {\n pointer-events: none;\n}\n.fields_inputStatic input,\n.fields_inputStatic input:hover,\n.fields_inputStatic input:focus,\n.fields_inputStatic input:focus-visible,\n.fields_inputStatic input:active {\n border-color: var(--dsw-alias-border-l4);\n background: var(--dsw-alias-bg-layer-3);\n outline: none;\n box-shadow: none;\n cursor: default;\n}\n.fields_inputInvalid input {\n border: 1px solid var(--dsw-alias-state-error-primary);\n}\n.fields_inputInvalid input:focus-visible {\n border-color: var(--dsw-alias-brand-primary);\n}\n.fields_inputWithAction {\n position: relative;\n display: flex;\n align-items: center;\n}\n.fields_inputWithAction .fields_input,\n.fields_inputWithAction .fields_inputInvalid {\n padding-right: 38px;\n}\n.fields_reveal {\n position: absolute;\n right: 4px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 26px;\n height: 26px;\n padding: 0;\n border: none;\n border-radius: 50%;\n corner-shape: round;\n background: transparent;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n.fields_reveal:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n.fields_revealOn {\n color: var(--dsw-alias-label-primary);\n}\n.fields_reveal:disabled {\n cursor: default;\n opacity: 0.4;\n}\n.fields_selectorAnchor {\n flex: none;\n}\n.fields_selector {\n display: inline-flex;\n align-items: center;\n gap: 12px;\n flex: none;\n max-width: 100%;\n height: 36px;\n padding: 0 14px;\n border: none;\n border-radius: var(--dsw-radius-md);\n background: var(--dsw-alias-bg-module-platform);\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n text-align: left;\n cursor: pointer;\n}\n.fields_selector:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.fields_selector:disabled {\n color: var(--dsw-alias-label-tertiary);\n cursor: default;\n}\n.fields_selectorChevron {\n flex: none;\n}\n.fields_hint {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.fields_pairNote {\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-warn-primary);\n}\n.fields_pairNote::before {\n content: \"\";\n flex: none;\n width: 5px;\n height: 5px;\n border-radius: 50%;\n corner-shape: round;\n background: currentColor;\n}\n.fields_invalid {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n.fields_actions {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n/* src/client/settings/BalanceSettingsCard.module.css */\n.BalanceSettingsCard_form {\n display: flex;\n flex-direction: column;\n}\n.BalanceSettingsCard_readOnly {\n margin: 0 0 12px;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalanceSettingsCard_footer {\n display: flex;\n align-items: center;\n gap: 8px;\n padding-top: 16px;\n}\n.BalanceSettingsCard_save {\n appearance: none;\n border: 1px solid transparent;\n border-radius: var(--dsw-radius-md);\n padding: 5px 14px;\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n cursor: pointer;\n background: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-bg-layer-3);\n}\n.BalanceSettingsCard_save:disabled {\n opacity: 0.4;\n cursor: default;\n}\n.BalanceSettingsCard_save:focus-visible {\n outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color);\n outline-offset: 1px;\n}\n.BalanceSettingsCard_failed {\n flex: 1;\n min-width: 0;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-state-error-primary);\n}\n.BalanceSettingsCard_notice {\n flex: 1;\n min-width: 0;\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n\n/* src/client/sidebar/BalancePopover.module.css */\n.BalancePopover_panel {\n position: fixed;\n isolation: isolate;\n z-index: 1100;\n box-sizing: border-box;\n width: max-content;\n min-width: min(300px, calc(100vw - 24px));\n max-width: min(440px, calc(100vw - 24px));\n padding: 16px;\n border: 0;\n border-radius: var(--dsw-radius-lg);\n --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);\n box-shadow: var(--dsw-elevation-prominent);\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n cursor: default;\n}\n.BalancePopover_panel::before {\n position: absolute;\n z-index: -1;\n inset: 0;\n border-radius: inherit;\n background: var(--dsw-specific-menu);\n backdrop-filter: var(--dsw-menu-backdrop-filter);\n content: \"\";\n pointer-events: none;\n}\n.BalancePopover_title {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n margin-bottom: 8px;\n color: var(--dsw-alias-label-primary);\n font-weight: 500;\n}\n.BalancePopover_titleMain {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n}\n.BalancePopover_titleLabel {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n min-width: 0;\n cursor: pointer;\n color: inherit;\n text-decoration: underline;\n text-underline-offset: 2px;\n}\n.BalancePopover_titleLabel:hover,\n.BalancePopover_titleLabel:visited {\n color: inherit;\n}\n.BalancePopover_sourceLabel {\n flex: 0 1 auto;\n min-width: 0;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n color: var(--dsw-alias-label-tertiary);\n font-weight: 400;\n}\n.BalancePopover_titleLabel svg {\n flex: none;\n width: 14px;\n height: auto;\n}\n.BalancePopover_iconButton {\n position: relative;\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n margin-block: -5px;\n border: none;\n border-radius: var(--dsw-radius-sm);\n padding: 0;\n background: transparent;\n cursor: pointer;\n color: var(--dsw-alias-label-secondary);\n}\n.BalancePopover_iconButton:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.BalancePopover_iconButton:focus-visible {\n outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color);\n outline-offset: -2px;\n}\n.BalancePopover_titleRule {\n margin-bottom: 10px;\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n.BalancePopover_details {\n display: grid;\n grid-template-columns: minmax(76px, auto) minmax(0, 1fr);\n gap: 6px 16px;\n margin: 0;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_details dt,\n.BalancePopover_details dd {\n min-width: 0;\n margin: 0;\n}\n.BalancePopover_details dd {\n color: var(--dsw-alias-label-secondary);\n font-variant-numeric: tabular-nums;\n text-align: right;\n}\n.BalancePopover_notice {\n margin-top: 12px;\n}\n.BalancePopover_noticeText {\n margin: 0 0 8px;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_noticeActions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n}\n.BalancePopover_footer {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 12px;\n}\n.BalancePopover_updated {\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_status {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n text-align: right;\n color: var(--dsw-alias-label-tertiary);\n}\n.BalancePopover_refresh {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: none;\n border-radius: var(--dsw-radius-sm);\n background: transparent;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n.BalancePopover_refresh:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-secondary);\n}\n.BalancePopover_refresh:focus-visible {\n outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color);\n outline-offset: -2px;\n}\n.BalancePopover_refresh:disabled {\n opacity: 0.4;\n cursor: default;\n}\n.BalancePopover_refresh[data-cooling] {\n color: var(--dsw-alias-label-caption);\n}\n.BalancePopover_refresh[data-refreshing] svg {\n animation: BalancePopover_balance-refresh-spin 900ms linear infinite;\n}\n@keyframes BalancePopover_balance-refresh-spin {\n to {\n transform: rotate(360deg);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .BalancePopover_refresh[data-refreshing] svg {\n animation-duration: 2400ms;\n }\n}\n\n/* src/client/sidebar/PercentRing.module.css */\n.PercentRing_ring {\n display: block;\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n}\n.PercentRing_ring[data-state=done] {\n color: var(--dsw-alias-state-success-primary);\n}\n.PercentRing_ring[data-state=warning] {\n color: var(--dsw-alias-state-warn-primary);\n}\n.PercentRing_ring[data-state=error] {\n color: var(--dsw-alias-state-error-primary);\n}\n.PercentRing_ring[data-state=idle] {\n color: var(--dsw-alias-state-idle-primary);\n}\n.PercentRing_track {\n fill: none;\n stroke: var(--dsw-alias-border-l3);\n stroke-width: 1;\n}\n.PercentRing_fill {\n fill: none;\n stroke: currentColor;\n stroke-width: 1;\n stroke-linecap: round;\n}\n.PercentRing_marker {\n fill: none;\n stroke: currentColor;\n stroke-width: 1;\n stroke-linecap: round;\n}\n.PercentRing_spin {\n transform-origin: center;\n animation: PercentRing_dsb-ring-spin 1.5s linear infinite;\n}\n@keyframes PercentRing_dsb-ring-spin {\n to {\n transform: rotate(360deg);\n }\n}\n@media (prefers-reduced-motion: reduce) {\n .PercentRing_spin {\n animation: none;\n }\n}\n\n/* src/client/sidebar/SidebarBalance.module.css */\n.SidebarBalance_root {\n position: relative;\n display: flex;\n min-width: 0;\n}\n.SidebarBalance_root[data-mode=wide] {\n flex: none;\n width: calc(100% + 4px);\n margin: 4px -2px 0;\n}\n.SidebarBalance_root[data-mode=rail] {\n flex: none;\n margin: 8px 0 0;\n}\n.SidebarBalance_trigger {\n display: flex;\n align-items: center;\n box-sizing: border-box;\n border: none;\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font-family: inherit;\n font-size: 14px;\n line-height: 22px;\n cursor: pointer;\n overflow: hidden;\n}\n.SidebarBalance_trigger:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n.SidebarBalance_trigger:focus-visible {\n outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color);\n outline-offset: -2px;\n}\n.SidebarBalance_root[data-mode=wide] .SidebarBalance_trigger {\n flex: none;\n gap: 8px;\n width: 100%;\n height: 42px;\n padding: 0 10px 0 8px;\n border-radius: var(--dsw-radius-md);\n}\n.SidebarBalance_root[data-mode=rail] .SidebarBalance_trigger {\n flex: none;\n justify-content: center;\n width: 36px;\n height: 36px;\n padding: 0;\n border-radius: var(--dsw-radius-md);\n}\n.SidebarBalance_icon {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n width: 16px;\n height: 16px;\n}\n.SidebarBalance_label {\n flex: 0 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.SidebarBalance_marker {\n display: inline-flex;\n flex: none;\n align-items: center;\n justify-content: center;\n color: var(--dsw-alias-label-tertiary);\n position: relative;\n top: 1.63px;\n}\n\n/* src/client/sidebar/footer-stack.module.css */\ndiv:has(> [data-slot=\"sidebar.footer.action\"]) {\n flex-direction: column;\n}\n";
|
|
2727
2885
|
var __dsbTagId = "dsh-ds-balance/client.css";
|
|
2728
2886
|
if (typeof document !== 'undefined' && document.querySelector('style[data-plugin-css="' + __dsbTagId + '"]') === null) {
|
|
2729
2887
|
var __dsbTag = document.createElement('style');
|