dsh-plugin-pack 1.0.13 → 1.0.14
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/client.js +157 -70
- package/package.json +1 -1
package/client.js
CHANGED
|
@@ -187,6 +187,9 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
|
|
|
187
187
|
'jobs.failed': '失败',
|
|
188
188
|
'jobs.clear': '清空已完成',
|
|
189
189
|
'conflict.title': '这些插件已经装过了',
|
|
190
|
+
'conflict.titleNew': '确认导入',
|
|
191
|
+
'conflict.subtitleAll': '个插件待安装',
|
|
192
|
+
'conflict.create': '新建',
|
|
190
193
|
'conflict.subtitle': '个插件与已安装的重名,请选择如何处理:',
|
|
191
194
|
'conflict.overwrite': '覆盖',
|
|
192
195
|
'conflict.skip': '跳过',
|
|
@@ -380,6 +383,9 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
|
|
|
380
383
|
'jobs.failed': 'Failed',
|
|
381
384
|
'jobs.clear': 'Clear finished',
|
|
382
385
|
'conflict.title': 'These plugins are already installed',
|
|
386
|
+
'conflict.titleNew': 'Confirm import',
|
|
387
|
+
'conflict.subtitleAll': 'plugins to install',
|
|
388
|
+
'conflict.create': 'New',
|
|
383
389
|
'conflict.subtitle': 'plugins already exist. Choose what to do:',
|
|
384
390
|
'conflict.overwrite': 'Overwrite',
|
|
385
391
|
'conflict.skip': 'Skip',
|
|
@@ -546,8 +552,9 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
|
|
|
546
552
|
|
|
547
553
|
/* 安装偏好:由界面上的「安装后立即启用」勾选同步过来。
|
|
548
554
|
* 放这里是因为 doImport 在接口层、拿不到组件 state;
|
|
549
|
-
* 用一个普通对象透传,避免把选项硬编码进每个调用点。
|
|
550
|
-
|
|
555
|
+
* 用一个普通对象透传,避免把选项硬编码进每个调用点。
|
|
556
|
+
* 默认 false:装完先不启用,由用户自己决定(更安全,也避免"装了没用的插件"). */
|
|
557
|
+
const installPrefs = { enable: false };
|
|
551
558
|
|
|
552
559
|
const getStatus = () => api('/plugin-pack/status');
|
|
553
560
|
const doExport = (body) => api('/plugin-pack/export', { method: 'POST', body: JSON.stringify(body) });
|
|
@@ -1553,7 +1560,7 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
|
|
|
1553
1560
|
},
|
|
1554
1561
|
h('input', {
|
|
1555
1562
|
type: 'checkbox',
|
|
1556
|
-
checked: enableOnInstall
|
|
1563
|
+
checked: Boolean(enableOnInstall),
|
|
1557
1564
|
disabled: busy,
|
|
1558
1565
|
onChange: (event) => onToggleEnable?.(event.target.checked),
|
|
1559
1566
|
}),
|
|
@@ -1576,10 +1583,18 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
|
|
|
1576
1583
|
}
|
|
1577
1584
|
|
|
1578
1585
|
function ConflictDialog({ pending, onConfirm, onCancel, t }) {
|
|
1586
|
+
/**
|
|
1587
|
+
* 弹窗列的是包里的**所有**插件,不只是重名的。
|
|
1588
|
+
* - 重名的(exists=true)→ 可选「覆盖 / 跳过」
|
|
1589
|
+
* - 新的(exists=false) → 标「新建」,没有二选一
|
|
1590
|
+
* 这样用户在真正写盘之前,能看清这次到底要装什么。
|
|
1591
|
+
*/
|
|
1579
1592
|
const conflicts = pending?.conflicts ?? [];
|
|
1593
|
+
const rows = pending?.rows ?? conflicts;
|
|
1594
|
+
const existing = rows.filter((item) => item.exists);
|
|
1580
1595
|
/** 初始全部选「覆盖」——多数人是想升级到新版本。 */
|
|
1581
1596
|
const [decisions, setDecisions] = useState(() =>
|
|
1582
|
-
Object.fromEntries(
|
|
1597
|
+
Object.fromEntries(existing.map((item) => [item.name, 'overwrite'])),
|
|
1583
1598
|
);
|
|
1584
1599
|
|
|
1585
1600
|
// 弹窗打开时挂 Esc
|
|
@@ -1593,9 +1608,10 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
|
|
|
1593
1608
|
|
|
1594
1609
|
if (!pending) return null;
|
|
1595
1610
|
|
|
1596
|
-
const setAll = (value) => setDecisions(Object.fromEntries(
|
|
1611
|
+
const setAll = (value) => setDecisions(Object.fromEntries(existing.map((item) => [item.name, value])));
|
|
1597
1612
|
const overwriteCount = Object.values(decisions).filter((v) => v === 'overwrite').length;
|
|
1598
1613
|
const skipCount = Object.values(decisions).filter((v) => v === 'skip').length;
|
|
1614
|
+
const createCount = rows.length - existing.length;
|
|
1599
1615
|
|
|
1600
1616
|
return h(
|
|
1601
1617
|
'div',
|
|
@@ -1632,30 +1648,38 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
|
|
|
1632
1648
|
h(
|
|
1633
1649
|
'div',
|
|
1634
1650
|
{ style: { padding: '12px 16px', borderBottom: '.5px solid var(--dsw-alias-border-l1,#eee)' } },
|
|
1635
|
-
h('b', { style: { fontSize: 14, fontWeight: 600, display: 'block', marginBottom: 4 } }, t('conflict.title')),
|
|
1636
1651
|
h(
|
|
1637
|
-
'
|
|
1638
|
-
{
|
|
1639
|
-
|
|
1652
|
+
'b',
|
|
1653
|
+
{ style: { fontSize: 14, fontWeight: 600, display: 'block', marginBottom: 4 } },
|
|
1654
|
+
existing.length ? t('conflict.title') : t('conflict.titleNew'),
|
|
1640
1655
|
),
|
|
1641
|
-
),
|
|
1642
|
-
// 一键按钮
|
|
1643
|
-
h(
|
|
1644
|
-
'div',
|
|
1645
|
-
{ className: 'pp-bar', style: { padding: '10px 16px 0', marginBottom: 0 } },
|
|
1646
|
-
h('button', { className: 'pp-btn sm', onClick: () => setAll('overwrite') }, t('conflict.allOverwrite')),
|
|
1647
|
-
h('button', { className: 'pp-btn sm', onClick: () => setAll('skip') }, t('conflict.allSkip')),
|
|
1648
1656
|
h(
|
|
1649
1657
|
'span',
|
|
1650
|
-
{ className: 'pp-hint'
|
|
1651
|
-
|
|
1658
|
+
{ className: 'pp-hint' },
|
|
1659
|
+
existing.length
|
|
1660
|
+
? `${rows.length} ${t('conflict.subtitleAll')} · ${existing.length} ${t('conflict.subtitle')}`
|
|
1661
|
+
: `${rows.length} ${t('conflict.subtitleAll')}`,
|
|
1652
1662
|
),
|
|
1653
1663
|
),
|
|
1654
|
-
//
|
|
1664
|
+
// 一键按钮(只有存在重名时才有意义)
|
|
1665
|
+
existing.length
|
|
1666
|
+
? h(
|
|
1667
|
+
'div',
|
|
1668
|
+
{ className: 'pp-bar', style: { padding: '10px 16px 0', marginBottom: 0 } },
|
|
1669
|
+
h('button', { className: 'pp-btn sm', onClick: () => setAll('overwrite') }, t('conflict.allOverwrite')),
|
|
1670
|
+
h('button', { className: 'pp-btn sm', onClick: () => setAll('skip') }, t('conflict.allSkip')),
|
|
1671
|
+
h(
|
|
1672
|
+
'span',
|
|
1673
|
+
{ className: 'pp-hint', style: { marginLeft: 'auto' } },
|
|
1674
|
+
`${t('conflict.overwrite')} ${overwriteCount} · ${t('conflict.skip')} ${skipCount}`,
|
|
1675
|
+
),
|
|
1676
|
+
)
|
|
1677
|
+
: null,
|
|
1678
|
+
// 列表:全部插件
|
|
1655
1679
|
h(
|
|
1656
1680
|
'div',
|
|
1657
1681
|
{ style: { flex: 1, minHeight: 120, overflow: 'auto', padding: '8px 16px' } },
|
|
1658
|
-
|
|
1682
|
+
rows.map((item) =>
|
|
1659
1683
|
h(
|
|
1660
1684
|
'div',
|
|
1661
1685
|
{
|
|
@@ -1670,34 +1694,49 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
|
|
|
1670
1694
|
'div',
|
|
1671
1695
|
{ className: 'pp-name' },
|
|
1672
1696
|
item.name,
|
|
1673
|
-
item.installedVersion
|
|
1697
|
+
item.exists && item.installedVersion
|
|
1674
1698
|
? h('span', { className: 'pp-ver' }, `${item.installedVersion} → ${item.version}`)
|
|
1675
1699
|
: h('span', { className: 'pp-ver' }, item.version),
|
|
1676
|
-
item.
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
),
|
|
1680
|
-
// 每个插件单独选
|
|
1681
|
-
h(
|
|
1682
|
-
'div',
|
|
1683
|
-
{ style: { display: 'flex', gap: 4, flex: 'none' } },
|
|
1684
|
-
h(
|
|
1685
|
-
'button',
|
|
1686
|
-
{
|
|
1687
|
-
className: `pp-btn sm${decisions[item.name] === 'overwrite' ? ' primary' : ''}`,
|
|
1688
|
-
onClick: () => setDecisions((prev) => ({ ...prev, [item.name]: 'overwrite' })),
|
|
1689
|
-
},
|
|
1690
|
-
t('conflict.overwrite'),
|
|
1691
|
-
),
|
|
1692
|
-
h(
|
|
1693
|
-
'button',
|
|
1694
|
-
{
|
|
1695
|
-
className: `pp-btn sm${decisions[item.name] === 'skip' ? ' primary' : ''}`,
|
|
1696
|
-
onClick: () => setDecisions((prev) => ({ ...prev, [item.name]: 'skip' })),
|
|
1697
|
-
},
|
|
1698
|
-
t('conflict.skip'),
|
|
1700
|
+
item.exists && item.sameVersion
|
|
1701
|
+
? h('span', { className: 'pp-ver' }, t('conflict.sameVersion'))
|
|
1702
|
+
: null,
|
|
1699
1703
|
),
|
|
1704
|
+
item.dest ? h('div', { className: 'pp-meta pp-mono', style: { fontSize: 11 } }, item.dest) : null,
|
|
1700
1705
|
),
|
|
1706
|
+
// 重名的给二选一;新的只标「新建」
|
|
1707
|
+
item.exists
|
|
1708
|
+
? h(
|
|
1709
|
+
'div',
|
|
1710
|
+
{ style: { display: 'flex', gap: 4, flex: 'none' } },
|
|
1711
|
+
h(
|
|
1712
|
+
'button',
|
|
1713
|
+
{
|
|
1714
|
+
className: `pp-btn sm${decisions[item.name] === 'overwrite' ? ' primary' : ''}`,
|
|
1715
|
+
onClick: () => setDecisions((prev) => ({ ...prev, [item.name]: 'overwrite' })),
|
|
1716
|
+
},
|
|
1717
|
+
t('conflict.overwrite'),
|
|
1718
|
+
),
|
|
1719
|
+
h(
|
|
1720
|
+
'button',
|
|
1721
|
+
{
|
|
1722
|
+
className: `pp-btn sm${decisions[item.name] === 'skip' ? ' primary' : ''}`,
|
|
1723
|
+
onClick: () => setDecisions((prev) => ({ ...prev, [item.name]: 'skip' })),
|
|
1724
|
+
},
|
|
1725
|
+
t('conflict.skip'),
|
|
1726
|
+
),
|
|
1727
|
+
)
|
|
1728
|
+
: h(
|
|
1729
|
+
'span',
|
|
1730
|
+
{
|
|
1731
|
+
className: 'pp-pill',
|
|
1732
|
+
style: {
|
|
1733
|
+
flex: 'none',
|
|
1734
|
+
background: 'color-mix(in srgb,var(--dsw-alias-state-success-primary,#16a34a) 14%,transparent)',
|
|
1735
|
+
color: 'var(--dsw-alias-state-success-primary,#15803d)',
|
|
1736
|
+
},
|
|
1737
|
+
},
|
|
1738
|
+
t('conflict.create'),
|
|
1739
|
+
),
|
|
1701
1740
|
),
|
|
1702
1741
|
),
|
|
1703
1742
|
),
|
|
@@ -1710,9 +1749,16 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
|
|
|
1710
1749
|
borderTop: '.5px solid var(--dsw-alias-border-l1,#eee)',
|
|
1711
1750
|
display: 'flex',
|
|
1712
1751
|
gap: 8,
|
|
1713
|
-
|
|
1752
|
+
alignItems: 'center',
|
|
1714
1753
|
},
|
|
1715
1754
|
},
|
|
1755
|
+
h(
|
|
1756
|
+
'span',
|
|
1757
|
+
{ className: 'pp-hint', style: { flex: 1 } },
|
|
1758
|
+
existing.length
|
|
1759
|
+
? `${t('conflict.overwrite')} ${overwriteCount} · ${t('conflict.skip')} ${skipCount} · ${t('conflict.create')} ${createCount}`
|
|
1760
|
+
: `${t('conflict.create')} ${createCount}`,
|
|
1761
|
+
),
|
|
1716
1762
|
h('button', { className: 'pp-btn', onClick: onCancel }, t('conflict.cancel')),
|
|
1717
1763
|
h(
|
|
1718
1764
|
'button',
|
|
@@ -1901,8 +1947,8 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
|
|
|
1901
1947
|
const [netResult, setNetResult] = useState(null);
|
|
1902
1948
|
/** 「添加整合包」弹窗是否打开。 */
|
|
1903
1949
|
const [netOpen, setNetOpen] = useState(false);
|
|
1904
|
-
/**
|
|
1905
|
-
const [enableOnInstall, setEnableOnInstall] = useState(
|
|
1950
|
+
/** 安装后是否立即启用(勾选框)。默认关:先装上,用户想用再启用。 */
|
|
1951
|
+
const [enableOnInstall, setEnableOnInstall] = useState(false);
|
|
1906
1952
|
/** 刚装完的插件及其启用状态,用于装完后再切换。 */
|
|
1907
1953
|
const [enablePrompt, setEnablePrompt] = useState(null);
|
|
1908
1954
|
/** 后台任务列表:切走画面回来靠它恢复 */
|
|
@@ -2151,21 +2197,35 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
|
|
|
2151
2197
|
return;
|
|
2152
2198
|
}
|
|
2153
2199
|
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2200
|
+
/* 不管有没有重名,都在写盘之前弹一次确认框,列出包里所有插件:
|
|
2201
|
+
* - 重名的 → 覆盖 / 跳过
|
|
2202
|
+
* - 新的 → 标「新建」
|
|
2203
|
+
* 这时文件还没上传,取消就什么都不发生。 */
|
|
2204
|
+
const rows = packPlugins.map((plugin) => {
|
|
2205
|
+
const hit = installed.get(plugin.name);
|
|
2206
|
+
return {
|
|
2207
|
+
name: plugin.name,
|
|
2208
|
+
version: plugin.version ?? null,
|
|
2209
|
+
installedVersion: hit?.version ?? null,
|
|
2210
|
+
dest: hit?.dir ?? null,
|
|
2211
|
+
bytes: plugin.bytes ?? null,
|
|
2212
|
+
sameVersion: (hit?.version ?? null) === (plugin.version ?? null),
|
|
2213
|
+
exists: Boolean(hit),
|
|
2214
|
+
};
|
|
2215
|
+
});
|
|
2216
|
+
|
|
2217
|
+
setPendingImport({
|
|
2218
|
+
kind: 'bundle',
|
|
2219
|
+
pendingFile: file, // 还没上传,先拿着 File 对象
|
|
2220
|
+
file: null,
|
|
2221
|
+
conflicts: rows.filter((row) => row.exists),
|
|
2222
|
+
rows,
|
|
2223
|
+
plugins: packPlugins,
|
|
2224
|
+
quick: true,
|
|
2225
|
+
});
|
|
2226
|
+
setBusy(false);
|
|
2227
|
+
setPhase('');
|
|
2228
|
+
return;
|
|
2169
2229
|
}
|
|
2170
2230
|
|
|
2171
2231
|
// 第二步:确认无冲突(或拿不到快速清单)才上传
|
|
@@ -2173,18 +2233,32 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
|
|
|
2173
2233
|
const uploaded = await uploadZip(file);
|
|
2174
2234
|
setZipPath(uploaded.file);
|
|
2175
2235
|
|
|
2176
|
-
// 先 dryRun
|
|
2236
|
+
// 先 dryRun 探一次:拿到完整插件清单,写盘前弹确认
|
|
2177
2237
|
setPhase(t('import.checking'));
|
|
2178
2238
|
const preview = await doImport({ file: uploaded.file, dryRun: true });
|
|
2179
2239
|
const conflicts = Array.isArray(preview?.conflicts) ? preview.conflicts : [];
|
|
2180
|
-
|
|
2181
|
-
|
|
2240
|
+
const conflictByName = new Map(conflicts.map((item) => [item.name, item]));
|
|
2241
|
+
const previewRows = (preview?.plugins ?? []).map((plugin) => {
|
|
2242
|
+
const hit = conflictByName.get(plugin.name);
|
|
2243
|
+
return {
|
|
2244
|
+
name: plugin.name,
|
|
2245
|
+
version: plugin.version ?? null,
|
|
2246
|
+
installedVersion: hit?.installedVersion ?? null,
|
|
2247
|
+
dest: hit?.dest ?? null,
|
|
2248
|
+
sameVersion: Boolean(hit?.sameVersion),
|
|
2249
|
+
exists: Boolean(hit),
|
|
2250
|
+
};
|
|
2251
|
+
});
|
|
2252
|
+
|
|
2253
|
+
if (previewRows.length) {
|
|
2254
|
+
// 服务端在 dryRun 时已登记了"待决策"任务(仅当有重名),带 jobId 回来
|
|
2182
2255
|
pendingJobId.current = preview?.jobId ?? null;
|
|
2183
2256
|
setPendingImport({
|
|
2184
2257
|
kind: 'bundle',
|
|
2185
2258
|
jobId: preview?.jobId ?? null,
|
|
2186
2259
|
file: uploaded.file,
|
|
2187
2260
|
conflicts,
|
|
2261
|
+
rows: previewRows,
|
|
2188
2262
|
plugins: preview.plugins ?? [],
|
|
2189
2263
|
});
|
|
2190
2264
|
setBusy(false);
|
|
@@ -2279,19 +2353,32 @@ window.__ModuleLoader__.load({ id: 'dsh-plugin-pack', factory: (require) => {
|
|
|
2279
2353
|
return;
|
|
2280
2354
|
}
|
|
2281
2355
|
|
|
2282
|
-
//
|
|
2356
|
+
// 下载好的包:先 dryRun 拿完整清单,写盘前弹确认
|
|
2283
2357
|
const preview = await doImport({ file: fetched.file, dryRun: true });
|
|
2284
|
-
const
|
|
2285
|
-
|
|
2358
|
+
const netConflicts = Array.isArray(preview?.conflicts) ? preview.conflicts : [];
|
|
2359
|
+
const netConflictByName = new Map(netConflicts.map((item) => [item.name, item]));
|
|
2360
|
+
const netRows = (preview?.plugins ?? []).map((plugin) => {
|
|
2361
|
+
const hit = netConflictByName.get(plugin.name);
|
|
2362
|
+
return {
|
|
2363
|
+
name: plugin.name,
|
|
2364
|
+
version: plugin.version ?? null,
|
|
2365
|
+
installedVersion: hit?.installedVersion ?? null,
|
|
2366
|
+
dest: hit?.dest ?? null,
|
|
2367
|
+
sameVersion: Boolean(hit?.sameVersion),
|
|
2368
|
+
exists: Boolean(hit),
|
|
2369
|
+
};
|
|
2370
|
+
});
|
|
2371
|
+
if (netRows.length) {
|
|
2286
2372
|
pendingJobId.current = preview?.jobId ?? null;
|
|
2287
2373
|
setPendingImport({
|
|
2288
2374
|
kind: 'bundle',
|
|
2289
2375
|
jobId: preview?.jobId ?? null,
|
|
2290
2376
|
file: fetched.file,
|
|
2291
|
-
conflicts,
|
|
2377
|
+
conflicts: netConflicts,
|
|
2378
|
+
rows: netRows,
|
|
2292
2379
|
plugins: preview.plugins ?? [],
|
|
2293
2380
|
});
|
|
2294
|
-
//
|
|
2381
|
+
// 交给确认弹窗接管,先关掉来源弹窗
|
|
2295
2382
|
setNetOpen(false);
|
|
2296
2383
|
return;
|
|
2297
2384
|
}
|
package/package.json
CHANGED