dsh-life-pack 0.2.3 → 0.2.5
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/dist/client.js +235 -25
- package/dist/client.js.map +1 -1
- package/dist/health-view.d.ts +17 -4
- package/dist/health-view.d.ts.map +1 -1
- package/dist/health-view.js +117 -22
- package/dist/health-view.js.map +1 -1
- package/dist/nav.d.ts +1 -1
- package/dist/nav.js +1 -1
- package/dist/update-client.d.ts.map +1 -1
- package/dist/update-client.js +3 -1
- package/dist/update-client.js.map +1 -1
- package/dist/update-contract.d.ts.map +1 -1
- package/dist/update-contract.js +1 -0
- package/dist/update-contract.js.map +1 -1
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -170,6 +170,7 @@ window.__ModuleLoader__.load({
|
|
|
170
170
|
"check-expired": "上次查新版的凭证过期了:重新查一次再点安装(不要重试旧编号)。",
|
|
171
171
|
"update-busy": "同一个使用范围同时只装一个:等当前任务结束再点。",
|
|
172
172
|
"install-failed": "安装没跑成:按下面那条手工命令在终端执行一次。",
|
|
173
|
+
"manager-unreachable": "总管的电话没接上(宿主半没注册或版本对不上):重启宿主后再试;仍不行看宿主日志。",
|
|
173
174
|
"bad-request": "回执异常(请求形状不对):把宿主日志里的事件名报给作者。",
|
|
174
175
|
internal: "回执异常(总管内部错误):把宿主日志里的事件名报给作者。"
|
|
175
176
|
};
|
|
@@ -223,7 +224,7 @@ window.__ModuleLoader__.load({
|
|
|
223
224
|
payload
|
|
224
225
|
});
|
|
225
226
|
} catch (error) {
|
|
226
|
-
return failure("
|
|
227
|
+
return failure("manager-unreachable", { detail: String(error?.message ?? error) });
|
|
227
228
|
}
|
|
228
229
|
if (!result || typeof result !== "object" || typeof result.ok !== "boolean") return failure("internal", { detail: "回执信封异常(非 ok 信封)" });
|
|
229
230
|
if (result.ok) return {
|
|
@@ -499,6 +500,55 @@ window.__ModuleLoader__.load({
|
|
|
499
500
|
color: "var(--dsw-alias-label-tertiary, #8a8a8a)",
|
|
500
501
|
fontSize: 12,
|
|
501
502
|
marginTop: 4
|
|
503
|
+
},
|
|
504
|
+
overlay: {
|
|
505
|
+
position: "fixed",
|
|
506
|
+
inset: 0,
|
|
507
|
+
zIndex: 40,
|
|
508
|
+
display: "flex",
|
|
509
|
+
alignItems: "center",
|
|
510
|
+
justifyContent: "center",
|
|
511
|
+
padding: 16,
|
|
512
|
+
background: "rgba(0,0,0,.45)"
|
|
513
|
+
},
|
|
514
|
+
dialog: {
|
|
515
|
+
width: "100%",
|
|
516
|
+
maxWidth: 560,
|
|
517
|
+
maxHeight: "80vh",
|
|
518
|
+
overflow: "auto",
|
|
519
|
+
padding: "12px 14px",
|
|
520
|
+
borderRadius: 12,
|
|
521
|
+
border: "1px solid var(--dsw-alias-border, rgba(128,128,128,.4))",
|
|
522
|
+
background: "var(--dsw-alias-bg-elevated, var(--dsw-alias-bg-base, #222))",
|
|
523
|
+
color: "var(--dsw-alias-label-primary, inherit)",
|
|
524
|
+
boxShadow: "0 12px 32px rgba(0,0,0,.35)"
|
|
525
|
+
},
|
|
526
|
+
dialogHead: {
|
|
527
|
+
display: "flex",
|
|
528
|
+
alignItems: "center",
|
|
529
|
+
justifyContent: "space-between",
|
|
530
|
+
gap: 8,
|
|
531
|
+
marginBottom: 8
|
|
532
|
+
},
|
|
533
|
+
dialogTitle: {
|
|
534
|
+
fontSize: 14,
|
|
535
|
+
fontWeight: 700
|
|
536
|
+
},
|
|
537
|
+
close: {
|
|
538
|
+
border: "1px solid var(--dsw-alias-border, rgba(128,128,128,.35))",
|
|
539
|
+
background: "transparent",
|
|
540
|
+
color: "var(--dsw-alias-label-primary, inherit)",
|
|
541
|
+
borderRadius: 8,
|
|
542
|
+
width: 26,
|
|
543
|
+
height: 26,
|
|
544
|
+
lineHeight: 1,
|
|
545
|
+
fontSize: 14,
|
|
546
|
+
cursor: "pointer"
|
|
547
|
+
},
|
|
548
|
+
dialogNote: {
|
|
549
|
+
color: "var(--dsw-alias-label-tertiary, #8a8a8a)",
|
|
550
|
+
fontSize: 12,
|
|
551
|
+
marginTop: 4
|
|
502
552
|
}
|
|
503
553
|
};
|
|
504
554
|
const IDLE$1 = {
|
|
@@ -513,6 +563,7 @@ window.__ModuleLoader__.load({
|
|
|
513
563
|
const [pollMs, setPollMs] = react.useState(1e3);
|
|
514
564
|
const [loadError, setLoadError] = react.useState(null);
|
|
515
565
|
const [checking, setChecking] = react.useState(false);
|
|
566
|
+
const [open, setOpen] = react.useState(false);
|
|
516
567
|
react.useEffect(() => {
|
|
517
568
|
let alive = true;
|
|
518
569
|
(async () => {
|
|
@@ -539,8 +590,11 @@ window.__ModuleLoader__.load({
|
|
|
539
590
|
pollMs,
|
|
540
591
|
loadError,
|
|
541
592
|
checking,
|
|
593
|
+
open,
|
|
594
|
+
close: () => setOpen(false),
|
|
542
595
|
checkAll: react.useCallback(() => {
|
|
543
596
|
setChecking(true);
|
|
597
|
+
setOpen(true);
|
|
544
598
|
const list = targets;
|
|
545
599
|
for (const target of list) patch(target.key, {
|
|
546
600
|
phase: "checking",
|
|
@@ -651,19 +705,31 @@ window.__ModuleLoader__.load({
|
|
|
651
705
|
if (lines.length === 0) return null;
|
|
652
706
|
return react.createElement("div", { style: PANEL_STYLE.banner }, lines.map((line, index) => react.createElement("div", { key: String(index) }, line)));
|
|
653
707
|
}
|
|
654
|
-
/**
|
|
708
|
+
/** 七家结果:装不了的与待重启的常驻(横幅),详细结果放**居中浮层**(点「检查更新」开)。
|
|
709
|
+
*
|
|
710
|
+
* 为什么是浮层:内联展开会把面板本体撑长、且它自身没有关闭控件(真机第一次做成内联后用户反馈
|
|
711
|
+
* 「打开就无法收回了」)。参照实现也是浮层:`dsh-mattpocock-skills-deck/src/client/views/SettingsPage.js`
|
|
712
|
+
* 的 `upd.dialog`。关法三种:右上角 ×、点遮罩、Esc(Esc 靠浮层自己拿焦点后收 keydown,
|
|
713
|
+
* 不摸 window——客户端纪律禁直写 DOM 全局)。
|
|
714
|
+
* 手工命令只在「装不了」或「装失败」的行显示:正常用户用不到,摊在每行上既吵又误导。
|
|
715
|
+
*/
|
|
655
716
|
function UpdateResults(props) {
|
|
656
|
-
const { targets, rows, loadError, checking } = props.face;
|
|
717
|
+
const { targets, rows, loadError, checking, open, close } = props.face;
|
|
718
|
+
const dialogRef = react.useRef(null);
|
|
719
|
+
react.useEffect(() => {
|
|
720
|
+
if (open) dialogRef.current?.focus();
|
|
721
|
+
}, [open]);
|
|
657
722
|
const shown = targets.filter((target) => rows[target.key] && rows[target.key].phase !== "idle");
|
|
658
723
|
if (loadError) return react.createElement("div", { style: PANEL_STYLE.reason }, "更新能力没接上:" + loadError);
|
|
659
724
|
if (targets.length === 0) return null;
|
|
660
|
-
if (shown.length === 0) return null;
|
|
661
|
-
|
|
725
|
+
if (shown.length === 0 && !open) return null;
|
|
726
|
+
const body = shown.map((target) => {
|
|
662
727
|
const row = rows[target.key];
|
|
663
728
|
const snapshot = row.outcome?.snapshot ?? null;
|
|
664
729
|
const verdict = snapshot ? verdictOf(target, snapshot) : null;
|
|
665
730
|
const manual = manualForDisplay(target, row.failure?.manual ?? row.outcome?.manual ?? null);
|
|
666
731
|
const busy = row.phase === "installing";
|
|
732
|
+
const showManual = manual !== null && (row.phase === "failed" || verdict?.kind === "blocked");
|
|
667
733
|
return react.createElement("div", {
|
|
668
734
|
key: target.key,
|
|
669
735
|
style: PANEL_STYLE.row
|
|
@@ -681,18 +747,50 @@ window.__ModuleLoader__.load({
|
|
|
681
747
|
}, verdict.action === "install" ? "装上" : "装上更新") : null, row.failure ? react.createElement("div", { style: PANEL_STYLE.reason }, "装不上:" + row.failure.message) : null, versionLines(target, snapshot).map((line, index) => react.createElement("div", {
|
|
682
748
|
key: String(index),
|
|
683
749
|
style: PANEL_STYLE.skill
|
|
684
|
-
}, line)),
|
|
685
|
-
})
|
|
750
|
+
}, line)), showManual ? react.createElement("code", { style: PANEL_STYLE.cmd }, manual) : null);
|
|
751
|
+
});
|
|
752
|
+
return react.createElement("div", null, react.createElement(RestartBanners, { face: props.face }), open ? react.createElement("div", {
|
|
753
|
+
style: PANEL_STYLE.overlay,
|
|
754
|
+
role: "presentation",
|
|
755
|
+
onClick: () => close()
|
|
756
|
+
}, react.createElement("div", {
|
|
757
|
+
ref: dialogRef,
|
|
758
|
+
tabIndex: -1,
|
|
759
|
+
role: "dialog",
|
|
760
|
+
"aria-label": "检查更新结果",
|
|
761
|
+
style: PANEL_STYLE.dialog,
|
|
762
|
+
onClick: (event) => event.stopPropagation(),
|
|
763
|
+
onKeyDown: (event) => {
|
|
764
|
+
if (event.key === "Escape") close();
|
|
765
|
+
}
|
|
766
|
+
}, react.createElement("div", { style: PANEL_STYLE.dialogHead }, react.createElement("div", { style: PANEL_STYLE.dialogTitle }, "检查更新(七家)"), react.createElement("button", {
|
|
767
|
+
type: "button",
|
|
768
|
+
style: PANEL_STYLE.close,
|
|
769
|
+
onClick: () => close(),
|
|
770
|
+
title: "关闭",
|
|
771
|
+
"aria-label": "关闭"
|
|
772
|
+
}, "×")), body, react.createElement("div", { style: PANEL_STYLE.dialogNote }, "装与更新都在宿主后台跑:关掉这块不影响正在进行的安装,再点「检查更新」可以看到最新状态。"))) : null);
|
|
686
773
|
}
|
|
687
|
-
/**
|
|
774
|
+
/** 缺席卡:**按宿主的装机读数分两态**,不让层与层的结论互相顶替。
|
|
775
|
+
*
|
|
776
|
+
* - 宿主说磁盘上没有这个包 →「未安装」+「装上」按钮(这是本票原有的能力);
|
|
777
|
+
* - 宿主说装着(`installedVersion` 非空)却没进页签槽 → 说实情、**不给「装上」**:
|
|
778
|
+
* 重装改不了产物里有没有注册代码这件事(真机实测:作息/居家/大厨/记账 的已发布 0.2.0
|
|
779
|
+
* 产物里根本没有页签槽注册,见票 #723)。给出可复制命令仅作参考。
|
|
780
|
+
*
|
|
781
|
+
* 原实现只看页签槽 ledger 就断言「未安装」——那对上面第二种情形是说假话,且点「装上」
|
|
782
|
+
* 会走进更新包的流程(它已经装着 ⇒ 没有新版 ⇒ 没有凭证)并报出误导的「查新版失败」。
|
|
783
|
+
*/
|
|
688
784
|
function AbsentCard(props) {
|
|
689
785
|
const target = props.target;
|
|
690
786
|
const row = target ? props.face.rows[target.key] : null;
|
|
691
787
|
const busy = row?.phase === "installing";
|
|
692
788
|
const manual = (target ? manualForDisplay(target, row?.failure?.manual ?? row?.outcome?.manual ?? null) : null) ?? props.fallbackCommand;
|
|
789
|
+
const installed = target ? target.installedVersion ?? target.runningVersion : null;
|
|
693
790
|
let reason = row?.failure?.message ?? null;
|
|
694
791
|
if (target && reason === null && row?.outcome && row.outcome.snapshot.blockedReason !== null) reason = verdictOf(target, row.outcome.snapshot).text;
|
|
695
|
-
|
|
792
|
+
const headline = !target ? "这个页签对应的插件还没装。" : installed === null ? "未安装[" + target.packageName + "],装上后这个页签就能用了。" : "插件已装(" + installed + "),但它这一版没把设置页接上爱生活面板:要等它发新版才对得上(重启与重装都不会变)。";
|
|
793
|
+
return react.createElement("div", { style: PANEL_STYLE.reco }, react.createElement("div", null, headline), target && installed === null ? react.createElement("button", {
|
|
696
794
|
type: "button",
|
|
697
795
|
style: busy ? {
|
|
698
796
|
...PANEL_STYLE.btn,
|
|
@@ -893,8 +991,8 @@ window.__ModuleLoader__.load({
|
|
|
893
991
|
};
|
|
894
992
|
/** 整行底色的浅一档:饱和降一档,免得红黄行「刺眼」压过正文(评审第二轮的扣分点)。 */
|
|
895
993
|
const STATUS_TINT = {
|
|
896
|
-
red: "rgba(192, 57, 43, 0.
|
|
897
|
-
yellow: "rgba(224, 138, 0, 0.
|
|
994
|
+
red: "rgba(192, 57, 43, 0.06)",
|
|
995
|
+
yellow: "rgba(224, 138, 0, 0.10)",
|
|
898
996
|
green: "transparent"
|
|
899
997
|
};
|
|
900
998
|
/** 档位词(灯里那几个字)用的色:红黄要**够深**才读得清,故另取一枚比灯更深的值。 */
|
|
@@ -908,6 +1006,12 @@ window.__ModuleLoader__.load({
|
|
|
908
1006
|
yellow: "黄",
|
|
909
1007
|
green: "绿"
|
|
910
1008
|
};
|
|
1009
|
+
/** 档位的**形状**标记:颜色之外的第二条读数(灰度截图、色弱视角下也分得开谁要处理)。 */
|
|
1010
|
+
const STATUS_MARK = {
|
|
1011
|
+
red: "✕",
|
|
1012
|
+
yellow: "!",
|
|
1013
|
+
green: "✓"
|
|
1014
|
+
};
|
|
911
1015
|
/** 面板上的文字色与分隔线(与 `client.ts` 同一套别名)。 */
|
|
912
1016
|
const INK = "var(--dsw-alias-label-primary, inherit)";
|
|
913
1017
|
const INK_DIM = "var(--dsw-alias-label-secondary, #9a9a9a)";
|
|
@@ -924,21 +1028,23 @@ window.__ModuleLoader__.load({
|
|
|
924
1028
|
flexWrap: "wrap",
|
|
925
1029
|
alignItems: "center",
|
|
926
1030
|
gap: 8,
|
|
927
|
-
marginBottom:
|
|
1031
|
+
marginBottom: 4
|
|
928
1032
|
},
|
|
929
1033
|
head: {
|
|
930
1034
|
fontSize: 13,
|
|
931
1035
|
fontWeight: 700,
|
|
932
1036
|
color: INK
|
|
933
1037
|
},
|
|
1038
|
+
/** 「体检一次」不挤在标题右端:它单独占一行、与标题同一起始边(视觉复评两轮点「孤立在右上缺层次」)。 */
|
|
1039
|
+
runRow: { margin: "8px 0 10px" },
|
|
934
1040
|
btn: {
|
|
935
|
-
marginLeft: "auto",
|
|
936
1041
|
border: "1px solid " + BORDER,
|
|
937
1042
|
background: "transparent",
|
|
938
1043
|
color: INK,
|
|
939
1044
|
borderRadius: 8,
|
|
940
|
-
padding: "
|
|
941
|
-
fontSize:
|
|
1045
|
+
padding: "6px 16px",
|
|
1046
|
+
fontSize: 13,
|
|
1047
|
+
fontWeight: 600,
|
|
942
1048
|
cursor: "pointer"
|
|
943
1049
|
},
|
|
944
1050
|
lightsRow: {
|
|
@@ -985,6 +1091,68 @@ window.__ModuleLoader__.load({
|
|
|
985
1091
|
const trimmed = action.trim();
|
|
986
1092
|
return trimmed.startsWith("去哪修:") ? trimmed.slice(4).trim() : trimmed;
|
|
987
1093
|
}
|
|
1094
|
+
/** 报文里能扫出来的每一段路径(盘符绝对路径;非 Windows 形状的退回 `/` 打头那一支)。 */
|
|
1095
|
+
function rawPathsIn(text) {
|
|
1096
|
+
return text.match(/[A-Za-z]:\/[^\s()「」,。;]+/g) ?? text.match(/\/[^\s()「」,。;]+/g) ?? [];
|
|
1097
|
+
}
|
|
1098
|
+
/** 一段落点的**根**(盘符):`C:/a/b` → `C:/`。用来把「同一个盘、但根下不同枝」的落点分开算,
|
|
1099
|
+
* 免得一个 D 盘上的旁证(比如「配了但目录不在:D:/media」)把 C 盘那几条的缩写全拖没。 */
|
|
1100
|
+
function rootOf(path) {
|
|
1101
|
+
const drive = /^[A-Za-z]:\//.exec(path);
|
|
1102
|
+
return drive === null ? "/" : drive[0];
|
|
1103
|
+
}
|
|
1104
|
+
/** 一段落点的公共目录前缀(按 `/` 切、整段比):`C:/a/b/c` + `C:/a/b/d` → `C:/a/b`。 */
|
|
1105
|
+
function commonDirOf(paths) {
|
|
1106
|
+
if (paths.length < 2) return "";
|
|
1107
|
+
const split = paths.map((path) => path.replace(/[.,。;]+$/, "").split("/"));
|
|
1108
|
+
const first = split[0];
|
|
1109
|
+
let size = 0;
|
|
1110
|
+
while (size < first.length && split.every((parts) => parts[size] === first[size])) size += 1;
|
|
1111
|
+
return size < 1 ? "" : first.slice(0, size).join("/");
|
|
1112
|
+
}
|
|
1113
|
+
/** 一份报文里**按根分开**的落点前缀(长的在前):只给「同一个根下至少两条落点」的根算前缀——
|
|
1114
|
+
* 这个根下只有一条落点时不缩(没有第二条可比,缩出来反而是瞎猜)。
|
|
1115
|
+
* 为什么要分根:一家报里常有别的盘的旁证(备忘录用 D 盘上那份媒体目录),只算一个总前缀,
|
|
1116
|
+
* 一条旁证就能把整张表的缩写全拖没(#706 出图复评:备忘录那张表整片没缩、记账那张缩了)。 */
|
|
1117
|
+
function dirPrefixesOf(report) {
|
|
1118
|
+
return dirPrefixesIn(pathsOf(report).join(" "));
|
|
1119
|
+
}
|
|
1120
|
+
/** `dirPrefixesOf` 的正文版:一段文字里(报文正文 + 表头两条混在一起)按根分组取公共目录前缀。 */
|
|
1121
|
+
function dirPrefixesIn(text) {
|
|
1122
|
+
const paths = rawPathsIn(text);
|
|
1123
|
+
const roots = [...new Set(paths.map(rootOf))];
|
|
1124
|
+
const prefixes = [];
|
|
1125
|
+
for (const root of roots) {
|
|
1126
|
+
const prefix = commonDirOf(paths.filter((path) => rootOf(path) === root));
|
|
1127
|
+
if (prefix !== "") prefixes.push(prefix);
|
|
1128
|
+
}
|
|
1129
|
+
return prefixes.sort((a, b) => b.length - a.length);
|
|
1130
|
+
}
|
|
1131
|
+
/** 那一行「配置文件 … · 数据目录 …」+ 各条报文里的长路径,都缩成「公共前缀 + 短尾巴」。 */
|
|
1132
|
+
function shorten(path, prefixes) {
|
|
1133
|
+
const hit = prefixes.find((prefix) => path.startsWith(prefix + "/"));
|
|
1134
|
+
return hit === void 0 ? path : "…/" + path.slice(hit.length + 1);
|
|
1135
|
+
}
|
|
1136
|
+
/** 一家里所有会印出来的路径。 */
|
|
1137
|
+
function pathsOf(report) {
|
|
1138
|
+
const out = [report.configPath, report.dataDir];
|
|
1139
|
+
for (const item of report.items) out.push(item.message);
|
|
1140
|
+
return out;
|
|
1141
|
+
}
|
|
1142
|
+
/** 把报文里那一长串路径按公共前缀缩短(只动打印,不动事实)。
|
|
1143
|
+
* 只按**扫得出来的那一段段落点**去缩,不做全串替换:既不误伤长路径,也不会把一段路劈成半截。 */
|
|
1144
|
+
function shortenPathsIn(text, prefixes) {
|
|
1145
|
+
const candidates = rawPathsIn(text);
|
|
1146
|
+
if (candidates.length === 0) return text;
|
|
1147
|
+
const longestFirst = [...new Set(candidates.map((path) => path.replace(/[.,。;]+$/, "")))].sort((a, b) => b.length - a.length);
|
|
1148
|
+
let out = text;
|
|
1149
|
+
for (const path of longestFirst) {
|
|
1150
|
+
const hit = prefixes.find((prefix) => path.startsWith(prefix + "/"));
|
|
1151
|
+
if (hit === void 0) continue;
|
|
1152
|
+
out = out.split(hit + "/").join("…/");
|
|
1153
|
+
}
|
|
1154
|
+
return out;
|
|
1155
|
+
}
|
|
988
1156
|
/** 从六份报告数出那一行的灯(每家按最严重那一档上色)。 */
|
|
989
1157
|
function lightsOf(tabs, reports) {
|
|
990
1158
|
return tabs.map((tab) => {
|
|
@@ -1010,7 +1178,7 @@ window.__ModuleLoader__.load({
|
|
|
1010
1178
|
return react.createElement("div", {
|
|
1011
1179
|
style: HEALTH_STYLE.box,
|
|
1012
1180
|
"data-ilife-health": "overview"
|
|
1013
|
-
}, react.createElement("div", { style: HEALTH_STYLE.headRow }, react.createElement("div", { style: HEALTH_STYLE.head }, "配置体检"), react.createElement("button", {
|
|
1181
|
+
}, react.createElement("div", { style: HEALTH_STYLE.headRow }, react.createElement("div", { style: HEALTH_STYLE.head }, "配置体检")), react.createElement("div", { style: HEALTH_STYLE.runRow }, react.createElement("button", {
|
|
1014
1182
|
type: "button",
|
|
1015
1183
|
style: props.running ? {
|
|
1016
1184
|
...HEALTH_STYLE.btn,
|
|
@@ -1054,32 +1222,51 @@ window.__ModuleLoader__.load({
|
|
|
1054
1222
|
fontWeight: 700
|
|
1055
1223
|
} }, light.status === null ? "—" : countsText(light.counts))))), react.createElement("div", { style: HEALTH_STYLE.meta }, props.error !== null ? props.error : "只看不改 · 灯=那一家最严重的一档 · 点一下跳到那家配置页"));
|
|
1056
1224
|
}
|
|
1057
|
-
/**
|
|
1225
|
+
/** 正正常常的那些:绿条只留「名字」,一句话与「去哪修」都不印(票面验收第一条:正常的收成一行)。 */
|
|
1226
|
+
function isAttentionItem(item) {
|
|
1227
|
+
return isAttention(item.status);
|
|
1228
|
+
}
|
|
1229
|
+
/** 一家那张表:**要处理的**(红黄)一条一块、整行上底带一句话与「去哪修」;
|
|
1230
|
+
* **正常的**(绿)收成一行并列的小字,点得到、扫得完(票面验收第一条:正常的收成一行,有问题的才展开)。 */
|
|
1058
1231
|
function HealthTable(props) {
|
|
1059
1232
|
const { report } = props;
|
|
1233
|
+
const prefixes = report ? dirPrefixesOf(report) : [];
|
|
1060
1234
|
return react.createElement("div", {
|
|
1061
1235
|
style: HEALTH_STYLE.box,
|
|
1062
1236
|
"data-ilife-health": "table"
|
|
1063
1237
|
}, react.createElement("div", { style: HEALTH_STYLE.headRow }, react.createElement("div", { style: HEALTH_STYLE.head }, props.title + " · 体检"), report ? react.createElement("div", { style: {
|
|
1064
1238
|
color: INK_DIM,
|
|
1065
1239
|
fontSize: 12
|
|
1066
|
-
} }, countsText(countByStatus(report.items))) : null), props.phase === "idle" ? react.createElement("div", { style: HEALTH_STYLE.meta }, "还没体检:点上面那个「体检一次」。") : null, props.phase === "running" ? react.createElement("div", { style: HEALTH_STYLE.meta }, "正在体检…") : null, props.error !== null ? react.createElement("div", { style: HEALTH_STYLE.error }, props.error) : null, report ? react.createElement("div", null, react.createElement("div", {
|
|
1240
|
+
} }, countsText(countByStatus(report.items))) : null), props.phase === "idle" ? react.createElement("div", { style: HEALTH_STYLE.meta }, "还没体检:点上面那个「体检一次」。") : null, props.phase === "running" ? react.createElement("div", { style: HEALTH_STYLE.meta }, "正在体检…") : null, props.error !== null ? react.createElement("div", { style: HEALTH_STYLE.error }, props.error) : null, report ? react.createElement("div", null, react.createElement("div", {
|
|
1241
|
+
style: HEALTH_STYLE.meta,
|
|
1242
|
+
title: prefixes.join(" ")
|
|
1243
|
+
}, "配置文件 " + shorten(report.configPath, prefixes) + " · 数据目录 " + shorten(report.dataDir, prefixes)), report.items.filter(isAttentionItem).map((item) => react.createElement("div", {
|
|
1067
1244
|
key: item.id,
|
|
1245
|
+
"data-ilife-health": "item",
|
|
1246
|
+
"data-status": item.status,
|
|
1068
1247
|
style: {
|
|
1069
1248
|
padding: "7px 8px",
|
|
1070
1249
|
margin: "2px 0",
|
|
1071
1250
|
borderTop: "1px solid " + BORDER,
|
|
1072
1251
|
borderRadius: 6,
|
|
1073
|
-
fontSize:
|
|
1074
|
-
lineHeight: 1.
|
|
1075
|
-
background:
|
|
1252
|
+
fontSize: 13,
|
|
1253
|
+
lineHeight: 1.75,
|
|
1254
|
+
background: STATUS_TINT[item.status]
|
|
1076
1255
|
}
|
|
1077
1256
|
}, react.createElement("div", { style: {
|
|
1078
1257
|
display: "flex",
|
|
1079
1258
|
flexWrap: "wrap",
|
|
1080
1259
|
alignItems: "center",
|
|
1081
1260
|
gap: 6
|
|
1082
|
-
} }, react.createElement("span", {
|
|
1261
|
+
} }, react.createElement("span", {
|
|
1262
|
+
style: {
|
|
1263
|
+
color: STATUS_TEXT[item.status],
|
|
1264
|
+
fontWeight: 700,
|
|
1265
|
+
fontSize: 13,
|
|
1266
|
+
lineHeight: 1
|
|
1267
|
+
},
|
|
1268
|
+
"aria-hidden": "true"
|
|
1269
|
+
}, STATUS_MARK[item.status]), react.createElement("span", { style: {
|
|
1083
1270
|
width: 8,
|
|
1084
1271
|
height: 8,
|
|
1085
1272
|
borderRadius: "50%",
|
|
@@ -1089,9 +1276,32 @@ window.__ModuleLoader__.load({
|
|
|
1089
1276
|
fontWeight: 650,
|
|
1090
1277
|
color: INK
|
|
1091
1278
|
} }, item.title), react.createElement("span", { style: {
|
|
1092
|
-
color:
|
|
1279
|
+
color: STATUS_TEXT[item.status],
|
|
1093
1280
|
fontWeight: 700
|
|
1094
|
-
} }, STATUS_LABEL[item.status]), item.source ? react.createElement("span", { style: { color: INK_DIM } }, "· 来自" + item.source) : null), react.createElement("div", {
|
|
1281
|
+
} }, STATUS_LABEL[item.status]), item.source ? react.createElement("span", { style: { color: INK_DIM } }, "· 来自" + item.source) : null), react.createElement("div", {
|
|
1282
|
+
style: { color: INK },
|
|
1283
|
+
title: item.message
|
|
1284
|
+
}, shortenPathsIn(item.message, prefixes)), item.action.length > 0 ? react.createElement("div", { style: { color: INK_DIM } }, "去哪修:" + actionText(item.action)) : null)), report.items.some((item) => !isAttentionItem(item)) ? react.createElement("div", {
|
|
1285
|
+
"data-ilife-health": "ok",
|
|
1286
|
+
style: {
|
|
1287
|
+
display: "flex",
|
|
1288
|
+
flexWrap: "wrap",
|
|
1289
|
+
alignItems: "center",
|
|
1290
|
+
gap: "2px 10px",
|
|
1291
|
+
marginTop: 8,
|
|
1292
|
+
paddingTop: 6,
|
|
1293
|
+
borderTop: "1px solid " + BORDER,
|
|
1294
|
+
fontSize: 12,
|
|
1295
|
+
lineHeight: 1.6,
|
|
1296
|
+
color: INK_DIM
|
|
1297
|
+
}
|
|
1298
|
+
}, react.createElement("span", { style: {
|
|
1299
|
+
fontWeight: 650,
|
|
1300
|
+
color: INK
|
|
1301
|
+
} }, "正常 " + String(countByStatus(report.items).green) + " 条"), report.items.filter((item) => !isAttentionItem(item)).map((item) => react.createElement("span", {
|
|
1302
|
+
key: item.id,
|
|
1303
|
+
"data-ilife-health": "ok-item"
|
|
1304
|
+
}, "· " + item.title))) : null) : null);
|
|
1095
1305
|
}
|
|
1096
1306
|
//#endregion
|
|
1097
1307
|
//#region src/client.ts
|
|
@@ -1349,7 +1559,7 @@ window.__ModuleLoader__.load({
|
|
|
1349
1559
|
setActiveId(next.plugin);
|
|
1350
1560
|
tabRefs.current[nextIndex]?.focus();
|
|
1351
1561
|
}
|
|
1352
|
-
return react.createElement("div", null, react.createElement("div", { style: S.headRow }, react.createElement("div", { style: S.head }, "爱生活"), react.createElement("div", { style: S.headActions }, react.createElement(CheckUpdateButton, { face }), react.createElement(PanelActions, null))), react.createElement("div", { style: S.meta }, react.createElement("div", null, "总开关 · 开关(缺省启用,只读)"), react.createElement("div", null, "总管 dsh-life-pack · 0.2.
|
|
1562
|
+
return react.createElement("div", null, react.createElement("div", { style: S.headRow }, react.createElement("div", { style: S.head }, "爱生活"), react.createElement("div", { style: S.headActions }, react.createElement(CheckUpdateButton, { face }), react.createElement(PanelActions, null))), react.createElement("div", { style: S.meta }, react.createElement("div", null, "总开关 · 开关(缺省启用,只读)"), react.createElement("div", null, "总管 dsh-life-pack · 0.2.5")), react.createElement(UpdateResults, { face }), react.createElement(HealthOverview, {
|
|
1353
1563
|
lights: lightsOf(rows.map((row) => ({
|
|
1354
1564
|
id: row.id,
|
|
1355
1565
|
title: labelForTab(row.id)
|