dsh-workbuddy-xdpool 1.5.2 → 1.7.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/CHANGELOG.md +226 -0
- package/lib/bin.js +288 -142
- package/lib/client.js +597 -416
- package/lib/index.d.ts +9 -1
- package/lib/index.js +380 -151
- package/package.json +17 -15
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
|
/**
|
|
@@ -64,28 +63,38 @@ window.__ModuleLoader__.load({
|
|
|
64
63
|
* naturally next to the other configuration rows instead of looking like a
|
|
65
64
|
* bright Google-Material block on top of DSH's dark surface.
|
|
66
65
|
*
|
|
67
|
-
* The
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
* are
|
|
66
|
+
* The page renders at full height with no collapse affordance, and its content is
|
|
67
|
+
* split into cards: a header row with the primary actions, a status card (region
|
|
68
|
+
* switch + distribution), then one card per feature area. The inner
|
|
69
|
+
* workbuddy-specific classes are namespaced `dsm-workbuddy-xdpool-*`.
|
|
71
70
|
*
|
|
72
71
|
* @module dsh-workbuddy-xdpool/client/styles
|
|
73
72
|
*/
|
|
74
73
|
const POOL_CARD_CSS = `
|
|
75
|
-
/*
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
.dsm-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
.
|
|
84
|
-
|
|
85
|
-
.dsm-
|
|
86
|
-
.dsm-
|
|
87
|
-
.dsm-
|
|
88
|
-
|
|
74
|
+
/*
|
|
75
|
+
* Page shell. The settings shell renders this inside its own scrollable content
|
|
76
|
+
* column, so the page supplies only the rhythm and the cards — no outer border
|
|
77
|
+
* and no extra margin (the column pads its own edges).
|
|
78
|
+
*/
|
|
79
|
+
.dsm-workbuddy-xdpool-page{max-width:860px;flex-direction:column;gap:16px;display:flex}
|
|
80
|
+
/*
|
|
81
|
+
* Header row: identity on the left, primary actions on the right. Wraps so a
|
|
82
|
+
* narrow panel drops the buttons below the title instead of squeezing it.
|
|
83
|
+
*/
|
|
84
|
+
.dsm-workbuddy-xdpool-page-head{align-items:center;gap:12px;flex-wrap:wrap;display:flex}
|
|
85
|
+
.dsm-workbuddy-xdpool-page-icon{width:32px;height:32px;flex:none;border-radius:7px}
|
|
86
|
+
.dsm-workbuddy-xdpool-page-copy{flex-direction:column;gap:4px;min-width:0;flex:1 1 220px;display:flex}
|
|
87
|
+
.dsm-workbuddy-xdpool-page-title{color:var(--dsw-alias-label-primary,#e6e6e6);margin:0;font-size:16px;font-weight:600;line-height:1.4}
|
|
88
|
+
.dsm-workbuddy-xdpool-page-desc{color:var(--dsw-alias-label-tertiary,#999);margin:0;font-size:13px;line-height:1.5}
|
|
89
|
+
.dsm-workbuddy-xdpool-page-actions{align-items:center;gap:8px;flex-wrap:wrap;flex:none;display:flex}
|
|
90
|
+
/*
|
|
91
|
+
* One feature area per card. The surface separates the sections the way the
|
|
92
|
+
* built-in settings pages do; without it every panel ran together into a single
|
|
93
|
+
* column of text with no visible boundary.
|
|
94
|
+
*/
|
|
95
|
+
.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}
|
|
96
|
+
/* Status card: the region switch sits above the state line, then the switch. */
|
|
97
|
+
.dsm-workbuddy-xdpool-status{gap:14px}
|
|
89
98
|
/* Reusable button primitives shared with the rest of the card body. */
|
|
90
99
|
.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
100
|
.dsm-btn:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#5686fe);outline-offset:1px}
|
|
@@ -95,12 +104,10 @@ window.__ModuleLoader__.load({
|
|
|
95
104
|
.dsm-btn-primary{background:var(--dsw-alias-label-primary,#e6e6e6);color:var(--dsw-alias-bg-layer-3,#202126)}
|
|
96
105
|
.dsm-btn-primary:hover:not(:disabled){opacity:.9}
|
|
97
106
|
|
|
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
107
|
/* Region tabs: two independent suppliers, one shown at a time. */
|
|
101
108
|
.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
109
|
/* Empty-region guide: steps for signing in on the other gateway. */
|
|
103
|
-
.dsm-workbuddy-xdpool-empty{
|
|
110
|
+
.dsm-workbuddy-xdpool-empty{gap:10px}
|
|
104
111
|
.dsm-workbuddy-xdpool-empty-title{margin:0;color:var(--dsw-alias-label-primary,#e6e6e6);font-size:14px;font-weight:600;line-height:20px}
|
|
105
112
|
.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
113
|
.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 +121,14 @@ window.__ModuleLoader__.load({
|
|
|
114
121
|
.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
122
|
.dsm-workbuddy-xdpool-tab-dot[data-state="error"]{background:var(--dsw-alias-state-error-primary,#ef4444)}
|
|
116
123
|
.dsm-workbuddy-xdpool-tab-dot[data-state="idle"]{background:var(--dsw-alias-label-dimmed,#9aa0a6)}
|
|
117
|
-
.dsm-workbuddy-xdpool-usage-head{display:flex;
|
|
124
|
+
.dsm-workbuddy-xdpool-usage-head{display:flex;flex-direction:column;gap:12px;min-width:0}
|
|
118
125
|
.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:
|
|
126
|
+
.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
127
|
.dsm-workbuddy-xdpool-usage-dot{width:9px;height:9px;border-radius:50%;flex:0 0 auto}
|
|
121
|
-
.dsm-workbuddy-xdpool-usage-hint{
|
|
128
|
+
.dsm-workbuddy-xdpool-usage-hint{margin:0;color:var(--dsw-alias-label-tertiary,#9aa0a8);font-size:12px;line-height:18px}
|
|
122
129
|
/* 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:
|
|
130
|
+
.dsm-workbuddy-xdpool-dist{display:flex;flex-direction:column;gap:7px}
|
|
131
|
+
.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
132
|
.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
133
|
.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
134
|
.dsm-workbuddy-xdpool-dist-option:focus-visible{outline:2px solid var(--dsw-alias-brand-primary,#5686fe);outline-offset:1px}
|
|
@@ -133,7 +140,7 @@ window.__ModuleLoader__.load({
|
|
|
133
140
|
.dsm-workbuddy-xdpool-usage-actions{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
|
|
134
141
|
|
|
135
142
|
/* Account list (each account = a labeled subpanel, same as dingminhua). */
|
|
136
|
-
.dsm-workbuddy-xdpool-accounts{
|
|
143
|
+
.dsm-workbuddy-xdpool-accounts{gap:14px}
|
|
137
144
|
.dsm-workbuddy-xdpool-accounts-head{display:flex;align-items:center;justify-content:space-between;gap:12px}
|
|
138
145
|
/* "In use now": answers which account is serving without scanning every row. */
|
|
139
146
|
/* A hairline + tint reads as status; a filled bar would read as a call to action. */
|
|
@@ -196,7 +203,7 @@ window.__ModuleLoader__.load({
|
|
|
196
203
|
.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
204
|
|
|
198
205
|
/* Model directory list. */
|
|
199
|
-
.dsm-workbuddy-xdpool-models{
|
|
206
|
+
.dsm-workbuddy-xdpool-models{gap:10px}
|
|
200
207
|
.dsm-workbuddy-xdpool-models-head{display:flex;align-items:center;justify-content:space-between;gap:12px}
|
|
201
208
|
.dsm-workbuddy-xdpool-models-title{margin:0;color:var(--dsw-alias-label-primary,#e6e6e6);font-size:14px;font-weight:600;line-height:20px}
|
|
202
209
|
.dsm-workbuddy-xdpool-models-summary{margin:2px 0 0;color:var(--dsw-alias-label-tertiary,#999);font-size:12px;line-height:18px}
|
|
@@ -225,6 +232,12 @@ window.__ModuleLoader__.load({
|
|
|
225
232
|
.dsm-workbuddy-xdpool-models-actions{display:flex;align-items:center;gap:8px;flex:none}
|
|
226
233
|
|
|
227
234
|
|
|
235
|
+
/* Automation: run-now button and the per-job progress line. */
|
|
236
|
+
.dsm-workbuddy-xdpool-auto-run{flex:none}
|
|
237
|
+
.dsm-workbuddy-xdpool-auto-job-detail{grid-column:1/-1;color:var(--dsw-alias-label-tertiary,#9aa0a8);font-size:11px;line-height:16px}
|
|
238
|
+
/* Credit packages panel heading inside the right-hand column. */
|
|
239
|
+
.dsm-workbuddy-xdpool-panel-packages{display:flex;flex-direction:column;gap:7px;min-width:0}
|
|
240
|
+
|
|
228
241
|
/* Check-in docked under the total, inside the right-hand panel. */
|
|
229
242
|
.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
243
|
.dsm-workbuddy-xdpool-checkin-meta{display:flex;flex-direction:column;align-items:center;gap:2px;width:100%}
|
|
@@ -305,8 +318,9 @@ window.__ModuleLoader__.load({
|
|
|
305
318
|
* token expiry / cooldown info / credit packages, then the model directory
|
|
306
319
|
* with per-model free/limited/night/image badges and context size.
|
|
307
320
|
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
321
|
+
* Rendered as a full settings page (see `client/index.tsx`): the shell gives it
|
|
322
|
+
* a left-nav row and a scrollable content column, so everything is visible at
|
|
323
|
+
* once — a fold inside the page only hid the pool behind a click.
|
|
310
324
|
*
|
|
311
325
|
* @module dsh-workbuddy-xdpool/client/PoolCard
|
|
312
326
|
*/
|
|
@@ -470,7 +484,6 @@ window.__ModuleLoader__.load({
|
|
|
470
484
|
const settingsWritable = settingsScope?.getSnapshot().writable === true;
|
|
471
485
|
/** Which region tab is showing. A CN-only install never leaves this. */
|
|
472
486
|
const [activeRegion, setActiveRegion] = (0, react.useState)("cn");
|
|
473
|
-
const [open, setOpen] = (0, react.useState)(false);
|
|
474
487
|
/**
|
|
475
488
|
* Last-known status per region. Kept per region (not a single slot) so
|
|
476
489
|
* switching tabs shows the other side's last answer immediately instead of
|
|
@@ -568,7 +581,6 @@ window.__ModuleLoader__.load({
|
|
|
568
581
|
}
|
|
569
582
|
}, []);
|
|
570
583
|
(0, react.useEffect)(() => {
|
|
571
|
-
if (!open) return;
|
|
572
584
|
const controller = new AbortController();
|
|
573
585
|
refresh(activeRegion, controller.signal);
|
|
574
586
|
const timer = window.setInterval(() => {
|
|
@@ -578,11 +590,7 @@ window.__ModuleLoader__.load({
|
|
|
578
590
|
window.clearInterval(timer);
|
|
579
591
|
controller.abort();
|
|
580
592
|
};
|
|
581
|
-
}, [
|
|
582
|
-
open,
|
|
583
|
-
refresh,
|
|
584
|
-
activeRegion
|
|
585
|
-
]);
|
|
593
|
+
}, [refresh, activeRegion]);
|
|
586
594
|
const rescan = async () => {
|
|
587
595
|
setBusy(true);
|
|
588
596
|
setFlash(void 0);
|
|
@@ -929,392 +937,398 @@ window.__ModuleLoader__.load({
|
|
|
929
937
|
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
938
|
const shimRunning = status?.shim.running === true;
|
|
931
939
|
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",
|
|
940
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
941
|
+
className: "dsm-workbuddy-xdpool-page",
|
|
942
|
+
children: [
|
|
943
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
944
|
+
className: "dsm-workbuddy-xdpool-page-head",
|
|
968
945
|
children: [
|
|
969
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
970
|
-
className: "dsm-workbuddy-xdpool-
|
|
971
|
-
|
|
972
|
-
|
|
946
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
947
|
+
className: "dsm-workbuddy-xdpool-page-icon",
|
|
948
|
+
src: POOL_PLUGIN_ICON,
|
|
949
|
+
alt: ""
|
|
950
|
+
}),
|
|
951
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
952
|
+
className: "dsm-workbuddy-xdpool-page-copy",
|
|
953
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
954
|
+
className: "dsm-workbuddy-xdpool-page-title",
|
|
955
|
+
children: title
|
|
956
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
957
|
+
className: "dsm-workbuddy-xdpool-page-desc",
|
|
958
|
+
children: description
|
|
959
|
+
})]
|
|
960
|
+
}),
|
|
961
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
962
|
+
className: "dsm-workbuddy-xdpool-page-actions",
|
|
963
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
973
964
|
type: "button",
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
className: `dsm-workbuddy-xdpool-tab${region === activeRegion ? " dsm-workbuddy-xdpool-tab-active" : ""}`,
|
|
965
|
+
className: "dsm-btn dsm-btn-outline",
|
|
966
|
+
disabled: busy,
|
|
977
967
|
onClick: () => {
|
|
978
|
-
|
|
968
|
+
rescan();
|
|
979
969
|
},
|
|
980
|
-
children:
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
970
|
+
children: busy ? t?.("row.accountsScanning") ?? "Detecting…" : t?.("row.accountsRescan") ?? "Detect accounts again"
|
|
971
|
+
}), cooling > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
972
|
+
type: "button",
|
|
973
|
+
className: "dsm-btn dsm-btn-outline",
|
|
974
|
+
disabled: cooldownBusy,
|
|
975
|
+
onClick: () => {
|
|
976
|
+
resetCooldowns();
|
|
977
|
+
},
|
|
978
|
+
children: cooldownBusy ? t?.("row.resetCooldownsBusy") ?? "Clearing…" : t?.("row.resetCooldowns") ?? "Clear all cooldowns"
|
|
979
|
+
}) : null]
|
|
980
|
+
})
|
|
981
|
+
]
|
|
982
|
+
}),
|
|
983
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
984
|
+
className: "dsm-workbuddy-xdpool-card dsm-workbuddy-xdpool-status",
|
|
985
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
986
|
+
className: "dsm-workbuddy-xdpool-tabs",
|
|
987
|
+
role: "tablist",
|
|
988
|
+
children: status?.regions.map((region) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
989
|
+
type: "button",
|
|
990
|
+
role: "tab",
|
|
991
|
+
"aria-selected": region === activeRegion,
|
|
992
|
+
className: `dsm-workbuddy-xdpool-tab${region === activeRegion ? " dsm-workbuddy-xdpool-tab-active" : ""}`,
|
|
993
|
+
onClick: () => {
|
|
994
|
+
setActiveRegion(region);
|
|
995
|
+
},
|
|
996
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
997
|
+
className: "dsm-workbuddy-xdpool-tab-dot",
|
|
998
|
+
"data-state": state
|
|
999
|
+
}), region === "cn" ? t?.("row.tabCn") ?? "CN" : t?.("row.tabGlobal") ?? "Global"]
|
|
1000
|
+
}, region))
|
|
1001
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1002
|
+
className: "dsm-workbuddy-xdpool-usage-head",
|
|
1003
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1004
|
+
className: "dsm-workbuddy-xdpool-usage-copy",
|
|
1005
|
+
role: "status",
|
|
1006
|
+
children: [
|
|
1007
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1008
|
+
className: "dsm-workbuddy-xdpool-usage-status",
|
|
1009
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1010
|
+
"aria-hidden": "true",
|
|
1011
|
+
className: "dsm-workbuddy-xdpool-usage-dot",
|
|
1012
|
+
style: { background: dotColor(state) }
|
|
1013
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: stateLabel })]
|
|
1014
|
+
}),
|
|
1015
|
+
accountCount > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1016
|
+
className: "dsm-workbuddy-xdpool-usage-hint",
|
|
1017
|
+
children: t?.("row.accountsSummary", {
|
|
1018
|
+
count: accountCount,
|
|
1019
|
+
cooling
|
|
1020
|
+
}) ?? `${accountCount} account(s) · ${cooling} cooling`
|
|
1021
|
+
}) : null,
|
|
1022
|
+
shimHint === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1023
|
+
className: "dsm-workbuddy-xdpool-usage-hint",
|
|
1024
|
+
children: shimHint
|
|
1025
|
+
}),
|
|
1026
|
+
status === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1027
|
+
className: "dsm-workbuddy-xdpool-dist",
|
|
1028
|
+
role: "radiogroup",
|
|
1029
|
+
"aria-label": t?.("row.distTitle") ?? "Account usage",
|
|
1030
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1031
|
+
className: "dsm-workbuddy-xdpool-dist-title",
|
|
1032
|
+
children: t?.("row.distTitle") ?? "Account usage"
|
|
1033
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1034
|
+
className: "dsm-workbuddy-xdpool-dist-options",
|
|
1035
|
+
children: [
|
|
1036
|
+
"priority",
|
|
1037
|
+
"balanced",
|
|
1038
|
+
"round-robin"
|
|
1039
|
+
].map((option) => {
|
|
1040
|
+
const active = (status.distribution ?? "priority") === option;
|
|
1041
|
+
const label = option === "priority" ? t?.("row.distPriority") ?? "Priority" : option === "balanced" ? t?.("row.distBalanced") ?? "Balanced" : t?.("row.distRoundRobin") ?? "Round-robin";
|
|
1042
|
+
const hint = option === "priority" ? t?.("row.distPriorityHint") ?? "" : option === "balanced" ? t?.("row.distBalancedHint") ?? "" : t?.("row.distRoundRobinHint") ?? "";
|
|
1043
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1044
|
+
type: "button",
|
|
1045
|
+
role: "radio",
|
|
1046
|
+
"aria-checked": active,
|
|
1047
|
+
title: hint,
|
|
1048
|
+
disabled: !modelsEditable,
|
|
1049
|
+
className: "dsm-workbuddy-xdpool-dist-option" + (active ? " dsm-workbuddy-xdpool-dist-option-active" : ""),
|
|
1050
|
+
onClick: () => {
|
|
1051
|
+
setDistribution(option);
|
|
1052
|
+
},
|
|
1053
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1054
|
+
className: "dsm-workbuddy-xdpool-dist-option-name",
|
|
1055
|
+
children: label
|
|
1056
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1057
|
+
className: "dsm-workbuddy-xdpool-dist-option-hint",
|
|
1058
|
+
children: hint
|
|
1059
|
+
})]
|
|
1060
|
+
}, option);
|
|
1061
|
+
})
|
|
1062
|
+
})]
|
|
1063
|
+
})
|
|
1064
|
+
]
|
|
1065
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1066
|
+
className: "dsm-workbuddy-xdpool-usage-actions",
|
|
1067
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1068
|
+
type: "button",
|
|
1069
|
+
className: "dsm-btn dsm-btn-outline",
|
|
1070
|
+
disabled: busy,
|
|
1071
|
+
onClick: () => {
|
|
1072
|
+
rescan();
|
|
1073
|
+
},
|
|
1074
|
+
children: busy ? t?.("row.accountsScanning") ?? "Detecting…" : t?.("row.accountsRescan") ?? "Detect accounts again"
|
|
1075
|
+
}), cooling > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1076
|
+
type: "button",
|
|
1077
|
+
className: "dsm-btn dsm-btn-outline",
|
|
1078
|
+
disabled: cooldownBusy,
|
|
1079
|
+
onClick: () => {
|
|
1080
|
+
resetCooldowns();
|
|
1081
|
+
},
|
|
1082
|
+
children: cooldownBusy ? t?.("row.resetCooldownsBusy") ?? "Clearing…" : t?.("row.resetCooldowns") ?? "Clear all cooldowns"
|
|
1083
|
+
}) : null]
|
|
1084
|
+
})]
|
|
1085
|
+
})]
|
|
1086
|
+
}),
|
|
1087
|
+
activeRegion !== "cn" || status?.automation === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1088
|
+
className: "dsm-workbuddy-xdpool-card dsm-workbuddy-xdpool-auto",
|
|
1089
|
+
"aria-label": t?.("row.autoTitle") ?? "Automation",
|
|
1090
|
+
children: [
|
|
986
1091
|
/* @__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", {
|
|
1092
|
+
className: "dsm-workbuddy-xdpool-auto-head",
|
|
1093
|
+
children: [
|
|
1094
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1095
|
+
className: "dsm-workbuddy-xdpool-auto-title",
|
|
1096
|
+
children: t?.("row.autoTitle") ?? "Automation"
|
|
1097
|
+
}),
|
|
1098
|
+
!status.automation.enabled ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1053
1099
|
type: "button",
|
|
1054
|
-
className: "dsm-btn dsm-btn-outline",
|
|
1055
|
-
disabled:
|
|
1100
|
+
className: "dsm-btn dsm-btn-outline dsm-workbuddy-xdpool-auto-run",
|
|
1101
|
+
disabled: automationRun !== void 0,
|
|
1056
1102
|
onClick: () => {
|
|
1057
|
-
|
|
1103
|
+
runAutomationJob();
|
|
1058
1104
|
},
|
|
1059
|
-
children:
|
|
1060
|
-
}),
|
|
1105
|
+
children: automationRun !== void 0 ? t?.("row.autoRunning") ?? "Running…" : t?.("row.autoRunAll") ?? "Run all now"
|
|
1106
|
+
}),
|
|
1107
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1061
1108
|
type: "button",
|
|
1062
|
-
|
|
1063
|
-
|
|
1109
|
+
role: "switch",
|
|
1110
|
+
"aria-checked": status.automation.enabled,
|
|
1111
|
+
disabled: !settingsWritable || automationBusy,
|
|
1112
|
+
className: `dsm-workbuddy-xdpool-auto-switch${status.automation.enabled ? " dsm-workbuddy-xdpool-auto-switch-on" : ""}`,
|
|
1064
1113
|
onClick: () => {
|
|
1065
|
-
|
|
1114
|
+
setAutomationEnabled(!status.automation.enabled);
|
|
1066
1115
|
},
|
|
1067
|
-
children:
|
|
1068
|
-
})
|
|
1116
|
+
children: automationBusy ? t?.("row.autoBusy") ?? "Saving…" : status.automation.enabled ? t?.("row.autoOn") ?? "On" : t?.("row.autoOff") ?? "Off"
|
|
1117
|
+
})
|
|
1118
|
+
]
|
|
1119
|
+
}),
|
|
1120
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1121
|
+
className: "dsm-workbuddy-xdpool-auto-hint",
|
|
1122
|
+
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."
|
|
1123
|
+
}),
|
|
1124
|
+
automationTotals.credit === 0 && automationTotals.checkinCredit === 0 && automationTotals.bonusCredit === 0 && automationTotals.travelCredit === 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1125
|
+
className: "dsm-workbuddy-xdpool-auto-total",
|
|
1126
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1127
|
+
className: "dsm-workbuddy-xdpool-auto-total-label",
|
|
1128
|
+
children: t?.("row.autoToday") ?? "Today"
|
|
1129
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1130
|
+
className: "dsm-workbuddy-xdpool-auto-total-list",
|
|
1131
|
+
children: [
|
|
1132
|
+
automationTotals.credit > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1133
|
+
className: "dsm-workbuddy-xdpool-auto-total-row",
|
|
1134
|
+
children: t?.("row.autoFromTasks", {
|
|
1135
|
+
credit: automationTotals.credit,
|
|
1136
|
+
energy: automationTotals.energy,
|
|
1137
|
+
count: automationTotals.claimed
|
|
1138
|
+
}) ?? `Tasks +${automationTotals.credit}`
|
|
1139
|
+
}) : null,
|
|
1140
|
+
automationTotals.checkinCredit > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1141
|
+
className: "dsm-workbuddy-xdpool-auto-total-row",
|
|
1142
|
+
children: t?.("row.autoFromCheckin", { credit: automationTotals.checkinCredit }) ?? `Check-in +${automationTotals.checkinCredit}`
|
|
1143
|
+
}) : null,
|
|
1144
|
+
automationTotals.bonusCredit > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1145
|
+
className: "dsm-workbuddy-xdpool-auto-total-row",
|
|
1146
|
+
children: t?.("row.autoFromBonus", { credit: automationTotals.bonusCredit }) ?? `Streak +${automationTotals.bonusCredit}`
|
|
1147
|
+
}) : null,
|
|
1148
|
+
automationTotals.travelCredit > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1149
|
+
className: "dsm-workbuddy-xdpool-auto-total-row",
|
|
1150
|
+
children: t?.("row.autoFromTravel", { credit: automationTotals.travelCredit }) ?? `Buddy +${automationTotals.travelCredit}`
|
|
1151
|
+
}) : null
|
|
1152
|
+
]
|
|
1069
1153
|
})]
|
|
1070
1154
|
}),
|
|
1071
|
-
|
|
1072
|
-
className: "dsm-workbuddy-xdpool-auto",
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1155
|
+
status.automation.enabled ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1156
|
+
className: "dsm-workbuddy-xdpool-auto-jobs",
|
|
1157
|
+
children: AUTOMATION_JOBS.map((kind) => {
|
|
1158
|
+
const job = automationJob(status, kind);
|
|
1159
|
+
const hours = automationHours(status, kind);
|
|
1160
|
+
const label = t?.(`row.autoJob_${kind}`) ?? kind;
|
|
1161
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1162
|
+
className: "dsm-workbuddy-xdpool-auto-job",
|
|
1077
1163
|
children: [
|
|
1078
1164
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1079
|
-
className: "dsm-workbuddy-xdpool-auto-
|
|
1080
|
-
children:
|
|
1165
|
+
className: "dsm-workbuddy-xdpool-auto-job-name",
|
|
1166
|
+
children: label
|
|
1167
|
+
}),
|
|
1168
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1169
|
+
className: "dsm-workbuddy-xdpool-auto-job-when",
|
|
1170
|
+
children: hours.length === 0 ? t?.("row.autoHourNone") ?? "not scheduled" : hours.map((hour) => `${String(hour).padStart(2, "0")}:00`).join(" · ")
|
|
1171
|
+
}),
|
|
1172
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1173
|
+
className: "dsm-workbuddy-xdpool-auto-job-last",
|
|
1174
|
+
children: job?.lastRunDate === void 0 ? t?.("row.autoNever") ?? "not run yet" : `${job.lastRunDate} · ${job.ok}${job.failed > 0 ? `/${job.failed}` : ""}`
|
|
1081
1175
|
}),
|
|
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"
|
|
1176
|
+
job?.progress === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1177
|
+
className: "dsm-workbuddy-xdpool-auto-job-note",
|
|
1178
|
+
children: job.progress
|
|
1090
1179
|
}),
|
|
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"
|
|
1180
|
+
job?.detail === void 0 || job.detail.length === 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1181
|
+
className: "dsm-workbuddy-xdpool-auto-job-detail",
|
|
1182
|
+
children: job.detail.join(" · ")
|
|
1101
1183
|
})
|
|
1102
1184
|
]
|
|
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
|
|
1185
|
+
}, kind);
|
|
1186
|
+
})
|
|
1187
|
+
}) : null
|
|
1188
|
+
]
|
|
1189
|
+
}),
|
|
1190
|
+
flash === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1191
|
+
className: "dsm-workbuddy-xdpool-note",
|
|
1192
|
+
children: flash
|
|
1193
|
+
}),
|
|
1194
|
+
error === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1195
|
+
className: "dsm-workbuddy-xdpool-error",
|
|
1196
|
+
children: t?.("row.error", { message: error }) ?? `Pool status unavailable: ${error}`
|
|
1197
|
+
}),
|
|
1198
|
+
accountCount === 0 && error === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1199
|
+
className: "dsm-workbuddy-xdpool-card dsm-workbuddy-xdpool-empty",
|
|
1200
|
+
children: [
|
|
1201
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1202
|
+
className: "dsm-workbuddy-xdpool-empty-title",
|
|
1203
|
+
children: t?.("row.regionEmptyTitle", { region: regionLabel }) ?? t?.("row.regionEmpty") ?? "No account yet"
|
|
1177
1204
|
}),
|
|
1178
|
-
|
|
1179
|
-
className: "dsm-workbuddy-xdpool-
|
|
1180
|
-
children:
|
|
1205
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1206
|
+
className: "dsm-workbuddy-xdpool-empty-steps",
|
|
1207
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1208
|
+
className: "dsm-workbuddy-xdpool-empty-steps-title",
|
|
1209
|
+
children: t?.("row.regionHowToTitle", { region: regionLabel }) ?? `How to sign in to the ${regionLabel} version`
|
|
1210
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ol", {
|
|
1211
|
+
className: "dsm-workbuddy-xdpool-empty-list",
|
|
1212
|
+
children: [
|
|
1213
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: t?.("row.regionHowTo1") ?? "" }),
|
|
1214
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: t?.("row.regionHowTo2") ?? "" }),
|
|
1215
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: t?.("row.regionHowTo3") ?? "" }),
|
|
1216
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: t?.("row.regionHowTo4") ?? "" })
|
|
1217
|
+
]
|
|
1218
|
+
})]
|
|
1181
1219
|
}),
|
|
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))
|
|
1220
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1221
|
+
className: "dsm-workbuddy-xdpool-empty-note",
|
|
1222
|
+
children: t?.("row.regionHowToNote") ?? ""
|
|
1223
|
+
})
|
|
1224
|
+
]
|
|
1225
|
+
}) : null,
|
|
1226
|
+
accountCount > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1227
|
+
className: "dsm-workbuddy-xdpool-card dsm-workbuddy-xdpool-accounts",
|
|
1228
|
+
"aria-label": t?.("row.accountsTitle") ?? "Accounts",
|
|
1229
|
+
children: [
|
|
1230
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1231
|
+
className: "dsm-workbuddy-xdpool-accounts-head",
|
|
1232
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
1233
|
+
className: "dsm-workbuddy-xdpool-accounts-title",
|
|
1234
|
+
children: t?.("row.accountsTitle") ?? "Accounts in the pool"
|
|
1235
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1236
|
+
className: "dsm-workbuddy-xdpool-accounts-summary",
|
|
1237
|
+
children: t?.("row.accountsSummary", {
|
|
1238
|
+
count: accountCount,
|
|
1239
|
+
cooling
|
|
1240
|
+
}) ?? `${accountCount} account(s) · ${cooling} cooling`
|
|
1313
1241
|
})]
|
|
1314
|
-
})
|
|
1242
|
+
}),
|
|
1243
|
+
(() => {
|
|
1244
|
+
const active = status?.activeAccountId === void 0 ? void 0 : status.accounts.find((account) => account.id === status.activeAccountId);
|
|
1245
|
+
if (active === void 0) return null;
|
|
1246
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1247
|
+
className: "dsm-workbuddy-xdpool-current",
|
|
1248
|
+
children: [
|
|
1249
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: "dsm-workbuddy-xdpool-current-dot" }),
|
|
1250
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1251
|
+
className: "dsm-workbuddy-xdpool-current-label",
|
|
1252
|
+
children: t?.("row.currentAccount") ?? "In use now"
|
|
1253
|
+
}),
|
|
1254
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1255
|
+
className: "dsm-workbuddy-xdpool-current-name",
|
|
1256
|
+
children: active.label
|
|
1257
|
+
}),
|
|
1258
|
+
active.disabled === true ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1259
|
+
className: "dsm-workbuddy-xdpool-current-note",
|
|
1260
|
+
children: t?.("row.currentAccountDisabled") ?? "disabled — will switch on the next request"
|
|
1261
|
+
}) : null
|
|
1262
|
+
]
|
|
1263
|
+
});
|
|
1264
|
+
})(),
|
|
1265
|
+
status?.accounts.map((account) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountBlock, {
|
|
1266
|
+
account,
|
|
1267
|
+
...checkinBusyId === void 0 ? {} : { checkinBusyId },
|
|
1268
|
+
onClaimCheckin: (accountId) => {
|
|
1269
|
+
claimCheckin(accountId);
|
|
1270
|
+
},
|
|
1271
|
+
onSaveCreditReserve: (accountId, reserve) => saveCreditReserve(accountId, reserve),
|
|
1272
|
+
onToggleDisabled: (accountId, disabled) => {
|
|
1273
|
+
toggleAccountDisabled(accountId, disabled);
|
|
1274
|
+
},
|
|
1275
|
+
...accountBusyId === void 0 ? {} : { accountBusyId },
|
|
1276
|
+
t
|
|
1277
|
+
}, account.id))
|
|
1315
1278
|
]
|
|
1316
|
-
})
|
|
1317
|
-
|
|
1279
|
+
}) : null,
|
|
1280
|
+
(status?.models.length ?? 0) > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1281
|
+
className: "dsm-workbuddy-xdpool-card dsm-workbuddy-xdpool-models",
|
|
1282
|
+
"aria-label": t?.("row.modelsTitle") ?? "Models",
|
|
1283
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1284
|
+
className: "dsm-workbuddy-xdpool-models-head",
|
|
1285
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1286
|
+
className: "dsm-workbuddy-xdpool-models-heading",
|
|
1287
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
1288
|
+
className: "dsm-workbuddy-xdpool-models-title",
|
|
1289
|
+
children: t?.("row.modelsTitle") ?? "Models"
|
|
1290
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1291
|
+
className: "dsm-workbuddy-xdpool-models-summary",
|
|
1292
|
+
children: t?.("row.modelsEnabledCount", {
|
|
1293
|
+
enabled: enabledCount,
|
|
1294
|
+
total: status?.models.length ?? 0
|
|
1295
|
+
}) ?? `${enabledCount} / ${status?.models.length ?? 0} enabled`
|
|
1296
|
+
})]
|
|
1297
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1298
|
+
className: "dsm-workbuddy-xdpool-models-actions",
|
|
1299
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1300
|
+
type: "button",
|
|
1301
|
+
className: "dsm-btn dsm-btn-outline",
|
|
1302
|
+
disabled: !modelsDirty || savingModels,
|
|
1303
|
+
onClick: discardModels,
|
|
1304
|
+
children: t?.("row.modelsDiscard") ?? "Discard"
|
|
1305
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1306
|
+
type: "button",
|
|
1307
|
+
className: "dsm-btn dsm-btn-primary",
|
|
1308
|
+
disabled: !modelsDirty || savingModels || enabledCount === 0,
|
|
1309
|
+
onClick: () => {
|
|
1310
|
+
saveModels();
|
|
1311
|
+
},
|
|
1312
|
+
children: savingModels ? t?.("row.modelsSaving") ?? "Saving…" : t?.("row.modelsSave") ?? "Save"
|
|
1313
|
+
})]
|
|
1314
|
+
})]
|
|
1315
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1316
|
+
className: "dsm-workbuddy-xdpool-model-list",
|
|
1317
|
+
children: status?.models.map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelRow, {
|
|
1318
|
+
model,
|
|
1319
|
+
t,
|
|
1320
|
+
draft: modelDraft[model.id] ?? {
|
|
1321
|
+
enabled: model.enabled,
|
|
1322
|
+
images: model.supportsImages
|
|
1323
|
+
},
|
|
1324
|
+
editable: modelsEditable,
|
|
1325
|
+
onToggle: toggleModel,
|
|
1326
|
+
onToggleImage: toggleModelImage,
|
|
1327
|
+
onBudget: setModelBudget
|
|
1328
|
+
}, model.id))
|
|
1329
|
+
})]
|
|
1330
|
+
}) : null
|
|
1331
|
+
]
|
|
1318
1332
|
});
|
|
1319
1333
|
}
|
|
1320
1334
|
/** One account block: label + status tag + meta + optional credit panels. */
|
|
@@ -1732,6 +1746,50 @@ window.__ModuleLoader__.load({
|
|
|
1732
1746
|
});
|
|
1733
1747
|
}
|
|
1734
1748
|
//#endregion
|
|
1749
|
+
//#region src/client/nav-icon.ts
|
|
1750
|
+
/**
|
|
1751
|
+
* Nav glyph for the WorkBuddy XD Pool settings page.
|
|
1752
|
+
*
|
|
1753
|
+
* The host's settings shell draws its own 16px `svg` in every nav row and the
|
|
1754
|
+
* `settings.section` registration contract projects only `id` / `order` /
|
|
1755
|
+
* `label` — there is no `icon` field to pass. A third-party page therefore has
|
|
1756
|
+
* to mark its row in the DOM and mask this artwork over the shell's glyph, the
|
|
1757
|
+
* same technique `dshmarket` uses (`installSettingsNavIcon`).
|
|
1758
|
+
*
|
|
1759
|
+
* Kept as a single monochrome path so `mask-image` + `currentColor` can tint it
|
|
1760
|
+
* with whatever the active theme uses for nav text: a filled mask cannot carry
|
|
1761
|
+
* its own palette, and a two-tone icon would render as a flat silhouette.
|
|
1762
|
+
*
|
|
1763
|
+
* @module dsh-workbuddy-xdpool/client/nav-icon
|
|
1764
|
+
*/
|
|
1765
|
+
/**
|
|
1766
|
+
* The nav mark: a stack of three rounded "accounts" under a rotation arc.
|
|
1767
|
+
*
|
|
1768
|
+
* Reads as "a pool of accounts being cycled" at 16px, and — unlike a literal
|
|
1769
|
+
* droplet or cloud — stays legible when reduced to a single-color silhouette.
|
|
1770
|
+
* `fill-rule="evenodd"` cuts the interior notches out of the silhouette so the
|
|
1771
|
+
* three layers stay distinguishable at that size.
|
|
1772
|
+
*/
|
|
1773
|
+
const POOL_NAV_ICON_SVG = [
|
|
1774
|
+
"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" width=\"16\" height=\"16\">",
|
|
1775
|
+
"<path fill=\"currentColor\" fill-rule=\"evenodd\" d=\"",
|
|
1776
|
+
"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",
|
|
1777
|
+
"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",
|
|
1778
|
+
"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",
|
|
1779
|
+
"\"/>",
|
|
1780
|
+
"<path fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.7\" stroke-linecap=\"round\"",
|
|
1781
|
+
" d=\"M4.4 17.2a8.6 8.6 0 0 0 15.2 0\" stroke-dasharray=\"2.6 2.2\"/>",
|
|
1782
|
+
"</svg>"
|
|
1783
|
+
].join("");
|
|
1784
|
+
/**
|
|
1785
|
+
* The same artwork as a `mask-image` URL.
|
|
1786
|
+
*
|
|
1787
|
+
* `encodeURIComponent` keeps the `#`-free markup safe inside a `url("…")` in a
|
|
1788
|
+
* stylesheet, and `currentColor` is resolved by the mask's own element rather
|
|
1789
|
+
* than by the SVG, so the glyph follows the theme.
|
|
1790
|
+
*/
|
|
1791
|
+
const POOL_NAV_ICON_MASK_URL = `data:image/svg+xml;utf8,${encodeURIComponent(POOL_NAV_ICON_SVG)}`;
|
|
1792
|
+
//#endregion
|
|
1735
1793
|
//#region src/client/locales.ts
|
|
1736
1794
|
/**
|
|
1737
1795
|
* Plugin-card copy registered under the `settings.workbuddy-xdpool` locale
|
|
@@ -1741,6 +1799,7 @@ window.__ModuleLoader__.load({
|
|
|
1741
1799
|
* @module dsh-workbuddy-xdpool/client/locales
|
|
1742
1800
|
*/
|
|
1743
1801
|
const en = {
|
|
1802
|
+
"row.navLabel": "XD Pool",
|
|
1744
1803
|
"row.title": "WorkBuddy XD Pool (dsh-workbuddy-xdpool)",
|
|
1745
1804
|
"row.desc": "Route every WorkBuddy sign-in on this machine into DSH as one auto-failing-over model pool.",
|
|
1746
1805
|
"row.expand": "Expand",
|
|
@@ -1872,6 +1931,7 @@ window.__ModuleLoader__.load({
|
|
|
1872
1931
|
"row.autoFromTravel": "Buddy travel +{credit} credits"
|
|
1873
1932
|
};
|
|
1874
1933
|
const zh = {
|
|
1934
|
+
"row.navLabel": "XD Pool",
|
|
1875
1935
|
"row.title": "WorkBuddy 池(dsh-workbuddy-xdpool)",
|
|
1876
1936
|
"row.desc": "把本机所有已登录的 WorkBuddy 账号并入 DSH,作为一个自动容错的模型池使用。",
|
|
1877
1937
|
"row.expand": "展开",
|
|
@@ -2006,13 +2066,26 @@ window.__ModuleLoader__.load({
|
|
|
2006
2066
|
//#region src/client/index.tsx
|
|
2007
2067
|
/** Stable browser-plugin name. */
|
|
2008
2068
|
const name = "dsh-workbuddy-xdpool-client";
|
|
2009
|
-
/**
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2069
|
+
/**
|
|
2070
|
+
* Client services required by the settings page.
|
|
2071
|
+
*
|
|
2072
|
+
* Deliberately only the two services present on BOTH host lines. The settings
|
|
2073
|
+
* surface differs by line — 0.1.5 provides `settingsScope`, 0.1.7 replaces it
|
|
2074
|
+
* with `configForms` — and cordis' dependency gate is hard: any inject entry the
|
|
2075
|
+
* running line does not provide keeps `apply` from ever running. Probing the one
|
|
2076
|
+
* that exists through `ctx.get()` (which returns undefined, never throws, for an
|
|
2077
|
+
* absent service) is what lets one build serve both lines.
|
|
2078
|
+
*/
|
|
2079
|
+
const inject = ["slots", "locale"];
|
|
2080
|
+
/** Settings namespace the host-side section registers (shared with the entry). */
|
|
2081
|
+
const WORKBUDDY_POOL_SETTINGS_NS = "workbuddy-xdpool";
|
|
2082
|
+
/**
|
|
2083
|
+
* Host plugin entry id this bundle is mounted under in `cordis.patch.yml`.
|
|
2084
|
+
*
|
|
2085
|
+
* `configForms` is addressed by this id on the 0.1.7 line.
|
|
2086
|
+
*/
|
|
2087
|
+
const WORKBUDDY_POOL_ENTRY_ID = "llm-workbuddy-xdpool";
|
|
2088
|
+
/** Register card copy and the pool page under Settings. */
|
|
2016
2089
|
function apply(ctx) {
|
|
2017
2090
|
try {
|
|
2018
2091
|
const namespace = "settings.workbuddy-xdpool";
|
|
@@ -2021,19 +2094,127 @@ window.__ModuleLoader__.load({
|
|
|
2021
2094
|
en
|
|
2022
2095
|
}), "dsh-workbuddy-xdpool: settings copy");
|
|
2023
2096
|
const t = ctx.locale.bind(namespace);
|
|
2024
|
-
const
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2097
|
+
const softGet = (serviceName) => ctx.get(serviceName);
|
|
2098
|
+
const settingsScope = resolveSettingsScope(softGet);
|
|
2099
|
+
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
2100
|
+
name: "settings.section",
|
|
2101
|
+
id: "workbuddy-xdpool",
|
|
2102
|
+
order: 440,
|
|
2103
|
+
label: () => t("row.navLabel"),
|
|
2104
|
+
inject: () => settingsScope === void 0 ? { t } : {
|
|
2030
2105
|
t,
|
|
2031
2106
|
settingsScope
|
|
2032
|
-
}
|
|
2107
|
+
}
|
|
2033
2108
|
}, PoolCard));
|
|
2109
|
+
installNavIcon(ctx, () => t("row.navLabel"));
|
|
2034
2110
|
} catch (error) {
|
|
2035
|
-
console.error("[dsh-workbuddy-xdpool] client
|
|
2111
|
+
console.error("[dsh-workbuddy-xdpool] client page failed to load (host provider unaffected):", error);
|
|
2112
|
+
}
|
|
2113
|
+
}
|
|
2114
|
+
/** Attribute carrying the nav-row marker this module installs. */
|
|
2115
|
+
const NAV_ICON_MARKER = "data-dsh-xdpool-nav-icon";
|
|
2116
|
+
/**
|
|
2117
|
+
* The settings nav rows, as the shell renders them. Scoped to the settings
|
|
2118
|
+
* dialog on purpose: the main sidebar has its own nav, and matching rows there
|
|
2119
|
+
* would stamp this glyph onto an unrelated control.
|
|
2120
|
+
*/
|
|
2121
|
+
const NAV_ROW_SELECTOR = "[role=\"dialog\"] nav button";
|
|
2122
|
+
/**
|
|
2123
|
+
* Draw this page's own glyph in its Settings nav row.
|
|
2124
|
+
*
|
|
2125
|
+
* The `settings.section` contract carries no icon: the shell decides the glyph
|
|
2126
|
+
* from the section id and falls back to a gear for anything it does not know.
|
|
2127
|
+
* So the row is matched by its LABEL (the same thunk passed to the
|
|
2128
|
+
* registration, re-read on every pass so a locale switch is followed) and
|
|
2129
|
+
* marked; CSS then hides the shell svg and masks this artwork into the row.
|
|
2130
|
+
*
|
|
2131
|
+
* Re-scanned on DOM mutations because the shell re-renders the nav on locale
|
|
2132
|
+
* and theme changes, which replaces the row elements and drops the marker.
|
|
2133
|
+
*
|
|
2134
|
+
* No-op off the browser (the node-side probe imports this module for types).
|
|
2135
|
+
*/
|
|
2136
|
+
function installNavIcon(ctx, resolveLabel) {
|
|
2137
|
+
if (typeof document === "undefined") return;
|
|
2138
|
+
ctx.effect(() => {
|
|
2139
|
+
const tag = document.createElement("style");
|
|
2140
|
+
tag.dataset.plugin = "dsh-workbuddy-xdpool";
|
|
2141
|
+
tag.dataset.pluginCss = "dsh-workbuddy-xdpool/settings-nav-icon";
|
|
2142
|
+
tag.textContent = [
|
|
2143
|
+
`[${NAV_ICON_MARKER}] > svg { display: none; }`,
|
|
2144
|
+
`[${NAV_ICON_MARKER}]::before {`,
|
|
2145
|
+
" content: '';",
|
|
2146
|
+
" flex: none;",
|
|
2147
|
+
" width: 16px;",
|
|
2148
|
+
" height: 16px;",
|
|
2149
|
+
" background-color: currentColor;",
|
|
2150
|
+
` -webkit-mask-image: url("${POOL_NAV_ICON_MASK_URL}");`,
|
|
2151
|
+
` mask-image: url("${POOL_NAV_ICON_MASK_URL}");`,
|
|
2152
|
+
" -webkit-mask-repeat: no-repeat;",
|
|
2153
|
+
" mask-repeat: no-repeat;",
|
|
2154
|
+
" -webkit-mask-position: center;",
|
|
2155
|
+
" mask-position: center;",
|
|
2156
|
+
" -webkit-mask-size: 16px 16px;",
|
|
2157
|
+
" mask-size: 16px 16px;",
|
|
2158
|
+
"}"
|
|
2159
|
+
].join("\n");
|
|
2160
|
+
document.head.appendChild(tag);
|
|
2161
|
+
let disposed = false;
|
|
2162
|
+
let scheduled = false;
|
|
2163
|
+
const sync = () => {
|
|
2164
|
+
scheduled = false;
|
|
2165
|
+
if (disposed) return;
|
|
2166
|
+
const wanted = String(resolveLabel() ?? "").trim();
|
|
2167
|
+
if (wanted === "") return;
|
|
2168
|
+
for (const row of document.querySelectorAll(NAV_ROW_SELECTOR)) if (String(row.textContent ?? "").trim() === wanted) row.setAttribute(NAV_ICON_MARKER, "");
|
|
2169
|
+
else row.removeAttribute(NAV_ICON_MARKER);
|
|
2170
|
+
};
|
|
2171
|
+
const schedule = () => {
|
|
2172
|
+
if (scheduled || disposed) return;
|
|
2173
|
+
scheduled = true;
|
|
2174
|
+
queueMicrotask(sync);
|
|
2175
|
+
};
|
|
2176
|
+
sync();
|
|
2177
|
+
const observer = new MutationObserver(schedule);
|
|
2178
|
+
observer.observe(document.body, {
|
|
2179
|
+
childList: true,
|
|
2180
|
+
subtree: true,
|
|
2181
|
+
characterData: true
|
|
2182
|
+
});
|
|
2183
|
+
return () => {
|
|
2184
|
+
disposed = true;
|
|
2185
|
+
observer.disconnect();
|
|
2186
|
+
for (const row of document.querySelectorAll(`[${NAV_ICON_MARKER}]`)) row.removeAttribute(NAV_ICON_MARKER);
|
|
2187
|
+
tag.remove();
|
|
2188
|
+
};
|
|
2189
|
+
}, "dsh-workbuddy-xdpool: settings nav icon");
|
|
2190
|
+
}
|
|
2191
|
+
/**
|
|
2192
|
+
* Bind the settings form the card reads and writes, on whichever line is
|
|
2193
|
+
* running.
|
|
2194
|
+
*
|
|
2195
|
+
* 0.1.7 exposes `configForms.get(entryId)`, keyed by the HOST plugin entry id —
|
|
2196
|
+
* the id this bundle registers under in `cordis.patch.yml`, not the settings
|
|
2197
|
+
* namespace. 0.1.5 exposes `settingsScope.bind({ namespace })`, keyed by the
|
|
2198
|
+
* namespace the host-side `installSection` registered. Both controllers answer
|
|
2199
|
+
* the same two methods the card uses (`getSnapshot()`, `set(field, value)`), so
|
|
2200
|
+
* the card needs no per-line branch of its own.
|
|
2201
|
+
*
|
|
2202
|
+
* Returns undefined when neither service is present (a locked-down host): the
|
|
2203
|
+
* card then renders read-only, which is the documented degradation.
|
|
2204
|
+
*/
|
|
2205
|
+
function resolveSettingsScope(softGet) {
|
|
2206
|
+
const forms = softGet("configForms");
|
|
2207
|
+
if (forms !== void 0) {
|
|
2208
|
+
let entryId = WORKBUDDY_POOL_ENTRY_ID;
|
|
2209
|
+
try {
|
|
2210
|
+
const namespaces = forms.describe().getSnapshot().view?.namespaces ?? [];
|
|
2211
|
+
const served = namespaces.find((entry) => entry.ns === WORKBUDDY_POOL_ENTRY_ID) ?? namespaces.find((entry) => /workbuddy-xdpool/.test(entry.ns));
|
|
2212
|
+
if (served !== void 0) entryId = served.ns;
|
|
2213
|
+
} catch {}
|
|
2214
|
+
return forms.get(entryId);
|
|
2036
2215
|
}
|
|
2216
|
+
const scope = softGet("settingsScope");
|
|
2217
|
+
if (scope !== void 0) return scope.bind({ namespace: WORKBUDDY_POOL_SETTINGS_NS });
|
|
2037
2218
|
}
|
|
2038
2219
|
//#endregion
|
|
2039
2220
|
exports.apply = apply;
|