@huaqiu/dsh-tool-plugin-update 0.6.11 → 0.6.13

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 CHANGED
@@ -317,8 +317,8 @@ window.__ModuleLoader__.load({
317
317
  * to `current`: the plugin is at (or ahead of) the offered release, there is
318
318
  * nothing to install, and no install control may be offered for it. Every
319
319
  * other state passes through untouched — `install` (plugin absent locally)
320
- * has no local version to compare, and `blocked`/`ignored`/`current` are
321
- * already non-actionable. Unknown server fields are preserved verbatim: the
320
+ * has no local version to compare, and `ignored`/`current` are already
321
+ * non-actionable. Unknown server fields are preserved verbatim: the
322
322
  * client stays a thin reader of the hq-edge report shape.
323
323
  */
324
324
  function normalizePluginUpdateItem(item) {
@@ -503,10 +503,32 @@ window.__ModuleLoader__.load({
503
503
  return request("/check", { method: "POST" }).then(normalizePluginUpdateReport);
504
504
  }
505
505
  /** POST the install transaction for the confirmed set version. */
506
- function installSet(setVersion) {
506
+ function installSet(setVersion, pluginNames) {
507
507
  return request("/install", {
508
508
  method: "POST",
509
- body: JSON.stringify({ setVersion })
509
+ body: JSON.stringify({
510
+ setVersion,
511
+ ...pluginNames ? { pluginNames } : {}
512
+ })
513
+ });
514
+ }
515
+ /** Persist a per-plugin decision for this release set. */
516
+ function ignorePlugin(setVersion, name) {
517
+ return request("/plugin-ignore", {
518
+ method: "POST",
519
+ body: JSON.stringify({
520
+ setVersion,
521
+ name
522
+ })
523
+ });
524
+ }
525
+ function unignorePlugin(setVersion, name) {
526
+ return request("/plugin-unignore", {
527
+ method: "POST",
528
+ body: JSON.stringify({
529
+ setVersion,
530
+ name
531
+ })
510
532
  });
511
533
  }
512
534
  /** POST ignore for the current offer (set-scoped, persists across restarts). */
@@ -588,7 +610,7 @@ window.__ModuleLoader__.load({
588
610
  entryTooltip: "查看可用的插件更新",
589
611
  viewTitle: "插件更新",
590
612
  viewIntro: "检查并安装可用的插件更新",
591
- viewInfo: "在这里查看插件集的更新。标注为「被阻止」的插件因主机或 HQ Edge 版本不兼容而无法安装;已是最新的插件无需操作。",
613
+ viewInfo: "在这里查看插件集的更新;已是最新的插件无需操作。",
592
614
  refresh: "刷新",
593
615
  close: "关闭",
594
616
  loading: "正在读取插件更新…",
@@ -596,6 +618,7 @@ window.__ModuleLoader__.load({
596
618
  checkFailed: "检查更新失败,请重试",
597
619
  installAll: (count) => `安装整套更新(${count} 项)`,
598
620
  installOne: "安装整套",
621
+ installOnePlugin: "安装此插件",
599
622
  installOneTip: "将安装整套 N 项更新并自动重启 DSH,而不仅是此插件",
600
623
  installing: "正在安装…(DSH 将自动重启)",
601
624
  retry: "重试",
@@ -609,22 +632,9 @@ window.__ModuleLoader__.load({
609
632
  groupCount: (count) => `${count} 个插件`,
610
633
  group: {
611
634
  actionable: "待处理",
612
- blocked: "无法安装",
613
635
  ignored: "已忽略",
614
636
  current: "已是最新"
615
637
  },
616
- state: {
617
- current: "当前",
618
- update: "可更新",
619
- install: "待安装",
620
- ignored: "已忽略",
621
- blocked: "被阻止"
622
- },
623
- blockedReason: {
624
- host: "不适用于当前 EDA 主机",
625
- "hq-edge-version": "当前 HQ Edge 版本不兼容",
626
- "runtime-unknown": "HQ Edge 版本未知,无法校验"
627
- },
628
638
  runtime: {
629
639
  title: "HQ Edge 运行时",
630
640
  current: "当前版本",
@@ -759,10 +769,9 @@ window.__ModuleLoader__.load({
759
769
  allChangelog: "展开全部更新日志",
760
770
  changelogBtn: "日志",
761
771
  changelogTitle: "更新内容:",
762
- blockedBadge: "无法安装",
763
772
  footerCount: (n) => `准备安装 ${n} 项兼容插件`,
764
773
  footerSet: (v) => `版本集: v${v}`,
765
- installAllSet: (v) => `一键更新全套插件 (v${v})`,
774
+ installAllSet: (v) => `更新插件集 (v${v})`,
766
775
  ignoreBtn: "忽略",
767
776
  footnote: "更新将自动应用并重启 DSH 视图,不影响 EDA 图纸数据"
768
777
  }
@@ -781,7 +790,7 @@ window.__ModuleLoader__.load({
781
790
  entryTooltip: "Review available plugin updates",
782
791
  viewTitle: "Plugin Updates",
783
792
  viewIntro: "Check for and install available plugin updates",
784
- viewInfo: "Review the plugin set updates here. A plugin marked Blocked cannot be installed because its host or HQ Edge version is incompatible; a plugin marked Current needs no action.",
793
+ viewInfo: "Review the plugin set updates here. Plugins that are up to date need no action.",
785
794
  refresh: "Refresh",
786
795
  close: "Close",
787
796
  loading: "Reading plugin updates…",
@@ -789,6 +798,7 @@ window.__ModuleLoader__.load({
789
798
  checkFailed: "Failed to check for updates — please retry",
790
799
  installAll: (count) => `Install whole set (${count})`,
791
800
  installOne: "Install set",
801
+ installOnePlugin: "Install this plugin",
792
802
  installOneTip: "Installs the whole set of N updates and restarts DSH — not just this plugin",
793
803
  installing: "Installing… (DSH will restart)",
794
804
  retry: "Retry",
@@ -802,22 +812,9 @@ window.__ModuleLoader__.load({
802
812
  groupCount: (count) => `${count} plugin${count === 1 ? "" : "s"}`,
803
813
  group: {
804
814
  actionable: "Actionable",
805
- blocked: "Blocked",
806
815
  ignored: "Ignored",
807
816
  current: "Up to date"
808
817
  },
809
- state: {
810
- current: "Current",
811
- update: "Update",
812
- install: "Install",
813
- ignored: "Ignored",
814
- blocked: "Blocked"
815
- },
816
- blockedReason: {
817
- host: "Not applicable to the current EDA host",
818
- "hq-edge-version": "Incompatible with the current HQ Edge version",
819
- "runtime-unknown": "HQ Edge version unknown — cannot verify"
820
- },
821
818
  runtime: {
822
819
  title: "HQ Edge Runtime",
823
820
  current: "Current version",
@@ -952,7 +949,6 @@ window.__ModuleLoader__.load({
952
949
  allChangelog: "Expand all changelogs",
953
950
  changelogBtn: "Log",
954
951
  changelogTitle: "What changed:",
955
- blockedBadge: "Cannot install",
956
952
  footerCount: (n) => `Ready to install ${n} compatible plugin${n === 1 ? "" : "s"}`,
957
953
  footerSet: (v) => `Set: v${v}`,
958
954
  installAllSet: (v) => `Update all plugins (v${v})`,
@@ -1059,19 +1055,6 @@ window.__ModuleLoader__.load({
1059
1055
  function shortName(name) {
1060
1056
  return (name.startsWith("@") ? name.slice(name.indexOf("/") + 1) : name).replace(/^dsh-(?:host-|client-)?/, "");
1061
1057
  }
1062
- /** Normalize the server's block reason to a list (it may arrive as a string). */
1063
- function blockedByList(item) {
1064
- const by = item.blockedBy;
1065
- if (Array.isArray(by)) return by.filter((entry) => typeof entry === "string");
1066
- return typeof by === "string" && by.length > 0 ? [by] : [];
1067
- }
1068
- function blockedReason(item, copy) {
1069
- const by = blockedByList(item);
1070
- if (by.includes("host")) return copy.blockedReason.host;
1071
- if (by.includes("hq-edge-version")) return copy.blockedReason["hq-edge-version"];
1072
- if (by.includes("runtime-unknown")) return copy.blockedReason["runtime-unknown"];
1073
- return by.length > 0 ? by.join(", ") : void 0;
1074
- }
1075
1058
  /** Two-letter avatar initials for a card (CJK-safe). */
1076
1059
  function avatarInitials(item) {
1077
1060
  const src = typeof item.displayName === "string" && item.displayName.trim().length > 0 ? item.displayName.trim() : shortName(item.name);
@@ -1081,22 +1064,37 @@ window.__ModuleLoader__.load({
1081
1064
  return src.replace(/^@/, "").slice(0, 2).toUpperCase();
1082
1065
  }
1083
1066
  /** Shared per-card changelog toggle drawer (the per-plugin changes[] list). */
1084
- function changelogDrawer(item, copy, open) {
1067
+ function changelogDrawer(item, copy, open, onInstall, onIgnore) {
1085
1068
  const drawer = el("div", "hqpu-changelog-drawer");
1086
1069
  drawer.style.display = open ? "" : "none";
1087
1070
  drawer.append(el("div", "hqpu-changelog-drawer-title", copy.ui.changelogTitle));
1088
1071
  const ul = el("ul");
1089
1072
  for (const change of item.changes ?? []) if (typeof change === "string" && change.length > 0) ul.append(el("li", "", change));
1090
- drawer.append(ul);
1073
+ if (ul.childElementCount > 0) drawer.append(ul);
1074
+ const actions = el("div", "hqpu-changelog-actions");
1075
+ if (item.state === "update" || item.state === "install") {
1076
+ const install = el("button", "hqpu-card-action hqpu-card-action--install", copy.installOnePlugin);
1077
+ install.type = "button";
1078
+ install.title = copy.installOneTip;
1079
+ install.addEventListener("click", onInstall);
1080
+ const ignore = el("button", "hqpu-card-action", copy.ignore);
1081
+ ignore.type = "button";
1082
+ ignore.addEventListener("click", onIgnore);
1083
+ actions.append(install, ignore);
1084
+ } else if (item.state === "ignored") {
1085
+ const show = el("button", "hqpu-card-action hqpu-card-action--install", copy.unignore);
1086
+ show.type = "button";
1087
+ show.addEventListener("click", onIgnore);
1088
+ actions.append(show);
1089
+ }
1090
+ if (actions.childElementCount > 0) drawer.append(actions);
1091
1091
  return drawer;
1092
1092
  }
1093
1093
  /** One package card per the mockup: avatar initials, display name + package
1094
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");
1095
+ * inline changelog. */
1096
+ function packageCard(item, copy, open, onToggle, onInstall, onIgnore) {
1097
+ const card = el("li", "hqpu-card");
1100
1098
  card.dataset.pluginName = item.name;
1101
1099
  card.dataset.state = item.state;
1102
1100
  const head = el("div", "hqpu-card-head");
@@ -1117,8 +1115,8 @@ window.__ModuleLoader__.load({
1117
1115
  main.append(ver);
1118
1116
  left.append(avatar, main);
1119
1117
  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) {
1118
+ const hasDetails = Array.isArray(item.changes) && item.changes.length > 0 || item.state === "update" || item.state === "install" || item.state === "ignored";
1119
+ if (hasDetails) {
1122
1120
  const toggle = el("button", "hqpu-log-toggle");
1123
1121
  toggle.type = "button";
1124
1122
  toggle.dataset.open = open ? "true" : "false";
@@ -1128,21 +1126,11 @@ window.__ModuleLoader__.load({
1128
1126
  }
1129
1127
  head.append(left, right);
1130
1128
  card.append(head);
1131
- if (!blocked && Array.isArray(item.changes) && item.changes.length > 0) card.append(changelogDrawer(item, copy, open));
1132
- if (blocked) {
1133
- const reason = blockedReason(item, copy);
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
- }
1141
- }
1129
+ if (hasDetails) card.append(changelogDrawer(item, copy, open, onInstall, onIgnore));
1142
1130
  return card;
1143
1131
  }
1144
1132
  /** A section: head (title + count pill + expand-all toggle) then its cards. */
1145
- function group(heading, items, copy, changelogOpen, allOpen, onToggle, onToggleAll) {
1133
+ function group(heading, items, copy, changelogOpen, allOpen, onToggle, onToggleAll, onInstall, onIgnore) {
1146
1134
  if (items.length === 0) return null;
1147
1135
  const section = el("section", "hqpu-group");
1148
1136
  section.dataset.group = heading;
@@ -1151,14 +1139,14 @@ window.__ModuleLoader__.load({
1151
1139
  titleWrap.append(el("span", "", heading));
1152
1140
  titleWrap.append(el("span", "hqpu-count-pill", String(items.length)));
1153
1141
  head.append(titleWrap);
1154
- if (items.some((i) => i.state !== "blocked" && Array.isArray(i.changes) && i.changes.length > 0)) {
1142
+ if (items.some((i) => Array.isArray(i.changes) && i.changes.length > 0)) {
1155
1143
  const all = el("button", "hqpu-all-changelog", copy.ui.allChangelog);
1156
1144
  all.type = "button";
1157
1145
  all.addEventListener("click", onToggleAll);
1158
1146
  head.append(all);
1159
1147
  }
1160
1148
  const list = el("ul", "hqpu-cards");
1161
- for (const item of items) list.append(packageCard(item, copy, allOpen || changelogOpen.has(item.name), () => onToggle(item.name)));
1149
+ for (const item of items) list.append(packageCard(item, copy, allOpen || changelogOpen.has(item.name), () => onToggle(item.name), () => onInstall(item.name), () => onIgnore(item)));
1162
1150
  section.append(head, list);
1163
1151
  return section;
1164
1152
  }
@@ -1634,7 +1622,7 @@ window.__ModuleLoader__.load({
1634
1622
  } else if (typeof runtime.lastError === "string" && runtime.lastError.length > 0) card.append(el("p", "hqpu-status", `${copy.lastError}: ${runtime.lastError}`));
1635
1623
  return card;
1636
1624
  }
1637
- function renderList(section, report, copy, changelogOpen, allOpen, onToggleCard, onToggleAll, onRetryCheck) {
1625
+ function renderList(section, report, copy, changelogOpen, allOpen, onToggleCard, onToggleAll, onRetryCheck, onInstall, onIgnore) {
1638
1626
  section.textContent = "";
1639
1627
  if (report === null) {
1640
1628
  section.append(skeleton(copy));
@@ -1651,12 +1639,11 @@ window.__ModuleLoader__.load({
1651
1639
  const byState = (state) => report.items.filter((item) => item.state === state);
1652
1640
  const order = [
1653
1641
  [copy.group.actionable, [...byState("update"), ...byState("install")]],
1654
- [copy.group.blocked, byState("blocked")],
1655
1642
  [copy.group.ignored, byState("ignored")],
1656
1643
  [copy.group.current, byState("current")]
1657
1644
  ];
1658
1645
  for (const [heading, items] of order) {
1659
- const node = group(heading, items, copy, changelogOpen, allOpen, onToggleCard, onToggleAll);
1646
+ const node = group(heading, items, copy, changelogOpen, allOpen, onToggleCard, onToggleAll, onInstall, onIgnore);
1660
1647
  if (node !== null) section.append(node);
1661
1648
  }
1662
1649
  }
@@ -1669,7 +1656,7 @@ window.__ModuleLoader__.load({
1669
1656
  if (engine !== null) section.append(engine);
1670
1657
  }
1671
1658
  /** Run the install transaction (a new durable job), then let the store poll it. */
1672
- async function runInstall(store, copy) {
1659
+ async function runInstall(store, copy, pluginNames) {
1673
1660
  const report = store.report();
1674
1661
  if (report === null) return;
1675
1662
  if (report.manifestVersion === null) {
@@ -1678,7 +1665,7 @@ window.__ModuleLoader__.load({
1678
1665
  }
1679
1666
  store.setInstalling(true);
1680
1667
  try {
1681
- const result = await installSet(report.manifestVersion);
1668
+ const result = await installSet(report.manifestVersion, pluginNames);
1682
1669
  if (result.error !== void 0) {
1683
1670
  store.setInstalling(false);
1684
1671
  showToast(`${copy.installError}: ${result.error}`, "error");
@@ -1742,7 +1729,7 @@ window.__ModuleLoader__.load({
1742
1729
  * The sticky footer: left meta ("准备安装 N 项兼容插件" / "版本集: vX"), a
1743
1730
  * full-width primary "一键更新全套插件 (vX)" (install = one durable job),
1744
1731
  * a secondary 忽略 wired to the existing ignore/unignore affordance, and the
1745
- * footnote. The count EXCLUDES blocked / ignored / already-current entries.
1732
+ * footnote. The count EXCLUDES ignored / already-current entries.
1746
1733
  */
1747
1734
  function renderFooter(footer, installBtn, ignoreBtn, countEl, setEl, report, copy, installing, store) {
1748
1735
  if (report === null) {
@@ -2036,6 +2023,12 @@ window.__ModuleLoader__.load({
2036
2023
  render();
2037
2024
  }, () => {
2038
2025
  store.check();
2026
+ }, (name) => {
2027
+ runInstall(store, copy, [name]);
2028
+ }, (item) => {
2029
+ const report = store.report();
2030
+ if (report?.manifestVersion === null || report?.manifestVersion === void 0) return;
2031
+ (item.state === "ignored" ? unignorePlugin(report.manifestVersion, item.name) : ignorePlugin(report.manifestVersion, item.name)).then(() => store.check()).catch(() => void 0);
2039
2032
  });
2040
2033
  renderRuntime(runtimeSection, report, copy, runtimeActions, dismissedAlert, () => {
2041
2034
  dismissedAlert = true;
@@ -3426,6 +3419,7 @@ window.__ModuleLoader__.load({
3426
3419
  align-items: start;
3427
3420
  }
3428
3421
  .hqpu-card {
3422
+ position: relative;
3429
3423
  margin: 0;
3430
3424
  padding: 10px;
3431
3425
  border-radius: 8px;
@@ -3491,6 +3485,30 @@ window.__ModuleLoader__.load({
3491
3485
  .hqpu-log-toggle:hover { color: var(--hq-text); }
3492
3486
  .hqpu-log-toggle svg { width: 12px; height: 12px; transition: transform 0.15s ease; }
3493
3487
  .hqpu-log-toggle[data-open='true'] svg { transform: rotate(180deg); }
3488
+ .hqpu-changelog-actions {
3489
+ display: flex;
3490
+ gap: 8px;
3491
+ margin-top: 10px;
3492
+ padding-top: 8px;
3493
+ border-top: 0.5px solid var(--hq-border);
3494
+ }
3495
+ .hqpu-card-action {
3496
+ height: 28px;
3497
+ padding: 0 10px;
3498
+ border: 0.5px solid var(--hq-border-strong);
3499
+ border-radius: 6px;
3500
+ background: var(--hq-card);
3501
+ color: var(--hq-text);
3502
+ font-size: 10px;
3503
+ cursor: pointer;
3504
+ }
3505
+ .hqpu-card-action:hover { border-color: var(--hq-brand-soft); color: var(--hq-brand-soft); }
3506
+ .hqpu-card-action--install {
3507
+ border-color: var(--hq-brand);
3508
+ background: var(--hq-brand);
3509
+ color: var(--hq-brand-fg);
3510
+ }
3511
+ .hqpu-card-action--install:hover { border-color: var(--hq-brand-soft); background: var(--hq-brand-soft); color: var(--hq-brand-fg); }
3494
3512
  .hqpu-changelog-drawer {
3495
3513
  margin-top: 8px;
3496
3514
  padding: 8px;
@@ -3513,40 +3531,6 @@ window.__ModuleLoader__.load({
3513
3531
  line-height: 16px;
3514
3532
  }
3515
3533
 
3516
- /* Blocked / incompatible card: dimmed, rose badge, no install button */
3517
- .hqpu-card--blocked {
3518
- opacity: 0.8;
3519
- background: color-mix(in srgb, var(--hq-card) 60%, transparent);
3520
- border-color: var(--hq-border);
3521
- }
3522
- .hqpu-card--blocked .hqpu-avatar {
3523
- background: color-mix(in srgb, var(--hq-card) 50%, transparent);
3524
- border-color: var(--hq-border);
3525
- color: var(--hq-faint);
3526
- }
3527
- .hqpu-card--blocked .hqpu-card-title { color: var(--hq-muted); }
3528
- .hqpu-blocked-badge {
3529
- font-size: 9px;
3530
- padding: 2px 6px;
3531
- border-radius: 4px;
3532
- color: var(--hq-rose);
3533
- background: color-mix(in srgb, var(--hq-rose) 18%, transparent);
3534
- border: 0.5px solid color-mix(in srgb, var(--hq-rose) 40%, transparent);
3535
- }
3536
- .hqpu-reason-line {
3537
- display: flex;
3538
- align-items: flex-start;
3539
- gap: 4px;
3540
- margin: 8px 0 0;
3541
- padding: 6px;
3542
- border-radius: 5px;
3543
- border: 0.5px solid color-mix(in srgb, var(--hq-rose) 20%, transparent);
3544
- background: color-mix(in srgb, var(--hq-rose) 8%, transparent);
3545
- font-size: 10px;
3546
- color: var(--hq-rose);
3547
- }
3548
- .hqpu-reason-line svg { width: 12px; height: 12px; flex: none; margin-top: 1px; }
3549
-
3550
3534
  /* Sticky footer */
3551
3535
  .hqpu-footer {
3552
3536
  flex: none;
@@ -3776,7 +3760,7 @@ window.__ModuleLoader__.load({
3776
3760
  if (report.runtime?.updateAvailable) count += 1;
3777
3761
  if (count === 0) {
3778
3762
  const latest = this.recent[0];
3779
- if (latest !== void 0 && (latest.phase === "failed" || latest.phase === "rolled-back")) count = 1;
3763
+ if (latest !== void 0 && TERMINAL_PHASES.has(latest.phase)) count = 1;
3780
3764
  }
3781
3765
  return count;
3782
3766
  }