@dshtrading/client-ui-updater 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client/contract.d.ts +2 -7
- package/lib/client/locales.js +4 -2
- package/lib/client.js +212 -103
- package/lib/client.js.map +1 -1
- package/package.json +9 -7
package/lib/client/contract.d.ts
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
//#region src/client/contract.d.ts
|
|
2
|
-
|
|
3
|
-
* Locale contract for the updater settings section. The zh dictionary in
|
|
4
|
-
* locales.ts is the key source of truth; this union + the LocaleNamespaceMap
|
|
5
|
-
* merge give the framework-injected t seat its key types.
|
|
6
|
-
*/
|
|
7
|
-
type UpdaterLocaleKey = 'nav' | 'lead' | 'currentVersion' | 'desktopApp' | 'unsupported' | 'viewReleases' | 'checkNow' | 'checking' | 'lastCheck' | 'never' | 'upToDate' | 'available' | 'publishedAt' | 'notesTitle' | 'applyNow' | 'payloadMissing' | 'phase.prepare' | 'phase.download' | 'phase.verify' | 'phase.install' | 'progress' | 'done' | 'restartHint' | 'restartNow' | 'restartManual' | 'checkError' | 'retry';
|
|
2
|
+
type UpdaterLocaleKey = 'nav' | 'lead' | 'currentVersion' | 'desktopApp' | 'unsupported' | 'viewReleases' | 'checkNow' | 'checking' | 'lastCheck' | 'never' | 'upToDate' | 'available' | 'publishedAt' | 'notesTitle' | 'applyNow' | 'payloadMissing' | 'phase.prepare' | 'phase.download' | 'phase.verify' | 'phase.install' | 'progress' | 'done' | 'restartHint' | 'restartNow' | 'restartManual' | 'checkError' | 'retry' | 'close';
|
|
8
3
|
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
9
4
|
interface LocaleNamespaceMap {
|
|
10
|
-
/**
|
|
5
|
+
/** Software-update dialog copy (check / notes / incremental apply). */
|
|
11
6
|
'dshtrading.updater': UpdaterLocaleKey;
|
|
12
7
|
}
|
|
13
8
|
}
|
package/lib/client/locales.js
CHANGED
|
@@ -26,7 +26,8 @@ const zh = {
|
|
|
26
26
|
restartNow: "重启应用",
|
|
27
27
|
restartManual: "请手动重启 DSH Trading 以完成更新。",
|
|
28
28
|
checkError: "检查失败:{message}",
|
|
29
|
-
retry: "重试"
|
|
29
|
+
retry: "重试",
|
|
30
|
+
close: "关闭"
|
|
30
31
|
};
|
|
31
32
|
const en = {
|
|
32
33
|
nav: "Software updates",
|
|
@@ -55,7 +56,8 @@ const en = {
|
|
|
55
56
|
restartNow: "Restart app",
|
|
56
57
|
restartManual: "Please restart DSH Trading manually to finish the update.",
|
|
57
58
|
checkError: "Check failed: {message}",
|
|
58
|
-
retry: "Retry"
|
|
59
|
+
retry: "Retry",
|
|
60
|
+
close: "Close"
|
|
59
61
|
};
|
|
60
62
|
//#endregion
|
|
61
63
|
export { en, zh };
|
package/lib/client.js
CHANGED
|
@@ -34,7 +34,8 @@ window.__ModuleLoader__.load({
|
|
|
34
34
|
restartNow: "重启应用",
|
|
35
35
|
restartManual: "请手动重启 DSH Trading 以完成更新。",
|
|
36
36
|
checkError: "检查失败:{message}",
|
|
37
|
-
retry: "重试"
|
|
37
|
+
retry: "重试",
|
|
38
|
+
close: "关闭"
|
|
38
39
|
};
|
|
39
40
|
const en = {
|
|
40
41
|
nav: "Software updates",
|
|
@@ -63,9 +64,25 @@ window.__ModuleLoader__.load({
|
|
|
63
64
|
restartNow: "Restart app",
|
|
64
65
|
restartManual: "Please restart DSH Trading manually to finish the update.",
|
|
65
66
|
checkError: "Check failed: {message}",
|
|
66
|
-
retry: "Retry"
|
|
67
|
+
retry: "Retry",
|
|
68
|
+
close: "Close"
|
|
67
69
|
};
|
|
68
70
|
//#endregion
|
|
71
|
+
//#region src/client/contract.ts
|
|
72
|
+
/**
|
|
73
|
+
* Window event contract with the trading shell sidebar (client-ui-trading
|
|
74
|
+
* MarketDock update entry). Cross-plugin coupling is intentionally a DOM
|
|
75
|
+
* custom event, not an import (client plugins never import each other's
|
|
76
|
+
* modules).
|
|
77
|
+
*
|
|
78
|
+
* - UPDATE_AVAILABLE_EVENT: fired by the dialog whenever the host snapshot
|
|
79
|
+
* changes. Detail: { available: boolean, version?: string }.
|
|
80
|
+
* - UPDATER_OPEN_EVENT: fired by the sidebar update entry to ask this plugin
|
|
81
|
+
* to open its dialog. No detail.
|
|
82
|
+
*/
|
|
83
|
+
const UPDATE_AVAILABLE_EVENT = "dshtrading-update-available";
|
|
84
|
+
const UPDATER_OPEN_EVENT = "dshtrading-updater-open";
|
|
85
|
+
//#endregion
|
|
69
86
|
//#region src/client/api.ts
|
|
70
87
|
var UpdaterBridgeError = class extends Error {
|
|
71
88
|
status;
|
|
@@ -112,65 +129,56 @@ window.__ModuleLoader__.load({
|
|
|
112
129
|
return window.desktop;
|
|
113
130
|
}
|
|
114
131
|
//#endregion
|
|
115
|
-
//#region src/client/
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
* event, not an import (client plugins never import each other's modules).
|
|
120
|
-
* Detail: { available: boolean, version?: string }.
|
|
121
|
-
*/
|
|
122
|
-
const UPDATE_AVAILABLE_EVENT = "dshtrading-update-available";
|
|
123
|
-
//#endregion
|
|
124
|
-
//#region \0dsh-css:/home/runner/work/dsh-trading/dsh-trading/packages/client-ui-updater/src/client/updater-section.module.css.mjs
|
|
125
|
-
const css = ".D0_G6G_root{--upd-text-primary:var(--dsw-alias-text-primary,#1a1e24);--upd-text-secondary:var(--dsw-alias-text-secondary,#5f6672);--upd-text-muted:var(--dsw-alias-text-muted,#8e95a3);--upd-border:var(--dsw-alias-border-l2,#e3e6ea);--upd-bg-hover:var(--dsw-alias-fill-hover,#0000000a);--upd-bg-active:var(--dsw-alias-primary-bg,#2563eb0f);--upd-primary:var(--dsw-alias-primary,#2563eb);--upd-ok:#16a34a;--upd-danger:#dc2626;color:var(--upd-text-primary);flex-direction:column;gap:16px;padding:4px 0 24px;font-size:13px;display:flex}body[data-ds-dark-theme] .D0_G6G_root,[data-theme=dark] .D0_G6G_root,:root[data-theme=dark] .D0_G6G_root,html.dark .D0_G6G_root,body.dark .D0_G6G_root{--upd-text-primary:var(--dsw-alias-text-primary,#f3f4f6);--upd-text-secondary:var(--dsw-alias-text-secondary,#9ca3af);--upd-text-muted:var(--dsw-alias-text-muted,#6b7280);--upd-border:var(--dsw-alias-border-l2,#ffffff1a);--upd-bg-hover:var(--dsw-alias-fill-hover,#ffffff0f);--upd-bg-active:#2563eb29;--upd-primary:#3b82f6;--upd-ok:#4ade80;--upd-danger:#f87171}.D0_G6G_lead{color:var(--upd-text-secondary);margin:0;font-size:13.5px;line-height:1.6}.D0_G6G_versions{border:1px solid var(--upd-border);background:var(--upd-bg-hover);border-radius:8px;flex-wrap:wrap;gap:6px 24px;padding:10px 12px;display:flex}.D0_G6G_versionItem{flex-direction:column;gap:2px;display:flex}.D0_G6G_versionLabel{color:var(--upd-text-muted);font-size:11.5px}.D0_G6G_versionValue{font-variant-numeric:tabular-nums;font-size:13px;font-weight:600}.D0_G6G_statusRow{flex-wrap:wrap;align-items:center;gap:12px;display:flex}.D0_G6G_statusText{color:var(--upd-text-secondary)}.D0_G6G_statusTextOk{color:var(--upd-ok)}.D0_G6G_statusTextAvailable{color:var(--upd-primary);font-weight:600}.D0_G6G_statusTextError{color:var(--upd-danger)}.D0_G6G_availableCard{border:1px solid var(--upd-primary);background:var(--upd-bg-active);border-radius:8px;flex-direction:column;gap:10px;padding:14px;display:flex}.D0_G6G_availableTitle{color:var(--upd-primary);margin:0;font-size:14px;font-weight:600}.D0_G6G_availableMeta{color:var(--upd-text-muted);margin:0;font-size:12px}.D0_G6G_notesTitle{color:var(--upd-text-secondary);margin:0;font-size:12.5px;font-weight:600}.D0_G6G_notes{border:1px solid var(--upd-border);background:var(--upd-bg-hover);color:var(--upd-text-secondary);white-space:pre-wrap;word-break:break-word;border-radius:6px;max-height:260px;margin:0;padding:10px 12px;font-family:inherit;font-size:12.5px;line-height:1.6;overflow:auto}.D0_G6G_actions{flex-wrap:wrap;align-items:center;gap:10px;display:flex}.D0_G6G_primaryButton{appearance:none;background:var(--upd-primary);color:#fff;cursor:pointer;border:none;border-radius:6px;padding:7px 16px;font-size:13px;font-weight:500}.D0_G6G_primaryButton:hover{filter:brightness(1.08)}.D0_G6G_primaryButton:disabled{opacity:.55;cursor:default;filter:none}.D0_G6G_secondaryButton{appearance:none;border:1px solid var(--upd-border);color:var(--upd-text-secondary);cursor:pointer;background:0 0;border-radius:6px;padding:6px 14px;font-size:13px}.D0_G6G_secondaryButton:hover{background:var(--upd-bg-hover)}.D0_G6G_secondaryButton:disabled{opacity:.55;cursor:default}.D0_G6G_link{color:var(--upd-primary);font-size:12.5px;text-decoration:none}.D0_G6G_link:hover{text-decoration:underline}.D0_G6G_progressWrap{flex-direction:column;gap:6px;display:flex}.D0_G6G_progressLabel{color:var(--upd-text-secondary);justify-content:space-between;font-size:12.5px;display:flex}.D0_G6G_progressTrack{background:var(--upd-bg-hover);border:1px solid var(--upd-border);border-radius:3px;height:6px;overflow:hidden}.D0_G6G_progressFill{background:var(--upd-primary);border-radius:3px;height:100%;transition:width .24s}.D0_G6G_progressIndeterminate{width:40%;animation:1.1s ease-in-out infinite alternate D0_G6G_upd-slide}@keyframes D0_G6G_upd-slide{0%{margin-left:0}to{margin-left:60%}}.D0_G6G_doneCard{border:1px solid var(--upd-ok);border-radius:8px;flex-direction:column;gap:8px;padding:14px;display:flex}.D0_G6G_doneTitle{color:var(--upd-ok);margin:0;font-size:14px;font-weight:600}.D0_G6G_doneMeta{color:var(--upd-text-secondary);margin:0;font-size:12.5px}.D0_G6G_errorText{color:var(--upd-danger);word-break:break-word;margin:0;font-size:12.5px}";
|
|
126
|
-
const tagId = "@dshtrading/client-ui-updater/updater-section.module.css";
|
|
127
|
-
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
132
|
+
//#region \0dsh-css:/home/runner/work/dsh-trading/dsh-trading/packages/client-ui-updater/src/client/updater-panel.module.css.mjs
|
|
133
|
+
const css$1 = ".SgPada_root{--upd-text-primary:var(--dsw-alias-text-primary,#1a1e24);--upd-text-secondary:var(--dsw-alias-text-secondary,#5f6672);--upd-text-muted:var(--dsw-alias-text-muted,#8e95a3);--upd-border:var(--dsw-alias-border-l2,#e3e6ea);--upd-bg-hover:var(--dsw-alias-fill-hover,#0000000a);--upd-bg-active:var(--dsw-alias-primary-bg,#2563eb0f);--upd-primary:var(--dsw-alias-primary,#2563eb);--upd-ok:#16a34a;--upd-danger:#dc2626;color:var(--upd-text-primary);flex-direction:column;gap:16px;padding:0;font-size:13px;display:flex}body[data-ds-dark-theme] .SgPada_root,[data-theme=dark] .SgPada_root,:root[data-theme=dark] .SgPada_root,html.dark .SgPada_root,body.dark .SgPada_root{--upd-text-primary:var(--dsw-alias-text-primary,#f3f4f6);--upd-text-secondary:var(--dsw-alias-text-secondary,#9ca3af);--upd-text-muted:var(--dsw-alias-text-muted,#6b7280);--upd-border:var(--dsw-alias-border-l2,#ffffff1a);--upd-bg-hover:var(--dsw-alias-fill-hover,#ffffff0f);--upd-bg-active:#2563eb29;--upd-primary:#3b82f6;--upd-ok:#4ade80;--upd-danger:#f87171}.SgPada_lead{color:var(--upd-text-secondary);margin:0;font-size:13.5px;line-height:1.6}.SgPada_versions{border:1px solid var(--upd-border);background:var(--upd-bg-hover);border-radius:8px;flex-wrap:wrap;gap:6px 24px;padding:10px 12px;display:flex}.SgPada_versionItem{flex-direction:column;gap:2px;display:flex}.SgPada_versionLabel{color:var(--upd-text-muted);font-size:11.5px}.SgPada_versionValue{font-variant-numeric:tabular-nums;font-size:13px;font-weight:600}.SgPada_statusRow{flex-wrap:wrap;align-items:center;gap:12px;display:flex}.SgPada_statusText{color:var(--upd-text-secondary)}.SgPada_statusTextOk{color:var(--upd-ok)}.SgPada_statusTextAvailable{color:var(--upd-primary);font-weight:600}.SgPada_statusTextError{color:var(--upd-danger)}.SgPada_availableCard{border:1px solid var(--upd-primary);background:var(--upd-bg-active);border-radius:8px;flex-direction:column;gap:10px;padding:14px;display:flex}.SgPada_availableTitle{color:var(--upd-primary);margin:0;font-size:14px;font-weight:600}.SgPada_availableMeta{color:var(--upd-text-muted);margin:0;font-size:12px}.SgPada_notesTitle{color:var(--upd-text-secondary);margin:0;font-size:12.5px;font-weight:600}.SgPada_notes{border:1px solid var(--upd-border);background:var(--upd-bg-hover);color:var(--upd-text-secondary);white-space:pre-wrap;word-break:break-word;border-radius:6px;max-height:260px;margin:0;padding:10px 12px;font-family:inherit;font-size:12.5px;line-height:1.6;overflow:auto}.SgPada_actions{flex-wrap:wrap;align-items:center;gap:10px;display:flex}.SgPada_primaryButton{appearance:none;background:var(--upd-primary);color:#fff;cursor:pointer;border:none;border-radius:6px;padding:7px 16px;font-size:13px;font-weight:500}.SgPada_primaryButton:hover{filter:brightness(1.08)}.SgPada_primaryButton:disabled{opacity:.55;cursor:default;filter:none}.SgPada_secondaryButton{appearance:none;border:1px solid var(--upd-border);color:var(--upd-text-secondary);cursor:pointer;background:0 0;border-radius:6px;padding:6px 14px;font-size:13px}.SgPada_secondaryButton:hover{background:var(--upd-bg-hover)}.SgPada_secondaryButton:disabled{opacity:.55;cursor:default}.SgPada_link{color:var(--upd-primary);font-size:12.5px;text-decoration:none}.SgPada_link:hover{text-decoration:underline}.SgPada_progressWrap{flex-direction:column;gap:6px;display:flex}.SgPada_progressLabel{color:var(--upd-text-secondary);justify-content:space-between;font-size:12.5px;display:flex}.SgPada_progressTrack{background:var(--upd-bg-hover);border:1px solid var(--upd-border);border-radius:3px;height:6px;overflow:hidden}.SgPada_progressFill{background:var(--upd-primary);border-radius:3px;height:100%;transition:width .24s}.SgPada_progressIndeterminate{width:40%;animation:1.1s ease-in-out infinite alternate SgPada_upd-slide}@keyframes SgPada_upd-slide{0%{margin-left:0}to{margin-left:60%}}.SgPada_doneCard{border:1px solid var(--upd-ok);border-radius:8px;flex-direction:column;gap:8px;padding:14px;display:flex}.SgPada_doneTitle{color:var(--upd-ok);margin:0;font-size:14px;font-weight:600}.SgPada_doneMeta{color:var(--upd-text-secondary);margin:0;font-size:12.5px}.SgPada_errorText{color:var(--upd-danger);word-break:break-word;margin:0;font-size:12.5px}";
|
|
134
|
+
const tagId$1 = "@dshtrading/client-ui-updater/updater-panel.module.css";
|
|
135
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
128
136
|
const tag = document.createElement("style");
|
|
129
137
|
tag.dataset.plugin = "@dshtrading/client-ui-updater";
|
|
130
|
-
tag.dataset.pluginCss = tagId;
|
|
131
|
-
tag.textContent = css;
|
|
138
|
+
tag.dataset.pluginCss = tagId$1;
|
|
139
|
+
tag.textContent = css$1;
|
|
132
140
|
document.head.appendChild(tag);
|
|
133
141
|
}
|
|
134
|
-
var
|
|
135
|
-
"
|
|
136
|
-
"
|
|
137
|
-
"actions": "
|
|
138
|
-
"
|
|
139
|
-
"
|
|
140
|
-
"
|
|
141
|
-
"
|
|
142
|
-
"
|
|
143
|
-
"
|
|
144
|
-
"
|
|
145
|
-
"
|
|
146
|
-
"
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"
|
|
151
|
-
"
|
|
152
|
-
"
|
|
153
|
-
"
|
|
154
|
-
"
|
|
155
|
-
"
|
|
156
|
-
"
|
|
157
|
-
"
|
|
158
|
-
"
|
|
159
|
-
"
|
|
160
|
-
"
|
|
161
|
-
"
|
|
162
|
-
"
|
|
163
|
-
"
|
|
164
|
-
"
|
|
142
|
+
var updater_panel_module_css_default = {
|
|
143
|
+
"primaryButton": "SgPada_primaryButton",
|
|
144
|
+
"progressLabel": "SgPada_progressLabel",
|
|
145
|
+
"actions": "SgPada_actions",
|
|
146
|
+
"versions": "SgPada_versions",
|
|
147
|
+
"availableCard": "SgPada_availableCard",
|
|
148
|
+
"notes": "SgPada_notes",
|
|
149
|
+
"link": "SgPada_link",
|
|
150
|
+
"doneTitle": "SgPada_doneTitle",
|
|
151
|
+
"doneMeta": "SgPada_doneMeta",
|
|
152
|
+
"progressWrap": "SgPada_progressWrap",
|
|
153
|
+
"availableMeta": "SgPada_availableMeta",
|
|
154
|
+
"upd-slide": "SgPada_upd-slide",
|
|
155
|
+
"versionItem": "SgPada_versionItem",
|
|
156
|
+
"statusTextError": "SgPada_statusTextError",
|
|
157
|
+
"notesTitle": "SgPada_notesTitle",
|
|
158
|
+
"versionValue": "SgPada_versionValue",
|
|
159
|
+
"statusTextAvailable": "SgPada_statusTextAvailable",
|
|
160
|
+
"progressTrack": "SgPada_progressTrack",
|
|
161
|
+
"doneCard": "SgPada_doneCard",
|
|
162
|
+
"progressIndeterminate": "SgPada_progressIndeterminate",
|
|
163
|
+
"progressFill": "SgPada_progressFill",
|
|
164
|
+
"availableTitle": "SgPada_availableTitle",
|
|
165
|
+
"versionLabel": "SgPada_versionLabel",
|
|
166
|
+
"lead": "SgPada_lead",
|
|
167
|
+
"statusText": "SgPada_statusText",
|
|
168
|
+
"statusTextOk": "SgPada_statusTextOk",
|
|
169
|
+
"errorText": "SgPada_errorText",
|
|
170
|
+
"root": "SgPada_root",
|
|
171
|
+
"statusRow": "SgPada_statusRow",
|
|
172
|
+
"secondaryButton": "SgPada_secondaryButton"
|
|
165
173
|
};
|
|
166
174
|
//#endregion
|
|
167
|
-
//#region src/client/
|
|
175
|
+
//#region src/client/UpdaterPanel.tsx
|
|
168
176
|
/**
|
|
169
|
-
* Software-update
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
177
|
+
* Software-update dialog body (rendered inside UpdaterDialog). Pure view over
|
|
178
|
+
* /dshtrading/api/updater: renders the current versions, the latest GitHub
|
|
179
|
+
* release with its notes, and drives the incremental apply + restart flow.
|
|
180
|
+
* Polls the host snapshot while mounted (faster while an apply is running);
|
|
181
|
+
* no SSE dependency.
|
|
174
182
|
*/
|
|
175
183
|
/** Poll cadences: lazy when idle, tight while an apply pipeline is running. */
|
|
176
184
|
const POLL_IDLE_MS = 3e4;
|
|
@@ -182,7 +190,7 @@ window.__ModuleLoader__.load({
|
|
|
182
190
|
if (Number.isNaN(parsed.getTime())) return "";
|
|
183
191
|
return parsed.toISOString().slice(0, 10);
|
|
184
192
|
}
|
|
185
|
-
function
|
|
193
|
+
function UpdaterPanel({ t }) {
|
|
186
194
|
const [state, setState] = (0, react.useState)(void 0);
|
|
187
195
|
const [actionError, setActionError] = (0, react.useState)(void 0);
|
|
188
196
|
const [checkBusy, setCheckBusy] = (0, react.useState)(false);
|
|
@@ -249,52 +257,52 @@ window.__ModuleLoader__.load({
|
|
|
249
257
|
const hasUpdate = check?.available === true && apply?.phase !== "done";
|
|
250
258
|
hasUpdate && latest?.payloadAvailable;
|
|
251
259
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
252
|
-
className:
|
|
260
|
+
className: updater_panel_module_css_default.root,
|
|
253
261
|
children: [
|
|
254
262
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
255
|
-
className:
|
|
263
|
+
className: updater_panel_module_css_default.lead,
|
|
256
264
|
children: t("lead")
|
|
257
265
|
}),
|
|
258
266
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
259
|
-
className:
|
|
267
|
+
className: updater_panel_module_css_default.versions,
|
|
260
268
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
261
|
-
className:
|
|
269
|
+
className: updater_panel_module_css_default.versionItem,
|
|
262
270
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
263
|
-
className:
|
|
271
|
+
className: updater_panel_module_css_default.versionLabel,
|
|
264
272
|
children: t("currentVersion")
|
|
265
273
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
266
|
-
className:
|
|
274
|
+
className: updater_panel_module_css_default.versionValue,
|
|
267
275
|
children: environment?.familyVersion ?? "—"
|
|
268
276
|
})]
|
|
269
277
|
}), environment?.appVersion !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
270
|
-
className:
|
|
278
|
+
className: updater_panel_module_css_default.versionItem,
|
|
271
279
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
272
|
-
className:
|
|
280
|
+
className: updater_panel_module_css_default.versionLabel,
|
|
273
281
|
children: t("desktopApp")
|
|
274
282
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
275
|
-
className:
|
|
283
|
+
className: updater_panel_module_css_default.versionValue,
|
|
276
284
|
children: environment.appVersion
|
|
277
285
|
})]
|
|
278
286
|
})]
|
|
279
287
|
}),
|
|
280
288
|
environment !== void 0 && !environment.supported && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
281
|
-
className:
|
|
289
|
+
className: updater_panel_module_css_default.statusText,
|
|
282
290
|
children: t("unsupported")
|
|
283
291
|
}),
|
|
284
292
|
environment?.supported === true && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
285
293
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
286
|
-
className:
|
|
294
|
+
className: updater_panel_module_css_default.statusRow,
|
|
287
295
|
children: [
|
|
288
296
|
check?.status === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
289
|
-
className: `${
|
|
297
|
+
className: `${updater_panel_module_css_default.statusText} ${updater_panel_module_css_default.statusTextError}`,
|
|
290
298
|
children: t("checkError", { message: check.error ?? "" })
|
|
291
299
|
}),
|
|
292
300
|
check?.status === "ok" && !hasUpdate && apply?.phase !== "done" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
293
|
-
className: `${
|
|
301
|
+
className: `${updater_panel_module_css_default.statusText} ${updater_panel_module_css_default.statusTextOk}`,
|
|
294
302
|
children: t("upToDate")
|
|
295
303
|
}),
|
|
296
304
|
check?.at !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
297
|
-
className:
|
|
305
|
+
className: updater_panel_module_css_default.statusText,
|
|
298
306
|
children: [
|
|
299
307
|
t("lastCheck"),
|
|
300
308
|
":",
|
|
@@ -303,12 +311,12 @@ window.__ModuleLoader__.load({
|
|
|
303
311
|
]
|
|
304
312
|
}),
|
|
305
313
|
check?.at === void 0 && check?.status !== "ok" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
306
|
-
className:
|
|
314
|
+
className: updater_panel_module_css_default.statusText,
|
|
307
315
|
children: t("never")
|
|
308
316
|
}),
|
|
309
317
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
310
318
|
type: "button",
|
|
311
|
-
className:
|
|
319
|
+
className: updater_panel_module_css_default.secondaryButton,
|
|
312
320
|
disabled: checkBusy || running,
|
|
313
321
|
onClick: () => {
|
|
314
322
|
handleCheck();
|
|
@@ -317,7 +325,7 @@ window.__ModuleLoader__.load({
|
|
|
317
325
|
}),
|
|
318
326
|
actionError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
319
327
|
type: "button",
|
|
320
|
-
className:
|
|
328
|
+
className: updater_panel_module_css_default.secondaryButton,
|
|
321
329
|
onClick: () => {
|
|
322
330
|
handleCheck();
|
|
323
331
|
},
|
|
@@ -326,51 +334,51 @@ window.__ModuleLoader__.load({
|
|
|
326
334
|
]
|
|
327
335
|
}),
|
|
328
336
|
running && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
329
|
-
className:
|
|
337
|
+
className: updater_panel_module_css_default.progressWrap,
|
|
330
338
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
331
|
-
className:
|
|
339
|
+
className: updater_panel_module_css_default.progressLabel,
|
|
332
340
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: progress?.step === "download" ? t("phase.download") : progress?.step === "verify" ? t("phase.verify") : progress?.step === "install" ? t("phase.install") : t("phase.prepare") }), progress?.percent !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("progress", { percent: progress.percent }) })]
|
|
333
341
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
334
|
-
className:
|
|
342
|
+
className: updater_panel_module_css_default.progressTrack,
|
|
335
343
|
role: "progressbar",
|
|
336
344
|
"aria-valuemin": 0,
|
|
337
345
|
"aria-valuemax": 100,
|
|
338
346
|
"aria-valuenow": progress?.percent ?? void 0,
|
|
339
347
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
340
|
-
className: `${
|
|
348
|
+
className: `${updater_panel_module_css_default.progressFill} ${progress?.percent === void 0 ? updater_panel_module_css_default.progressIndeterminate : ""}`,
|
|
341
349
|
style: progress?.percent === void 0 ? void 0 : { width: `${progress.percent}%` }
|
|
342
350
|
})
|
|
343
351
|
})]
|
|
344
352
|
}),
|
|
345
353
|
hasUpdate && latest !== void 0 && !running && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
346
|
-
className:
|
|
354
|
+
className: updater_panel_module_css_default.availableCard,
|
|
347
355
|
children: [
|
|
348
356
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
349
|
-
className:
|
|
357
|
+
className: updater_panel_module_css_default.availableTitle,
|
|
350
358
|
children: t("available", { version: latest.version })
|
|
351
359
|
}),
|
|
352
360
|
publishedDay !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
353
|
-
className:
|
|
361
|
+
className: updater_panel_module_css_default.availableMeta,
|
|
354
362
|
children: t("publishedAt", { date: publishedDay })
|
|
355
363
|
}),
|
|
356
364
|
latest.notes.trim() !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
357
|
-
className:
|
|
365
|
+
className: updater_panel_module_css_default.notesTitle,
|
|
358
366
|
children: t("notesTitle")
|
|
359
367
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
360
|
-
className:
|
|
368
|
+
className: updater_panel_module_css_default.notes,
|
|
361
369
|
children: latest.notes
|
|
362
370
|
})] }),
|
|
363
371
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
364
|
-
className:
|
|
372
|
+
className: updater_panel_module_css_default.actions,
|
|
365
373
|
children: [latest.payloadAvailable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
366
374
|
type: "button",
|
|
367
|
-
className:
|
|
375
|
+
className: updater_panel_module_css_default.primaryButton,
|
|
368
376
|
onClick: () => {
|
|
369
377
|
handleApply();
|
|
370
378
|
},
|
|
371
379
|
children: t("applyNow")
|
|
372
380
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
373
|
-
className:
|
|
381
|
+
className: updater_panel_module_css_default.link,
|
|
374
382
|
href: releasesUrl,
|
|
375
383
|
target: "_blank",
|
|
376
384
|
rel: "noreferrer",
|
|
@@ -378,37 +386,37 @@ window.__ModuleLoader__.load({
|
|
|
378
386
|
})]
|
|
379
387
|
}),
|
|
380
388
|
!latest.payloadAvailable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
381
|
-
className:
|
|
389
|
+
className: updater_panel_module_css_default.doneMeta,
|
|
382
390
|
children: t("payloadMissing")
|
|
383
391
|
})
|
|
384
392
|
]
|
|
385
393
|
}),
|
|
386
394
|
apply?.phase === "done" && apply.targetVersion !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
387
|
-
className:
|
|
395
|
+
className: updater_panel_module_css_default.doneCard,
|
|
388
396
|
children: [
|
|
389
397
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
390
|
-
className:
|
|
398
|
+
className: updater_panel_module_css_default.doneTitle,
|
|
391
399
|
children: t("done", { version: apply.targetVersion })
|
|
392
400
|
}),
|
|
393
401
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
394
|
-
className:
|
|
402
|
+
className: updater_panel_module_css_default.doneMeta,
|
|
395
403
|
children: t("restartHint")
|
|
396
404
|
}),
|
|
397
405
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
398
|
-
className:
|
|
406
|
+
className: updater_panel_module_css_default.actions,
|
|
399
407
|
children: [
|
|
400
408
|
desktopBridge()?.relaunch !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
401
409
|
type: "button",
|
|
402
|
-
className:
|
|
410
|
+
className: updater_panel_module_css_default.primaryButton,
|
|
403
411
|
onClick: handleRestart,
|
|
404
412
|
children: t("restartNow")
|
|
405
413
|
}),
|
|
406
414
|
desktopBridge()?.relaunch === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
407
|
-
className:
|
|
415
|
+
className: updater_panel_module_css_default.doneMeta,
|
|
408
416
|
children: t("restartManual")
|
|
409
417
|
}),
|
|
410
418
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
411
|
-
className:
|
|
419
|
+
className: updater_panel_module_css_default.link,
|
|
412
420
|
href: releasesUrl,
|
|
413
421
|
target: "_blank",
|
|
414
422
|
rel: "noreferrer",
|
|
@@ -419,12 +427,12 @@ window.__ModuleLoader__.load({
|
|
|
419
427
|
]
|
|
420
428
|
}),
|
|
421
429
|
apply?.phase === "error" && apply.error !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
422
|
-
className:
|
|
430
|
+
className: updater_panel_module_css_default.errorText,
|
|
423
431
|
children: apply.error
|
|
424
432
|
})
|
|
425
433
|
] }),
|
|
426
434
|
environment === void 0 || !environment.supported ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
427
|
-
className:
|
|
435
|
+
className: updater_panel_module_css_default.link,
|
|
428
436
|
href: releasesUrl,
|
|
429
437
|
target: "_blank",
|
|
430
438
|
rel: "noreferrer",
|
|
@@ -434,27 +442,128 @@ window.__ModuleLoader__.load({
|
|
|
434
442
|
});
|
|
435
443
|
}
|
|
436
444
|
//#endregion
|
|
445
|
+
//#region \0dsh-css:/home/runner/work/dsh-trading/dsh-trading/packages/client-ui-updater/src/client/updater-dialog.module.css.mjs
|
|
446
|
+
const css = ".Sd___q_overlay{z-index:900;pointer-events:auto;--upd-text-primary:var(--dsw-alias-text-primary,#1a1e24);--upd-text-secondary:var(--dsw-alias-text-secondary,#5f6672);--upd-text-muted:var(--dsw-alias-text-muted,#8e95a3);--upd-border:var(--dsw-alias-border-l2,#e3e6ea);--upd-bg-layer:var(--dsw-alias-bg-layer-2,#fff);--upd-bg-hover:var(--dsw-alias-fill-hover,#0000000a);--upd-mask:var(--dsw-alias-bg-mask-1,#00000052);--upd-shadow:var(--dsw-elevation-prominent,0 12px 32px #0000002e);justify-content:center;align-items:center;display:flex;position:fixed;inset:0}body[data-ds-dark-theme] .Sd___q_overlay,[data-theme=dark] .Sd___q_overlay,:root[data-theme=dark] .Sd___q_overlay,html.dark .Sd___q_overlay,body.dark .Sd___q_overlay{--upd-text-primary:var(--dsw-alias-text-primary,#f3f4f6);--upd-text-secondary:var(--dsw-alias-text-secondary,#9ca3af);--upd-text-muted:var(--dsw-alias-text-muted,#6b7280);--upd-border:var(--dsw-alias-border-l2,#ffffff1a);--upd-bg-layer:var(--dsw-alias-bg-layer-2,#1f232b);--upd-bg-hover:var(--dsw-alias-fill-hover,#ffffff0f);--upd-mask:var(--dsw-alias-bg-mask-1,#00000080);--upd-shadow:var(--dsw-elevation-prominent,0 12px 32px #00000080)}.Sd___q_mask{background:var(--upd-mask);backdrop-filter:var(--dsw-mask-blur,blur(2px));position:absolute;inset:0}.Sd___q_panel{z-index:1;background:var(--upd-bg-layer);width:560px;max-width:calc(100vw - 48px);max-height:min(640px,100vh - 48px);color:var(--upd-text-primary);border:1px solid var(--upd-border);box-shadow:var(--upd-shadow);border-radius:16px;flex-direction:column;display:flex;position:relative;overflow:hidden}.Sd___q_header{border-bottom:1px solid var(--upd-border);flex:none;justify-content:space-between;align-items:center;gap:8px;padding:14px 14px 10px 18px;display:flex}.Sd___q_title{color:var(--upd-text-primary);font-size:15px;font-weight:600}.Sd___q_close{appearance:none;color:var(--upd-text-secondary);cursor:pointer;background:0 0;border:none;border-radius:50%;justify-content:center;align-items:center;width:28px;height:28px;padding:0;transition:background .15s,color .15s;display:inline-flex}.Sd___q_close:hover{background:var(--upd-bg-hover);color:var(--upd-text-primary)}.Sd___q_body{flex:1;min-height:0;padding:14px 18px 18px;overflow-y:auto}";
|
|
447
|
+
const tagId = "@dshtrading/client-ui-updater/updater-dialog.module.css";
|
|
448
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
449
|
+
const tag = document.createElement("style");
|
|
450
|
+
tag.dataset.plugin = "@dshtrading/client-ui-updater";
|
|
451
|
+
tag.dataset.pluginCss = tagId;
|
|
452
|
+
tag.textContent = css;
|
|
453
|
+
document.head.appendChild(tag);
|
|
454
|
+
}
|
|
455
|
+
var updater_dialog_module_css_default = {
|
|
456
|
+
"mask": "Sd___q_mask",
|
|
457
|
+
"header": "Sd___q_header",
|
|
458
|
+
"panel": "Sd___q_panel",
|
|
459
|
+
"overlay": "Sd___q_overlay",
|
|
460
|
+
"title": "Sd___q_title",
|
|
461
|
+
"close": "Sd___q_close",
|
|
462
|
+
"body": "Sd___q_body"
|
|
463
|
+
};
|
|
464
|
+
//#endregion
|
|
465
|
+
//#region src/client/UpdaterDialog.tsx
|
|
466
|
+
/**
|
|
467
|
+
* Software-update dialog (the 'shell.overlay' entry registered by this plugin).
|
|
468
|
+
* The sidebar's update entry dispatches UPDATER_OPEN_EVENT; this component owns
|
|
469
|
+
* the modal chrome (mask click + Escape close) around UpdaterPanel. Frame-wide
|
|
470
|
+
* floating layer: fixed overlay opts back into pointer events.
|
|
471
|
+
*/
|
|
472
|
+
function UpdaterDialog({ t }) {
|
|
473
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
474
|
+
(0, react.useEffect)(() => {
|
|
475
|
+
const onOpen = () => {
|
|
476
|
+
setOpen(true);
|
|
477
|
+
};
|
|
478
|
+
window.addEventListener(UPDATER_OPEN_EVENT, onOpen);
|
|
479
|
+
return () => {
|
|
480
|
+
window.removeEventListener(UPDATER_OPEN_EVENT, onOpen);
|
|
481
|
+
};
|
|
482
|
+
}, []);
|
|
483
|
+
const close = (0, react.useCallback)(() => {
|
|
484
|
+
setOpen(false);
|
|
485
|
+
}, []);
|
|
486
|
+
(0, react.useEffect)(() => {
|
|
487
|
+
if (!open) return;
|
|
488
|
+
const onKeyDown = (event) => {
|
|
489
|
+
if (event.key === "Escape") close();
|
|
490
|
+
};
|
|
491
|
+
document.addEventListener("keydown", onKeyDown);
|
|
492
|
+
return () => {
|
|
493
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
494
|
+
};
|
|
495
|
+
}, [open, close]);
|
|
496
|
+
if (!open) return null;
|
|
497
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
498
|
+
className: updater_dialog_module_css_default.overlay,
|
|
499
|
+
role: "presentation",
|
|
500
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
501
|
+
className: updater_dialog_module_css_default.mask,
|
|
502
|
+
"aria-hidden": "true",
|
|
503
|
+
onClick: close
|
|
504
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
505
|
+
className: updater_dialog_module_css_default.panel,
|
|
506
|
+
role: "dialog",
|
|
507
|
+
"aria-modal": "true",
|
|
508
|
+
"aria-label": t("nav"),
|
|
509
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
510
|
+
className: updater_dialog_module_css_default.header,
|
|
511
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
512
|
+
className: updater_dialog_module_css_default.title,
|
|
513
|
+
children: t("nav")
|
|
514
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
515
|
+
type: "button",
|
|
516
|
+
className: updater_dialog_module_css_default.close,
|
|
517
|
+
"aria-label": t("close"),
|
|
518
|
+
title: t("close"),
|
|
519
|
+
onClick: close,
|
|
520
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
521
|
+
viewBox: "0 0 16 16",
|
|
522
|
+
width: 14,
|
|
523
|
+
height: 14,
|
|
524
|
+
"aria-hidden": "true",
|
|
525
|
+
fill: "none",
|
|
526
|
+
stroke: "currentColor",
|
|
527
|
+
strokeWidth: "1.4",
|
|
528
|
+
strokeLinecap: "round",
|
|
529
|
+
strokeLinejoin: "round",
|
|
530
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M4.25 4.25l7.5 7.5M11.75 4.25l-7.5 7.5" })
|
|
531
|
+
})
|
|
532
|
+
})]
|
|
533
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
534
|
+
className: updater_dialog_module_css_default.body,
|
|
535
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UpdaterPanel, { t })
|
|
536
|
+
})]
|
|
537
|
+
})]
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
//#endregion
|
|
437
541
|
//#region src/client/index.ts
|
|
438
|
-
/**
|
|
542
|
+
/** This dialog's locale namespace. */
|
|
439
543
|
const NS = "dshtrading.updater";
|
|
440
544
|
/** Required services (cordis fiber inject). */
|
|
441
545
|
const inject = ["slots", "locale"];
|
|
442
|
-
/**
|
|
546
|
+
/**
|
|
547
|
+
* Register the update dialog on shell.overlay (no settings.section: the entry
|
|
548
|
+
* moved beside Settings in the sidebar bottom bar). The sidebar asks this
|
|
549
|
+
* plugin to open through the UPDATER_OPEN_EVENT window event — cross-plugin
|
|
550
|
+
* coupling is a DOM event, never an import.
|
|
551
|
+
*/
|
|
443
552
|
function apply(ctx) {
|
|
444
|
-
|
|
553
|
+
ctx.locale.bind(NS);
|
|
445
554
|
ctx.effect(() => ctx.locale.register(NS, {
|
|
446
555
|
zh,
|
|
447
556
|
en
|
|
448
557
|
}), "dsh-trading-updater: dictionaries");
|
|
449
|
-
ctx.slots.inject("
|
|
450
|
-
name: "
|
|
451
|
-
id: "updater",
|
|
452
|
-
order:
|
|
453
|
-
label: () => t("nav"),
|
|
558
|
+
ctx.slots.inject("shell.overlay", () => ctx.slots.register({
|
|
559
|
+
name: "shell.overlay",
|
|
560
|
+
id: "dshtrading-updater-dialog",
|
|
561
|
+
order: 90,
|
|
454
562
|
locale: NS
|
|
455
|
-
},
|
|
563
|
+
}, UpdaterDialog));
|
|
456
564
|
}
|
|
457
565
|
//#endregion
|
|
566
|
+
exports.UPDATER_OPEN_EVENT = UPDATER_OPEN_EVENT;
|
|
458
567
|
exports.UPDATE_AVAILABLE_EVENT = UPDATE_AVAILABLE_EVENT;
|
|
459
568
|
exports.apply = apply;
|
|
460
569
|
exports.inject = inject;
|
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["useState","useRef","useCallback","css"],"sources":["../src/client/locales.ts","../src/client/api.ts","../src/client/contract.ts","../src/client/UpdaterSection.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * client-ui-updater 词典(纯数据模块:零运行时依赖)。\n *\n * 单一来源:本包 client apply 注册 zh/en(typed register 编译期校验键位);\n * packages/dsh-i18n 语言包构建期 import 本模块注册 zh-CN;scripts/i18n-audit.mjs\n * 静态加载本模块做 zh/en 键对齐与占位符对齐门禁。\n */\nimport type { UpdaterLocaleKey } from './contract.ts'\n\nexport const zh: Record<UpdaterLocaleKey, string> = {\n nav: '软件更新',\n lead: '检测 GitHub Releases 上的新版本,增量更新只下载变动的交易插件包,无需重装应用。',\n currentVersion: '交易插件版本',\n desktopApp: '桌面应用版本',\n unsupported: '当前环境不支持自动增量更新(仅 DSH Trading 桌面版支持)。可以前往发布页手动下载完整安装包。',\n viewReleases: '在 GitHub 查看发布',\n checkNow: '检查更新',\n checking: '正在检查…',\n lastCheck: '上次检查',\n never: '尚未检查',\n upToDate: '已是最新版本。',\n available: '发现新版本 {version}',\n publishedAt: '发布于 {date}',\n notesTitle: '更新说明',\n applyNow: '立即更新',\n payloadMissing: '该版本未附带增量更新包,请前往发布页下载完整安装包。',\n 'phase.prepare': '正在准备…',\n 'phase.download': '正在下载增量包…',\n 'phase.verify': '正在校验增量包…',\n 'phase.install': '正在安装更新…',\n progress: '{percent}%',\n done: '已更新到 {version}',\n restartHint: '重启 DSH Trading 后生效。',\n restartNow: '重启应用',\n restartManual: '请手动重启 DSH Trading 以完成更新。',\n checkError: '检查失败:{message}',\n retry: '重试',\n}\n\nexport const en: Record<UpdaterLocaleKey, string> = {\n nav: 'Software updates',\n lead: 'Detects new versions published on GitHub Releases and applies incremental updates — only the changed trading plugin packages are downloaded, no reinstall needed.',\n currentVersion: 'Trading plugins',\n desktopApp: 'Desktop app',\n unsupported: 'Incremental updates are only available inside the DSH Trading desktop app. You can download a full installer from the releases page.',\n viewReleases: 'View releases on GitHub',\n checkNow: 'Check for updates',\n checking: 'Checking…',\n lastCheck: 'Last checked',\n never: 'Never checked',\n upToDate: 'You are up to date.',\n available: 'New version {version} available',\n publishedAt: 'Published {date}',\n notesTitle: 'Release notes',\n applyNow: 'Update now',\n payloadMissing: 'This release does not carry the incremental update payload. Please download a full installer from the releases page.',\n 'phase.prepare': 'Preparing…',\n 'phase.download': 'Downloading update payload…',\n 'phase.verify': 'Verifying update payload…',\n 'phase.install': 'Installing update…',\n progress: '{percent}%',\n done: 'Updated to {version}',\n restartHint: 'Restart DSH Trading to activate.',\n restartNow: 'Restart app',\n restartManual: 'Please restart DSH Trading manually to finish the update.',\n checkError: 'Check failed: {message}',\n retry: 'Retry',\n}\n","/**\n * Updater bridge client: same-origin fetch wrappers over\n * /dshtrading/api/updater (the node half registers the route behind the\n * browser-auth fence; same-origin fetch carries the auth cookie by default).\n * Error semantics mirror the tasks bridge: non-2xx or { ok:false } envelopes\n * become rejections carrying the business code.\n */\nimport type { UpdaterSnapshot } from '../updater-service.ts'\n\nexport class UpdaterBridgeError extends Error {\n constructor(readonly status: number, message: string, readonly code?: string) {\n super(message)\n }\n}\n\nasync function updaterJson<T>(path: string, init?: RequestInit): Promise<T> {\n const response = await fetch(path, init)\n if (!response.ok) {\n const body = await response.json().catch(() => undefined) as { code?: string; message?: string } | undefined\n const detail = typeof body?.message === 'string' && body.message !== '' ? ': ' + body.message : ''\n throw new UpdaterBridgeError(response.status, 'updater ' + path + ' failed: ' + String(response.status) + detail, body?.code)\n }\n const wire = await response.json() as T\n if (wire !== null && typeof wire === 'object' && (wire as { ok?: unknown }).ok === false) {\n const business = wire as { code?: string; message?: string }\n throw new UpdaterBridgeError(200, (business.code ?? 'UPDATER_UNKNOWN') + ': ' + (business.message ?? 'updater bridge error'), business.code)\n }\n return wire\n}\n\n/** Current updater snapshot (environment + check + apply state). */\nexport async function fetchUpdaterState(): Promise<UpdaterSnapshot> {\n return updaterJson<UpdaterSnapshot>('/dshtrading/api/updater/state', { headers: { accept: 'application/json' } })\n}\n\n/** Run a GitHub release check; force=true bypasses the host-side TTL cache. */\nexport async function requestUpdaterCheck(force: boolean): Promise<UpdaterSnapshot> {\n return updaterJson<UpdaterSnapshot>(`/dshtrading/api/updater/check?force=${force ? '1' : '0'}`, { headers: { accept: 'application/json' } })\n}\n\n/** Start the incremental apply pipeline; returns the running snapshot. */\nexport async function requestUpdaterApply(): Promise<UpdaterSnapshot> {\n return updaterJson<UpdaterSnapshot>('/dshtrading/api/updater/apply', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: '{}',\n })\n}\n\n/** Electron shell bridge exposed by the desktop preload (absent in browsers). */\ninterface DesktopBridge {\n relaunch?: () => void\n}\n\n/** Resolve the desktop shell bridge, if this page runs inside DSH Trading. */\nexport function desktopBridge(): DesktopBridge | undefined {\n if (typeof window === 'undefined' || !('desktop' in window)) return undefined\n return (window as { desktop?: DesktopBridge }).desktop\n}\n","/**\n * Locale contract for the updater settings section. The zh dictionary in\n * locales.ts is the key source of truth; this union + the LocaleNamespaceMap\n * merge give the framework-injected t seat its key types.\n */\nexport type UpdaterLocaleKey =\n | 'nav'\n | 'lead'\n | 'currentVersion'\n | 'desktopApp'\n | 'unsupported'\n | 'viewReleases'\n | 'checkNow'\n | 'checking'\n | 'lastCheck'\n | 'never'\n | 'upToDate'\n | 'available'\n | 'publishedAt'\n | 'notesTitle'\n | 'applyNow'\n | 'payloadMissing'\n | 'phase.prepare'\n | 'phase.download'\n | 'phase.verify'\n | 'phase.install'\n | 'progress'\n | 'done'\n | 'restartHint'\n | 'restartNow'\n | 'restartManual'\n | 'checkError'\n | 'retry'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** Updater settings section copy (check / notes / incremental apply). */\n 'dshtrading.updater': UpdaterLocaleKey\n }\n}\n\n/**\n * Window event contract with the trading shell rail (client-ui-trading\n * SessionRail badge). Cross-plugin coupling is intentionally a DOM custom\n * event, not an import (client plugins never import each other's modules).\n * Detail: { available: boolean, version?: string }.\n */\nexport const UPDATE_AVAILABLE_EVENT = 'dshtrading-update-available'\n","/**\n * Software-update settings page (the first-level section registered by this\n * plugin). Pure view over /dshtrading/api/updater: renders the current\n * versions, the latest GitHub release with its notes, and drives the\n * incremental apply + restart flow. Polls the host snapshot while mounted\n * (faster while an apply is running); no SSE dependency.\n */\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { UpdaterSnapshot } from '../updater-service.ts'\nimport { desktopBridge, fetchUpdaterState, requestUpdaterApply, requestUpdaterCheck } from './api.ts'\nimport { UPDATE_AVAILABLE_EVENT } from './contract.ts'\nimport css from './updater-section.module.css'\n\nexport type UpdaterSectionProps =\n & PropsRuntime<'settings.section'>\n & PropsLocale<'dshtrading.updater'>\n\n/** Poll cadences: lazy when idle, tight while an apply pipeline is running. */\nconst POLL_IDLE_MS = 30_000\nconst POLL_RUNNING_MS = 1_200\n\n/** ISO date (yyyy-mm-dd) for the published line; empty when unknown. */\nfunction formatDay(iso: string | undefined): string {\n if (iso === undefined) return ''\n const parsed = new Date(iso)\n if (Number.isNaN(parsed.getTime())) return ''\n return parsed.toISOString().slice(0, 10)\n}\n\nexport function UpdaterSection({ t }: UpdaterSectionProps) {\n const [state, setState] = useState<UpdaterSnapshot | undefined>(undefined)\n const [actionError, setActionError] = useState<string | undefined>(undefined)\n const [checkBusy, setCheckBusy] = useState(false)\n const applyBusyRef = useRef(false)\n\n const running = state?.apply.phase === 'running'\n\n const refresh = useCallback(async () => {\n try {\n setState(await fetchUpdaterState())\n } catch {\n // Bridge absent (headless profile / old deployment): keep the page quiet.\n }\n }, [])\n\n useEffect(() => { void refresh() }, [refresh])\n\n useEffect(() => {\n const interval = setInterval(() => { void refresh() }, running ? POLL_RUNNING_MS : POLL_IDLE_MS)\n return () => { clearInterval(interval) }\n }, [refresh, running])\n\n // Rail badge sync: mirror availability onto the window event the trading\n // shell rail listens to (see UPDATE_AVAILABLE_EVENT in contract.ts).\n useEffect(() => {\n if (state === undefined) return\n const available = state.check.available === true && state.apply.phase !== 'done'\n window.dispatchEvent(new CustomEvent(UPDATE_AVAILABLE_EVENT, {\n detail: { available, version: state.check.latest?.version },\n }))\n }, [state])\n\n const handleCheck = async (): Promise<void> => {\n setCheckBusy(true)\n setActionError(undefined)\n try {\n setState(await requestUpdaterCheck(true))\n } catch (error) {\n setActionError(error instanceof Error ? error.message : String(error))\n } finally {\n setCheckBusy(false)\n }\n }\n\n const handleApply = async (): Promise<void> => {\n if (applyBusyRef.current) return\n applyBusyRef.current = true\n setActionError(undefined)\n try {\n setState(await requestUpdaterApply())\n // Pipeline started: tighten polling immediately instead of waiting a tick.\n void refresh()\n } catch (error) {\n setActionError(error instanceof Error ? error.message : String(error))\n } finally {\n applyBusyRef.current = false\n }\n }\n\n const handleRestart = (): void => {\n desktopBridge()?.relaunch?.()\n }\n\n const environment = state?.environment\n const check = state?.check\n const apply = state?.apply\n const progress = state?.progress\n const latest = check?.latest\n const releasesUrl = latest?.url ?? 'https://github.com/zhu1090093659/dsh-trading/releases'\n const publishedDay = formatDay(latest?.publishedAt)\n const hasUpdate = check?.available === true && apply?.phase !== 'done'\n const applyable = hasUpdate && latest?.payloadAvailable === true\n\n return (\n <div className={css.root}>\n <p className={css.lead}>{t('lead')}</p>\n\n <div className={css.versions}>\n <div className={css.versionItem}>\n <span className={css.versionLabel}>{t('currentVersion')}</span>\n <span className={css.versionValue}>{environment?.familyVersion ?? '—'}</span>\n </div>\n {environment?.appVersion !== undefined && (\n <div className={css.versionItem}>\n <span className={css.versionLabel}>{t('desktopApp')}</span>\n <span className={css.versionValue}>{environment.appVersion}</span>\n </div>\n )}\n </div>\n\n {environment !== undefined && !environment.supported && (\n <p className={css.statusText}>{t('unsupported')}</p>\n )}\n\n {environment?.supported === true && (\n <>\n <div className={css.statusRow}>\n {check?.status === 'error' && (\n <span className={`${css.statusText} ${css.statusTextError}`}>\n {t('checkError', { message: check.error ?? '' })}\n </span>\n )}\n {check?.status === 'ok' && !hasUpdate && apply?.phase !== 'done' && (\n <span className={`${css.statusText} ${css.statusTextOk}`}>{t('upToDate')}</span>\n )}\n {check?.at !== undefined && (\n <span className={css.statusText}>\n {t('lastCheck')}\n :\n {' '}\n {check.at.slice(0, 19).replace('T', ' ')}\n </span>\n )}\n {check?.at === undefined && check?.status !== 'ok' && (\n <span className={css.statusText}>{t('never')}</span>\n )}\n <button\n type=\"button\"\n className={css.secondaryButton}\n disabled={checkBusy || running}\n onClick={() => { void handleCheck() }}\n >\n {checkBusy ? t('checking') : t('checkNow')}\n </button>\n {actionError !== undefined && (\n <button type=\"button\" className={css.secondaryButton} onClick={() => { void handleCheck() }}>\n {t('retry')}\n </button>\n )}\n </div>\n\n {running && (\n <div className={css.progressWrap}>\n <span className={css.progressLabel}>\n <span>\n {progress?.step === 'download'\n ? t('phase.download')\n : progress?.step === 'verify'\n ? t('phase.verify')\n : progress?.step === 'install'\n ? t('phase.install')\n : t('phase.prepare')}\n </span>\n {progress?.percent !== undefined && (\n <span>{t('progress', { percent: progress.percent })}</span>\n )}\n </span>\n <div\n className={css.progressTrack}\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={progress?.percent ?? undefined}\n >\n <div\n className={`${css.progressFill} ${progress?.percent === undefined ? css.progressIndeterminate : ''}`}\n style={progress?.percent === undefined ? undefined : { width: `${progress.percent}%` }}\n />\n </div>\n </div>\n )}\n\n {hasUpdate && latest !== undefined && !running && (\n <div className={css.availableCard}>\n <p className={css.availableTitle}>{t('available', { version: latest.version })}</p>\n {publishedDay !== '' && (\n <p className={css.availableMeta}>{t('publishedAt', { date: publishedDay })}</p>\n )}\n {latest.notes.trim() !== '' && (\n <>\n <span className={css.notesTitle}>{t('notesTitle')}</span>\n <pre className={css.notes}>{latest.notes}</pre>\n </>\n )}\n <div className={css.actions}>\n {latest.payloadAvailable && (\n <button\n type=\"button\"\n className={css.primaryButton}\n onClick={() => { void handleApply() }}\n >\n {t('applyNow')}\n </button>\n )}\n <a className={css.link} href={releasesUrl} target=\"_blank\" rel=\"noreferrer\">\n {t('viewReleases')}\n </a>\n </div>\n {!latest.payloadAvailable && (\n <p className={css.doneMeta}>{t('payloadMissing')}</p>\n )}\n </div>\n )}\n\n {apply?.phase === 'done' && apply.targetVersion !== undefined && (\n <div className={css.doneCard}>\n <p className={css.doneTitle}>{t('done', { version: apply.targetVersion })}</p>\n <p className={css.doneMeta}>{t('restartHint')}</p>\n <div className={css.actions}>\n {desktopBridge()?.relaunch !== undefined && (\n <button type=\"button\" className={css.primaryButton} onClick={handleRestart}>\n {t('restartNow')}\n </button>\n )}\n {desktopBridge()?.relaunch === undefined && (\n <span className={css.doneMeta}>{t('restartManual')}</span>\n )}\n <a className={css.link} href={releasesUrl} target=\"_blank\" rel=\"noreferrer\">\n {t('viewReleases')}\n </a>\n </div>\n </div>\n )}\n\n {apply?.phase === 'error' && apply.error !== undefined && (\n <p className={css.errorText}>{apply.error}</p>\n )}\n </>\n )}\n\n {environment === undefined || !environment.supported ? (\n <a className={css.link} href={releasesUrl} target=\"_blank\" rel=\"noreferrer\">\n {t('viewReleases')}\n </a>\n ) : null}\n </div>\n )\n}\n","/**\n * dsh-trading auto-update, browser half — the '软件更新' first-level section\n * inside the host settings panel (settings.section, order 20: after the\n * official general/models/plugins and the trading section at order 8).\n *\n * The page talks to the node half over /dshtrading/api/updater (same-origin\n * fetch inside the browser-auth fence). In environments without incremental\n * support (dev checkouts, headless profiles) it degrades to an information\n * surface linking the GitHub releases page.\n */\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from './contract.ts'\nimport { en, zh } from './locales.ts'\nimport { UpdaterSection } from './UpdaterSection.tsx'\n\nimport { UPDATE_AVAILABLE_EVENT } from './contract.ts'\n/** 本面板/字符串翻译的 locale namespace。 */\nconst NS = 'dshtrading.updater'\n\n/** Required services (cordis fiber inject). */\nexport const inject = ['slots', 'locale']\n\n/** 注册『软件更新』设置一级菜单。 */\nexport function apply(ctx: ClientContext): void {\n const t = ctx.locale.bind(NS)\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-trading-updater: dictionaries')\n\n ctx.slots.inject('settings.section', () => ctx.slots.register({\n name: 'settings.section',\n id: 'updater',\n order: 20,\n label: () => t('nav'),\n locale: NS,\n }, UpdaterSection))\n}\n\nexport { UPDATE_AVAILABLE_EVENT } from './contract.ts'\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["useState","useRef","useCallback","css","useState","useCallback","css"],"sources":["../src/client/locales.ts","../src/client/contract.ts","../src/client/api.ts","../src/client/UpdaterPanel.tsx","../src/client/UpdaterDialog.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * client-ui-updater 词典(纯数据模块:零运行时依赖)。\n *\n * 单一来源:本包 client apply 注册 zh/en(typed register 编译期校验键位);\n * packages/dsh-i18n 语言包构建期 import 本模块注册 zh-CN;scripts/i18n-audit.mjs\n * 静态加载本模块做 zh/en 键对齐与占位符对齐门禁。\n */\nimport type { UpdaterLocaleKey } from './contract.ts'\n\nexport const zh: Record<UpdaterLocaleKey, string> = {\n nav: '软件更新',\n lead: '检测 GitHub Releases 上的新版本,增量更新只下载变动的交易插件包,无需重装应用。',\n currentVersion: '交易插件版本',\n desktopApp: '桌面应用版本',\n unsupported: '当前环境不支持自动增量更新(仅 DSH Trading 桌面版支持)。可以前往发布页手动下载完整安装包。',\n viewReleases: '在 GitHub 查看发布',\n checkNow: '检查更新',\n checking: '正在检查…',\n lastCheck: '上次检查',\n never: '尚未检查',\n upToDate: '已是最新版本。',\n available: '发现新版本 {version}',\n publishedAt: '发布于 {date}',\n notesTitle: '更新说明',\n applyNow: '立即更新',\n payloadMissing: '该版本未附带增量更新包,请前往发布页下载完整安装包。',\n 'phase.prepare': '正在准备…',\n 'phase.download': '正在下载增量包…',\n 'phase.verify': '正在校验增量包…',\n 'phase.install': '正在安装更新…',\n progress: '{percent}%',\n done: '已更新到 {version}',\n restartHint: '重启 DSH Trading 后生效。',\n restartNow: '重启应用',\n restartManual: '请手动重启 DSH Trading 以完成更新。',\n checkError: '检查失败:{message}',\n retry: '重试',\n close: '关闭',\n}\n\nexport const en: Record<UpdaterLocaleKey, string> = {\n nav: 'Software updates',\n lead: 'Detects new versions published on GitHub Releases and applies incremental updates — only the changed trading plugin packages are downloaded, no reinstall needed.',\n currentVersion: 'Trading plugins',\n desktopApp: 'Desktop app',\n unsupported: 'Incremental updates are only available inside the DSH Trading desktop app. You can download a full installer from the releases page.',\n viewReleases: 'View releases on GitHub',\n checkNow: 'Check for updates',\n checking: 'Checking…',\n lastCheck: 'Last checked',\n never: 'Never checked',\n upToDate: 'You are up to date.',\n available: 'New version {version} available',\n publishedAt: 'Published {date}',\n notesTitle: 'Release notes',\n applyNow: 'Update now',\n payloadMissing: 'This release does not carry the incremental update payload. Please download a full installer from the releases page.',\n 'phase.prepare': 'Preparing…',\n 'phase.download': 'Downloading update payload…',\n 'phase.verify': 'Verifying update payload…',\n 'phase.install': 'Installing update…',\n progress: '{percent}%',\n done: 'Updated to {version}',\n restartHint: 'Restart DSH Trading to activate.',\n restartNow: 'Restart app',\n restartManual: 'Please restart DSH Trading manually to finish the update.',\n checkError: 'Check failed: {message}',\n retry: 'Retry',\n close: 'Close',\n}\n","/**\n * Locale contract for the software-update dialog. The zh dictionary in\n * locales.ts is the key source of truth; this union + the LocaleNamespaceMap\n * merge give the framework-injected t seat its key types.\n *\n * Type-only imports pull the host slot augmentations (shell.overlay) into the\n * program so the dialog registers against a declared slot.\n */\nimport type {} from '@deepseek-ai/dsh-client-ui-slots'\nimport type {} from '@deepseek-ai/dsh-client-ui-layout/client'\n\nexport type UpdaterLocaleKey =\n | 'nav'\n | 'lead'\n | 'currentVersion'\n | 'desktopApp'\n | 'unsupported'\n | 'viewReleases'\n | 'checkNow'\n | 'checking'\n | 'lastCheck'\n | 'never'\n | 'upToDate'\n | 'available'\n | 'publishedAt'\n | 'notesTitle'\n | 'applyNow'\n | 'payloadMissing'\n | 'phase.prepare'\n | 'phase.download'\n | 'phase.verify'\n | 'phase.install'\n | 'progress'\n | 'done'\n | 'restartHint'\n | 'restartNow'\n | 'restartManual'\n | 'checkError'\n | 'retry'\n | 'close'\n\ndeclare module '@deepseek-ai/dsh-client-ui-slots' {\n interface LocaleNamespaceMap {\n /** Software-update dialog copy (check / notes / incremental apply). */\n 'dshtrading.updater': UpdaterLocaleKey\n }\n}\n\n/**\n * Window event contract with the trading shell sidebar (client-ui-trading\n * MarketDock update entry). Cross-plugin coupling is intentionally a DOM\n * custom event, not an import (client plugins never import each other's\n * modules).\n *\n * - UPDATE_AVAILABLE_EVENT: fired by the dialog whenever the host snapshot\n * changes. Detail: { available: boolean, version?: string }.\n * - UPDATER_OPEN_EVENT: fired by the sidebar update entry to ask this plugin\n * to open its dialog. No detail.\n */\nexport const UPDATE_AVAILABLE_EVENT = 'dshtrading-update-available'\nexport const UPDATER_OPEN_EVENT = 'dshtrading-updater-open'\n","/**\n * Updater bridge client: same-origin fetch wrappers over\n * /dshtrading/api/updater (the node half registers the route behind the\n * browser-auth fence; same-origin fetch carries the auth cookie by default).\n * Error semantics mirror the tasks bridge: non-2xx or { ok:false } envelopes\n * become rejections carrying the business code.\n */\nimport type { UpdaterSnapshot } from '../updater-service.ts'\n\nexport class UpdaterBridgeError extends Error {\n constructor(readonly status: number, message: string, readonly code?: string) {\n super(message)\n }\n}\n\nasync function updaterJson<T>(path: string, init?: RequestInit): Promise<T> {\n const response = await fetch(path, init)\n if (!response.ok) {\n const body = await response.json().catch(() => undefined) as { code?: string; message?: string } | undefined\n const detail = typeof body?.message === 'string' && body.message !== '' ? ': ' + body.message : ''\n throw new UpdaterBridgeError(response.status, 'updater ' + path + ' failed: ' + String(response.status) + detail, body?.code)\n }\n const wire = await response.json() as T\n if (wire !== null && typeof wire === 'object' && (wire as { ok?: unknown }).ok === false) {\n const business = wire as { code?: string; message?: string }\n throw new UpdaterBridgeError(200, (business.code ?? 'UPDATER_UNKNOWN') + ': ' + (business.message ?? 'updater bridge error'), business.code)\n }\n return wire\n}\n\n/** Current updater snapshot (environment + check + apply state). */\nexport async function fetchUpdaterState(): Promise<UpdaterSnapshot> {\n return updaterJson<UpdaterSnapshot>('/dshtrading/api/updater/state', { headers: { accept: 'application/json' } })\n}\n\n/** Run a GitHub release check; force=true bypasses the host-side TTL cache. */\nexport async function requestUpdaterCheck(force: boolean): Promise<UpdaterSnapshot> {\n return updaterJson<UpdaterSnapshot>(`/dshtrading/api/updater/check?force=${force ? '1' : '0'}`, { headers: { accept: 'application/json' } })\n}\n\n/** Start the incremental apply pipeline; returns the running snapshot. */\nexport async function requestUpdaterApply(): Promise<UpdaterSnapshot> {\n return updaterJson<UpdaterSnapshot>('/dshtrading/api/updater/apply', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: '{}',\n })\n}\n\n/** Electron shell bridge exposed by the desktop preload (absent in browsers). */\ninterface DesktopBridge {\n relaunch?: () => void\n}\n\n/** Resolve the desktop shell bridge, if this page runs inside DSH Trading. */\nexport function desktopBridge(): DesktopBridge | undefined {\n if (typeof window === 'undefined' || !('desktop' in window)) return undefined\n return (window as { desktop?: DesktopBridge }).desktop\n}\n","/**\n * Software-update dialog body (rendered inside UpdaterDialog). Pure view over\n * /dshtrading/api/updater: renders the current versions, the latest GitHub\n * release with its notes, and drives the incremental apply + restart flow.\n * Polls the host snapshot while mounted (faster while an apply is running);\n * no SSE dependency.\n */\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\nimport type { UpdaterSnapshot } from '../updater-service.ts'\nimport { desktopBridge, fetchUpdaterState, requestUpdaterApply, requestUpdaterCheck } from './api.ts'\nimport { UPDATE_AVAILABLE_EVENT } from './contract.ts'\nimport css from './updater-panel.module.css'\n\nexport type UpdaterPanelProps = PropsLocale<'dshtrading.updater'>\n\n/** Poll cadences: lazy when idle, tight while an apply pipeline is running. */\nconst POLL_IDLE_MS = 30_000\nconst POLL_RUNNING_MS = 1_200\n\n/** ISO date (yyyy-mm-dd) for the published line; empty when unknown. */\nfunction formatDay(iso: string | undefined): string {\n if (iso === undefined) return ''\n const parsed = new Date(iso)\n if (Number.isNaN(parsed.getTime())) return ''\n return parsed.toISOString().slice(0, 10)\n}\n\nexport function UpdaterPanel({ t }: UpdaterPanelProps) {\n const [state, setState] = useState<UpdaterSnapshot | undefined>(undefined)\n const [actionError, setActionError] = useState<string | undefined>(undefined)\n const [checkBusy, setCheckBusy] = useState(false)\n const applyBusyRef = useRef(false)\n\n const running = state?.apply.phase === 'running'\n\n const refresh = useCallback(async () => {\n try {\n setState(await fetchUpdaterState())\n } catch {\n // Bridge absent (headless profile / old deployment): keep the page quiet.\n }\n }, [])\n\n useEffect(() => { void refresh() }, [refresh])\n\n useEffect(() => {\n const interval = setInterval(() => { void refresh() }, running ? POLL_RUNNING_MS : POLL_IDLE_MS)\n return () => { clearInterval(interval) }\n }, [refresh, running])\n\n // Sidebar badge sync: mirror availability onto the window event the trading\n // shell sidebar listens to (see UPDATE_AVAILABLE_EVENT in contract.ts).\n useEffect(() => {\n if (state === undefined) return\n const available = state.check.available === true && state.apply.phase !== 'done'\n window.dispatchEvent(new CustomEvent(UPDATE_AVAILABLE_EVENT, {\n detail: { available, version: state.check.latest?.version },\n }))\n }, [state])\n\n const handleCheck = async (): Promise<void> => {\n setCheckBusy(true)\n setActionError(undefined)\n try {\n setState(await requestUpdaterCheck(true))\n } catch (error) {\n setActionError(error instanceof Error ? error.message : String(error))\n } finally {\n setCheckBusy(false)\n }\n }\n\n const handleApply = async (): Promise<void> => {\n if (applyBusyRef.current) return\n applyBusyRef.current = true\n setActionError(undefined)\n try {\n setState(await requestUpdaterApply())\n // Pipeline started: tighten polling immediately instead of waiting a tick.\n void refresh()\n } catch (error) {\n setActionError(error instanceof Error ? error.message : String(error))\n } finally {\n applyBusyRef.current = false\n }\n }\n\n const handleRestart = (): void => {\n desktopBridge()?.relaunch?.()\n }\n\n const environment = state?.environment\n const check = state?.check\n const apply = state?.apply\n const progress = state?.progress\n const latest = check?.latest\n const releasesUrl = latest?.url ?? 'https://github.com/zhu1090093659/dsh-trading/releases'\n const publishedDay = formatDay(latest?.publishedAt)\n const hasUpdate = check?.available === true && apply?.phase !== 'done'\n const applyable = hasUpdate && latest?.payloadAvailable === true\n\n return (\n <div className={css.root}>\n <p className={css.lead}>{t('lead')}</p>\n\n <div className={css.versions}>\n <div className={css.versionItem}>\n <span className={css.versionLabel}>{t('currentVersion')}</span>\n <span className={css.versionValue}>{environment?.familyVersion ?? '—'}</span>\n </div>\n {environment?.appVersion !== undefined && (\n <div className={css.versionItem}>\n <span className={css.versionLabel}>{t('desktopApp')}</span>\n <span className={css.versionValue}>{environment.appVersion}</span>\n </div>\n )}\n </div>\n\n {environment !== undefined && !environment.supported && (\n <p className={css.statusText}>{t('unsupported')}</p>\n )}\n\n {environment?.supported === true && (\n <>\n <div className={css.statusRow}>\n {check?.status === 'error' && (\n <span className={`${css.statusText} ${css.statusTextError}`}>\n {t('checkError', { message: check.error ?? '' })}\n </span>\n )}\n {check?.status === 'ok' && !hasUpdate && apply?.phase !== 'done' && (\n <span className={`${css.statusText} ${css.statusTextOk}`}>{t('upToDate')}</span>\n )}\n {check?.at !== undefined && (\n <span className={css.statusText}>\n {t('lastCheck')}\n :\n {' '}\n {check.at.slice(0, 19).replace('T', ' ')}\n </span>\n )}\n {check?.at === undefined && check?.status !== 'ok' && (\n <span className={css.statusText}>{t('never')}</span>\n )}\n <button\n type=\"button\"\n className={css.secondaryButton}\n disabled={checkBusy || running}\n onClick={() => { void handleCheck() }}\n >\n {checkBusy ? t('checking') : t('checkNow')}\n </button>\n {actionError !== undefined && (\n <button type=\"button\" className={css.secondaryButton} onClick={() => { void handleCheck() }}>\n {t('retry')}\n </button>\n )}\n </div>\n\n {running && (\n <div className={css.progressWrap}>\n <span className={css.progressLabel}>\n <span>\n {progress?.step === 'download'\n ? t('phase.download')\n : progress?.step === 'verify'\n ? t('phase.verify')\n : progress?.step === 'install'\n ? t('phase.install')\n : t('phase.prepare')}\n </span>\n {progress?.percent !== undefined && (\n <span>{t('progress', { percent: progress.percent })}</span>\n )}\n </span>\n <div\n className={css.progressTrack}\n role=\"progressbar\"\n aria-valuemin={0}\n aria-valuemax={100}\n aria-valuenow={progress?.percent ?? undefined}\n >\n <div\n className={`${css.progressFill} ${progress?.percent === undefined ? css.progressIndeterminate : ''}`}\n style={progress?.percent === undefined ? undefined : { width: `${progress.percent}%` }}\n />\n </div>\n </div>\n )}\n\n {hasUpdate && latest !== undefined && !running && (\n <div className={css.availableCard}>\n <p className={css.availableTitle}>{t('available', { version: latest.version })}</p>\n {publishedDay !== '' && (\n <p className={css.availableMeta}>{t('publishedAt', { date: publishedDay })}</p>\n )}\n {latest.notes.trim() !== '' && (\n <>\n <span className={css.notesTitle}>{t('notesTitle')}</span>\n <pre className={css.notes}>{latest.notes}</pre>\n </>\n )}\n <div className={css.actions}>\n {latest.payloadAvailable && (\n <button\n type=\"button\"\n className={css.primaryButton}\n onClick={() => { void handleApply() }}\n >\n {t('applyNow')}\n </button>\n )}\n <a className={css.link} href={releasesUrl} target=\"_blank\" rel=\"noreferrer\">\n {t('viewReleases')}\n </a>\n </div>\n {!latest.payloadAvailable && (\n <p className={css.doneMeta}>{t('payloadMissing')}</p>\n )}\n </div>\n )}\n\n {apply?.phase === 'done' && apply.targetVersion !== undefined && (\n <div className={css.doneCard}>\n <p className={css.doneTitle}>{t('done', { version: apply.targetVersion })}</p>\n <p className={css.doneMeta}>{t('restartHint')}</p>\n <div className={css.actions}>\n {desktopBridge()?.relaunch !== undefined && (\n <button type=\"button\" className={css.primaryButton} onClick={handleRestart}>\n {t('restartNow')}\n </button>\n )}\n {desktopBridge()?.relaunch === undefined && (\n <span className={css.doneMeta}>{t('restartManual')}</span>\n )}\n <a className={css.link} href={releasesUrl} target=\"_blank\" rel=\"noreferrer\">\n {t('viewReleases')}\n </a>\n </div>\n </div>\n )}\n\n {apply?.phase === 'error' && apply.error !== undefined && (\n <p className={css.errorText}>{apply.error}</p>\n )}\n </>\n )}\n\n {environment === undefined || !environment.supported ? (\n <a className={css.link} href={releasesUrl} target=\"_blank\" rel=\"noreferrer\">\n {t('viewReleases')}\n </a>\n ) : null}\n </div>\n )\n}\n","/**\n * Software-update dialog (the 'shell.overlay' entry registered by this plugin).\n * The sidebar's update entry dispatches UPDATER_OPEN_EVENT; this component owns\n * the modal chrome (mask click + Escape close) around UpdaterPanel. Frame-wide\n * floating layer: fixed overlay opts back into pointer events.\n */\nimport { useCallback, useEffect, useState } from 'react'\nimport type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'\nimport { UPDATER_OPEN_EVENT } from './contract.ts'\nimport { UpdaterPanel } from './UpdaterPanel.tsx'\nimport css from './updater-dialog.module.css'\n\nexport type UpdaterDialogProps = PropsLocale<'dshtrading.updater'>\n\nexport function UpdaterDialog({ t }: UpdaterDialogProps) {\n const [open, setOpen] = useState(false)\n\n useEffect(() => {\n const onOpen = (): void => { setOpen(true) }\n window.addEventListener(UPDATER_OPEN_EVENT, onOpen)\n return () => { window.removeEventListener(UPDATER_OPEN_EVENT, onOpen) }\n }, [])\n\n const close = useCallback((): void => { setOpen(false) }, [])\n\n useEffect(() => {\n if (!open) return\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.key === 'Escape') close()\n }\n document.addEventListener('keydown', onKeyDown)\n return () => { document.removeEventListener('keydown', onKeyDown) }\n }, [open, close])\n\n if (!open) return null\n\n return (\n <div className={css.overlay} role=\"presentation\">\n <div className={css.mask} aria-hidden=\"true\" onClick={close} />\n <div className={css.panel} role=\"dialog\" aria-modal=\"true\" aria-label={t('nav')}>\n <div className={css.header}>\n <span className={css.title}>{t('nav')}</span>\n <button type=\"button\" className={css.close} aria-label={t('close')} title={t('close')} onClick={close}>\n <svg viewBox=\"0 0 16 16\" width={14} height={14} aria-hidden=\"true\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.4\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n <path d=\"M4.25 4.25l7.5 7.5M11.75 4.25l-7.5 7.5\" />\n </svg>\n </button>\n </div>\n <div className={css.body}>\n <UpdaterPanel t={t} />\n </div>\n </div>\n </div>\n )\n}\n","/**\n * dsh-trading auto-update, browser half — the software-update dialog on the\n * host's frame-wide shell.overlay layer. The entry point is the update button\n * beside Settings in the trading sidebar's bottom bar (client-ui-trading\n * dispatches UPDATER_OPEN_EVENT); this plugin owns the modal chrome and body.\n *\n * The dialog talks to the node half over /dshtrading/api/updater (same-origin\n * fetch inside the browser-auth fence). In environments without incremental\n * support (dev checkouts, headless profiles) it degrades to an information\n * surface linking the GitHub releases page.\n */\nimport type { Context as ClientContext } from '@deepseek-ai/cordis'\nimport type {} from '@deepseek-ai/dsh-client-locale/client'\nimport type {} from './contract.ts'\nimport { en, zh } from './locales.ts'\nimport { UpdaterDialog } from './UpdaterDialog.tsx'\n\nimport { UPDATE_AVAILABLE_EVENT, UPDATER_OPEN_EVENT } from './contract.ts'\n/** This dialog's locale namespace. */\nconst NS = 'dshtrading.updater'\n\n/** Required services (cordis fiber inject). */\nexport const inject = ['slots', 'locale']\n\n/**\n * Register the update dialog on shell.overlay (no settings.section: the entry\n * moved beside Settings in the sidebar bottom bar). The sidebar asks this\n * plugin to open through the UPDATER_OPEN_EVENT window event — cross-plugin\n * coupling is a DOM event, never an import.\n */\nexport function apply(ctx: ClientContext): void {\n ctx.locale.bind(NS)\n ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-trading-updater: dictionaries')\n\n ctx.slots.inject('shell.overlay', () => ctx.slots.register({\n name: 'shell.overlay',\n id: 'dshtrading-updater-dialog',\n order: 90,\n locale: NS,\n }, UpdaterDialog))\n}\n\nexport { UPDATE_AVAILABLE_EVENT, UPDATER_OPEN_EVENT } from './contract.ts'\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dshtrading/client-ui-updater",
|
|
3
|
-
"description": "dsh-trading auto-update plugin: GitHub Releases version check with release notes, incremental update of the @dshtrading/* plugin family inside a desktop-seeded profile (vendor payload zip, per-package swap), and the '
|
|
4
|
-
"version": "0.
|
|
3
|
+
"description": "dsh-trading auto-update plugin: GitHub Releases version check with release notes, incremental update of the @dshtrading/* plugin family inside a desktop-seeded profile (vendor payload zip, per-package swap), and the software-update dialog opened from the trading sidebar's update entry. Browser half registers the shell.overlay dialog; node half registers the /dshtrading/api/updater routes and the update engine.",
|
|
4
|
+
"version": "0.3.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "./lib/index.d.ts",
|
|
@@ -26,12 +26,13 @@
|
|
|
26
26
|
"license": "PolyForm-Noncommercial-1.0.0",
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"fflate": "^0.8.2",
|
|
29
|
-
"@dshtrading/dsh-home": "^0.
|
|
29
|
+
"@dshtrading/dsh-home": "^0.3.0"
|
|
30
30
|
},
|
|
31
31
|
"peerDependencies": {
|
|
32
32
|
"@deepseek-ai/cordis": ">=4.0.0",
|
|
33
|
-
"@deepseek-ai/dsh-client-locale": ">=0.1.
|
|
34
|
-
"@deepseek-ai/dsh-client-ui-
|
|
33
|
+
"@deepseek-ai/dsh-client-locale": ">=0.1.5-rc.1",
|
|
34
|
+
"@deepseek-ai/dsh-client-ui-layout": ">=0.1.5-rc.1",
|
|
35
|
+
"@deepseek-ai/dsh-client-ui-slots": ">=0.1.5-rc.1",
|
|
35
36
|
"react": "^18.2.0",
|
|
36
37
|
"@types/react": "~18.3.1"
|
|
37
38
|
},
|
|
@@ -46,8 +47,9 @@
|
|
|
46
47
|
},
|
|
47
48
|
"devDependencies": {
|
|
48
49
|
"@deepseek-ai/cordis": "^4.0.2",
|
|
49
|
-
"@deepseek-ai/dsh-client-locale": "0.1.
|
|
50
|
-
"@deepseek-ai/dsh-client-ui-
|
|
50
|
+
"@deepseek-ai/dsh-client-locale": "0.1.5-rc.1",
|
|
51
|
+
"@deepseek-ai/dsh-client-ui-layout": "0.1.5-rc.1",
|
|
52
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.5-rc.1",
|
|
51
53
|
"@types/node": "^24.0.0",
|
|
52
54
|
"@types/react": "~18.3.1",
|
|
53
55
|
"lightningcss": "^1.0.0",
|