@huaqiu/dsh-tool-plugin-update 0.6.7 → 0.6.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +1060 -324
- package/lib/client.js.map +1 -1
- package/package.json +3 -3
- package/src/client/copy.ts +93 -0
- package/src/client/index.ts +640 -1
- package/src/client/update-view.ts +502 -329
package/lib/client.js
CHANGED
|
@@ -718,6 +718,53 @@ window.__ModuleLoader__.load({
|
|
|
718
718
|
changesTitle: "更新内容",
|
|
719
719
|
advanced: "高级:更新源",
|
|
720
720
|
publishedAt: (when) => `发布于 ${when}`
|
|
721
|
+
},
|
|
722
|
+
ui: {
|
|
723
|
+
title: "更新中心",
|
|
724
|
+
gearTooltip: "高级设置",
|
|
725
|
+
settingsTitle: "更新源配置 (高级)",
|
|
726
|
+
originDefault: "默认源",
|
|
727
|
+
originCustom: "自定义源",
|
|
728
|
+
pluginUrlLabel: "插件 Manifest URL",
|
|
729
|
+
runtimeUrlLabel: "运行时 Manifest URL",
|
|
730
|
+
saveAndRefresh: "保存并刷新",
|
|
731
|
+
checkedAgo: (ago) => `上次检查: ${ago}`,
|
|
732
|
+
checkedUnknown: "尚未检查更新",
|
|
733
|
+
agoJust: "刚刚",
|
|
734
|
+
agoMinutes: (n) => `${n} 分钟前`,
|
|
735
|
+
agoHours: (n) => `${n} 小时前`,
|
|
736
|
+
agoDays: (n) => `${n} 天前`,
|
|
737
|
+
jobPluginTitle: (v) => `正在升级全套插件 (v${v})`,
|
|
738
|
+
jobRuntimeTitle: (v) => `正在升级 HQ Edge 运行时 (v${v})`,
|
|
739
|
+
jobSteps: [
|
|
740
|
+
"下载",
|
|
741
|
+
"校验",
|
|
742
|
+
"替换",
|
|
743
|
+
"重启"
|
|
744
|
+
],
|
|
745
|
+
rollbackTitle: "上次 HQ Edge 运行时更新已自动回滚",
|
|
746
|
+
failedTitle: "上次 HQ Edge 运行时更新失败",
|
|
747
|
+
rollbackBody: (oldVer, code) => `系统已安全恢复至旧版本 (v${oldVer})。代码: ${code}`,
|
|
748
|
+
failedBody: (oldVer, code) => `未能完成运行时替换 (旧版本 v${oldVer})。代码: ${code}`,
|
|
749
|
+
dismiss: "忽略",
|
|
750
|
+
successInline: "上次运行时更新成功",
|
|
751
|
+
runtimeEngine: "HQ Edge 核心运行时",
|
|
752
|
+
currentChip: (v) => `v${v} (当前)`,
|
|
753
|
+
newVersion: (v) => `新版本 v${v} 可用`,
|
|
754
|
+
breakingTag: "关键修复",
|
|
755
|
+
sizeLine: (size, summary) => `体积: ${size}${summary ? ` · ${summary}` : ""}`,
|
|
756
|
+
upgradeCore: "升级核心",
|
|
757
|
+
runtimeRestartNote: "升级运行时需自动重启 KiCad 进程服务",
|
|
758
|
+
pendingTitle: "待更新插件",
|
|
759
|
+
allChangelog: "展开全部更新日志",
|
|
760
|
+
changelogBtn: "日志",
|
|
761
|
+
changelogTitle: "更新内容:",
|
|
762
|
+
blockedBadge: "无法安装",
|
|
763
|
+
footerCount: (n) => `准备安装 ${n} 项兼容插件`,
|
|
764
|
+
footerSet: (v) => `版本集: v${v}`,
|
|
765
|
+
installAllSet: (v) => `一键更新全套插件 (v${v})`,
|
|
766
|
+
ignoreBtn: "忽略",
|
|
767
|
+
footnote: "更新将自动应用并重启 DSH 视图,不影响 EDA 图纸数据"
|
|
721
768
|
}
|
|
722
769
|
};
|
|
723
770
|
/** Compact a byte count for display: "约 12.3 MB" / "约 480 MB". */
|
|
@@ -864,6 +911,53 @@ window.__ModuleLoader__.load({
|
|
|
864
911
|
changesTitle: "What changed",
|
|
865
912
|
advanced: "Advanced: update sources",
|
|
866
913
|
publishedAt: (when) => `Published ${when}`
|
|
914
|
+
},
|
|
915
|
+
ui: {
|
|
916
|
+
title: "Update Center",
|
|
917
|
+
gearTooltip: "Advanced settings",
|
|
918
|
+
settingsTitle: "Update source (advanced)",
|
|
919
|
+
originDefault: "Default source",
|
|
920
|
+
originCustom: "Custom source",
|
|
921
|
+
pluginUrlLabel: "Plugin manifest URL",
|
|
922
|
+
runtimeUrlLabel: "Runtime manifest URL",
|
|
923
|
+
saveAndRefresh: "Save & refresh",
|
|
924
|
+
checkedAgo: (ago) => `Last checked: ${ago}`,
|
|
925
|
+
checkedUnknown: "No check yet",
|
|
926
|
+
agoJust: "just now",
|
|
927
|
+
agoMinutes: (n) => `${n} min ago`,
|
|
928
|
+
agoHours: (n) => `${n} h ago`,
|
|
929
|
+
agoDays: (n) => `${n} d ago`,
|
|
930
|
+
jobPluginTitle: (v) => `Updating plugin set (v${v})`,
|
|
931
|
+
jobRuntimeTitle: (v) => `Upgrading HQ Edge runtime (v${v})`,
|
|
932
|
+
jobSteps: [
|
|
933
|
+
"Download",
|
|
934
|
+
"Verify",
|
|
935
|
+
"Swap",
|
|
936
|
+
"Restart"
|
|
937
|
+
],
|
|
938
|
+
rollbackTitle: "Last HQ Edge runtime update rolled back automatically",
|
|
939
|
+
failedTitle: "Last HQ Edge runtime update failed",
|
|
940
|
+
rollbackBody: (oldVer, code) => `Safely restored to the previous version (v${oldVer}). Code: ${code}`,
|
|
941
|
+
failedBody: (oldVer, code) => `Runtime swap did not complete (old v${oldVer}). Code: ${code}`,
|
|
942
|
+
dismiss: "Dismiss",
|
|
943
|
+
successInline: "Last runtime update succeeded",
|
|
944
|
+
runtimeEngine: "HQ Core Runtime",
|
|
945
|
+
currentChip: (v) => `v${v} (current)`,
|
|
946
|
+
newVersion: (v) => `New v${v} available`,
|
|
947
|
+
breakingTag: "Critical fix",
|
|
948
|
+
sizeLine: (size, summary) => `Size: ${size}${summary ? ` · ${summary}` : ""}`,
|
|
949
|
+
upgradeCore: "Upgrade core",
|
|
950
|
+
runtimeRestartNote: "Upgrading the runtime restarts the KiCad process service",
|
|
951
|
+
pendingTitle: "Plugins to update",
|
|
952
|
+
allChangelog: "Expand all changelogs",
|
|
953
|
+
changelogBtn: "Log",
|
|
954
|
+
changelogTitle: "What changed:",
|
|
955
|
+
blockedBadge: "Cannot install",
|
|
956
|
+
footerCount: (n) => `Ready to install ${n} compatible plugin${n === 1 ? "" : "s"}`,
|
|
957
|
+
footerSet: (v) => `Set: v${v}`,
|
|
958
|
+
installAllSet: (v) => `Update all plugins (v${v})`,
|
|
959
|
+
ignoreBtn: "Ignore",
|
|
960
|
+
footnote: "Updates apply automatically and restart the DSH view — your EDA schematic data is untouched"
|
|
867
961
|
}
|
|
868
962
|
}
|
|
869
963
|
};
|
|
@@ -918,18 +1012,6 @@ window.__ModuleLoader__.load({
|
|
|
918
1012
|
]);
|
|
919
1013
|
/** The settled-state glyph (`IconCheckCircleFillRegular`). */
|
|
920
1014
|
const CHECK_CIRCLE_ICON = (size = 16) => fillGlyph(size, ["M28.1936 14.6936L19.8066 23.0806C19.2373 23.65 18.7159 24.1742 18.24 24.5571C17.7389 24.9602 17.1365 25.3359 16.3657 25.458C15.9581 25.5225 15.5428 25.5225 15.1353 25.458C14.3645 25.3359 13.7621 24.9602 13.261 24.5571C12.7851 24.1742 12.2637 23.65 11.6943 23.0806L7.80737 19.1936L10.1936 16.8074L14.0806 20.6943C14.7033 21.317 15.0763 21.6873 15.377 21.9292C15.6523 22.1507 15.7109 22.1325 15.6626 22.1248C15.7208 22.1339 15.7802 22.1339 15.8384 22.1248C15.7901 22.1325 15.8486 22.1507 16.124 21.9292C16.4247 21.6873 16.7977 21.317 17.4204 20.6943L25.8074 12.3074L28.1936 14.6936Z", "M32.8496 18.0005C32.8496 9.79906 26.2019 3.15137 18.0005 3.15137C9.79906 3.15137 3.15137 9.79906 3.15137 18.0005C3.15137 26.2019 9.79906 32.8496 18.0005 32.8496C26.2019 32.8496 32.8496 26.2019 32.8496 18.0005ZM35.7764 18.0005C35.7764 27.8173 27.8173 35.7764 18.0005 35.7764C8.18363 35.7764 0.224609 27.8173 0.224609 18.0005C0.224609 8.18363 8.18363 0.224609 18.0005 0.224609C27.8173 0.224609 35.7764 8.18363 35.7764 18.0005Z"], "0 0 36 36");
|
|
921
|
-
/** The install action (`IconDownloadOutlineRegular`). */
|
|
922
|
-
const DOWNLOAD_ICON = (size = 16) => glyph(size, REGULAR, [
|
|
923
|
-
"M8 1.95317V10.0469",
|
|
924
|
-
"M4.25 6.29688L8 10.0469L11.75 6.29688",
|
|
925
|
-
"M1.5 10.0469V13.158C1.5 13.3937 1.60536 13.6198 1.79289 13.7865C1.98043 13.9532 2.23478 14.0469 2.5 14.0469H13.5C13.7652 14.0469 14.0196 13.9532 14.2071 13.7865C14.3946 13.6198 14.5 13.3937 14.5 13.158V10.0469"
|
|
926
|
-
]);
|
|
927
|
-
/** The head's info affordance (`IconInfoOutlineRegular`, fill-only artwork). */
|
|
928
|
-
const INFO_ICON = (size = 11) => fillGlyph(size, [
|
|
929
|
-
"M12.5757 7.00012C12.5757 3.92085 10.0794 1.42463 7.00012 1.42456C3.9208 1.42456 1.42456 3.9208 1.42456 7.00012C1.42463 10.0794 3.92085 12.5757 7.00012 12.5757C10.0793 12.5756 12.5756 10.0793 12.5757 7.00012ZM13.8002 7.00012C13.8001 10.7559 10.7559 13.8001 7.00012 13.8002C3.2443 13.8002 0.199291 10.7559 0.199219 7.00012C0.199219 3.24426 3.24426 0.199219 7.00012 0.199219C10.7559 0.199291 13.8002 3.2443 13.8002 7.00012Z",
|
|
930
|
-
"M7.6127 3.18921V4.55986H6.38735V3.18921H7.6127Z",
|
|
931
|
-
"M7.6127 5.68921V10.8109H6.38735V5.68921H7.6127Z"
|
|
932
|
-
], "0 0 14 14");
|
|
933
1015
|
//#endregion
|
|
934
1016
|
//#region src/client/update-view.ts
|
|
935
1017
|
/**
|
|
@@ -983,33 +1065,6 @@ window.__ModuleLoader__.load({
|
|
|
983
1065
|
if (Array.isArray(by)) return by.filter((entry) => typeof entry === "string");
|
|
984
1066
|
return typeof by === "string" && by.length > 0 ? [by] : [];
|
|
985
1067
|
}
|
|
986
|
-
/** The tag tone a state reads as, matching the shell's Tag palette. */
|
|
987
|
-
function stateTone(item) {
|
|
988
|
-
switch (item.state) {
|
|
989
|
-
case "update": return "info";
|
|
990
|
-
case "install": return "warning";
|
|
991
|
-
case "blocked": return "danger";
|
|
992
|
-
case "ignored": return "neutral";
|
|
993
|
-
case "current": return "success";
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
function stateLabel(item, copy) {
|
|
997
|
-
switch (item.state) {
|
|
998
|
-
case "current": return copy.state.current;
|
|
999
|
-
case "update": return copy.state.update;
|
|
1000
|
-
case "install": return copy.state.install;
|
|
1001
|
-
case "ignored": return copy.state.ignored;
|
|
1002
|
-
case "blocked": return copy.state.blocked;
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
/** The one-line version transition under a card's title. */
|
|
1006
|
-
function versionLine(item) {
|
|
1007
|
-
switch (item.state) {
|
|
1008
|
-
case "current": return item.currentVersion ?? item.availableVersion;
|
|
1009
|
-
case "install": return item.availableVersion;
|
|
1010
|
-
default: return item.currentVersion === null ? item.availableVersion : `${item.currentVersion} → ${item.availableVersion}`;
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
1068
|
function blockedReason(item, copy) {
|
|
1014
1069
|
const by = blockedByList(item);
|
|
1015
1070
|
if (by.includes("host")) return copy.blockedReason.host;
|
|
@@ -1017,72 +1072,93 @@ window.__ModuleLoader__.load({
|
|
|
1017
1072
|
if (by.includes("runtime-unknown")) return copy.blockedReason["runtime-unknown"];
|
|
1018
1073
|
return by.length > 0 ? by.join(", ") : void 0;
|
|
1019
1074
|
}
|
|
1020
|
-
/**
|
|
1021
|
-
function
|
|
1022
|
-
const
|
|
1075
|
+
/** Two-letter avatar initials for a card (CJK-safe). */
|
|
1076
|
+
function avatarInitials(item) {
|
|
1077
|
+
const src = typeof item.displayName === "string" && item.displayName.trim().length > 0 ? item.displayName.trim() : shortName(item.name);
|
|
1078
|
+
if (/[⺀-鿿]/.test(src)) return src.slice(0, 2);
|
|
1079
|
+
const words = src.split(/[\s_\-./@]+/).filter(Boolean);
|
|
1080
|
+
if (words.length >= 2) return (words[0][0] + words[1][0]).toUpperCase();
|
|
1081
|
+
return src.replace(/^@/, "").slice(0, 2).toUpperCase();
|
|
1082
|
+
}
|
|
1083
|
+
/** Shared per-card changelog toggle drawer (the per-plugin changes[] list). */
|
|
1084
|
+
function changelogDrawer(item, copy, open) {
|
|
1085
|
+
const drawer = el("div", "hqpu-changelog-drawer");
|
|
1086
|
+
drawer.style.display = open ? "" : "none";
|
|
1087
|
+
drawer.append(el("div", "hqpu-changelog-drawer-title", copy.ui.changelogTitle));
|
|
1088
|
+
const ul = el("ul");
|
|
1089
|
+
for (const change of item.changes ?? []) if (typeof change === "string" && change.length > 0) ul.append(el("li", "", change));
|
|
1090
|
+
drawer.append(ul);
|
|
1091
|
+
return drawer;
|
|
1092
|
+
}
|
|
1093
|
+
/** One package card per the mockup: avatar initials, display name + package
|
|
1094
|
+
* subtitle, old→new version row (new in emerald), a 日志 toggle expanding the
|
|
1095
|
+
* inline changelog. Blocked/incompatible cards are dimmed with a rose
|
|
1096
|
+
* 无法安装 badge and a reason line, and carry NO install button. */
|
|
1097
|
+
function packageCard(item, copy, open, onToggle) {
|
|
1098
|
+
const blocked = item.state === "blocked";
|
|
1099
|
+
const card = el("li", blocked ? "hqpu-card hqpu-card--blocked" : "hqpu-card");
|
|
1023
1100
|
card.dataset.pluginName = item.name;
|
|
1024
1101
|
card.dataset.state = item.state;
|
|
1025
|
-
card.title = `${item.name} · ${versionLine(item)}`;
|
|
1026
1102
|
const head = el("div", "hqpu-card-head");
|
|
1027
|
-
const
|
|
1028
|
-
|
|
1029
|
-
|
|
1103
|
+
const left = el("div");
|
|
1104
|
+
const avatar = el("span", "hqpu-avatar", avatarInitials(item));
|
|
1105
|
+
avatar.setAttribute("aria-hidden", "true");
|
|
1030
1106
|
const main = el("div", "hqpu-card-main");
|
|
1031
|
-
const
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
const desc = el("span", "hqpu-card-desc", size.length > 0 ? `${versionLine(item)} · ${size}` : versionLine(item));
|
|
1039
|
-
main.append(titleRow, desc);
|
|
1040
|
-
if (typeof item.description === "string" && item.description.trim().length > 0) main.append(el("span", "hqpu-card-desc", item.description.trim()));
|
|
1041
|
-
head.append(glyph, main);
|
|
1042
|
-
const end = el("div", "hqpu-card-end");
|
|
1043
|
-
if (item.state === "update" || item.state === "install") {
|
|
1044
|
-
const button = el("button", "hqpu-btn hqpu-btn--sm hqpu-btn--primary");
|
|
1045
|
-
button.type = "button";
|
|
1046
|
-
button.disabled = installing;
|
|
1047
|
-
button.innerHTML = `${DOWNLOAD_ICON(13)}<span>${copy.installOne}</span>`;
|
|
1048
|
-
button.title = copy.installOneTip;
|
|
1049
|
-
button.addEventListener("click", () => {
|
|
1050
|
-
runInstall(store, copy);
|
|
1051
|
-
});
|
|
1052
|
-
end.append(button);
|
|
1107
|
+
const titleText = typeof item.displayName === "string" && item.displayName.trim().length > 0 ? item.displayName.trim() : shortName(item.name);
|
|
1108
|
+
main.append(el("span", "hqpu-card-title", titleText));
|
|
1109
|
+
main.append(el("span", "hqpu-card-sub", shortName(item.name)));
|
|
1110
|
+
const ver = el("div", "hqpu-version-row");
|
|
1111
|
+
if (item.currentVersion !== null && item.currentVersion !== void 0) {
|
|
1112
|
+
ver.append(el("span", "hqpu-ver-old", item.currentVersion));
|
|
1113
|
+
ver.append(el("span", "hqpu-ver-arrow", "→"));
|
|
1053
1114
|
}
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1115
|
+
const size = formatMb(item.sizeBytes ?? 0);
|
|
1116
|
+
ver.append(el("span", "hqpu-ver-new", size.length > 0 ? `${item.availableVersion} (${size})` : item.availableVersion));
|
|
1117
|
+
main.append(ver);
|
|
1118
|
+
left.append(avatar, main);
|
|
1119
|
+
const right = el("div", "hqpu-card-end");
|
|
1120
|
+
if (blocked) right.append(el("span", "hqpu-blocked-badge", copy.ui.blockedBadge));
|
|
1121
|
+
else if (Array.isArray(item.changes) && item.changes.length > 0) {
|
|
1122
|
+
const toggle = el("button", "hqpu-log-toggle");
|
|
1059
1123
|
toggle.type = "button";
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
list.style.display = list.style.display === "none" ? "" : "none";
|
|
1065
|
-
});
|
|
1066
|
-
expander.append(toggle, list);
|
|
1067
|
-
card.append(expander);
|
|
1124
|
+
toggle.dataset.open = open ? "true" : "false";
|
|
1125
|
+
toggle.innerHTML = `${copy.ui.changelogBtn}<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 6L7.29289 9.29289C7.68342 9.68342 8.31658 9.68342 8.70711 9.29289L12 6"/></svg>`;
|
|
1126
|
+
toggle.addEventListener("click", onToggle);
|
|
1127
|
+
right.append(toggle);
|
|
1068
1128
|
}
|
|
1069
|
-
|
|
1129
|
+
head.append(left, right);
|
|
1130
|
+
card.append(head);
|
|
1131
|
+
if (!blocked && Array.isArray(item.changes) && item.changes.length > 0) card.append(changelogDrawer(item, copy, open));
|
|
1132
|
+
if (blocked) {
|
|
1070
1133
|
const reason = blockedReason(item, copy);
|
|
1071
|
-
|
|
1072
|
-
for (const entry of
|
|
1134
|
+
const entries = [...reason !== void 0 ? [reason] : [], ...[...item.reasons ?? [], ...item.notes ?? []].filter((e) => typeof e === "string" && e.length > 0)];
|
|
1135
|
+
for (const entry of entries) {
|
|
1136
|
+
const line = el("p", "hqpu-reason-line");
|
|
1137
|
+
line.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 5V8.5M8 11.25h.01M14.5 8a6.5 6.5 0 11-13 0 6.5 6.5 0 0113 0Z"/></svg>`;
|
|
1138
|
+
line.append(document.createTextNode(entry));
|
|
1139
|
+
card.append(line);
|
|
1140
|
+
}
|
|
1073
1141
|
}
|
|
1074
1142
|
return card;
|
|
1075
1143
|
}
|
|
1076
|
-
/** A section:
|
|
1077
|
-
function group(heading, items, copy,
|
|
1144
|
+
/** A section: head (title + count pill + expand-all toggle) then its cards. */
|
|
1145
|
+
function group(heading, items, copy, changelogOpen, allOpen, onToggle, onToggleAll) {
|
|
1078
1146
|
if (items.length === 0) return null;
|
|
1079
1147
|
const section = el("section", "hqpu-group");
|
|
1080
1148
|
section.dataset.group = heading;
|
|
1081
|
-
const head = el("div", "hqpu-
|
|
1082
|
-
|
|
1083
|
-
|
|
1149
|
+
const head = el("div", "hqpu-section-head");
|
|
1150
|
+
const titleWrap = el("div", "hqpu-section-title");
|
|
1151
|
+
titleWrap.append(el("span", "", heading));
|
|
1152
|
+
titleWrap.append(el("span", "hqpu-count-pill", String(items.length)));
|
|
1153
|
+
head.append(titleWrap);
|
|
1154
|
+
if (items.some((i) => i.state !== "blocked" && Array.isArray(i.changes) && i.changes.length > 0)) {
|
|
1155
|
+
const all = el("button", "hqpu-all-changelog", copy.ui.allChangelog);
|
|
1156
|
+
all.type = "button";
|
|
1157
|
+
all.addEventListener("click", onToggleAll);
|
|
1158
|
+
head.append(all);
|
|
1159
|
+
}
|
|
1084
1160
|
const list = el("ul", "hqpu-cards");
|
|
1085
|
-
for (const item of items) list.append(packageCard(item, copy,
|
|
1161
|
+
for (const item of items) list.append(packageCard(item, copy, allOpen || changelogOpen.has(item.name), () => onToggle(item.name)));
|
|
1086
1162
|
section.append(head, list);
|
|
1087
1163
|
return section;
|
|
1088
1164
|
}
|
|
@@ -1130,13 +1206,17 @@ window.__ModuleLoader__.load({
|
|
|
1130
1206
|
if (n >= 1024) return `${(n / 1024).toFixed(0)} KB`;
|
|
1131
1207
|
return `${n} B`;
|
|
1132
1208
|
}
|
|
1133
|
-
/**
|
|
1134
|
-
function
|
|
1135
|
-
if (
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1209
|
+
/** "上次检查: N 分钟前" — relative time from an ISO timestamp. */
|
|
1210
|
+
function relativeAgo(iso, copy) {
|
|
1211
|
+
if (typeof iso !== "string" || iso.length === 0) return null;
|
|
1212
|
+
const then = new Date(iso).getTime();
|
|
1213
|
+
if (!Number.isFinite(then)) return null;
|
|
1214
|
+
const diffMin = Math.round((Date.now() - then) / 6e4);
|
|
1215
|
+
if (diffMin < 1) return copy.ui.agoJust;
|
|
1216
|
+
if (diffMin < 60) return copy.ui.agoMinutes(diffMin);
|
|
1217
|
+
const hours = Math.round(diffMin / 60);
|
|
1218
|
+
if (hours < 24) return copy.ui.agoHours(hours);
|
|
1219
|
+
return copy.ui.agoDays(Math.round(hours / 24));
|
|
1140
1220
|
}
|
|
1141
1221
|
function jobKindLabel(job, copy) {
|
|
1142
1222
|
return job.kind === "runtime" ? copy.job.kindRuntime : copy.job.kindPluginSet;
|
|
@@ -1163,29 +1243,40 @@ window.__ModuleLoader__.load({
|
|
|
1163
1243
|
wrap.append(ol);
|
|
1164
1244
|
return wrap;
|
|
1165
1245
|
}
|
|
1246
|
+
/** Map a job phase onto the 4-step indicator index (下载/校验/替换/重启). */
|
|
1247
|
+
function stepIndex(phase) {
|
|
1248
|
+
switch (phase) {
|
|
1249
|
+
case "downloading": return 0;
|
|
1250
|
+
case "verifying":
|
|
1251
|
+
case "resolving": return 1;
|
|
1252
|
+
case "staging":
|
|
1253
|
+
case "activating":
|
|
1254
|
+
case "awaiting-host": return 2;
|
|
1255
|
+
case "restarting":
|
|
1256
|
+
case "verifying-after-restart": return 3;
|
|
1257
|
+
case "queued": return -1;
|
|
1258
|
+
default: return -1;
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1166
1261
|
/**
|
|
1167
|
-
* The ACTIVE-JOB
|
|
1168
|
-
*
|
|
1169
|
-
*
|
|
1170
|
-
*
|
|
1262
|
+
* The ACTIVE-JOB banner per the mockup: pulsing brand dot + job title with the
|
|
1263
|
+
* target version, mono percentage, a gradient bar only when `percent != null`,
|
|
1264
|
+
* phase + speed line ("3.1 MB/s (286MB / 450MB)"), and a 4-step indicator row
|
|
1265
|
+
* (done=emerald, active=pulsing brand, upcoming=muted).
|
|
1171
1266
|
*/
|
|
1172
1267
|
function activeJobView(job, copy) {
|
|
1173
1268
|
const section = el("section", "hqpu-group");
|
|
1174
1269
|
section.dataset.group = "active-job";
|
|
1175
|
-
const
|
|
1176
|
-
const
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
const phaseLine = el("p", "hqpu-status hqpu-status--dot");
|
|
1183
|
-
phaseLine.append(el("span", "hqpu-spinner"));
|
|
1184
|
-
const transition = job.previousVersion !== null && job.previousVersion.length > 0 ? `${job.previousVersion} → ${job.targetVersion} · ${phaseLabel(job, copy)}` : `${job.targetVersion} · ${phaseLabel(job, copy)}`;
|
|
1185
|
-
phaseLine.append(el("span", "", transition));
|
|
1186
|
-
card.append(phaseLine);
|
|
1187
|
-
if (typeof job.message === "string" && job.message.length > 0) card.append(el("p", "hqpu-status", job.message));
|
|
1270
|
+
const card = el("div", "hqpu-active");
|
|
1271
|
+
const top = el("div", "hqpu-active-top");
|
|
1272
|
+
const titleWrap = el("div", "hqpu-active-title");
|
|
1273
|
+
const pulse = el("span", "hqpu-pulse-dot");
|
|
1274
|
+
pulse.append(el("span", "hqpu-pulse-ring"));
|
|
1275
|
+
const title = job.kind === "runtime" ? copy.ui.jobRuntimeTitle(job.targetVersion) : copy.ui.jobPluginTitle(job.targetVersion);
|
|
1276
|
+
titleWrap.append(pulse, el("span", "", title));
|
|
1188
1277
|
const pct = job.progress.percent;
|
|
1278
|
+
if (pct !== null) top.append(el("span", "hqpu-active-percent", `${Math.round(pct)}%`));
|
|
1279
|
+
card.append(top);
|
|
1189
1280
|
if (pct !== null) {
|
|
1190
1281
|
const bar = el("div", "hqpu-progress");
|
|
1191
1282
|
const fill = el("div", "hqpu-progress-fill");
|
|
@@ -1193,20 +1284,27 @@ window.__ModuleLoader__.load({
|
|
|
1193
1284
|
bar.append(fill);
|
|
1194
1285
|
card.append(bar);
|
|
1195
1286
|
}
|
|
1196
|
-
const
|
|
1197
|
-
|
|
1287
|
+
const meta = el("div", "hqpu-active-meta");
|
|
1288
|
+
const phaseText = typeof job.message === "string" && job.message.length > 0 ? job.message : phaseLabel(job, copy);
|
|
1289
|
+
meta.append(el("span", "", phaseText));
|
|
1290
|
+
const speed = formatBytes(job.progress.bytesPerSecond);
|
|
1198
1291
|
const done = formatBytes(job.progress.bytesDone);
|
|
1199
1292
|
const total = formatBytes(job.progress.bytesTotal);
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
const
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1293
|
+
const telemetry = speed !== null && done !== null && total !== null ? `${speed}/s (${done} / ${total})` : speed !== null ? `${speed}/s` : done !== null && total !== null ? copy.job.bytes(done, total) : "";
|
|
1294
|
+
if (telemetry.length > 0) meta.append(el("span", "", telemetry));
|
|
1295
|
+
card.append(meta);
|
|
1296
|
+
const transition = el("div", "hqpu-active-meta");
|
|
1297
|
+
transition.append(el("span", "", job.previousVersion !== null && job.previousVersion.length > 0 ? `${job.previousVersion} → ${job.targetVersion}` : job.targetVersion));
|
|
1298
|
+
transition.append(el("span", "", job.kind === "runtime" ? copy.job.willSwapRuntime : copy.job.willRestartDsh));
|
|
1299
|
+
card.append(transition);
|
|
1300
|
+
card.append(el("p", "hqpu-job-meta", copy.job.closeNote));
|
|
1301
|
+
const current = stepIndex(job.phase);
|
|
1302
|
+
const stepsRow = el("div", "hqpu-job-steps4");
|
|
1303
|
+
copy.ui.jobSteps.forEach((label, index) => {
|
|
1304
|
+
const cls = current === -1 ? "hqpu-job-step--todo" : index < current ? "hqpu-job-step--done" : index === current ? "hqpu-job-step--active" : "hqpu-job-step--todo";
|
|
1305
|
+
stepsRow.append(el("div", cls, label));
|
|
1306
|
+
});
|
|
1307
|
+
card.append(stepsRow);
|
|
1210
1308
|
section.append(card);
|
|
1211
1309
|
return section;
|
|
1212
1310
|
}
|
|
@@ -1328,14 +1426,6 @@ window.__ModuleLoader__.load({
|
|
|
1328
1426
|
}
|
|
1329
1427
|
return section;
|
|
1330
1428
|
}
|
|
1331
|
-
/** Native disclosure that hides the developer-facing source editors by
|
|
1332
|
-
* default (end users should never need to type a manifest URL). */
|
|
1333
|
-
function advancedBlock(copy, nodes) {
|
|
1334
|
-
const details = el("details", "hqpu-advanced");
|
|
1335
|
-
details.append(el("summary", "", copy.release.advanced));
|
|
1336
|
-
for (const node of nodes) if (node !== null) details.append(node);
|
|
1337
|
-
return details;
|
|
1338
|
-
}
|
|
1339
1429
|
/**
|
|
1340
1430
|
* Normalize the report's `runtime.source` to the full shape.
|
|
1341
1431
|
*
|
|
@@ -1354,29 +1444,6 @@ window.__ModuleLoader__.load({
|
|
|
1354
1444
|
override: candidate.override === true
|
|
1355
1445
|
};
|
|
1356
1446
|
}
|
|
1357
|
-
/** The tag naming where the URL in effect came from. */
|
|
1358
|
-
function originLabel(origin, copy) {
|
|
1359
|
-
switch (origin) {
|
|
1360
|
-
case "override": return copy.originOverride;
|
|
1361
|
-
case "config": return copy.originConfig;
|
|
1362
|
-
default: return copy.originUnset;
|
|
1363
|
-
}
|
|
1364
|
-
}
|
|
1365
|
-
/** The 更新源 fact row: the URL in effect plus an origin tag. */
|
|
1366
|
-
function sourceFactRow(facts, source, copy) {
|
|
1367
|
-
const wrap = el("div");
|
|
1368
|
-
wrap.append(el("dt", "", copy.runtime.source));
|
|
1369
|
-
const dd = el("dd");
|
|
1370
|
-
const line = el("div", "hqpu-source-line");
|
|
1371
|
-
const code = el("code", "hqpu-source-url", source.url.length > 0 ? source.url : copy.runtime.notConfigured);
|
|
1372
|
-
const tag = el("span", "hqpu-tag");
|
|
1373
|
-
tag.dataset.tone = source.override ? "info" : source.origin === "config" ? "success" : "neutral";
|
|
1374
|
-
tag.textContent = originLabel(source.origin, copy);
|
|
1375
|
-
line.append(code, tag);
|
|
1376
|
-
dd.append(line);
|
|
1377
|
-
wrap.append(dd);
|
|
1378
|
-
facts.append(wrap);
|
|
1379
|
-
}
|
|
1380
1447
|
/** Pick the labels for one kind out of the copy table. */
|
|
1381
1448
|
function sourceLabels(copy, kind) {
|
|
1382
1449
|
return kind === "runtime" ? {
|
|
@@ -1409,6 +1476,9 @@ window.__ModuleLoader__.load({
|
|
|
1409
1476
|
const labels = sourceLabels(copy, kind);
|
|
1410
1477
|
const block = el("div", `hqpu-source-editor hqpu-source-editor--${kind}`);
|
|
1411
1478
|
if (!actions.sourceEditing) {
|
|
1479
|
+
const urlLine = el("p", "hqpu-source-current-url", source.url);
|
|
1480
|
+
urlLine.style.cssText = "margin:2px 0 6px;font-size:9px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;color:#a1a1aa;word-break:break-all;";
|
|
1481
|
+
block.append(urlLine);
|
|
1412
1482
|
block.append(el("p", "hqpu-status hqpu-source-hint", labels.hint));
|
|
1413
1483
|
const edit = el("button", "hqpu-btn hqpu-btn--outline hqpu-btn--sm", labels.edit);
|
|
1414
1484
|
edit.type = "button";
|
|
@@ -1463,125 +1533,108 @@ window.__ModuleLoader__.load({
|
|
|
1463
1533
|
return block;
|
|
1464
1534
|
}
|
|
1465
1535
|
/**
|
|
1466
|
-
* The
|
|
1467
|
-
*
|
|
1468
|
-
*
|
|
1469
|
-
*
|
|
1536
|
+
* The host's own report of the last runtime swap. Rolled-back / failed renders
|
|
1537
|
+
* as an AMBER alert card (title, old→new body, errorCode chip, 忽略 dismiss);
|
|
1538
|
+
* succeeded renders as a subtle green inline line — not a loud banner. The
|
|
1539
|
+
* plugin has NO log-open affordance, so "查看诊断日志" is omitted (never faked).
|
|
1470
1540
|
*/
|
|
1471
|
-
function
|
|
1472
|
-
const
|
|
1473
|
-
if (
|
|
1541
|
+
function runtimeResultAlert(report, copy, dismissed, onDismiss) {
|
|
1542
|
+
const lastResult = report.runtime.lastResult;
|
|
1543
|
+
if (lastResult === null || lastResult === void 0) return null;
|
|
1544
|
+
if (lastResult.state === "succeeded") {
|
|
1545
|
+
const line = el("p", "hqpu-alert-green");
|
|
1546
|
+
line.dataset.role = "runtime-success";
|
|
1547
|
+
line.textContent = copy.ui.successInline;
|
|
1548
|
+
return line;
|
|
1549
|
+
}
|
|
1550
|
+
if (dismissed) return null;
|
|
1474
1551
|
const section = el("section", "hqpu-group");
|
|
1475
|
-
section.dataset.group = "
|
|
1476
|
-
const
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
const
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1552
|
+
section.dataset.group = "runtime-alert";
|
|
1553
|
+
const card = el("div", "hqpu-alert hqpu-alert--amber");
|
|
1554
|
+
card.innerHTML = WARNING_ICON(14);
|
|
1555
|
+
const body = el("div");
|
|
1556
|
+
const title = el("div", "hqpu-alert-title");
|
|
1557
|
+
title.textContent = lastResult.state === "failed" ? copy.ui.failedTitle : copy.ui.rollbackTitle;
|
|
1558
|
+
body.append(title);
|
|
1559
|
+
const oldVer = lastResult.installedVersion ?? lastResult.targetVersion ?? "—";
|
|
1560
|
+
const code = typeof lastResult.errorCode === "string" && lastResult.errorCode.length > 0 ? lastResult.errorCode : "—";
|
|
1561
|
+
lastResult.state === "failed" ? copy.ui.failedBody(oldVer, code) : copy.ui.rollbackBody(oldVer, code);
|
|
1562
|
+
const bodyP = el("p", "hqpu-alert-body");
|
|
1563
|
+
const textOnly = lastResult.state === "failed" ? copy.ui.failedBody(oldVer, "") : copy.ui.rollbackBody(oldVer, "");
|
|
1564
|
+
bodyP.append(document.createTextNode(textOnly.replace(/\s*$/, "")));
|
|
1565
|
+
if (typeof lastResult.errorCode === "string" && lastResult.errorCode.length > 0) {
|
|
1566
|
+
bodyP.append(document.createTextNode(" "));
|
|
1567
|
+
const chip = el("code", "", lastResult.errorCode);
|
|
1568
|
+
bodyP.append(chip);
|
|
1569
|
+
}
|
|
1570
|
+
if (typeof lastResult.message === "string" && lastResult.message.length > 0) bodyP.append(el("br"), document.createTextNode(lastResult.message));
|
|
1571
|
+
body.append(bodyP);
|
|
1572
|
+
const actions = el("div", "hqpu-alert-actions");
|
|
1573
|
+
const dismiss = el("button", "hqpu-alert-dismiss", copy.ui.dismiss);
|
|
1574
|
+
dismiss.type = "button";
|
|
1575
|
+
dismiss.addEventListener("click", onDismiss);
|
|
1576
|
+
actions.append(dismiss);
|
|
1577
|
+
body.append(actions);
|
|
1578
|
+
card.append(body);
|
|
1579
|
+
section.append(card);
|
|
1483
1580
|
return section;
|
|
1484
1581
|
}
|
|
1485
|
-
/** The
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
const head = el("div", "hqpu-group-head");
|
|
1490
|
-
head.append(el("h3", "hqpu-group-title", copy.runtime.title));
|
|
1491
|
-
section.append(head);
|
|
1492
|
-
const facts = el("dl", "hqpu-facts");
|
|
1582
|
+
/** The HQ Edge runtime engine card per the mockup: current chip, "新版本 vY
|
|
1583
|
+
* 可用" with a 关键修复 tag when breaking/notes exist, size+summary line, a
|
|
1584
|
+
* 升级核心 button (existing arm→confirm flow), and the amber restart note. */
|
|
1585
|
+
function runtimeEngineCard(report, copy, actions) {
|
|
1493
1586
|
const runtime = report.runtime;
|
|
1494
1587
|
const latestVersion = runtimeLatestVersion(runtime);
|
|
1495
|
-
const
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
facts.append(wrap);
|
|
1505
|
-
};
|
|
1506
|
-
const source = normalizeSource(runtime.source);
|
|
1507
|
-
if (runtime.configured === false) {
|
|
1508
|
-
if (source !== null) sourceFactRow(facts, source, copy);
|
|
1509
|
-
else row(copy.runtime.source, copy.runtime.notConfigured);
|
|
1510
|
-
} else {
|
|
1511
|
-
row(copy.runtime.current, runtime.currentVersion ?? copy.runtime.unknown);
|
|
1512
|
-
if (runtime.updateAvailable && latestVersion !== null) {
|
|
1513
|
-
row(copy.runtime.latest, latestVersion);
|
|
1514
|
-
const latestEntry = runtime.latest;
|
|
1515
|
-
const size = typeof latestEntry?.sizeBytes === "number" ? formatMb(latestEntry.sizeBytes) : "";
|
|
1516
|
-
if (size.length > 0) row(copy.runtime.sizeLabel, size);
|
|
1517
|
-
}
|
|
1518
|
-
if (report.manifestVersion !== null) row(copy.runtime.set, report.manifestVersion, true);
|
|
1519
|
-
if (typeof runtime.checkedAt === "string" && runtime.checkedAt.length > 0) row(copy.runtime.checkedAt, new Date(runtime.checkedAt).toLocaleString());
|
|
1520
|
-
if (source !== null) sourceFactRow(facts, source, copy);
|
|
1521
|
-
}
|
|
1522
|
-
section.append(facts);
|
|
1523
|
-
if (source !== null) section.append(advancedBlock(copy, [sourceEditor("runtime", source, copy, actions)]));
|
|
1588
|
+
const card = el("section", "hqpu-engine");
|
|
1589
|
+
card.dataset.group = "runtime";
|
|
1590
|
+
const head = el("div", "hqpu-engine-head");
|
|
1591
|
+
const titleWrap = el("div", "hqpu-engine-title");
|
|
1592
|
+
titleWrap.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.33333 2L4.66667 8H8L6.66667 14L11.33333 8H8L9.33333 2Z"/></svg>`;
|
|
1593
|
+
titleWrap.append(el("span", "", copy.ui.runtimeEngine));
|
|
1594
|
+
head.append(titleWrap);
|
|
1595
|
+
if (typeof runtime.currentVersion === "string" && runtime.currentVersion.length > 0) head.append(el("span", "hqpu-chip", copy.ui.currentChip(runtime.currentVersion)));
|
|
1596
|
+
card.append(head);
|
|
1524
1597
|
if (runtime.updateAvailable && latestVersion !== null) {
|
|
1525
|
-
const row = el("div", "hqpu-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1598
|
+
const row = el("div", "hqpu-engine-update-row");
|
|
1599
|
+
const left = el("div");
|
|
1600
|
+
const newLine = el("div", "hqpu-engine-new-line");
|
|
1601
|
+
newLine.append(el("span", "", copy.ui.newVersion(latestVersion)));
|
|
1602
|
+
const latestEntry = runtime.latest;
|
|
1603
|
+
if (Array.isArray(latestEntry?.breaking) && (latestEntry?.breaking?.length ?? 0) > 0 || Array.isArray(latestEntry?.notes) && (latestEntry?.notes?.length ?? 0) > 0) newLine.append(el("span", "hqpu-tag--brand", copy.ui.breakingTag));
|
|
1604
|
+
left.append(newLine);
|
|
1605
|
+
const size = typeof latestEntry?.sizeBytes === "number" ? formatMb(latestEntry.sizeBytes) : "";
|
|
1606
|
+
const summary = typeof latestEntry?.summary === "string" ? latestEntry.summary : "";
|
|
1607
|
+
if (size.length > 0 || summary.length > 0) left.append(el("p", "hqpu-engine-size", copy.ui.sizeLine(size, summary)));
|
|
1608
|
+
row.append(left);
|
|
1609
|
+
if (actions.accepted) row.append(el("span", "hqpu-status", copy.runtime.updateAccepted));
|
|
1610
|
+
else if (actions.busy) row.append(el("span", "hqpu-status", copy.runtime.updating));
|
|
1611
|
+
else if (actions.armed) {
|
|
1612
|
+
const confirmWrap = el("div");
|
|
1613
|
+
confirmWrap.append(el("p", "hqpu-status", copy.runtime.updateConfirm(latestVersion)));
|
|
1614
|
+
const yes = el("button", "hqpu-btn hqpu-btn--engine", copy.confirmInstall);
|
|
1539
1615
|
yes.type = "button";
|
|
1540
1616
|
yes.dataset.runtimeConfirm = "";
|
|
1541
1617
|
yes.addEventListener("click", actions.onConfirm);
|
|
1542
|
-
const no = el("button", "hqpu-btn hqpu-btn--
|
|
1618
|
+
const no = el("button", "hqpu-btn hqpu-btn--engine", copy.cancel);
|
|
1543
1619
|
no.type = "button";
|
|
1544
1620
|
no.addEventListener("click", actions.onCancel);
|
|
1545
|
-
|
|
1621
|
+
confirmWrap.append(yes, no);
|
|
1622
|
+
row.append(confirmWrap);
|
|
1546
1623
|
} else {
|
|
1547
|
-
const start = el("button", "hqpu-btn hqpu-btn--
|
|
1624
|
+
const start = el("button", "hqpu-btn hqpu-btn--engine", copy.ui.upgradeCore);
|
|
1548
1625
|
start.type = "button";
|
|
1549
1626
|
start.dataset.runtimeUpdate = "";
|
|
1550
|
-
start.innerHTML = `${DOWNLOAD_ICON(13)}<span>${copy.runtime.update}</span>`;
|
|
1551
1627
|
start.addEventListener("click", actions.onArm);
|
|
1552
1628
|
row.append(start);
|
|
1553
1629
|
}
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
if (
|
|
1559
|
-
|
|
1560
|
-
const line = el("p", "hqpu-status hqpu-status--dot");
|
|
1561
|
-
line.setAttribute("role", "status");
|
|
1562
|
-
const dot = el("span", "hqpu-dot");
|
|
1563
|
-
dot.dataset.state = state === "succeeded" ? "done" : state === "failed" ? "error" : "warning";
|
|
1564
|
-
const parts = [state === "succeeded" ? copy.runtime.lastResult.succeeded : state === "failed" ? copy.runtime.lastResult.failed : copy.runtime.lastResult.rolledBack];
|
|
1565
|
-
if (lastResult.targetVersion) parts.push(`→ ${lastResult.targetVersion}`);
|
|
1566
|
-
if (lastResult.installedVersion) parts.push(`(${lastResult.installedVersion})`);
|
|
1567
|
-
if (lastResult.at) parts.push(new Date(lastResult.at).toLocaleString());
|
|
1568
|
-
line.append(dot, el("span", "", parts.join(" ")));
|
|
1569
|
-
section.append(line);
|
|
1570
|
-
if (typeof lastResult.message === "string" && lastResult.message.length > 0) section.append(el("p", "hqpu-status", lastResult.message));
|
|
1571
|
-
if (typeof lastResult.errorCode === "string" && lastResult.errorCode.length > 0) section.append(el("p", "hqpu-status hqpu-job-meta", lastResult.errorCode));
|
|
1572
|
-
if (state !== "succeeded") section.append(el("p", "hqpu-status hqpu-job-meta", copy.runtime.lastResult.elevation));
|
|
1573
|
-
}
|
|
1574
|
-
if (typeof runtime.lastError === "string" && runtime.lastError.length > 0) {
|
|
1575
|
-
const line = el("p", "hqpu-status hqpu-status--dot");
|
|
1576
|
-
line.setAttribute("role", "status");
|
|
1577
|
-
const dot = el("span", "hqpu-dot");
|
|
1578
|
-
dot.dataset.state = "error";
|
|
1579
|
-
line.append(dot, el("span", "", `${copy.lastError}: ${runtime.lastError}`));
|
|
1580
|
-
section.append(line);
|
|
1581
|
-
}
|
|
1582
|
-
return section;
|
|
1630
|
+
card.append(row);
|
|
1631
|
+
const note = el("p", "hqpu-engine-note");
|
|
1632
|
+
note.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2.5L14 13H2L8 2.5Z"/></svg><span>${copy.ui.runtimeRestartNote}</span>`;
|
|
1633
|
+
card.append(note);
|
|
1634
|
+
} else if (typeof runtime.lastError === "string" && runtime.lastError.length > 0) card.append(el("p", "hqpu-status", `${copy.lastError}: ${runtime.lastError}`));
|
|
1635
|
+
return card;
|
|
1583
1636
|
}
|
|
1584
|
-
function renderList(section, report, copy,
|
|
1637
|
+
function renderList(section, report, copy, changelogOpen, allOpen, onToggleCard, onToggleAll, onRetryCheck) {
|
|
1585
1638
|
section.textContent = "";
|
|
1586
1639
|
if (report === null) {
|
|
1587
1640
|
section.append(skeleton(copy));
|
|
@@ -1603,23 +1656,17 @@ window.__ModuleLoader__.load({
|
|
|
1603
1656
|
[copy.group.current, byState("current")]
|
|
1604
1657
|
];
|
|
1605
1658
|
for (const [heading, items] of order) {
|
|
1606
|
-
const node = group(heading, items, copy,
|
|
1659
|
+
const node = group(heading, items, copy, changelogOpen, allOpen, onToggleCard, onToggleAll);
|
|
1607
1660
|
if (node !== null) section.append(node);
|
|
1608
1661
|
}
|
|
1609
1662
|
}
|
|
1610
|
-
function renderRuntime(section, report, copy, actions) {
|
|
1611
|
-
section.textContent = "";
|
|
1612
|
-
if (report === null) return;
|
|
1613
|
-
section.append(runtimeGroup(report, copy, actions));
|
|
1614
|
-
}
|
|
1615
|
-
/** The plugin-source group, above the plugin groups, hidden behind an advanced
|
|
1616
|
-
* disclosure (manifest-URL editing is a developer affordance). No-op without
|
|
1617
|
-
* the field. */
|
|
1618
|
-
function renderPluginSource(section, report, copy, actions) {
|
|
1663
|
+
function renderRuntime(section, report, copy, actions, dismissedAlert, onDismissAlert) {
|
|
1619
1664
|
section.textContent = "";
|
|
1620
1665
|
if (report === null) return;
|
|
1621
|
-
const
|
|
1622
|
-
if (
|
|
1666
|
+
const alert = runtimeResultAlert(report, copy, dismissedAlert, onDismissAlert);
|
|
1667
|
+
if (alert !== null) section.append(alert);
|
|
1668
|
+
const engine = runtimeEngineCard(report, copy, actions);
|
|
1669
|
+
if (engine !== null) section.append(engine);
|
|
1623
1670
|
}
|
|
1624
1671
|
/** Run the install transaction (a new durable job), then let the store poll it. */
|
|
1625
1672
|
async function runInstall(store, copy) {
|
|
@@ -1663,45 +1710,65 @@ window.__ModuleLoader__.load({
|
|
|
1663
1710
|
toastTimer = null;
|
|
1664
1711
|
}, TOAST_HOLD_MS);
|
|
1665
1712
|
}
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1713
|
+
/**
|
|
1714
|
+
* The collapsible "更新源配置 (高级)" panel (gear-toggled). It hosts the
|
|
1715
|
+
* EXISTING plugin-source and runtime-source editors (POST /plugin-source,
|
|
1716
|
+
* POST /runtime-source, save→check→refresh already wired). No new endpoints:
|
|
1717
|
+
* if a manifest source has no data, that field is omitted rather than faked.
|
|
1718
|
+
*/
|
|
1719
|
+
function renderSettingsPanel(panel, report, copy, open, pluginActions, runtimeActions) {
|
|
1720
|
+
panel.textContent = "";
|
|
1721
|
+
panel.style.display = open ? "" : "none";
|
|
1722
|
+
if (!open || report === null) return;
|
|
1723
|
+
const row = el("div", "hqpu-settings-row");
|
|
1724
|
+
row.append(el("div", "hqpu-settings-title", copy.ui.settingsTitle));
|
|
1725
|
+
const pluginSource = normalizeSource(report.pluginSource);
|
|
1726
|
+
const runtimeSource = normalizeSource(report.runtime.source);
|
|
1727
|
+
const overridden = (pluginSource?.override ?? false) || (runtimeSource?.override ?? false);
|
|
1728
|
+
const badge = el("span", "hqpu-origin-badge", overridden ? copy.ui.originCustom : copy.ui.originDefault);
|
|
1729
|
+
badge.dataset.origin = overridden ? "override" : "config";
|
|
1730
|
+
row.append(badge);
|
|
1731
|
+
panel.append(row);
|
|
1732
|
+
if (pluginSource !== null) {
|
|
1733
|
+
panel.append(el("label", "", copy.ui.pluginUrlLabel));
|
|
1734
|
+
panel.append(sourceEditor("plugin", pluginSource, copy, pluginActions));
|
|
1735
|
+
}
|
|
1736
|
+
if (runtimeSource !== null) {
|
|
1737
|
+
panel.append(el("label", "", copy.ui.runtimeUrlLabel));
|
|
1738
|
+
panel.append(sourceEditor("runtime", runtimeSource, copy, runtimeActions));
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
/**
|
|
1742
|
+
* The sticky footer: left meta ("准备安装 N 项兼容插件" / "版本集: vX"), a
|
|
1743
|
+
* full-width primary "一键更新全套插件 (vX)" (install = one durable job),
|
|
1744
|
+
* a secondary 忽略 wired to the existing ignore/unignore affordance, and the
|
|
1745
|
+
* footnote. The count EXCLUDES blocked / ignored / already-current entries.
|
|
1746
|
+
*/
|
|
1747
|
+
function renderFooter(footer, installBtn, ignoreBtn, countEl, setEl, report, copy, installing, store) {
|
|
1748
|
+
if (report === null) {
|
|
1749
|
+
countEl.textContent = "";
|
|
1750
|
+
setEl.textContent = "";
|
|
1751
|
+
installBtn.disabled = true;
|
|
1752
|
+
ignoreBtn.style.display = "none";
|
|
1674
1753
|
return;
|
|
1675
1754
|
}
|
|
1676
1755
|
const actionable = report.items.filter((item) => item.state === "update" || item.state === "install").length;
|
|
1677
1756
|
const hasSet = report.manifestVersion !== null;
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
unignore.addEventListener("click", () => {
|
|
1694
|
-
unignoreOffer(report.manifestVersion).then(() => store.refresh()).catch(() => void 0);
|
|
1695
|
-
});
|
|
1696
|
-
bar.append(unignore);
|
|
1697
|
-
} else if (actionable > 0) {
|
|
1698
|
-
const ignore = el("button", "hqpu-btn hqpu-btn--ghost hqpu-btn--sm", copy.ignore);
|
|
1699
|
-
ignore.type = "button";
|
|
1700
|
-
ignore.addEventListener("click", () => {
|
|
1701
|
-
ignoreOffer(report.manifestVersion).then(() => store.refresh()).catch(() => void 0);
|
|
1702
|
-
});
|
|
1703
|
-
bar.append(ignore);
|
|
1704
|
-
}
|
|
1757
|
+
const setVersion = report.manifestVersion ?? "";
|
|
1758
|
+
countEl.textContent = copy.ui.footerCount(actionable);
|
|
1759
|
+
setEl.textContent = hasSet ? copy.ui.footerSet(setVersion) : "";
|
|
1760
|
+
installBtn.textContent = hasSet ? copy.ui.installAllSet(setVersion) : copy.ui.installAllSet("—");
|
|
1761
|
+
installBtn.disabled = installing || actionable === 0 || !hasSet || report.ignoredSet;
|
|
1762
|
+
installBtn.dataset.busy = installing ? "true" : "false";
|
|
1763
|
+
installBtn.onclick = () => {
|
|
1764
|
+
runInstall(store, copy);
|
|
1765
|
+
};
|
|
1766
|
+
ignoreBtn.style.display = hasSet ? "" : "none";
|
|
1767
|
+
ignoreBtn.textContent = report.ignoredSet ? copy.unignore : copy.ui.ignoreBtn;
|
|
1768
|
+
ignoreBtn.onclick = () => {
|
|
1769
|
+
const version = report.manifestVersion;
|
|
1770
|
+
(report.ignoredSet ? unignoreOffer(version) : ignoreOffer(version)).then(() => store.refresh()).catch(() => void 0);
|
|
1771
|
+
};
|
|
1705
1772
|
}
|
|
1706
1773
|
/**
|
|
1707
1774
|
* Open (or focus) the update panel. Re-renders from the store; when the store
|
|
@@ -1726,40 +1793,53 @@ window.__ModuleLoader__.load({
|
|
|
1726
1793
|
panel.tabIndex = -1;
|
|
1727
1794
|
const head = el("div", "hqpu-head");
|
|
1728
1795
|
const headMain = el("div", "hqpu-head-main");
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
info.innerHTML = INFO_ICON(11);
|
|
1737
|
-
intro.append(info);
|
|
1738
|
-
headMain.append(intro);
|
|
1796
|
+
const brandIcon = el("span", "hqpu-brand-icon");
|
|
1797
|
+
brandIcon.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"><path d="M5.6 2.6a6 6 0 015.6 1.6M12.4 13.4a6 6 0 01-5.6-1.6M10.6 2V5.4H7.2M5.4 14V10.6H8.8"/></svg>`;
|
|
1798
|
+
const titleBlock = el("div", "hqpu-title-block");
|
|
1799
|
+
titleBlock.append(el("h1", "hqpu-title", copy.ui.title));
|
|
1800
|
+
const sub = el("p", "hqpu-sub");
|
|
1801
|
+
titleBlock.append(sub);
|
|
1802
|
+
headMain.append(brandIcon, titleBlock);
|
|
1739
1803
|
const toolbar = el("div", "hqpu-toolbar");
|
|
1740
1804
|
const refreshBtn = iconButton("hqpu-icon-btn", REFRESH_ICON(16), copy.refresh, () => {
|
|
1741
|
-
store.
|
|
1805
|
+
store.check();
|
|
1742
1806
|
});
|
|
1743
1807
|
toolbar.append(refreshBtn);
|
|
1808
|
+
const gearBtn = iconButton("hqpu-icon-btn", `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><circle cx="8" cy="8" r="2.2"/><path d="M13.5 9.2v-2.4l-1.8-.6a4.4 4.4 0 00-.5-1.2l.9-1.7-1.7-1.7-1.7.9a4.4 4.4 0 00-1.2-.5L7.2 2.5H4.8l-.6 1.8a4.4 4.4 0 00-1.2.5l-1.7-.9-1.7 1.7.9 1.7a4.4 4.4 0 00-.5 1.2L2.5 7.2v2.4l1.8.6a4.4 4.4 0 00.5 1.2l-.9 1.7 1.7 1.7 1.7-.9a4.4 4.4 0 001.2.5l.6 1.8h2.4l.6-1.8a4.4 4.4 0 001.2-.5l1.7.9 1.7-1.7-.9-1.7a4.4 4.4 0 00.5-1.2l1.8-.6z"/></svg>`, copy.ui.gearTooltip, () => {
|
|
1809
|
+
settingsOpen = !settingsOpen;
|
|
1810
|
+
render();
|
|
1811
|
+
});
|
|
1812
|
+
toolbar.append(gearBtn);
|
|
1744
1813
|
const closeBtn = iconButton("hqpu-icon-btn", CLOSE_ICON(16), copy.close, () => {
|
|
1745
1814
|
onClose();
|
|
1746
1815
|
});
|
|
1747
1816
|
toolbar.append(closeBtn);
|
|
1748
1817
|
head.append(headMain, toolbar);
|
|
1749
1818
|
panel.append(head);
|
|
1819
|
+
const settingsPanel = el("div", "hqpu-settings");
|
|
1820
|
+
panel.append(settingsPanel);
|
|
1750
1821
|
const scroll = el("div", "hqpu-scroll");
|
|
1751
1822
|
const column = el("div", "hqpu-column");
|
|
1752
1823
|
const jobSection = el("div", "hqpu-stack");
|
|
1753
|
-
const pluginSourceSection = el("div", "hqpu-stack");
|
|
1754
1824
|
const listSection = el("div", "hqpu-stack");
|
|
1755
1825
|
const runtimeSection = el("div", "hqpu-stack");
|
|
1756
1826
|
const toastSection = el("div", "hqpu-toast-host");
|
|
1757
|
-
column.append(jobSection,
|
|
1827
|
+
column.append(jobSection, listSection, runtimeSection, toastSection);
|
|
1758
1828
|
scroll.append(column);
|
|
1759
1829
|
panel.append(scroll);
|
|
1760
1830
|
const footer = el("div", "hqpu-footer");
|
|
1761
|
-
const
|
|
1762
|
-
|
|
1831
|
+
const footMeta = el("div", "hqpu-foot-meta");
|
|
1832
|
+
const footCount = el("span", "");
|
|
1833
|
+
const footSet = el("span", "hqpu-foot-set");
|
|
1834
|
+
footMeta.append(footCount, footSet);
|
|
1835
|
+
const footActions = el("div", "hqpu-foot-actions");
|
|
1836
|
+
const installAllBtn = el("button", "hqpu-btn hqpu-btn--block");
|
|
1837
|
+
installAllBtn.type = "button";
|
|
1838
|
+
const ignoreBtn = el("button", "hqpu-btn--ignore", copy.ui.ignoreBtn);
|
|
1839
|
+
ignoreBtn.type = "button";
|
|
1840
|
+
footActions.append(installAllBtn, ignoreBtn);
|
|
1841
|
+
const footnote = el("p", "hqpu-footnote", copy.ui.footnote);
|
|
1842
|
+
footer.append(footMeta, footActions, footnote);
|
|
1763
1843
|
panel.append(footer);
|
|
1764
1844
|
overlay.append(scrim, panel);
|
|
1765
1845
|
document.body.appendChild(overlay);
|
|
@@ -1769,6 +1849,10 @@ window.__ModuleLoader__.load({
|
|
|
1769
1849
|
let runtimeArmed = false;
|
|
1770
1850
|
let runtimeBusy = false;
|
|
1771
1851
|
let runtimeAccepted = false;
|
|
1852
|
+
const changelogOpen = /* @__PURE__ */ new Set();
|
|
1853
|
+
let allOpen = false;
|
|
1854
|
+
let settingsOpen = false;
|
|
1855
|
+
let dismissedAlert = false;
|
|
1772
1856
|
const runtimeSourceState = {
|
|
1773
1857
|
editing: false,
|
|
1774
1858
|
saving: false,
|
|
@@ -1935,16 +2019,29 @@ window.__ModuleLoader__.load({
|
|
|
1935
2019
|
const installing = store.installing() || jobActive;
|
|
1936
2020
|
const stale = report === null;
|
|
1937
2021
|
refreshBtn.disabled = stale;
|
|
2022
|
+
refreshBtn.title = copy.refresh;
|
|
2023
|
+
const ago = relativeAgo(report?.checkedAt, copy);
|
|
2024
|
+
sub.textContent = ago !== null ? copy.ui.checkedAgo(ago) : copy.ui.checkedUnknown;
|
|
2025
|
+
renderSettingsPanel(settingsPanel, report, copy, settingsOpen, pluginActions, runtimeSourceActions);
|
|
1938
2026
|
renderJobSection();
|
|
1939
2027
|
if (stale) {
|
|
1940
2028
|
listSection.textContent = "";
|
|
1941
2029
|
listSection.append(skeleton(copy));
|
|
1942
|
-
} else renderList(listSection, report, copy,
|
|
2030
|
+
} else renderList(listSection, report, copy, changelogOpen, allOpen, (name) => {
|
|
2031
|
+
if (changelogOpen.has(name)) changelogOpen.delete(name);
|
|
2032
|
+
else changelogOpen.add(name);
|
|
2033
|
+
render();
|
|
2034
|
+
}, () => {
|
|
2035
|
+
allOpen = !allOpen;
|
|
2036
|
+
render();
|
|
2037
|
+
}, () => {
|
|
1943
2038
|
store.check();
|
|
1944
2039
|
});
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
2040
|
+
renderRuntime(runtimeSection, report, copy, runtimeActions, dismissedAlert, () => {
|
|
2041
|
+
dismissedAlert = true;
|
|
2042
|
+
render();
|
|
2043
|
+
});
|
|
2044
|
+
renderFooter(footer, installAllBtn, ignoreBtn, footCount, footSet, report, copy, installing, store);
|
|
1948
2045
|
};
|
|
1949
2046
|
const unsubscribe = store.subscribe(render);
|
|
1950
2047
|
disposers.push(unsubscribe);
|
|
@@ -2834,10 +2931,649 @@ window.__ModuleLoader__.load({
|
|
|
2834
2931
|
.hqpu-panel,
|
|
2835
2932
|
.hqpu-skeleton-fill,
|
|
2836
2933
|
.hqpu-spinner,
|
|
2837
|
-
.hqpu-toast
|
|
2934
|
+
.hqpu-toast,
|
|
2935
|
+
.hqpu-pulse-ring,
|
|
2936
|
+
.hqpu-job-step--active {
|
|
2838
2937
|
animation: none;
|
|
2839
2938
|
}
|
|
2840
2939
|
}
|
|
2940
|
+
|
|
2941
|
+
/* ════════════════════════════════════════════════════════════════════════
|
|
2942
|
+
* Refactored dock (interactive_refactored_ui_mockup.html) — a narrow dark-zinc
|
|
2943
|
+
* update-center column. These rules cascade over the shell-token base: the
|
|
2944
|
+
* panel becomes ~340px wide, the zinc palette hard-coded per mockup, with a
|
|
2945
|
+
* sticky header / scroll body / sticky footer. No Tailwind, no dependencies.
|
|
2946
|
+
* ════════════════════════════════════════════════════════════════════════ */
|
|
2947
|
+
.hqpu-panel,
|
|
2948
|
+
.hqpu-panel * {
|
|
2949
|
+
--hq-bg: #18181b;
|
|
2950
|
+
--hq-card: #27272a;
|
|
2951
|
+
--hq-card-soft: #1c1c1f;
|
|
2952
|
+
--hq-border: #3f3f46;
|
|
2953
|
+
--hq-hover: #323236;
|
|
2954
|
+
--hq-text: #f4f4f5;
|
|
2955
|
+
--hq-muted: #a1a1aa;
|
|
2956
|
+
--hq-faint: #71717a;
|
|
2957
|
+
--hq-brand: #dc2626;
|
|
2958
|
+
--hq-brand-soft: #ef4444;
|
|
2959
|
+
--hq-emerald: #34d399;
|
|
2960
|
+
--hq-amber: #f59e0b;
|
|
2961
|
+
}
|
|
2962
|
+
.hqpu-panel {
|
|
2963
|
+
width: min(360px, calc(100vw - 32px));
|
|
2964
|
+
max-height: min(86vh, 720px);
|
|
2965
|
+
background: var(--hq-bg);
|
|
2966
|
+
color: var(--hq-text);
|
|
2967
|
+
border: 0.5px solid var(--hq-border);
|
|
2968
|
+
border-radius: 12px;
|
|
2969
|
+
gap: 0;
|
|
2970
|
+
overflow: hidden;
|
|
2971
|
+
}
|
|
2972
|
+
.hqpu-scrim {
|
|
2973
|
+
background: rgba(0, 0, 0, 0.55);
|
|
2974
|
+
}
|
|
2975
|
+
|
|
2976
|
+
/* Sticky header */
|
|
2977
|
+
.hqpu-head {
|
|
2978
|
+
flex: none;
|
|
2979
|
+
display: flex;
|
|
2980
|
+
align-items: center;
|
|
2981
|
+
justify-content: space-between;
|
|
2982
|
+
gap: 8px;
|
|
2983
|
+
padding: 10px 12px;
|
|
2984
|
+
border-bottom: 0.5px solid var(--hq-border);
|
|
2985
|
+
background: color-mix(in srgb, var(--hq-bg) 95%, transparent);
|
|
2986
|
+
position: sticky;
|
|
2987
|
+
top: 0;
|
|
2988
|
+
z-index: 2;
|
|
2989
|
+
}
|
|
2990
|
+
.hqpu-head-main {
|
|
2991
|
+
display: flex;
|
|
2992
|
+
align-items: center;
|
|
2993
|
+
gap: 8px;
|
|
2994
|
+
min-width: 0;
|
|
2995
|
+
margin: 0;
|
|
2996
|
+
}
|
|
2997
|
+
.hqpu-brand-icon {
|
|
2998
|
+
display: flex;
|
|
2999
|
+
align-items: center;
|
|
3000
|
+
justify-content: center;
|
|
3001
|
+
flex: none;
|
|
3002
|
+
width: 24px;
|
|
3003
|
+
height: 24px;
|
|
3004
|
+
border-radius: 6px;
|
|
3005
|
+
background: color-mix(in srgb, var(--hq-brand) 20%, transparent);
|
|
3006
|
+
color: var(--hq-brand-soft);
|
|
3007
|
+
}
|
|
3008
|
+
.hqpu-brand-icon svg { width: 14px; height: 14px; display: block; }
|
|
3009
|
+
.hqpu-title-block { min-width: 0; }
|
|
3010
|
+
.hqpu-title {
|
|
3011
|
+
margin: 0;
|
|
3012
|
+
font-size: 13px;
|
|
3013
|
+
font-weight: 600;
|
|
3014
|
+
line-height: 16px;
|
|
3015
|
+
color: var(--hq-text);
|
|
3016
|
+
}
|
|
3017
|
+
.hqpu-sub {
|
|
3018
|
+
margin: 2px 0 0;
|
|
3019
|
+
font-size: 10px;
|
|
3020
|
+
line-height: 14px;
|
|
3021
|
+
color: var(--hq-muted);
|
|
3022
|
+
white-space: nowrap;
|
|
3023
|
+
overflow: hidden;
|
|
3024
|
+
text-overflow: ellipsis;
|
|
3025
|
+
}
|
|
3026
|
+
.hqpu-toolbar { gap: 2px; }
|
|
3027
|
+
.hqpu-icon-btn {
|
|
3028
|
+
width: 26px;
|
|
3029
|
+
height: 26px;
|
|
3030
|
+
border-radius: 6px;
|
|
3031
|
+
color: var(--hq-muted);
|
|
3032
|
+
}
|
|
3033
|
+
.hqpu-icon-btn:hover:not(:disabled) {
|
|
3034
|
+
background: var(--hq-hover);
|
|
3035
|
+
color: var(--hq-text);
|
|
3036
|
+
}
|
|
3037
|
+
.hqpu-icon-btn svg { width: 14px; height: 14px; }
|
|
3038
|
+
|
|
3039
|
+
/* Collapsible settings panel */
|
|
3040
|
+
.hqpu-settings {
|
|
3041
|
+
flex: none;
|
|
3042
|
+
padding: 10px 12px;
|
|
3043
|
+
border-bottom: 0.5px solid var(--hq-border);
|
|
3044
|
+
background: #131316;
|
|
3045
|
+
}
|
|
3046
|
+
.hqpu-settings-row {
|
|
3047
|
+
display: flex;
|
|
3048
|
+
align-items: center;
|
|
3049
|
+
justify-content: space-between;
|
|
3050
|
+
gap: 8px;
|
|
3051
|
+
margin-bottom: 8px;
|
|
3052
|
+
}
|
|
3053
|
+
.hqpu-settings-title {
|
|
3054
|
+
font-size: 11px;
|
|
3055
|
+
font-weight: 500;
|
|
3056
|
+
color: #d4d4d8;
|
|
3057
|
+
}
|
|
3058
|
+
.hqpu-origin-badge {
|
|
3059
|
+
font-size: 9px;
|
|
3060
|
+
padding: 1px 6px;
|
|
3061
|
+
border-radius: 4px;
|
|
3062
|
+
border: 0.5px solid;
|
|
3063
|
+
}
|
|
3064
|
+
.hqpu-origin-badge[data-origin='config'] {
|
|
3065
|
+
background: rgba(6, 78, 59, 0.4);
|
|
3066
|
+
color: var(--hq-emerald);
|
|
3067
|
+
border-color: rgba(6, 95, 70, 0.6);
|
|
3068
|
+
}
|
|
3069
|
+
.hqpu-origin-badge[data-origin='override'] {
|
|
3070
|
+
background: rgba(120, 53, 15, 0.4);
|
|
3071
|
+
color: var(--hq-amber);
|
|
3072
|
+
border-color: rgba(180, 83, 9, 0.5);
|
|
3073
|
+
}
|
|
3074
|
+
.hqpu-settings label {
|
|
3075
|
+
display: block;
|
|
3076
|
+
font-size: 10px;
|
|
3077
|
+
color: var(--hq-muted);
|
|
3078
|
+
margin: 6px 0 3px;
|
|
3079
|
+
}
|
|
3080
|
+
.hqpu-source-input {
|
|
3081
|
+
width: 100%;
|
|
3082
|
+
height: 26px;
|
|
3083
|
+
font-size: 10px;
|
|
3084
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
3085
|
+
background: var(--hq-bg);
|
|
3086
|
+
border: 0.5px solid var(--hq-border);
|
|
3087
|
+
border-radius: 5px;
|
|
3088
|
+
color: #d4d4d8;
|
|
3089
|
+
padding: 0 8px;
|
|
3090
|
+
box-sizing: border-box;
|
|
3091
|
+
}
|
|
3092
|
+
.hqpu-source-input:focus-visible {
|
|
3093
|
+
outline: none;
|
|
3094
|
+
border-color: var(--hq-brand-soft);
|
|
3095
|
+
}
|
|
3096
|
+
.hqpu-settings-actions {
|
|
3097
|
+
display: flex;
|
|
3098
|
+
justify-content: flex-end;
|
|
3099
|
+
gap: 6px;
|
|
3100
|
+
margin-top: 8px;
|
|
3101
|
+
}
|
|
3102
|
+
|
|
3103
|
+
/* Scroll body */
|
|
3104
|
+
.hqpu-scroll {
|
|
3105
|
+
flex: 1;
|
|
3106
|
+
padding: 12px;
|
|
3107
|
+
background: var(--hq-bg);
|
|
3108
|
+
--dsh-scrollbar-thumb: #3f3f46;
|
|
3109
|
+
--dsh-scrollbar-thumb-hover: #52525b;
|
|
3110
|
+
}
|
|
3111
|
+
.hqpu-column {
|
|
3112
|
+
max-width: none;
|
|
3113
|
+
margin: 0;
|
|
3114
|
+
gap: 10px;
|
|
3115
|
+
}
|
|
3116
|
+
.hqpu-stack { gap: 10px; }
|
|
3117
|
+
|
|
3118
|
+
/* ── Active-job banner ─────────────────────────────────────────────────── */
|
|
3119
|
+
.hqpu-active {
|
|
3120
|
+
position: relative;
|
|
3121
|
+
padding: 12px;
|
|
3122
|
+
border-radius: 8px;
|
|
3123
|
+
border: 0.5px solid color-mix(in srgb, var(--hq-brand-soft) 30%, transparent);
|
|
3124
|
+
background: #18181b;
|
|
3125
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
|
|
3126
|
+
}
|
|
3127
|
+
.hqpu-active-top {
|
|
3128
|
+
display: flex;
|
|
3129
|
+
align-items: center;
|
|
3130
|
+
justify-content: space-between;
|
|
3131
|
+
gap: 8px;
|
|
3132
|
+
}
|
|
3133
|
+
.hqpu-active-title {
|
|
3134
|
+
display: flex;
|
|
3135
|
+
align-items: center;
|
|
3136
|
+
gap: 6px;
|
|
3137
|
+
min-width: 0;
|
|
3138
|
+
font-size: 11px;
|
|
3139
|
+
font-weight: 600;
|
|
3140
|
+
color: #e4e4e7;
|
|
3141
|
+
}
|
|
3142
|
+
.hqpu-pulse-dot {
|
|
3143
|
+
position: relative;
|
|
3144
|
+
flex: none;
|
|
3145
|
+
width: 8px;
|
|
3146
|
+
height: 8px;
|
|
3147
|
+
}
|
|
3148
|
+
.hqpu-pulse-dot::before {
|
|
3149
|
+
content: '';
|
|
3150
|
+
position: absolute;
|
|
3151
|
+
inset: 0;
|
|
3152
|
+
border-radius: 50%;
|
|
3153
|
+
background: var(--hq-brand-soft);
|
|
3154
|
+
}
|
|
3155
|
+
.hqpu-pulse-ring {
|
|
3156
|
+
position: absolute;
|
|
3157
|
+
inset: 0;
|
|
3158
|
+
border-radius: 50%;
|
|
3159
|
+
background: var(--hq-brand-soft);
|
|
3160
|
+
opacity: 0.6;
|
|
3161
|
+
animation: hqpu-ping 1.4s cubic-bezier(0, 0, 0.2, 1) infinite;
|
|
3162
|
+
}
|
|
3163
|
+
@keyframes hqpu-ping {
|
|
3164
|
+
75%, 100% { transform: scale(2.2); opacity: 0; }
|
|
3165
|
+
}
|
|
3166
|
+
.hqpu-active-percent {
|
|
3167
|
+
flex: none;
|
|
3168
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
3169
|
+
font-size: 11px;
|
|
3170
|
+
font-weight: 500;
|
|
3171
|
+
color: var(--hq-brand-soft);
|
|
3172
|
+
}
|
|
3173
|
+
.hqpu-progress {
|
|
3174
|
+
height: 6px;
|
|
3175
|
+
margin-top: 10px;
|
|
3176
|
+
border-radius: 999px;
|
|
3177
|
+
background: #27272a;
|
|
3178
|
+
overflow: hidden;
|
|
3179
|
+
}
|
|
3180
|
+
.hqpu-progress-fill {
|
|
3181
|
+
background: linear-gradient(to right, var(--hq-brand), var(--hq-brand-soft));
|
|
3182
|
+
transition: width 0.3s ease;
|
|
3183
|
+
}
|
|
3184
|
+
.hqpu-active-meta {
|
|
3185
|
+
display: flex;
|
|
3186
|
+
justify-content: space-between;
|
|
3187
|
+
gap: 8px;
|
|
3188
|
+
margin-top: 4px;
|
|
3189
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
3190
|
+
font-size: 10px;
|
|
3191
|
+
color: var(--hq-muted);
|
|
3192
|
+
}
|
|
3193
|
+
/* 4-step indicator row */
|
|
3194
|
+
.hqpu-job-steps4 {
|
|
3195
|
+
display: grid;
|
|
3196
|
+
grid-template-columns: repeat(4, 1fr);
|
|
3197
|
+
gap: 4px;
|
|
3198
|
+
margin-top: 10px;
|
|
3199
|
+
padding-top: 8px;
|
|
3200
|
+
border-top: 0.5px solid #27272a;
|
|
3201
|
+
text-align: center;
|
|
3202
|
+
font-size: 9px;
|
|
3203
|
+
font-weight: 500;
|
|
3204
|
+
}
|
|
3205
|
+
.hqpu-job-step--done { color: var(--hq-emerald); }
|
|
3206
|
+
.hqpu-job-step--active {
|
|
3207
|
+
color: var(--hq-brand-soft);
|
|
3208
|
+
animation: hqpu-step-pulse 1.2s ease-in-out infinite;
|
|
3209
|
+
}
|
|
3210
|
+
.hqpu-job-step--todo { color: var(--hq-muted); }
|
|
3211
|
+
@keyframes hqpu-step-pulse {
|
|
3212
|
+
0%, 100% { opacity: 1; }
|
|
3213
|
+
50% { opacity: 0.45; }
|
|
3214
|
+
}
|
|
3215
|
+
|
|
3216
|
+
/* ── Result / rollback alert (amber) vs green success ──────────────────── */
|
|
3217
|
+
.hqpu-alert {
|
|
3218
|
+
display: flex;
|
|
3219
|
+
align-items: flex-start;
|
|
3220
|
+
gap: 8px;
|
|
3221
|
+
padding: 10px;
|
|
3222
|
+
border-radius: 8px;
|
|
3223
|
+
}
|
|
3224
|
+
.hqpu-alert--amber {
|
|
3225
|
+
background: rgba(69, 26, 3, 0.35);
|
|
3226
|
+
border: 0.5px solid rgba(180, 83, 9, 0.4);
|
|
3227
|
+
}
|
|
3228
|
+
.hqpu-alert--amber svg { color: var(--hq-amber); flex: none; margin-top: 1px; }
|
|
3229
|
+
.hqpu-alert-green {
|
|
3230
|
+
background: rgba(6, 78, 59, 0.3);
|
|
3231
|
+
border: 0.5px solid rgba(6, 95, 70, 0.4);
|
|
3232
|
+
color: #a7f3d0;
|
|
3233
|
+
font-size: 11px;
|
|
3234
|
+
}
|
|
3235
|
+
.hqpu-alert-title {
|
|
3236
|
+
font-size: 11px;
|
|
3237
|
+
font-weight: 500;
|
|
3238
|
+
color: #fcd34d;
|
|
3239
|
+
}
|
|
3240
|
+
.hqpu-alert-body {
|
|
3241
|
+
margin: 2px 0 0;
|
|
3242
|
+
font-size: 10px;
|
|
3243
|
+
line-height: 15px;
|
|
3244
|
+
color: rgba(252, 211, 77, 0.8);
|
|
3245
|
+
}
|
|
3246
|
+
.hqpu-alert-body code {
|
|
3247
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
3248
|
+
background: rgba(120, 53, 15, 0.5);
|
|
3249
|
+
padding: 1px 4px;
|
|
3250
|
+
border-radius: 3px;
|
|
3251
|
+
}
|
|
3252
|
+
.hqpu-alert-actions {
|
|
3253
|
+
display: flex;
|
|
3254
|
+
gap: 8px;
|
|
3255
|
+
margin-top: 6px;
|
|
3256
|
+
}
|
|
3257
|
+
.hqpu-alert-dismiss {
|
|
3258
|
+
background: none;
|
|
3259
|
+
border: 0;
|
|
3260
|
+
padding: 0;
|
|
3261
|
+
font-size: 10px;
|
|
3262
|
+
color: #fbbf24;
|
|
3263
|
+
cursor: pointer;
|
|
3264
|
+
text-decoration: underline;
|
|
3265
|
+
}
|
|
3266
|
+
|
|
3267
|
+
/* ── Runtime engine card ────────────────────────────────────────────────── */
|
|
3268
|
+
.hqpu-engine {
|
|
3269
|
+
padding: 12px;
|
|
3270
|
+
border-radius: 8px;
|
|
3271
|
+
border: 0.5px solid var(--hq-border);
|
|
3272
|
+
background: var(--hq-card);
|
|
3273
|
+
}
|
|
3274
|
+
.hqpu-engine-head {
|
|
3275
|
+
display: flex;
|
|
3276
|
+
align-items: center;
|
|
3277
|
+
justify-content: space-between;
|
|
3278
|
+
gap: 8px;
|
|
3279
|
+
}
|
|
3280
|
+
.hqpu-engine-title {
|
|
3281
|
+
display: flex;
|
|
3282
|
+
align-items: center;
|
|
3283
|
+
gap: 6px;
|
|
3284
|
+
font-size: 12px;
|
|
3285
|
+
font-weight: 600;
|
|
3286
|
+
color: #e4e4e7;
|
|
3287
|
+
}
|
|
3288
|
+
.hqpu-engine-title svg { width: 14px; height: 14px; color: #a1a1aa; }
|
|
3289
|
+
.hqpu-chip {
|
|
3290
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
3291
|
+
font-size: 9px;
|
|
3292
|
+
padding: 2px 6px;
|
|
3293
|
+
border-radius: 4px;
|
|
3294
|
+
background: #27272a;
|
|
3295
|
+
border: 0.5px solid #52525b;
|
|
3296
|
+
color: #d4d4d8;
|
|
3297
|
+
}
|
|
3298
|
+
.hqpu-engine-update-row {
|
|
3299
|
+
display: flex;
|
|
3300
|
+
align-items: center;
|
|
3301
|
+
justify-content: space-between;
|
|
3302
|
+
gap: 8px;
|
|
3303
|
+
margin-top: 10px;
|
|
3304
|
+
padding: 8px;
|
|
3305
|
+
border-radius: 6px;
|
|
3306
|
+
border: 0.5px solid rgba(63, 63, 70, 0.7);
|
|
3307
|
+
background: rgba(24, 24, 27, 0.6);
|
|
3308
|
+
}
|
|
3309
|
+
.hqpu-engine-new-line {
|
|
3310
|
+
display: flex;
|
|
3311
|
+
align-items: center;
|
|
3312
|
+
gap: 4px;
|
|
3313
|
+
font-size: 11px;
|
|
3314
|
+
font-weight: 500;
|
|
3315
|
+
color: #d4d4d8;
|
|
3316
|
+
}
|
|
3317
|
+
.hqpu-tag--brand {
|
|
3318
|
+
font-size: 9px;
|
|
3319
|
+
padding: 1px 4px;
|
|
3320
|
+
border-radius: 3px;
|
|
3321
|
+
color: var(--hq-brand-soft);
|
|
3322
|
+
background: rgba(69, 10, 10, 0.6);
|
|
3323
|
+
border: 0.5px solid rgba(153, 27, 27, 0.5);
|
|
3324
|
+
}
|
|
3325
|
+
.hqpu-engine-size {
|
|
3326
|
+
margin: 3px 0 0;
|
|
3327
|
+
font-size: 10px;
|
|
3328
|
+
color: var(--hq-muted);
|
|
3329
|
+
overflow: hidden;
|
|
3330
|
+
text-overflow: ellipsis;
|
|
3331
|
+
white-space: nowrap;
|
|
3332
|
+
}
|
|
3333
|
+
.hqpu-btn--engine {
|
|
3334
|
+
flex: none;
|
|
3335
|
+
height: auto;
|
|
3336
|
+
padding: 6px 10px;
|
|
3337
|
+
font-size: 10px;
|
|
3338
|
+
background: #27272a;
|
|
3339
|
+
border: 0.5px solid #52525b;
|
|
3340
|
+
color: #e4e4e7;
|
|
3341
|
+
border-radius: 5px;
|
|
3342
|
+
}
|
|
3343
|
+
.hqpu-btn--engine:hover:not(:disabled) { background: #3f3f46; }
|
|
3344
|
+
.hqpu-engine-note {
|
|
3345
|
+
display: flex;
|
|
3346
|
+
align-items: center;
|
|
3347
|
+
gap: 4px;
|
|
3348
|
+
margin: 8px 0 0;
|
|
3349
|
+
font-size: 9px;
|
|
3350
|
+
color: var(--hq-muted);
|
|
3351
|
+
}
|
|
3352
|
+
.hqpu-engine-note svg { width: 10px; height: 10px; color: var(--hq-amber); flex: none; }
|
|
3353
|
+
|
|
3354
|
+
/* ── Plugin cards ───────────────────────────────────────────────────────── */
|
|
3355
|
+
.hqpu-section-head {
|
|
3356
|
+
display: flex;
|
|
3357
|
+
align-items: center;
|
|
3358
|
+
justify-content: space-between;
|
|
3359
|
+
gap: 8px;
|
|
3360
|
+
padding: 0 2px;
|
|
3361
|
+
}
|
|
3362
|
+
.hqpu-section-title {
|
|
3363
|
+
display: flex;
|
|
3364
|
+
align-items: center;
|
|
3365
|
+
gap: 6px;
|
|
3366
|
+
font-size: 12px;
|
|
3367
|
+
font-weight: 600;
|
|
3368
|
+
color: #e4e4e7;
|
|
3369
|
+
}
|
|
3370
|
+
.hqpu-count-pill {
|
|
3371
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
3372
|
+
font-size: 10px;
|
|
3373
|
+
font-weight: 700;
|
|
3374
|
+
padding: 1px 6px;
|
|
3375
|
+
border-radius: 999px;
|
|
3376
|
+
background: color-mix(in srgb, var(--hq-brand) 20%, transparent);
|
|
3377
|
+
color: var(--hq-brand-soft);
|
|
3378
|
+
}
|
|
3379
|
+
.hqpu-all-changelog {
|
|
3380
|
+
background: none;
|
|
3381
|
+
border: 0;
|
|
3382
|
+
padding: 0;
|
|
3383
|
+
font-size: 10px;
|
|
3384
|
+
color: var(--hq-muted);
|
|
3385
|
+
cursor: pointer;
|
|
3386
|
+
}
|
|
3387
|
+
.hqpu-all-changelog:hover { color: var(--hq-text); }
|
|
3388
|
+
|
|
3389
|
+
.hqpu-cards { gap: 8px; }
|
|
3390
|
+
.hqpu-card {
|
|
3391
|
+
margin: 0;
|
|
3392
|
+
padding: 10px;
|
|
3393
|
+
border-radius: 8px;
|
|
3394
|
+
border: 0.5px solid var(--hq-border);
|
|
3395
|
+
background: var(--hq-card);
|
|
3396
|
+
transition: border-color 0.15s ease;
|
|
3397
|
+
}
|
|
3398
|
+
.hqpu-card:hover { border-color: #52525b; }
|
|
3399
|
+
.hqpu-card-head {
|
|
3400
|
+
display: flex;
|
|
3401
|
+
align-items: flex-start;
|
|
3402
|
+
justify-content: space-between;
|
|
3403
|
+
gap: 8px;
|
|
3404
|
+
padding: 0;
|
|
3405
|
+
}
|
|
3406
|
+
.hqpu-card-head > * { display: flex; align-items: center; gap: 8px; min-width: 0; }
|
|
3407
|
+
.hqpu-avatar {
|
|
3408
|
+
display: flex;
|
|
3409
|
+
align-items: center;
|
|
3410
|
+
justify-content: center;
|
|
3411
|
+
flex: none;
|
|
3412
|
+
width: 28px;
|
|
3413
|
+
height: 28px;
|
|
3414
|
+
border-radius: 6px;
|
|
3415
|
+
border: 0.5px solid #52525b;
|
|
3416
|
+
background: #27272a;
|
|
3417
|
+
color: #d4d4d8;
|
|
3418
|
+
font-size: 10px;
|
|
3419
|
+
font-weight: 700;
|
|
3420
|
+
}
|
|
3421
|
+
.hqpu-card-title {
|
|
3422
|
+
font-size: 12px;
|
|
3423
|
+
font-weight: 600;
|
|
3424
|
+
color: #e4e4e7;
|
|
3425
|
+
}
|
|
3426
|
+
.hqpu-card-sub {
|
|
3427
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
3428
|
+
font-size: 9px;
|
|
3429
|
+
color: var(--hq-faint);
|
|
3430
|
+
}
|
|
3431
|
+
.hqpu-version-row {
|
|
3432
|
+
display: flex;
|
|
3433
|
+
align-items: center;
|
|
3434
|
+
gap: 4px;
|
|
3435
|
+
margin-top: 2px;
|
|
3436
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
3437
|
+
font-size: 10px;
|
|
3438
|
+
}
|
|
3439
|
+
.hqpu-ver-old { color: var(--hq-muted); }
|
|
3440
|
+
.hqpu-ver-arrow { color: #52525b; }
|
|
3441
|
+
.hqpu-ver-new { color: var(--hq-emerald); font-weight: 700; }
|
|
3442
|
+
.hqpu-log-toggle {
|
|
3443
|
+
display: inline-flex;
|
|
3444
|
+
align-items: center;
|
|
3445
|
+
gap: 2px;
|
|
3446
|
+
background: none;
|
|
3447
|
+
border: 0;
|
|
3448
|
+
padding: 4px;
|
|
3449
|
+
font-size: 10px;
|
|
3450
|
+
color: var(--hq-muted);
|
|
3451
|
+
cursor: pointer;
|
|
3452
|
+
}
|
|
3453
|
+
.hqpu-log-toggle:hover { color: var(--hq-text); }
|
|
3454
|
+
.hqpu-log-toggle svg { width: 12px; height: 12px; transition: transform 0.15s ease; }
|
|
3455
|
+
.hqpu-log-toggle[data-open='true'] svg { transform: rotate(180deg); }
|
|
3456
|
+
.hqpu-changelog-drawer {
|
|
3457
|
+
margin-top: 8px;
|
|
3458
|
+
padding: 8px;
|
|
3459
|
+
border-radius: 6px;
|
|
3460
|
+
border: 0.5px solid #27272a;
|
|
3461
|
+
background: rgba(24, 24, 27, 0.8);
|
|
3462
|
+
font-size: 10px;
|
|
3463
|
+
}
|
|
3464
|
+
.hqpu-changelog-drawer-title {
|
|
3465
|
+
font-size: 9px;
|
|
3466
|
+
font-weight: 500;
|
|
3467
|
+
text-transform: uppercase;
|
|
3468
|
+
letter-spacing: 0.05em;
|
|
3469
|
+
color: #a1a1aa;
|
|
3470
|
+
}
|
|
3471
|
+
.hqpu-changelog-drawer ul {
|
|
3472
|
+
margin: 4px 0 0;
|
|
3473
|
+
padding-left: 16px;
|
|
3474
|
+
color: #d4d4d8;
|
|
3475
|
+
line-height: 16px;
|
|
3476
|
+
}
|
|
3477
|
+
|
|
3478
|
+
/* Blocked / incompatible card: dimmed, rose badge, no install button */
|
|
3479
|
+
.hqpu-card--blocked {
|
|
3480
|
+
opacity: 0.8;
|
|
3481
|
+
background: rgba(39, 39, 42, 0.6);
|
|
3482
|
+
border-color: #27272a;
|
|
3483
|
+
}
|
|
3484
|
+
.hqpu-card--blocked .hqpu-avatar {
|
|
3485
|
+
background: rgba(39, 39, 42, 0.5);
|
|
3486
|
+
border-color: #27272a;
|
|
3487
|
+
color: #71717a;
|
|
3488
|
+
}
|
|
3489
|
+
.hqpu-card--blocked .hqpu-card-title { color: #a1a1aa; }
|
|
3490
|
+
.hqpu-blocked-badge {
|
|
3491
|
+
font-size: 9px;
|
|
3492
|
+
padding: 2px 6px;
|
|
3493
|
+
border-radius: 4px;
|
|
3494
|
+
color: #fb7185;
|
|
3495
|
+
background: rgba(76, 5, 25, 0.5);
|
|
3496
|
+
border: 0.5px solid rgba(136, 19, 55, 0.5);
|
|
3497
|
+
}
|
|
3498
|
+
.hqpu-reason-line {
|
|
3499
|
+
display: flex;
|
|
3500
|
+
align-items: flex-start;
|
|
3501
|
+
gap: 4px;
|
|
3502
|
+
margin: 8px 0 0;
|
|
3503
|
+
padding: 6px;
|
|
3504
|
+
border-radius: 5px;
|
|
3505
|
+
border: 0.5px solid rgba(136, 19, 55, 0.2);
|
|
3506
|
+
background: rgba(76, 5, 25, 0.2);
|
|
3507
|
+
font-size: 10px;
|
|
3508
|
+
color: rgba(251, 113, 133, 0.9);
|
|
3509
|
+
}
|
|
3510
|
+
.hqpu-reason-line svg { width: 12px; height: 12px; flex: none; margin-top: 1px; }
|
|
3511
|
+
|
|
3512
|
+
/* Sticky footer */
|
|
3513
|
+
.hqpu-footer {
|
|
3514
|
+
flex: none;
|
|
3515
|
+
display: flex;
|
|
3516
|
+
flex-direction: column;
|
|
3517
|
+
align-items: stretch;
|
|
3518
|
+
gap: 8px;
|
|
3519
|
+
padding: 10px 12px 12px;
|
|
3520
|
+
border-top: 0.5px solid var(--hq-border);
|
|
3521
|
+
background: color-mix(in srgb, var(--hq-bg) 95%, transparent);
|
|
3522
|
+
}
|
|
3523
|
+
.hqpu-foot-meta {
|
|
3524
|
+
display: flex;
|
|
3525
|
+
align-items: center;
|
|
3526
|
+
justify-content: space-between;
|
|
3527
|
+
gap: 8px;
|
|
3528
|
+
font-size: 10px;
|
|
3529
|
+
color: var(--hq-muted);
|
|
3530
|
+
}
|
|
3531
|
+
.hqpu-foot-set {
|
|
3532
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
3533
|
+
}
|
|
3534
|
+
.hqpu-foot-actions {
|
|
3535
|
+
display: flex;
|
|
3536
|
+
gap: 8px;
|
|
3537
|
+
}
|
|
3538
|
+
.hqpu-btn--block {
|
|
3539
|
+
flex: 1;
|
|
3540
|
+
height: 32px;
|
|
3541
|
+
background: var(--hq-brand);
|
|
3542
|
+
color: #fff;
|
|
3543
|
+
font-size: 11px;
|
|
3544
|
+
font-weight: 500;
|
|
3545
|
+
border-radius: 6px;
|
|
3546
|
+
box-shadow: 0 4px 12px rgba(127, 29, 29, 0.4);
|
|
3547
|
+
}
|
|
3548
|
+
.hqpu-btn--block:hover:not(:disabled) { background: var(--hq-brand-soft); }
|
|
3549
|
+
.hqpu-btn--block:disabled { opacity: 0.5; box-shadow: none; }
|
|
3550
|
+
.hqpu-btn--ignore {
|
|
3551
|
+
height: 32px;
|
|
3552
|
+
padding: 0 10px;
|
|
3553
|
+
background: var(--hq-card);
|
|
3554
|
+
border: 0.5px solid var(--hq-border);
|
|
3555
|
+
color: var(--hq-muted);
|
|
3556
|
+
font-size: 10px;
|
|
3557
|
+
border-radius: 6px;
|
|
3558
|
+
}
|
|
3559
|
+
.hqpu-btn--ignore:hover:not(:disabled) { background: var(--hq-hover); color: var(--hq-text); }
|
|
3560
|
+
.hqpu-footnote {
|
|
3561
|
+
margin: 0;
|
|
3562
|
+
font-size: 9px;
|
|
3563
|
+
text-align: center;
|
|
3564
|
+
color: var(--hq-muted);
|
|
3565
|
+
}
|
|
3566
|
+
|
|
3567
|
+
/* Shared bits on the new palette */
|
|
3568
|
+
.hqpu-status { color: var(--hq-muted); font-size: 11px; }
|
|
3569
|
+
.hqpu-empty { color: var(--hq-muted); font-size: 11px; padding: 16px 0; }
|
|
3570
|
+
.hqpu-toast { background: var(--hq-card); border: 0.5px solid var(--hq-border); color: var(--hq-text); font-size: 12px; }
|
|
3571
|
+
.hqpu-skeleton-fill { background: #3f3f46; }
|
|
3572
|
+
.hqpu-job { background: var(--hq-card); border-color: var(--hq-border); }
|
|
3573
|
+
.hqpu-job-meta { color: var(--hq-muted); }
|
|
3574
|
+
.hqpu-release-notes { color: var(--hq-muted); font-size: 11px; }
|
|
3575
|
+
.hqpu-advanced > summary { color: var(--hq-muted); }
|
|
3576
|
+
.hqpu-recent-jobs li { color: var(--hq-muted); font-size: 10px; }
|
|
2841
3577
|
`;
|
|
2842
3578
|
const STYLE_TAG_ID = "data-plugin-css=\"huaqiu-plugin-update\"";
|
|
2843
3579
|
/**
|