@huaqiu/dsh-tool-plugin-update 0.5.21 → 0.6.1
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 +1144 -259
- package/lib/client.js.map +1 -1
- package/package.json +3 -3
- package/src/client/api.ts +12 -8
- package/src/client/copy.ts +46 -18
- package/src/client/icons.ts +91 -0
- package/src/client/index.ts +663 -121
- package/src/client/update-view.ts +478 -160
package/lib/client.js
CHANGED
|
@@ -64,15 +64,40 @@ window.__ModuleLoader__.load({
|
|
|
64
64
|
applyBadge
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* Re-insert the entry after the New Session row, in the family's intended
|
|
69
|
+
* order.
|
|
70
|
+
*
|
|
71
|
+
* The `familySelectors` array order is the single source of truth for visual
|
|
72
|
+
* order, so the rendered order is stable regardless of which plugin mounts
|
|
73
|
+
* first or of observer callback order — a re-render can never swap two rows.
|
|
74
|
+
* (Earlier builds used the `position: 'before' | 'after'` convention, which
|
|
75
|
+
* clustered rows by mount order and let a late-mounting `before` row steal the
|
|
76
|
+
* lead. The array order supersedes it; `position` remains only as a fallback
|
|
77
|
+
* for a row whose selector is absent from the family list.)
|
|
78
|
+
*/
|
|
68
79
|
function placeEntry(root, entry, options) {
|
|
69
80
|
const button = newSessionButton(root);
|
|
70
81
|
if (button === void 0) return false;
|
|
71
82
|
if (entry.parentElement !== root) {
|
|
72
83
|
const row = button.closest("[class*=\"logoRow\"]");
|
|
73
84
|
const base = row !== null && row.parentElement === root ? row : button;
|
|
74
|
-
const
|
|
75
|
-
const
|
|
85
|
+
const order = options.familySelectors;
|
|
86
|
+
const present = Array.from(root.children).filter((el) => el instanceof HTMLElement && el.matches(order.join(", "))).map((el) => ({
|
|
87
|
+
el,
|
|
88
|
+
idx: order.findIndex((sel) => el.matches(sel))
|
|
89
|
+
}));
|
|
90
|
+
const selfIndex = order.indexOf(options.rowSelector);
|
|
91
|
+
let anchor;
|
|
92
|
+
if (selfIndex === -1) anchor = options.position === "before" ? present.length > 0 ? present[0].el : base.nextElementSibling : present.length > 0 ? present[present.length - 1].el.nextElementSibling : base.nextElementSibling;
|
|
93
|
+
else {
|
|
94
|
+
const later = present.find((member) => member.idx > selfIndex);
|
|
95
|
+
if (later !== void 0) anchor = later.el;
|
|
96
|
+
else {
|
|
97
|
+
const earlier = [...present].reverse().find((member) => member.idx < selfIndex);
|
|
98
|
+
anchor = earlier !== void 0 ? earlier.el.nextElementSibling : base.nextElementSibling;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
76
101
|
root.insertBefore(entry, anchor ?? null);
|
|
77
102
|
}
|
|
78
103
|
return true;
|
|
@@ -158,10 +183,11 @@ window.__ModuleLoader__.load({
|
|
|
158
183
|
* family row means adding its selector here (and to no plugin-local list).
|
|
159
184
|
*/
|
|
160
185
|
const HUAQIU_SIDEBAR_ENTRY_FAMILY = [
|
|
186
|
+
"[data-hq-plugin-update-entry]",
|
|
161
187
|
"[data-hqcg-footprint-entry]",
|
|
162
188
|
"[data-hqcg-symbol-entry]",
|
|
163
189
|
"[data-hqcg-schematic-entry]",
|
|
164
|
-
"[data-hq-
|
|
190
|
+
"[data-hq-dummy-entry]"
|
|
165
191
|
];
|
|
166
192
|
/**
|
|
167
193
|
* Read the host UI language from `<html lang>`.
|
|
@@ -261,6 +287,13 @@ window.__ModuleLoader__.load({
|
|
|
261
287
|
body: JSON.stringify({ setVersion })
|
|
262
288
|
});
|
|
263
289
|
}
|
|
290
|
+
/** POST ignore for the current offer (set-scoped, persists across restarts). */
|
|
291
|
+
function ignoreOffer(setVersion) {
|
|
292
|
+
return request("/ignore", {
|
|
293
|
+
method: "POST",
|
|
294
|
+
body: JSON.stringify({ setVersion })
|
|
295
|
+
});
|
|
296
|
+
}
|
|
264
297
|
/** POST unignore for the set version (reverses an ignore). */
|
|
265
298
|
function unignoreOffer(setVersion) {
|
|
266
299
|
return request("/unignore", {
|
|
@@ -273,15 +306,27 @@ window.__ModuleLoader__.load({
|
|
|
273
306
|
entryLabel: "插件更新",
|
|
274
307
|
entryTooltip: "查看可用的插件更新",
|
|
275
308
|
viewTitle: "插件更新",
|
|
309
|
+
viewIntro: "检查并安装可用的插件更新",
|
|
310
|
+
viewInfo: "在这里查看插件集的更新。标注为「被阻止」的插件因主机或 HQ Edge 版本不兼容而无法安装;已是最新的插件无需操作。",
|
|
276
311
|
refresh: "刷新",
|
|
277
312
|
close: "关闭",
|
|
313
|
+
loading: "正在读取插件更新…",
|
|
278
314
|
empty: "没有可用的插件更新",
|
|
279
|
-
checkFailed: "
|
|
280
|
-
manifestVersion: "插件集",
|
|
281
|
-
ignoredOffer: "已忽略当前插件集更新",
|
|
282
|
-
unignore: "恢复提醒",
|
|
315
|
+
checkFailed: "检查更新失败,请重试",
|
|
283
316
|
installAll: (count) => `安装 ${count} 项更新`,
|
|
284
|
-
|
|
317
|
+
installOne: "安装",
|
|
318
|
+
installing: "正在安装…(DSH 将自动重启)",
|
|
319
|
+
nothingToInstall: "暂无可安装的更新",
|
|
320
|
+
ignore: "忽略此版本",
|
|
321
|
+
unignore: "恢复提醒",
|
|
322
|
+
ignoredOffer: "已忽略当前插件集更新",
|
|
323
|
+
groupCount: (count) => `${count} 个插件`,
|
|
324
|
+
group: {
|
|
325
|
+
actionable: "待处理",
|
|
326
|
+
blocked: "无法安装",
|
|
327
|
+
ignored: "已忽略",
|
|
328
|
+
current: "已是最新"
|
|
329
|
+
},
|
|
285
330
|
state: {
|
|
286
331
|
current: "当前",
|
|
287
332
|
update: "可更新",
|
|
@@ -296,14 +341,16 @@ window.__ModuleLoader__.load({
|
|
|
296
341
|
},
|
|
297
342
|
runtime: {
|
|
298
343
|
title: "HQ Edge 运行时",
|
|
299
|
-
|
|
300
|
-
|
|
344
|
+
current: "当前版本",
|
|
345
|
+
latest: "最新版本",
|
|
346
|
+
set: "发布插件集",
|
|
347
|
+
checkedAt: "上次检查",
|
|
348
|
+
source: "更新源",
|
|
301
349
|
unknown: "版本未知",
|
|
302
350
|
notConfigured: "未配置更新源",
|
|
303
351
|
note: "运行时更新由 EDA 安装器处理"
|
|
304
352
|
},
|
|
305
353
|
lastError: "上次检查失败",
|
|
306
|
-
fetchedAt: "检查时间",
|
|
307
354
|
installError: "安装失败",
|
|
308
355
|
installSuccess: "更新已安装,正在重启 DSH…"
|
|
309
356
|
},
|
|
@@ -311,15 +358,27 @@ window.__ModuleLoader__.load({
|
|
|
311
358
|
entryLabel: "Plugin Updates",
|
|
312
359
|
entryTooltip: "Review available plugin updates",
|
|
313
360
|
viewTitle: "Plugin Updates",
|
|
361
|
+
viewIntro: "Check for and install available plugin updates",
|
|
362
|
+
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.",
|
|
314
363
|
refresh: "Refresh",
|
|
315
364
|
close: "Close",
|
|
365
|
+
loading: "Reading plugin updates…",
|
|
316
366
|
empty: "No plugin updates available",
|
|
317
|
-
checkFailed: "Failed to check for updates",
|
|
318
|
-
manifestVersion: "Plugin set",
|
|
319
|
-
ignoredOffer: "The current plugin-set update is ignored",
|
|
320
|
-
unignore: "Show again",
|
|
367
|
+
checkFailed: "Failed to check for updates — please retry",
|
|
321
368
|
installAll: (count) => `Install ${count} update${count === 1 ? "" : "s"}`,
|
|
369
|
+
installOne: "Install",
|
|
322
370
|
installing: "Installing… (DSH will restart)",
|
|
371
|
+
nothingToInstall: "Nothing to install right now",
|
|
372
|
+
ignore: "Ignore this release",
|
|
373
|
+
unignore: "Show again",
|
|
374
|
+
ignoredOffer: "The current plugin-set update is ignored",
|
|
375
|
+
groupCount: (count) => `${count} plugin${count === 1 ? "" : "s"}`,
|
|
376
|
+
group: {
|
|
377
|
+
actionable: "Actionable",
|
|
378
|
+
blocked: "Blocked",
|
|
379
|
+
ignored: "Ignored",
|
|
380
|
+
current: "Up to date"
|
|
381
|
+
},
|
|
323
382
|
state: {
|
|
324
383
|
current: "Current",
|
|
325
384
|
update: "Update",
|
|
@@ -334,44 +393,146 @@ window.__ModuleLoader__.load({
|
|
|
334
393
|
},
|
|
335
394
|
runtime: {
|
|
336
395
|
title: "HQ Edge Runtime",
|
|
337
|
-
|
|
338
|
-
|
|
396
|
+
current: "Current version",
|
|
397
|
+
latest: "Latest version",
|
|
398
|
+
set: "Release set",
|
|
399
|
+
checkedAt: "Last checked",
|
|
400
|
+
source: "Update source",
|
|
339
401
|
unknown: "Version unknown",
|
|
340
402
|
notConfigured: "No update source configured",
|
|
341
403
|
note: "Runtime updates are handled by the EDA installer"
|
|
342
404
|
},
|
|
343
405
|
lastError: "Last check failed",
|
|
344
|
-
fetchedAt: "Checked at",
|
|
345
406
|
installError: "Install failed",
|
|
346
407
|
installSuccess: "Update installed — restarting DSH…"
|
|
347
408
|
}
|
|
348
409
|
};
|
|
349
410
|
//#endregion
|
|
411
|
+
//#region src/client/icons.ts
|
|
412
|
+
/**
|
|
413
|
+
* Official DSH icon artwork, inlined as SVG strings.
|
|
414
|
+
*
|
|
415
|
+
* The paths are copied verbatim from `@deepseek-ai/dsh-client-ui-primitives`
|
|
416
|
+
* (deepseek-harness `packages/client/ui-primitives/src/icons/index.tsx`) so the
|
|
417
|
+
* Huaqiu plugin-update view draws the same glyphs as the shell's own plugin
|
|
418
|
+
* manager. Only `currentColor` is used, so every glyph inherits the label ink
|
|
419
|
+
* of whatever surface it sits on — the same contract the primitives rely on.
|
|
420
|
+
*
|
|
421
|
+
* The plugin renders plain DOM (never a React tree), so the artwork is exposed
|
|
422
|
+
* as markup strings rather than components.
|
|
423
|
+
*
|
|
424
|
+
* @module
|
|
425
|
+
*/
|
|
426
|
+
/** Stroke width of the primitives' "Regular" weight. */
|
|
427
|
+
const REGULAR = 1;
|
|
428
|
+
/** Stroke width of the primitives' "Medium" weight. */
|
|
429
|
+
const MEDIUM = 1.3;
|
|
430
|
+
/** Wrap paths in a 16×16 stroked glyph. */
|
|
431
|
+
function glyph(size, strokeWidth, paths, viewBox = "0 0 16 16") {
|
|
432
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="${viewBox}" fill="none" aria-hidden="true" stroke-width="${strokeWidth}" stroke-linecap="round" stroke-linejoin="round">${paths.map((d) => `<path d="${d}" stroke="currentColor" />`).join("")}</svg>`;
|
|
433
|
+
}
|
|
434
|
+
/** Wrap fill-only paths (the check glyph) in their own viewBox. */
|
|
435
|
+
function fillGlyph(size, paths, viewBox) {
|
|
436
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="${viewBox}" fill="none" aria-hidden="true">${paths.map((d) => `<path d="${d}" fill="currentColor" />`).join("")}</svg>`;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* The plugin pinwheel — the glyph the shell's own Plugins sidebar entry uses
|
|
440
|
+
* (`IconPluginPinwheelOutlineRegular`). Shared by the sidebar row and the
|
|
441
|
+
* package cards so both read as the same feature.
|
|
442
|
+
*/
|
|
443
|
+
const PLUGIN_ICON = (size = 16) => glyph(size, REGULAR, [
|
|
444
|
+
"M7.84457 5.06199C11.6605 4.93876 14.7962 6.14848 14.8484 7.76397C14.8875 8.97461 13.1838 10.0696 10.7215 10.5942",
|
|
445
|
+
"M5.12742 8.07731C5.00419 4.26138 6.21391 1.12568 7.8294 1.07351C9.04004 1.03441 10.135 2.73808 10.6596 5.20037",
|
|
446
|
+
"M8.02457 10.6802C4.20865 10.8034 1.07294 9.5937 1.02077 7.97821C0.981678 6.76758 2.68535 5.67262 5.14763 5.14798",
|
|
447
|
+
"M10.7476 7.89535C10.8708 11.7113 9.66109 14.847 8.0456 14.8991C6.83496 14.9382 5.74 13.2346 5.21536 10.7723"
|
|
448
|
+
]);
|
|
449
|
+
/** The toolbar's refresh action (`IconRefreshOutlineRegular`). */
|
|
450
|
+
const REFRESH_ICON = (size = 16) => glyph(size, REGULAR, ["M14.5001 8C14.5 9.28552 14.1188 10.5422 13.4045 11.611C12.6903 12.6799 11.6752 13.5129 10.4875 14.0049C9.29982 14.4968 7.99295 14.6255 6.73212 14.3747C5.4713 14.124 4.31314 13.505 3.4041 12.596C2.49514 11.687 1.87614 10.5288 1.62537 9.26798C1.37459 8.00716 1.50331 6.70028 1.99525 5.51261C2.48719 4.32494 3.32025 3.30981 4.3891 2.59557C5.45795 1.88134 6.71458 1.50008 8.0001 1.5C9.9001 1.5 11.7001 2.3 13.0001 3.6L14.5001 5.1", "M14.4999 1.5V5.1H10.8999"]);
|
|
451
|
+
/** The panel's close action (`IconCloseOutlineMedium`). */
|
|
452
|
+
const CLOSE_ICON = (size = 16) => glyph(size, MEDIUM, ["M2.5 2.5L13.5 13.5", "M13.5 2.5L2.5 13.5"]);
|
|
453
|
+
/** The notice glyph (`IconWarningOutlineRegular`). */
|
|
454
|
+
const WARNING_ICON = (size = 16) => glyph(size, REGULAR, [
|
|
455
|
+
"M8 14.5C11.5899 14.5 14.5 11.5899 14.5 8C14.5 4.41015 11.5899 1.5 8 1.5C4.41015 1.5 1.5 4.41015 1.5 8C1.5 11.5899 4.41015 14.5 8 14.5Z",
|
|
456
|
+
"M8 4.29199V9.79199",
|
|
457
|
+
"M8 10.708V11.708"
|
|
458
|
+
]);
|
|
459
|
+
/** The settled-state glyph (`IconCheckCircleFillRegular`). */
|
|
460
|
+
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");
|
|
461
|
+
/** The install action (`IconDownloadOutlineRegular`). */
|
|
462
|
+
const DOWNLOAD_ICON = (size = 16) => glyph(size, REGULAR, [
|
|
463
|
+
"M8 1.95317V10.0469",
|
|
464
|
+
"M4.25 6.29688L8 10.0469L11.75 6.29688",
|
|
465
|
+
"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"
|
|
466
|
+
]);
|
|
467
|
+
/** The head's info affordance (`IconInfoOutlineRegular`, fill-only artwork). */
|
|
468
|
+
const INFO_ICON = (size = 11) => fillGlyph(size, [
|
|
469
|
+
"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",
|
|
470
|
+
"M7.6127 3.18921V4.55986H6.38735V3.18921H7.6127Z",
|
|
471
|
+
"M7.6127 5.68921V10.8109H6.38735V5.68921H7.6127Z"
|
|
472
|
+
], "0 0 14 14");
|
|
473
|
+
//#endregion
|
|
350
474
|
//#region src/client/update-view.ts
|
|
351
475
|
/**
|
|
352
|
-
* Plugin-update review
|
|
476
|
+
* Plugin-update review view (browser half).
|
|
353
477
|
*
|
|
354
|
-
* Plain-DOM
|
|
478
|
+
* Plain-DOM panel (no React tree) so it can never disturb the DSH shell's
|
|
355
479
|
* reconciliation — same rule as the sidebar entry rows. Rendered content:
|
|
356
480
|
*
|
|
357
|
-
* -
|
|
358
|
-
* -
|
|
359
|
-
*
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
364
|
-
*
|
|
365
|
-
*
|
|
481
|
+
* - head: title + intro + refresh toolbar (the shell plugin-manager head row)
|
|
482
|
+
* - state-grouped sections, each a group head + package cards
|
|
483
|
+
* (48px hairline-framed glyph, title row with a state tag, one-line
|
|
484
|
+
* version transition, end actions) — the shell's card geometry
|
|
485
|
+
* - a facts group for the independent HQ Edge runtime report
|
|
486
|
+
* - footer actions (install / ignore / show again), with a toast that
|
|
487
|
+
* reports the outcome of an install the way the shell's Toast does
|
|
488
|
+
*
|
|
489
|
+
* Every surface rides a `--dsw-alias-*` design token (see VIEW_CSS_TEXT), so
|
|
490
|
+
* the panel follows the shell's light/dark theme and its focus-ring contract.
|
|
366
491
|
*
|
|
367
492
|
* @module
|
|
368
493
|
*/
|
|
369
|
-
|
|
494
|
+
/** How long the outcome toast stays up, in milliseconds. */
|
|
495
|
+
const TOAST_HOLD_MS = 4e3;
|
|
496
|
+
function el(tag, className = "", text) {
|
|
370
497
|
const node = document.createElement(tag);
|
|
371
|
-
node.className = className;
|
|
498
|
+
if (className.length > 0) node.className = className;
|
|
372
499
|
if (text !== void 0) node.textContent = text;
|
|
373
500
|
return node;
|
|
374
501
|
}
|
|
502
|
+
/** A button carrying inline SVG artwork (the icon modules emit markup). */
|
|
503
|
+
function iconButton(className, markup, label, onClick) {
|
|
504
|
+
const button = el("button", className);
|
|
505
|
+
button.type = "button";
|
|
506
|
+
button.setAttribute("aria-label", label);
|
|
507
|
+
button.title = label;
|
|
508
|
+
button.innerHTML = markup;
|
|
509
|
+
button.addEventListener("click", onClick);
|
|
510
|
+
return button;
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Compact a package name to what a person calls it — the shell plugin
|
|
514
|
+
* manager's own rule (`presentation.ts` `shortName`), so both UIs read the
|
|
515
|
+
* same plugin by the same name.
|
|
516
|
+
*/
|
|
517
|
+
function shortName(name) {
|
|
518
|
+
return (name.startsWith("@") ? name.slice(name.indexOf("/") + 1) : name).replace(/^dsh-(?:host-|client-)?/, "");
|
|
519
|
+
}
|
|
520
|
+
/** Normalize the server's block reason to a list (it may arrive as a string). */
|
|
521
|
+
function blockedByList(item) {
|
|
522
|
+
const by = item.blockedBy;
|
|
523
|
+
if (Array.isArray(by)) return by.filter((entry) => typeof entry === "string");
|
|
524
|
+
return typeof by === "string" && by.length > 0 ? [by] : [];
|
|
525
|
+
}
|
|
526
|
+
/** The tag tone a state reads as, matching the shell's Tag palette. */
|
|
527
|
+
function stateTone(item) {
|
|
528
|
+
switch (item.state) {
|
|
529
|
+
case "update": return "info";
|
|
530
|
+
case "install": return "warning";
|
|
531
|
+
case "blocked": return "danger";
|
|
532
|
+
case "ignored": return "neutral";
|
|
533
|
+
case "current": return "success";
|
|
534
|
+
}
|
|
535
|
+
}
|
|
375
536
|
function stateLabel(item, copy) {
|
|
376
537
|
switch (item.state) {
|
|
377
538
|
case "current": return copy.state.current;
|
|
@@ -381,152 +542,258 @@ window.__ModuleLoader__.load({
|
|
|
381
542
|
case "blocked": return copy.state.blocked;
|
|
382
543
|
}
|
|
383
544
|
}
|
|
545
|
+
/** The one-line version transition under a card's title. */
|
|
546
|
+
function versionLine(item) {
|
|
547
|
+
switch (item.state) {
|
|
548
|
+
case "current": return item.currentVersion ?? item.availableVersion;
|
|
549
|
+
case "install": return item.availableVersion;
|
|
550
|
+
default: return item.currentVersion === null ? item.availableVersion : `${item.currentVersion} → ${item.availableVersion}`;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
384
553
|
function blockedReason(item, copy) {
|
|
385
|
-
const by = item
|
|
554
|
+
const by = blockedByList(item);
|
|
386
555
|
if (by.includes("host")) return copy.blockedReason.host;
|
|
387
556
|
if (by.includes("hq-edge-version")) return copy.blockedReason["hq-edge-version"];
|
|
388
557
|
if (by.includes("runtime-unknown")) return copy.blockedReason["runtime-unknown"];
|
|
389
558
|
return by.length > 0 ? by.join(", ") : void 0;
|
|
390
559
|
}
|
|
391
|
-
/**
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
560
|
+
/** One package card: glyph, name with its state tag, version line, end actions. */
|
|
561
|
+
function packageCard(item, copy, installing, store) {
|
|
562
|
+
const card = el("li", "hqpu-card");
|
|
563
|
+
card.dataset.pluginName = item.name;
|
|
564
|
+
card.dataset.state = item.state;
|
|
565
|
+
card.title = `${item.name} · ${versionLine(item)}`;
|
|
566
|
+
const head = el("div", "hqpu-card-head");
|
|
567
|
+
const glyph = el("span", "hqpu-card-icon");
|
|
568
|
+
glyph.setAttribute("aria-hidden", "true");
|
|
569
|
+
glyph.innerHTML = PLUGIN_ICON(24);
|
|
570
|
+
const main = el("div", "hqpu-card-main");
|
|
571
|
+
const titleRow = el("div", "hqpu-title-row");
|
|
572
|
+
const title = el("span", "hqpu-card-title", shortName(item.name));
|
|
573
|
+
const tag = el("span", "hqpu-tag");
|
|
574
|
+
tag.dataset.tone = stateTone(item);
|
|
575
|
+
tag.textContent = stateLabel(item, copy);
|
|
576
|
+
titleRow.append(title, tag);
|
|
577
|
+
const desc = el("span", "hqpu-card-desc", versionLine(item));
|
|
578
|
+
main.append(titleRow, desc);
|
|
579
|
+
head.append(glyph, main);
|
|
580
|
+
const end = el("div", "hqpu-card-end");
|
|
581
|
+
if (item.state === "update" || item.state === "install") {
|
|
582
|
+
const button = el("button", "hqpu-btn hqpu-btn--sm hqpu-btn--primary");
|
|
583
|
+
button.type = "button";
|
|
584
|
+
button.disabled = installing;
|
|
585
|
+
button.innerHTML = `${DOWNLOAD_ICON(13)}<span>${copy.installOne}</span>`;
|
|
586
|
+
button.addEventListener("click", () => {
|
|
587
|
+
runInstall(store, copy);
|
|
588
|
+
});
|
|
589
|
+
end.append(button);
|
|
400
590
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
const
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
const
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
591
|
+
head.append(end);
|
|
592
|
+
card.append(head);
|
|
593
|
+
if (item.state === "blocked") {
|
|
594
|
+
const reason = blockedReason(item, copy);
|
|
595
|
+
if (reason !== void 0) card.append(el("p", "hqpu-card-reason", reason));
|
|
596
|
+
}
|
|
597
|
+
return card;
|
|
598
|
+
}
|
|
599
|
+
/** A section: group head with its count, then the cards. */
|
|
600
|
+
function group(heading, items, copy, installing, store) {
|
|
601
|
+
if (items.length === 0) return null;
|
|
602
|
+
const section = el("section", "hqpu-group");
|
|
603
|
+
section.dataset.group = heading;
|
|
604
|
+
const head = el("div", "hqpu-group-head");
|
|
605
|
+
head.append(el("h3", "hqpu-group-title", heading));
|
|
606
|
+
head.append(el("span", "hqpu-group-count", copy.groupCount(items.length)));
|
|
607
|
+
const list = el("ul", "hqpu-cards");
|
|
608
|
+
for (const item of items) list.append(packageCard(item, copy, installing, store));
|
|
609
|
+
section.append(head, list);
|
|
610
|
+
return section;
|
|
611
|
+
}
|
|
612
|
+
/** First-read placeholders, sharing the card and text-line layout. */
|
|
613
|
+
function skeleton(copy) {
|
|
614
|
+
const section = el("section", "hqpu-group");
|
|
615
|
+
section.setAttribute("role", "status");
|
|
616
|
+
section.dataset.loading = "";
|
|
617
|
+
const head = el("div", "hqpu-group-head");
|
|
618
|
+
head.setAttribute("aria-hidden", "true");
|
|
619
|
+
const heading = el("span", "hqpu-group-title hqpu-skeleton-text hqpu-skeleton-heading");
|
|
620
|
+
const headingBar = el("span", "hqpu-skeleton-fill hqpu-skeleton-bar");
|
|
621
|
+
heading.append(headingBar);
|
|
622
|
+
head.append(heading);
|
|
623
|
+
const list = el("ul", "hqpu-cards");
|
|
624
|
+
list.setAttribute("aria-hidden", "true");
|
|
625
|
+
for (let index = 0; index < 3; index += 1) {
|
|
626
|
+
const card = el("li", "hqpu-card");
|
|
627
|
+
const cardHead = el("div", "hqpu-card-head");
|
|
628
|
+
const glyph = el("span", "hqpu-card-icon hqpu-skeleton-fill hqpu-skeleton-icon");
|
|
629
|
+
const main = el("div", "hqpu-card-main");
|
|
630
|
+
const titleRow = el("div", "hqpu-title-row");
|
|
631
|
+
const title = el("span", "hqpu-card-title hqpu-skeleton-text hqpu-skeleton-title");
|
|
632
|
+
title.append(el("span", "hqpu-skeleton-fill hqpu-skeleton-bar"));
|
|
633
|
+
titleRow.append(title);
|
|
634
|
+
const desc = el("span", "hqpu-card-desc hqpu-skeleton-text hqpu-skeleton-desc");
|
|
635
|
+
desc.append(el("span", "hqpu-skeleton-fill hqpu-skeleton-bar"));
|
|
636
|
+
main.append(titleRow, desc);
|
|
637
|
+
cardHead.append(glyph, main);
|
|
638
|
+
const end = el("div", "hqpu-card-end");
|
|
639
|
+
end.setAttribute("aria-hidden", "true");
|
|
640
|
+
cardHead.append(end);
|
|
641
|
+
card.append(cardHead);
|
|
642
|
+
list.append(card);
|
|
643
|
+
}
|
|
644
|
+
section.append(head, list);
|
|
645
|
+
section.setAttribute("aria-label", copy.loading);
|
|
646
|
+
return section;
|
|
647
|
+
}
|
|
648
|
+
/** The independent HQ Edge runtime report, as ruled fact rows. */
|
|
649
|
+
function runtimeGroup(report, copy) {
|
|
650
|
+
const section = el("section", "hqpu-group");
|
|
651
|
+
section.dataset.group = "runtime";
|
|
652
|
+
const head = el("div", "hqpu-group-head");
|
|
653
|
+
head.append(el("h3", "hqpu-group-title", copy.runtime.title));
|
|
654
|
+
section.append(head);
|
|
655
|
+
const facts = el("dl", "hqpu-facts");
|
|
656
|
+
const runtime = report.runtime;
|
|
657
|
+
const row = (label, value, code = false) => {
|
|
658
|
+
const wrap = el("div");
|
|
659
|
+
wrap.append(el("dt", "", label));
|
|
660
|
+
const dd = el("dd");
|
|
661
|
+
if (code) {
|
|
662
|
+
const node = el("code", "", value);
|
|
663
|
+
dd.append(node);
|
|
664
|
+
} else dd.textContent = value;
|
|
665
|
+
wrap.append(dd);
|
|
666
|
+
facts.append(wrap);
|
|
434
667
|
};
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
668
|
+
if (runtime.configured === false) row(copy.runtime.source, copy.runtime.notConfigured);
|
|
669
|
+
else {
|
|
670
|
+
row(copy.runtime.current, runtime.currentVersion ?? copy.runtime.unknown);
|
|
671
|
+
if (runtime.updateAvailable && runtime.latest != null) row(copy.runtime.latest, runtime.latest);
|
|
672
|
+
if (report.manifestVersion !== null) row(copy.runtime.set, report.manifestVersion, true);
|
|
673
|
+
if (typeof runtime.checkedAt === "string" && runtime.checkedAt.length > 0) row(copy.runtime.checkedAt, new Date(runtime.checkedAt).toLocaleString());
|
|
674
|
+
}
|
|
675
|
+
section.append(facts);
|
|
676
|
+
section.append(el("p", "hqpu-status", copy.runtime.note));
|
|
677
|
+
if (typeof runtime.lastError === "string" && runtime.lastError.length > 0) {
|
|
678
|
+
const line = el("p", "hqpu-status hqpu-status--dot");
|
|
679
|
+
line.setAttribute("role", "status");
|
|
680
|
+
const dot = el("span", "hqpu-dot");
|
|
681
|
+
dot.dataset.state = "error";
|
|
682
|
+
line.append(dot, el("span", "", `${copy.lastError}: ${runtime.lastError}`));
|
|
683
|
+
section.append(line);
|
|
684
|
+
}
|
|
685
|
+
return section;
|
|
448
686
|
}
|
|
449
687
|
function renderList(section, report, copy, installing, store) {
|
|
450
688
|
section.textContent = "";
|
|
451
689
|
if (report === null) {
|
|
452
|
-
section.append(
|
|
690
|
+
section.append(skeleton(copy));
|
|
453
691
|
return;
|
|
454
692
|
}
|
|
455
693
|
if (report.items.length === 0) {
|
|
456
694
|
section.append(el("div", "hqpu-empty", copy.empty));
|
|
457
695
|
return;
|
|
458
696
|
}
|
|
459
|
-
const
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
section.append(banner);
|
|
470
|
-
}
|
|
471
|
-
const list = el("ul", "hqpu-list");
|
|
472
|
-
for (const item of report.items) {
|
|
473
|
-
const row = el("li", `hqpu-item hqpu-item-${item.state}`);
|
|
474
|
-
const name = el("span", "hqpu-item-name", item.name);
|
|
475
|
-
const version = el("span", "hqpu-item-version", item.state === "current" ? item.currentVersion : `${item.currentVersion} → ${item.availableVersion}`);
|
|
476
|
-
const state = el("span", `hqpu-item-state hqpu-state-${item.state}`, stateLabel(item, copy));
|
|
477
|
-
row.append(name, version, state);
|
|
478
|
-
const reason = blockedReason(item, copy);
|
|
479
|
-
if (reason !== void 0) row.append(el("span", "hqpu-item-reason", reason));
|
|
480
|
-
list.append(row);
|
|
697
|
+
const byState = (state) => report.items.filter((item) => item.state === state);
|
|
698
|
+
const order = [
|
|
699
|
+
[copy.group.actionable, [...byState("update"), ...byState("install")]],
|
|
700
|
+
[copy.group.blocked, byState("blocked")],
|
|
701
|
+
[copy.group.ignored, byState("ignored")],
|
|
702
|
+
[copy.group.current, byState("current")]
|
|
703
|
+
];
|
|
704
|
+
for (const [heading, items] of order) {
|
|
705
|
+
const node = group(heading, items, copy, installing, store);
|
|
706
|
+
if (node !== null) section.append(node);
|
|
481
707
|
}
|
|
482
|
-
section.append(list);
|
|
483
708
|
}
|
|
484
709
|
function renderRuntime(section, report, copy) {
|
|
485
710
|
section.textContent = "";
|
|
486
|
-
|
|
487
|
-
section.append(
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
711
|
+
if (report === null) return;
|
|
712
|
+
section.append(runtimeGroup(report, copy));
|
|
713
|
+
}
|
|
714
|
+
/** Run the install transaction, then keep polling until the state settles. */
|
|
715
|
+
async function runInstall(store, copy) {
|
|
716
|
+
const report = store.report();
|
|
717
|
+
if (report === null) return;
|
|
718
|
+
if (report.manifestVersion === null) {
|
|
719
|
+
showToast(copy.checkFailed, "error");
|
|
491
720
|
return;
|
|
492
721
|
}
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
722
|
+
try {
|
|
723
|
+
const result = await installSet(report.manifestVersion);
|
|
724
|
+
if (result.error !== void 0) {
|
|
725
|
+
showToast(`${copy.installError}: ${result.error}`, "error");
|
|
726
|
+
return;
|
|
727
|
+
}
|
|
728
|
+
showToast(copy.installSuccess, "success");
|
|
729
|
+
pollUntilSettled(store);
|
|
730
|
+
} catch (err) {
|
|
731
|
+
showToast(`${copy.installError}: ${err instanceof Error ? err.message : String(err)}`, "error");
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
/** The single live toast; a new message replaces the one on screen. */
|
|
735
|
+
let toastHost = null;
|
|
736
|
+
let toastTimer = null;
|
|
737
|
+
function showToast(message, tone) {
|
|
738
|
+
if (toastHost === null) return;
|
|
739
|
+
if (toastTimer !== null) window.clearTimeout(toastTimer);
|
|
740
|
+
toastHost.textContent = "";
|
|
741
|
+
const toast = el("div", "hqpu-toast");
|
|
742
|
+
toast.setAttribute("role", "status");
|
|
743
|
+
const icon = el("span", "hqpu-toast-icon");
|
|
744
|
+
icon.dataset.tone = tone;
|
|
745
|
+
icon.innerHTML = tone === "success" ? CHECK_CIRCLE_ICON(16) : WARNING_ICON(16);
|
|
746
|
+
toast.append(icon, el("span", "hqpu-toast-text", message));
|
|
747
|
+
toastHost.append(toast);
|
|
748
|
+
toastTimer = window.setTimeout(() => {
|
|
749
|
+
toastHost?.replaceChildren();
|
|
750
|
+
toastTimer = null;
|
|
751
|
+
}, TOAST_HOLD_MS);
|
|
498
752
|
}
|
|
499
753
|
function renderActions(bar, report, copy, store, installing) {
|
|
500
754
|
bar.textContent = "";
|
|
501
755
|
if (report === null) return;
|
|
502
756
|
if (installing) {
|
|
503
|
-
|
|
757
|
+
const line = el("span", "hqpu-status hqpu-status--dot");
|
|
758
|
+
const spinner = el("span", "hqpu-spinner");
|
|
759
|
+
line.append(spinner, el("span", "", copy.installing));
|
|
760
|
+
bar.append(line);
|
|
504
761
|
return;
|
|
505
762
|
}
|
|
506
763
|
const actionable = report.items.filter((item) => item.state === "update" || item.state === "install").length;
|
|
507
|
-
const
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
bar.textContent = "";
|
|
517
|
-
bar.append(el("span", "hqpu-installing", copy.installSuccess));
|
|
518
|
-
pollUntilSettled(store, report.manifestVersion);
|
|
519
|
-
}).catch((err) => {
|
|
520
|
-
bar.textContent = "";
|
|
521
|
-
bar.append(el("div", "hqpu-error", `${copy.installError}: ${err instanceof Error ? err.message : String(err)}`));
|
|
764
|
+
const hasSet = report.manifestVersion !== null;
|
|
765
|
+
if (actionable === 0) bar.append(el("span", "hqpu-status", copy.nothingToInstall));
|
|
766
|
+
else {
|
|
767
|
+
const installBtn = el("button", "hqpu-btn hqpu-btn--primary");
|
|
768
|
+
installBtn.type = "button";
|
|
769
|
+
installBtn.disabled = !hasSet || report.ignoredSet;
|
|
770
|
+
installBtn.innerHTML = `${DOWNLOAD_ICON(13)}<span>${copy.installAll(actionable)}</span>`;
|
|
771
|
+
installBtn.addEventListener("click", () => {
|
|
772
|
+
runInstall(store, copy);
|
|
522
773
|
});
|
|
523
|
-
|
|
524
|
-
|
|
774
|
+
bar.append(installBtn);
|
|
775
|
+
}
|
|
776
|
+
if (!hasSet) return;
|
|
777
|
+
if (report.ignoredSet) {
|
|
778
|
+
const unignore = el("button", "hqpu-btn hqpu-btn--outline hqpu-btn--sm", copy.unignore);
|
|
779
|
+
unignore.type = "button";
|
|
780
|
+
unignore.addEventListener("click", () => {
|
|
781
|
+
unignoreOffer(report.manifestVersion).then(() => store.refresh()).catch(() => void 0);
|
|
782
|
+
});
|
|
783
|
+
bar.append(unignore);
|
|
784
|
+
} else if (actionable > 0) {
|
|
785
|
+
const ignore = el("button", "hqpu-btn hqpu-btn--ghost hqpu-btn--sm", copy.ignore);
|
|
786
|
+
ignore.type = "button";
|
|
787
|
+
ignore.addEventListener("click", () => {
|
|
788
|
+
ignoreOffer(report.manifestVersion).then(() => store.refresh()).catch(() => void 0);
|
|
789
|
+
});
|
|
790
|
+
bar.append(ignore);
|
|
791
|
+
}
|
|
525
792
|
}
|
|
526
793
|
/** After an install, poll the backend until the update report settles
|
|
527
794
|
* (installing flag clears or DSH restarts under us — the next load re-reads
|
|
528
795
|
* the fresh state). */
|
|
529
|
-
function pollUntilSettled(store
|
|
796
|
+
function pollUntilSettled(store) {
|
|
530
797
|
let attempts = 0;
|
|
531
798
|
const tick = () => {
|
|
532
799
|
store.refresh().then((report) => {
|
|
@@ -539,6 +806,101 @@ window.__ModuleLoader__.load({
|
|
|
539
806
|
};
|
|
540
807
|
tick();
|
|
541
808
|
}
|
|
809
|
+
/**
|
|
810
|
+
* Open (or focus) the update panel. Re-renders from the store; when the store
|
|
811
|
+
* is stale the panel first refreshes the report.
|
|
812
|
+
*/
|
|
813
|
+
function openUpdateView(store, copy) {
|
|
814
|
+
const existing = document.querySelector("[data-hq-plugin-update-view]");
|
|
815
|
+
if (existing !== null) {
|
|
816
|
+
existing.style.display = "";
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
const overlay = el("div", "hqpu-overlay");
|
|
820
|
+
overlay.setAttribute("data-hq-plugin-update-view", "");
|
|
821
|
+
overlay.addEventListener("click", (ev) => {
|
|
822
|
+
if (ev.target === overlay) onClose();
|
|
823
|
+
});
|
|
824
|
+
const scrim = el("div", "hqpu-scrim");
|
|
825
|
+
const panel = el("div", "hqpu-panel");
|
|
826
|
+
panel.setAttribute("role", "dialog");
|
|
827
|
+
panel.setAttribute("aria-modal", "true");
|
|
828
|
+
panel.setAttribute("aria-label", copy.viewTitle);
|
|
829
|
+
panel.tabIndex = -1;
|
|
830
|
+
const head = el("div", "hqpu-head");
|
|
831
|
+
const headMain = el("div", "hqpu-head-main");
|
|
832
|
+
headMain.append(el("h1", "hqpu-title", copy.viewTitle));
|
|
833
|
+
const intro = el("p", "hqpu-intro");
|
|
834
|
+
intro.append(el("span", "", copy.viewIntro));
|
|
835
|
+
const info = el("button", "hqpu-info");
|
|
836
|
+
info.type = "button";
|
|
837
|
+
info.setAttribute("aria-label", copy.viewInfo);
|
|
838
|
+
info.title = copy.viewInfo;
|
|
839
|
+
info.innerHTML = INFO_ICON(11);
|
|
840
|
+
intro.append(info);
|
|
841
|
+
headMain.append(intro);
|
|
842
|
+
const toolbar = el("div", "hqpu-toolbar");
|
|
843
|
+
const refreshBtn = iconButton("hqpu-icon-btn", REFRESH_ICON(16), copy.refresh, () => {
|
|
844
|
+
store.refresh();
|
|
845
|
+
});
|
|
846
|
+
toolbar.append(refreshBtn);
|
|
847
|
+
const closeBtn = iconButton("hqpu-icon-btn", CLOSE_ICON(16), copy.close, () => {
|
|
848
|
+
onClose();
|
|
849
|
+
});
|
|
850
|
+
toolbar.append(closeBtn);
|
|
851
|
+
head.append(headMain, toolbar);
|
|
852
|
+
panel.append(head);
|
|
853
|
+
const scroll = el("div", "hqpu-scroll");
|
|
854
|
+
const column = el("div", "hqpu-column");
|
|
855
|
+
const listSection = el("div", "hqpu-stack");
|
|
856
|
+
const runtimeSection = el("div", "hqpu-stack");
|
|
857
|
+
const toastSection = el("div", "hqpu-toast-host");
|
|
858
|
+
column.append(listSection, runtimeSection, toastSection);
|
|
859
|
+
scroll.append(column);
|
|
860
|
+
panel.append(scroll);
|
|
861
|
+
const footer = el("div", "hqpu-footer");
|
|
862
|
+
const actionBar = el("div", "hqpu-actions");
|
|
863
|
+
footer.append(actionBar);
|
|
864
|
+
panel.append(footer);
|
|
865
|
+
overlay.append(scrim, panel);
|
|
866
|
+
document.body.appendChild(overlay);
|
|
867
|
+
toastHost = toastSection;
|
|
868
|
+
panel.focus();
|
|
869
|
+
const disposers = [];
|
|
870
|
+
const render = () => {
|
|
871
|
+
const report = store.report();
|
|
872
|
+
const installing = store.installing();
|
|
873
|
+
const stale = report === null;
|
|
874
|
+
refreshBtn.disabled = stale;
|
|
875
|
+
if (stale) {
|
|
876
|
+
listSection.textContent = "";
|
|
877
|
+
listSection.append(skeleton(copy));
|
|
878
|
+
} else renderList(listSection, report, copy, installing, store);
|
|
879
|
+
renderRuntime(runtimeSection, report, copy);
|
|
880
|
+
renderActions(actionBar, report, copy, store, installing);
|
|
881
|
+
};
|
|
882
|
+
const unsubscribe = store.subscribe(render);
|
|
883
|
+
disposers.push(unsubscribe);
|
|
884
|
+
store.refresh().then(() => {});
|
|
885
|
+
const onKeyDown = (ev) => {
|
|
886
|
+
if (ev.key === "Escape") {
|
|
887
|
+
ev.stopPropagation();
|
|
888
|
+
onClose();
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
document.addEventListener("keydown", onKeyDown);
|
|
892
|
+
disposers.push(() => document.removeEventListener("keydown", onKeyDown));
|
|
893
|
+
function onClose() {
|
|
894
|
+
for (const dispose of disposers) try {
|
|
895
|
+
dispose();
|
|
896
|
+
} catch {}
|
|
897
|
+
if (toastTimer !== null) window.clearTimeout(toastTimer);
|
|
898
|
+
toastTimer = null;
|
|
899
|
+
if (toastHost === toastSection) toastHost = null;
|
|
900
|
+
overlay.remove();
|
|
901
|
+
}
|
|
902
|
+
render();
|
|
903
|
+
}
|
|
542
904
|
//#endregion
|
|
543
905
|
//#region src/client/index.ts
|
|
544
906
|
/**
|
|
@@ -579,15 +941,14 @@ window.__ModuleLoader__.load({
|
|
|
579
941
|
tooltip: COPY.zh.entryTooltip
|
|
580
942
|
};
|
|
581
943
|
}
|
|
582
|
-
/**
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
<path d="M2.5 8a5.5 5.5 0 1 1 1.61 3.89" />
|
|
586
|
-
<path d="M2.5 8V4.75M2.5 8h3.25" />
|
|
587
|
-
</g>
|
|
588
|
-
</svg>`;
|
|
944
|
+
/** The sidebar glyph — the same pinwheel the shell's own Plugins entry draws
|
|
945
|
+
* (`IconPluginPinwheelOutlineRegular`), so both rows read as one feature. */
|
|
946
|
+
const UPDATE_ICON = PLUGIN_ICON(16);
|
|
589
947
|
/** Sidebar entry styles — matched to the family rows (same inset/padding/gap
|
|
590
|
-
* as the shell's own Plugins entry
|
|
948
|
+
* as the shell's own Plugins entry, `SidebarRoot.module.css` `.panelRow`).
|
|
949
|
+
* Every colour rides a `--dsw-alias-*` token so the row follows the shell's
|
|
950
|
+
* light/dark theme; the badge foreground uses the toast label, the shell's
|
|
951
|
+
* "always light ink on a saturated surface" token. */
|
|
591
952
|
const ENTRY_CSS_TEXT = `
|
|
592
953
|
.hqpu-sidebar-entry {
|
|
593
954
|
box-sizing: border-box;
|
|
@@ -600,7 +961,7 @@ window.__ModuleLoader__.load({
|
|
|
600
961
|
padding: 7px 8px;
|
|
601
962
|
background: transparent;
|
|
602
963
|
border: none;
|
|
603
|
-
border-radius:
|
|
964
|
+
border-radius: var(--dsw-radius-md);
|
|
604
965
|
color: var(--dsw-alias-label-primary);
|
|
605
966
|
cursor: pointer;
|
|
606
967
|
font: inherit;
|
|
@@ -615,6 +976,10 @@ window.__ModuleLoader__.load({
|
|
|
615
976
|
background: var(--dsw-alias-interactive-bg-hover);
|
|
616
977
|
color: var(--dsw-alias-label-primary);
|
|
617
978
|
}
|
|
979
|
+
.hqpu-sidebar-entry:focus-visible {
|
|
980
|
+
outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
|
|
981
|
+
outline-offset: -2px;
|
|
982
|
+
}
|
|
618
983
|
.hqpu-sidebar-entry__icon {
|
|
619
984
|
display: inline-flex;
|
|
620
985
|
align-items: center;
|
|
@@ -638,11 +1003,13 @@ window.__ModuleLoader__.load({
|
|
|
638
1003
|
height: 16px;
|
|
639
1004
|
padding: 0 5px;
|
|
640
1005
|
border-radius: 8px;
|
|
641
|
-
background: var(--dsw-alias-
|
|
642
|
-
color:
|
|
1006
|
+
background: var(--dsw-alias-state-error-primary);
|
|
1007
|
+
color: var(--dsw-alias-toast-label);
|
|
643
1008
|
font-size: 11px;
|
|
644
1009
|
line-height: 16px;
|
|
1010
|
+
font-weight: 500;
|
|
645
1011
|
text-align: center;
|
|
1012
|
+
font-variant-numeric: tabular-nums;
|
|
646
1013
|
}
|
|
647
1014
|
/* Collapsed rail: icon-only, centered — same 36px square the shell uses. */
|
|
648
1015
|
[data-sidebar-collapsed] .hqpu-sidebar-entry {
|
|
@@ -661,9 +1028,28 @@ window.__ModuleLoader__.load({
|
|
|
661
1028
|
display: none;
|
|
662
1029
|
}
|
|
663
1030
|
`;
|
|
664
|
-
/**
|
|
665
|
-
*
|
|
1031
|
+
/**
|
|
1032
|
+
* View styles (hqpu-*). Plain overlay + panel, drawn with the SAME design
|
|
1033
|
+
* tokens and geometry the shell's own plugin manager uses
|
|
1034
|
+
* (`ui-plugin-manager/src/client/PluginManagerPage.module.css` +
|
|
1035
|
+
* `ui-primitives/src/{Modal,Toast,Tag,StateDot}.module.css`), so this page
|
|
1036
|
+
* reads as part of the product rather than a bolt-on.
|
|
1037
|
+
*
|
|
1038
|
+
* Two rules keep it honest across themes:
|
|
1039
|
+
* 1. every colour is a `--dsw-alias-*` token — no literal hex/rgb, so light
|
|
1040
|
+
* and dark both come out right (the old sheet invented
|
|
1041
|
+
* `--dsw-alias-bg-surface` / `--dsw-alias-line-border` / `--dsw-alias-bg-badge`,
|
|
1042
|
+
* none of which exist, and so always fell back to a white panel);
|
|
1043
|
+
* 2. `color-mix()` tints come from the state token itself, so a palette
|
|
1044
|
+
* change moves fill and ink together.
|
|
1045
|
+
*
|
|
1046
|
+
* The chrome (panel, scrim, header, footer) follows `ui-primitives/Modal`,
|
|
1047
|
+
* because this view IS a dialog; the body follows `PluginManagerPage`, because
|
|
1048
|
+
* that is the content it heads. The one token the bundled shell does not
|
|
1049
|
+
* publish is backfilled by {@link ensureDesignTokens} — see the note there.
|
|
1050
|
+
*/
|
|
666
1051
|
const VIEW_CSS_TEXT = `
|
|
1052
|
+
/* ── Overlay + panel (ui-primitives Modal.module.css) ─────────────────── */
|
|
667
1053
|
.hqpu-overlay {
|
|
668
1054
|
position: fixed;
|
|
669
1055
|
inset: 0;
|
|
@@ -671,175 +1057,675 @@ window.__ModuleLoader__.load({
|
|
|
671
1057
|
display: flex;
|
|
672
1058
|
align-items: center;
|
|
673
1059
|
justify-content: center;
|
|
674
|
-
|
|
1060
|
+
/* The frame's own top inset keeps a tall card clear of the window chrome. */
|
|
1061
|
+
padding: max(24px, var(--dsh-frame-overlay-top, 24px)) 24px;
|
|
1062
|
+
}
|
|
1063
|
+
.hqpu-scrim {
|
|
1064
|
+
position: absolute;
|
|
1065
|
+
/* Only paint excludes the native caption; the root still blocks clicks. */
|
|
1066
|
+
inset: var(--dsh-frame-chrome-top, 0px) 0 0;
|
|
1067
|
+
background: var(--dsw-alias-bg-mask-1);
|
|
1068
|
+
animation: hqpu-fade var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease);
|
|
675
1069
|
}
|
|
676
1070
|
.hqpu-panel {
|
|
1071
|
+
position: relative;
|
|
1072
|
+
z-index: 1;
|
|
677
1073
|
box-sizing: border-box;
|
|
678
|
-
width: min(640px, calc(100vw - 48px));
|
|
679
|
-
max-height: min(80vh, 720px);
|
|
680
1074
|
display: flex;
|
|
681
1075
|
flex-direction: column;
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
box-shadow: 0 24px 64px rgba(0, 0, 0, 0.24);
|
|
1076
|
+
gap: 20px;
|
|
1077
|
+
width: min(920px, 100%);
|
|
1078
|
+
max-height: 100%;
|
|
686
1079
|
overflow: hidden;
|
|
1080
|
+
border: 0;
|
|
1081
|
+
border-radius: var(--dsw-radius-panel);
|
|
1082
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
1083
|
+
box-shadow: var(--dsw-elevation-prominent);
|
|
1084
|
+
color: var(--dsw-alias-label-primary);
|
|
1085
|
+
animation: hqpu-panel-in var(--ds-transition-duration, 0.2s) var(--ds-ease-in-out, ease);
|
|
687
1086
|
}
|
|
688
|
-
.hqpu-
|
|
1087
|
+
.hqpu-panel:focus {
|
|
1088
|
+
outline: none;
|
|
1089
|
+
}
|
|
1090
|
+
@keyframes hqpu-fade {
|
|
1091
|
+
from { opacity: 0; }
|
|
1092
|
+
to { opacity: 1; }
|
|
1093
|
+
}
|
|
1094
|
+
@keyframes hqpu-panel-in {
|
|
1095
|
+
from { opacity: 0; }
|
|
1096
|
+
to { opacity: 1; }
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
/* ── Head row (ui-primitives Modal .header) ─────────────────────────────── */
|
|
1100
|
+
.hqpu-head {
|
|
689
1101
|
display: flex;
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
1102
|
+
flex: none;
|
|
1103
|
+
flex-wrap: wrap;
|
|
1104
|
+
align-items: flex-start;
|
|
1105
|
+
justify-content: space-between;
|
|
1106
|
+
gap: 16px;
|
|
1107
|
+
box-sizing: border-box;
|
|
1108
|
+
/* The official Title row: 22/14/12/24 — the toolbar sits 10px further right
|
|
1109
|
+
* than the body content on purpose, matching the shell's own close button. */
|
|
1110
|
+
padding: 22px 14px 12px 24px;
|
|
1111
|
+
}
|
|
1112
|
+
.hqpu-head-main {
|
|
1113
|
+
min-width: 0;
|
|
1114
|
+
max-width: 100%;
|
|
694
1115
|
}
|
|
695
1116
|
.hqpu-title {
|
|
1117
|
+
margin: 0;
|
|
1118
|
+
font-size: 20px;
|
|
1119
|
+
font-weight: 500;
|
|
1120
|
+
line-height: 28px;
|
|
1121
|
+
color: var(--dsw-alias-label-primary);
|
|
1122
|
+
}
|
|
1123
|
+
.hqpu-intro {
|
|
1124
|
+
display: flex;
|
|
1125
|
+
align-items: center;
|
|
1126
|
+
gap: 4px;
|
|
1127
|
+
margin: 4px 0 0;
|
|
1128
|
+
font-size: 13px;
|
|
1129
|
+
line-height: 20px;
|
|
1130
|
+
color: var(--dsw-alias-label-secondary);
|
|
1131
|
+
}
|
|
1132
|
+
.hqpu-info {
|
|
1133
|
+
display: inline-flex;
|
|
1134
|
+
align-items: center;
|
|
1135
|
+
justify-content: center;
|
|
1136
|
+
flex: none;
|
|
1137
|
+
width: 20px;
|
|
1138
|
+
height: 20px;
|
|
1139
|
+
padding: 0;
|
|
1140
|
+
border: 0;
|
|
1141
|
+
border-radius: var(--dsw-radius-sm);
|
|
1142
|
+
background: transparent;
|
|
1143
|
+
color: var(--dsw-alias-label-caption);
|
|
1144
|
+
cursor: pointer;
|
|
1145
|
+
}
|
|
1146
|
+
.hqpu-info:hover {
|
|
1147
|
+
background: var(--dsw-alias-interactive-bg-hover);
|
|
1148
|
+
color: var(--dsw-alias-label-secondary);
|
|
1149
|
+
}
|
|
1150
|
+
.hqpu-info:focus-visible {
|
|
1151
|
+
outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
|
|
1152
|
+
outline-offset: 1px;
|
|
1153
|
+
}
|
|
1154
|
+
.hqpu-toolbar {
|
|
1155
|
+
display: flex;
|
|
1156
|
+
flex: none;
|
|
1157
|
+
align-items: center;
|
|
1158
|
+
gap: 16px;
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
/* ── Scrolling body: the page's centred column ────────────────────────── */
|
|
1162
|
+
.hqpu-scroll {
|
|
696
1163
|
flex: 1;
|
|
697
|
-
|
|
698
|
-
|
|
1164
|
+
min-height: 0;
|
|
1165
|
+
overflow-y: auto;
|
|
1166
|
+
box-sizing: border-box;
|
|
1167
|
+
/* The panel's 20px gap already separates this from the head and footer. */
|
|
1168
|
+
padding: 0 clamp(16px, 3vw, 32px) 4px;
|
|
1169
|
+
/* Anything that scrolls inside the panel draws the l2 thumb. */
|
|
1170
|
+
--dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);
|
|
1171
|
+
--dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);
|
|
699
1172
|
}
|
|
700
|
-
.hqpu-
|
|
701
|
-
overflow: auto;
|
|
702
|
-
padding: 16px;
|
|
1173
|
+
.hqpu-column {
|
|
703
1174
|
display: flex;
|
|
704
1175
|
flex-direction: column;
|
|
705
|
-
gap:
|
|
1176
|
+
gap: 24px;
|
|
1177
|
+
width: 100%;
|
|
1178
|
+
max-width: 880px;
|
|
1179
|
+
margin: 0 auto;
|
|
1180
|
+
}
|
|
1181
|
+
/* A stack of groups (or the single toast host) inside the column. */
|
|
1182
|
+
.hqpu-stack {
|
|
1183
|
+
display: flex;
|
|
1184
|
+
flex-direction: column;
|
|
1185
|
+
gap: 24px;
|
|
706
1186
|
}
|
|
707
|
-
.hqpu-
|
|
1187
|
+
.hqpu-toast-host:empty {
|
|
1188
|
+
display: none;
|
|
1189
|
+
}
|
|
1190
|
+
|
|
1191
|
+
/* ── Groups (PluginManagerPage .group) ────────────────────────────────── */
|
|
1192
|
+
.hqpu-group {
|
|
708
1193
|
display: flex;
|
|
709
1194
|
flex-direction: column;
|
|
710
1195
|
gap: 8px;
|
|
711
1196
|
}
|
|
712
|
-
.hqpu-
|
|
1197
|
+
.hqpu-group-head {
|
|
713
1198
|
display: flex;
|
|
714
1199
|
align-items: center;
|
|
715
1200
|
gap: 8px;
|
|
716
|
-
font-size: 12px;
|
|
717
|
-
color: var(--dsw-alias-label-secondary, #646a73);
|
|
718
1201
|
}
|
|
719
|
-
.hqpu-
|
|
720
|
-
|
|
721
|
-
|
|
1202
|
+
.hqpu-group-title {
|
|
1203
|
+
flex: 1;
|
|
1204
|
+
min-width: 0;
|
|
1205
|
+
margin: 0;
|
|
1206
|
+
font-size: 14px;
|
|
1207
|
+
font-weight: 500;
|
|
1208
|
+
line-height: 22px;
|
|
1209
|
+
color: var(--dsw-alias-label-primary);
|
|
722
1210
|
}
|
|
723
|
-
.hqpu-
|
|
724
|
-
|
|
1211
|
+
.hqpu-group-count {
|
|
1212
|
+
flex: none;
|
|
1213
|
+
font-size: 12px;
|
|
1214
|
+
line-height: 18px;
|
|
1215
|
+
color: var(--dsw-alias-label-tertiary);
|
|
1216
|
+
font-variant-numeric: tabular-nums;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
/* ── Cards (PluginManagerPage .card) ──────────────────────────────────── */
|
|
1220
|
+
.hqpu-cards {
|
|
725
1221
|
margin: 0;
|
|
726
1222
|
padding: 0;
|
|
1223
|
+
list-style: none;
|
|
727
1224
|
display: flex;
|
|
728
1225
|
flex-direction: column;
|
|
729
|
-
gap:
|
|
1226
|
+
gap: 2px;
|
|
730
1227
|
}
|
|
731
|
-
.hqpu-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
1228
|
+
.hqpu-card {
|
|
1229
|
+
min-width: 0;
|
|
1230
|
+
/* The hover surface reaches 8px past the content on both sides. */
|
|
1231
|
+
margin: 0 -8px;
|
|
1232
|
+
border-radius: var(--dsw-radius-xl);
|
|
1233
|
+
}
|
|
1234
|
+
.hqpu-card:hover {
|
|
1235
|
+
background: var(--dsw-alias-interactive-bg-hover);
|
|
1236
|
+
}
|
|
1237
|
+
.hqpu-card-head {
|
|
1238
|
+
display: flex;
|
|
735
1239
|
align-items: center;
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
1240
|
+
gap: 14px;
|
|
1241
|
+
padding: 8px;
|
|
1242
|
+
}
|
|
1243
|
+
.hqpu-card-icon {
|
|
1244
|
+
display: inline-flex;
|
|
1245
|
+
flex: none;
|
|
1246
|
+
align-items: center;
|
|
1247
|
+
justify-content: center;
|
|
1248
|
+
width: 48px;
|
|
1249
|
+
height: 48px;
|
|
1250
|
+
border: 0.5px solid var(--dsw-alias-border-l3);
|
|
1251
|
+
border-radius: var(--dsw-radius-lg);
|
|
1252
|
+
color: var(--dsw-alias-label-secondary);
|
|
1253
|
+
}
|
|
1254
|
+
.hqpu-card-icon svg {
|
|
1255
|
+
display: block;
|
|
1256
|
+
width: 24px;
|
|
1257
|
+
height: 24px;
|
|
1258
|
+
}
|
|
1259
|
+
.hqpu-card-main {
|
|
1260
|
+
flex: 1;
|
|
1261
|
+
min-width: 0;
|
|
1262
|
+
display: flex;
|
|
1263
|
+
flex-direction: column;
|
|
1264
|
+
gap: 4px;
|
|
1265
|
+
}
|
|
1266
|
+
.hqpu-title-row {
|
|
1267
|
+
display: flex;
|
|
1268
|
+
align-items: center;
|
|
1269
|
+
flex-wrap: wrap;
|
|
1270
|
+
gap: 8px;
|
|
1271
|
+
min-width: 0;
|
|
740
1272
|
}
|
|
741
|
-
.hqpu-
|
|
1273
|
+
.hqpu-card-title {
|
|
1274
|
+
min-width: 0;
|
|
1275
|
+
font-size: 14px;
|
|
742
1276
|
font-weight: 500;
|
|
1277
|
+
line-height: 20px;
|
|
1278
|
+
color: var(--dsw-alias-label-primary);
|
|
743
1279
|
overflow: hidden;
|
|
744
1280
|
text-overflow: ellipsis;
|
|
1281
|
+
white-space: nowrap;
|
|
745
1282
|
}
|
|
746
|
-
.hqpu-
|
|
747
|
-
|
|
748
|
-
|
|
1283
|
+
.hqpu-card-desc {
|
|
1284
|
+
font-size: 13px;
|
|
1285
|
+
line-height: 18px;
|
|
1286
|
+
color: var(--dsw-alias-label-tertiary);
|
|
1287
|
+
display: -webkit-box;
|
|
1288
|
+
-webkit-box-orient: vertical;
|
|
1289
|
+
-webkit-line-clamp: 1;
|
|
1290
|
+
overflow: hidden;
|
|
1291
|
+
overflow-wrap: anywhere;
|
|
749
1292
|
}
|
|
750
|
-
.hqpu-
|
|
751
|
-
|
|
1293
|
+
.hqpu-card-end {
|
|
1294
|
+
position: relative;
|
|
1295
|
+
z-index: 1;
|
|
1296
|
+
display: inline-flex;
|
|
1297
|
+
flex: none;
|
|
1298
|
+
align-items: center;
|
|
1299
|
+
gap: 8px;
|
|
1300
|
+
}
|
|
1301
|
+
.hqpu-card-reason {
|
|
1302
|
+
margin: 0;
|
|
1303
|
+
padding: 0 8px 8px 70px;
|
|
1304
|
+
font-size: 12px;
|
|
1305
|
+
line-height: 18px;
|
|
1306
|
+
color: var(--dsw-alias-state-error-primary);
|
|
1307
|
+
overflow-wrap: anywhere;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
/* ── Tags (ui-primitives Tag.module.css) ──────────────────────────────── */
|
|
1311
|
+
.hqpu-tag {
|
|
1312
|
+
display: inline-flex;
|
|
1313
|
+
align-items: center;
|
|
1314
|
+
flex: none;
|
|
752
1315
|
border-radius: 999px;
|
|
1316
|
+
corner-shape: round;
|
|
1317
|
+
padding: 1px 8px;
|
|
753
1318
|
font-size: 11px;
|
|
754
|
-
|
|
1319
|
+
font-weight: 500;
|
|
1320
|
+
line-height: 17px;
|
|
1321
|
+
white-space: nowrap;
|
|
755
1322
|
}
|
|
756
|
-
.hqpu-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
.hqpu-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
1323
|
+
.hqpu-tag[data-tone='success'] {
|
|
1324
|
+
background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent);
|
|
1325
|
+
color: var(--dsw-alias-state-success-primary);
|
|
1326
|
+
}
|
|
1327
|
+
.hqpu-tag[data-tone='info'] {
|
|
1328
|
+
background: color-mix(in srgb, var(--dsw-alias-state-business-primary) 10%, transparent);
|
|
1329
|
+
color: var(--dsw-alias-state-business-primary);
|
|
1330
|
+
}
|
|
1331
|
+
.hqpu-tag[data-tone='warning'] {
|
|
1332
|
+
background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);
|
|
1333
|
+
color: var(--dsw-alias-state-warn-primary);
|
|
1334
|
+
}
|
|
1335
|
+
.hqpu-tag[data-tone='danger'] {
|
|
1336
|
+
background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);
|
|
1337
|
+
color: var(--dsw-alias-state-error-primary);
|
|
1338
|
+
}
|
|
1339
|
+
.hqpu-tag[data-tone='neutral'] {
|
|
1340
|
+
background: var(--dsw-alias-bg-module-platform);
|
|
1341
|
+
color: var(--dsw-alias-label-secondary);
|
|
764
1342
|
}
|
|
765
|
-
|
|
1343
|
+
|
|
1344
|
+
/* ── Fact rows (PluginManagerPage .facts / .rows) ─────────────────────── */
|
|
1345
|
+
.hqpu-facts {
|
|
1346
|
+
margin: 0;
|
|
1347
|
+
display: flex;
|
|
1348
|
+
flex-direction: column;
|
|
1349
|
+
}
|
|
1350
|
+
.hqpu-facts > div {
|
|
766
1351
|
display: flex;
|
|
767
1352
|
align-items: center;
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
1353
|
+
justify-content: space-between;
|
|
1354
|
+
gap: 16px;
|
|
1355
|
+
min-height: 44px;
|
|
1356
|
+
padding: 8px 2px;
|
|
1357
|
+
border-bottom: 0.5px solid var(--dsw-alias-border-l2);
|
|
1358
|
+
}
|
|
1359
|
+
.hqpu-facts > div:last-child {
|
|
1360
|
+
border-bottom: 0;
|
|
1361
|
+
}
|
|
1362
|
+
.hqpu-facts dt {
|
|
1363
|
+
flex: none;
|
|
1364
|
+
font-size: 13px;
|
|
1365
|
+
line-height: 20px;
|
|
1366
|
+
color: var(--dsw-alias-label-secondary);
|
|
1367
|
+
}
|
|
1368
|
+
.hqpu-facts dd {
|
|
1369
|
+
min-width: 0;
|
|
1370
|
+
margin: 0;
|
|
1371
|
+
font-size: 13px;
|
|
1372
|
+
line-height: 20px;
|
|
1373
|
+
text-align: end;
|
|
1374
|
+
overflow-wrap: anywhere;
|
|
1375
|
+
color: var(--dsw-alias-label-primary);
|
|
1376
|
+
}
|
|
1377
|
+
.hqpu-facts code {
|
|
1378
|
+
padding: 2px 6px;
|
|
1379
|
+
border-radius: var(--dsw-radius-xs);
|
|
1380
|
+
background: var(--dsw-alias-bg-module-platform);
|
|
1381
|
+
font-family: var(--dsw-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
|
|
772
1382
|
font-size: 12px;
|
|
773
|
-
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
/* ── Banner (PluginManagerPage .installSafety) ────────────────────────── */
|
|
1386
|
+
.hqpu-banner {
|
|
1387
|
+
display: flex;
|
|
1388
|
+
align-items: flex-start;
|
|
1389
|
+
gap: 8px;
|
|
1390
|
+
padding: 10px 12px;
|
|
1391
|
+
border-radius: var(--dsw-radius-md);
|
|
1392
|
+
background: var(--dsw-alias-state-warn-tertiary);
|
|
1393
|
+
font-size: 12.5px;
|
|
1394
|
+
line-height: 18px;
|
|
1395
|
+
color: var(--dsw-alias-label-secondary);
|
|
1396
|
+
}
|
|
1397
|
+
.hqpu-banner > svg {
|
|
1398
|
+
flex: none;
|
|
1399
|
+
margin-top: 2px;
|
|
1400
|
+
color: var(--dsw-alias-state-warn-primary);
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
/* ── Status, empty, failure (PluginManagerPage .status / .empty / .failure) */
|
|
1404
|
+
.hqpu-status {
|
|
1405
|
+
margin: 0;
|
|
1406
|
+
font-size: 13px;
|
|
1407
|
+
line-height: 20px;
|
|
1408
|
+
color: var(--dsw-alias-label-tertiary);
|
|
1409
|
+
}
|
|
1410
|
+
.hqpu-status--dot {
|
|
1411
|
+
display: inline-flex;
|
|
1412
|
+
align-items: center;
|
|
1413
|
+
gap: 6px;
|
|
1414
|
+
}
|
|
1415
|
+
.hqpu-failure {
|
|
1416
|
+
display: flex;
|
|
1417
|
+
align-items: center;
|
|
1418
|
+
gap: 10px;
|
|
1419
|
+
color: var(--dsw-alias-state-error-primary);
|
|
774
1420
|
}
|
|
775
1421
|
.hqpu-empty {
|
|
776
|
-
padding:
|
|
1422
|
+
padding: 32px 0;
|
|
777
1423
|
text-align: center;
|
|
778
|
-
color: var(--dsw-alias-label-tertiary, #8f959e);
|
|
779
1424
|
font-size: 13px;
|
|
1425
|
+
line-height: 20px;
|
|
1426
|
+
color: var(--dsw-alias-label-tertiary);
|
|
780
1427
|
}
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
1428
|
+
|
|
1429
|
+
/* ── State dot + spinner (ui-primitives StateDot.module.css) ──────────── */
|
|
1430
|
+
.hqpu-dot {
|
|
1431
|
+
position: relative;
|
|
1432
|
+
display: inline-block;
|
|
1433
|
+
flex: none;
|
|
1434
|
+
width: 10px;
|
|
1435
|
+
height: 10px;
|
|
784
1436
|
}
|
|
785
|
-
.hqpu-
|
|
786
|
-
|
|
787
|
-
|
|
1437
|
+
.hqpu-dot::after {
|
|
1438
|
+
content: '';
|
|
1439
|
+
position: absolute;
|
|
1440
|
+
inset: 20%;
|
|
1441
|
+
border-radius: 50%;
|
|
1442
|
+
corner-shape: round;
|
|
1443
|
+
background: currentColor;
|
|
788
1444
|
}
|
|
789
|
-
.hqpu-
|
|
790
|
-
|
|
791
|
-
|
|
1445
|
+
.hqpu-dot[data-state='done'] { color: var(--dsw-alias-state-success-primary); }
|
|
1446
|
+
.hqpu-dot[data-state='warning'] { color: var(--dsw-alias-state-warn-primary); }
|
|
1447
|
+
.hqpu-dot[data-state='error'] { color: var(--dsw-alias-state-error-primary); }
|
|
1448
|
+
.hqpu-dot[data-state='idle'] { color: var(--dsw-alias-state-idle-primary); }
|
|
1449
|
+
.hqpu-spinner {
|
|
1450
|
+
flex: none;
|
|
1451
|
+
width: 14px;
|
|
1452
|
+
height: 14px;
|
|
1453
|
+
border-radius: 50%;
|
|
1454
|
+
border: 1.5px solid color-mix(in srgb, currentColor 25%, transparent);
|
|
1455
|
+
border-top-color: currentColor;
|
|
1456
|
+
animation: hqpu-spin 1.5s linear infinite;
|
|
792
1457
|
}
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
color: var(--dsw-alias-label-tertiary, #8f959e);
|
|
1458
|
+
@keyframes hqpu-spin {
|
|
1459
|
+
to { transform: rotate(360deg); }
|
|
796
1460
|
}
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
1461
|
+
|
|
1462
|
+
/* ── Skeleton (PluginManagerPage .skeleton*) ──────────────────────────── */
|
|
1463
|
+
.hqpu-skeleton-fill {
|
|
1464
|
+
background: var(--dsw-alias-bg-skeleton);
|
|
1465
|
+
animation: hqpu-skeleton 2s cubic-bezier(0.36, 0, 0.64, 1) infinite;
|
|
800
1466
|
}
|
|
801
|
-
.hqpu-
|
|
1467
|
+
.hqpu-skeleton-text {
|
|
802
1468
|
display: flex;
|
|
803
1469
|
align-items: center;
|
|
804
|
-
|
|
1470
|
+
height: 1lh;
|
|
1471
|
+
}
|
|
1472
|
+
.hqpu-skeleton-bar {
|
|
1473
|
+
width: 100%;
|
|
1474
|
+
height: 12px;
|
|
1475
|
+
border-radius: var(--dsw-radius-xs);
|
|
1476
|
+
}
|
|
1477
|
+
.hqpu-skeleton-heading { width: 96px; }
|
|
1478
|
+
.hqpu-skeleton-title { width: min(144px, 60%); }
|
|
1479
|
+
.hqpu-skeleton-desc { width: min(280px, 85%); }
|
|
1480
|
+
.hqpu-skeleton-icon { border-color: transparent; }
|
|
1481
|
+
@keyframes hqpu-skeleton {
|
|
1482
|
+
0% { opacity: 1; }
|
|
1483
|
+
40% { opacity: 0.6; }
|
|
1484
|
+
80%, 100% { opacity: 1; }
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
/* ── Toast (ui-primitives Toast.module.css, held inside the panel) ────── */
|
|
1488
|
+
.hqpu-toast {
|
|
1489
|
+
display: flex;
|
|
1490
|
+
align-items: center;
|
|
1491
|
+
gap: 10px;
|
|
1492
|
+
padding: 12px 16px;
|
|
1493
|
+
border-radius: var(--dsw-radius-lg);
|
|
1494
|
+
background: var(--dsw-alias-toast-bg);
|
|
1495
|
+
color: var(--dsw-alias-toast-label);
|
|
1496
|
+
font-size: 14px;
|
|
1497
|
+
line-height: 22px;
|
|
1498
|
+
box-shadow: var(--dsw-shadow-lv3);
|
|
1499
|
+
animation: hqpu-toast-in 160ms ease-out;
|
|
1500
|
+
}
|
|
1501
|
+
.hqpu-toast-icon {
|
|
1502
|
+
display: grid;
|
|
1503
|
+
place-items: center;
|
|
1504
|
+
flex: none;
|
|
1505
|
+
color: var(--dsw-alias-state-warn-label);
|
|
1506
|
+
}
|
|
1507
|
+
.hqpu-toast-icon[data-tone='success'] { color: var(--dsw-alias-state-success-primary); }
|
|
1508
|
+
.hqpu-toast-text { min-width: 0; }
|
|
1509
|
+
@keyframes hqpu-toast-in {
|
|
1510
|
+
from { opacity: 0; transform: translateY(-6px); }
|
|
1511
|
+
to { opacity: 1; transform: none; }
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
/* ── Buttons (PluginManagerPage .addButton / .iconButton) ─────────────── */
|
|
1515
|
+
.hqpu-icon-btn {
|
|
1516
|
+
display: inline-flex;
|
|
1517
|
+
align-items: center;
|
|
1518
|
+
justify-content: center;
|
|
1519
|
+
flex: none;
|
|
1520
|
+
width: 28px;
|
|
1521
|
+
height: 28px;
|
|
1522
|
+
padding: 0;
|
|
1523
|
+
border: 0;
|
|
1524
|
+
border-radius: var(--dsw-radius-sm);
|
|
1525
|
+
background: transparent;
|
|
1526
|
+
color: var(--dsw-alias-label-caption);
|
|
1527
|
+
cursor: pointer;
|
|
1528
|
+
}
|
|
1529
|
+
.hqpu-icon-btn svg { display: block; }
|
|
1530
|
+
.hqpu-icon-btn:hover:not(:disabled) {
|
|
1531
|
+
background: var(--dsw-alias-interactive-bg-hover);
|
|
1532
|
+
color: var(--dsw-alias-label-secondary);
|
|
1533
|
+
}
|
|
1534
|
+
.hqpu-icon-btn:disabled {
|
|
1535
|
+
opacity: 0.5;
|
|
1536
|
+
cursor: default;
|
|
1537
|
+
}
|
|
1538
|
+
.hqpu-icon-btn:focus-visible {
|
|
1539
|
+
outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
|
|
1540
|
+
outline-offset: 1px;
|
|
805
1541
|
}
|
|
806
1542
|
.hqpu-btn {
|
|
807
1543
|
box-sizing: border-box;
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
1544
|
+
display: inline-flex;
|
|
1545
|
+
align-items: center;
|
|
1546
|
+
justify-content: center;
|
|
1547
|
+
gap: 6px;
|
|
1548
|
+
height: 32px;
|
|
1549
|
+
padding: 0 12px;
|
|
1550
|
+
border: 0;
|
|
1551
|
+
border-radius: var(--dsw-radius-md);
|
|
1552
|
+
background: var(--dsw-alias-bg-layer-3);
|
|
1553
|
+
color: var(--dsw-alias-label-primary);
|
|
813
1554
|
font: inherit;
|
|
814
1555
|
font-size: 13px;
|
|
1556
|
+
line-height: 20px;
|
|
815
1557
|
cursor: pointer;
|
|
816
1558
|
}
|
|
817
|
-
.hqpu-btn
|
|
818
|
-
|
|
819
|
-
|
|
1559
|
+
.hqpu-btn svg { display: block; }
|
|
1560
|
+
.hqpu-btn:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover-solid); }
|
|
1561
|
+
.hqpu-btn:disabled { opacity: 0.5; cursor: default; }
|
|
1562
|
+
.hqpu-btn:focus-visible {
|
|
1563
|
+
outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary));
|
|
1564
|
+
outline-offset: 1px;
|
|
820
1565
|
}
|
|
821
|
-
.hqpu-btn
|
|
822
|
-
|
|
823
|
-
|
|
1566
|
+
.hqpu-btn--primary {
|
|
1567
|
+
background: var(--dsw-alias-button-primary-fill);
|
|
1568
|
+
color: var(--dsw-alias-label-primary-foreground);
|
|
824
1569
|
}
|
|
825
|
-
.hqpu-btn-
|
|
1570
|
+
.hqpu-btn--primary:hover:not(:disabled) { background: var(--dsw-alias-button-primary-hover); }
|
|
1571
|
+
.hqpu-btn--outline {
|
|
826
1572
|
background: transparent;
|
|
827
|
-
border
|
|
1573
|
+
border: 0.5px solid var(--dsw-alias-border-l4);
|
|
1574
|
+
color: var(--dsw-alias-label-secondary);
|
|
828
1575
|
}
|
|
829
|
-
.hqpu-btn-
|
|
830
|
-
|
|
831
|
-
|
|
1576
|
+
.hqpu-btn--outline:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
|
|
1577
|
+
.hqpu-btn--ghost { background: transparent; color: var(--dsw-alias-label-secondary); }
|
|
1578
|
+
.hqpu-btn--ghost:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
|
|
1579
|
+
.hqpu-btn--danger { color: var(--dsw-alias-state-error-primary); }
|
|
1580
|
+
.hqpu-btn--sm { height: 28px; padding: 0 10px; font-size: 12.5px; }
|
|
1581
|
+
.hqpu-actions {
|
|
1582
|
+
display: flex;
|
|
1583
|
+
align-items: center;
|
|
1584
|
+
flex-wrap: wrap;
|
|
1585
|
+
gap: 8px;
|
|
832
1586
|
}
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
1587
|
+
|
|
1588
|
+
/* ── Footer action row (ui-primitives Modal .footer) ───────────────────── */
|
|
1589
|
+
.hqpu-footer {
|
|
1590
|
+
display: flex;
|
|
1591
|
+
flex: none;
|
|
1592
|
+
align-items: center;
|
|
1593
|
+
justify-content: flex-end;
|
|
1594
|
+
gap: 8px;
|
|
1595
|
+
padding: 0 24px 20px;
|
|
836
1596
|
}
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
1597
|
+
|
|
1598
|
+
.hqpu-visually-hidden {
|
|
1599
|
+
position: absolute;
|
|
1600
|
+
width: 1px;
|
|
1601
|
+
height: 1px;
|
|
1602
|
+
margin: -1px;
|
|
1603
|
+
padding: 0;
|
|
1604
|
+
overflow: hidden;
|
|
1605
|
+
clip-path: inset(50%);
|
|
1606
|
+
white-space: nowrap;
|
|
1607
|
+
border: 0;
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
/* ── Reduced motion: drop every decorative animation ──────────────────── */
|
|
1611
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1612
|
+
.hqpu-scrim,
|
|
1613
|
+
.hqpu-panel,
|
|
1614
|
+
.hqpu-skeleton-fill,
|
|
1615
|
+
.hqpu-spinner,
|
|
1616
|
+
.hqpu-toast {
|
|
1617
|
+
animation: none;
|
|
1618
|
+
}
|
|
840
1619
|
}
|
|
841
1620
|
`;
|
|
842
1621
|
const STYLE_TAG_ID = "data-plugin-css=\"huaqiu-plugin-update\"";
|
|
1622
|
+
/**
|
|
1623
|
+
* Design tokens the bundled DSH shell may not publish.
|
|
1624
|
+
*
|
|
1625
|
+
* hq-edge ships an older `ui-theme` build. A live probe of the running shell
|
|
1626
|
+
* (both themes) shows 13 of the tokens this stylesheet reads are absent:
|
|
1627
|
+
* `--dsw-radius-{xs,sm,md,lg,xl,panel}`, `--dsw-focus-ring-width`,
|
|
1628
|
+
* `--dsw-focus-ring-color`, `--dsw-alias-toast-label`,
|
|
1629
|
+
* `--dsw-alias-state-idle-primary`, `--dsw-font-mono`,
|
|
1630
|
+
* `--dsh-frame-overlay-top` and `--dsh-frame-chrome-top`.
|
|
1631
|
+
*
|
|
1632
|
+
* An unresolved `var()` is not an error — it silently degrades the property to
|
|
1633
|
+
* its initial value. That is how this panel once rendered with
|
|
1634
|
+
* `border-radius: 0px` and a 3px `auto` focus ring while every colour was
|
|
1635
|
+
* already correct.
|
|
1636
|
+
*
|
|
1637
|
+
* The last three (`--dsw-font-mono`, `--dsh-frame-*`) are deliberately NOT
|
|
1638
|
+
* backfilled: the shell's own primitives rely on the inline `var(…, fallback)`
|
|
1639
|
+
* form for those (`Modal.module.css`, `PluginManagerPage.module.css`), so this
|
|
1640
|
+
* sheet does too. Everything else is backfilled below with the canonical value
|
|
1641
|
+
* from `ui-theme/src/styles/{base,focus,design-platform}.css`.
|
|
1642
|
+
*
|
|
1643
|
+
* Values are feature-detected at runtime and scoped to this plugin's own roots
|
|
1644
|
+
* rather than `:root`, so a newer shell always wins and filling a gap can never
|
|
1645
|
+
* restyle the host.
|
|
1646
|
+
*/
|
|
1647
|
+
/** The two roots this plugin styles: the view overlay (built in
|
|
1648
|
+
* update-view.ts) and the sidebar row ({@link ENTRY_CSS}.entry). */
|
|
1649
|
+
const STYLE_ROOTS = ".hqpu-overlay, .hqpu-sidebar-entry";
|
|
1650
|
+
/** The shell's dark-theme carrier — audited live as `body[data-ds-dark-theme]`. */
|
|
1651
|
+
const DARK_THEME_SELECTOR = "body[data-ds-dark-theme]";
|
|
1652
|
+
/** Same roots, one rule per theme, for tokens whose official value flips. */
|
|
1653
|
+
const DARK_STYLE_ROOTS = STYLE_ROOTS.split(",").map((root) => `${DARK_THEME_SELECTOR} ${root.trim()}`).join(",");
|
|
1654
|
+
const DESIGN_TOKEN_FALLBACKS = [
|
|
1655
|
+
{
|
|
1656
|
+
token: "--dsw-radius-xs",
|
|
1657
|
+
value: "4px"
|
|
1658
|
+
},
|
|
1659
|
+
{
|
|
1660
|
+
token: "--dsw-radius-sm",
|
|
1661
|
+
value: "8px"
|
|
1662
|
+
},
|
|
1663
|
+
{
|
|
1664
|
+
token: "--dsw-radius-md",
|
|
1665
|
+
value: "12px"
|
|
1666
|
+
},
|
|
1667
|
+
{
|
|
1668
|
+
token: "--dsw-radius-lg",
|
|
1669
|
+
value: "16px"
|
|
1670
|
+
},
|
|
1671
|
+
{
|
|
1672
|
+
token: "--dsw-radius-xl",
|
|
1673
|
+
value: "20px"
|
|
1674
|
+
},
|
|
1675
|
+
{
|
|
1676
|
+
token: "--dsw-radius-panel",
|
|
1677
|
+
value: "28px"
|
|
1678
|
+
},
|
|
1679
|
+
{
|
|
1680
|
+
token: "--dsw-focus-ring-width",
|
|
1681
|
+
value: "2px"
|
|
1682
|
+
},
|
|
1683
|
+
{
|
|
1684
|
+
token: "--dsw-focus-ring-color",
|
|
1685
|
+
value: "var(--dsw-alias-state-business-primary, #C7000B)"
|
|
1686
|
+
},
|
|
1687
|
+
{
|
|
1688
|
+
token: "--dsw-alias-toast-label",
|
|
1689
|
+
value: "var(--dsw-static-neutral-bluish-00, #fff)"
|
|
1690
|
+
},
|
|
1691
|
+
{
|
|
1692
|
+
token: "--dsw-alias-state-idle-primary",
|
|
1693
|
+
value: {
|
|
1694
|
+
light: "var(--dsw-static-neutral-300, #d4d4d4)",
|
|
1695
|
+
dark: "var(--dsw-static-neutral-600, #545557)"
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
];
|
|
1699
|
+
const TOKEN_STYLE_TAG_ID = "data-plugin-css=\"huaqiu-plugin-update-tokens\"";
|
|
1700
|
+
/**
|
|
1701
|
+
* Publish canonical values for the design tokens the shell is missing.
|
|
1702
|
+
*
|
|
1703
|
+
* Idempotent and cheap: safe to call on every open, so a shell that publishes
|
|
1704
|
+
* its tokens late still wins (the stale fallbacks are removed in that case).
|
|
1705
|
+
*/
|
|
1706
|
+
function ensureDesignTokens() {
|
|
1707
|
+
if (typeof document === "undefined" || document.body === null) return;
|
|
1708
|
+
const probe = getComputedStyle(document.body);
|
|
1709
|
+
const missing = DESIGN_TOKEN_FALLBACKS.filter((entry) => probe.getPropertyValue(entry.token).trim() === "");
|
|
1710
|
+
const existing = document.querySelector(`style[${TOKEN_STYLE_TAG_ID}]`);
|
|
1711
|
+
if (missing.length === 0) {
|
|
1712
|
+
existing?.remove();
|
|
1713
|
+
return;
|
|
1714
|
+
}
|
|
1715
|
+
const flat = missing.filter((entry) => typeof entry.value === "string");
|
|
1716
|
+
const themed = missing.filter((entry) => typeof entry.value !== "string");
|
|
1717
|
+
const rules = [];
|
|
1718
|
+
const lightDecls = [...flat.map((entry) => ` ${entry.token}: ${entry.value};`), ...themed.map((entry) => ` ${entry.token}: ${entry.value.light};`)];
|
|
1719
|
+
rules.push(`${STYLE_ROOTS} {\n${lightDecls.join("\n")}\n}`);
|
|
1720
|
+
if (themed.length > 0) {
|
|
1721
|
+
const darkDecls = themed.map((entry) => ` ${entry.token}: ${entry.value.dark};`);
|
|
1722
|
+
rules.push(`${DARK_STYLE_ROOTS} {\n${darkDecls.join("\n")}\n}`);
|
|
1723
|
+
}
|
|
1724
|
+
const tag = existing ?? document.createElement("style");
|
|
1725
|
+
tag.dataset.pluginCss = "huaqiu-plugin-update-tokens";
|
|
1726
|
+
tag.textContent = rules.join("\n");
|
|
1727
|
+
if (tag.parentNode === null) document.head.appendChild(tag);
|
|
1728
|
+
}
|
|
843
1729
|
/** Inject styles once (idempotent). */
|
|
844
1730
|
function injectUpdateStyles() {
|
|
845
1731
|
if (typeof document === "undefined") return;
|
|
@@ -934,6 +1820,7 @@ window.__ModuleLoader__.load({
|
|
|
934
1820
|
function apply(ctx) {
|
|
935
1821
|
if (typeof document === "undefined") return () => {};
|
|
936
1822
|
injectUpdateStyles();
|
|
1823
|
+
ensureDesignTokens();
|
|
937
1824
|
const store = new UpdateStore();
|
|
938
1825
|
const copy = {
|
|
939
1826
|
zh: COPY.zh,
|
|
@@ -954,11 +1841,8 @@ window.__ModuleLoader__.load({
|
|
|
954
1841
|
fn();
|
|
955
1842
|
} catch {}
|
|
956
1843
|
});
|
|
957
|
-
const labelState = {
|
|
958
|
-
label: entryCopy(locale).label,
|
|
959
|
-
tooltip: entryCopy(locale).tooltip
|
|
960
|
-
};
|
|
961
1844
|
const openView = () => {
|
|
1845
|
+
ensureDesignTokens();
|
|
962
1846
|
store.check().then((report) => {
|
|
963
1847
|
if (report !== null) openUpdateView(store, copyFor());
|
|
964
1848
|
});
|
|
@@ -969,8 +1853,8 @@ window.__ModuleLoader__.load({
|
|
|
969
1853
|
plugin: PLUGIN_ID,
|
|
970
1854
|
icon: UPDATE_ICON,
|
|
971
1855
|
css: ENTRY_CSS,
|
|
972
|
-
label: () =>
|
|
973
|
-
tooltip: () =>
|
|
1856
|
+
label: () => entryCopy(locale).label,
|
|
1857
|
+
tooltip: () => entryCopy(locale).tooltip,
|
|
974
1858
|
refresh: { subscribe: refreshSubscribe },
|
|
975
1859
|
badge: {
|
|
976
1860
|
subscribe: (listener) => store.subscribe(listener),
|
|
@@ -989,7 +1873,7 @@ window.__ModuleLoader__.load({
|
|
|
989
1873
|
unsubscribeLocale();
|
|
990
1874
|
store.stop();
|
|
991
1875
|
};
|
|
992
|
-
if (typeof ctx.effect === "function") ctx.effect(dispose, "plugin-update");
|
|
1876
|
+
if (typeof ctx.effect === "function") ctx.effect(() => dispose, "plugin-update");
|
|
993
1877
|
return dispose;
|
|
994
1878
|
}
|
|
995
1879
|
//#endregion
|
|
@@ -997,6 +1881,7 @@ window.__ModuleLoader__.load({
|
|
|
997
1881
|
exports.UPDATE_ENTRY_SELECTOR = UPDATE_ENTRY_SELECTOR;
|
|
998
1882
|
exports.UPDATE_ICON = UPDATE_ICON;
|
|
999
1883
|
exports.apply = apply;
|
|
1884
|
+
exports.ensureDesignTokens = ensureDesignTokens;
|
|
1000
1885
|
exports.inject = inject;
|
|
1001
1886
|
exports.injectUpdateStyles = injectUpdateStyles;
|
|
1002
1887
|
return module.exports;
|