@1e0zj/dsh-plugin-mall 0.4.5 → 0.4.7
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/package.json +1 -1
- package/src/client.js +255 -119
- package/src/guard.js +491 -1
- package/src/index.js +42 -3
- package/src/installer.js +101 -1
package/src/client.js
CHANGED
|
@@ -16,9 +16,6 @@ window.__ModuleLoader__.load({
|
|
|
16
16
|
// ── styles ──────────────────────────────────────────────────────────────
|
|
17
17
|
var css = [
|
|
18
18
|
".mkt_root{display:flex;flex-direction:column;gap:12px;max-width:1040px}",
|
|
19
|
-
".mkt_head{display:flex;flex-direction:column;gap:2px}",
|
|
20
|
-
".mkt_title{font-size:16px;font-weight:600;color:var(--dsw-alias-label-primary)}",
|
|
21
|
-
".mkt_sub{font-size:12px;color:var(--dsw-alias-label-tertiary)}",
|
|
22
19
|
".mkt_row{display:flex;gap:8px;align-items:center;flex-wrap:wrap}",
|
|
23
20
|
".mkt_input{flex:1;min-width:200px;background:var(--dsw-specific-input-major);border:1px solid var(--dsw-alias-border-l2);border-radius:6px;padding:6px 10px;font-size:13px;color:var(--dsw-alias-label-primary)}",
|
|
24
21
|
".mkt_input::placeholder{color:var(--dsw-alias-label-caption)}",
|
|
@@ -31,6 +28,7 @@ window.__ModuleLoader__.load({
|
|
|
31
28
|
".mkt_btnDanger:hover:not(:disabled){border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary)}",
|
|
32
29
|
".mkt_btnSm{padding:3px 10px;font-size:12px}",
|
|
33
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}",
|
|
34
32
|
".mkt_list{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;align-items:stretch;min-width:0}",
|
|
35
33
|
"@media (max-width:820px){.mkt_list{grid-template-columns:minmax(0,1fr)}}",
|
|
36
34
|
".mkt_listHead{grid-column:1/-1;font-size:12px;color:var(--dsw-alias-label-tertiary)}",
|
|
@@ -46,8 +44,9 @@ window.__ModuleLoader__.load({
|
|
|
46
44
|
".mkt_panelTitle{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary);margin:0}",
|
|
47
45
|
".mkt_panelRow{display:flex;align-items:center;gap:8px}",
|
|
48
46
|
".mkt_panelRow .mkt_link{margin-left:auto}",
|
|
49
|
-
".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:
|
|
47
|
+
".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}",
|
|
50
48
|
".mkt_ok{color:var(--dsw-alias-state-success-primary)}",
|
|
49
|
+
".mkt_warn{color:var(--dsw-alias-state-warn-label)}",
|
|
51
50
|
".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)}",
|
|
52
51
|
".mkt_badgeOk{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary)}",
|
|
53
52
|
".mkt_badgeWarn{border-color:var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-label)}",
|
|
@@ -60,13 +59,31 @@ window.__ModuleLoader__.load({
|
|
|
60
59
|
".mkt_depList{display:flex;flex-direction:column;gap:6px;margin-top:8px}",
|
|
61
60
|
".mkt_depRow{display:flex;justify-content:space-between;align-items:center;gap:8px}",
|
|
62
61
|
".mkt_depActions{display:flex;align-items:center;gap:6px;flex-wrap:wrap}",
|
|
63
|
-
".
|
|
64
|
-
".
|
|
62
|
+
".mkt_decision{display:flex;flex-direction:column;border:1px solid var(--dsw-alias-state-warn-secondary);border-radius:6px;overflow:hidden;margin-top:4px}",
|
|
63
|
+
".mkt_decisionError{border-color:var(--dsw-alias-state-error-primary)}",
|
|
64
|
+
".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)}",
|
|
65
|
+
".mkt_decisionError .mkt_decisionHead{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-state-error-primary)}",
|
|
66
|
+
".mkt_decisionTitle{font-size:13px;font-weight:600}",
|
|
67
|
+
".mkt_decisionBody{display:flex;flex-direction:column;gap:8px;min-width:0;padding:10px;max-height:300px;overflow:auto}",
|
|
68
|
+
".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)}",
|
|
65
69
|
".mkt_approvePkg{display:flex;flex-direction:column;gap:4px}",
|
|
66
70
|
".mkt_approveName{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary);margin-right:8px;overflow-wrap:anywhere}",
|
|
67
71
|
".mkt_approveCmd{max-height:none;margin:0}",
|
|
68
72
|
".mkt_jobDone{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:2px}",
|
|
69
|
-
".mkt_logBlock{display:flex;flex-direction:column;gap:4px;align-items:
|
|
73
|
+
".mkt_logBlock{display:flex;flex-direction:column;gap:4px;align-items:stretch;min-width:0;max-width:100%}",
|
|
74
|
+
".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}",
|
|
75
|
+
".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)}",
|
|
76
|
+
".mkt_panelRow + .mkt_job{padding-top:0;border-top:0}",
|
|
77
|
+
".mkt_jobHead{display:flex;align-items:center;gap:8px;min-width:0}",
|
|
78
|
+
".mkt_jobIdentity{display:flex;align-items:center;gap:7px;min-width:0;font-size:12px;color:var(--dsw-alias-label-tertiary)}",
|
|
79
|
+
".mkt_jobHead .mkt_btn{margin-left:auto;flex:none}",
|
|
80
|
+
".mkt_stateDot{width:7px;height:7px;border-radius:50%;background:var(--dsw-alias-label-caption);flex:none}",
|
|
81
|
+
".mkt_stateRunning{background:var(--dsw-alias-state-business-primary);animation:mktPulse 1.6s ease-in-out infinite}",
|
|
82
|
+
".mkt_stateDone{background:var(--dsw-alias-state-success-primary)}",
|
|
83
|
+
".mkt_stateWarn{background:var(--dsw-alias-state-warn-primary)}",
|
|
84
|
+
".mkt_stateError{background:var(--dsw-alias-state-error-primary)}",
|
|
85
|
+
"@keyframes mktPulse{0%,100%{opacity:.45}50%{opacity:1}}",
|
|
86
|
+
"@media (prefers-reduced-motion:reduce){.mkt_stateRunning{animation:none}.mkt_switch,.mkt_switchKnob{transition:none}}",
|
|
70
87
|
".mkt_depOff{opacity:.5;text-decoration:line-through}",
|
|
71
88
|
".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}",
|
|
72
89
|
".mkt_switch:disabled{opacity:.55;cursor:default}",
|
|
@@ -74,11 +91,16 @@ window.__ModuleLoader__.load({
|
|
|
74
91
|
".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)}",
|
|
75
92
|
".mkt_switchOn .mkt_switchKnob{transform:translateX(16px)}",
|
|
76
93
|
".mkt_issueList{list-style:none;display:flex;flex-direction:column;gap:8px;margin:0;padding:0}",
|
|
77
|
-
".mkt_issue{border:1px solid var(--dsw-alias-border-l2);border-radius:
|
|
94
|
+
".mkt_issue{border:1px solid var(--dsw-alias-border-l2);border-radius:6px;padding:8px 10px;background:var(--dsw-alias-bg-layer-3)}",
|
|
78
95
|
".mkt_issueBlock{border-color:var(--dsw-alias-state-error-primary)}",
|
|
79
96
|
".mkt_issueWarn{border-color:var(--dsw-alias-state-warn-primary)}",
|
|
80
97
|
".mkt_issueTitle{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary)}",
|
|
81
98
|
".mkt_issueDetail{font-size:12px;color:var(--dsw-alias-label-secondary);margin-top:4px;line-height:18px;overflow-wrap:anywhere}",
|
|
99
|
+
".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)}",
|
|
100
|
+
".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)}",
|
|
101
|
+
".mkt_modalHead{padding:14px 16px 8px;font-size:15px;font-weight:600;color:var(--dsw-alias-label-primary)}",
|
|
102
|
+
".mkt_modalBody{padding:0 16px 14px;font-size:12.5px;line-height:19px;color:var(--dsw-alias-label-secondary);overflow:auto}",
|
|
103
|
+
".mkt_modalActions{display:flex;justify-content:flex-end;gap:8px;padding:10px 16px;border-top:1px solid var(--dsw-alias-border-l2)}",
|
|
82
104
|
].join("\n");
|
|
83
105
|
var tagId = "@1e0zj/dsh-plugin-mall/market-tab.css";
|
|
84
106
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
@@ -105,6 +127,10 @@ window.__ModuleLoader__.load({
|
|
|
105
127
|
return String(e && e.message ? e.message : e);
|
|
106
128
|
}
|
|
107
129
|
|
|
130
|
+
function isJobActive(status) {
|
|
131
|
+
return status === "running" || status === "stopping";
|
|
132
|
+
}
|
|
133
|
+
|
|
108
134
|
function kindLabel(kind) {
|
|
109
135
|
if (kind === "bundle") return "宿主插件层";
|
|
110
136
|
if (kind === "client") return "浏览器UI插件";
|
|
@@ -162,7 +188,7 @@ window.__ModuleLoader__.load({
|
|
|
162
188
|
var current = jobsRef.current;
|
|
163
189
|
var running = Object.keys(current).filter(function (id) {
|
|
164
190
|
var job = current[id];
|
|
165
|
-
return job && job.status
|
|
191
|
+
return job && isJobActive(job.status);
|
|
166
192
|
});
|
|
167
193
|
if (running.length === 0) return;
|
|
168
194
|
running.forEach(function (id) {
|
|
@@ -214,21 +240,23 @@ window.__ModuleLoader__.load({
|
|
|
214
240
|
delete next[carryFromId];
|
|
215
241
|
}
|
|
216
242
|
for (var key in next) {
|
|
217
|
-
if (key !== id && next[key] && next[key].spec === spec && next[key].status
|
|
243
|
+
if (key !== id && next[key] && next[key].spec === spec && !isJobActive(next[key].status)) {
|
|
218
244
|
delete next[key];
|
|
219
245
|
}
|
|
220
246
|
}
|
|
221
247
|
next[id] = { status: "running", spec: spec, output: carried };
|
|
222
248
|
commit(next);
|
|
223
249
|
}, [commit]);
|
|
224
|
-
var clear = useCallback(function () {
|
|
225
|
-
commit({});
|
|
226
|
-
}, [commit]);
|
|
227
250
|
var drop = useCallback(function (id) {
|
|
228
251
|
var next = Object.assign({}, jobsRef.current);
|
|
229
252
|
delete next[id];
|
|
230
253
|
commit(next);
|
|
231
254
|
}, [commit]);
|
|
255
|
+
var setStatus = useCallback(function (id, status) {
|
|
256
|
+
var current = jobsRef.current[id];
|
|
257
|
+
if (!current) return;
|
|
258
|
+
commit(Object.assign({}, jobsRef.current, { [id]: Object.assign({}, current, { status: status }) }));
|
|
259
|
+
}, [commit]);
|
|
232
260
|
// 恢复后端任务记录(tracker.list 的形状):安装事务改写
|
|
233
261
|
// cordis.patch.yml 会让 dsh 重放装配树、整个市场 UI 重挂载,React
|
|
234
262
|
// state 全丢——任务面板、完成提醒、重启按钮一起消失(真实事故:
|
|
@@ -272,7 +300,7 @@ window.__ModuleLoader__.load({
|
|
|
272
300
|
for (var key in next) {
|
|
273
301
|
if (serverIds[key]) continue;
|
|
274
302
|
var stale = next[key];
|
|
275
|
-
if (stale.status
|
|
303
|
+
if (isJobActive(stale.status)) {
|
|
276
304
|
next[key] = Object.assign({}, stale, {
|
|
277
305
|
status: "killed",
|
|
278
306
|
detail: "宿主进程已重启,该任务的记录随之丢失",
|
|
@@ -285,7 +313,7 @@ window.__ModuleLoader__.load({
|
|
|
285
313
|
}
|
|
286
314
|
commit(next);
|
|
287
315
|
}, [commit]);
|
|
288
|
-
return { jobs: jobs, track: track,
|
|
316
|
+
return { jobs: jobs, track: track, drop: drop, setStatus: setStatus, restore: restore };
|
|
289
317
|
}
|
|
290
318
|
|
|
291
319
|
// ── plugin verification badge ───────────────────────────────────────────
|
|
@@ -322,7 +350,10 @@ window.__ModuleLoader__.load({
|
|
|
322
350
|
var installLabel = props.alreadyInstalled === true ? "已装" : "安装";
|
|
323
351
|
var installDisabled = installing || props.alreadyInstalled === true;
|
|
324
352
|
if (!installing && job) {
|
|
325
|
-
if (job.status
|
|
353
|
+
if (isJobActive(job.status)) {
|
|
354
|
+
installLabel = job.status === "stopping" ? "停止中…" : "安装中…";
|
|
355
|
+
installDisabled = true;
|
|
356
|
+
}
|
|
326
357
|
else if (job.status === "completed") { installLabel = "已装 · 重启生效"; installDisabled = true; }
|
|
327
358
|
else if (job.status === "failed") { installLabel = "安装失败 · 见任务日志"; }
|
|
328
359
|
else { installLabel = "已取消 · 重试"; }
|
|
@@ -349,11 +380,62 @@ window.__ModuleLoader__.load({
|
|
|
349
380
|
);
|
|
350
381
|
}
|
|
351
382
|
|
|
383
|
+
function DecisionPanel(props) {
|
|
384
|
+
var tone = props.tone === "error" ? " mkt_decisionError" : "";
|
|
385
|
+
return h("div", { className: "mkt_decision" + tone },
|
|
386
|
+
h("div", { className: "mkt_decisionHead" },
|
|
387
|
+
h("span", { className: "mkt_decisionTitle" }, props.title),
|
|
388
|
+
props.meta ? h("span", { className: "mkt_meta" }, props.meta) : null),
|
|
389
|
+
h("div", { className: "mkt_decisionBody" }, props.children),
|
|
390
|
+
h("div", { className: "mkt_decisionActions" }, props.actions));
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function ErrorNotice(props) {
|
|
394
|
+
if (!props.message) return null;
|
|
395
|
+
return h("div", { className: "mkt_notice", role: "alert" }, props.message);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function RestartDialog(props) {
|
|
399
|
+
useEffect(function () {
|
|
400
|
+
function onKeyDown(event) {
|
|
401
|
+
if (event.key === "Escape" && props.busy !== true) props.onCancel();
|
|
402
|
+
}
|
|
403
|
+
document.addEventListener("keydown", onKeyDown);
|
|
404
|
+
return function () { document.removeEventListener("keydown", onKeyDown); };
|
|
405
|
+
}, [props.busy, props.onCancel]);
|
|
406
|
+
return h("div", {
|
|
407
|
+
className: "mkt_modalMask",
|
|
408
|
+
onMouseDown: function (event) {
|
|
409
|
+
if (event.target === event.currentTarget && props.busy !== true) props.onCancel();
|
|
410
|
+
},
|
|
411
|
+
}, h("div", { className: "mkt_modal", role: "dialog", "aria-modal": "true", "aria-labelledby": "mkt-restart-title" },
|
|
412
|
+
h("div", { id: "mkt-restart-title", className: "mkt_modalHead" }, "重启 dsh"),
|
|
413
|
+
h("div", { className: "mkt_modalBody" }, props.activeCount > 0
|
|
414
|
+
? "当前有 " + props.activeCount + " 个任务仍在进行。重启会中断这些任务,未完成的改动将由事务恢复逻辑处理。"
|
|
415
|
+
: "重启后,已经完成的插件安装、更新或卸载才会生效。"),
|
|
416
|
+
h("div", { className: "mkt_modalActions" },
|
|
417
|
+
h("button", { className: "mkt_btn", disabled: props.busy === true, autoFocus: true, onClick: props.onCancel }, "取消"),
|
|
418
|
+
h("button", { className: "mkt_btn mkt_btnPrimary", disabled: props.busy === true, onClick: props.onConfirm }, props.busy ? "重启中…" : "确认重启"))));
|
|
419
|
+
}
|
|
420
|
+
|
|
352
421
|
// ── install-script approval ─────────────────────────────────────────────
|
|
353
422
|
function ApprovalRequest(props) {
|
|
354
423
|
var pkgs = props.needsApproval || [];
|
|
355
|
-
|
|
356
|
-
h("
|
|
424
|
+
var actions = [
|
|
425
|
+
h("button", { key: "cancel", className: "mkt_btn mkt_btnSm", disabled: props.busy === true, onClick: props.onDismiss }, "取消"),
|
|
426
|
+
h("button", {
|
|
427
|
+
key: "allow",
|
|
428
|
+
className: "mkt_btn mkt_btnPrimary mkt_btnSm",
|
|
429
|
+
disabled: props.busy === true,
|
|
430
|
+
onClick: function () { props.onApprove(pkgs.map(function (p) { return p.name; })); },
|
|
431
|
+
}, props.busy ? "继续中…" : "允许并继续"),
|
|
432
|
+
];
|
|
433
|
+
return h(DecisionPanel, {
|
|
434
|
+
title: "安装期代码需要确认",
|
|
435
|
+
meta: clip(props.spec || "", 50),
|
|
436
|
+
actions: actions,
|
|
437
|
+
},
|
|
438
|
+
props.detail ? h("div", { className: "mkt_desc" }, props.detail) : null,
|
|
357
439
|
pkgs.map(function (p, index) {
|
|
358
440
|
var facts = [];
|
|
359
441
|
if (typeof p.weeklyDownloads === "number") facts.push("周下载 " + p.weeklyDownloads.toLocaleString());
|
|
@@ -373,16 +455,7 @@ window.__ModuleLoader__.load({
|
|
|
373
455
|
h("div", { className: "mkt_meta" }, facts.join(" · "))
|
|
374
456
|
);
|
|
375
457
|
}),
|
|
376
|
-
h("div", { className: "mkt_meta" }, "这些命令会以你的权限在你的机器上运行,早于任何插件代码加载。")
|
|
377
|
-
h("div", { className: "mkt_row" },
|
|
378
|
-
h("button", {
|
|
379
|
-
className: "mkt_btn mkt_btnPrimary mkt_btnSm",
|
|
380
|
-
disabled: props.busy === true,
|
|
381
|
-
onClick: function () { props.onApprove(pkgs.map(function (p) { return p.name; })); },
|
|
382
|
-
}, props.busy ? "继续中…" : "允许并继续"),
|
|
383
|
-
h("button", { className: "mkt_btn mkt_btnSm", onClick: props.onDismiss }, "取消")
|
|
384
|
-
)
|
|
385
|
-
);
|
|
458
|
+
h("div", { className: "mkt_meta" }, "这些命令会以你的权限在你的机器上运行,早于任何插件代码加载。"));
|
|
386
459
|
}
|
|
387
460
|
|
|
388
461
|
// ── preflight result card ────────────────────────────────────────────────
|
|
@@ -394,11 +467,23 @@ window.__ModuleLoader__.load({
|
|
|
394
467
|
var blocked = report.verdict === "blocked";
|
|
395
468
|
var title = blocked ? "安装被阻止" : "安装存在风险";
|
|
396
469
|
var issues = report.issues || [];
|
|
397
|
-
|
|
398
|
-
h("
|
|
399
|
-
|
|
400
|
-
h("
|
|
401
|
-
|
|
470
|
+
var actions = blocked
|
|
471
|
+
? h("button", { className: "mkt_btn mkt_btnSm", onClick: props.onClose }, "关闭")
|
|
472
|
+
: [
|
|
473
|
+
h("button", { key: "cancel", className: "mkt_btn mkt_btnSm", disabled: props.busy === true, onClick: props.onClose }, "取消"),
|
|
474
|
+
h("button", {
|
|
475
|
+
key: "confirm",
|
|
476
|
+
className: "mkt_btn mkt_btnPrimary mkt_btnSm",
|
|
477
|
+
disabled: props.busy === true,
|
|
478
|
+
onClick: props.onConfirm,
|
|
479
|
+
}, props.busy ? "安装中…" : "了解风险并继续"),
|
|
480
|
+
];
|
|
481
|
+
return h(DecisionPanel, {
|
|
482
|
+
tone: blocked ? "error" : "warning",
|
|
483
|
+
title: title,
|
|
484
|
+
meta: clip(props.spec, 50),
|
|
485
|
+
actions: actions,
|
|
486
|
+
},
|
|
402
487
|
report.summary ? h("div", { className: "mkt_desc" }, report.summary) : null,
|
|
403
488
|
issues.length > 0 ? h("ul", { className: "mkt_issueList" },
|
|
404
489
|
issues.map(function (issue) {
|
|
@@ -409,21 +494,7 @@ window.__ModuleLoader__.load({
|
|
|
409
494
|
h("div", { className: "mkt_issueTitle" }, issue.title),
|
|
410
495
|
issue.detail ? h("div", { className: "mkt_issueDetail" }, issue.detail) : null);
|
|
411
496
|
})
|
|
412
|
-
) : null
|
|
413
|
-
h("div", { className: "mkt_row" },
|
|
414
|
-
blocked
|
|
415
|
-
? h("button", { className: "mkt_btn mkt_btnSm", onClick: props.onClose }, "关闭")
|
|
416
|
-
: [
|
|
417
|
-
h("button", { key: "cancel", className: "mkt_btn mkt_btnSm", onClick: props.onClose }, "取消"),
|
|
418
|
-
h("button", {
|
|
419
|
-
key: "confirm",
|
|
420
|
-
className: "mkt_btn mkt_btnPrimary mkt_btnSm",
|
|
421
|
-
disabled: props.busy === true,
|
|
422
|
-
onClick: props.onConfirm,
|
|
423
|
-
}, props.busy ? "安装中…" : "我已了解风险,继续安装"),
|
|
424
|
-
]
|
|
425
|
-
)
|
|
426
|
-
);
|
|
497
|
+
) : null);
|
|
427
498
|
}
|
|
428
499
|
|
|
429
500
|
var MARKET_PACKAGE = "@1e0zj/dsh-plugin-mall";
|
|
@@ -438,64 +509,99 @@ window.__ModuleLoader__.load({
|
|
|
438
509
|
if (status === "completed") return "完成";
|
|
439
510
|
if (status === "failed") return "失败";
|
|
440
511
|
if (status === "killed") return "已取消";
|
|
512
|
+
if (status === "stopping") return "停止中";
|
|
441
513
|
return "进行中";
|
|
442
514
|
}
|
|
443
515
|
|
|
444
516
|
function jobStatusClass(status) {
|
|
445
517
|
if (status === "completed") return "mkt_ok";
|
|
446
|
-
if (status === "failed"
|
|
518
|
+
if (status === "failed") return "mkt_error";
|
|
519
|
+
if (status === "killed" || status === "stopping") return "mkt_warn";
|
|
447
520
|
return "";
|
|
448
521
|
}
|
|
449
522
|
|
|
523
|
+
function jobStateDotClass(status, awaitingDecision) {
|
|
524
|
+
if (awaitingDecision || status === "killed" || status === "stopping") return "mkt_stateWarn";
|
|
525
|
+
if (status === "completed") return "mkt_stateDone";
|
|
526
|
+
if (status === "failed") return "mkt_stateError";
|
|
527
|
+
return "mkt_stateRunning";
|
|
528
|
+
}
|
|
529
|
+
|
|
450
530
|
// 任务日志:跑的时候只露尾部几行(够看进度,不霸屏),落定后默认折叠
|
|
451
531
|
// ——成功的日志没人回头读,失败的才需要,点开即可。
|
|
452
|
-
var LOG_TAIL_LINES =
|
|
532
|
+
var LOG_TAIL_LINES = 12;
|
|
453
533
|
function JobLog(props) {
|
|
454
534
|
var _open = useState(false);
|
|
455
535
|
var open = _open[0];
|
|
456
536
|
var setOpen = _open[1];
|
|
457
537
|
var text = String(props.output || "").trimEnd();
|
|
538
|
+
var failed = props.status === "failed";
|
|
539
|
+
useEffect(function () {
|
|
540
|
+
if (failed) setOpen(true);
|
|
541
|
+
}, [failed]);
|
|
458
542
|
if (text.length === 0) return null;
|
|
459
543
|
var lines = text.split("\n");
|
|
460
|
-
var
|
|
461
|
-
var
|
|
544
|
+
var settled = !isJobActive(props.status);
|
|
545
|
+
var collapsed = settled && !open;
|
|
546
|
+
var shown = settled || lines.length <= LOG_TAIL_LINES ? lines : lines.slice(-LOG_TAIL_LINES);
|
|
547
|
+
var rendered = shown.join("\n");
|
|
548
|
+
if (rendered.length > 64000) rendered = "…前部日志已截断…\n" + rendered.slice(-64000);
|
|
462
549
|
// 展开/收起始终在日志块上方:放在下方的话,点开后按钮会被推到长长的
|
|
463
550
|
// 日志末尾,想收起还得先滚回去。
|
|
464
551
|
return h("div", { className: "mkt_logBlock" },
|
|
465
|
-
|
|
466
|
-
? h("
|
|
467
|
-
|
|
552
|
+
settled
|
|
553
|
+
? h("button", {
|
|
554
|
+
type: "button",
|
|
555
|
+
className: "mkt_linkButton",
|
|
556
|
+
"aria-expanded": open ? "true" : "false",
|
|
468
557
|
onClick: function () { setOpen(!open); },
|
|
469
558
|
}, open ? "收起日志" : "查看日志(" + lines.length + " 行)")
|
|
470
559
|
: lines.length > LOG_TAIL_LINES
|
|
471
560
|
? h("div", { className: "mkt_meta" }, "只显示最后 " + LOG_TAIL_LINES + " 行")
|
|
472
561
|
: null,
|
|
473
|
-
collapsed ? null : h("pre", { className: "mkt_pre" },
|
|
562
|
+
collapsed ? null : h("pre", { className: "mkt_pre", "aria-label": "任务日志" }, rendered)
|
|
474
563
|
);
|
|
475
564
|
}
|
|
476
565
|
|
|
477
566
|
// ── jobs panel ──────────────────────────────────────────────────────────
|
|
478
567
|
function JobsPanel(props) {
|
|
479
568
|
var ids = Object.keys(props.jobs);
|
|
480
|
-
if (ids.length === 0) return null;
|
|
569
|
+
if (ids.length === 0 && !props.error) return null;
|
|
570
|
+
var hasSettled = ids.some(function (id) {
|
|
571
|
+
var job = props.jobs[id];
|
|
572
|
+
var hasDecision = (props.preflight && props.preflight.jobId === id)
|
|
573
|
+
|| (job.needsApproval && job.needsApproval.length > 0);
|
|
574
|
+
return !isJobActive(job.status) && !hasDecision;
|
|
575
|
+
});
|
|
481
576
|
return h("div", { className: "mkt_card" },
|
|
482
577
|
h("div", { className: "mkt_panelRow" },
|
|
483
578
|
h("p", { className: "mkt_panelTitle" }, "任务"),
|
|
484
|
-
props.onClear ? h("span", { className: "mkt_link", onClick: props.onClear }, "
|
|
579
|
+
props.onClear && hasSettled ? h("span", { className: "mkt_link", onClick: props.onClear }, "清空已结束") : null
|
|
485
580
|
),
|
|
581
|
+
h(ErrorNotice, { message: props.error }),
|
|
486
582
|
ids.map(function (id) {
|
|
487
583
|
var job = props.jobs[id];
|
|
488
584
|
var done = job.status === "completed" || job.status === "failed" || job.status === "killed";
|
|
489
|
-
|
|
585
|
+
var preflightDecision = props.preflight && props.preflight.jobId === id ? props.preflight : null;
|
|
586
|
+
var awaitingDecision = preflightDecision !== null || (job.needsApproval && job.needsApproval.length > 0);
|
|
587
|
+
return h("div", { key: id, className: "mkt_job" },
|
|
490
588
|
// 不再显示 market-N 这种内部 id——对用户没有意义,反而让人以为
|
|
491
589
|
// 自己点了两次。只说清「在做什么 · 到哪一步了」。
|
|
492
|
-
//
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
590
|
+
// 状态词和状态点表达结论,任务类型与目标保持次要色。
|
|
591
|
+
h("div", { className: "mkt_jobHead" },
|
|
592
|
+
h("div", { className: "mkt_jobIdentity" },
|
|
593
|
+
h("span", { className: "mkt_stateDot " + jobStateDotClass(job.status, awaitingDecision), "aria-hidden": "true" }),
|
|
594
|
+
h("span", null, jobKindLabel(job.kind) + clip(job.spec || "", 44) + " · "),
|
|
595
|
+
h("span", { className: awaitingDecision ? "mkt_warn" : jobStatusClass(job.status) }, awaitingDecision ? "待确认" : jobStatusLabel(job.status))),
|
|
596
|
+
isJobActive(job.status) ? h("button", {
|
|
597
|
+
className: "mkt_btn mkt_btnSm",
|
|
598
|
+
disabled: job.status === "stopping",
|
|
599
|
+
onClick: function () { props.onCancel(id); },
|
|
600
|
+
}, job.status === "stopping" ? "停止中…" : "停止") : null),
|
|
497
601
|
job.needsApproval && job.needsApproval.length > 0
|
|
498
602
|
? h(ApprovalRequest, {
|
|
603
|
+
spec: job.spec,
|
|
604
|
+
detail: job.detail,
|
|
499
605
|
needsApproval: job.needsApproval,
|
|
500
606
|
busy: props.approving === job.spec,
|
|
501
607
|
onApprove: function (names) {
|
|
@@ -508,7 +614,15 @@ window.__ModuleLoader__.load({
|
|
|
508
614
|
},
|
|
509
615
|
onDismiss: function () { props.onDismiss(id); },
|
|
510
616
|
})
|
|
511
|
-
:
|
|
617
|
+
: preflightDecision
|
|
618
|
+
? h(PreflightCard, {
|
|
619
|
+
spec: preflightDecision.spec,
|
|
620
|
+
report: preflightDecision.report,
|
|
621
|
+
busy: props.preflightBusy === true,
|
|
622
|
+
onConfirm: props.onConfirmPreflight,
|
|
623
|
+
onClose: props.onClosePreflight,
|
|
624
|
+
})
|
|
625
|
+
: job.detail ? h("div", { className: job.status === "failed" ? "mkt_error" : "mkt_desc" }, job.detail) : null,
|
|
512
626
|
// 预检完成不提示重启——它没有改动任何东西,接下来才是安装。
|
|
513
627
|
// 也不再重复一个绿色「完成」:状态行已经写了「· 完成」。
|
|
514
628
|
done && job.status === "completed" && job.kind !== "dsh-plugin-preflight"
|
|
@@ -523,10 +637,8 @@ window.__ModuleLoader__.load({
|
|
|
523
637
|
disabled: props.restarting === true,
|
|
524
638
|
onClick: props.onRestart,
|
|
525
639
|
}, props.restarting ? "重启中…" : "重启 dsh 生效"))
|
|
526
|
-
:
|
|
527
|
-
|
|
528
|
-
: null,
|
|
529
|
-
h(JobLog, { output: job.output, done: done })
|
|
640
|
+
: null,
|
|
641
|
+
h(JobLog, { output: job.output, status: job.status })
|
|
530
642
|
);
|
|
531
643
|
})
|
|
532
644
|
);
|
|
@@ -551,6 +663,7 @@ window.__ModuleLoader__.load({
|
|
|
551
663
|
h("span", { className: "mkt_badge" }, count + " 个"),
|
|
552
664
|
h("span", { className: "mkt_meta mkt_installedToggle" }, open ? "收起" : "展开")
|
|
553
665
|
),
|
|
666
|
+
h(ErrorNotice, { message: props.error }),
|
|
554
667
|
installed.error
|
|
555
668
|
? h("div", { className: "mkt_error" }, installed.error)
|
|
556
669
|
: !open ? null
|
|
@@ -607,6 +720,9 @@ window.__ModuleLoader__.load({
|
|
|
607
720
|
var _error = useState(null);
|
|
608
721
|
var error = _error[0];
|
|
609
722
|
var setError = _error[1];
|
|
723
|
+
var reportError = useCallback(function (scope, value) {
|
|
724
|
+
setError({ scope: scope, message: errorText(value) });
|
|
725
|
+
}, []);
|
|
610
726
|
var _installed = useState(null);
|
|
611
727
|
var installed = _installed[0];
|
|
612
728
|
var setInstalled = _installed[1];
|
|
@@ -648,6 +764,9 @@ window.__ModuleLoader__.load({
|
|
|
648
764
|
var _restarting = useState(false);
|
|
649
765
|
var restarting = _restarting[0];
|
|
650
766
|
var setRestarting = _restarting[1];
|
|
767
|
+
var _restartConfirm = useState(false);
|
|
768
|
+
var restartConfirm = _restartConfirm[0];
|
|
769
|
+
var setRestartConfirm = _restartConfirm[1];
|
|
651
770
|
// 本次宿主进程的启动时间(jobs 端点带回):完成时间早于它的任务,
|
|
652
771
|
// 其「重启 dsh 生效」按钮已经兑现,改显示「重启已生效」。
|
|
653
772
|
var _hostStartedAt = useState(0);
|
|
@@ -717,11 +836,11 @@ window.__ModuleLoader__.load({
|
|
|
717
836
|
setCompat({});
|
|
718
837
|
verifyPage(value.items);
|
|
719
838
|
}).catch(function (e) {
|
|
720
|
-
|
|
839
|
+
reportError("search", e);
|
|
721
840
|
}).finally(function () {
|
|
722
841
|
setLoading(false);
|
|
723
842
|
});
|
|
724
|
-
}, [call, query, sort, verifyPage]);
|
|
843
|
+
}, [call, query, reportError, sort, verifyPage]);
|
|
725
844
|
|
|
726
845
|
var canLoadMore = results !== null && results.items.length < results.total && !reachedLimit;
|
|
727
846
|
var loadMoreLock = useRef(false);
|
|
@@ -747,13 +866,13 @@ window.__ModuleLoader__.load({
|
|
|
747
866
|
return { total: value.total, items: merged };
|
|
748
867
|
});
|
|
749
868
|
}).catch(function (e) {
|
|
750
|
-
|
|
869
|
+
reportError("search", e);
|
|
751
870
|
setRetryAt(Date.now() + 60000);
|
|
752
871
|
}).finally(function () {
|
|
753
872
|
loadMoreLock.current = false;
|
|
754
873
|
setLoadingMore(false);
|
|
755
874
|
});
|
|
756
|
-
}, [call, canLoadMore, loading, loadingMore, page, query, sort, retryAt, verifyPage]);
|
|
875
|
+
}, [call, canLoadMore, loading, loadingMore, page, query, reportError, sort, retryAt, verifyPage]);
|
|
757
876
|
|
|
758
877
|
useEffect(function () {
|
|
759
878
|
var node = sentinelRef.current;
|
|
@@ -778,7 +897,7 @@ window.__ModuleLoader__.load({
|
|
|
778
897
|
return prev && !prev.error ? Object.assign({}, prev, { entries: value.entries }) : prev;
|
|
779
898
|
});
|
|
780
899
|
}).catch(function (e) {
|
|
781
|
-
|
|
900
|
+
reportError("installed", e);
|
|
782
901
|
}).finally(function () {
|
|
783
902
|
setToggling(function (prev) {
|
|
784
903
|
var next = Object.assign({}, prev);
|
|
@@ -786,7 +905,7 @@ window.__ModuleLoader__.load({
|
|
|
786
905
|
return next;
|
|
787
906
|
});
|
|
788
907
|
});
|
|
789
|
-
}, [call]);
|
|
908
|
+
}, [call, reportError]);
|
|
790
909
|
|
|
791
910
|
var refreshInstalled = useCallback(function () {
|
|
792
911
|
call("installed", {}).then(function (value) {
|
|
@@ -824,8 +943,8 @@ window.__ModuleLoader__.load({
|
|
|
824
943
|
var polling = useJobPolling(call, onJobSettled, onApprovalToken, onPreflightSettled);
|
|
825
944
|
var track = polling.track;
|
|
826
945
|
var jobs = polling.jobs;
|
|
827
|
-
var clearJobs = polling.clear;
|
|
828
946
|
var dropJob = polling.drop;
|
|
947
|
+
var setJobStatus = polling.setStatus;
|
|
829
948
|
|
|
830
949
|
useEffect(function () {
|
|
831
950
|
doSearch();
|
|
@@ -851,7 +970,7 @@ window.__ModuleLoader__.load({
|
|
|
851
970
|
track(value.jobId, spec, carryFromId);
|
|
852
971
|
}).catch(function (e) {
|
|
853
972
|
delete approvalTokensRef.current[spec];
|
|
854
|
-
|
|
973
|
+
reportError("tasks", e);
|
|
855
974
|
}).finally(function () {
|
|
856
975
|
setInstalling(function (prev) {
|
|
857
976
|
var next = Object.assign({}, prev);
|
|
@@ -859,7 +978,7 @@ window.__ModuleLoader__.load({
|
|
|
859
978
|
return next;
|
|
860
979
|
});
|
|
861
980
|
});
|
|
862
|
-
}, [call, track]);
|
|
981
|
+
}, [call, reportError, track]);
|
|
863
982
|
|
|
864
983
|
var doApprove = useCallback(function (spec, names, token, carryFromId) {
|
|
865
984
|
var extra = { allowBuildScripts: names };
|
|
@@ -875,7 +994,7 @@ window.__ModuleLoader__.load({
|
|
|
875
994
|
useEffect(function () {
|
|
876
995
|
preflightHandlerRef.current = function (spec, report, jobId) {
|
|
877
996
|
if (!report || !report.verdict) {
|
|
878
|
-
|
|
997
|
+
reportError("tasks", "预检没有返回结论,请重试");
|
|
879
998
|
return;
|
|
880
999
|
}
|
|
881
1000
|
if (report.verdict === "safe") {
|
|
@@ -885,7 +1004,7 @@ window.__ModuleLoader__.load({
|
|
|
885
1004
|
setPreflight({ spec: spec, report: report, jobId: jobId });
|
|
886
1005
|
}
|
|
887
1006
|
};
|
|
888
|
-
}, [doRawInstall]);
|
|
1007
|
+
}, [doRawInstall, reportError]);
|
|
889
1008
|
|
|
890
1009
|
// 点安装 = 立刻起一个预检 job,面板马上有东西看、日志实时流。
|
|
891
1010
|
// 结论由轮询经 onPreflightSettled 交回上面的 handler,这里不等待。
|
|
@@ -895,18 +1014,15 @@ window.__ModuleLoader__.load({
|
|
|
895
1014
|
call("preflight", { spec: spec }).then(function (value) {
|
|
896
1015
|
track(value.jobId, value.spec || spec);
|
|
897
1016
|
}).catch(function (e) {
|
|
898
|
-
|
|
1017
|
+
reportError("tasks", e);
|
|
899
1018
|
});
|
|
900
|
-
}, [call, track]);
|
|
1019
|
+
}, [call, reportError, track]);
|
|
901
1020
|
|
|
902
1021
|
var doInstall = useCallback(function (repo) {
|
|
903
1022
|
preflightAndInstall("github:" + repo);
|
|
904
1023
|
}, [preflightAndInstall]);
|
|
905
1024
|
|
|
906
1025
|
var doRestart = useCallback(function () {
|
|
907
|
-
if (typeof window !== "undefined" && typeof window.confirm === "function") {
|
|
908
|
-
if (window.confirm("重启 dsh?正在进行的任务会中断。") !== true) return;
|
|
909
|
-
}
|
|
910
1026
|
clearRestartPing();
|
|
911
1027
|
setRestarting(true);
|
|
912
1028
|
setError(null);
|
|
@@ -924,7 +1040,7 @@ window.__ModuleLoader__.load({
|
|
|
924
1040
|
if (tries > 40) {
|
|
925
1041
|
clearRestartPing();
|
|
926
1042
|
setRestarting(false);
|
|
927
|
-
|
|
1043
|
+
reportError("restart", "2 分钟内未检测到 dsh 重启完成,请手动检查 dsh 状态后刷新页面。");
|
|
928
1044
|
return;
|
|
929
1045
|
}
|
|
930
1046
|
// Prefer identity change over wall-clock ordering: NTP may move the
|
|
@@ -947,9 +1063,9 @@ window.__ModuleLoader__.load({
|
|
|
947
1063
|
if (restartControlRef.current.mounted !== true) return;
|
|
948
1064
|
clearRestartPing();
|
|
949
1065
|
setRestarting(false);
|
|
950
|
-
|
|
1066
|
+
reportError("restart", e);
|
|
951
1067
|
});
|
|
952
|
-
}, [call, clearRestartPing, hostStartedAt]);
|
|
1068
|
+
}, [call, clearRestartPing, hostStartedAt, reportError]);
|
|
953
1069
|
|
|
954
1070
|
var doUninstall = useCallback(function (name) {
|
|
955
1071
|
delete approvalTokensRef.current[name];
|
|
@@ -961,7 +1077,7 @@ window.__ModuleLoader__.load({
|
|
|
961
1077
|
call("uninstall", { package: name }).then(function (value) {
|
|
962
1078
|
track(value.jobId, name);
|
|
963
1079
|
}).catch(function (e) {
|
|
964
|
-
|
|
1080
|
+
reportError("installed", e);
|
|
965
1081
|
}).finally(function () {
|
|
966
1082
|
setRemoving(function (prev) {
|
|
967
1083
|
var next = Object.assign({}, prev);
|
|
@@ -969,7 +1085,7 @@ window.__ModuleLoader__.load({
|
|
|
969
1085
|
return next;
|
|
970
1086
|
});
|
|
971
1087
|
});
|
|
972
|
-
}, [call, track]);
|
|
1088
|
+
}, [call, reportError, track]);
|
|
973
1089
|
|
|
974
1090
|
useEffect(function () {
|
|
975
1091
|
refreshInstalled();
|
|
@@ -981,14 +1097,13 @@ window.__ModuleLoader__.load({
|
|
|
981
1097
|
return v !== undefined && (v.kind === "bundle" || v.kind === "client")
|
|
982
1098
|
&& !(v.hostDeps !== undefined && v.hostDeps.length > 0);
|
|
983
1099
|
});
|
|
1100
|
+
var activeJobCount = Object.keys(jobs).filter(function (id) {
|
|
1101
|
+
return jobs[id] && isJobActive(jobs[id].status);
|
|
1102
|
+
}).length;
|
|
984
1103
|
resultsRef.current = results;
|
|
985
1104
|
var verifyPending = results !== null && results.items.some(function (it) { return verified[it.fullName] === undefined; });
|
|
986
1105
|
|
|
987
1106
|
return h("div", { className: "mkt_root" },
|
|
988
|
-
h("div", { className: "mkt_head" },
|
|
989
|
-
h("div", { className: "mkt_title" }, "插件市场"),
|
|
990
|
-
h("div", { className: "mkt_sub" }, "搜索 GitHub dsh-plugin 话题插件 · 装/卸后需重启 dsh 生效")
|
|
991
|
-
),
|
|
992
1107
|
h("div", { className: "mkt_row" },
|
|
993
1108
|
h("input", {
|
|
994
1109
|
className: "mkt_input",
|
|
@@ -1007,13 +1122,12 @@ window.__ModuleLoader__.load({
|
|
|
1007
1122
|
h("option", { value: "forks" }, "按 fork")
|
|
1008
1123
|
),
|
|
1009
1124
|
h("button", { className: "mkt_btn mkt_btnPrimary", disabled: loading, onClick: doSearch }, loading ? "搜索中…" : "搜索"),
|
|
1010
|
-
h("button", { className: "mkt_btn", onClick:
|
|
1011
|
-
h("button", { className: "mkt_btn mkt_btnDanger", disabled: restarting, onClick: doRestart }, restarting ? "重启中…" : "重启 dsh"),
|
|
1125
|
+
h("button", { className: "mkt_btn mkt_btnDanger", disabled: restarting, onClick: function () { setRestartConfirm(true); } }, restarting ? "重启中…" : "重启 dsh"),
|
|
1012
1126
|
h("label", { className: "mkt_check" },
|
|
1013
1127
|
h("input", { type: "checkbox", checked: verifiedOnly, onChange: function (e) { setVerifiedOnly(e.target.checked); } }),
|
|
1014
1128
|
"只看已验证插件")
|
|
1015
1129
|
),
|
|
1016
|
-
|
|
1130
|
+
h(ErrorNotice, { message: error && (error.scope === "search" || error.scope === "restart") ? error.message : null }),
|
|
1017
1131
|
h(InstalledPanel, {
|
|
1018
1132
|
installed: installed,
|
|
1019
1133
|
removing: removing,
|
|
@@ -1023,19 +1137,50 @@ window.__ModuleLoader__.load({
|
|
|
1023
1137
|
onToggle: doToggle,
|
|
1024
1138
|
onUninstall: doUninstall,
|
|
1025
1139
|
onInstallSpec: preflightAndInstall,
|
|
1140
|
+
error: error && error.scope === "installed" ? error.message : null,
|
|
1026
1141
|
}),
|
|
1027
1142
|
h(JobsPanel, {
|
|
1028
1143
|
jobs: jobs,
|
|
1144
|
+
error: error && error.scope === "tasks" ? error.message : null,
|
|
1145
|
+
preflight: preflight,
|
|
1146
|
+
preflightBusy: preflight ? installing[preflight.spec] === true : false,
|
|
1029
1147
|
onClear: function () {
|
|
1030
1148
|
Object.keys(jobs).forEach(function (id) {
|
|
1031
1149
|
var job = jobs[id];
|
|
1150
|
+
var hasDecision = job && ((preflight && preflight.jobId === id)
|
|
1151
|
+
|| (job.needsApproval && job.needsApproval.length > 0));
|
|
1152
|
+
if (!job || isJobActive(job.status) || hasDecision) return;
|
|
1032
1153
|
var token = job && job.approvalToken ? job.approvalToken : (job && job.spec ? approvalTokensRef.current[job.spec] : undefined);
|
|
1033
1154
|
call("jobDismiss", { jobId: id, token: token }).catch(function () {});
|
|
1155
|
+
if (job.spec) delete approvalTokensRef.current[job.spec];
|
|
1156
|
+
dropJob(id);
|
|
1157
|
+
});
|
|
1158
|
+
},
|
|
1159
|
+
onCancel: function (id) {
|
|
1160
|
+
var job = jobs[id];
|
|
1161
|
+
if (!job || job.status !== "running") return;
|
|
1162
|
+
setJobStatus(id, "stopping");
|
|
1163
|
+
call("jobCancel", { jobId: id }).catch(function (e) {
|
|
1164
|
+
setJobStatus(id, "running");
|
|
1165
|
+
reportError("tasks", e);
|
|
1034
1166
|
});
|
|
1035
|
-
approvalTokensRef.current = {};
|
|
1036
|
-
clearJobs();
|
|
1037
1167
|
},
|
|
1038
1168
|
onApprove: doApprove,
|
|
1169
|
+
onConfirmPreflight: function () {
|
|
1170
|
+
if (!preflight) return;
|
|
1171
|
+
var spec = preflight.spec;
|
|
1172
|
+
var carry = preflight.jobId;
|
|
1173
|
+
var report = preflight.report;
|
|
1174
|
+
setPreflight(null);
|
|
1175
|
+
// consentDigest 来自预检 job 的 extras,装的时候与当前报告比对:
|
|
1176
|
+
// 用户点「继续」到安装真正开跑之间候选包或 profile 变了,
|
|
1177
|
+
// 布尔同意不得沿用,要重新看新的警告。
|
|
1178
|
+
doRawInstall(spec, { acceptWarnings: true, acceptedReportDigest: report.consentDigest }, carry);
|
|
1179
|
+
},
|
|
1180
|
+
onClosePreflight: function () {
|
|
1181
|
+
if (preflight && preflight.spec) delete approvalTokensRef.current[preflight.spec];
|
|
1182
|
+
setPreflight(null);
|
|
1183
|
+
},
|
|
1039
1184
|
onDismiss: function (id) {
|
|
1040
1185
|
var job = jobs[id];
|
|
1041
1186
|
var token = job && job.approvalToken ? job.approvalToken : (job && job.spec ? approvalTokensRef.current[job.spec] : undefined);
|
|
@@ -1044,29 +1189,11 @@ window.__ModuleLoader__.load({
|
|
|
1044
1189
|
dropJob(id);
|
|
1045
1190
|
},
|
|
1046
1191
|
onDrop: dropJob,
|
|
1047
|
-
onRestart:
|
|
1192
|
+
onRestart: function () { setRestartConfirm(true); },
|
|
1048
1193
|
restarting: restarting,
|
|
1049
1194
|
hostStartedAt: hostStartedAt,
|
|
1050
1195
|
approving: Object.keys(installing).filter(function (s) { return installing[s]; })[0],
|
|
1051
1196
|
}),
|
|
1052
|
-
preflight ? h(PreflightCard, {
|
|
1053
|
-
spec: preflight.spec,
|
|
1054
|
-
report: preflight.report,
|
|
1055
|
-
busy: installing[preflight.spec] === true,
|
|
1056
|
-
onConfirm: function () {
|
|
1057
|
-
var spec = preflight.spec;
|
|
1058
|
-
var carry = preflight.jobId;
|
|
1059
|
-
setPreflight(null);
|
|
1060
|
-
// consentDigest 来自预检 job 的 extras,装的时候与当前报告比对:
|
|
1061
|
-
// 用户点「继续」到安装真正开跑之间候选包或 profile 变了,
|
|
1062
|
-
// 布尔同意不得沿用,要重新看新的警告。
|
|
1063
|
-
doRawInstall(spec, { acceptWarnings: true, acceptedReportDigest: preflight.report.consentDigest }, carry);
|
|
1064
|
-
},
|
|
1065
|
-
onClose: function () {
|
|
1066
|
-
if (preflight && preflight.spec) delete approvalTokensRef.current[preflight.spec];
|
|
1067
|
-
setPreflight(null);
|
|
1068
|
-
},
|
|
1069
|
-
}) : null,
|
|
1070
1197
|
h("div", { className: "mkt_list" },
|
|
1071
1198
|
results == null
|
|
1072
1199
|
? h("div", { className: "mkt_meta mkt_listHead" }, loading ? "正在加载最热插件…" : "—")
|
|
@@ -1103,7 +1230,16 @@ window.__ModuleLoader__.load({
|
|
|
1103
1230
|
? h("div", { className: "mkt_loadMore", ref: sentinelRef }, loadingMore ? "加载中…" : Date.now() < retryAt ? "GitHub 限流中,稍后再下滑加载" : "下滑加载更多")
|
|
1104
1231
|
: h("div", { className: "mkt_loadMore" }, reachedLimit ? "已达 GitHub 搜索上限(前 1000 个结果)" : "已显示全部 " + results.items.length + " 个")
|
|
1105
1232
|
)
|
|
1106
|
-
)
|
|
1233
|
+
),
|
|
1234
|
+
restartConfirm ? h(RestartDialog, {
|
|
1235
|
+
activeCount: activeJobCount,
|
|
1236
|
+
busy: restarting,
|
|
1237
|
+
onCancel: function () { setRestartConfirm(false); },
|
|
1238
|
+
onConfirm: function () {
|
|
1239
|
+
setRestartConfirm(false);
|
|
1240
|
+
doRestart();
|
|
1241
|
+
},
|
|
1242
|
+
}) : null
|
|
1107
1243
|
);
|
|
1108
1244
|
}
|
|
1109
1245
|
|