@restregular/dsh-powerup 0.2.1 → 0.2.3
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/README.md +3 -1
- package/client.js +265 -102
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -87,7 +87,9 @@ unload the dialog mid-flow. Use **Add plugin** with the new package version.
|
|
|
87
87
|
`--dsw-elevation-prominent`, and the primary button uses
|
|
88
88
|
`--dsw-alias-button-primary-fill` / `-hover`, so the dialog follows both
|
|
89
89
|
themes instead of inventing its own palette. The registry picker and version
|
|
90
|
-
list are custom controls built from `--dsw-alias-*` tokens
|
|
90
|
+
list are custom controls built from `--dsw-alias-*` tokens; both open as
|
|
91
|
+
fixed-position popovers anchored to their triggers, so they never grow the
|
|
92
|
+
dialog or get clipped by its scroll area.
|
|
91
93
|
|
|
92
94
|
## Development
|
|
93
95
|
|
package/client.js
CHANGED
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
|
|
45
45
|
const NS = 'dsh-powerup';
|
|
46
46
|
const SETTINGS_KEY = 'dsh-powerup:settings:v1';
|
|
47
|
-
const VERSION = '0.2.
|
|
47
|
+
const VERSION = '0.2.3';
|
|
48
48
|
const MENU_GAP = 8;
|
|
49
49
|
const MENU_WIDTH = 248;
|
|
50
50
|
|
|
@@ -126,6 +126,8 @@
|
|
|
126
126
|
'update.versionsFailed': '读取版本失败:{message}',
|
|
127
127
|
'update.versionsEmpty': '安装源没有返回可用版本',
|
|
128
128
|
'update.latest': '最新',
|
|
129
|
+
'update.currentTag': '当前',
|
|
130
|
+
'update.currentAndLatest': '当前 · 最新',
|
|
129
131
|
'update.retry': '重试',
|
|
130
132
|
'update.registry': '安装源',
|
|
131
133
|
'update.registryDefault': '默认安装源',
|
|
@@ -246,6 +248,8 @@
|
|
|
246
248
|
'update.versionsFailed': 'Could not read versions: {message}',
|
|
247
249
|
'update.versionsEmpty': 'The registry returned no versions',
|
|
248
250
|
'update.latest': 'latest',
|
|
251
|
+
'update.currentTag': 'Current',
|
|
252
|
+
'update.currentAndLatest': 'Current · latest',
|
|
249
253
|
'update.retry': 'Retry',
|
|
250
254
|
'update.registry': 'Registry',
|
|
251
255
|
'update.registryDefault': 'Default registry',
|
|
@@ -694,12 +698,18 @@
|
|
|
694
698
|
.dsh-powerup-update-toggle .chevron{display:inline-flex;color:var(--dsw-alias-label-tertiary);transition:transform .16s ease}
|
|
695
699
|
.dsh-powerup-update-toggle[aria-expanded=true] .chevron{transform:rotate(180deg);color:var(--dsw-alias-label-secondary)}
|
|
696
700
|
.dsh-powerup-update-list{display:flex;flex-direction:column;max-height:240px;overflow-y:auto;border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-lg,10px);background:var(--dsw-alias-bg-layer-1);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2)}
|
|
701
|
+
.dsh-powerup-update-popover{position:fixed;z-index:1300;box-sizing:border-box;overflow-y:auto;pointer-events:auto;border:.5px solid var(--dsw-alias-border-l2);border-radius:var(--dsw-radius-lg,10px);background:var(--dsw-alias-bg-layer-2);box-shadow:var(--dsw-elevation-prominent);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2)}
|
|
702
|
+
.dsh-powerup-update-popover.dsh-powerup-update-list{border-radius:var(--dsw-radius-lg,10px)}
|
|
703
|
+
.dsh-powerup-update-popover.dsh-powerup-update-select-menu{display:flex;flex-direction:column;padding:4px}
|
|
697
704
|
.dsh-powerup-update-list-head{position:sticky;top:0;z-index:1;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:7px 12px;border-bottom:.5px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}
|
|
698
705
|
.dsh-powerup-update-version{display:flex;align-items:center;gap:8px;width:100%;min-height:34px;padding:0 12px;border:0;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:12.5px;line-height:18px;text-align:left;cursor:pointer;font-variant-numeric:tabular-nums}
|
|
706
|
+
.dsh-powerup-update-version>span:first-child{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
699
707
|
.dsh-powerup-update-version:hover{background:var(--dsw-alias-interactive-bg-hover)}
|
|
700
708
|
.dsh-powerup-update-version[aria-selected=true]{background:var(--dsw-alias-interactive-bg-active)}
|
|
701
|
-
.dsh-powerup-update-
|
|
702
|
-
.dsh-powerup-update-
|
|
709
|
+
.dsh-powerup-update-version[data-current]{box-shadow:inset 2px 0 0 var(--dsw-alias-state-business-primary)}
|
|
710
|
+
.dsh-powerup-update-trailing{display:inline-flex;flex:none;align-items:center;gap:8px;margin-left:auto;white-space:nowrap}
|
|
711
|
+
.dsh-powerup-update-tag{padding:0 6px;border:.5px solid var(--dsw-alias-border-l2);border-radius:999px;background:transparent;color:var(--dsw-alias-label-tertiary);font-size:10px;line-height:16px;white-space:nowrap}
|
|
712
|
+
.dsh-powerup-update-tag.is-current{border-color:color-mix(in srgb,var(--dsw-alias-state-business-primary) 38%,transparent);background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 8%,transparent);color:var(--dsw-alias-state-business-primary)}
|
|
703
713
|
.dsh-powerup-update-check{display:inline-flex;color:var(--dsw-alias-state-business-primary)}
|
|
704
714
|
.dsh-powerup-update-status{display:flex;align-items:center;gap:10px;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:20px}
|
|
705
715
|
.dsh-powerup-update-spinner{flex:none;width:14px;height:14px;border:2px solid color-mix(in srgb,var(--dsw-alias-state-business-primary) 24%,transparent);border-top-color:var(--dsw-alias-state-business-primary);border-radius:50%;animation:dsh-powerup-spin .8s linear infinite}
|
|
@@ -1342,6 +1352,24 @@
|
|
|
1342
1352
|
return list.sort(compareVersionsDesc);
|
|
1343
1353
|
}
|
|
1344
1354
|
|
|
1355
|
+
/**
|
|
1356
|
+
* Which status a version row carries. The installed and the latest
|
|
1357
|
+
* version can be the same; that row gets one combined tag instead of two
|
|
1358
|
+
* chips sharing the trailing space.
|
|
1359
|
+
* @param {string} version
|
|
1360
|
+
* @param {string | null | undefined} current
|
|
1361
|
+
* @param {string | null | undefined} latest
|
|
1362
|
+
* @returns {'current-latest' | 'current' | 'latest' | null}
|
|
1363
|
+
*/
|
|
1364
|
+
function versionTagKind(version, current, latest) {
|
|
1365
|
+
const isCurrent = typeof current === 'string' && current !== '' && version === current;
|
|
1366
|
+
const isLatest = typeof latest === 'string' && latest !== '' && version === latest;
|
|
1367
|
+
if (isCurrent && isLatest) return 'current-latest';
|
|
1368
|
+
if (isCurrent) return 'current';
|
|
1369
|
+
if (isLatest) return 'latest';
|
|
1370
|
+
return null;
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1345
1373
|
/**
|
|
1346
1374
|
* Read the versions the registry publishes for one package. The
|
|
1347
1375
|
* abbreviated metadata keeps the response small; both npm and npmmirror
|
|
@@ -1477,6 +1505,33 @@
|
|
|
1477
1505
|
for (const button of [...buttons]) if (button.isConnected !== true) buttons.delete(button);
|
|
1478
1506
|
}
|
|
1479
1507
|
|
|
1508
|
+
/**
|
|
1509
|
+
* Place a floating panel under an anchor, flipping above when the space
|
|
1510
|
+
* below is short, and clamp it to the viewport.
|
|
1511
|
+
* @param {{ getBoundingClientRect: () => DOMRect }} anchor
|
|
1512
|
+
* @param {number} minWidth
|
|
1513
|
+
* @param {number} preferredHeight
|
|
1514
|
+
* @returns {{ left: number, width: number, top?: number, bottom?: number, maxHeight: number }}
|
|
1515
|
+
*/
|
|
1516
|
+
function popoverPlacement(anchor, minWidth, preferredHeight) {
|
|
1517
|
+
const rect = anchor.getBoundingClientRect();
|
|
1518
|
+
const gap = 6;
|
|
1519
|
+
const margin = 12;
|
|
1520
|
+
const viewportWidth = typeof window === 'undefined' ? 1280 : window.innerWidth;
|
|
1521
|
+
const viewportHeight = typeof window === 'undefined' ? 900 : window.innerHeight;
|
|
1522
|
+
const width = Math.min(Math.max(rect.width, minWidth), Math.max(200, viewportWidth - margin * 2));
|
|
1523
|
+
const left = Math.min(Math.max(margin, rect.left), Math.max(margin, viewportWidth - width - margin));
|
|
1524
|
+
const spaceBelow = viewportHeight - rect.bottom - margin - gap;
|
|
1525
|
+
const spaceAbove = rect.top - margin - gap;
|
|
1526
|
+
const above = spaceBelow < Math.min(preferredHeight, 180) && spaceAbove > spaceBelow;
|
|
1527
|
+
return {
|
|
1528
|
+
left,
|
|
1529
|
+
width,
|
|
1530
|
+
...(above ? { bottom: viewportHeight - rect.top + gap } : { top: rect.bottom + gap }),
|
|
1531
|
+
maxHeight: Math.max(120, Math.min(preferredHeight, above ? spaceAbove : spaceBelow)),
|
|
1532
|
+
};
|
|
1533
|
+
}
|
|
1534
|
+
|
|
1480
1535
|
/**
|
|
1481
1536
|
* The Plugins-page update control. It injects one icon button into each
|
|
1482
1537
|
* third-party card of the built-in "Installed plugins" group, then owns
|
|
@@ -1491,7 +1546,10 @@
|
|
|
1491
1546
|
const abortRef = useRef(null);
|
|
1492
1547
|
const buttonsRef = useRef(new Set());
|
|
1493
1548
|
const inputRef = useRef(null);
|
|
1549
|
+
const versionRef = useRef(null);
|
|
1550
|
+
const versionPanelRef = useRef(null);
|
|
1494
1551
|
const registryRef = useRef(null);
|
|
1552
|
+
const registryPanelRef = useRef(null);
|
|
1495
1553
|
const versionSeq = useRef(0);
|
|
1496
1554
|
const tRef = useRef((key, params) => translateCurrent(key, params));
|
|
1497
1555
|
tRef.current = (key, params) => translateCurrent(key, params);
|
|
@@ -1523,6 +1581,17 @@
|
|
|
1523
1581
|
setView(null);
|
|
1524
1582
|
}, [view]);
|
|
1525
1583
|
|
|
1584
|
+
/** Dismiss both floating panels without touching the dialog. */
|
|
1585
|
+
const closePopovers = useCallback(() => {
|
|
1586
|
+
setView((current) => current === null ? current : {
|
|
1587
|
+
...current,
|
|
1588
|
+
listOpen: false,
|
|
1589
|
+
listPopover: null,
|
|
1590
|
+
registryOpen: false,
|
|
1591
|
+
registryPopover: null,
|
|
1592
|
+
});
|
|
1593
|
+
}, []);
|
|
1594
|
+
|
|
1526
1595
|
const loadVersions = useCallback(async (token, name, choice, choices, resetVersion) => {
|
|
1527
1596
|
const t = tRef.current;
|
|
1528
1597
|
const seq = versionSeq.current + 1;
|
|
@@ -1581,8 +1650,10 @@
|
|
|
1581
1650
|
versionsError: null,
|
|
1582
1651
|
versionsRegistry: null,
|
|
1583
1652
|
version: '',
|
|
1584
|
-
listOpen:
|
|
1653
|
+
listOpen: false,
|
|
1654
|
+
listPopover: null,
|
|
1585
1655
|
registryOpen: false,
|
|
1656
|
+
registryPopover: null,
|
|
1586
1657
|
error: null,
|
|
1587
1658
|
formError: null,
|
|
1588
1659
|
log: '',
|
|
@@ -1675,19 +1746,18 @@
|
|
|
1675
1746
|
}
|
|
1676
1747
|
}, [view === null ? null : view.phase]);
|
|
1677
1748
|
|
|
1678
|
-
// Escape closes the innermost
|
|
1679
|
-
// version list, then the dialog itself.
|
|
1749
|
+
// Escape closes the innermost floating panel first, then the dialog.
|
|
1680
1750
|
useEffect(() => {
|
|
1681
1751
|
if (view === null) return undefined;
|
|
1682
1752
|
const onKeyDown = (event) => {
|
|
1683
1753
|
if (event.key !== 'Escape') return;
|
|
1684
1754
|
event.stopPropagation();
|
|
1685
1755
|
if (view.registryOpen === true) {
|
|
1686
|
-
setView((current) => current === null ? current : { ...current, registryOpen: false });
|
|
1756
|
+
setView((current) => current === null ? current : { ...current, registryOpen: false, registryPopover: null });
|
|
1687
1757
|
return;
|
|
1688
1758
|
}
|
|
1689
1759
|
if (view.phase === 'choose' && view.listOpen === true) {
|
|
1690
|
-
setView((current) => current === null ? current : { ...current, listOpen: false });
|
|
1760
|
+
setView((current) => current === null ? current : { ...current, listOpen: false, listPopover: null });
|
|
1691
1761
|
return;
|
|
1692
1762
|
}
|
|
1693
1763
|
close();
|
|
@@ -1696,17 +1766,42 @@
|
|
|
1696
1766
|
return () => document.removeEventListener('keydown', onKeyDown, true);
|
|
1697
1767
|
}, [view, close]);
|
|
1698
1768
|
|
|
1699
|
-
//
|
|
1769
|
+
// Clicking outside the open floating panel and its trigger dismisses it.
|
|
1700
1770
|
useEffect(() => {
|
|
1701
|
-
if (view === null || view.registryOpen !== true) return undefined;
|
|
1771
|
+
if (view === null || (view.registryOpen !== true && view.listOpen !== true)) return undefined;
|
|
1702
1772
|
const onPointerDown = (event) => {
|
|
1703
|
-
const
|
|
1704
|
-
if (
|
|
1705
|
-
|
|
1773
|
+
const target = event.target;
|
|
1774
|
+
if (!(target instanceof Node)) return;
|
|
1775
|
+
const inside = [versionRef.current, versionPanelRef.current, registryRef.current, registryPanelRef.current]
|
|
1776
|
+
.some((root) => root !== null && root.contains(target));
|
|
1777
|
+
if (inside) return;
|
|
1778
|
+
closePopovers();
|
|
1706
1779
|
};
|
|
1707
1780
|
document.addEventListener('pointerdown', onPointerDown, true);
|
|
1708
1781
|
return () => document.removeEventListener('pointerdown', onPointerDown, true);
|
|
1709
|
-
}, [view === null ? null : view.registryOpen]);
|
|
1782
|
+
}, [view === null ? null : `${String(view.registryOpen)}:${String(view.listOpen)}`, closePopovers]);
|
|
1783
|
+
|
|
1784
|
+
// Scrolling the dialog or the page would leave a fixed panel behind;
|
|
1785
|
+
// dismiss it instead. Scrolling inside the panel itself is allowed.
|
|
1786
|
+
useEffect(() => {
|
|
1787
|
+
if (view === null || (view.registryOpen !== true && view.listOpen !== true)) return undefined;
|
|
1788
|
+
const onScroll = (event) => {
|
|
1789
|
+
const target = event.target;
|
|
1790
|
+
if (target instanceof Node) {
|
|
1791
|
+
const insidePanel = [versionPanelRef.current, registryPanelRef.current]
|
|
1792
|
+
.some((panel) => panel !== null && panel.contains(target));
|
|
1793
|
+
if (insidePanel) return;
|
|
1794
|
+
}
|
|
1795
|
+
closePopovers();
|
|
1796
|
+
};
|
|
1797
|
+
const onResize = () => closePopovers();
|
|
1798
|
+
document.addEventListener('scroll', onScroll, true);
|
|
1799
|
+
window.addEventListener('resize', onResize);
|
|
1800
|
+
return () => {
|
|
1801
|
+
document.removeEventListener('scroll', onScroll, true);
|
|
1802
|
+
window.removeEventListener('resize', onResize);
|
|
1803
|
+
};
|
|
1804
|
+
}, [view === null ? null : `${String(view.registryOpen)}:${String(view.listOpen)}`, closePopovers]);
|
|
1710
1805
|
|
|
1711
1806
|
// Show pnpm output while an installation runs.
|
|
1712
1807
|
useEffect(() => {
|
|
@@ -1731,7 +1826,7 @@
|
|
|
1731
1826
|
|
|
1732
1827
|
const chooseVersion = (version) => {
|
|
1733
1828
|
if (tokenRef.current === null) return;
|
|
1734
|
-
setView((current) => current === null ? current : { ...current, version, listOpen: false, formError: null });
|
|
1829
|
+
setView((current) => current === null ? current : { ...current, version, listOpen: false, listPopover: null, formError: null });
|
|
1735
1830
|
};
|
|
1736
1831
|
|
|
1737
1832
|
const chooseRegistry = (key) => {
|
|
@@ -1741,10 +1836,48 @@
|
|
|
1741
1836
|
if (current === null) return;
|
|
1742
1837
|
const choice = current.choices.find((item) => item.key === key);
|
|
1743
1838
|
if (choice === undefined) return;
|
|
1744
|
-
setView((state) => state === null ? state : { ...state, registryKey: key, registryOpen: false, formError: null });
|
|
1839
|
+
setView((state) => state === null ? state : { ...state, registryKey: key, registryOpen: false, registryPopover: null, formError: null });
|
|
1745
1840
|
loadVersions(token, current.name, choice, current.choices, true);
|
|
1746
1841
|
};
|
|
1747
1842
|
|
|
1843
|
+
/** Open or close the floating version list under the input row. */
|
|
1844
|
+
const toggleVersionList = () => {
|
|
1845
|
+
const current = view;
|
|
1846
|
+
if (current === null || current.phase !== 'choose') return;
|
|
1847
|
+
if (current.listOpen === true) {
|
|
1848
|
+
setView((state) => state === null ? state : { ...state, listOpen: false, listPopover: null });
|
|
1849
|
+
return;
|
|
1850
|
+
}
|
|
1851
|
+
const anchor = versionRef.current;
|
|
1852
|
+
const popover = anchor === null ? null : popoverPlacement(anchor, 280, 260);
|
|
1853
|
+
setView((state) => state === null ? state : {
|
|
1854
|
+
...state,
|
|
1855
|
+
listOpen: true,
|
|
1856
|
+
listPopover: popover,
|
|
1857
|
+
registryOpen: false,
|
|
1858
|
+
registryPopover: null,
|
|
1859
|
+
});
|
|
1860
|
+
};
|
|
1861
|
+
|
|
1862
|
+
/** Open or close the floating registry menu under its trigger. */
|
|
1863
|
+
const toggleRegistry = () => {
|
|
1864
|
+
const current = view;
|
|
1865
|
+
if (current === null || current.phase !== 'choose') return;
|
|
1866
|
+
if (current.registryOpen === true) {
|
|
1867
|
+
setView((state) => state === null ? state : { ...state, registryOpen: false, registryPopover: null });
|
|
1868
|
+
return;
|
|
1869
|
+
}
|
|
1870
|
+
const anchor = registryRef.current;
|
|
1871
|
+
const popover = anchor === null ? null : popoverPlacement(anchor, 280, 220);
|
|
1872
|
+
setView((state) => state === null ? state : {
|
|
1873
|
+
...state,
|
|
1874
|
+
registryOpen: true,
|
|
1875
|
+
registryPopover: popover,
|
|
1876
|
+
listOpen: false,
|
|
1877
|
+
listPopover: null,
|
|
1878
|
+
});
|
|
1879
|
+
};
|
|
1880
|
+
|
|
1748
1881
|
const startUpdate = async () => {
|
|
1749
1882
|
const token = tokenRef.current;
|
|
1750
1883
|
const current = view;
|
|
@@ -1907,6 +2040,61 @@
|
|
|
1907
2040
|
|
|
1908
2041
|
const currentChoice = view.choices.find((item) => item.key === view.registryKey) ?? view.choices[0];
|
|
1909
2042
|
|
|
2043
|
+
/** Rows of the floating version list, including its loading/error states. */
|
|
2044
|
+
const versionRows = (() => {
|
|
2045
|
+
if (view.versionsState === 'loading') {
|
|
2046
|
+
return [h('div', { key: 'state', className: 'dsh-powerup-update-list-state' },
|
|
2047
|
+
h('div', { className: 'dsh-powerup-update-status' },
|
|
2048
|
+
h('span', { className: 'dsh-powerup-update-spinner', 'aria-hidden': 'true' }),
|
|
2049
|
+
t('update.loadingVersions'),
|
|
2050
|
+
),
|
|
2051
|
+
)];
|
|
2052
|
+
}
|
|
2053
|
+
if (view.versionsState === 'error') {
|
|
2054
|
+
return [h('div', { key: 'state', className: 'dsh-powerup-update-list-state' },
|
|
2055
|
+
notice('error', h(WarnIcon, { size: 14 }), null, t('update.versionsFailed', { message: view.versionsError ?? '' })),
|
|
2056
|
+
h('button', {
|
|
2057
|
+
type: 'button',
|
|
2058
|
+
className: 'dsh-powerup-update-ghost',
|
|
2059
|
+
onClick: () => loadVersions(tokenRef.current, view.name, currentChoice, view.choices, false),
|
|
2060
|
+
}, t('update.retry')),
|
|
2061
|
+
)];
|
|
2062
|
+
}
|
|
2063
|
+
if ((view.versions ?? []).length === 0) {
|
|
2064
|
+
return [h('div', { key: 'state', className: 'dsh-powerup-update-list-state' },
|
|
2065
|
+
h('p', { className: 'dsh-powerup-update-note' }, t('update.versionsEmpty')),
|
|
2066
|
+
)];
|
|
2067
|
+
}
|
|
2068
|
+
return [
|
|
2069
|
+
h('div', { key: 'head', className: 'dsh-powerup-update-list-head' },
|
|
2070
|
+
h('span', null, t('update.versionsCount', { count: view.versions.length })),
|
|
2071
|
+
view.versionsRegistry === null || view.versionsRegistry === undefined
|
|
2072
|
+
? null
|
|
2073
|
+
: h('span', { title: view.versionsRegistry.hint }, view.versionsRegistry.hint),
|
|
2074
|
+
),
|
|
2075
|
+
...view.versions.map((version) => {
|
|
2076
|
+
const tagKind = versionTagKind(version, view.currentVersion, view.latest);
|
|
2077
|
+
return h('button', {
|
|
2078
|
+
key: version,
|
|
2079
|
+
type: 'button',
|
|
2080
|
+
role: 'option',
|
|
2081
|
+
className: 'dsh-powerup-update-version',
|
|
2082
|
+
'aria-selected': version === view.version ? 'true' : 'false',
|
|
2083
|
+
'data-current': version === view.currentVersion ? '' : undefined,
|
|
2084
|
+
onClick: () => chooseVersion(version),
|
|
2085
|
+
},
|
|
2086
|
+
h('span', null, version),
|
|
2087
|
+
h('span', { className: 'dsh-powerup-update-trailing' },
|
|
2088
|
+
tagKind === null ? null : h('span', {
|
|
2089
|
+
className: `dsh-powerup-update-tag${tagKind === 'latest' ? '' : ' is-current'}`,
|
|
2090
|
+
}, t(tagKind === 'current-latest' ? 'update.currentAndLatest' : tagKind === 'current' ? 'update.currentTag' : 'update.latest')),
|
|
2091
|
+
version === view.version ? h('span', { className: 'dsh-powerup-update-check' }, h(CheckIcon, { size: 13 })) : null,
|
|
2092
|
+
),
|
|
2093
|
+
);
|
|
2094
|
+
}),
|
|
2095
|
+
];
|
|
2096
|
+
})();
|
|
2097
|
+
|
|
1910
2098
|
const body = (() => {
|
|
1911
2099
|
if (view.phase === 'loading') {
|
|
1912
2100
|
return h('div', { className: 'dsh-powerup-update-status' },
|
|
@@ -1921,53 +2109,6 @@
|
|
|
1921
2109
|
return notice('error', h(WarnIcon, { size: 15 }), t('update.unsupportedTitle'), view.error ?? t('update.notRemovable'));
|
|
1922
2110
|
}
|
|
1923
2111
|
if (view.phase === 'choose') {
|
|
1924
|
-
const rows = (() => {
|
|
1925
|
-
if (view.versionsState === 'loading') {
|
|
1926
|
-
return [h('div', { key: 'state', className: 'dsh-powerup-update-list-state' },
|
|
1927
|
-
h('div', { className: 'dsh-powerup-update-status' },
|
|
1928
|
-
h('span', { className: 'dsh-powerup-update-spinner', 'aria-hidden': 'true' }),
|
|
1929
|
-
t('update.loadingVersions'),
|
|
1930
|
-
),
|
|
1931
|
-
)];
|
|
1932
|
-
}
|
|
1933
|
-
if (view.versionsState === 'error') {
|
|
1934
|
-
return [h('div', { key: 'state', className: 'dsh-powerup-update-list-state' },
|
|
1935
|
-
notice('error', h(WarnIcon, { size: 14 }), null, t('update.versionsFailed', { message: view.versionsError ?? '' })),
|
|
1936
|
-
h('button', {
|
|
1937
|
-
type: 'button',
|
|
1938
|
-
className: 'dsh-powerup-update-ghost',
|
|
1939
|
-
onClick: () => loadVersions(tokenRef.current, view.name, currentChoice, view.choices, false),
|
|
1940
|
-
}, t('update.retry')),
|
|
1941
|
-
)];
|
|
1942
|
-
}
|
|
1943
|
-
if ((view.versions ?? []).length === 0) {
|
|
1944
|
-
return [h('div', { key: 'state', className: 'dsh-powerup-update-list-state' },
|
|
1945
|
-
h('p', { className: 'dsh-powerup-update-note' }, t('update.versionsEmpty')),
|
|
1946
|
-
)];
|
|
1947
|
-
}
|
|
1948
|
-
return [
|
|
1949
|
-
h('div', { key: 'head', className: 'dsh-powerup-update-list-head' },
|
|
1950
|
-
h('span', null, t('update.versionsCount', { count: view.versions.length })),
|
|
1951
|
-
view.versionsRegistry === null || view.versionsRegistry === undefined
|
|
1952
|
-
? null
|
|
1953
|
-
: h('span', { title: view.versionsRegistry.hint }, view.versionsRegistry.hint),
|
|
1954
|
-
),
|
|
1955
|
-
...view.versions.map((version) => h('button', {
|
|
1956
|
-
key: version,
|
|
1957
|
-
type: 'button',
|
|
1958
|
-
role: 'option',
|
|
1959
|
-
className: 'dsh-powerup-update-version',
|
|
1960
|
-
'aria-selected': version === view.version ? 'true' : 'false',
|
|
1961
|
-
onClick: () => chooseVersion(version),
|
|
1962
|
-
},
|
|
1963
|
-
h('span', null, version),
|
|
1964
|
-
h('span', { className: 'dsh-powerup-update-trailing' },
|
|
1965
|
-
version === view.latest ? h('span', { className: 'dsh-powerup-update-tag' }, t('update.latest')) : null,
|
|
1966
|
-
version === view.version ? h('span', { className: 'dsh-powerup-update-check' }, h(CheckIcon, { size: 13 })) : null,
|
|
1967
|
-
),
|
|
1968
|
-
)),
|
|
1969
|
-
];
|
|
1970
|
-
})();
|
|
1971
2112
|
return [
|
|
1972
2113
|
h('div', { key: 'summary', className: 'dsh-powerup-update-summary' },
|
|
1973
2114
|
h('div', { className: 'dsh-powerup-update-now' },
|
|
@@ -1979,7 +2120,7 @@
|
|
|
1979
2120
|
),
|
|
1980
2121
|
h('div', { key: 'version', className: 'dsh-powerup-update-field' },
|
|
1981
2122
|
h('label', { className: 'dsh-powerup-update-label', htmlFor: 'dsh-powerup-update-version' }, t('update.versionLabel')),
|
|
1982
|
-
h('div', { className: 'dsh-powerup-update-row' },
|
|
2123
|
+
h('div', { className: 'dsh-powerup-update-row', ref: versionRef },
|
|
1983
2124
|
h('input', {
|
|
1984
2125
|
id: 'dsh-powerup-update-version',
|
|
1985
2126
|
ref: inputRef,
|
|
@@ -1999,7 +2140,7 @@
|
|
|
1999
2140
|
className: 'dsh-powerup-update-toggle',
|
|
2000
2141
|
'aria-expanded': showVersions ? 'true' : 'false',
|
|
2001
2142
|
'aria-controls': 'dsh-powerup-update-versions',
|
|
2002
|
-
onClick:
|
|
2143
|
+
onClick: toggleVersionList,
|
|
2003
2144
|
},
|
|
2004
2145
|
showVersions ? t('update.hideVersions') : t('update.chooseVersion'),
|
|
2005
2146
|
h('span', { className: 'chevron' }, h(ChevronDownIcon, { size: 12 })),
|
|
@@ -2009,7 +2150,6 @@
|
|
|
2009
2150
|
? null
|
|
2010
2151
|
: notice('error', h(WarnIcon, { size: 14 }), null, view.formError),
|
|
2011
2152
|
),
|
|
2012
|
-
showVersions ? h('div', { key: 'versions', id: 'dsh-powerup-update-versions', className: 'dsh-powerup-update-list', role: 'listbox', 'aria-label': t('update.versionLabel') }, rows) : null,
|
|
2013
2153
|
h('div', { key: 'registry', className: 'dsh-powerup-update-field' },
|
|
2014
2154
|
h('span', { className: 'dsh-powerup-update-label' }, t('update.registry')),
|
|
2015
2155
|
h('div', { className: 'dsh-powerup-update-select', ref: registryRef },
|
|
@@ -2018,27 +2158,12 @@
|
|
|
2018
2158
|
className: 'dsh-powerup-update-select-trigger',
|
|
2019
2159
|
'aria-haspopup': 'listbox',
|
|
2020
2160
|
'aria-expanded': view.registryOpen === true ? 'true' : 'false',
|
|
2021
|
-
onClick:
|
|
2161
|
+
onClick: toggleRegistry,
|
|
2022
2162
|
},
|
|
2023
2163
|
h('span', { className: 'dsh-powerup-update-select-value' }, currentChoice?.label ?? ''),
|
|
2024
2164
|
h('span', { className: 'dsh-powerup-update-select-host' }, currentChoice?.hint ?? ''),
|
|
2025
2165
|
h('span', { className: 'chevron' }, h(ChevronDownIcon, { size: 12 })),
|
|
2026
2166
|
),
|
|
2027
|
-
view.registryOpen === true ? h('div', { className: 'dsh-powerup-update-select-menu', role: 'listbox', 'aria-label': t('update.registry') },
|
|
2028
|
-
view.choices.map((choice) => h('button', {
|
|
2029
|
-
key: choice.key,
|
|
2030
|
-
type: 'button',
|
|
2031
|
-
role: 'option',
|
|
2032
|
-
className: 'dsh-powerup-update-option',
|
|
2033
|
-
'aria-selected': choice.key === view.registryKey ? 'true' : 'false',
|
|
2034
|
-
onClick: () => chooseRegistry(choice.key),
|
|
2035
|
-
},
|
|
2036
|
-
h('span', { className: 'dsh-powerup-update-option-copy' },
|
|
2037
|
-
h('span', { className: 'dsh-powerup-update-option-title' }, choice.label),
|
|
2038
|
-
h('span', { className: 'dsh-powerup-update-option-host' }, choice.hint),
|
|
2039
|
-
),
|
|
2040
|
-
choice.key === view.registryKey ? h('span', { className: 'dsh-powerup-update-check' }, h(CheckIcon, { size: 13 })) : null,
|
|
2041
|
-
))) : null,
|
|
2042
2167
|
),
|
|
2043
2168
|
view.versionsRegistry === null || view.versionsRegistry === undefined
|
|
2044
2169
|
? null
|
|
@@ -2121,28 +2246,64 @@
|
|
|
2121
2246
|
return null;
|
|
2122
2247
|
})();
|
|
2123
2248
|
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2249
|
+
const fallbackPopover = { left: 24, top: 120, width: 320, maxHeight: 260 };
|
|
2250
|
+
|
|
2251
|
+
return h(React.Fragment, null,
|
|
2252
|
+
h('div', {
|
|
2253
|
+
className: 'dsh-powerup-update-mask',
|
|
2254
|
+
onMouseDown: (event) => {
|
|
2255
|
+
if (event.target === event.currentTarget) close();
|
|
2256
|
+
},
|
|
2128
2257
|
},
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2258
|
+
h('div', {
|
|
2259
|
+
className: 'dsh-powerup-update-dialog',
|
|
2260
|
+
role: 'dialog',
|
|
2261
|
+
'aria-modal': 'true',
|
|
2262
|
+
'aria-labelledby': 'dsh-powerup-update-title',
|
|
2263
|
+
},
|
|
2264
|
+
h('div', { className: 'dsh-powerup-update-head' },
|
|
2265
|
+
h('div', { className: 'dsh-powerup-update-heading' },
|
|
2266
|
+
h('h2', { id: 'dsh-powerup-update-title' }, t('update.title')),
|
|
2267
|
+
h('p', { title }, title),
|
|
2268
|
+
),
|
|
2269
|
+
canClose ? h('button', { type: 'button', className: 'dsh-powerup-update-close', 'aria-label': t('update.close'), onClick: close }, '×') : null,
|
|
2140
2270
|
),
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2271
|
+
h('div', { className: 'dsh-powerup-update-body' }, body),
|
|
2272
|
+
footer.length === 0 ? null : h('div', { className: 'dsh-powerup-update-foot' }, footer),
|
|
2273
|
+
),
|
|
2274
|
+
),
|
|
2275
|
+
view.listOpen === true
|
|
2276
|
+
? h('div', {
|
|
2277
|
+
id: 'dsh-powerup-update-versions',
|
|
2278
|
+
ref: versionPanelRef,
|
|
2279
|
+
className: 'dsh-powerup-update-popover dsh-powerup-update-list',
|
|
2280
|
+
role: 'listbox',
|
|
2281
|
+
'aria-label': t('update.versionLabel'),
|
|
2282
|
+
style: view.listPopover ?? fallbackPopover,
|
|
2283
|
+
}, versionRows)
|
|
2284
|
+
: null,
|
|
2285
|
+
view.registryOpen === true
|
|
2286
|
+
? h('div', {
|
|
2287
|
+
ref: registryPanelRef,
|
|
2288
|
+
className: 'dsh-powerup-update-popover dsh-powerup-update-select-menu',
|
|
2289
|
+
role: 'listbox',
|
|
2290
|
+
'aria-label': t('update.registry'),
|
|
2291
|
+
style: view.registryPopover ?? fallbackPopover,
|
|
2292
|
+
}, view.choices.map((choice) => h('button', {
|
|
2293
|
+
key: choice.key,
|
|
2294
|
+
type: 'button',
|
|
2295
|
+
role: 'option',
|
|
2296
|
+
className: 'dsh-powerup-update-option',
|
|
2297
|
+
'aria-selected': choice.key === view.registryKey ? 'true' : 'false',
|
|
2298
|
+
onClick: () => chooseRegistry(choice.key),
|
|
2299
|
+
},
|
|
2300
|
+
h('span', { className: 'dsh-powerup-update-option-copy' },
|
|
2301
|
+
h('span', { className: 'dsh-powerup-update-option-title' }, choice.label),
|
|
2302
|
+
h('span', { className: 'dsh-powerup-update-option-host' }, choice.hint),
|
|
2303
|
+
),
|
|
2304
|
+
choice.key === view.registryKey ? h('span', { className: 'dsh-powerup-update-check' }, h(CheckIcon, { size: 13 })) : null,
|
|
2305
|
+
)))
|
|
2306
|
+
: null,
|
|
2146
2307
|
);
|
|
2147
2308
|
}
|
|
2148
2309
|
|
|
@@ -2517,6 +2678,7 @@
|
|
|
2517
2678
|
PluginUpdateOverlay,
|
|
2518
2679
|
ensureUpdateButtons,
|
|
2519
2680
|
updateButtonLabel,
|
|
2681
|
+
popoverPlacement,
|
|
2520
2682
|
rowKeyParts,
|
|
2521
2683
|
resolveForkSeq,
|
|
2522
2684
|
markdownQuote,
|
|
@@ -2524,6 +2686,7 @@
|
|
|
2524
2686
|
buildRowItems,
|
|
2525
2687
|
buildSessionItems,
|
|
2526
2688
|
sortVersions,
|
|
2689
|
+
versionTagKind,
|
|
2527
2690
|
compareVersionsDesc,
|
|
2528
2691
|
buildRegistryChoices,
|
|
2529
2692
|
pickRegistryChoice,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@restregular/dsh-powerup",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Power-Up — small, opt-in upgrades for DeepSeek Harness. Adds a right-click action menu to the Trajectory ledger and an update control for third-party plugins installed from the Plugins page, with version lookup, uninstall-and-reinstall through the Add plugin path, and an optional DSH restart. · 为 DeepSeek Harness 提供小型增强:在轨迹页面右键记录即可复制、引用、查看详情或从该记录 Fork;并在插件页为第三方已安装插件提供带版本查询的更新按钮,沿用「添加插件」的安装流程,并可重启 DSH 使更改生效。",
|
|
5
5
|
"icon": "./icon.svg",
|
|
6
6
|
"type": "module",
|