dsh-workbuddy-xdpool 1.6.1 → 1.7.1
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/CHANGELOG.md +285 -0
- package/lib/bin.js +441 -51
- package/lib/client.js +764 -425
- package/lib/index.d.ts +209 -4
- package/lib/index.js +571 -83
- package/package.json +3 -3
package/lib/client.js
CHANGED
|
@@ -5,7 +5,6 @@ window.__ModuleLoader__.load({
|
|
|
5
5
|
var exports = module.exports;
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
7
|
let react = require("react");
|
|
8
|
-
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
9
8
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
10
9
|
//#region src/status-paths.ts
|
|
11
10
|
/**
|
|
@@ -28,10 +27,39 @@ window.__ModuleLoader__.load({
|
|
|
28
27
|
const POOL_RESET_COOLDOWN_PATH = "/plugins/dsh-workbuddy-xdpool/cooldowns/reset";
|
|
29
28
|
/** Plugin-owned daily check-in action endpoint (claim today's reward). */
|
|
30
29
|
const POOL_CHECKIN_PATH = "/plugins/dsh-workbuddy-xdpool/checkin";
|
|
30
|
+
/**
|
|
31
|
+
* Throw one account out of the pool for good, or take it back.
|
|
32
|
+
*
|
|
33
|
+
* Separate from the disable route because the semantics differ: disabling is a
|
|
34
|
+
* rotation preference the account survives, ignoring survives the account.
|
|
35
|
+
*/
|
|
36
|
+
const POOL_ACCOUNT_IGNORE_PATH = "/plugins/dsh-workbuddy-xdpool/accounts/ignored";
|
|
31
37
|
/** Run one automation job immediately, so the card can verify it on demand. */
|
|
32
38
|
const POOL_AUTOMATION_RUN_PATH = "/plugins/dsh-workbuddy-xdpool/automation/run";
|
|
33
39
|
/** Set or clear one account's reserved-credit floor. */
|
|
34
40
|
const POOL_CREDIT_RESERVE_PATH = "/plugins/dsh-workbuddy-xdpool/accounts/credit-reserve";
|
|
41
|
+
/**
|
|
42
|
+
* The schedule every automation job falls back to.
|
|
43
|
+
*
|
|
44
|
+
* Shared by both halves on purpose. The host uses it when a configured hour
|
|
45
|
+
* list arrives empty (the settings schema materializes "never configured" into
|
|
46
|
+
* `[]`), and the card uses it when it writes the `automation` block back, so a
|
|
47
|
+
* document that already holds an empty list is healed instead of being saved
|
|
48
|
+
* back as an unrunnable schedule.
|
|
49
|
+
*
|
|
50
|
+
* This lives here rather than in `scheduler.ts` because the browser half cannot
|
|
51
|
+
* import the host module: `scheduler.ts` pulls in `node:crypto` and the whole
|
|
52
|
+
* upstream client, none of which exists in the browser bundle. Two hand-written
|
|
53
|
+
* copies would drift, and the drift is invisible — the card would write a
|
|
54
|
+
* schedule the scheduler does not run.
|
|
55
|
+
*/
|
|
56
|
+
const DEFAULT_AUTOMATION_HOURS = {
|
|
57
|
+
checkin: [9],
|
|
58
|
+
report: [10],
|
|
59
|
+
tasks: [11],
|
|
60
|
+
streak: [12],
|
|
61
|
+
travel: [9, 21]
|
|
62
|
+
};
|
|
35
63
|
//#endregion
|
|
36
64
|
//#region src/client/icon.ts
|
|
37
65
|
/**
|
|
@@ -64,28 +92,38 @@ window.__ModuleLoader__.load({
|
|
|
64
92
|
* naturally next to the other configuration rows instead of looking like a
|
|
65
93
|
* bright Google-Material block on top of DSH's dark surface.
|
|
66
94
|
*
|
|
67
|
-
* The
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* are
|
|
95
|
+
* The page renders at full height with no collapse affordance, and its content is
|
|
96
|
+
* split into cards: a header row with the primary actions, a status card (region
|
|
97
|
+
* switch + distribution), then one card per feature area. The inner
|
|
98
|
+
* workbuddy-specific classes are namespaced `dsm-workbuddy-xdpool-*`.
|
|
71
99
|
*
|
|
72
100
|
* @module dsh-workbuddy-xdpool/client/styles
|
|
73
101
|
*/
|
|
74
102
|
const POOL_CARD_CSS = `
|
|
75
|
-
/*
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
.dsm-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
.
|
|
84
|
-
|
|
85
|
-
.dsm-
|
|
86
|
-
.dsm-
|
|
87
|
-
.dsm-
|
|
88
|
-
|
|
103
|
+
/*
|
|
104
|
+
* Page shell. The settings shell renders this inside its own scrollable content
|
|
105
|
+
* column, so the page supplies only the rhythm and the cards — no outer border
|
|
106
|
+
* and no extra margin (the column pads its own edges).
|
|
107
|
+
*/
|
|
108
|
+
.dsm-workbuddy-xdpool-page{max-width:860px;flex-direction:column;gap:16px;display:flex}
|
|
109
|
+
/*
|
|
110
|
+
* Header row: identity on the left, primary actions on the right. Wraps so a
|
|
111
|
+
* narrow panel drops the buttons below the title instead of squeezing it.
|
|
112
|
+
*/
|
|
113
|
+
.dsm-workbuddy-xdpool-page-head{align-items:center;gap:12px;flex-wrap:wrap;display:flex}
|
|
114
|
+
.dsm-workbuddy-xdpool-page-icon{width:32px;height:32px;flex:none;border-radius:7px}
|
|
115
|
+
.dsm-workbuddy-xdpool-page-copy{flex-direction:column;gap:4px;min-width:0;flex:1 1 220px;display:flex}
|
|
116
|
+
.dsm-workbuddy-xdpool-page-title{color:var(--dsw-alias-label-primary,#e6e6e6);margin:0;font-size:16px;font-weight:600;line-height:1.4}
|
|
117
|
+
.dsm-workbuddy-xdpool-page-desc{color:var(--dsw-alias-label-tertiary,#999);margin:0;font-size:13px;line-height:1.5}
|
|
118
|
+
.dsm-workbuddy-xdpool-page-actions{align-items:center;gap:8px;flex-wrap:wrap;flex:none;display:flex}
|
|
119
|
+
/*
|
|
120
|
+
* One feature area per card. The surface separates the sections the way the
|
|
121
|
+
* built-in settings pages do; without it every panel ran together into a single
|
|
122
|
+
* column of text with no visible boundary.
|
|
123
|
+
*/
|
|
124
|
+
.dsm-workbuddy-xdpool-card{border:1px solid var(--dsw-alias-border-l2,#36373b);background:var(--dsw-alias-bg-layer-2,#232529);border-radius:14px;flex-direction:column;gap:12px;padding:14px 16px;display:flex}
|
|
125
|
+
/* Status card: the region switch sits above the state line, then the switch. */
|
|
126
|
+
.dsm-workbuddy-xdpool-status{gap:14px}
|
|
89
127
|
/* Reusable button primitives shared with the rest of the card body. */
|
|
90
128
|
.dsm-btn{appearance:none;font:inherit;cursor:pointer;border:1px solid transparent;border-radius:8px;padding:5px 14px;font-size:13px;line-height:1.5}
|
|
91
129
|
.dsm-btn:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#5686fe);outline-offset:1px}
|
|
@@ -95,12 +133,10 @@ window.__ModuleLoader__.load({
|
|
|
95
133
|
.dsm-btn-primary{background:var(--dsw-alias-label-primary,#e6e6e6);color:var(--dsw-alias-bg-layer-3,#202126)}
|
|
96
134
|
.dsm-btn-primary:hover:not(:disabled){opacity:.9}
|
|
97
135
|
|
|
98
|
-
/* Body layout: status row + accounts list + models list. */
|
|
99
|
-
.dsm-workbuddy-xdpool-usage{display:flex;flex-direction:column;gap:14px;margin:0;padding:14px 0 4px}
|
|
100
136
|
/* Region tabs: two independent suppliers, one shown at a time. */
|
|
101
137
|
.dsm-workbuddy-xdpool-tabs{display:flex;gap:6px;padding:4px;border:1px solid var(--dsw-alias-border-l2,#3a3d45);border-radius:10px;background:var(--dsw-alias-bg-layer-3,#2a2c33)}
|
|
102
138
|
/* Empty-region guide: steps for signing in on the other gateway. */
|
|
103
|
-
.dsm-workbuddy-xdpool-empty{
|
|
139
|
+
.dsm-workbuddy-xdpool-empty{gap:10px}
|
|
104
140
|
.dsm-workbuddy-xdpool-empty-title{margin:0;color:var(--dsw-alias-label-primary,#e6e6e6);font-size:14px;font-weight:600;line-height:20px}
|
|
105
141
|
.dsm-workbuddy-xdpool-empty-steps{display:flex;flex-direction:column;gap:6px;padding:12px;border-radius:10px;background:var(--dsw-alias-bg-layer-3,#2a2c33)}
|
|
106
142
|
.dsm-workbuddy-xdpool-empty-steps-title{margin:0;color:var(--dsw-alias-label-secondary,#c6c9d0);font-size:12px;font-weight:600;line-height:18px}
|
|
@@ -114,14 +150,14 @@ window.__ModuleLoader__.load({
|
|
|
114
150
|
.dsm-workbuddy-xdpool-tab-dot{display:inline-block;width:7px;height:7px;border-radius:50%;margin-right:6px;vertical-align:baseline;background:var(--dsw-alias-state-success-primary,#22a06b)}
|
|
115
151
|
.dsm-workbuddy-xdpool-tab-dot[data-state="error"]{background:var(--dsw-alias-state-error-primary,#ef4444)}
|
|
116
152
|
.dsm-workbuddy-xdpool-tab-dot[data-state="idle"]{background:var(--dsw-alias-label-dimmed,#9aa0a6)}
|
|
117
|
-
.dsm-workbuddy-xdpool-usage-head{display:flex;
|
|
153
|
+
.dsm-workbuddy-xdpool-usage-head{display:flex;flex-direction:column;gap:12px;min-width:0}
|
|
118
154
|
.dsm-workbuddy-xdpool-usage-copy{display:flex;flex-direction:column;gap:3px;min-width:0}
|
|
119
|
-
.dsm-workbuddy-xdpool-usage-status{display:flex;align-items:center;gap:10px;font-size:15px;font-weight:
|
|
155
|
+
.dsm-workbuddy-xdpool-usage-status{display:flex;align-items:center;gap:10px;font-size:15px;font-weight:600;color:var(--dsw-alias-label-primary,#e6e6e6)}
|
|
120
156
|
.dsm-workbuddy-xdpool-usage-dot{width:9px;height:9px;border-radius:50%;flex:0 0 auto}
|
|
121
|
-
.dsm-workbuddy-xdpool-usage-hint{
|
|
157
|
+
.dsm-workbuddy-xdpool-usage-hint{margin:0;color:var(--dsw-alias-label-tertiary,#9aa0a8);font-size:12px;line-height:18px}
|
|
122
158
|
/* Distribution switch: priority (drain one) vs round-robin (spread). */
|
|
123
|
-
.dsm-workbuddy-xdpool-dist{display:flex;flex-direction:column;gap:
|
|
124
|
-
.dsm-workbuddy-xdpool-dist-title{color:var(--dsw-alias-label-tertiary,#9aa0a8);font-size:
|
|
159
|
+
.dsm-workbuddy-xdpool-dist{display:flex;flex-direction:column;gap:7px}
|
|
160
|
+
.dsm-workbuddy-xdpool-dist-title{color:var(--dsw-alias-label-tertiary,#9aa0a8);font-size:11px;line-height:16px;letter-spacing:.03em;text-transform:uppercase;font-weight:600}
|
|
125
161
|
.dsm-workbuddy-xdpool-dist-option{appearance:none;font:inherit;cursor:pointer;text-align:left;display:flex;flex-direction:column;justify-content:center;gap:2px;min-height:44px;border:1px solid var(--dsw-alias-border-l2,#3a3d45);border-radius:8px;padding:6px 10px;background:transparent;color:var(--dsw-alias-label-tertiary,#9aa0a8);transition:color .16s,border-color .16s,background .16s}
|
|
126
162
|
.dsm-workbuddy-xdpool-dist-option:hover:not(:disabled):not(.dsm-workbuddy-xdpool-dist-option-active){color:var(--dsw-alias-label-primary,#e6e6e6);border-color:var(--dsw-alias-label-dimmed,#777)}
|
|
127
163
|
.dsm-workbuddy-xdpool-dist-option:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#5686fe);outline-offset:1px}
|
|
@@ -133,7 +169,7 @@ window.__ModuleLoader__.load({
|
|
|
133
169
|
.dsm-workbuddy-xdpool-usage-actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
|
134
170
|
|
|
135
171
|
/* Account list (each account = a labeled subpanel, same as dingminhua). */
|
|
136
|
-
.dsm-workbuddy-xdpool-accounts{
|
|
172
|
+
.dsm-workbuddy-xdpool-accounts{gap:14px}
|
|
137
173
|
.dsm-workbuddy-xdpool-accounts-head{display:flex;align-items:center;justify-content:space-between;gap:12px}
|
|
138
174
|
/* "In use now": answers which account is serving without scanning every row. */
|
|
139
175
|
/* A hairline + tint reads as status; a filled bar would read as a call to action. */
|
|
@@ -161,6 +197,23 @@ window.__ModuleLoader__.load({
|
|
|
161
197
|
.dsm-workbuddy-xdpool-account-toggle:disabled{cursor:default;opacity:.6}
|
|
162
198
|
.dsm-workbuddy-xdpool-account-toggle-on{background:color-mix(in oklab, var(--dsw-alias-state-success-primary,#22a06b) 14%, transparent);border-color:color-mix(in oklab, var(--dsw-alias-state-success-primary,#22a06b) 55%, transparent);color:var(--dsw-alias-state-success-primary,#22a06b);font-weight:600}
|
|
163
199
|
.dsm-workbuddy-xdpool-account-toggle-dot{width:6px;height:6px;border-radius:50%;flex:none;background:currentColor;opacity:.9}
|
|
200
|
+
/* "Remove" button: destructive and reversible, so it is quiet until hovered. */
|
|
201
|
+
.dsm-workbuddy-xdpool-account-ignore{appearance:none;font:inherit;flex:none;cursor:pointer;border:1px solid transparent;border-radius:999px;padding:3px 10px;font-size:11px;line-height:17px;background:transparent;color:var(--dsw-alias-label-tertiary,#9aa0a8);transition:color .16s,border-color .16s,background .16s}
|
|
202
|
+
.dsm-workbuddy-xdpool-account-ignore:hover:not(:disabled){color:var(--dsw-alias-state-error-primary,#ef4444);border-color:color-mix(in oklab, var(--dsw-alias-state-error-primary,#ef4444) 45%, transparent);background:color-mix(in oklab, var(--dsw-alias-state-error-primary,#ef4444) 10%, transparent)}
|
|
203
|
+
.dsm-workbuddy-xdpool-account-ignore:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#5686fe);outline-offset:1px}
|
|
204
|
+
.dsm-workbuddy-xdpool-account-ignore:disabled{cursor:default;opacity:.6}
|
|
205
|
+
/* Ignored-account list: visible proof that "remove" can be undone. */
|
|
206
|
+
.dsm-workbuddy-xdpool-ignored-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;padding:12px 16px;border-bottom:1px solid color-mix(in oklab, var(--dsw-alias-border-l2,#3a3d45) 45%, transparent)}
|
|
207
|
+
.dsm-workbuddy-xdpool-ignored-title{margin:0;color:var(--dsw-alias-label-primary,#e6e6e6);font-size:13px;font-weight:600;line-height:19px}
|
|
208
|
+
.dsm-workbuddy-xdpool-ignored-summary{margin:0;color:var(--dsw-alias-label-tertiary,#9aa0a8);font-size:11px;line-height:17px}
|
|
209
|
+
.dsm-workbuddy-xdpool-ignored-list{display:flex;flex-direction:column}
|
|
210
|
+
.dsm-workbuddy-xdpool-ignored-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 16px}
|
|
211
|
+
.dsm-workbuddy-xdpool-ignored-row+.dsm-workbuddy-xdpool-ignored-row{border-top:1px solid color-mix(in oklab, var(--dsw-alias-border-l2,#3a3d45) 30%, transparent)}
|
|
212
|
+
.dsm-workbuddy-xdpool-ignored-label{color:var(--dsw-alias-label-secondary,#c6c9d0);font-size:12px;line-height:18px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
213
|
+
.dsm-workbuddy-xdpool-ignored-restore{appearance:none;font:inherit;flex:none;cursor:pointer;border:1px solid color-mix(in oklab, var(--dsw-alias-border-l2,#3a3d45) 70%, transparent);border-radius:999px;padding:3px 10px;font-size:11px;line-height:17px;background:transparent;color:var(--dsw-alias-label-secondary,#c6c9d0);transition:color .16s,border-color .16s}
|
|
214
|
+
.dsm-workbuddy-xdpool-ignored-restore:hover:not(:disabled){color:var(--dsw-alias-label-primary,#e6e6e6);border-color:var(--dsw-alias-label-dimmed,#777)}
|
|
215
|
+
.dsm-workbuddy-xdpool-ignored-restore:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#5686fe);outline-offset:1px}
|
|
216
|
+
.dsm-workbuddy-xdpool-ignored-restore:disabled{cursor:default;opacity:.6}
|
|
164
217
|
.dsm-workbuddy-xdpool-account-tags{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
|
|
165
218
|
.dsm-workbuddy-xdpool-account-tag{padding:1px 8px;border-radius:999px;font-size:11px;line-height:18px;background:var(--dsw-alias-state-success-subtle,rgba(34,160,107,.12));color:var(--dsw-alias-state-success-primary,#22a06b)}
|
|
166
219
|
.dsm-workbuddy-xdpool-account-tag-cooling{background:var(--dsw-alias-state-warning-subtle,rgba(217,119,6,.15));color:var(--dsw-alias-state-warning-primary,#d97706)}
|
|
@@ -196,7 +249,7 @@ window.__ModuleLoader__.load({
|
|
|
196
249
|
.dsm-workbuddy-xdpool-total-value{color:var(--dsw-alias-state-success-primary,#22a06b);font-size:28px;line-height:32px;font-weight:800;letter-spacing:-.02em;white-space:nowrap;font-variant-numeric:tabular-nums}
|
|
197
250
|
|
|
198
251
|
/* Model directory list. */
|
|
199
|
-
.dsm-workbuddy-xdpool-models{
|
|
252
|
+
.dsm-workbuddy-xdpool-models{gap:10px}
|
|
200
253
|
.dsm-workbuddy-xdpool-models-head{display:flex;align-items:center;justify-content:space-between;gap:12px}
|
|
201
254
|
.dsm-workbuddy-xdpool-models-title{margin:0;color:var(--dsw-alias-label-primary,#e6e6e6);font-size:14px;font-weight:600;line-height:20px}
|
|
202
255
|
.dsm-workbuddy-xdpool-models-summary{margin:2px 0 0;color:var(--dsw-alias-label-tertiary,#999);font-size:12px;line-height:18px}
|
|
@@ -225,6 +278,12 @@ window.__ModuleLoader__.load({
|
|
|
225
278
|
.dsm-workbuddy-xdpool-models-actions{display:flex;align-items:center;gap:8px;flex:none}
|
|
226
279
|
|
|
227
280
|
|
|
281
|
+
/* Automation: run-now button and the per-job progress line. */
|
|
282
|
+
.dsm-workbuddy-xdpool-auto-run{flex:none}
|
|
283
|
+
.dsm-workbuddy-xdpool-auto-job-detail{grid-column:1/-1;color:var(--dsw-alias-label-tertiary,#9aa0a8);font-size:11px;line-height:16px}
|
|
284
|
+
/* Credit packages panel heading inside the right-hand column. */
|
|
285
|
+
.dsm-workbuddy-xdpool-panel-packages{display:flex;flex-direction:column;gap:7px;min-width:0}
|
|
286
|
+
|
|
228
287
|
/* Check-in docked under the total, inside the right-hand panel. */
|
|
229
288
|
.dsm-workbuddy-xdpool-checkin{display:flex;flex-direction:column;align-items:center;gap:7px;width:100%;margin-top:10px;padding-top:11px;border-top:1px solid var(--dsw-alias-border-l2,#36373b)}
|
|
230
289
|
.dsm-workbuddy-xdpool-checkin-meta{display:flex;flex-direction:column;align-items:center;gap:2px;width:100%}
|
|
@@ -305,8 +364,9 @@ window.__ModuleLoader__.load({
|
|
|
305
364
|
* token expiry / cooldown info / credit packages, then the model directory
|
|
306
365
|
* with per-model free/limited/night/image badges and context size.
|
|
307
366
|
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
367
|
+
* Rendered as a full settings page (see `client/index.tsx`): the shell gives it
|
|
368
|
+
* a left-nav row and a scrollable content column, so everything is visible at
|
|
369
|
+
* once — a fold inside the page only hid the pool behind a click.
|
|
310
370
|
*
|
|
311
371
|
* @module dsh-workbuddy-xdpool/client/PoolCard
|
|
312
372
|
*/
|
|
@@ -377,6 +437,17 @@ window.__ModuleLoader__.load({
|
|
|
377
437
|
"streak",
|
|
378
438
|
"travel"
|
|
379
439
|
];
|
|
440
|
+
/**
|
|
441
|
+
* The hour list to save for one job: what the card holds, or the default.
|
|
442
|
+
*
|
|
443
|
+
* Mirrors the host's own fallback (`hoursOrDefault` in `scheduler.ts`). An
|
|
444
|
+
* empty list must resolve to the default on BOTH sides, or the card would save
|
|
445
|
+
* a schedule the scheduler then refuses to run — the exact silent standstill
|
|
446
|
+
* this pair of fixes exists to remove.
|
|
447
|
+
*/
|
|
448
|
+
function hoursOrDefault(configured, fallback) {
|
|
449
|
+
return configured !== void 0 && configured.length > 0 ? [...configured] : [...fallback];
|
|
450
|
+
}
|
|
380
451
|
/** Read one job's configured hours off the status document. */
|
|
381
452
|
function automationHours(status, kind) {
|
|
382
453
|
const automation = status.automation;
|
|
@@ -459,9 +530,21 @@ window.__ModuleLoader__.load({
|
|
|
459
530
|
const days = daysUntil(pack.expiresAtMs);
|
|
460
531
|
return days !== void 0 && days <= 3;
|
|
461
532
|
}
|
|
533
|
+
/**
|
|
534
|
+
* The promo badge for one model, or undefined when it has none.
|
|
535
|
+
*
|
|
536
|
+
* `free` is read off the CREDIT MULTIPLIER, not off a tag. Neither gateway ever
|
|
537
|
+
* sends a literal `free` tag: the global roster marks its zero-cost models
|
|
538
|
+
* (`hy3`, `hy4-preview-f`, `deepseek-v4.1-flash`) as `credits: "x0.00"`, so
|
|
539
|
+
* waiting for a tag meant the badge NEVER appeared — including on models that
|
|
540
|
+
* genuinely cost nothing.
|
|
541
|
+
*
|
|
542
|
+
* An explicit free-ish tag still wins when present, so a gateway that starts
|
|
543
|
+
* tagging them keeps working without another change.
|
|
544
|
+
*/
|
|
462
545
|
function tagFor(model) {
|
|
463
546
|
const tags = model.tags ?? [];
|
|
464
|
-
if (tags.includes("free")) return "free";
|
|
547
|
+
if (tags.includes("free") || model.multiplier === 0) return "free";
|
|
465
548
|
if (tags.includes("limited-free")) return "limited";
|
|
466
549
|
if (tags.includes("night-discount")) return "night";
|
|
467
550
|
}
|
|
@@ -470,7 +553,6 @@ window.__ModuleLoader__.load({
|
|
|
470
553
|
const settingsWritable = settingsScope?.getSnapshot().writable === true;
|
|
471
554
|
/** Which region tab is showing. A CN-only install never leaves this. */
|
|
472
555
|
const [activeRegion, setActiveRegion] = (0, react.useState)("cn");
|
|
473
|
-
const [open, setOpen] = (0, react.useState)(false);
|
|
474
556
|
/**
|
|
475
557
|
* Last-known status per region. Kept per region (not a single slot) so
|
|
476
558
|
* switching tabs shows the other side's last answer immediately instead of
|
|
@@ -568,7 +650,6 @@ window.__ModuleLoader__.load({
|
|
|
568
650
|
}
|
|
569
651
|
}, []);
|
|
570
652
|
(0, react.useEffect)(() => {
|
|
571
|
-
if (!open) return;
|
|
572
653
|
const controller = new AbortController();
|
|
573
654
|
refresh(activeRegion, controller.signal);
|
|
574
655
|
const timer = window.setInterval(() => {
|
|
@@ -578,11 +659,7 @@ window.__ModuleLoader__.load({
|
|
|
578
659
|
window.clearInterval(timer);
|
|
579
660
|
controller.abort();
|
|
580
661
|
};
|
|
581
|
-
}, [
|
|
582
|
-
open,
|
|
583
|
-
refresh,
|
|
584
|
-
activeRegion
|
|
585
|
-
]);
|
|
662
|
+
}, [refresh, activeRegion]);
|
|
586
663
|
const rescan = async () => {
|
|
587
664
|
setBusy(true);
|
|
588
665
|
setFlash(void 0);
|
|
@@ -679,6 +756,37 @@ window.__ModuleLoader__.load({
|
|
|
679
756
|
if (mounted.current) setAccountBusyId(void 0);
|
|
680
757
|
}
|
|
681
758
|
};
|
|
759
|
+
/**
|
|
760
|
+
* Throw one account out of the pool for good, or take it back.
|
|
761
|
+
*
|
|
762
|
+
* The host owns the ignore file, so this is a plain route call: no settings
|
|
763
|
+
* scope is involved, which is also why it keeps working on a profile whose
|
|
764
|
+
* settings section is read-only.
|
|
765
|
+
*/
|
|
766
|
+
const setAccountIgnored = async (accountId, ignored) => {
|
|
767
|
+
setAccountBusyId(accountId);
|
|
768
|
+
setFlash(void 0);
|
|
769
|
+
try {
|
|
770
|
+
const response = await fetch(POOL_ACCOUNT_IGNORE_PATH, {
|
|
771
|
+
method: "POST",
|
|
772
|
+
headers: { "Content-Type": "application/json" },
|
|
773
|
+
body: JSON.stringify({
|
|
774
|
+
accountId,
|
|
775
|
+
ignored
|
|
776
|
+
})
|
|
777
|
+
});
|
|
778
|
+
if (!response.ok) {
|
|
779
|
+
const detail = await response.json().catch(() => ({}));
|
|
780
|
+
throw new Error(detail.error ?? `HTTP ${response.status}`);
|
|
781
|
+
}
|
|
782
|
+
await refresh(activeRegion);
|
|
783
|
+
} catch (cause) {
|
|
784
|
+
const message = cause instanceof Error ? cause.message : String(cause);
|
|
785
|
+
if (mounted.current) setError(t?.("row.accountIgnoreError", { message }) ?? "Could not change the ignore list: " + message);
|
|
786
|
+
} finally {
|
|
787
|
+
if (mounted.current) setAccountBusyId(void 0);
|
|
788
|
+
}
|
|
789
|
+
};
|
|
682
790
|
/** Keep the draft in step with the server copy while nothing is dirty. */
|
|
683
791
|
const modelDraft = draft ?? (status === void 0 ? {} : draftFromStatus(status));
|
|
684
792
|
/** Model edits need a writable settings scope; otherwise the rows are read-only. */
|
|
@@ -782,12 +890,11 @@ window.__ModuleLoader__.load({
|
|
|
782
890
|
setFlash(void 0);
|
|
783
891
|
try {
|
|
784
892
|
await write.call(settingsScope, "automation", {
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
},
|
|
893
|
+
checkinHours: hoursOrDefault(existing?.checkinHours, DEFAULT_AUTOMATION_HOURS.checkin),
|
|
894
|
+
reportHours: hoursOrDefault(existing?.reportHours, DEFAULT_AUTOMATION_HOURS.report),
|
|
895
|
+
taskHours: hoursOrDefault(existing?.taskHours, DEFAULT_AUTOMATION_HOURS.tasks),
|
|
896
|
+
streakHours: hoursOrDefault(existing?.streakHours, DEFAULT_AUTOMATION_HOURS.streak),
|
|
897
|
+
travelHours: hoursOrDefault(existing?.travelHours, DEFAULT_AUTOMATION_HOURS.travel),
|
|
791
898
|
enabled
|
|
792
899
|
});
|
|
793
900
|
await refresh(activeRegion);
|
|
@@ -929,396 +1036,437 @@ window.__ModuleLoader__.load({
|
|
|
929
1036
|
const stateLabel = error !== void 0 ? t?.("row.requestFailed") ?? "Request failed" : accountCount === 0 ? t?.("row.regionEmpty") ?? t?.("row.poolEmpty") ?? "No account yet" : state === "ok" ? t?.("row.ok") ?? "Healthy" : t?.("row.allCooling") ?? "All cooling";
|
|
930
1037
|
const shimRunning = status?.shim.running === true;
|
|
931
1038
|
const shimHint = status === void 0 ? null : shimRunning ? `${t?.("row.shimRunning") ?? "Provider listening"}${status.shim.baseUrl === void 0 ? "" : ` · ${status.shim.baseUrl}`}` : t?.("row.shimStopped") ?? "Provider loopback not running";
|
|
932
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("
|
|
933
|
-
className:
|
|
934
|
-
children: [
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
"aria-expanded": open,
|
|
938
|
-
"aria-label": `${t?.(open ? "row.collapse" : "row.expand") ?? ""}: ${title}`,
|
|
939
|
-
onClick: () => {
|
|
940
|
-
setOpen(!open);
|
|
941
|
-
},
|
|
942
|
-
children: [
|
|
943
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
944
|
-
className: "dsm-plugin-card-icon",
|
|
945
|
-
src: POOL_PLUGIN_ICON,
|
|
946
|
-
alt: ""
|
|
947
|
-
}),
|
|
948
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
949
|
-
className: "dsm-plugin-card-head",
|
|
950
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
951
|
-
className: "dsm-plugin-card-title",
|
|
952
|
-
children: title
|
|
953
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
954
|
-
className: "dsm-plugin-card-description",
|
|
955
|
-
children: description
|
|
956
|
-
})]
|
|
957
|
-
}),
|
|
958
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
959
|
-
"aria-hidden": "true",
|
|
960
|
-
className: `dsm-plugin-card-chevron${open ? " dsm-plugin-card-chevron-open" : ""}`,
|
|
961
|
-
children: (0, react.createElement)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 14 })
|
|
962
|
-
})
|
|
963
|
-
]
|
|
964
|
-
}), open ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
965
|
-
className: "dsm-plugin-card-body",
|
|
966
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
967
|
-
className: "dsm-workbuddy-xdpool-usage",
|
|
1039
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1040
|
+
className: "dsm-workbuddy-xdpool-page",
|
|
1041
|
+
children: [
|
|
1042
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
1043
|
+
className: "dsm-workbuddy-xdpool-page-head",
|
|
968
1044
|
children: [
|
|
969
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
970
|
-
className: "dsm-workbuddy-xdpool-
|
|
971
|
-
|
|
972
|
-
|
|
1045
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
1046
|
+
className: "dsm-workbuddy-xdpool-page-icon",
|
|
1047
|
+
src: POOL_PLUGIN_ICON,
|
|
1048
|
+
alt: ""
|
|
1049
|
+
}),
|
|
1050
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1051
|
+
className: "dsm-workbuddy-xdpool-page-copy",
|
|
1052
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
1053
|
+
className: "dsm-workbuddy-xdpool-page-title",
|
|
1054
|
+
children: title
|
|
1055
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1056
|
+
className: "dsm-workbuddy-xdpool-page-desc",
|
|
1057
|
+
children: description
|
|
1058
|
+
})]
|
|
1059
|
+
}),
|
|
1060
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1061
|
+
className: "dsm-workbuddy-xdpool-page-actions",
|
|
1062
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
973
1063
|
type: "button",
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
className: `dsm-workbuddy-xdpool-tab${region === activeRegion ? " dsm-workbuddy-xdpool-tab-active" : ""}`,
|
|
1064
|
+
className: "dsm-btn dsm-btn-outline",
|
|
1065
|
+
disabled: busy,
|
|
977
1066
|
onClick: () => {
|
|
978
|
-
|
|
1067
|
+
rescan();
|
|
979
1068
|
},
|
|
980
|
-
children:
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
1069
|
+
children: busy ? t?.("row.accountsScanning") ?? "Detecting…" : t?.("row.accountsRescan") ?? "Detect accounts again"
|
|
1070
|
+
}), cooling > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1071
|
+
type: "button",
|
|
1072
|
+
className: "dsm-btn dsm-btn-outline",
|
|
1073
|
+
disabled: cooldownBusy,
|
|
1074
|
+
onClick: () => {
|
|
1075
|
+
resetCooldowns();
|
|
1076
|
+
},
|
|
1077
|
+
children: cooldownBusy ? t?.("row.resetCooldownsBusy") ?? "Clearing…" : t?.("row.resetCooldowns") ?? "Clear all cooldowns"
|
|
1078
|
+
}) : null]
|
|
1079
|
+
})
|
|
1080
|
+
]
|
|
1081
|
+
}),
|
|
1082
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1083
|
+
className: "dsm-workbuddy-xdpool-card dsm-workbuddy-xdpool-status",
|
|
1084
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1085
|
+
className: "dsm-workbuddy-xdpool-tabs",
|
|
1086
|
+
role: "tablist",
|
|
1087
|
+
children: status?.regions.map((region) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1088
|
+
type: "button",
|
|
1089
|
+
role: "tab",
|
|
1090
|
+
"aria-selected": region === activeRegion,
|
|
1091
|
+
className: `dsm-workbuddy-xdpool-tab${region === activeRegion ? " dsm-workbuddy-xdpool-tab-active" : ""}`,
|
|
1092
|
+
onClick: () => {
|
|
1093
|
+
setActiveRegion(region);
|
|
1094
|
+
},
|
|
1095
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1096
|
+
className: "dsm-workbuddy-xdpool-tab-dot",
|
|
1097
|
+
"data-state": state
|
|
1098
|
+
}), region === "cn" ? t?.("row.tabCn") ?? "CN" : t?.("row.tabGlobal") ?? "Global"]
|
|
1099
|
+
}, region))
|
|
1100
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1101
|
+
className: "dsm-workbuddy-xdpool-usage-head",
|
|
1102
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1103
|
+
className: "dsm-workbuddy-xdpool-usage-copy",
|
|
1104
|
+
role: "status",
|
|
1105
|
+
children: [
|
|
1106
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1107
|
+
className: "dsm-workbuddy-xdpool-usage-status",
|
|
1108
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1109
|
+
"aria-hidden": "true",
|
|
1110
|
+
className: "dsm-workbuddy-xdpool-usage-dot",
|
|
1111
|
+
style: { background: dotColor(state) }
|
|
1112
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: stateLabel })]
|
|
1113
|
+
}),
|
|
1114
|
+
accountCount > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1115
|
+
className: "dsm-workbuddy-xdpool-usage-hint",
|
|
1116
|
+
children: t?.("row.accountsSummary", {
|
|
1117
|
+
count: accountCount,
|
|
1118
|
+
cooling
|
|
1119
|
+
}) ?? `${accountCount} account(s) · ${cooling} cooling`
|
|
1120
|
+
}) : null,
|
|
1121
|
+
shimHint === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1122
|
+
className: "dsm-workbuddy-xdpool-usage-hint",
|
|
1123
|
+
children: shimHint
|
|
1124
|
+
}),
|
|
1125
|
+
status === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1126
|
+
className: "dsm-workbuddy-xdpool-dist",
|
|
1127
|
+
role: "radiogroup",
|
|
1128
|
+
"aria-label": t?.("row.distTitle") ?? "Account usage",
|
|
1129
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1130
|
+
className: "dsm-workbuddy-xdpool-dist-title",
|
|
1131
|
+
children: t?.("row.distTitle") ?? "Account usage"
|
|
1132
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1133
|
+
className: "dsm-workbuddy-xdpool-dist-options",
|
|
1134
|
+
children: [
|
|
1135
|
+
"priority",
|
|
1136
|
+
"balanced",
|
|
1137
|
+
"round-robin"
|
|
1138
|
+
].map((option) => {
|
|
1139
|
+
const active = (status.distribution ?? "priority") === option;
|
|
1140
|
+
const label = option === "priority" ? t?.("row.distPriority") ?? "Priority" : option === "balanced" ? t?.("row.distBalanced") ?? "Balanced" : t?.("row.distRoundRobin") ?? "Round-robin";
|
|
1141
|
+
const hint = option === "priority" ? t?.("row.distPriorityHint") ?? "" : option === "balanced" ? t?.("row.distBalancedHint") ?? "" : t?.("row.distRoundRobinHint") ?? "";
|
|
1142
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1143
|
+
type: "button",
|
|
1144
|
+
role: "radio",
|
|
1145
|
+
"aria-checked": active,
|
|
1146
|
+
title: hint,
|
|
1147
|
+
disabled: !modelsEditable,
|
|
1148
|
+
className: "dsm-workbuddy-xdpool-dist-option" + (active ? " dsm-workbuddy-xdpool-dist-option-active" : ""),
|
|
1149
|
+
onClick: () => {
|
|
1150
|
+
setDistribution(option);
|
|
1151
|
+
},
|
|
1152
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1153
|
+
className: "dsm-workbuddy-xdpool-dist-option-name",
|
|
1154
|
+
children: label
|
|
1155
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1156
|
+
className: "dsm-workbuddy-xdpool-dist-option-hint",
|
|
1157
|
+
children: hint
|
|
1158
|
+
})]
|
|
1159
|
+
}, option);
|
|
1160
|
+
})
|
|
1161
|
+
})]
|
|
1162
|
+
})
|
|
1163
|
+
]
|
|
1164
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1165
|
+
className: "dsm-workbuddy-xdpool-usage-actions",
|
|
1166
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1167
|
+
type: "button",
|
|
1168
|
+
className: "dsm-btn dsm-btn-outline",
|
|
1169
|
+
disabled: busy,
|
|
1170
|
+
onClick: () => {
|
|
1171
|
+
rescan();
|
|
1172
|
+
},
|
|
1173
|
+
children: busy ? t?.("row.accountsScanning") ?? "Detecting…" : t?.("row.accountsRescan") ?? "Detect accounts again"
|
|
1174
|
+
}), cooling > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1175
|
+
type: "button",
|
|
1176
|
+
className: "dsm-btn dsm-btn-outline",
|
|
1177
|
+
disabled: cooldownBusy,
|
|
1178
|
+
onClick: () => {
|
|
1179
|
+
resetCooldowns();
|
|
1180
|
+
},
|
|
1181
|
+
children: cooldownBusy ? t?.("row.resetCooldownsBusy") ?? "Clearing…" : t?.("row.resetCooldowns") ?? "Clear all cooldowns"
|
|
1182
|
+
}) : null]
|
|
1183
|
+
})]
|
|
1184
|
+
})]
|
|
1185
|
+
}),
|
|
1186
|
+
activeRegion !== "cn" || status?.automation === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1187
|
+
className: "dsm-workbuddy-xdpool-card dsm-workbuddy-xdpool-auto",
|
|
1188
|
+
"aria-label": t?.("row.autoTitle") ?? "Automation",
|
|
1189
|
+
children: [
|
|
986
1190
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
987
|
-
className: "dsm-workbuddy-xdpool-
|
|
988
|
-
children: [
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
995
|
-
"aria-hidden": "true",
|
|
996
|
-
className: "dsm-workbuddy-xdpool-usage-dot",
|
|
997
|
-
style: { background: dotColor(state) }
|
|
998
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: stateLabel })]
|
|
999
|
-
}),
|
|
1000
|
-
accountCount > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1001
|
-
className: "dsm-workbuddy-xdpool-usage-hint",
|
|
1002
|
-
children: t?.("row.accountsSummary", {
|
|
1003
|
-
count: accountCount,
|
|
1004
|
-
cooling
|
|
1005
|
-
}) ?? `${accountCount} account(s) · ${cooling} cooling`
|
|
1006
|
-
}) : null,
|
|
1007
|
-
shimHint === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1008
|
-
className: "dsm-workbuddy-xdpool-usage-hint",
|
|
1009
|
-
children: shimHint
|
|
1010
|
-
}),
|
|
1011
|
-
status === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1012
|
-
className: "dsm-workbuddy-xdpool-dist",
|
|
1013
|
-
role: "radiogroup",
|
|
1014
|
-
"aria-label": t?.("row.distTitle") ?? "Account usage",
|
|
1015
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1016
|
-
className: "dsm-workbuddy-xdpool-dist-title",
|
|
1017
|
-
children: t?.("row.distTitle") ?? "Account usage"
|
|
1018
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1019
|
-
className: "dsm-workbuddy-xdpool-dist-options",
|
|
1020
|
-
children: [
|
|
1021
|
-
"priority",
|
|
1022
|
-
"balanced",
|
|
1023
|
-
"round-robin"
|
|
1024
|
-
].map((option) => {
|
|
1025
|
-
const active = (status.distribution ?? "priority") === option;
|
|
1026
|
-
const label = option === "priority" ? t?.("row.distPriority") ?? "Priority" : option === "balanced" ? t?.("row.distBalanced") ?? "Balanced" : t?.("row.distRoundRobin") ?? "Round-robin";
|
|
1027
|
-
const hint = option === "priority" ? t?.("row.distPriorityHint") ?? "" : option === "balanced" ? t?.("row.distBalancedHint") ?? "" : t?.("row.distRoundRobinHint") ?? "";
|
|
1028
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1029
|
-
type: "button",
|
|
1030
|
-
role: "radio",
|
|
1031
|
-
"aria-checked": active,
|
|
1032
|
-
title: hint,
|
|
1033
|
-
disabled: !modelsEditable,
|
|
1034
|
-
className: "dsm-workbuddy-xdpool-dist-option" + (active ? " dsm-workbuddy-xdpool-dist-option-active" : ""),
|
|
1035
|
-
onClick: () => {
|
|
1036
|
-
setDistribution(option);
|
|
1037
|
-
},
|
|
1038
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1039
|
-
className: "dsm-workbuddy-xdpool-dist-option-name",
|
|
1040
|
-
children: label
|
|
1041
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1042
|
-
className: "dsm-workbuddy-xdpool-dist-option-hint",
|
|
1043
|
-
children: hint
|
|
1044
|
-
})]
|
|
1045
|
-
}, option);
|
|
1046
|
-
})
|
|
1047
|
-
})]
|
|
1048
|
-
})
|
|
1049
|
-
]
|
|
1050
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1051
|
-
className: "dsm-workbuddy-xdpool-usage-actions",
|
|
1052
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1191
|
+
className: "dsm-workbuddy-xdpool-auto-head",
|
|
1192
|
+
children: [
|
|
1193
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1194
|
+
className: "dsm-workbuddy-xdpool-auto-title",
|
|
1195
|
+
children: t?.("row.autoTitle") ?? "Automation"
|
|
1196
|
+
}),
|
|
1197
|
+
!status.automation.enabled ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1053
1198
|
type: "button",
|
|
1054
|
-
className: "dsm-btn dsm-btn-outline",
|
|
1055
|
-
disabled:
|
|
1199
|
+
className: "dsm-btn dsm-btn-outline dsm-workbuddy-xdpool-auto-run",
|
|
1200
|
+
disabled: automationRun !== void 0,
|
|
1056
1201
|
onClick: () => {
|
|
1057
|
-
|
|
1202
|
+
runAutomationJob();
|
|
1058
1203
|
},
|
|
1059
|
-
children:
|
|
1060
|
-
}),
|
|
1204
|
+
children: automationRun !== void 0 ? t?.("row.autoRunning") ?? "Running…" : t?.("row.autoRunAll") ?? "Run all now"
|
|
1205
|
+
}),
|
|
1206
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1061
1207
|
type: "button",
|
|
1062
|
-
|
|
1063
|
-
|
|
1208
|
+
role: "switch",
|
|
1209
|
+
"aria-checked": status.automation.enabled,
|
|
1210
|
+
disabled: !settingsWritable || automationBusy,
|
|
1211
|
+
className: `dsm-workbuddy-xdpool-auto-switch${status.automation.enabled ? " dsm-workbuddy-xdpool-auto-switch-on" : ""}`,
|
|
1064
1212
|
onClick: () => {
|
|
1065
|
-
|
|
1213
|
+
setAutomationEnabled(!status.automation.enabled);
|
|
1066
1214
|
},
|
|
1067
|
-
children:
|
|
1068
|
-
})
|
|
1215
|
+
children: automationBusy ? t?.("row.autoBusy") ?? "Saving…" : status.automation.enabled ? t?.("row.autoOn") ?? "On" : t?.("row.autoOff") ?? "Off"
|
|
1216
|
+
})
|
|
1217
|
+
]
|
|
1218
|
+
}),
|
|
1219
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1220
|
+
className: "dsm-workbuddy-xdpool-auto-hint",
|
|
1221
|
+
children: status.automation.enabled ? t?.("row.autoHintOn") ?? "Reports activity, claims task rewards and checks in once a day." : t?.("row.autoHintOff") ?? "Off: no background requests are made for you."
|
|
1222
|
+
}),
|
|
1223
|
+
automationTotals.credit === 0 && automationTotals.checkinCredit === 0 && automationTotals.bonusCredit === 0 && automationTotals.travelCredit === 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1224
|
+
className: "dsm-workbuddy-xdpool-auto-total",
|
|
1225
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1226
|
+
className: "dsm-workbuddy-xdpool-auto-total-label",
|
|
1227
|
+
children: t?.("row.autoToday") ?? "Today"
|
|
1228
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1229
|
+
className: "dsm-workbuddy-xdpool-auto-total-list",
|
|
1230
|
+
children: [
|
|
1231
|
+
automationTotals.credit > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1232
|
+
className: "dsm-workbuddy-xdpool-auto-total-row",
|
|
1233
|
+
children: t?.("row.autoFromTasks", {
|
|
1234
|
+
credit: automationTotals.credit,
|
|
1235
|
+
energy: automationTotals.energy,
|
|
1236
|
+
count: automationTotals.claimed
|
|
1237
|
+
}) ?? `Tasks +${automationTotals.credit}`
|
|
1238
|
+
}) : null,
|
|
1239
|
+
automationTotals.checkinCredit > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1240
|
+
className: "dsm-workbuddy-xdpool-auto-total-row",
|
|
1241
|
+
children: t?.("row.autoFromCheckin", { credit: automationTotals.checkinCredit }) ?? `Check-in +${automationTotals.checkinCredit}`
|
|
1242
|
+
}) : null,
|
|
1243
|
+
automationTotals.bonusCredit > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1244
|
+
className: "dsm-workbuddy-xdpool-auto-total-row",
|
|
1245
|
+
children: t?.("row.autoFromBonus", { credit: automationTotals.bonusCredit }) ?? `Streak +${automationTotals.bonusCredit}`
|
|
1246
|
+
}) : null,
|
|
1247
|
+
automationTotals.travelCredit > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1248
|
+
className: "dsm-workbuddy-xdpool-auto-total-row",
|
|
1249
|
+
children: t?.("row.autoFromTravel", { credit: automationTotals.travelCredit }) ?? `Buddy +${automationTotals.travelCredit}`
|
|
1250
|
+
}) : null
|
|
1251
|
+
]
|
|
1069
1252
|
})]
|
|
1070
1253
|
}),
|
|
1071
|
-
|
|
1072
|
-
className: "dsm-workbuddy-xdpool-auto",
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1254
|
+
status.automation.enabled ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1255
|
+
className: "dsm-workbuddy-xdpool-auto-jobs",
|
|
1256
|
+
children: AUTOMATION_JOBS.map((kind) => {
|
|
1257
|
+
const job = automationJob(status, kind);
|
|
1258
|
+
const hours = automationHours(status, kind);
|
|
1259
|
+
const label = t?.(`row.autoJob_${kind}`) ?? kind;
|
|
1260
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1261
|
+
className: "dsm-workbuddy-xdpool-auto-job",
|
|
1077
1262
|
children: [
|
|
1078
1263
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1079
|
-
className: "dsm-workbuddy-xdpool-auto-
|
|
1080
|
-
children:
|
|
1264
|
+
className: "dsm-workbuddy-xdpool-auto-job-name",
|
|
1265
|
+
children: label
|
|
1266
|
+
}),
|
|
1267
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1268
|
+
className: "dsm-workbuddy-xdpool-auto-job-when",
|
|
1269
|
+
children: hours.length === 0 ? t?.("row.autoHourNone") ?? "not scheduled" : hours.map((hour) => `${String(hour).padStart(2, "0")}:00`).join(" · ")
|
|
1270
|
+
}),
|
|
1271
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1272
|
+
className: "dsm-workbuddy-xdpool-auto-job-last",
|
|
1273
|
+
children: job?.lastRunDate === void 0 ? t?.("row.autoNever") ?? "not run yet" : `${job.lastRunDate} · ${job.ok}${job.failed > 0 ? `/${job.failed}` : ""}`
|
|
1081
1274
|
}),
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
disabled: automationRun !== void 0,
|
|
1086
|
-
onClick: () => {
|
|
1087
|
-
runAutomationJob();
|
|
1088
|
-
},
|
|
1089
|
-
children: automationRun !== void 0 ? t?.("row.autoRunning") ?? "Running…" : t?.("row.autoRunAll") ?? "Run all now"
|
|
1275
|
+
job?.progress === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1276
|
+
className: "dsm-workbuddy-xdpool-auto-job-note",
|
|
1277
|
+
children: job.progress
|
|
1090
1278
|
}),
|
|
1091
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
"aria-checked": status.automation.enabled,
|
|
1095
|
-
disabled: !settingsWritable || automationBusy,
|
|
1096
|
-
className: `dsm-workbuddy-xdpool-auto-switch${status.automation.enabled ? " dsm-workbuddy-xdpool-auto-switch-on" : ""}`,
|
|
1097
|
-
onClick: () => {
|
|
1098
|
-
setAutomationEnabled(!status.automation.enabled);
|
|
1099
|
-
},
|
|
1100
|
-
children: automationBusy ? t?.("row.autoBusy") ?? "Saving…" : status.automation.enabled ? t?.("row.autoOn") ?? "On" : t?.("row.autoOff") ?? "Off"
|
|
1279
|
+
job?.detail === void 0 || job.detail.length === 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1280
|
+
className: "dsm-workbuddy-xdpool-auto-job-detail",
|
|
1281
|
+
children: job.detail.join(" · ")
|
|
1101
1282
|
})
|
|
1102
1283
|
]
|
|
1103
|
-
})
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
}) ?? `Tasks +${automationTotals.credit}`
|
|
1123
|
-
}) : null,
|
|
1124
|
-
automationTotals.checkinCredit > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1125
|
-
className: "dsm-workbuddy-xdpool-auto-total-row",
|
|
1126
|
-
children: t?.("row.autoFromCheckin", { credit: automationTotals.checkinCredit }) ?? `Check-in +${automationTotals.checkinCredit}`
|
|
1127
|
-
}) : null,
|
|
1128
|
-
automationTotals.bonusCredit > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1129
|
-
className: "dsm-workbuddy-xdpool-auto-total-row",
|
|
1130
|
-
children: t?.("row.autoFromBonus", { credit: automationTotals.bonusCredit }) ?? `Streak +${automationTotals.bonusCredit}`
|
|
1131
|
-
}) : null,
|
|
1132
|
-
automationTotals.travelCredit > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1133
|
-
className: "dsm-workbuddy-xdpool-auto-total-row",
|
|
1134
|
-
children: t?.("row.autoFromTravel", { credit: automationTotals.travelCredit }) ?? `Buddy +${automationTotals.travelCredit}`
|
|
1135
|
-
}) : null
|
|
1136
|
-
]
|
|
1137
|
-
})]
|
|
1138
|
-
}),
|
|
1139
|
-
status.automation.enabled ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1140
|
-
className: "dsm-workbuddy-xdpool-auto-jobs",
|
|
1141
|
-
children: AUTOMATION_JOBS.map((kind) => {
|
|
1142
|
-
const job = automationJob(status, kind);
|
|
1143
|
-
const hours = automationHours(status, kind);
|
|
1144
|
-
const label = t?.(`row.autoJob_${kind}`) ?? kind;
|
|
1145
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1146
|
-
className: "dsm-workbuddy-xdpool-auto-job",
|
|
1147
|
-
children: [
|
|
1148
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1149
|
-
className: "dsm-workbuddy-xdpool-auto-job-name",
|
|
1150
|
-
children: label
|
|
1151
|
-
}),
|
|
1152
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1153
|
-
className: "dsm-workbuddy-xdpool-auto-job-when",
|
|
1154
|
-
children: hours.length === 0 ? t?.("row.autoHourNone") ?? "not scheduled" : hours.map((hour) => `${String(hour).padStart(2, "0")}:00`).join(" · ")
|
|
1155
|
-
}),
|
|
1156
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1157
|
-
className: "dsm-workbuddy-xdpool-auto-job-last",
|
|
1158
|
-
children: job?.lastRunDate === void 0 ? t?.("row.autoNever") ?? "not run yet" : `${job.lastRunDate} · ${job.ok}${job.failed > 0 ? `/${job.failed}` : ""}`
|
|
1159
|
-
}),
|
|
1160
|
-
job?.progress === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1161
|
-
className: "dsm-workbuddy-xdpool-auto-job-note",
|
|
1162
|
-
children: job.progress
|
|
1163
|
-
}),
|
|
1164
|
-
job?.detail === void 0 || job.detail.length === 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1165
|
-
className: "dsm-workbuddy-xdpool-auto-job-detail",
|
|
1166
|
-
children: job.detail.join(" · ")
|
|
1167
|
-
})
|
|
1168
|
-
]
|
|
1169
|
-
}, kind);
|
|
1170
|
-
})
|
|
1171
|
-
}) : null
|
|
1172
|
-
]
|
|
1173
|
-
}),
|
|
1174
|
-
flash === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1175
|
-
className: "dsm-workbuddy-xdpool-note",
|
|
1176
|
-
children: flash
|
|
1284
|
+
}, kind);
|
|
1285
|
+
})
|
|
1286
|
+
}) : null
|
|
1287
|
+
]
|
|
1288
|
+
}),
|
|
1289
|
+
flash === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1290
|
+
className: "dsm-workbuddy-xdpool-note",
|
|
1291
|
+
children: flash
|
|
1292
|
+
}),
|
|
1293
|
+
error === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1294
|
+
className: "dsm-workbuddy-xdpool-error",
|
|
1295
|
+
children: t?.("row.error", { message: error }) ?? `Pool status unavailable: ${error}`
|
|
1296
|
+
}),
|
|
1297
|
+
accountCount === 0 && error === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1298
|
+
className: "dsm-workbuddy-xdpool-card dsm-workbuddy-xdpool-empty",
|
|
1299
|
+
children: [
|
|
1300
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1301
|
+
className: "dsm-workbuddy-xdpool-empty-title",
|
|
1302
|
+
children: t?.("row.regionEmptyTitle", { region: regionLabel }) ?? t?.("row.regionEmpty") ?? "No account yet"
|
|
1177
1303
|
}),
|
|
1178
|
-
|
|
1179
|
-
className: "dsm-workbuddy-xdpool-
|
|
1180
|
-
children:
|
|
1304
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1305
|
+
className: "dsm-workbuddy-xdpool-empty-steps",
|
|
1306
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1307
|
+
className: "dsm-workbuddy-xdpool-empty-steps-title",
|
|
1308
|
+
children: t?.("row.regionHowToTitle", { region: regionLabel }) ?? `How to sign in to the ${regionLabel} version`
|
|
1309
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ol", {
|
|
1310
|
+
className: "dsm-workbuddy-xdpool-empty-list",
|
|
1311
|
+
children: [
|
|
1312
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: t?.("row.regionHowTo1") ?? "" }),
|
|
1313
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: t?.("row.regionHowTo2") ?? "" }),
|
|
1314
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: t?.("row.regionHowTo3") ?? "" }),
|
|
1315
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: t?.("row.regionHowTo4") ?? "" })
|
|
1316
|
+
]
|
|
1317
|
+
})]
|
|
1181
1318
|
}),
|
|
1182
|
-
|
|
1183
|
-
className: "dsm-workbuddy-xdpool-empty",
|
|
1184
|
-
children:
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
}),
|
|
1204
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1205
|
-
className: "dsm-workbuddy-xdpool-empty-note",
|
|
1206
|
-
children: t?.("row.regionHowToNote") ?? ""
|
|
1207
|
-
})
|
|
1208
|
-
]
|
|
1209
|
-
}) : null,
|
|
1210
|
-
accountCount > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1211
|
-
className: "dsm-workbuddy-xdpool-accounts",
|
|
1212
|
-
"aria-label": t?.("row.accountsTitle") ?? "Accounts",
|
|
1213
|
-
children: [
|
|
1214
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1215
|
-
className: "dsm-workbuddy-xdpool-accounts-head",
|
|
1216
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
1217
|
-
className: "dsm-workbuddy-xdpool-accounts-title",
|
|
1218
|
-
children: t?.("row.accountsTitle") ?? "Accounts in the pool"
|
|
1219
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1220
|
-
className: "dsm-workbuddy-xdpool-accounts-summary",
|
|
1221
|
-
children: t?.("row.accountsSummary", {
|
|
1222
|
-
count: accountCount,
|
|
1223
|
-
cooling
|
|
1224
|
-
}) ?? `${accountCount} account(s) · ${cooling} cooling`
|
|
1225
|
-
})]
|
|
1226
|
-
}),
|
|
1227
|
-
(() => {
|
|
1228
|
-
const active = status?.activeAccountId === void 0 ? void 0 : status.accounts.find((account) => account.id === status.activeAccountId);
|
|
1229
|
-
if (active === void 0) return null;
|
|
1230
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1231
|
-
className: "dsm-workbuddy-xdpool-current",
|
|
1232
|
-
children: [
|
|
1233
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "dsm-workbuddy-xdpool-current-dot" }),
|
|
1234
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1235
|
-
className: "dsm-workbuddy-xdpool-current-label",
|
|
1236
|
-
children: t?.("row.currentAccount") ?? "In use now"
|
|
1237
|
-
}),
|
|
1238
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1239
|
-
className: "dsm-workbuddy-xdpool-current-name",
|
|
1240
|
-
children: active.label
|
|
1241
|
-
}),
|
|
1242
|
-
active.disabled === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1243
|
-
className: "dsm-workbuddy-xdpool-current-note",
|
|
1244
|
-
children: t?.("row.currentAccountDisabled") ?? "disabled — will switch on the next request"
|
|
1245
|
-
}) : null
|
|
1246
|
-
]
|
|
1247
|
-
});
|
|
1248
|
-
})(),
|
|
1249
|
-
status?.accounts.map((account) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountBlock, {
|
|
1250
|
-
account,
|
|
1251
|
-
...checkinBusyId === void 0 ? {} : { checkinBusyId },
|
|
1252
|
-
onClaimCheckin: (accountId) => {
|
|
1253
|
-
claimCheckin(accountId);
|
|
1254
|
-
},
|
|
1255
|
-
onSaveCreditReserve: (accountId, reserve) => saveCreditReserve(accountId, reserve),
|
|
1256
|
-
onToggleDisabled: (accountId, disabled) => {
|
|
1257
|
-
toggleAccountDisabled(accountId, disabled);
|
|
1258
|
-
},
|
|
1259
|
-
...accountBusyId === void 0 ? {} : { accountBusyId },
|
|
1260
|
-
t
|
|
1261
|
-
}, account.id))
|
|
1262
|
-
]
|
|
1263
|
-
}) : null,
|
|
1264
|
-
(status?.models.length ?? 0) > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1265
|
-
className: "dsm-workbuddy-xdpool-models",
|
|
1266
|
-
"aria-label": t?.("row.modelsTitle") ?? "Models",
|
|
1267
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1268
|
-
className: "dsm-workbuddy-xdpool-models-head",
|
|
1269
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1270
|
-
className: "dsm-workbuddy-xdpool-models-heading",
|
|
1271
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
1272
|
-
className: "dsm-workbuddy-xdpool-models-title",
|
|
1273
|
-
children: t?.("row.modelsTitle") ?? "Models"
|
|
1274
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1275
|
-
className: "dsm-workbuddy-xdpool-models-summary",
|
|
1276
|
-
children: t?.("row.modelsEnabledCount", {
|
|
1277
|
-
enabled: enabledCount,
|
|
1278
|
-
total: status?.models.length ?? 0
|
|
1279
|
-
}) ?? `${enabledCount} / ${status?.models.length ?? 0} enabled`
|
|
1280
|
-
})]
|
|
1281
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1282
|
-
className: "dsm-workbuddy-xdpool-models-actions",
|
|
1283
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1284
|
-
type: "button",
|
|
1285
|
-
className: "dsm-btn dsm-btn-outline",
|
|
1286
|
-
disabled: !modelsDirty || savingModels,
|
|
1287
|
-
onClick: discardModels,
|
|
1288
|
-
children: t?.("row.modelsDiscard") ?? "Discard"
|
|
1289
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1290
|
-
type: "button",
|
|
1291
|
-
className: "dsm-btn dsm-btn-primary",
|
|
1292
|
-
disabled: !modelsDirty || savingModels || enabledCount === 0,
|
|
1293
|
-
onClick: () => {
|
|
1294
|
-
saveModels();
|
|
1295
|
-
},
|
|
1296
|
-
children: savingModels ? t?.("row.modelsSaving") ?? "Saving…" : t?.("row.modelsSave") ?? "Save"
|
|
1297
|
-
})]
|
|
1298
|
-
})]
|
|
1299
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1300
|
-
className: "dsm-workbuddy-xdpool-model-list",
|
|
1301
|
-
children: status?.models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelRow, {
|
|
1302
|
-
model,
|
|
1303
|
-
t,
|
|
1304
|
-
draft: modelDraft[model.id] ?? {
|
|
1305
|
-
enabled: model.enabled,
|
|
1306
|
-
images: model.supportsImages
|
|
1307
|
-
},
|
|
1308
|
-
editable: modelsEditable,
|
|
1309
|
-
onToggle: toggleModel,
|
|
1310
|
-
onToggleImage: toggleModelImage,
|
|
1311
|
-
onBudget: setModelBudget
|
|
1312
|
-
}, model.id))
|
|
1319
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1320
|
+
className: "dsm-workbuddy-xdpool-empty-note",
|
|
1321
|
+
children: t?.("row.regionHowToNote") ?? ""
|
|
1322
|
+
})
|
|
1323
|
+
]
|
|
1324
|
+
}) : null,
|
|
1325
|
+
accountCount > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1326
|
+
className: "dsm-workbuddy-xdpool-card dsm-workbuddy-xdpool-accounts",
|
|
1327
|
+
"aria-label": t?.("row.accountsTitle") ?? "Accounts",
|
|
1328
|
+
children: [
|
|
1329
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1330
|
+
className: "dsm-workbuddy-xdpool-accounts-head",
|
|
1331
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
1332
|
+
className: "dsm-workbuddy-xdpool-accounts-title",
|
|
1333
|
+
children: t?.("row.accountsTitle") ?? "Accounts in the pool"
|
|
1334
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1335
|
+
className: "dsm-workbuddy-xdpool-accounts-summary",
|
|
1336
|
+
children: t?.("row.accountsSummary", {
|
|
1337
|
+
count: accountCount,
|
|
1338
|
+
cooling
|
|
1339
|
+
}) ?? `${accountCount} account(s) · ${cooling} cooling`
|
|
1313
1340
|
})]
|
|
1314
|
-
})
|
|
1341
|
+
}),
|
|
1342
|
+
(() => {
|
|
1343
|
+
const active = status?.activeAccountId === void 0 ? void 0 : status.accounts.find((account) => account.id === status.activeAccountId);
|
|
1344
|
+
if (active === void 0) return null;
|
|
1345
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1346
|
+
className: "dsm-workbuddy-xdpool-current",
|
|
1347
|
+
children: [
|
|
1348
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "dsm-workbuddy-xdpool-current-dot" }),
|
|
1349
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1350
|
+
className: "dsm-workbuddy-xdpool-current-label",
|
|
1351
|
+
children: t?.("row.currentAccount") ?? "In use now"
|
|
1352
|
+
}),
|
|
1353
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1354
|
+
className: "dsm-workbuddy-xdpool-current-name",
|
|
1355
|
+
children: active.label
|
|
1356
|
+
}),
|
|
1357
|
+
active.disabled === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1358
|
+
className: "dsm-workbuddy-xdpool-current-note",
|
|
1359
|
+
children: t?.("row.currentAccountDisabled") ?? "disabled — will switch on the next request"
|
|
1360
|
+
}) : null
|
|
1361
|
+
]
|
|
1362
|
+
});
|
|
1363
|
+
})(),
|
|
1364
|
+
status?.accounts.map((account) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountBlock, {
|
|
1365
|
+
account,
|
|
1366
|
+
...checkinBusyId === void 0 ? {} : { checkinBusyId },
|
|
1367
|
+
onClaimCheckin: (accountId) => {
|
|
1368
|
+
claimCheckin(accountId);
|
|
1369
|
+
},
|
|
1370
|
+
onSaveCreditReserve: (accountId, reserve) => saveCreditReserve(accountId, reserve),
|
|
1371
|
+
onToggleDisabled: (accountId, disabled) => {
|
|
1372
|
+
toggleAccountDisabled(accountId, disabled);
|
|
1373
|
+
},
|
|
1374
|
+
onIgnoreAccount: (accountId) => {
|
|
1375
|
+
setAccountIgnored(accountId, true);
|
|
1376
|
+
},
|
|
1377
|
+
...accountBusyId === void 0 ? {} : { accountBusyId },
|
|
1378
|
+
t
|
|
1379
|
+
}, account.id))
|
|
1315
1380
|
]
|
|
1316
|
-
})
|
|
1317
|
-
|
|
1381
|
+
}) : null,
|
|
1382
|
+
(status?.ignored.length ?? 0) > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1383
|
+
className: "dsm-workbuddy-xdpool-card dsm-workbuddy-xdpool-ignored",
|
|
1384
|
+
"aria-label": t?.("row.ignoredTitle") ?? "Removed accounts",
|
|
1385
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1386
|
+
className: "dsm-workbuddy-xdpool-ignored-head",
|
|
1387
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
1388
|
+
className: "dsm-workbuddy-xdpool-ignored-title",
|
|
1389
|
+
children: t?.("row.ignoredTitle") ?? "Removed accounts"
|
|
1390
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1391
|
+
className: "dsm-workbuddy-xdpool-ignored-summary",
|
|
1392
|
+
children: t?.("row.ignoredSummary", { count: status?.ignored.length ?? 0 }) ?? `${status?.ignored.length ?? 0} account(s) no longer in the pool`
|
|
1393
|
+
})]
|
|
1394
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1395
|
+
className: "dsm-workbuddy-xdpool-ignored-list",
|
|
1396
|
+
children: (status?.ignored ?? []).map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1397
|
+
className: "dsm-workbuddy-xdpool-ignored-row",
|
|
1398
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1399
|
+
className: "dsm-workbuddy-xdpool-ignored-label",
|
|
1400
|
+
children: entry.label
|
|
1401
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1402
|
+
type: "button",
|
|
1403
|
+
className: "dsm-workbuddy-xdpool-ignored-restore",
|
|
1404
|
+
title: t?.("row.ignoredRestoreHint") ?? "Put this account back into the pool",
|
|
1405
|
+
disabled: accountBusyId === entry.id,
|
|
1406
|
+
onClick: () => {
|
|
1407
|
+
setAccountIgnored(entry.id, false);
|
|
1408
|
+
},
|
|
1409
|
+
children: t?.("row.ignoredRestore") ?? "Restore"
|
|
1410
|
+
})]
|
|
1411
|
+
}, entry.id))
|
|
1412
|
+
})]
|
|
1413
|
+
}) : null,
|
|
1414
|
+
(status?.models.length ?? 0) > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1415
|
+
className: "dsm-workbuddy-xdpool-card dsm-workbuddy-xdpool-models",
|
|
1416
|
+
"aria-label": t?.("row.modelsTitle") ?? "Models",
|
|
1417
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1418
|
+
className: "dsm-workbuddy-xdpool-models-head",
|
|
1419
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1420
|
+
className: "dsm-workbuddy-xdpool-models-heading",
|
|
1421
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
1422
|
+
className: "dsm-workbuddy-xdpool-models-title",
|
|
1423
|
+
children: t?.("row.modelsTitle") ?? "Models"
|
|
1424
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1425
|
+
className: "dsm-workbuddy-xdpool-models-summary",
|
|
1426
|
+
children: t?.("row.modelsEnabledCount", {
|
|
1427
|
+
enabled: enabledCount,
|
|
1428
|
+
total: status?.models.length ?? 0
|
|
1429
|
+
}) ?? `${enabledCount} / ${status?.models.length ?? 0} enabled`
|
|
1430
|
+
})]
|
|
1431
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1432
|
+
className: "dsm-workbuddy-xdpool-models-actions",
|
|
1433
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1434
|
+
type: "button",
|
|
1435
|
+
className: "dsm-btn dsm-btn-outline",
|
|
1436
|
+
disabled: !modelsDirty || savingModels,
|
|
1437
|
+
onClick: discardModels,
|
|
1438
|
+
children: t?.("row.modelsDiscard") ?? "Discard"
|
|
1439
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1440
|
+
type: "button",
|
|
1441
|
+
className: "dsm-btn dsm-btn-primary",
|
|
1442
|
+
disabled: !modelsDirty || savingModels || enabledCount === 0,
|
|
1443
|
+
onClick: () => {
|
|
1444
|
+
saveModels();
|
|
1445
|
+
},
|
|
1446
|
+
children: savingModels ? t?.("row.modelsSaving") ?? "Saving…" : t?.("row.modelsSave") ?? "Save"
|
|
1447
|
+
})]
|
|
1448
|
+
})]
|
|
1449
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1450
|
+
className: "dsm-workbuddy-xdpool-model-list",
|
|
1451
|
+
children: status?.models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelRow, {
|
|
1452
|
+
model,
|
|
1453
|
+
t,
|
|
1454
|
+
draft: modelDraft[model.id] ?? {
|
|
1455
|
+
enabled: model.enabled,
|
|
1456
|
+
images: model.supportsImages
|
|
1457
|
+
},
|
|
1458
|
+
editable: modelsEditable,
|
|
1459
|
+
onToggle: toggleModel,
|
|
1460
|
+
onToggleImage: toggleModelImage,
|
|
1461
|
+
onBudget: setModelBudget
|
|
1462
|
+
}, model.id))
|
|
1463
|
+
})]
|
|
1464
|
+
}) : null
|
|
1465
|
+
]
|
|
1318
1466
|
});
|
|
1319
1467
|
}
|
|
1320
1468
|
/** One account block: label + status tag + meta + optional credit panels. */
|
|
1321
|
-
function AccountBlock({ account, t, checkinBusyId, onClaimCheckin, accountBusyId, onToggleDisabled, onSaveCreditReserve, reserveBusyId }) {
|
|
1469
|
+
function AccountBlock({ account, t, checkinBusyId, onClaimCheckin, accountBusyId, onToggleDisabled, onIgnoreAccount, onSaveCreditReserve, reserveBusyId }) {
|
|
1322
1470
|
const isDisabled = account.disabled === true;
|
|
1323
1471
|
const isCooling = account.cooling === true;
|
|
1324
1472
|
const cooldownUntil = account.cooldownUntil !== void 0 ? Date.parse(account.cooldownUntil) : void 0;
|
|
@@ -1351,6 +1499,16 @@ window.__ModuleLoader__.load({
|
|
|
1351
1499
|
onToggleDisabled(account.id, !isDisabled);
|
|
1352
1500
|
},
|
|
1353
1501
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "dsm-workbuddy-xdpool-account-toggle-dot" }), isDisabled ? t?.("row.accountOff") ?? "Disabled" : t?.("row.accountInRotation") ?? "Enabled"]
|
|
1502
|
+
}),
|
|
1503
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1504
|
+
type: "button",
|
|
1505
|
+
className: "dsm-workbuddy-xdpool-account-ignore",
|
|
1506
|
+
title: t?.("row.accountIgnoreHint") ?? "Remove this account from the pool for good",
|
|
1507
|
+
disabled: accountBusyId === account.id,
|
|
1508
|
+
onClick: () => {
|
|
1509
|
+
onIgnoreAccount(account.id);
|
|
1510
|
+
},
|
|
1511
|
+
children: t?.("row.accountIgnore") ?? "Remove"
|
|
1354
1512
|
})
|
|
1355
1513
|
]
|
|
1356
1514
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -1668,7 +1826,7 @@ window.__ModuleLoader__.load({
|
|
|
1668
1826
|
className: "dsm-workbuddy-xdpool-model-copy",
|
|
1669
1827
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1670
1828
|
className: "dsm-workbuddy-xdpool-model-name",
|
|
1671
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model.name }), model.multiplier === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1829
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: model.name }), model.multiplier === void 0 || model.multiplier === 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1672
1830
|
className: "dsm-workbuddy-xdpool-model-name-rate",
|
|
1673
1831
|
children: t?.("row.rate", { rate: model.multiplier.toFixed(2) }) ?? `${model.multiplier.toFixed(2)}x`
|
|
1674
1832
|
})]
|
|
@@ -1732,6 +1890,50 @@ window.__ModuleLoader__.load({
|
|
|
1732
1890
|
});
|
|
1733
1891
|
}
|
|
1734
1892
|
//#endregion
|
|
1893
|
+
//#region src/client/nav-icon.ts
|
|
1894
|
+
/**
|
|
1895
|
+
* Nav glyph for the WorkBuddy XD Pool settings page.
|
|
1896
|
+
*
|
|
1897
|
+
* The host's settings shell draws its own 16px `svg` in every nav row and the
|
|
1898
|
+
* `settings.section` registration contract projects only `id` / `order` /
|
|
1899
|
+
* `label` — there is no `icon` field to pass. A third-party page therefore has
|
|
1900
|
+
* to mark its row in the DOM and mask this artwork over the shell's glyph, the
|
|
1901
|
+
* same technique `dshmarket` uses (`installSettingsNavIcon`).
|
|
1902
|
+
*
|
|
1903
|
+
* Kept as a single monochrome path so `mask-image` + `currentColor` can tint it
|
|
1904
|
+
* with whatever the active theme uses for nav text: a filled mask cannot carry
|
|
1905
|
+
* its own palette, and a two-tone icon would render as a flat silhouette.
|
|
1906
|
+
*
|
|
1907
|
+
* @module dsh-workbuddy-xdpool/client/nav-icon
|
|
1908
|
+
*/
|
|
1909
|
+
/**
|
|
1910
|
+
* The nav mark: a stack of three rounded "accounts" under a rotation arc.
|
|
1911
|
+
*
|
|
1912
|
+
* Reads as "a pool of accounts being cycled" at 16px, and — unlike a literal
|
|
1913
|
+
* droplet or cloud — stays legible when reduced to a single-color silhouette.
|
|
1914
|
+
* `fill-rule="evenodd"` cuts the interior notches out of the silhouette so the
|
|
1915
|
+
* three layers stay distinguishable at that size.
|
|
1916
|
+
*/
|
|
1917
|
+
const POOL_NAV_ICON_SVG = [
|
|
1918
|
+
"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"16\" height=\"16\">",
|
|
1919
|
+
"<path fill=\"currentColor\" fill-rule=\"evenodd\" d=\"",
|
|
1920
|
+
"M12 2.6a3.1 3.1 0 1 1 0 6.2 3.1 3.1 0 0 1 0-6.2Zm0 1.7a1.4 1.4 0 1 0 0 2.8 1.4 1.4 0 0 0 0-2.8Z",
|
|
1921
|
+
"M6.6 8.9a2.6 2.6 0 1 1 0 5.2 2.6 2.6 0 0 1 0-5.2Zm0 1.6a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z",
|
|
1922
|
+
"M17.4 8.9a2.6 2.6 0 1 1 0 5.2 2.6 2.6 0 0 1 0-5.2Zm0 1.6a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z",
|
|
1923
|
+
"\"/>",
|
|
1924
|
+
"<path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.7\" stroke-linecap=\"round\"",
|
|
1925
|
+
" d=\"M4.4 17.2a8.6 8.6 0 0 0 15.2 0\" stroke-dasharray=\"2.6 2.2\"/>",
|
|
1926
|
+
"</svg>"
|
|
1927
|
+
].join("");
|
|
1928
|
+
/**
|
|
1929
|
+
* The same artwork as a `mask-image` URL.
|
|
1930
|
+
*
|
|
1931
|
+
* `encodeURIComponent` keeps the `#`-free markup safe inside a `url("…")` in a
|
|
1932
|
+
* stylesheet, and `currentColor` is resolved by the mask's own element rather
|
|
1933
|
+
* than by the SVG, so the glyph follows the theme.
|
|
1934
|
+
*/
|
|
1935
|
+
const POOL_NAV_ICON_MASK_URL = `data:image/svg+xml;utf8,${encodeURIComponent(POOL_NAV_ICON_SVG)}`;
|
|
1936
|
+
//#endregion
|
|
1735
1937
|
//#region src/client/locales.ts
|
|
1736
1938
|
/**
|
|
1737
1939
|
* Plugin-card copy registered under the `settings.workbuddy-xdpool` locale
|
|
@@ -1741,6 +1943,7 @@ window.__ModuleLoader__.load({
|
|
|
1741
1943
|
* @module dsh-workbuddy-xdpool/client/locales
|
|
1742
1944
|
*/
|
|
1743
1945
|
const en = {
|
|
1946
|
+
"row.navLabel": "XD Pool",
|
|
1744
1947
|
"row.title": "WorkBuddy XD Pool (dsh-workbuddy-xdpool)",
|
|
1745
1948
|
"row.desc": "Route every WorkBuddy sign-in on this machine into DSH as one auto-failing-over model pool.",
|
|
1746
1949
|
"row.expand": "Expand",
|
|
@@ -1770,6 +1973,13 @@ window.__ModuleLoader__.load({
|
|
|
1770
1973
|
"row.accountOff": "Disabled",
|
|
1771
1974
|
"row.accountToggleHint": "Enable this account (uncheck to keep it out of the pool)",
|
|
1772
1975
|
"row.accountToggleError": "Could not switch the account: {message}",
|
|
1976
|
+
"row.accountIgnore": "Remove",
|
|
1977
|
+
"row.accountIgnoreHint": "Remove this account from the pool for good — its credential stops being read and it will not come back",
|
|
1978
|
+
"row.accountIgnoreError": "Could not change the ignore list: {message}",
|
|
1979
|
+
"row.ignoredTitle": "Removed accounts",
|
|
1980
|
+
"row.ignoredSummary": "{count} account(s) no longer in the pool",
|
|
1981
|
+
"row.ignoredRestore": "Restore",
|
|
1982
|
+
"row.ignoredRestoreHint": "Put this account back into the pool",
|
|
1773
1983
|
"row.currentAccount": "In use now",
|
|
1774
1984
|
"row.currentAccountDisabled": "switched off — the next request moves on",
|
|
1775
1985
|
"row.cooling": "Cooling (rate-limited)",
|
|
@@ -1872,6 +2082,7 @@ window.__ModuleLoader__.load({
|
|
|
1872
2082
|
"row.autoFromTravel": "Buddy travel +{credit} credits"
|
|
1873
2083
|
};
|
|
1874
2084
|
const zh = {
|
|
2085
|
+
"row.navLabel": "XD Pool",
|
|
1875
2086
|
"row.title": "WorkBuddy 池(dsh-workbuddy-xdpool)",
|
|
1876
2087
|
"row.desc": "把本机所有已登录的 WorkBuddy 账号并入 DSH,作为一个自动容错的模型池使用。",
|
|
1877
2088
|
"row.expand": "展开",
|
|
@@ -1901,6 +2112,13 @@ window.__ModuleLoader__.load({
|
|
|
1901
2112
|
"row.accountOff": "已停用",
|
|
1902
2113
|
"row.accountToggleHint": "启用该账号(取消勾选则不参与池子)",
|
|
1903
2114
|
"row.accountToggleError": "切换账号失败:{message}",
|
|
2115
|
+
"row.accountIgnore": "移出池子",
|
|
2116
|
+
"row.accountIgnoreHint": "把这个账号永久移出池子 —— 不再读取它的凭据,即使重新登录也不会回来",
|
|
2117
|
+
"row.accountIgnoreError": "修改忽略列表失败:{message}",
|
|
2118
|
+
"row.ignoredTitle": "已移出的账号",
|
|
2119
|
+
"row.ignoredSummary": "{count} 个账号已不在池中",
|
|
2120
|
+
"row.ignoredRestore": "恢复",
|
|
2121
|
+
"row.ignoredRestoreHint": "把这个账号放回池子",
|
|
1904
2122
|
"row.currentAccount": "当前使用",
|
|
1905
2123
|
"row.currentAccountDisabled": "已停用 —— 下次请求会换号",
|
|
1906
2124
|
"row.cooling": "冷却中(被限流)",
|
|
@@ -2006,13 +2224,26 @@ window.__ModuleLoader__.load({
|
|
|
2006
2224
|
//#region src/client/index.tsx
|
|
2007
2225
|
/** Stable browser-plugin name. */
|
|
2008
2226
|
const name = "dsh-workbuddy-xdpool-client";
|
|
2009
|
-
/**
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2227
|
+
/**
|
|
2228
|
+
* Client services required by the settings page.
|
|
2229
|
+
*
|
|
2230
|
+
* Deliberately only the two services present on BOTH host lines. The settings
|
|
2231
|
+
* surface differs by line — 0.1.5 provides `settingsScope`, 0.1.7 replaces it
|
|
2232
|
+
* with `configForms` — and cordis' dependency gate is hard: any inject entry the
|
|
2233
|
+
* running line does not provide keeps `apply` from ever running. Probing the one
|
|
2234
|
+
* that exists through `ctx.get()` (which returns undefined, never throws, for an
|
|
2235
|
+
* absent service) is what lets one build serve both lines.
|
|
2236
|
+
*/
|
|
2237
|
+
const inject = ["slots", "locale"];
|
|
2238
|
+
/** Settings namespace the host-side section registers (shared with the entry). */
|
|
2239
|
+
const WORKBUDDY_POOL_SETTINGS_NS = "workbuddy-xdpool";
|
|
2240
|
+
/**
|
|
2241
|
+
* Host plugin entry id this bundle is mounted under in `cordis.patch.yml`.
|
|
2242
|
+
*
|
|
2243
|
+
* `configForms` is addressed by this id on the 0.1.7 line.
|
|
2244
|
+
*/
|
|
2245
|
+
const WORKBUDDY_POOL_ENTRY_ID = "llm-workbuddy-xdpool";
|
|
2246
|
+
/** Register card copy and the pool page under Settings. */
|
|
2016
2247
|
function apply(ctx) {
|
|
2017
2248
|
try {
|
|
2018
2249
|
const namespace = "settings.workbuddy-xdpool";
|
|
@@ -2021,19 +2252,127 @@ window.__ModuleLoader__.load({
|
|
|
2021
2252
|
en
|
|
2022
2253
|
}), "dsh-workbuddy-xdpool: settings copy");
|
|
2023
2254
|
const t = ctx.locale.bind(namespace);
|
|
2024
|
-
const
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2255
|
+
const softGet = (serviceName) => ctx.get(serviceName);
|
|
2256
|
+
const settingsScope = resolveSettingsScope(softGet);
|
|
2257
|
+
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
2258
|
+
name: "settings.section",
|
|
2259
|
+
id: "workbuddy-xdpool",
|
|
2260
|
+
order: 440,
|
|
2261
|
+
label: () => t("row.navLabel"),
|
|
2262
|
+
inject: () => settingsScope === void 0 ? { t } : {
|
|
2030
2263
|
t,
|
|
2031
2264
|
settingsScope
|
|
2032
|
-
}
|
|
2265
|
+
}
|
|
2033
2266
|
}, PoolCard));
|
|
2267
|
+
installNavIcon(ctx, () => t("row.navLabel"));
|
|
2034
2268
|
} catch (error) {
|
|
2035
|
-
console.error("[dsh-workbuddy-xdpool] client
|
|
2269
|
+
console.error("[dsh-workbuddy-xdpool] client page failed to load (host provider unaffected):", error);
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
/** Attribute carrying the nav-row marker this module installs. */
|
|
2273
|
+
const NAV_ICON_MARKER = "data-dsh-xdpool-nav-icon";
|
|
2274
|
+
/**
|
|
2275
|
+
* The settings nav rows, as the shell renders them. Scoped to the settings
|
|
2276
|
+
* dialog on purpose: the main sidebar has its own nav, and matching rows there
|
|
2277
|
+
* would stamp this glyph onto an unrelated control.
|
|
2278
|
+
*/
|
|
2279
|
+
const NAV_ROW_SELECTOR = "[role=\"dialog\"] nav button";
|
|
2280
|
+
/**
|
|
2281
|
+
* Draw this page's own glyph in its Settings nav row.
|
|
2282
|
+
*
|
|
2283
|
+
* The `settings.section` contract carries no icon: the shell decides the glyph
|
|
2284
|
+
* from the section id and falls back to a gear for anything it does not know.
|
|
2285
|
+
* So the row is matched by its LABEL (the same thunk passed to the
|
|
2286
|
+
* registration, re-read on every pass so a locale switch is followed) and
|
|
2287
|
+
* marked; CSS then hides the shell svg and masks this artwork into the row.
|
|
2288
|
+
*
|
|
2289
|
+
* Re-scanned on DOM mutations because the shell re-renders the nav on locale
|
|
2290
|
+
* and theme changes, which replaces the row elements and drops the marker.
|
|
2291
|
+
*
|
|
2292
|
+
* No-op off the browser (the node-side probe imports this module for types).
|
|
2293
|
+
*/
|
|
2294
|
+
function installNavIcon(ctx, resolveLabel) {
|
|
2295
|
+
if (typeof document === "undefined") return;
|
|
2296
|
+
ctx.effect(() => {
|
|
2297
|
+
const tag = document.createElement("style");
|
|
2298
|
+
tag.dataset.plugin = "dsh-workbuddy-xdpool";
|
|
2299
|
+
tag.dataset.pluginCss = "dsh-workbuddy-xdpool/settings-nav-icon";
|
|
2300
|
+
tag.textContent = [
|
|
2301
|
+
`[${NAV_ICON_MARKER}] > svg { display: none; }`,
|
|
2302
|
+
`[${NAV_ICON_MARKER}]::before {`,
|
|
2303
|
+
" content: '';",
|
|
2304
|
+
" flex: none;",
|
|
2305
|
+
" width: 16px;",
|
|
2306
|
+
" height: 16px;",
|
|
2307
|
+
" background-color: currentColor;",
|
|
2308
|
+
` -webkit-mask-image: url("${POOL_NAV_ICON_MASK_URL}");`,
|
|
2309
|
+
` mask-image: url("${POOL_NAV_ICON_MASK_URL}");`,
|
|
2310
|
+
" -webkit-mask-repeat: no-repeat;",
|
|
2311
|
+
" mask-repeat: no-repeat;",
|
|
2312
|
+
" -webkit-mask-position: center;",
|
|
2313
|
+
" mask-position: center;",
|
|
2314
|
+
" -webkit-mask-size: 16px 16px;",
|
|
2315
|
+
" mask-size: 16px 16px;",
|
|
2316
|
+
"}"
|
|
2317
|
+
].join("\n");
|
|
2318
|
+
document.head.appendChild(tag);
|
|
2319
|
+
let disposed = false;
|
|
2320
|
+
let scheduled = false;
|
|
2321
|
+
const sync = () => {
|
|
2322
|
+
scheduled = false;
|
|
2323
|
+
if (disposed) return;
|
|
2324
|
+
const wanted = String(resolveLabel() ?? "").trim();
|
|
2325
|
+
if (wanted === "") return;
|
|
2326
|
+
for (const row of document.querySelectorAll(NAV_ROW_SELECTOR)) if (String(row.textContent ?? "").trim() === wanted) row.setAttribute(NAV_ICON_MARKER, "");
|
|
2327
|
+
else row.removeAttribute(NAV_ICON_MARKER);
|
|
2328
|
+
};
|
|
2329
|
+
const schedule = () => {
|
|
2330
|
+
if (scheduled || disposed) return;
|
|
2331
|
+
scheduled = true;
|
|
2332
|
+
queueMicrotask(sync);
|
|
2333
|
+
};
|
|
2334
|
+
sync();
|
|
2335
|
+
const observer = new MutationObserver(schedule);
|
|
2336
|
+
observer.observe(document.body, {
|
|
2337
|
+
childList: true,
|
|
2338
|
+
subtree: true,
|
|
2339
|
+
characterData: true
|
|
2340
|
+
});
|
|
2341
|
+
return () => {
|
|
2342
|
+
disposed = true;
|
|
2343
|
+
observer.disconnect();
|
|
2344
|
+
for (const row of document.querySelectorAll(`[${NAV_ICON_MARKER}]`)) row.removeAttribute(NAV_ICON_MARKER);
|
|
2345
|
+
tag.remove();
|
|
2346
|
+
};
|
|
2347
|
+
}, "dsh-workbuddy-xdpool: settings nav icon");
|
|
2348
|
+
}
|
|
2349
|
+
/**
|
|
2350
|
+
* Bind the settings form the card reads and writes, on whichever line is
|
|
2351
|
+
* running.
|
|
2352
|
+
*
|
|
2353
|
+
* 0.1.7 exposes `configForms.get(entryId)`, keyed by the HOST plugin entry id —
|
|
2354
|
+
* the id this bundle registers under in `cordis.patch.yml`, not the settings
|
|
2355
|
+
* namespace. 0.1.5 exposes `settingsScope.bind({ namespace })`, keyed by the
|
|
2356
|
+
* namespace the host-side `installSection` registered. Both controllers answer
|
|
2357
|
+
* the same two methods the card uses (`getSnapshot()`, `set(field, value)`), so
|
|
2358
|
+
* the card needs no per-line branch of its own.
|
|
2359
|
+
*
|
|
2360
|
+
* Returns undefined when neither service is present (a locked-down host): the
|
|
2361
|
+
* card then renders read-only, which is the documented degradation.
|
|
2362
|
+
*/
|
|
2363
|
+
function resolveSettingsScope(softGet) {
|
|
2364
|
+
const forms = softGet("configForms");
|
|
2365
|
+
if (forms !== void 0) {
|
|
2366
|
+
let entryId = WORKBUDDY_POOL_ENTRY_ID;
|
|
2367
|
+
try {
|
|
2368
|
+
const namespaces = forms.describe().getSnapshot().view?.namespaces ?? [];
|
|
2369
|
+
const served = namespaces.find((entry) => entry.ns === WORKBUDDY_POOL_ENTRY_ID) ?? namespaces.find((entry) => /workbuddy-xdpool/.test(entry.ns));
|
|
2370
|
+
if (served !== void 0) entryId = served.ns;
|
|
2371
|
+
} catch {}
|
|
2372
|
+
return forms.get(entryId);
|
|
2036
2373
|
}
|
|
2374
|
+
const scope = softGet("settingsScope");
|
|
2375
|
+
if (scope !== void 0) return scope.bind({ namespace: WORKBUDDY_POOL_SETTINGS_NS });
|
|
2037
2376
|
}
|
|
2038
2377
|
//#endregion
|
|
2039
2378
|
exports.apply = apply;
|