@1e0zj/dsh-plugin-mall 0.4.6 → 0.4.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/package.json +1 -1
- package/src/cli.js +924 -65
- package/src/client.js +278 -112
- package/src/index.js +635 -33
- package/src/restart-protocol.js +258 -0
package/src/client.js
CHANGED
|
@@ -28,6 +28,8 @@ window.__ModuleLoader__.load({
|
|
|
28
28
|
".mkt_btnDanger:hover:not(:disabled){border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}",
|
|
29
29
|
".mkt_btnSm{padding:3px 10px;font-size:12px}",
|
|
30
30
|
".mkt_error{color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px}",
|
|
31
|
+
".mkt_notice{border-left:3px solid var(--dsw-alias-state-error-primary);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-state-error-primary);padding:7px 10px;font-size:12px;line-height:18px;overflow-wrap:anywhere}",
|
|
32
|
+
".mkt_noticeInfo{border-left-color:var(--dsw-alias-state-accent-primary);color:inherit}",
|
|
31
33
|
".mkt_list{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;align-items:stretch;min-width:0}",
|
|
32
34
|
"@media (max-width:820px){.mkt_list{grid-template-columns:minmax(0,1fr)}}",
|
|
33
35
|
".mkt_listHead{grid-column:1/-1;font-size:12px;color:var(--dsw-alias-label-tertiary)}",
|
|
@@ -43,8 +45,9 @@ window.__ModuleLoader__.load({
|
|
|
43
45
|
".mkt_panelTitle{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary);margin:0}",
|
|
44
46
|
".mkt_panelRow{display:flex;align-items:center;gap:8px}",
|
|
45
47
|
".mkt_panelRow .mkt_link{margin-left:auto}",
|
|
46
|
-
".mkt_pre{font-family:Consolas,Monaco,monospace;font-size:11.5px;line-height:16px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-markdown-code-block);border-radius:6px;padding:8px;max-height:
|
|
48
|
+
".mkt_pre{box-sizing:border-box;width:100%;max-width:100%;min-width:0;font-family:Consolas,Monaco,monospace;font-size:11.5px;line-height:16px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-markdown-code-block);border-radius:6px;padding:8px;max-height:280px;overflow:auto;white-space:pre;word-break:normal}",
|
|
47
49
|
".mkt_ok{color:var(--dsw-alias-state-success-primary)}",
|
|
50
|
+
".mkt_warn{color:var(--dsw-alias-state-warn-label)}",
|
|
48
51
|
".mkt_badge{display:inline-block;border-radius:999px;padding:1px 8px;font-size:11px;border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary)}",
|
|
49
52
|
".mkt_badgeOk{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary)}",
|
|
50
53
|
".mkt_badgeWarn{border-color:var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-label)}",
|
|
@@ -57,13 +60,31 @@ window.__ModuleLoader__.load({
|
|
|
57
60
|
".mkt_depList{display:flex;flex-direction:column;gap:6px;margin-top:8px}",
|
|
58
61
|
".mkt_depRow{display:flex;justify-content:space-between;align-items:center;gap:8px}",
|
|
59
62
|
".mkt_depActions{display:flex;align-items:center;gap:6px;flex-wrap:wrap}",
|
|
60
|
-
".
|
|
61
|
-
".
|
|
63
|
+
".mkt_decision{display:flex;flex-direction:column;border:1px solid var(--dsw-alias-state-warn-secondary);border-radius:6px;overflow:hidden;margin-top:4px}",
|
|
64
|
+
".mkt_decisionError{border-color:var(--dsw-alias-state-error-primary)}",
|
|
65
|
+
".mkt_decisionHead{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;padding:8px 10px;background:var(--dsw-alias-state-warn-tertiary);color:var(--dsw-alias-state-warn-label)}",
|
|
66
|
+
".mkt_decisionError .mkt_decisionHead{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-state-error-primary)}",
|
|
67
|
+
".mkt_decisionTitle{font-size:13px;font-weight:600}",
|
|
68
|
+
".mkt_decisionBody{display:flex;flex-direction:column;gap:8px;min-width:0;padding:10px;max-height:300px;overflow:auto}",
|
|
69
|
+
".mkt_decisionActions{display:flex;justify-content:flex-end;align-items:center;gap:8px;padding:8px 10px;border-top:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3)}",
|
|
62
70
|
".mkt_approvePkg{display:flex;flex-direction:column;gap:4px}",
|
|
63
71
|
".mkt_approveName{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary);margin-right:8px;overflow-wrap:anywhere}",
|
|
64
72
|
".mkt_approveCmd{max-height:none;margin:0}",
|
|
65
73
|
".mkt_jobDone{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:2px}",
|
|
66
|
-
".mkt_logBlock{display:flex;flex-direction:column;gap:4px;align-items:
|
|
74
|
+
".mkt_logBlock{display:flex;flex-direction:column;gap:4px;align-items:stretch;min-width:0;max-width:100%}",
|
|
75
|
+
".mkt_linkButton{align-self:flex-start;border:0;background:none;padding:0;color:var(--dsw-alias-state-business-primary);font:inherit;font-size:12px;cursor:pointer}",
|
|
76
|
+
".mkt_job{display:flex;flex-direction:column;gap:6px;min-width:0;max-width:100%;padding-top:10px;border-top:1px solid var(--dsw-alias-border-l2)}",
|
|
77
|
+
".mkt_panelRow + .mkt_job{padding-top:0;border-top:0}",
|
|
78
|
+
".mkt_jobHead{display:flex;align-items:center;gap:8px;min-width:0}",
|
|
79
|
+
".mkt_jobIdentity{display:flex;align-items:center;gap:7px;min-width:0;font-size:12px;color:var(--dsw-alias-label-tertiary)}",
|
|
80
|
+
".mkt_jobHead .mkt_btn{margin-left:auto;flex:none}",
|
|
81
|
+
".mkt_stateDot{width:7px;height:7px;border-radius:50%;background:var(--dsw-alias-label-caption);flex:none}",
|
|
82
|
+
".mkt_stateRunning{background:var(--dsw-alias-state-business-primary);animation:mktPulse 1.6s ease-in-out infinite}",
|
|
83
|
+
".mkt_stateDone{background:var(--dsw-alias-state-success-primary)}",
|
|
84
|
+
".mkt_stateWarn{background:var(--dsw-alias-state-warn-primary)}",
|
|
85
|
+
".mkt_stateError{background:var(--dsw-alias-state-error-primary)}",
|
|
86
|
+
"@keyframes mktPulse{0%,100%{opacity:.45}50%{opacity:1}}",
|
|
87
|
+
"@media (prefers-reduced-motion:reduce){.mkt_stateRunning{animation:none}.mkt_switch,.mkt_switchKnob{transition:none}}",
|
|
67
88
|
".mkt_depOff{opacity:.5;text-decoration:line-through}",
|
|
68
89
|
".mkt_switch{position:relative;width:34px;height:18px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);cursor:pointer;padding:0;transition:background .15s,border-color .15s}",
|
|
69
90
|
".mkt_switch:disabled{opacity:.55;cursor:default}",
|
|
@@ -71,11 +92,16 @@ window.__ModuleLoader__.load({
|
|
|
71
92
|
".mkt_switchKnob{position:absolute;top:1px;left:1px;width:14px;height:14px;border-radius:50%;background:var(--dsw-alias-label-primary-foreground);transition:transform .15s;box-shadow:var(--dsw-shadow-lv1)}",
|
|
72
93
|
".mkt_switchOn .mkt_switchKnob{transform:translateX(16px)}",
|
|
73
94
|
".mkt_issueList{list-style:none;display:flex;flex-direction:column;gap:8px;margin:0;padding:0}",
|
|
74
|
-
".mkt_issue{border:1px solid var(--dsw-alias-border-l2);border-radius:
|
|
95
|
+
".mkt_issue{border:1px solid var(--dsw-alias-border-l2);border-radius:6px;padding:8px 10px;background:var(--dsw-alias-bg-layer-3)}",
|
|
75
96
|
".mkt_issueBlock{border-color:var(--dsw-alias-state-error-primary)}",
|
|
76
97
|
".mkt_issueWarn{border-color:var(--dsw-alias-state-warn-primary)}",
|
|
77
98
|
".mkt_issueTitle{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary)}",
|
|
78
99
|
".mkt_issueDetail{font-size:12px;color:var(--dsw-alias-label-secondary);margin-top:4px;line-height:18px;overflow-wrap:anywhere}",
|
|
100
|
+
".mkt_modalMask{position:fixed;inset:0;z-index:1000;display:flex;align-items:center;justify-content:center;padding:20px;background:var(--dsw-alias-bg-mask-3)}",
|
|
101
|
+
".mkt_modal{width:min(420px,100%);max-height:min(520px,calc(100vh - 40px));display:flex;flex-direction:column;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-3);box-shadow:var(--dsw-shadow-lv3)}",
|
|
102
|
+
".mkt_modalHead{padding:14px 16px 8px;font-size:15px;font-weight:600;color:var(--dsw-alias-label-primary)}",
|
|
103
|
+
".mkt_modalBody{padding:0 16px 14px;font-size:12.5px;line-height:19px;color:var(--dsw-alias-label-secondary);overflow:auto}",
|
|
104
|
+
".mkt_modalActions{display:flex;justify-content:flex-end;gap:8px;padding:10px 16px;border-top:1px solid var(--dsw-alias-border-l2)}",
|
|
79
105
|
].join("\n");
|
|
80
106
|
var tagId = "@1e0zj/dsh-plugin-mall/market-tab.css";
|
|
81
107
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
@@ -102,6 +128,10 @@ window.__ModuleLoader__.load({
|
|
|
102
128
|
return String(e && e.message ? e.message : e);
|
|
103
129
|
}
|
|
104
130
|
|
|
131
|
+
function isJobActive(status) {
|
|
132
|
+
return status === "running" || status === "stopping";
|
|
133
|
+
}
|
|
134
|
+
|
|
105
135
|
function kindLabel(kind) {
|
|
106
136
|
if (kind === "bundle") return "宿主插件层";
|
|
107
137
|
if (kind === "client") return "浏览器UI插件";
|
|
@@ -159,7 +189,7 @@ window.__ModuleLoader__.load({
|
|
|
159
189
|
var current = jobsRef.current;
|
|
160
190
|
var running = Object.keys(current).filter(function (id) {
|
|
161
191
|
var job = current[id];
|
|
162
|
-
return job && job.status
|
|
192
|
+
return job && isJobActive(job.status);
|
|
163
193
|
});
|
|
164
194
|
if (running.length === 0) return;
|
|
165
195
|
running.forEach(function (id) {
|
|
@@ -211,21 +241,23 @@ window.__ModuleLoader__.load({
|
|
|
211
241
|
delete next[carryFromId];
|
|
212
242
|
}
|
|
213
243
|
for (var key in next) {
|
|
214
|
-
if (key !== id && next[key] && next[key].spec === spec && next[key].status
|
|
244
|
+
if (key !== id && next[key] && next[key].spec === spec && !isJobActive(next[key].status)) {
|
|
215
245
|
delete next[key];
|
|
216
246
|
}
|
|
217
247
|
}
|
|
218
248
|
next[id] = { status: "running", spec: spec, output: carried };
|
|
219
249
|
commit(next);
|
|
220
250
|
}, [commit]);
|
|
221
|
-
var clear = useCallback(function () {
|
|
222
|
-
commit({});
|
|
223
|
-
}, [commit]);
|
|
224
251
|
var drop = useCallback(function (id) {
|
|
225
252
|
var next = Object.assign({}, jobsRef.current);
|
|
226
253
|
delete next[id];
|
|
227
254
|
commit(next);
|
|
228
255
|
}, [commit]);
|
|
256
|
+
var setStatus = useCallback(function (id, status) {
|
|
257
|
+
var current = jobsRef.current[id];
|
|
258
|
+
if (!current) return;
|
|
259
|
+
commit(Object.assign({}, jobsRef.current, { [id]: Object.assign({}, current, { status: status }) }));
|
|
260
|
+
}, [commit]);
|
|
229
261
|
// 恢复后端任务记录(tracker.list 的形状):安装事务改写
|
|
230
262
|
// cordis.patch.yml 会让 dsh 重放装配树、整个市场 UI 重挂载,React
|
|
231
263
|
// state 全丢——任务面板、完成提醒、重启按钮一起消失(真实事故:
|
|
@@ -269,7 +301,7 @@ window.__ModuleLoader__.load({
|
|
|
269
301
|
for (var key in next) {
|
|
270
302
|
if (serverIds[key]) continue;
|
|
271
303
|
var stale = next[key];
|
|
272
|
-
if (stale.status
|
|
304
|
+
if (isJobActive(stale.status)) {
|
|
273
305
|
next[key] = Object.assign({}, stale, {
|
|
274
306
|
status: "killed",
|
|
275
307
|
detail: "宿主进程已重启,该任务的记录随之丢失",
|
|
@@ -282,7 +314,7 @@ window.__ModuleLoader__.load({
|
|
|
282
314
|
}
|
|
283
315
|
commit(next);
|
|
284
316
|
}, [commit]);
|
|
285
|
-
return { jobs: jobs, track: track,
|
|
317
|
+
return { jobs: jobs, track: track, drop: drop, setStatus: setStatus, restore: restore };
|
|
286
318
|
}
|
|
287
319
|
|
|
288
320
|
// ── plugin verification badge ───────────────────────────────────────────
|
|
@@ -319,7 +351,10 @@ window.__ModuleLoader__.load({
|
|
|
319
351
|
var installLabel = props.alreadyInstalled === true ? "已装" : "安装";
|
|
320
352
|
var installDisabled = installing || props.alreadyInstalled === true;
|
|
321
353
|
if (!installing && job) {
|
|
322
|
-
if (job.status
|
|
354
|
+
if (isJobActive(job.status)) {
|
|
355
|
+
installLabel = job.status === "stopping" ? "停止中…" : "安装中…";
|
|
356
|
+
installDisabled = true;
|
|
357
|
+
}
|
|
323
358
|
else if (job.status === "completed") { installLabel = "已装 · 重启生效"; installDisabled = true; }
|
|
324
359
|
else if (job.status === "failed") { installLabel = "安装失败 · 见任务日志"; }
|
|
325
360
|
else { installLabel = "已取消 · 重试"; }
|
|
@@ -346,11 +381,69 @@ window.__ModuleLoader__.load({
|
|
|
346
381
|
);
|
|
347
382
|
}
|
|
348
383
|
|
|
384
|
+
function DecisionPanel(props) {
|
|
385
|
+
var tone = props.tone === "error" ? " mkt_decisionError" : "";
|
|
386
|
+
return h("div", { className: "mkt_decision" + tone },
|
|
387
|
+
h("div", { className: "mkt_decisionHead" },
|
|
388
|
+
h("span", { className: "mkt_decisionTitle" }, props.title),
|
|
389
|
+
props.meta ? h("span", { className: "mkt_meta" }, props.meta) : null),
|
|
390
|
+
h("div", { className: "mkt_decisionBody" }, props.children),
|
|
391
|
+
h("div", { className: "mkt_decisionActions" }, props.actions));
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function ErrorNotice(props) {
|
|
395
|
+
if (!props.message) return null;
|
|
396
|
+
return h("div", { className: "mkt_notice", role: "alert" }, props.message);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// 状态性提示(区别于 ErrorNotice 的 role=alert):「重启已调度」这类
|
|
400
|
+
// 成功路径的进展信息,页面自动重连后随刷新自然消失。
|
|
401
|
+
function StatusNotice(props) {
|
|
402
|
+
if (!props.message) return null;
|
|
403
|
+
return h("div", { className: "mkt_notice mkt_noticeInfo", role: "status" }, props.message);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function RestartDialog(props) {
|
|
407
|
+
useEffect(function () {
|
|
408
|
+
function onKeyDown(event) {
|
|
409
|
+
if (event.key === "Escape" && props.busy !== true) props.onCancel();
|
|
410
|
+
}
|
|
411
|
+
document.addEventListener("keydown", onKeyDown);
|
|
412
|
+
return function () { document.removeEventListener("keydown", onKeyDown); };
|
|
413
|
+
}, [props.busy, props.onCancel]);
|
|
414
|
+
return h("div", {
|
|
415
|
+
className: "mkt_modalMask",
|
|
416
|
+
onMouseDown: function (event) {
|
|
417
|
+
if (event.target === event.currentTarget && props.busy !== true) props.onCancel();
|
|
418
|
+
},
|
|
419
|
+
}, h("div", { className: "mkt_modal", role: "dialog", "aria-modal": "true", "aria-labelledby": "mkt-restart-title" },
|
|
420
|
+
h("div", { id: "mkt-restart-title", className: "mkt_modalHead" }, "重启 dsh"),
|
|
421
|
+
h("div", { className: "mkt_modalBody" }, props.activeCount > 0
|
|
422
|
+
? "当前有 " + props.activeCount + " 个任务仍在进行。重启会中断这些任务,未完成的改动将由事务恢复逻辑处理。"
|
|
423
|
+
: "重启后,已经完成的插件安装、更新或卸载才会生效。"),
|
|
424
|
+
h("div", { className: "mkt_modalActions" },
|
|
425
|
+
h("button", { className: "mkt_btn", disabled: props.busy === true, autoFocus: true, onClick: props.onCancel }, "取消"),
|
|
426
|
+
h("button", { className: "mkt_btn mkt_btnPrimary", disabled: props.busy === true, onClick: props.onConfirm }, props.busy ? "重启中…" : "确认重启"))));
|
|
427
|
+
}
|
|
428
|
+
|
|
349
429
|
// ── install-script approval ─────────────────────────────────────────────
|
|
350
430
|
function ApprovalRequest(props) {
|
|
351
431
|
var pkgs = props.needsApproval || [];
|
|
352
|
-
|
|
353
|
-
h("
|
|
432
|
+
var actions = [
|
|
433
|
+
h("button", { key: "cancel", className: "mkt_btn mkt_btnSm", disabled: props.busy === true, onClick: props.onDismiss }, "取消"),
|
|
434
|
+
h("button", {
|
|
435
|
+
key: "allow",
|
|
436
|
+
className: "mkt_btn mkt_btnPrimary mkt_btnSm",
|
|
437
|
+
disabled: props.busy === true,
|
|
438
|
+
onClick: function () { props.onApprove(pkgs.map(function (p) { return p.name; })); },
|
|
439
|
+
}, props.busy ? "继续中…" : "允许并继续"),
|
|
440
|
+
];
|
|
441
|
+
return h(DecisionPanel, {
|
|
442
|
+
title: "安装期代码需要确认",
|
|
443
|
+
meta: clip(props.spec || "", 50),
|
|
444
|
+
actions: actions,
|
|
445
|
+
},
|
|
446
|
+
props.detail ? h("div", { className: "mkt_desc" }, props.detail) : null,
|
|
354
447
|
pkgs.map(function (p, index) {
|
|
355
448
|
var facts = [];
|
|
356
449
|
if (typeof p.weeklyDownloads === "number") facts.push("周下载 " + p.weeklyDownloads.toLocaleString());
|
|
@@ -370,16 +463,7 @@ window.__ModuleLoader__.load({
|
|
|
370
463
|
h("div", { className: "mkt_meta" }, facts.join(" · "))
|
|
371
464
|
);
|
|
372
465
|
}),
|
|
373
|
-
h("div", { className: "mkt_meta" }, "这些命令会以你的权限在你的机器上运行,早于任何插件代码加载。")
|
|
374
|
-
h("div", { className: "mkt_row" },
|
|
375
|
-
h("button", {
|
|
376
|
-
className: "mkt_btn mkt_btnPrimary mkt_btnSm",
|
|
377
|
-
disabled: props.busy === true,
|
|
378
|
-
onClick: function () { props.onApprove(pkgs.map(function (p) { return p.name; })); },
|
|
379
|
-
}, props.busy ? "继续中…" : "允许并继续"),
|
|
380
|
-
h("button", { className: "mkt_btn mkt_btnSm", onClick: props.onDismiss }, "取消")
|
|
381
|
-
)
|
|
382
|
-
);
|
|
466
|
+
h("div", { className: "mkt_meta" }, "这些命令会以你的权限在你的机器上运行,早于任何插件代码加载。"));
|
|
383
467
|
}
|
|
384
468
|
|
|
385
469
|
// ── preflight result card ────────────────────────────────────────────────
|
|
@@ -391,11 +475,23 @@ window.__ModuleLoader__.load({
|
|
|
391
475
|
var blocked = report.verdict === "blocked";
|
|
392
476
|
var title = blocked ? "安装被阻止" : "安装存在风险";
|
|
393
477
|
var issues = report.issues || [];
|
|
394
|
-
|
|
395
|
-
h("
|
|
396
|
-
|
|
397
|
-
h("
|
|
398
|
-
|
|
478
|
+
var actions = blocked
|
|
479
|
+
? h("button", { className: "mkt_btn mkt_btnSm", onClick: props.onClose }, "关闭")
|
|
480
|
+
: [
|
|
481
|
+
h("button", { key: "cancel", className: "mkt_btn mkt_btnSm", disabled: props.busy === true, onClick: props.onClose }, "取消"),
|
|
482
|
+
h("button", {
|
|
483
|
+
key: "confirm",
|
|
484
|
+
className: "mkt_btn mkt_btnPrimary mkt_btnSm",
|
|
485
|
+
disabled: props.busy === true,
|
|
486
|
+
onClick: props.onConfirm,
|
|
487
|
+
}, props.busy ? "安装中…" : "了解风险并继续"),
|
|
488
|
+
];
|
|
489
|
+
return h(DecisionPanel, {
|
|
490
|
+
tone: blocked ? "error" : "warning",
|
|
491
|
+
title: title,
|
|
492
|
+
meta: clip(props.spec, 50),
|
|
493
|
+
actions: actions,
|
|
494
|
+
},
|
|
399
495
|
report.summary ? h("div", { className: "mkt_desc" }, report.summary) : null,
|
|
400
496
|
issues.length > 0 ? h("ul", { className: "mkt_issueList" },
|
|
401
497
|
issues.map(function (issue) {
|
|
@@ -406,21 +502,7 @@ window.__ModuleLoader__.load({
|
|
|
406
502
|
h("div", { className: "mkt_issueTitle" }, issue.title),
|
|
407
503
|
issue.detail ? h("div", { className: "mkt_issueDetail" }, issue.detail) : null);
|
|
408
504
|
})
|
|
409
|
-
) : null
|
|
410
|
-
h("div", { className: "mkt_row" },
|
|
411
|
-
blocked
|
|
412
|
-
? h("button", { className: "mkt_btn mkt_btnSm", onClick: props.onClose }, "关闭")
|
|
413
|
-
: [
|
|
414
|
-
h("button", { key: "cancel", className: "mkt_btn mkt_btnSm", onClick: props.onClose }, "取消"),
|
|
415
|
-
h("button", {
|
|
416
|
-
key: "confirm",
|
|
417
|
-
className: "mkt_btn mkt_btnPrimary mkt_btnSm",
|
|
418
|
-
disabled: props.busy === true,
|
|
419
|
-
onClick: props.onConfirm,
|
|
420
|
-
}, props.busy ? "安装中…" : "我已了解风险,继续安装"),
|
|
421
|
-
]
|
|
422
|
-
)
|
|
423
|
-
);
|
|
505
|
+
) : null);
|
|
424
506
|
}
|
|
425
507
|
|
|
426
508
|
var MARKET_PACKAGE = "@1e0zj/dsh-plugin-mall";
|
|
@@ -435,64 +517,99 @@ window.__ModuleLoader__.load({
|
|
|
435
517
|
if (status === "completed") return "完成";
|
|
436
518
|
if (status === "failed") return "失败";
|
|
437
519
|
if (status === "killed") return "已取消";
|
|
520
|
+
if (status === "stopping") return "停止中";
|
|
438
521
|
return "进行中";
|
|
439
522
|
}
|
|
440
523
|
|
|
441
524
|
function jobStatusClass(status) {
|
|
442
525
|
if (status === "completed") return "mkt_ok";
|
|
443
|
-
if (status === "failed"
|
|
526
|
+
if (status === "failed") return "mkt_error";
|
|
527
|
+
if (status === "killed" || status === "stopping") return "mkt_warn";
|
|
444
528
|
return "";
|
|
445
529
|
}
|
|
446
530
|
|
|
531
|
+
function jobStateDotClass(status, awaitingDecision) {
|
|
532
|
+
if (awaitingDecision || status === "killed" || status === "stopping") return "mkt_stateWarn";
|
|
533
|
+
if (status === "completed") return "mkt_stateDone";
|
|
534
|
+
if (status === "failed") return "mkt_stateError";
|
|
535
|
+
return "mkt_stateRunning";
|
|
536
|
+
}
|
|
537
|
+
|
|
447
538
|
// 任务日志:跑的时候只露尾部几行(够看进度,不霸屏),落定后默认折叠
|
|
448
539
|
// ——成功的日志没人回头读,失败的才需要,点开即可。
|
|
449
|
-
var LOG_TAIL_LINES =
|
|
540
|
+
var LOG_TAIL_LINES = 12;
|
|
450
541
|
function JobLog(props) {
|
|
451
542
|
var _open = useState(false);
|
|
452
543
|
var open = _open[0];
|
|
453
544
|
var setOpen = _open[1];
|
|
454
545
|
var text = String(props.output || "").trimEnd();
|
|
546
|
+
var failed = props.status === "failed";
|
|
547
|
+
useEffect(function () {
|
|
548
|
+
if (failed) setOpen(true);
|
|
549
|
+
}, [failed]);
|
|
455
550
|
if (text.length === 0) return null;
|
|
456
551
|
var lines = text.split("\n");
|
|
457
|
-
var
|
|
458
|
-
var
|
|
552
|
+
var settled = !isJobActive(props.status);
|
|
553
|
+
var collapsed = settled && !open;
|
|
554
|
+
var shown = settled || lines.length <= LOG_TAIL_LINES ? lines : lines.slice(-LOG_TAIL_LINES);
|
|
555
|
+
var rendered = shown.join("\n");
|
|
556
|
+
if (rendered.length > 64000) rendered = "…前部日志已截断…\n" + rendered.slice(-64000);
|
|
459
557
|
// 展开/收起始终在日志块上方:放在下方的话,点开后按钮会被推到长长的
|
|
460
558
|
// 日志末尾,想收起还得先滚回去。
|
|
461
559
|
return h("div", { className: "mkt_logBlock" },
|
|
462
|
-
|
|
463
|
-
? h("
|
|
464
|
-
|
|
560
|
+
settled
|
|
561
|
+
? h("button", {
|
|
562
|
+
type: "button",
|
|
563
|
+
className: "mkt_linkButton",
|
|
564
|
+
"aria-expanded": open ? "true" : "false",
|
|
465
565
|
onClick: function () { setOpen(!open); },
|
|
466
566
|
}, open ? "收起日志" : "查看日志(" + lines.length + " 行)")
|
|
467
567
|
: lines.length > LOG_TAIL_LINES
|
|
468
568
|
? h("div", { className: "mkt_meta" }, "只显示最后 " + LOG_TAIL_LINES + " 行")
|
|
469
569
|
: null,
|
|
470
|
-
collapsed ? null : h("pre", { className: "mkt_pre" },
|
|
570
|
+
collapsed ? null : h("pre", { className: "mkt_pre", "aria-label": "任务日志" }, rendered)
|
|
471
571
|
);
|
|
472
572
|
}
|
|
473
573
|
|
|
474
574
|
// ── jobs panel ──────────────────────────────────────────────────────────
|
|
475
575
|
function JobsPanel(props) {
|
|
476
576
|
var ids = Object.keys(props.jobs);
|
|
477
|
-
if (ids.length === 0) return null;
|
|
577
|
+
if (ids.length === 0 && !props.error) return null;
|
|
578
|
+
var hasSettled = ids.some(function (id) {
|
|
579
|
+
var job = props.jobs[id];
|
|
580
|
+
var hasDecision = (props.preflight && props.preflight.jobId === id)
|
|
581
|
+
|| (job.needsApproval && job.needsApproval.length > 0);
|
|
582
|
+
return !isJobActive(job.status) && !hasDecision;
|
|
583
|
+
});
|
|
478
584
|
return h("div", { className: "mkt_card" },
|
|
479
585
|
h("div", { className: "mkt_panelRow" },
|
|
480
586
|
h("p", { className: "mkt_panelTitle" }, "任务"),
|
|
481
|
-
props.onClear ? h("span", { className: "mkt_link", onClick: props.onClear }, "
|
|
587
|
+
props.onClear && hasSettled ? h("span", { className: "mkt_link", onClick: props.onClear }, "清空已结束") : null
|
|
482
588
|
),
|
|
589
|
+
h(ErrorNotice, { message: props.error }),
|
|
483
590
|
ids.map(function (id) {
|
|
484
591
|
var job = props.jobs[id];
|
|
485
592
|
var done = job.status === "completed" || job.status === "failed" || job.status === "killed";
|
|
486
|
-
|
|
593
|
+
var preflightDecision = props.preflight && props.preflight.jobId === id ? props.preflight : null;
|
|
594
|
+
var awaitingDecision = preflightDecision !== null || (job.needsApproval && job.needsApproval.length > 0);
|
|
595
|
+
return h("div", { key: id, className: "mkt_job" },
|
|
487
596
|
// 不再显示 market-N 这种内部 id——对用户没有意义,反而让人以为
|
|
488
597
|
// 自己点了两次。只说清「在做什么 · 到哪一步了」。
|
|
489
|
-
//
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
598
|
+
// 状态词和状态点表达结论,任务类型与目标保持次要色。
|
|
599
|
+
h("div", { className: "mkt_jobHead" },
|
|
600
|
+
h("div", { className: "mkt_jobIdentity" },
|
|
601
|
+
h("span", { className: "mkt_stateDot " + jobStateDotClass(job.status, awaitingDecision), "aria-hidden": "true" }),
|
|
602
|
+
h("span", null, jobKindLabel(job.kind) + clip(job.spec || "", 44) + " · "),
|
|
603
|
+
h("span", { className: awaitingDecision ? "mkt_warn" : jobStatusClass(job.status) }, awaitingDecision ? "待确认" : jobStatusLabel(job.status))),
|
|
604
|
+
isJobActive(job.status) ? h("button", {
|
|
605
|
+
className: "mkt_btn mkt_btnSm",
|
|
606
|
+
disabled: job.status === "stopping",
|
|
607
|
+
onClick: function () { props.onCancel(id); },
|
|
608
|
+
}, job.status === "stopping" ? "停止中…" : "停止") : null),
|
|
494
609
|
job.needsApproval && job.needsApproval.length > 0
|
|
495
610
|
? h(ApprovalRequest, {
|
|
611
|
+
spec: job.spec,
|
|
612
|
+
detail: job.detail,
|
|
496
613
|
needsApproval: job.needsApproval,
|
|
497
614
|
busy: props.approving === job.spec,
|
|
498
615
|
onApprove: function (names) {
|
|
@@ -505,7 +622,15 @@ window.__ModuleLoader__.load({
|
|
|
505
622
|
},
|
|
506
623
|
onDismiss: function () { props.onDismiss(id); },
|
|
507
624
|
})
|
|
508
|
-
:
|
|
625
|
+
: preflightDecision
|
|
626
|
+
? h(PreflightCard, {
|
|
627
|
+
spec: preflightDecision.spec,
|
|
628
|
+
report: preflightDecision.report,
|
|
629
|
+
busy: props.preflightBusy === true,
|
|
630
|
+
onConfirm: props.onConfirmPreflight,
|
|
631
|
+
onClose: props.onClosePreflight,
|
|
632
|
+
})
|
|
633
|
+
: job.detail ? h("div", { className: job.status === "failed" ? "mkt_error" : "mkt_desc" }, job.detail) : null,
|
|
509
634
|
// 预检完成不提示重启——它没有改动任何东西,接下来才是安装。
|
|
510
635
|
// 也不再重复一个绿色「完成」:状态行已经写了「· 完成」。
|
|
511
636
|
done && job.status === "completed" && job.kind !== "dsh-plugin-preflight"
|
|
@@ -520,10 +645,8 @@ window.__ModuleLoader__.load({
|
|
|
520
645
|
disabled: props.restarting === true,
|
|
521
646
|
onClick: props.onRestart,
|
|
522
647
|
}, props.restarting ? "重启中…" : "重启 dsh 生效"))
|
|
523
|
-
:
|
|
524
|
-
|
|
525
|
-
: null,
|
|
526
|
-
h(JobLog, { output: job.output, done: done })
|
|
648
|
+
: null,
|
|
649
|
+
h(JobLog, { output: job.output, status: job.status })
|
|
527
650
|
);
|
|
528
651
|
})
|
|
529
652
|
);
|
|
@@ -548,6 +671,7 @@ window.__ModuleLoader__.load({
|
|
|
548
671
|
h("span", { className: "mkt_badge" }, count + " 个"),
|
|
549
672
|
h("span", { className: "mkt_meta mkt_installedToggle" }, open ? "收起" : "展开")
|
|
550
673
|
),
|
|
674
|
+
h(ErrorNotice, { message: props.error }),
|
|
551
675
|
installed.error
|
|
552
676
|
? h("div", { className: "mkt_error" }, installed.error)
|
|
553
677
|
: !open ? null
|
|
@@ -604,6 +728,9 @@ window.__ModuleLoader__.load({
|
|
|
604
728
|
var _error = useState(null);
|
|
605
729
|
var error = _error[0];
|
|
606
730
|
var setError = _error[1];
|
|
731
|
+
var reportError = useCallback(function (scope, value) {
|
|
732
|
+
setError({ scope: scope, message: errorText(value) });
|
|
733
|
+
}, []);
|
|
607
734
|
var _installed = useState(null);
|
|
608
735
|
var installed = _installed[0];
|
|
609
736
|
var setInstalled = _installed[1];
|
|
@@ -645,6 +772,12 @@ window.__ModuleLoader__.load({
|
|
|
645
772
|
var _restarting = useState(false);
|
|
646
773
|
var restarting = _restarting[0];
|
|
647
774
|
var setRestarting = _restarting[1];
|
|
775
|
+
var _restartNote = useState(null);
|
|
776
|
+
var restartNote = _restartNote[0];
|
|
777
|
+
var setRestartNote = _restartNote[1];
|
|
778
|
+
var _restartConfirm = useState(false);
|
|
779
|
+
var restartConfirm = _restartConfirm[0];
|
|
780
|
+
var setRestartConfirm = _restartConfirm[1];
|
|
648
781
|
// 本次宿主进程的启动时间(jobs 端点带回):完成时间早于它的任务,
|
|
649
782
|
// 其「重启 dsh 生效」按钮已经兑现,改显示「重启已生效」。
|
|
650
783
|
var _hostStartedAt = useState(0);
|
|
@@ -714,11 +847,11 @@ window.__ModuleLoader__.load({
|
|
|
714
847
|
setCompat({});
|
|
715
848
|
verifyPage(value.items);
|
|
716
849
|
}).catch(function (e) {
|
|
717
|
-
|
|
850
|
+
reportError("search", e);
|
|
718
851
|
}).finally(function () {
|
|
719
852
|
setLoading(false);
|
|
720
853
|
});
|
|
721
|
-
}, [call, query, sort, verifyPage]);
|
|
854
|
+
}, [call, query, reportError, sort, verifyPage]);
|
|
722
855
|
|
|
723
856
|
var canLoadMore = results !== null && results.items.length < results.total && !reachedLimit;
|
|
724
857
|
var loadMoreLock = useRef(false);
|
|
@@ -744,13 +877,13 @@ window.__ModuleLoader__.load({
|
|
|
744
877
|
return { total: value.total, items: merged };
|
|
745
878
|
});
|
|
746
879
|
}).catch(function (e) {
|
|
747
|
-
|
|
880
|
+
reportError("search", e);
|
|
748
881
|
setRetryAt(Date.now() + 60000);
|
|
749
882
|
}).finally(function () {
|
|
750
883
|
loadMoreLock.current = false;
|
|
751
884
|
setLoadingMore(false);
|
|
752
885
|
});
|
|
753
|
-
}, [call, canLoadMore, loading, loadingMore, page, query, sort, retryAt, verifyPage]);
|
|
886
|
+
}, [call, canLoadMore, loading, loadingMore, page, query, reportError, sort, retryAt, verifyPage]);
|
|
754
887
|
|
|
755
888
|
useEffect(function () {
|
|
756
889
|
var node = sentinelRef.current;
|
|
@@ -775,7 +908,7 @@ window.__ModuleLoader__.load({
|
|
|
775
908
|
return prev && !prev.error ? Object.assign({}, prev, { entries: value.entries }) : prev;
|
|
776
909
|
});
|
|
777
910
|
}).catch(function (e) {
|
|
778
|
-
|
|
911
|
+
reportError("installed", e);
|
|
779
912
|
}).finally(function () {
|
|
780
913
|
setToggling(function (prev) {
|
|
781
914
|
var next = Object.assign({}, prev);
|
|
@@ -783,7 +916,7 @@ window.__ModuleLoader__.load({
|
|
|
783
916
|
return next;
|
|
784
917
|
});
|
|
785
918
|
});
|
|
786
|
-
}, [call]);
|
|
919
|
+
}, [call, reportError]);
|
|
787
920
|
|
|
788
921
|
var refreshInstalled = useCallback(function () {
|
|
789
922
|
call("installed", {}).then(function (value) {
|
|
@@ -821,8 +954,8 @@ window.__ModuleLoader__.load({
|
|
|
821
954
|
var polling = useJobPolling(call, onJobSettled, onApprovalToken, onPreflightSettled);
|
|
822
955
|
var track = polling.track;
|
|
823
956
|
var jobs = polling.jobs;
|
|
824
|
-
var clearJobs = polling.clear;
|
|
825
957
|
var dropJob = polling.drop;
|
|
958
|
+
var setJobStatus = polling.setStatus;
|
|
826
959
|
|
|
827
960
|
useEffect(function () {
|
|
828
961
|
doSearch();
|
|
@@ -848,7 +981,7 @@ window.__ModuleLoader__.load({
|
|
|
848
981
|
track(value.jobId, spec, carryFromId);
|
|
849
982
|
}).catch(function (e) {
|
|
850
983
|
delete approvalTokensRef.current[spec];
|
|
851
|
-
|
|
984
|
+
reportError("tasks", e);
|
|
852
985
|
}).finally(function () {
|
|
853
986
|
setInstalling(function (prev) {
|
|
854
987
|
var next = Object.assign({}, prev);
|
|
@@ -856,7 +989,7 @@ window.__ModuleLoader__.load({
|
|
|
856
989
|
return next;
|
|
857
990
|
});
|
|
858
991
|
});
|
|
859
|
-
}, [call, track]);
|
|
992
|
+
}, [call, reportError, track]);
|
|
860
993
|
|
|
861
994
|
var doApprove = useCallback(function (spec, names, token, carryFromId) {
|
|
862
995
|
var extra = { allowBuildScripts: names };
|
|
@@ -872,7 +1005,7 @@ window.__ModuleLoader__.load({
|
|
|
872
1005
|
useEffect(function () {
|
|
873
1006
|
preflightHandlerRef.current = function (spec, report, jobId) {
|
|
874
1007
|
if (!report || !report.verdict) {
|
|
875
|
-
|
|
1008
|
+
reportError("tasks", "预检没有返回结论,请重试");
|
|
876
1009
|
return;
|
|
877
1010
|
}
|
|
878
1011
|
if (report.verdict === "safe") {
|
|
@@ -882,7 +1015,7 @@ window.__ModuleLoader__.load({
|
|
|
882
1015
|
setPreflight({ spec: spec, report: report, jobId: jobId });
|
|
883
1016
|
}
|
|
884
1017
|
};
|
|
885
|
-
}, [doRawInstall]);
|
|
1018
|
+
}, [doRawInstall, reportError]);
|
|
886
1019
|
|
|
887
1020
|
// 点安装 = 立刻起一个预检 job,面板马上有东西看、日志实时流。
|
|
888
1021
|
// 结论由轮询经 onPreflightSettled 交回上面的 handler,这里不等待。
|
|
@@ -892,25 +1025,30 @@ window.__ModuleLoader__.load({
|
|
|
892
1025
|
call("preflight", { spec: spec }).then(function (value) {
|
|
893
1026
|
track(value.jobId, value.spec || spec);
|
|
894
1027
|
}).catch(function (e) {
|
|
895
|
-
|
|
1028
|
+
reportError("tasks", e);
|
|
896
1029
|
});
|
|
897
|
-
}, [call, track]);
|
|
1030
|
+
}, [call, reportError, track]);
|
|
898
1031
|
|
|
899
1032
|
var doInstall = useCallback(function (repo) {
|
|
900
1033
|
preflightAndInstall("github:" + repo);
|
|
901
1034
|
}, [preflightAndInstall]);
|
|
902
1035
|
|
|
903
1036
|
var doRestart = useCallback(function () {
|
|
904
|
-
if (typeof window !== "undefined" && typeof window.confirm === "function") {
|
|
905
|
-
if (window.confirm("重启 dsh?正在进行的任务会中断。") !== true) return;
|
|
906
|
-
}
|
|
907
1037
|
clearRestartPing();
|
|
908
1038
|
setRestarting(true);
|
|
909
1039
|
setError(null);
|
|
1040
|
+
setRestartNote(null);
|
|
910
1041
|
var requestedAt = Date.now();
|
|
911
1042
|
var previousHostStartedAt = Number(hostStartedAt);
|
|
912
|
-
|
|
1043
|
+
var scheduledLogPath = null;
|
|
1044
|
+
call("restart", {}).then(function (value) {
|
|
913
1045
|
if (restartControlRef.current.mounted !== true) return;
|
|
1046
|
+
// 响应语义是「已调度交接」而不是「重启成功」:新宿主何时接管
|
|
1047
|
+
// 由下面的轮询判断。这里只把输出会出现在哪里告诉用户。
|
|
1048
|
+
scheduledLogPath = value && value.logPath ? String(value.logPath) : null;
|
|
1049
|
+
setRestartNote(value && value.mode === "visible"
|
|
1050
|
+
? "重启已调度——dsh 正在新的控制台窗口中启动,窗口里 Ctrl+C 可停止;输出同时写入 " + scheduledLogPath
|
|
1051
|
+
: "重启已调度,输出与日志:" + (scheduledLogPath || "<home>/guard/ 下"));
|
|
914
1052
|
var tries = 0;
|
|
915
1053
|
var ping = setInterval(function () {
|
|
916
1054
|
if (restartControlRef.current.mounted !== true) {
|
|
@@ -921,7 +1059,8 @@ window.__ModuleLoader__.load({
|
|
|
921
1059
|
if (tries > 40) {
|
|
922
1060
|
clearRestartPing();
|
|
923
1061
|
setRestarting(false);
|
|
924
|
-
|
|
1062
|
+
reportError("restart", "2 分钟内未检测到 dsh 重启完成,请手动检查 dsh 状态后刷新页面。"
|
|
1063
|
+
+ (scheduledLogPath ? "输出与日志:" + scheduledLogPath : ""));
|
|
925
1064
|
return;
|
|
926
1065
|
}
|
|
927
1066
|
// Prefer identity change over wall-clock ordering: NTP may move the
|
|
@@ -944,9 +1083,10 @@ window.__ModuleLoader__.load({
|
|
|
944
1083
|
if (restartControlRef.current.mounted !== true) return;
|
|
945
1084
|
clearRestartPing();
|
|
946
1085
|
setRestarting(false);
|
|
947
|
-
|
|
1086
|
+
setRestartNote(null);
|
|
1087
|
+
reportError("restart", e);
|
|
948
1088
|
});
|
|
949
|
-
}, [call, clearRestartPing, hostStartedAt]);
|
|
1089
|
+
}, [call, clearRestartPing, hostStartedAt, reportError]);
|
|
950
1090
|
|
|
951
1091
|
var doUninstall = useCallback(function (name) {
|
|
952
1092
|
delete approvalTokensRef.current[name];
|
|
@@ -958,7 +1098,7 @@ window.__ModuleLoader__.load({
|
|
|
958
1098
|
call("uninstall", { package: name }).then(function (value) {
|
|
959
1099
|
track(value.jobId, name);
|
|
960
1100
|
}).catch(function (e) {
|
|
961
|
-
|
|
1101
|
+
reportError("installed", e);
|
|
962
1102
|
}).finally(function () {
|
|
963
1103
|
setRemoving(function (prev) {
|
|
964
1104
|
var next = Object.assign({}, prev);
|
|
@@ -966,7 +1106,7 @@ window.__ModuleLoader__.load({
|
|
|
966
1106
|
return next;
|
|
967
1107
|
});
|
|
968
1108
|
});
|
|
969
|
-
}, [call, track]);
|
|
1109
|
+
}, [call, reportError, track]);
|
|
970
1110
|
|
|
971
1111
|
useEffect(function () {
|
|
972
1112
|
refreshInstalled();
|
|
@@ -978,6 +1118,9 @@ window.__ModuleLoader__.load({
|
|
|
978
1118
|
return v !== undefined && (v.kind === "bundle" || v.kind === "client")
|
|
979
1119
|
&& !(v.hostDeps !== undefined && v.hostDeps.length > 0);
|
|
980
1120
|
});
|
|
1121
|
+
var activeJobCount = Object.keys(jobs).filter(function (id) {
|
|
1122
|
+
return jobs[id] && isJobActive(jobs[id].status);
|
|
1123
|
+
}).length;
|
|
981
1124
|
resultsRef.current = results;
|
|
982
1125
|
var verifyPending = results !== null && results.items.some(function (it) { return verified[it.fullName] === undefined; });
|
|
983
1126
|
|
|
@@ -1000,12 +1143,13 @@ window.__ModuleLoader__.load({
|
|
|
1000
1143
|
h("option", { value: "forks" }, "按 fork")
|
|
1001
1144
|
),
|
|
1002
1145
|
h("button", { className: "mkt_btn mkt_btnPrimary", disabled: loading, onClick: doSearch }, loading ? "搜索中…" : "搜索"),
|
|
1003
|
-
h("button", { className: "mkt_btn mkt_btnDanger", disabled: restarting, onClick:
|
|
1146
|
+
h("button", { className: "mkt_btn mkt_btnDanger", disabled: restarting, onClick: function () { setRestartConfirm(true); } }, restarting ? "重启中…" : "重启 dsh"),
|
|
1004
1147
|
h("label", { className: "mkt_check" },
|
|
1005
1148
|
h("input", { type: "checkbox", checked: verifiedOnly, onChange: function (e) { setVerifiedOnly(e.target.checked); } }),
|
|
1006
1149
|
"只看已验证插件")
|
|
1007
1150
|
),
|
|
1008
|
-
|
|
1151
|
+
h(ErrorNotice, { message: error && (error.scope === "search" || error.scope === "restart") ? error.message : null }),
|
|
1152
|
+
restarting ? h(StatusNotice, { message: restartNote }) : null,
|
|
1009
1153
|
h(InstalledPanel, {
|
|
1010
1154
|
installed: installed,
|
|
1011
1155
|
removing: removing,
|
|
@@ -1015,19 +1159,50 @@ window.__ModuleLoader__.load({
|
|
|
1015
1159
|
onToggle: doToggle,
|
|
1016
1160
|
onUninstall: doUninstall,
|
|
1017
1161
|
onInstallSpec: preflightAndInstall,
|
|
1162
|
+
error: error && error.scope === "installed" ? error.message : null,
|
|
1018
1163
|
}),
|
|
1019
1164
|
h(JobsPanel, {
|
|
1020
1165
|
jobs: jobs,
|
|
1166
|
+
error: error && error.scope === "tasks" ? error.message : null,
|
|
1167
|
+
preflight: preflight,
|
|
1168
|
+
preflightBusy: preflight ? installing[preflight.spec] === true : false,
|
|
1021
1169
|
onClear: function () {
|
|
1022
1170
|
Object.keys(jobs).forEach(function (id) {
|
|
1023
1171
|
var job = jobs[id];
|
|
1172
|
+
var hasDecision = job && ((preflight && preflight.jobId === id)
|
|
1173
|
+
|| (job.needsApproval && job.needsApproval.length > 0));
|
|
1174
|
+
if (!job || isJobActive(job.status) || hasDecision) return;
|
|
1024
1175
|
var token = job && job.approvalToken ? job.approvalToken : (job && job.spec ? approvalTokensRef.current[job.spec] : undefined);
|
|
1025
1176
|
call("jobDismiss", { jobId: id, token: token }).catch(function () {});
|
|
1177
|
+
if (job.spec) delete approvalTokensRef.current[job.spec];
|
|
1178
|
+
dropJob(id);
|
|
1179
|
+
});
|
|
1180
|
+
},
|
|
1181
|
+
onCancel: function (id) {
|
|
1182
|
+
var job = jobs[id];
|
|
1183
|
+
if (!job || job.status !== "running") return;
|
|
1184
|
+
setJobStatus(id, "stopping");
|
|
1185
|
+
call("jobCancel", { jobId: id }).catch(function (e) {
|
|
1186
|
+
setJobStatus(id, "running");
|
|
1187
|
+
reportError("tasks", e);
|
|
1026
1188
|
});
|
|
1027
|
-
approvalTokensRef.current = {};
|
|
1028
|
-
clearJobs();
|
|
1029
1189
|
},
|
|
1030
1190
|
onApprove: doApprove,
|
|
1191
|
+
onConfirmPreflight: function () {
|
|
1192
|
+
if (!preflight) return;
|
|
1193
|
+
var spec = preflight.spec;
|
|
1194
|
+
var carry = preflight.jobId;
|
|
1195
|
+
var report = preflight.report;
|
|
1196
|
+
setPreflight(null);
|
|
1197
|
+
// consentDigest 来自预检 job 的 extras,装的时候与当前报告比对:
|
|
1198
|
+
// 用户点「继续」到安装真正开跑之间候选包或 profile 变了,
|
|
1199
|
+
// 布尔同意不得沿用,要重新看新的警告。
|
|
1200
|
+
doRawInstall(spec, { acceptWarnings: true, acceptedReportDigest: report.consentDigest }, carry);
|
|
1201
|
+
},
|
|
1202
|
+
onClosePreflight: function () {
|
|
1203
|
+
if (preflight && preflight.spec) delete approvalTokensRef.current[preflight.spec];
|
|
1204
|
+
setPreflight(null);
|
|
1205
|
+
},
|
|
1031
1206
|
onDismiss: function (id) {
|
|
1032
1207
|
var job = jobs[id];
|
|
1033
1208
|
var token = job && job.approvalToken ? job.approvalToken : (job && job.spec ? approvalTokensRef.current[job.spec] : undefined);
|
|
@@ -1036,29 +1211,11 @@ window.__ModuleLoader__.load({
|
|
|
1036
1211
|
dropJob(id);
|
|
1037
1212
|
},
|
|
1038
1213
|
onDrop: dropJob,
|
|
1039
|
-
onRestart:
|
|
1214
|
+
onRestart: function () { setRestartConfirm(true); },
|
|
1040
1215
|
restarting: restarting,
|
|
1041
1216
|
hostStartedAt: hostStartedAt,
|
|
1042
1217
|
approving: Object.keys(installing).filter(function (s) { return installing[s]; })[0],
|
|
1043
1218
|
}),
|
|
1044
|
-
preflight ? h(PreflightCard, {
|
|
1045
|
-
spec: preflight.spec,
|
|
1046
|
-
report: preflight.report,
|
|
1047
|
-
busy: installing[preflight.spec] === true,
|
|
1048
|
-
onConfirm: function () {
|
|
1049
|
-
var spec = preflight.spec;
|
|
1050
|
-
var carry = preflight.jobId;
|
|
1051
|
-
setPreflight(null);
|
|
1052
|
-
// consentDigest 来自预检 job 的 extras,装的时候与当前报告比对:
|
|
1053
|
-
// 用户点「继续」到安装真正开跑之间候选包或 profile 变了,
|
|
1054
|
-
// 布尔同意不得沿用,要重新看新的警告。
|
|
1055
|
-
doRawInstall(spec, { acceptWarnings: true, acceptedReportDigest: preflight.report.consentDigest }, carry);
|
|
1056
|
-
},
|
|
1057
|
-
onClose: function () {
|
|
1058
|
-
if (preflight && preflight.spec) delete approvalTokensRef.current[preflight.spec];
|
|
1059
|
-
setPreflight(null);
|
|
1060
|
-
},
|
|
1061
|
-
}) : null,
|
|
1062
1219
|
h("div", { className: "mkt_list" },
|
|
1063
1220
|
results == null
|
|
1064
1221
|
? h("div", { className: "mkt_meta mkt_listHead" }, loading ? "正在加载最热插件…" : "—")
|
|
@@ -1095,7 +1252,16 @@ window.__ModuleLoader__.load({
|
|
|
1095
1252
|
? h("div", { className: "mkt_loadMore", ref: sentinelRef }, loadingMore ? "加载中…" : Date.now() < retryAt ? "GitHub 限流中,稍后再下滑加载" : "下滑加载更多")
|
|
1096
1253
|
: h("div", { className: "mkt_loadMore" }, reachedLimit ? "已达 GitHub 搜索上限(前 1000 个结果)" : "已显示全部 " + results.items.length + " 个")
|
|
1097
1254
|
)
|
|
1098
|
-
)
|
|
1255
|
+
),
|
|
1256
|
+
restartConfirm ? h(RestartDialog, {
|
|
1257
|
+
activeCount: activeJobCount,
|
|
1258
|
+
busy: restarting,
|
|
1259
|
+
onCancel: function () { setRestartConfirm(false); },
|
|
1260
|
+
onConfirm: function () {
|
|
1261
|
+
setRestartConfirm(false);
|
|
1262
|
+
doRestart();
|
|
1263
|
+
},
|
|
1264
|
+
}) : null
|
|
1099
1265
|
);
|
|
1100
1266
|
}
|
|
1101
1267
|
|