dsh-update-plugin 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -0
- package/LICENSE +21 -0
- package/README.md +151 -0
- package/README.zh-CN.md +134 -0
- package/assets/screenshots/general-en.webp +0 -0
- package/assets/screenshots/general-zh.webp +0 -0
- package/cordis.patch.yml +10 -0
- package/lib/client.js +1063 -0
- package/lib/index.js +366 -0
- package/lib/update-core.js +669 -0
- package/package.json +65 -0
package/lib/client.js
ADDED
|
@@ -0,0 +1,1063 @@
|
|
|
1
|
+
// dsh-update-plugin browser half.
|
|
2
|
+
//
|
|
3
|
+
// Built in the DSH lazy-CJS bundle format: executing this file only registers
|
|
4
|
+
// a factory; the module body (styles, locale, slot registration) runs when the
|
|
5
|
+
// browser materializes the module.
|
|
6
|
+
|
|
7
|
+
window.__ModuleLoader__.load({
|
|
8
|
+
id: "dsh-update-plugin",
|
|
9
|
+
factory: (require) => {
|
|
10
|
+
var module = { exports: {} };
|
|
11
|
+
Object.defineProperty(module.exports, Symbol.toStringTag, { value: "Module" });
|
|
12
|
+
|
|
13
|
+
var React = require("react");
|
|
14
|
+
var h = React.createElement;
|
|
15
|
+
|
|
16
|
+
var NS = "dsh-update-plugin";
|
|
17
|
+
var HEADER = "x-dsh-update-plugin";
|
|
18
|
+
var STATUS_PATH = "/api/dsh-update-plugin/status";
|
|
19
|
+
var UPDATE_PATH = "/api/dsh-update-plugin/update";
|
|
20
|
+
var CONFIG_PATH = "/api/dsh-update-plugin/config";
|
|
21
|
+
var BACKUPS_PATH = "/api/dsh-update-plugin/backups";
|
|
22
|
+
var ROLLBACK_PATH = "/api/dsh-update-plugin/rollback";
|
|
23
|
+
var STYLE_ID = "dsh-update-plugin-style";
|
|
24
|
+
var SIDEBAR_ID = "dsh-update-plugin";
|
|
25
|
+
|
|
26
|
+
var CSS = [
|
|
27
|
+
".dsu-row{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:4px 0}",
|
|
28
|
+
".dsu-main{display:flex;flex-direction:column;gap:2px;min-width:0}",
|
|
29
|
+
".dsu-title{color:var(--dsw-alias-label-primary,#fff);font-size:14px;line-height:20px;font-weight:500}",
|
|
30
|
+
".dsu-desc{color:var(--dsw-alias-label-secondary,#c2c4ca);font-size:12px;line-height:18px}",
|
|
31
|
+
".dsu-meta{color:var(--dsw-alias-label-tertiary,#9da1aa);font-size:12px;line-height:18px;font-family:ui-monospace,SFMono-Regular,Consolas,monospace}",
|
|
32
|
+
".dsu-control{display:flex;align-items:center;gap:8px;flex:0 0 auto}",
|
|
33
|
+
".dsu-btn{display:inline-flex;align-items:center;justify-content:center;min-height:28px;padding:0 10px;border:1px solid var(--dsw-alias-border-l2,#4b4d52);border-radius:7px;background:transparent;color:var(--dsw-alias-label-secondary,#b8bbc2);font:inherit;font-size:12px;line-height:18px;white-space:nowrap;cursor:pointer}",
|
|
34
|
+
".dsu-btn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#3a3b3f);color:var(--dsw-alias-label-primary,#fff)}",
|
|
35
|
+
".dsu-btn:disabled{cursor:not-allowed;opacity:.55}",
|
|
36
|
+
".dsu-btn-primary{border-color:var(--dsw-alias-state-business-primary,#4f8cff);background:var(--dsw-alias-state-business-primary,#4f8cff);color:#fff}",
|
|
37
|
+
".dsu-btn-primary:hover:not(:disabled){background:var(--dsw-alias-state-business-primary-hover,#3d7bea);color:#fff}",
|
|
38
|
+
".dsu-error{color:var(--dsw-alias-state-error-primary,#ff6464);font-size:12px;line-height:18px;word-break:break-word}",
|
|
39
|
+
".dsu-ok{color:var(--dsw-alias-state-success-primary,#36d67a);font-size:12px;line-height:18px}",
|
|
40
|
+
".dsu-manual{display:flex;flex-direction:column;gap:4px;margin-top:6px}",
|
|
41
|
+
".dsu-manual code,.dsu-log{display:block;overflow:auto;white-space:pre-wrap;border-radius:6px;padding:6px 8px;background:var(--dsw-alias-bg-layer-3,#252527);color:var(--dsw-alias-label-secondary,#c2c4ca);font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:11px;line-height:16px}",
|
|
42
|
+
".dsu-page{display:flex;flex-direction:column;gap:16px;padding:4px 2px 24px;max-width:820px}",
|
|
43
|
+
".dsu-card{display:flex;flex-direction:column;gap:10px;border:1px solid var(--dsw-alias-border-l2,#3a3b3f);border-radius:10px;padding:14px}",
|
|
44
|
+
".dsu-card-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}",
|
|
45
|
+
".dsu-card-title{color:var(--dsw-alias-label-primary,#fff);font-size:14px;line-height:20px;font-weight:600}",
|
|
46
|
+
".dsu-field{display:flex;align-items:center;justify-content:space-between;gap:12px}",
|
|
47
|
+
".dsu-field-label{display:flex;flex-direction:column;gap:2px;min-width:0}",
|
|
48
|
+
".dsu-select,.dsu-input{min-height:28px;border:1px solid var(--dsw-alias-border-l2,#4b4d52);border-radius:7px;background:var(--dsw-alias-bg-layer-3,#252527);color:var(--dsw-alias-label-primary,#fff);font:inherit;font-size:12px;padding:0 8px}",
|
|
49
|
+
".dsu-input{width:72px}",
|
|
50
|
+
".dsu-list{display:flex;flex-direction:column;gap:6px;margin:0;padding:0;list-style:none}",
|
|
51
|
+
".dsu-list-item{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary,#c2c4ca)}",
|
|
52
|
+
".dsu-list-item code{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;color:var(--dsw-alias-label-primary,#fff)}",
|
|
53
|
+
".dsu-backup{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:8px 0;border-bottom:1px solid var(--dsw-alias-border-l2,#3a3b3f)}",
|
|
54
|
+
".dsu-backup:last-child{border-bottom:none}",
|
|
55
|
+
".dsu-badge{display:inline-block;width:7px;height:7px;margin-left:6px;border-radius:50%;background:var(--dsw-alias-state-error-primary,#ff6464);vertical-align:middle}",
|
|
56
|
+
".dsu-empty{color:var(--dsw-alias-label-tertiary,#9da1aa);font-size:12px;line-height:18px}",
|
|
57
|
+
".dsu-link{border:none;background:transparent;padding:0;color:var(--dsw-alias-state-business-primary,#4f8cff);font:inherit;font-size:12px;cursor:pointer}",
|
|
58
|
+
].join("");
|
|
59
|
+
|
|
60
|
+
var ZH = {
|
|
61
|
+
title: "检查更新",
|
|
62
|
+
sidebarDescription: "检查并更新 DSH CLI 和所有 profile 插件",
|
|
63
|
+
check: "检查更新",
|
|
64
|
+
recheck: "重新检查",
|
|
65
|
+
update: "立即更新",
|
|
66
|
+
checking: "正在检查…",
|
|
67
|
+
latest: "已是最新版本",
|
|
68
|
+
found: "发现新版本 {version}",
|
|
69
|
+
updating: "正在更新…",
|
|
70
|
+
rollbacking: "正在回滚…",
|
|
71
|
+
phase: "阶段:{phase}",
|
|
72
|
+
failed: "检查或更新失败",
|
|
73
|
+
partial: "部分更新失败",
|
|
74
|
+
restart: "更新完成,请重启 DSH",
|
|
75
|
+
current: "当前 {version}",
|
|
76
|
+
target: "最新 {version}",
|
|
77
|
+
profiles: "{count} 个 profile",
|
|
78
|
+
manual: "自动更新失败时,可在终端执行:",
|
|
79
|
+
openSidebar: "打开侧边卡片",
|
|
80
|
+
statusTitle: "状态",
|
|
81
|
+
settingsTitle: "更新设置",
|
|
82
|
+
profilesTitle: "Profiles",
|
|
83
|
+
backupsTitle: "备份",
|
|
84
|
+
channel: "更新频道",
|
|
85
|
+
channelHint: "auto 会从所有 dist-tag 中选最高版本",
|
|
86
|
+
channelAuto: "自动(最高版本)",
|
|
87
|
+
channelStable: "stable(latest)",
|
|
88
|
+
channelNext: "next(预发布)",
|
|
89
|
+
channelAlpha: "alpha(内测)",
|
|
90
|
+
minAge: "最小释出时间",
|
|
91
|
+
minAgeUnit: "分钟",
|
|
92
|
+
minAgeHint: "0 = 总是最新;1440 = 24 小时",
|
|
93
|
+
save: "保存",
|
|
94
|
+
saved: "已保存",
|
|
95
|
+
saveFailed: "保存失败",
|
|
96
|
+
profilesCount: "{count} 个依赖",
|
|
97
|
+
noBackups: "暂无备份",
|
|
98
|
+
backupMeta: "{date} · CLI {version} · {profiles}",
|
|
99
|
+
rollback: "回滚",
|
|
100
|
+
rollbackConfirm: "确定回滚到这个备份吗?DSH 会自动恢复 package.json / lockfile 并重装依赖。",
|
|
101
|
+
rollbackStarted: "正在回滚…",
|
|
102
|
+
rollbackDone: "回滚完成,请重启 DSH",
|
|
103
|
+
rollbackFailed: "回滚失败",
|
|
104
|
+
refresh: "刷新",
|
|
105
|
+
sidebarPanelTitle: "DSH 更新",
|
|
106
|
+
viewSettingsHint: "更多设置请到 设置 → 通用设置 / 更新。",
|
|
107
|
+
forbidden: "仅本机 DSH Web 可以执行此操作。",
|
|
108
|
+
noJob: "空闲",
|
|
109
|
+
badgeUpdate: "有可用更新",
|
|
110
|
+
hostOutdated: "宿主端接口未加载(HTTP 404),请重启 DSH 后再试。",
|
|
111
|
+
testStart: "测试更新提醒",
|
|
112
|
+
testStop: "停止测试",
|
|
113
|
+
testReminder: "测试提醒:发现可用更新(仅测试,不会真的更新)",
|
|
114
|
+
testReminderMeta: "仅用于验证角标和提醒效果",
|
|
115
|
+
notificationTitle: "DSH 有可用更新",
|
|
116
|
+
notificationBody: "测试提醒:仅用于验证浏览器通知和角标(不会真的更新)",
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
var EN = {
|
|
120
|
+
title: "Check for Updates...",
|
|
121
|
+
sidebarDescription: "Check and update the DSH CLI and all profile plugins",
|
|
122
|
+
check: "Check for updates",
|
|
123
|
+
recheck: "Check again",
|
|
124
|
+
update: "Update now",
|
|
125
|
+
checking: "Checking...",
|
|
126
|
+
latest: "You are up to date",
|
|
127
|
+
found: "New version available: {version}",
|
|
128
|
+
updating: "Updating...",
|
|
129
|
+
rollbacking: "Rolling back...",
|
|
130
|
+
phase: "Phase: {phase}",
|
|
131
|
+
failed: "Update check or update failed",
|
|
132
|
+
partial: "Some updates failed",
|
|
133
|
+
restart: "Update complete. Restart DSH.",
|
|
134
|
+
current: "Current {version}",
|
|
135
|
+
target: "Latest {version}",
|
|
136
|
+
profiles: "{count} profiles",
|
|
137
|
+
manual: "If automatic update fails, run this in a terminal:",
|
|
138
|
+
openSidebar: "Open side card",
|
|
139
|
+
statusTitle: "Status",
|
|
140
|
+
settingsTitle: "Update settings",
|
|
141
|
+
profilesTitle: "Profiles",
|
|
142
|
+
backupsTitle: "Backups",
|
|
143
|
+
channel: "Update channel",
|
|
144
|
+
channelHint: "auto picks the highest version across all dist-tags",
|
|
145
|
+
channelAuto: "Auto (highest version)",
|
|
146
|
+
channelStable: "stable (latest)",
|
|
147
|
+
channelNext: "next (prerelease)",
|
|
148
|
+
channelAlpha: "alpha (canary)",
|
|
149
|
+
minAge: "Minimum release age",
|
|
150
|
+
minAgeUnit: "minutes",
|
|
151
|
+
minAgeHint: "0 = always newest; 1440 = 24 hours",
|
|
152
|
+
save: "Save",
|
|
153
|
+
saved: "Saved",
|
|
154
|
+
saveFailed: "Save failed",
|
|
155
|
+
profilesCount: "{count} dependencies",
|
|
156
|
+
noBackups: "No backups yet",
|
|
157
|
+
backupMeta: "{date} · CLI {version} · {profiles}",
|
|
158
|
+
rollback: "Roll back",
|
|
159
|
+
rollbackConfirm: "Roll back to this backup? DSH will restore package.json / lockfile and reinstall dependencies.",
|
|
160
|
+
rollbackStarted: "Rolling back...",
|
|
161
|
+
rollbackDone: "Rollback complete. Restart DSH.",
|
|
162
|
+
rollbackFailed: "Rollback failed",
|
|
163
|
+
refresh: "Refresh",
|
|
164
|
+
sidebarPanelTitle: "DSH updates",
|
|
165
|
+
viewSettingsHint: "More settings live in Settings → General / Updates.",
|
|
166
|
+
forbidden: "This action is only available from a local DSH Web page.",
|
|
167
|
+
noJob: "Idle",
|
|
168
|
+
badgeUpdate: "Update available",
|
|
169
|
+
hostOutdated: "The host endpoints are not loaded yet (HTTP 404). Restart DSH and try again.",
|
|
170
|
+
testStart: "Send test reminder",
|
|
171
|
+
testStop: "Stop test",
|
|
172
|
+
testReminder: "Test reminder: update available (test only, nothing is updated)",
|
|
173
|
+
testReminderMeta: "Only used to verify the badge and reminder UI",
|
|
174
|
+
notificationTitle: "DSH update available",
|
|
175
|
+
notificationBody: "Test reminder: only verifying the browser notification and badge (nothing is updated)",
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
function injectStyle() {
|
|
179
|
+
if (typeof document === "undefined" || document.getElementById(STYLE_ID)) return;
|
|
180
|
+
var style = document.createElement("style");
|
|
181
|
+
style.id = STYLE_ID;
|
|
182
|
+
style.textContent = CSS;
|
|
183
|
+
document.head.appendChild(style);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function removeStyle() {
|
|
187
|
+
if (typeof document === "undefined") return;
|
|
188
|
+
var style = document.getElementById(STYLE_ID);
|
|
189
|
+
if (style) style.remove();
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function request(url, options) {
|
|
193
|
+
var headers = { [HEADER]: "1" };
|
|
194
|
+
if (options && options.headers) Object.assign(headers, options.headers);
|
|
195
|
+
return fetch(url, { credentials: "same-origin", ...(options || {}), headers: headers });
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function parseJson(response) {
|
|
199
|
+
return response.json().catch(function () {
|
|
200
|
+
return { error: "HTTP " + response.status };
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function getStatus(refresh) {
|
|
205
|
+
return request(STATUS_PATH + (refresh ? "?refresh=1" : "")).then(parseJson);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function startUpdate() {
|
|
209
|
+
return request(UPDATE_PATH, { method: "POST" }).then(parseJson);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function getConfig() {
|
|
213
|
+
return request(CONFIG_PATH).then(parseJson);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function saveConfig(config) {
|
|
217
|
+
return request(CONFIG_PATH, {
|
|
218
|
+
method: "POST",
|
|
219
|
+
headers: { "content-type": "application/json" },
|
|
220
|
+
body: JSON.stringify(config),
|
|
221
|
+
}).then(parseJson);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function getBackups() {
|
|
225
|
+
return request(BACKUPS_PATH).then(parseJson);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function startRollback(id) {
|
|
229
|
+
return request(ROLLBACK_PATH, {
|
|
230
|
+
method: "POST",
|
|
231
|
+
headers: { "content-type": "application/json" },
|
|
232
|
+
body: JSON.stringify({ id: id }),
|
|
233
|
+
}).then(parseJson);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function sendBrowserNotification(t) {
|
|
237
|
+
try {
|
|
238
|
+
if (typeof Notification === "undefined") return;
|
|
239
|
+
var show = function () {
|
|
240
|
+
try {
|
|
241
|
+
new Notification(t("notificationTitle"), { body: t("notificationBody") });
|
|
242
|
+
} catch (error) {}
|
|
243
|
+
};
|
|
244
|
+
if (Notification.permission === "granted") {
|
|
245
|
+
show();
|
|
246
|
+
} else if (Notification.permission !== "denied") {
|
|
247
|
+
Notification.requestPermission()
|
|
248
|
+
.then(function (permission) {
|
|
249
|
+
if (permission === "granted") show();
|
|
250
|
+
})
|
|
251
|
+
.catch(function () {});
|
|
252
|
+
}
|
|
253
|
+
} catch (error) {}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function manualCommands(profileName) {
|
|
257
|
+
return [
|
|
258
|
+
"dsh plugin --profile " + (profileName || "web") + " update --latest",
|
|
259
|
+
"dsh plugin --profile " + (profileName || "web") + " add dsh-update-plugin@latest",
|
|
260
|
+
];
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function statusText(t, data, error) {
|
|
264
|
+
if (error) return t("failed");
|
|
265
|
+
if (!data) return t("checking");
|
|
266
|
+
if (data.testReminder) return t("testReminder");
|
|
267
|
+
if (data.running) {
|
|
268
|
+
var phase = data.phase && data.phase !== "idle" ? " · " + t("phase", { phase: data.phase }) : "";
|
|
269
|
+
return (data.kind === "rollback" ? t("rollbacking") : t("updating")) + phase;
|
|
270
|
+
}
|
|
271
|
+
if (data.kind === "rollback" && data.restartRequired) return t("rollbackDone");
|
|
272
|
+
if (data.result && data.result.ok === false) return data.kind === "rollback" ? t("rollbackFailed") : t("partial");
|
|
273
|
+
if (data.restartRequired) return t("restart");
|
|
274
|
+
if (data.updateAvailable) return t("found", { version: data.targetVersion || "?" });
|
|
275
|
+
if (data.currentVersion) return t("latest");
|
|
276
|
+
return t("checking");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function friendlyError(t, message) {
|
|
280
|
+
var text = String(message || "");
|
|
281
|
+
if (text.indexOf("HTTP 404") !== -1) return t("hostOutdated");
|
|
282
|
+
return text;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function metaText(t, data) {
|
|
286
|
+
if (!data) return "";
|
|
287
|
+
if (data.testReminder) return t("testReminderMeta");
|
|
288
|
+
var parts = [];
|
|
289
|
+
if (data.currentVersion) parts.push(t("current", { version: data.currentVersion }));
|
|
290
|
+
if (data.targetVersion) parts.push(t("target", { version: data.targetVersion }));
|
|
291
|
+
if (data.profiles && data.profiles.length) parts.push(t("profiles", { count: data.profiles.length }));
|
|
292
|
+
return parts.join(" · ");
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
var testReminder = { active: false, until: 0 };
|
|
296
|
+
var testReminderTimer = null;
|
|
297
|
+
var testReminderListeners = new Set();
|
|
298
|
+
|
|
299
|
+
function notifyTestReminder() {
|
|
300
|
+
testReminderListeners.forEach(function (listener) {
|
|
301
|
+
listener();
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function setTestReminder(active, durationMs) {
|
|
306
|
+
var duration = durationMs || 60000;
|
|
307
|
+
testReminder.active = Boolean(active);
|
|
308
|
+
testReminder.until = testReminder.active ? Date.now() + duration : 0;
|
|
309
|
+
if (testReminderTimer) {
|
|
310
|
+
clearTimeout(testReminderTimer);
|
|
311
|
+
testReminderTimer = null;
|
|
312
|
+
}
|
|
313
|
+
if (testReminder.active) {
|
|
314
|
+
testReminderTimer = setTimeout(function () {
|
|
315
|
+
testReminderTimer = null;
|
|
316
|
+
setTestReminder(false);
|
|
317
|
+
}, duration);
|
|
318
|
+
}
|
|
319
|
+
notifyTestReminder();
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function useTestReminder() {
|
|
323
|
+
var pair = React.useState(testReminder.active);
|
|
324
|
+
var active = pair[0];
|
|
325
|
+
var setActive = pair[1];
|
|
326
|
+
React.useEffect(
|
|
327
|
+
function () {
|
|
328
|
+
var listener = function () {
|
|
329
|
+
setActive(testReminder.active);
|
|
330
|
+
};
|
|
331
|
+
testReminderListeners.add(listener);
|
|
332
|
+
return function () {
|
|
333
|
+
testReminderListeners.delete(listener);
|
|
334
|
+
};
|
|
335
|
+
},
|
|
336
|
+
[setActive],
|
|
337
|
+
);
|
|
338
|
+
return active;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function applyTestReminder(data, test) {
|
|
342
|
+
if (!test) return data;
|
|
343
|
+
return Object.assign({}, data || {}, { updateAvailable: true, testReminder: true });
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function useUpdater(t) {
|
|
347
|
+
var pair = React.useState({ loading: true, data: null, error: null });
|
|
348
|
+
var state = pair[0];
|
|
349
|
+
var setState = pair[1];
|
|
350
|
+
|
|
351
|
+
var load = React.useCallback(function (refresh) {
|
|
352
|
+
setState(function (previous) {
|
|
353
|
+
return { loading: true, data: previous.data, error: null };
|
|
354
|
+
});
|
|
355
|
+
return getStatus(Boolean(refresh))
|
|
356
|
+
.then(function (data) {
|
|
357
|
+
var message = data && (data.error || data.targetError) ? friendlyError(t, data.error || data.targetError) : null;
|
|
358
|
+
setState({ loading: false, data: data, error: message });
|
|
359
|
+
return data;
|
|
360
|
+
})
|
|
361
|
+
.catch(function (error) {
|
|
362
|
+
setState({ loading: false, data: null, error: friendlyError(t, (error && error.message) || error) });
|
|
363
|
+
return null;
|
|
364
|
+
});
|
|
365
|
+
}, [t]);
|
|
366
|
+
|
|
367
|
+
React.useEffect(
|
|
368
|
+
function () {
|
|
369
|
+
load(false);
|
|
370
|
+
},
|
|
371
|
+
[load],
|
|
372
|
+
);
|
|
373
|
+
|
|
374
|
+
var running = Boolean(state.data && state.data.running);
|
|
375
|
+
React.useEffect(
|
|
376
|
+
function () {
|
|
377
|
+
if (!running) return undefined;
|
|
378
|
+
var timer = setInterval(function () {
|
|
379
|
+
load(false);
|
|
380
|
+
}, 1500);
|
|
381
|
+
return function () {
|
|
382
|
+
clearInterval(timer);
|
|
383
|
+
};
|
|
384
|
+
},
|
|
385
|
+
[running, load],
|
|
386
|
+
);
|
|
387
|
+
|
|
388
|
+
var update = React.useCallback(function () {
|
|
389
|
+
setState(function (previous) {
|
|
390
|
+
return { loading: true, data: previous.data, error: null };
|
|
391
|
+
});
|
|
392
|
+
return startUpdate()
|
|
393
|
+
.then(function (result) {
|
|
394
|
+
if (result && result.error) {
|
|
395
|
+
setState(function (previous) {
|
|
396
|
+
return { loading: false, data: previous.data, error: friendlyError(t, result.error) };
|
|
397
|
+
});
|
|
398
|
+
return result;
|
|
399
|
+
}
|
|
400
|
+
return load(false);
|
|
401
|
+
})
|
|
402
|
+
.catch(function (error) {
|
|
403
|
+
setState(function (previous) {
|
|
404
|
+
return { loading: false, data: previous.data, error: String((error && error.message) || error) };
|
|
405
|
+
});
|
|
406
|
+
return null;
|
|
407
|
+
});
|
|
408
|
+
}, [load, t]);
|
|
409
|
+
|
|
410
|
+
return { state: state, load: load, update: update, running: running };
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function useConfig(t) {
|
|
414
|
+
var pair = React.useState({ loading: true, config: null, error: null, saved: false });
|
|
415
|
+
var state = pair[0];
|
|
416
|
+
var setState = pair[1];
|
|
417
|
+
|
|
418
|
+
var load = React.useCallback(function () {
|
|
419
|
+
return getConfig()
|
|
420
|
+
.then(function (config) {
|
|
421
|
+
setState({ loading: false, config: config, error: config && config.error ? friendlyError(t, config.error) : null, saved: false });
|
|
422
|
+
})
|
|
423
|
+
.catch(function (error) {
|
|
424
|
+
setState({ loading: false, config: null, error: friendlyError(t, (error && error.message) || error), saved: false });
|
|
425
|
+
});
|
|
426
|
+
}, [t]);
|
|
427
|
+
|
|
428
|
+
React.useEffect(
|
|
429
|
+
function () {
|
|
430
|
+
load();
|
|
431
|
+
},
|
|
432
|
+
[load],
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
var save = React.useCallback(function (config) {
|
|
436
|
+
setState(function (previous) {
|
|
437
|
+
return { loading: true, config: previous.config, error: null, saved: false };
|
|
438
|
+
});
|
|
439
|
+
return saveConfig(config)
|
|
440
|
+
.then(function (next) {
|
|
441
|
+
if (next && next.error) {
|
|
442
|
+
setState({ loading: false, config: config, error: friendlyError(t, next.error), saved: false });
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
setState({ loading: false, config: next, error: null, saved: true });
|
|
446
|
+
return next;
|
|
447
|
+
})
|
|
448
|
+
.catch(function (error) {
|
|
449
|
+
setState({ loading: false, config: config, error: friendlyError(t, (error && error.message) || error), saved: false });
|
|
450
|
+
return null;
|
|
451
|
+
});
|
|
452
|
+
}, [t]);
|
|
453
|
+
|
|
454
|
+
return { state: state, load: load, save: save };
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function useBackups(t) {
|
|
458
|
+
var pair = React.useState({ loading: true, backups: [], error: null });
|
|
459
|
+
var state = pair[0];
|
|
460
|
+
var setState = pair[1];
|
|
461
|
+
|
|
462
|
+
var load = React.useCallback(function () {
|
|
463
|
+
return getBackups()
|
|
464
|
+
.then(function (result) {
|
|
465
|
+
if (result && result.error) {
|
|
466
|
+
setState({ loading: false, backups: [], error: friendlyError(t, result.error) });
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
setState({ loading: false, backups: (result && result.backups) || [], error: null });
|
|
470
|
+
})
|
|
471
|
+
.catch(function (error) {
|
|
472
|
+
setState({ loading: false, backups: [], error: friendlyError(t, (error && error.message) || error) });
|
|
473
|
+
});
|
|
474
|
+
}, [t]);
|
|
475
|
+
|
|
476
|
+
React.useEffect(
|
|
477
|
+
function () {
|
|
478
|
+
load();
|
|
479
|
+
},
|
|
480
|
+
[load],
|
|
481
|
+
);
|
|
482
|
+
|
|
483
|
+
return { state: state, load: load };
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function UpdateRow(props) {
|
|
487
|
+
var t = props.t;
|
|
488
|
+
var updater = useUpdater(t);
|
|
489
|
+
var test = useTestReminder();
|
|
490
|
+
var data = applyTestReminder(updater.state.data, test) || {};
|
|
491
|
+
var description = statusText(t, data, updater.state.error);
|
|
492
|
+
var meta = metaText(t, data);
|
|
493
|
+
var showSidebar = typeof props.showSidebar === "function" && props.showSidebar();
|
|
494
|
+
|
|
495
|
+
var children = [
|
|
496
|
+
h(
|
|
497
|
+
"div",
|
|
498
|
+
{ className: "dsu-main", key: "main" },
|
|
499
|
+
[
|
|
500
|
+
h(
|
|
501
|
+
"div",
|
|
502
|
+
{ className: "dsu-title", key: "title" },
|
|
503
|
+
[t("title"), data.updateAvailable || data.testReminder ? h("span", { className: "dsu-badge", key: "dot" }) : null],
|
|
504
|
+
),
|
|
505
|
+
h("div", { className: "dsu-desc", key: "desc" }, description),
|
|
506
|
+
meta ? h("div", { className: "dsu-meta", key: "meta" }, meta) : null,
|
|
507
|
+
updater.state.error ? h("div", { className: "dsu-error", key: "error" }, updater.state.error) : null,
|
|
508
|
+
],
|
|
509
|
+
),
|
|
510
|
+
h(
|
|
511
|
+
"div",
|
|
512
|
+
{ className: "dsu-control", key: "control" },
|
|
513
|
+
[
|
|
514
|
+
showSidebar
|
|
515
|
+
? h(
|
|
516
|
+
"button",
|
|
517
|
+
{
|
|
518
|
+
key: "sidebar",
|
|
519
|
+
type: "button",
|
|
520
|
+
className: "dsu-link",
|
|
521
|
+
onClick: function () {
|
|
522
|
+
if (typeof props.openSidebar === "function") props.openSidebar();
|
|
523
|
+
},
|
|
524
|
+
},
|
|
525
|
+
t("openSidebar"),
|
|
526
|
+
)
|
|
527
|
+
: null,
|
|
528
|
+
h(
|
|
529
|
+
"button",
|
|
530
|
+
{
|
|
531
|
+
key: "check",
|
|
532
|
+
type: "button",
|
|
533
|
+
className: "dsu-btn",
|
|
534
|
+
disabled: updater.state.loading || updater.running,
|
|
535
|
+
onClick: function () {
|
|
536
|
+
updater.load(true);
|
|
537
|
+
},
|
|
538
|
+
},
|
|
539
|
+
t("check"),
|
|
540
|
+
),
|
|
541
|
+
h(
|
|
542
|
+
"button",
|
|
543
|
+
{
|
|
544
|
+
key: "update",
|
|
545
|
+
type: "button",
|
|
546
|
+
className: "dsu-btn dsu-btn-primary",
|
|
547
|
+
disabled: updater.state.loading || updater.running || !data.updateAvailable || Boolean(data.testReminder),
|
|
548
|
+
onClick: function () {
|
|
549
|
+
updater.update();
|
|
550
|
+
},
|
|
551
|
+
},
|
|
552
|
+
t("update"),
|
|
553
|
+
),
|
|
554
|
+
],
|
|
555
|
+
),
|
|
556
|
+
];
|
|
557
|
+
|
|
558
|
+
if (updater.state.error) {
|
|
559
|
+
children.push(
|
|
560
|
+
h(
|
|
561
|
+
"div",
|
|
562
|
+
{ className: "dsu-manual", key: "manual" },
|
|
563
|
+
[h("div", { className: "dsu-desc", key: "label" }, t("manual"))].concat(
|
|
564
|
+
manualCommands(data.profileName).map(function (command, index) {
|
|
565
|
+
return h("code", { key: "cmd" + index }, command);
|
|
566
|
+
}),
|
|
567
|
+
),
|
|
568
|
+
),
|
|
569
|
+
);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
return h("div", { className: "dsu-row" }, children);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
function SettingsPage(props) {
|
|
576
|
+
var t = props.t;
|
|
577
|
+
var updater = useUpdater(t);
|
|
578
|
+
var test = useTestReminder();
|
|
579
|
+
var configState = useConfig(t);
|
|
580
|
+
var backupsState = useBackups(t);
|
|
581
|
+
var draftPair = React.useState({ channel: "auto", minAge: 0 });
|
|
582
|
+
var draft = draftPair[0];
|
|
583
|
+
var setDraft = draftPair[1];
|
|
584
|
+
|
|
585
|
+
React.useEffect(
|
|
586
|
+
function () {
|
|
587
|
+
if (configState.state.config) {
|
|
588
|
+
setDraft({
|
|
589
|
+
channel: configState.state.config.channel || "auto",
|
|
590
|
+
minAge: Number.isInteger(configState.state.config.minAge) ? configState.state.config.minAge : 0,
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
},
|
|
594
|
+
[configState.state.config],
|
|
595
|
+
);
|
|
596
|
+
|
|
597
|
+
var restartRequired = Boolean(updater.state.data && updater.state.data.restartRequired);
|
|
598
|
+
React.useEffect(
|
|
599
|
+
function () {
|
|
600
|
+
if (restartRequired) {
|
|
601
|
+
backupsState.load();
|
|
602
|
+
}
|
|
603
|
+
},
|
|
604
|
+
[restartRequired, backupsState.load],
|
|
605
|
+
);
|
|
606
|
+
|
|
607
|
+
var data = applyTestReminder(updater.state.data, test) || {};
|
|
608
|
+
var profiles = data.profiles || [];
|
|
609
|
+
var backups = backupsState.state.backups || [];
|
|
610
|
+
|
|
611
|
+
function saveDraft() {
|
|
612
|
+
configState.save({
|
|
613
|
+
channel: draft.channel,
|
|
614
|
+
minAge: Number(draft.minAge) || 0,
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
function rollback(id) {
|
|
619
|
+
if (typeof window !== "undefined" && typeof window.confirm === "function" && !window.confirm(t("rollbackConfirm"))) {
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
startRollback(id).then(function (result) {
|
|
623
|
+
if (result && result.error) {
|
|
624
|
+
updater.load(false);
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
updater.load(false);
|
|
628
|
+
});
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
return h("div", { className: "dsu-page" }, [
|
|
632
|
+
h(
|
|
633
|
+
"div",
|
|
634
|
+
{ className: "dsu-card", key: "status" },
|
|
635
|
+
[
|
|
636
|
+
h(
|
|
637
|
+
"div",
|
|
638
|
+
{ className: "dsu-card-head", key: "head" },
|
|
639
|
+
[
|
|
640
|
+
h("div", { className: "dsu-main", key: "main" }, [
|
|
641
|
+
h("div", { className: "dsu-card-title", key: "title" }, t("statusTitle")),
|
|
642
|
+
h("div", { className: "dsu-desc", key: "desc" }, statusText(t, data, updater.state.error)),
|
|
643
|
+
h("div", { className: "dsu-meta", key: "meta" }, metaText(t, data)),
|
|
644
|
+
]),
|
|
645
|
+
h("div", { className: "dsu-control", key: "control" }, [
|
|
646
|
+
h(
|
|
647
|
+
"button",
|
|
648
|
+
{
|
|
649
|
+
key: "check",
|
|
650
|
+
type: "button",
|
|
651
|
+
className: "dsu-btn",
|
|
652
|
+
disabled: updater.state.loading || updater.running,
|
|
653
|
+
onClick: function () {
|
|
654
|
+
updater.load(true);
|
|
655
|
+
},
|
|
656
|
+
},
|
|
657
|
+
t("check"),
|
|
658
|
+
),
|
|
659
|
+
h(
|
|
660
|
+
"button",
|
|
661
|
+
{
|
|
662
|
+
key: "update",
|
|
663
|
+
type: "button",
|
|
664
|
+
className: "dsu-btn dsu-btn-primary",
|
|
665
|
+
disabled: updater.state.loading || updater.running || !data.updateAvailable || Boolean(data.testReminder),
|
|
666
|
+
onClick: function () {
|
|
667
|
+
updater.update();
|
|
668
|
+
},
|
|
669
|
+
},
|
|
670
|
+
t("update"),
|
|
671
|
+
),
|
|
672
|
+
h(
|
|
673
|
+
"button",
|
|
674
|
+
{
|
|
675
|
+
key: "test",
|
|
676
|
+
type: "button",
|
|
677
|
+
className: "dsu-btn",
|
|
678
|
+
onClick: function () {
|
|
679
|
+
if (test) {
|
|
680
|
+
setTestReminder(false);
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
if (typeof props.openSidebar === "function") props.openSidebar();
|
|
684
|
+
sendBrowserNotification(t);
|
|
685
|
+
setTestReminder(true, 10000);
|
|
686
|
+
},
|
|
687
|
+
},
|
|
688
|
+
test ? t("testStop") : t("testStart"),
|
|
689
|
+
),
|
|
690
|
+
]),
|
|
691
|
+
],
|
|
692
|
+
),
|
|
693
|
+
updater.state.error ? h("div", { className: "dsu-error", key: "error" }, updater.state.error) : null,
|
|
694
|
+
data.logs && data.logs.length
|
|
695
|
+
? h("pre", { className: "dsu-log", key: "log" }, data.logs.slice(-12).join("\n"))
|
|
696
|
+
: null,
|
|
697
|
+
updater.state.error
|
|
698
|
+
? h(
|
|
699
|
+
"div",
|
|
700
|
+
{ className: "dsu-manual", key: "manual" },
|
|
701
|
+
[h("div", { className: "dsu-desc", key: "label" }, t("manual"))].concat(
|
|
702
|
+
manualCommands(data.profileName).map(function (command, index) {
|
|
703
|
+
return h("code", { key: "cmd" + index }, command);
|
|
704
|
+
}),
|
|
705
|
+
),
|
|
706
|
+
)
|
|
707
|
+
: null,
|
|
708
|
+
],
|
|
709
|
+
),
|
|
710
|
+
h(
|
|
711
|
+
"div",
|
|
712
|
+
{ className: "dsu-card", key: "config" },
|
|
713
|
+
[
|
|
714
|
+
h("div", { className: "dsu-card-title", key: "title" }, t("settingsTitle")),
|
|
715
|
+
h(
|
|
716
|
+
"div",
|
|
717
|
+
{ className: "dsu-field", key: "channel" },
|
|
718
|
+
[
|
|
719
|
+
h("div", { className: "dsu-field-label", key: "label" }, [
|
|
720
|
+
h("div", { className: "dsu-title", key: "t" }, t("channel")),
|
|
721
|
+
h("div", { className: "dsu-desc", key: "d" }, t("channelHint")),
|
|
722
|
+
]),
|
|
723
|
+
h(
|
|
724
|
+
"select",
|
|
725
|
+
{
|
|
726
|
+
key: "select",
|
|
727
|
+
className: "dsu-select",
|
|
728
|
+
value: draft.channel,
|
|
729
|
+
onChange: function (event) {
|
|
730
|
+
setDraft({ channel: event.target.value, minAge: draft.minAge });
|
|
731
|
+
},
|
|
732
|
+
},
|
|
733
|
+
[
|
|
734
|
+
h("option", { key: "auto", value: "auto" }, t("channelAuto")),
|
|
735
|
+
h("option", { key: "stable", value: "stable" }, t("channelStable")),
|
|
736
|
+
h("option", { key: "next", value: "next" }, t("channelNext")),
|
|
737
|
+
h("option", { key: "alpha", value: "alpha" }, t("channelAlpha")),
|
|
738
|
+
],
|
|
739
|
+
),
|
|
740
|
+
],
|
|
741
|
+
),
|
|
742
|
+
h(
|
|
743
|
+
"div",
|
|
744
|
+
{ className: "dsu-field", key: "min-age" },
|
|
745
|
+
[
|
|
746
|
+
h("div", { className: "dsu-field-label", key: "label" }, [
|
|
747
|
+
h("div", { className: "dsu-title", key: "t" }, t("minAge")),
|
|
748
|
+
h("div", { className: "dsu-desc", key: "d" }, t("minAgeHint")),
|
|
749
|
+
]),
|
|
750
|
+
h("div", { className: "dsu-control", key: "control" }, [
|
|
751
|
+
h("input", {
|
|
752
|
+
key: "input",
|
|
753
|
+
className: "dsu-input",
|
|
754
|
+
type: "number",
|
|
755
|
+
min: 0,
|
|
756
|
+
step: 60,
|
|
757
|
+
value: draft.minAge,
|
|
758
|
+
onChange: function (event) {
|
|
759
|
+
setDraft({ channel: draft.channel, minAge: Math.max(0, Number(event.target.value) || 0) });
|
|
760
|
+
},
|
|
761
|
+
}),
|
|
762
|
+
h("span", { className: "dsu-desc", key: "unit" }, t("minAgeUnit")),
|
|
763
|
+
]),
|
|
764
|
+
],
|
|
765
|
+
),
|
|
766
|
+
h(
|
|
767
|
+
"div",
|
|
768
|
+
{ className: "dsu-control", key: "actions" },
|
|
769
|
+
[
|
|
770
|
+
h(
|
|
771
|
+
"button",
|
|
772
|
+
{ key: "save", type: "button", className: "dsu-btn dsu-btn-primary", disabled: configState.state.loading, onClick: saveDraft },
|
|
773
|
+
t("save"),
|
|
774
|
+
),
|
|
775
|
+
configState.state.saved ? h("span", { key: "saved", className: "dsu-ok" }, t("saved")) : null,
|
|
776
|
+
configState.state.error ? h("span", { key: "error", className: "dsu-error" }, configState.state.error) : null,
|
|
777
|
+
],
|
|
778
|
+
),
|
|
779
|
+
],
|
|
780
|
+
),
|
|
781
|
+
h(
|
|
782
|
+
"div",
|
|
783
|
+
{ className: "dsu-card", key: "profiles" },
|
|
784
|
+
[
|
|
785
|
+
h("div", { className: "dsu-card-title", key: "title" }, t("profilesTitle")),
|
|
786
|
+
profiles.length
|
|
787
|
+
? h(
|
|
788
|
+
"ul",
|
|
789
|
+
{ className: "dsu-list", key: "list" },
|
|
790
|
+
profiles.map(function (profile) {
|
|
791
|
+
return h(
|
|
792
|
+
"li",
|
|
793
|
+
{ className: "dsu-list-item", key: profile.name },
|
|
794
|
+
[
|
|
795
|
+
h("code", { key: "name" }, profile.name),
|
|
796
|
+
h("span", { key: "count" }, t("profilesCount", { count: profile.dependencyCount })),
|
|
797
|
+
],
|
|
798
|
+
);
|
|
799
|
+
}),
|
|
800
|
+
)
|
|
801
|
+
: h("div", { className: "dsu-empty", key: "empty" }, "—"),
|
|
802
|
+
],
|
|
803
|
+
),
|
|
804
|
+
h(
|
|
805
|
+
"div",
|
|
806
|
+
{ className: "dsu-card", key: "backups" },
|
|
807
|
+
[
|
|
808
|
+
h("div", { className: "dsu-card-title", key: "title" }, t("backupsTitle")),
|
|
809
|
+
backupsState.state.error ? h("div", { className: "dsu-error", key: "error" }, backupsState.state.error) : null,
|
|
810
|
+
backups.length
|
|
811
|
+
? h(
|
|
812
|
+
"div",
|
|
813
|
+
{ key: "list" },
|
|
814
|
+
backups.slice(0, 20).map(function (backup) {
|
|
815
|
+
var date = backup.createdAt ? new Date(backup.createdAt).toLocaleString() : backup.id;
|
|
816
|
+
var profileNames = Array.isArray(backup.profiles) ? backup.profiles.join(", ") : "";
|
|
817
|
+
return h(
|
|
818
|
+
"div",
|
|
819
|
+
{ className: "dsu-backup", key: backup.id },
|
|
820
|
+
[
|
|
821
|
+
h("div", { className: "dsu-main", key: "main" }, [
|
|
822
|
+
h("div", { className: "dsu-title", key: "id" }, backup.id),
|
|
823
|
+
h("div", { className: "dsu-meta", key: "meta" }, t("backupMeta", {
|
|
824
|
+
date: date,
|
|
825
|
+
version: backup.cliVersion || "?",
|
|
826
|
+
profiles: profileNames || "—",
|
|
827
|
+
})),
|
|
828
|
+
]),
|
|
829
|
+
h(
|
|
830
|
+
"button",
|
|
831
|
+
{
|
|
832
|
+
key: "rollback",
|
|
833
|
+
type: "button",
|
|
834
|
+
className: "dsu-btn",
|
|
835
|
+
disabled: updater.running,
|
|
836
|
+
onClick: function () {
|
|
837
|
+
rollback(backup.id);
|
|
838
|
+
},
|
|
839
|
+
},
|
|
840
|
+
t("rollback"),
|
|
841
|
+
),
|
|
842
|
+
],
|
|
843
|
+
);
|
|
844
|
+
}),
|
|
845
|
+
)
|
|
846
|
+
: h("div", { className: "dsu-empty", key: "empty" }, t("noBackups")),
|
|
847
|
+
],
|
|
848
|
+
),
|
|
849
|
+
]);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
function UpdatePanel(props) {
|
|
853
|
+
var t = props.t;
|
|
854
|
+
var updater = useUpdater(t);
|
|
855
|
+
var data = updater.state.data || {};
|
|
856
|
+
var description = statusText(t, updater.state.data, updater.state.error);
|
|
857
|
+
var meta = metaText(t, updater.state.data);
|
|
858
|
+
|
|
859
|
+
return h("div", { className: "dsu-page", style: { padding: "12px", maxWidth: "none" } }, [
|
|
860
|
+
h("div", { className: "dsu-card", key: "status" }, [
|
|
861
|
+
h("div", { className: "dsu-main", key: "main" }, [
|
|
862
|
+
h("div", { className: "dsu-title", key: "title" }, t("sidebarPanelTitle")),
|
|
863
|
+
h("div", { className: "dsu-desc", key: "desc" }, description),
|
|
864
|
+
meta ? h("div", { className: "dsu-meta", key: "meta" }, meta) : null,
|
|
865
|
+
updater.state.error ? h("div", { className: "dsu-error", key: "error" }, updater.state.error) : null,
|
|
866
|
+
]),
|
|
867
|
+
h("div", { className: "dsu-control", key: "control", style: { marginTop: "10px" } }, [
|
|
868
|
+
h(
|
|
869
|
+
"button",
|
|
870
|
+
{
|
|
871
|
+
key: "check",
|
|
872
|
+
type: "button",
|
|
873
|
+
className: "dsu-btn",
|
|
874
|
+
disabled: updater.state.loading || updater.running,
|
|
875
|
+
onClick: function () {
|
|
876
|
+
updater.load(true);
|
|
877
|
+
},
|
|
878
|
+
},
|
|
879
|
+
t("check"),
|
|
880
|
+
),
|
|
881
|
+
h(
|
|
882
|
+
"button",
|
|
883
|
+
{
|
|
884
|
+
key: "update",
|
|
885
|
+
type: "button",
|
|
886
|
+
className: "dsu-btn dsu-btn-primary",
|
|
887
|
+
disabled: updater.state.loading || updater.running || !data.updateAvailable || Boolean(data.testReminder),
|
|
888
|
+
onClick: function () {
|
|
889
|
+
updater.update();
|
|
890
|
+
},
|
|
891
|
+
},
|
|
892
|
+
t("update"),
|
|
893
|
+
),
|
|
894
|
+
]),
|
|
895
|
+
data.logs && data.logs.length
|
|
896
|
+
? h("pre", { className: "dsu-log", key: "log", style: { marginTop: "10px" } }, data.logs.slice(-8).join("\n"))
|
|
897
|
+
: null,
|
|
898
|
+
h("div", { className: "dsu-desc", key: "hint", style: { marginTop: "10px" } }, t("viewSettingsHint")),
|
|
899
|
+
]),
|
|
900
|
+
]);
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
function SidebarTitle(props) {
|
|
904
|
+
var t = props.t;
|
|
905
|
+
var test = useTestReminder();
|
|
906
|
+
var pair = React.useState({ updateAvailable: false, running: false });
|
|
907
|
+
var state = pair[0];
|
|
908
|
+
var setState = pair[1];
|
|
909
|
+
|
|
910
|
+
React.useEffect(
|
|
911
|
+
function () {
|
|
912
|
+
var active = true;
|
|
913
|
+
function tick() {
|
|
914
|
+
getStatus(false)
|
|
915
|
+
.then(function (data) {
|
|
916
|
+
if (!active) return;
|
|
917
|
+
setState({
|
|
918
|
+
updateAvailable: Boolean(data && data.updateAvailable),
|
|
919
|
+
running: Boolean(data && data.running),
|
|
920
|
+
});
|
|
921
|
+
})
|
|
922
|
+
.catch(function () {});
|
|
923
|
+
}
|
|
924
|
+
tick();
|
|
925
|
+
var timer = setInterval(tick, 30000);
|
|
926
|
+
return function () {
|
|
927
|
+
active = false;
|
|
928
|
+
clearInterval(timer);
|
|
929
|
+
};
|
|
930
|
+
},
|
|
931
|
+
[],
|
|
932
|
+
);
|
|
933
|
+
|
|
934
|
+
return h(
|
|
935
|
+
"span",
|
|
936
|
+
{ className: "dsu-title" },
|
|
937
|
+
[
|
|
938
|
+
h("span", { key: "label" }, t("title")),
|
|
939
|
+
state.updateAvailable || state.running || test
|
|
940
|
+
? h("span", { key: "badge", className: "dsu-badge", title: state.updateAvailable || test ? t("badgeUpdate") : t("updating") })
|
|
941
|
+
: null,
|
|
942
|
+
],
|
|
943
|
+
);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
function apply(ctx) {
|
|
947
|
+
function t(key, params) {
|
|
948
|
+
return ctx.locale.bind(NS)(key, params);
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
ctx.effect(
|
|
952
|
+
function () {
|
|
953
|
+
injectStyle();
|
|
954
|
+
return removeStyle;
|
|
955
|
+
},
|
|
956
|
+
"dsh-update-plugin: styles",
|
|
957
|
+
);
|
|
958
|
+
|
|
959
|
+
ctx.effect(
|
|
960
|
+
function () {
|
|
961
|
+
return ctx.locale.register(NS, { zh: ZH, en: EN });
|
|
962
|
+
},
|
|
963
|
+
"dsh-update-plugin: dictionaries",
|
|
964
|
+
);
|
|
965
|
+
|
|
966
|
+
var sidebarRight = null;
|
|
967
|
+
ctx.inject(["sidebarRightTabs", "sidebarRight"], function (sideCtx) {
|
|
968
|
+
sidebarRight = sideCtx.sidebarRight;
|
|
969
|
+
sideCtx.effect(
|
|
970
|
+
function () {
|
|
971
|
+
return sideCtx.sidebarRightTabs.register({
|
|
972
|
+
id: SIDEBAR_ID,
|
|
973
|
+
kind: SIDEBAR_ID,
|
|
974
|
+
title: function () {
|
|
975
|
+
return t("title");
|
|
976
|
+
},
|
|
977
|
+
});
|
|
978
|
+
},
|
|
979
|
+
"dsh-update-plugin: sidebar tab type",
|
|
980
|
+
);
|
|
981
|
+
sideCtx.effect(
|
|
982
|
+
function () {
|
|
983
|
+
return sideCtx.slots.register(
|
|
984
|
+
{ name: "sidebar.right.pane.tab", key: SIDEBAR_ID },
|
|
985
|
+
function SidebarBodyWrapper(props) {
|
|
986
|
+
return h(UpdatePanel, Object.assign({}, props, { t: t }));
|
|
987
|
+
},
|
|
988
|
+
);
|
|
989
|
+
},
|
|
990
|
+
"dsh-update-plugin: sidebar tab body",
|
|
991
|
+
);
|
|
992
|
+
sideCtx.effect(
|
|
993
|
+
function () {
|
|
994
|
+
return sideCtx.slots.register(
|
|
995
|
+
{ name: "sidebar.right.pane.tab.title", key: SIDEBAR_ID },
|
|
996
|
+
function SidebarTitleWrapper() {
|
|
997
|
+
return h(SidebarTitle, { t: t });
|
|
998
|
+
},
|
|
999
|
+
);
|
|
1000
|
+
},
|
|
1001
|
+
"dsh-update-plugin: sidebar tab title",
|
|
1002
|
+
);
|
|
1003
|
+
});
|
|
1004
|
+
|
|
1005
|
+
ctx.slots.inject("settings.general.item", function () {
|
|
1006
|
+
return ctx.slots.register(
|
|
1007
|
+
{
|
|
1008
|
+
name: "settings.general.item",
|
|
1009
|
+
id: "dsh-update-plugin",
|
|
1010
|
+
order: 80,
|
|
1011
|
+
locale: NS,
|
|
1012
|
+
inject: function () {
|
|
1013
|
+
return {
|
|
1014
|
+
showSidebar: function () {
|
|
1015
|
+
return Boolean(sidebarRight);
|
|
1016
|
+
},
|
|
1017
|
+
openSidebar: function () {
|
|
1018
|
+
if (sidebarRight && typeof sidebarRight.openTab === "function") {
|
|
1019
|
+
sidebarRight.openTab(SIDEBAR_ID);
|
|
1020
|
+
}
|
|
1021
|
+
},
|
|
1022
|
+
};
|
|
1023
|
+
},
|
|
1024
|
+
},
|
|
1025
|
+
function GeneralRowWrapper(props) {
|
|
1026
|
+
return h(UpdateRow, Object.assign({}, props, { t: props.t || t }));
|
|
1027
|
+
},
|
|
1028
|
+
);
|
|
1029
|
+
});
|
|
1030
|
+
|
|
1031
|
+
ctx.slots.inject("settings.section", function () {
|
|
1032
|
+
return ctx.slots.register(
|
|
1033
|
+
{
|
|
1034
|
+
name: "settings.section",
|
|
1035
|
+
id: "dsh-update-plugin",
|
|
1036
|
+
order: 80,
|
|
1037
|
+
label: function () {
|
|
1038
|
+
return t("title");
|
|
1039
|
+
},
|
|
1040
|
+
locale: NS,
|
|
1041
|
+
inject: function () {
|
|
1042
|
+
return {
|
|
1043
|
+
openSidebar: function () {
|
|
1044
|
+
if (sidebarRight && typeof sidebarRight.openTab === "function") {
|
|
1045
|
+
sidebarRight.openTab(SIDEBAR_ID);
|
|
1046
|
+
}
|
|
1047
|
+
},
|
|
1048
|
+
};
|
|
1049
|
+
},
|
|
1050
|
+
},
|
|
1051
|
+
function SettingsPageWrapper(props) {
|
|
1052
|
+
return h(SettingsPage, Object.assign({}, props, { t: props.t || t }));
|
|
1053
|
+
},
|
|
1054
|
+
);
|
|
1055
|
+
});
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
module.exports.name = "dsh-update-plugin";
|
|
1059
|
+
module.exports.apply = apply;
|
|
1060
|
+
module.exports.inject = ["slots", "locale"];
|
|
1061
|
+
return module.exports;
|
|
1062
|
+
},
|
|
1063
|
+
});
|