dsh-m 0.1.1 → 0.2.0
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.en.md +25 -10
- package/README.md +25 -10
- package/docs/DESIGN.md +172 -0
- package/lib/cli.js +134 -63
- package/lib/client.js +778 -114
- package/lib/core/host-api.js +285 -0
- package/lib/core/httpx.js +93 -36
- package/lib/core/market.js +477 -105
- package/lib/core/npm-integrity.js +141 -0
- package/lib/core/registry-check.js +111 -0
- package/lib/core/registry-controller.js +321 -0
- package/lib/core/registry.js +634 -100
- package/lib/core/versions.js +66 -23
- package/lib/host.js +22 -173
- package/lib/tools.js +54 -40
- package/package.json +3 -2
- package/registry.json +29 -7
- package/DESIGN.md +0 -140
package/lib/client.js
CHANGED
|
@@ -2,14 +2,124 @@ window.__ModuleLoader__.load({
|
|
|
2
2
|
id: "dsh-m",
|
|
3
3
|
factory: (require) => {
|
|
4
4
|
"use strict";
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
16
|
+
var __copyProps = (to, from, except, desc) => {
|
|
17
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
18
|
+
for (let key of __getOwnPropNames(from))
|
|
19
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
20
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
21
|
+
}
|
|
22
|
+
return to;
|
|
23
|
+
};
|
|
24
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
25
|
+
|
|
26
|
+
// src/client/market-state.js
|
|
27
|
+
var market_state_exports = {};
|
|
28
|
+
__export(market_state_exports, {
|
|
29
|
+
MARKET_PAGE_SIZE: () => MARKET_PAGE_SIZE,
|
|
30
|
+
normalizeMarketQuery: () => normalizeMarketQuery,
|
|
31
|
+
normalizeMarketResponse: () => normalizeMarketResponse,
|
|
32
|
+
registryNotice: () => registryNotice,
|
|
33
|
+
resetPageOnFilterChange: () => resetPageOnFilterChange
|
|
34
|
+
});
|
|
35
|
+
function toSafeInt(value, fallback, min, max) {
|
|
36
|
+
const n = typeof value === "number" && Number.isFinite(value) ? Math.floor(value) : fallback;
|
|
37
|
+
if (min !== void 0 && n < min) return min;
|
|
38
|
+
if (max !== void 0 && n > max) return max;
|
|
39
|
+
return n;
|
|
40
|
+
}
|
|
41
|
+
function normalizeMarketQuery(input) {
|
|
42
|
+
const raw = input && typeof input === "object" ? input : {};
|
|
43
|
+
const query = typeof raw.query === "string" ? raw.query.trim() : "";
|
|
44
|
+
const category = typeof raw.category === "string" && CATEGORIES.includes(raw.category) ? raw.category : null;
|
|
45
|
+
const offset = toSafeInt(raw.offset, 0, 0);
|
|
46
|
+
const limit = toSafeInt(raw.limit, MARKET_PAGE_SIZE, 1, MARKET_PAGE_SIZE);
|
|
47
|
+
return { query, category, offset, limit };
|
|
48
|
+
}
|
|
49
|
+
function resetPageOnFilterChange(previous, next) {
|
|
50
|
+
const prev = previous && typeof previous === "object" ? previous : {};
|
|
51
|
+
const merged = { ...next };
|
|
52
|
+
if (prev.query !== next.query || prev.category !== next.category) {
|
|
53
|
+
merged.offset = 0;
|
|
54
|
+
}
|
|
55
|
+
return merged;
|
|
56
|
+
}
|
|
57
|
+
function normalizeMarketResponse(raw) {
|
|
58
|
+
const body = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
|
|
59
|
+
const items = Array.isArray(body.items) ? body.items.filter((it) => it && typeof it === "object") : [];
|
|
60
|
+
const total = toSafeInt(body.total, items.length, 0);
|
|
61
|
+
const offset = toSafeInt(body.offset, 0, 0);
|
|
62
|
+
const limit = toSafeInt(body.limit, MARKET_PAGE_SIZE, 1);
|
|
63
|
+
let categoryCounts = {};
|
|
64
|
+
if (body.categoryCounts && typeof body.categoryCounts === "object" && !Array.isArray(body.categoryCounts)) {
|
|
65
|
+
for (const [key, value] of Object.entries(body.categoryCounts)) {
|
|
66
|
+
if (typeof value === "number" && Number.isFinite(value)) categoryCounts[key] = value;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const rs = body.registryState && typeof body.registryState === "object" && !Array.isArray(body.registryState) ? body.registryState : {};
|
|
70
|
+
const registryState = {
|
|
71
|
+
...FALLBACK_REGISTRY_STATE,
|
|
72
|
+
...rs,
|
|
73
|
+
errors: Array.isArray(rs.errors) ? rs.errors.map(String) : []
|
|
74
|
+
};
|
|
75
|
+
return {
|
|
76
|
+
items,
|
|
77
|
+
total,
|
|
78
|
+
offset,
|
|
79
|
+
limit,
|
|
80
|
+
categoryCounts,
|
|
81
|
+
registryState,
|
|
82
|
+
installedComplete: body.installedComplete === true,
|
|
83
|
+
latestComplete: body.latestComplete === true,
|
|
84
|
+
latestTimedOut: body.latestTimedOut === true
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function registryNotice(summary, total) {
|
|
88
|
+
const s = summary && typeof summary === "object" ? summary : {};
|
|
89
|
+
let key = "notice.default";
|
|
90
|
+
if (s.status === "unavailable") key = "notice.unavailable";
|
|
91
|
+
else if (s.stale || s.status === "stale") key = "notice.stale";
|
|
92
|
+
else if (!s.isDefault) key = "notice.custom";
|
|
93
|
+
return { key, count: typeof total === "number" && Number.isFinite(total) ? total : 0 };
|
|
94
|
+
}
|
|
95
|
+
var MARKET_PAGE_SIZE, CATEGORIES, FALLBACK_REGISTRY_STATE;
|
|
96
|
+
var init_market_state = __esm({
|
|
97
|
+
"src/client/market-state.js"() {
|
|
98
|
+
"use strict";
|
|
99
|
+
MARKET_PAGE_SIZE = 50;
|
|
100
|
+
CATEGORIES = ["market", "tools", "ui", "search", "media", "other"];
|
|
101
|
+
FALLBACK_REGISTRY_STATE = {
|
|
102
|
+
configuredAddress: "",
|
|
103
|
+
activeAddress: null,
|
|
104
|
+
source: "bundled",
|
|
105
|
+
status: "unavailable",
|
|
106
|
+
isDefault: true,
|
|
107
|
+
stale: false,
|
|
108
|
+
fetchedAt: null,
|
|
109
|
+
errors: [],
|
|
110
|
+
count: 0
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
});
|
|
5
114
|
|
|
6
115
|
// src/client/main.jsx
|
|
7
116
|
var React = require("react");
|
|
8
117
|
var rd = require("react-dom");
|
|
9
118
|
var h = React.createElement;
|
|
10
|
-
var { useState, useEffect, useCallback, useMemo } = React;
|
|
119
|
+
var { useState, useEffect, useCallback, useMemo, useRef } = React;
|
|
11
120
|
var PLUGIN_ID = "dsh-m";
|
|
12
121
|
var API = "/dshm";
|
|
122
|
+
var { MARKET_PAGE_SIZE: MARKET_PAGE_SIZE2, normalizeMarketQuery: normalizeMarketQuery2, resetPageOnFilterChange: resetPageOnFilterChange2, normalizeMarketResponse: normalizeMarketResponse2, registryNotice: registryNotice2 } = (init_market_state(), __toCommonJS(market_state_exports));
|
|
13
123
|
var ZH = {
|
|
14
124
|
"market.title": "\u63D2\u4EF6\u5E02\u573A",
|
|
15
125
|
"tab.market": "\u5E02\u573A",
|
|
@@ -38,6 +148,7 @@ var ZH = {
|
|
|
38
148
|
"badge.update": "\u53EF\u5347\u7EA7",
|
|
39
149
|
"badge.market": "\u5E02\u573A\u5B89\u88C5",
|
|
40
150
|
"badge.nonmarket": "\u975E\u5E02\u573A\u5B89\u88C5",
|
|
151
|
+
"badge.custom": "\u81EA\u5B9A\u4E49",
|
|
41
152
|
"action.install": "\u5B89\u88C5",
|
|
42
153
|
"action.upgrade": "\u5347\u7EA7",
|
|
43
154
|
"action.uninstall": "\u5378\u8F7D",
|
|
@@ -55,6 +166,8 @@ var ZH = {
|
|
|
55
166
|
"detail.listed.no": "\u4E0D\u5728\u6536\u5F55\u6E05\u5355\u4E2D",
|
|
56
167
|
"detail.path": "\u8DEF\u5F84",
|
|
57
168
|
"detail.note": "\u6CE8\u610F",
|
|
169
|
+
"detail.links": "\u8BE6\u60C5",
|
|
170
|
+
"link.home": "\u5B98\u7F51",
|
|
58
171
|
"manage.hint": "\u5DF2\u5B89\u88C5\uFF0C\u53EF\u5728\u300C\u5DF2\u88C5\u300D\u9875\u7BA1\u7406",
|
|
59
172
|
"version.failed": "\u7248\u672C\u67E5\u8BE2\u5931\u8D25",
|
|
60
173
|
"src.npm": "npm",
|
|
@@ -81,12 +194,59 @@ var ZH = {
|
|
|
81
194
|
"settings.upgradeself": "\u5347\u7EA7 dsh-m",
|
|
82
195
|
"settings.upgradehint": "\u5347\u7EA7\u540E\u540C\u6837\u9700\u8981\u91CD\u542F\u751F\u6548",
|
|
83
196
|
"settings.about": "\u5173\u4E8E",
|
|
84
|
-
"settings.about.text": "
|
|
197
|
+
"settings.about.text": "\u4E2A\u4EBA DSH \u63D2\u4EF6\u5E02\u573A\uFF1A\u6536\u5F55\u3001\u5B89\u88C5\u3001\u5378\u8F7D\u3001\u5347\u7EA7\u5168\u90E8\u672C\u673A\u5B8C\u6210\uFF1B\u6536\u5F55\u6E05\u5355\u652F\u6301\u81EA\u5B9A\u4E49\u8986\u76D6\uFF0C\u5E94\u7528\u5373\u65F6\u751F\u6548\u3002",
|
|
85
198
|
"src.override": "\u81EA\u5B9A\u4E49\u6E90",
|
|
86
199
|
"src.jsdelivr": "jsDelivr\uFF08@main\uFF09",
|
|
87
200
|
"src.raw": "raw.githubusercontent\uFF08@main\uFF09",
|
|
88
201
|
"src.cache": "\u672C\u5730\u7F13\u5B58",
|
|
89
202
|
"src.bundled": "\u5305\u5185\u5FEB\u7167\uFF08\u515C\u5E95\uFF09",
|
|
203
|
+
"src.default.raw": "raw.githubusercontent\uFF08@main\uFF09",
|
|
204
|
+
"src.default.jsdelivr": "jsDelivr\uFF08@main\uFF09",
|
|
205
|
+
"src.default.cache": "\u9ED8\u8BA4\u6E05\u5355\u7F13\u5B58",
|
|
206
|
+
"src.custom.url": "\u81EA\u5B9A\u4E49 URL \u6E90",
|
|
207
|
+
"src.custom.file": "\u672C\u5730\u6587\u4EF6\u6E90",
|
|
208
|
+
"src.custom.cache": "\u81EA\u5B9A\u4E49\u6E90\uFF08\u7F13\u5B58\uFF09",
|
|
209
|
+
"src.custom.unavailable": "\u81EA\u5B9A\u4E49\u6E90\uFF08\u4E0D\u53EF\u7528\uFF09",
|
|
210
|
+
"settings.address": "Registry \u5730\u5740",
|
|
211
|
+
"settings.address.hint": "\u7A7A = \u5B98\u65B9\u9ED8\u8BA4\u6E05\u5355\uFF1B\u652F\u6301 HTTPS URL \u6216\u672C\u673A\u7EDD\u5BF9\u8DEF\u5F84 / file://\u3002\u6574\u4F53\u8986\u76D6\u9ED8\u8BA4\u6E05\u5355\uFF0C\u4E0D\u505A\u5408\u5E76\u3002",
|
|
212
|
+
"settings.address.ph": "https://example.com/registry.json \u6216 /path/to/registry.json",
|
|
213
|
+
"settings.configured": "\u914D\u7F6E\u5730\u5740",
|
|
214
|
+
"settings.activecfg": "\u5F53\u524D\u751F\u6548\u914D\u7F6E",
|
|
215
|
+
"settings.effective": "\u751F\u6548\u6765\u6E90",
|
|
216
|
+
"settings.status.label": "\u914D\u7F6E\u72B6\u6001",
|
|
217
|
+
"settings.status.loading": "\u52A0\u8F7D\u4E2D",
|
|
218
|
+
"settings.status.ready": "\u5DF2\u751F\u6548",
|
|
219
|
+
"settings.status.pending": "\u5F85\u5199\u5165\uFF08\u6821\u9A8C\u5DF2\u901A\u8FC7\uFF09",
|
|
220
|
+
"settings.status.rejected": "\u5DF2\u62D2\u7EDD\uFF08\u4FDD\u6301\u65E7\u914D\u7F6E\uFF09",
|
|
221
|
+
"settings.status.unavailable": "\u4E0D\u53EF\u7528",
|
|
222
|
+
"settings.apply": "\u6821\u9A8C\u5E76\u5E94\u7528",
|
|
223
|
+
"settings.apply.applying": "\u6821\u9A8C\u4E2D\u2026",
|
|
224
|
+
"settings.apply.ok": "Registry \u5730\u5740\u5DF2\u751F\u6548\uFF08\u65E0\u9700\u91CD\u542F\uFF09",
|
|
225
|
+
"settings.apply.failed": "\u5E94\u7528\u5931\u8D25\uFF1A{err}",
|
|
226
|
+
"settings.reset": "\u6062\u590D\u9ED8\u8BA4",
|
|
227
|
+
"settings.reset.ok": "\u5DF2\u6062\u590D\u9ED8\u8BA4\u6536\u5F55\u6E05\u5355",
|
|
228
|
+
"settings.download": "\u4E0B\u8F7D\u9ED8\u8BA4 registry.json",
|
|
229
|
+
"settings.download.downloading": "\u4E0B\u8F7D\u4E2D\u2026",
|
|
230
|
+
"settings.download.ok": "\u9ED8\u8BA4\u6E05\u5355\u5DF2\u4E0B\u8F7D\uFF08\u5F53\u524D\u914D\u7F6E\u4E0D\u53D8\uFF09",
|
|
231
|
+
"settings.download.failed": "\u4E0B\u8F7D\u5931\u8D25\uFF1A{err}",
|
|
232
|
+
"settings.diagnose": "\u68C0\u67E5\u6761\u76EE\u53EF\u8FBE\u6027",
|
|
233
|
+
"settings.diagnose.running": "\u8BCA\u65AD\u4E2D\u2026",
|
|
234
|
+
"settings.diagnose.failed": "\u8BCA\u65AD\u5931\u8D25\uFF1A{err}",
|
|
235
|
+
"settings.diagnose.result": "\u63A2\u6D4B {checked} \u9879 \xB7 \u901A\u8FC7 {passed} \xB7 \u5931\u8D25 {failed}{trunc}",
|
|
236
|
+
"settings.diagnose.truncated": "\uFF08\u4EC5\u663E\u793A\u524D 100 \u6761\u95EE\u9898\uFF09",
|
|
237
|
+
"settings.diagnose.none": "\u672A\u53D1\u73B0\u95EE\u9898",
|
|
238
|
+
"settings.trust.hint": "\u26A0\uFE0F \u81EA\u5B9A\u4E49\u6536\u5F55\u6E05\u5355\u672A\u7ECF\u5B98\u65B9 CI \u6821\u9A8C\uFF0C\u6761\u76EE\u6765\u6E90\u8BF7\u786E\u8BA4\u53EF\u4FE1\u540E\u518D\u5B89\u88C5\u3002",
|
|
239
|
+
"settings.cache.hint": "\u5207\u6362\u540E\u65E7\u81EA\u5B9A\u4E49\u6E90\u7F13\u5B58\u5C06\u88AB\u6E05\u7406\uFF08\u9ED8\u8BA4\u7F13\u5B58\u4FDD\u7559\uFF09\uFF1B\u81EA\u5B9A\u4E49\u6E90\u5931\u8D25\u65F6\u4FDD\u7559\u5176\u6700\u8FD1\u4E00\u6B21\u6210\u529F\u7F13\u5B58\u3002",
|
|
240
|
+
"settings.warnings": "\u7EF4\u62A4\u63D0\u793A",
|
|
241
|
+
"notice.default": "\u5B98\u65B9\u9ED8\u8BA4\u6536\u5F55\u6E05\u5355 \xB7 \u5171 {count} \u6761",
|
|
242
|
+
"notice.custom": "\u81EA\u5B9A\u4E49\u6536\u5F55\u6E05\u5355 \xB7 \u5171 {count} \u6761",
|
|
243
|
+
"notice.stale": "\u6765\u6E90\u4E3A\u672C\u5730\u7F13\u5B58\uFF08\u5171 {count} \u6761\uFF09\uFF0C\u53EF\u7528\u300C\u5F3A\u5236\u5237\u65B0\u300D\u66F4\u65B0",
|
|
244
|
+
"notice.unavailable": "\u6536\u5F55\u6E05\u5355\u4E0D\u53EF\u7528 \xB7 \u8BF7\u5230\u8BBE\u7F6E\u9875\u68C0\u67E5\u5730\u5740",
|
|
245
|
+
"market.page.prev": "\u4E0A\u4E00\u9875",
|
|
246
|
+
"market.page.next": "\u4E0B\u4E00\u9875",
|
|
247
|
+
"market.page.info": "\u7B2C {page} / {pages} \u9875 \xB7 \u5171 {total} \u6761",
|
|
248
|
+
"market.perf": "\u6536\u5F55\u8D85\u8FC7 200 \u6761\uFF1A\u4EC5\u67E5\u8BE2\u5F53\u524D\u9875\u7684\u6700\u65B0\u7248\u672C\uFF08\u6BCF\u9875 50 \u6761\uFF09\uFF0C\u5982\u9700\u5168\u90E8\u8BF7\u7528\u641C\u7D22/\u5206\u7C7B\u8FC7\u6EE4",
|
|
249
|
+
"notice.toolview.err": "\u6536\u5F55\u6E05\u5355\u6682\u4E0D\u53EF\u7528",
|
|
90
250
|
"self.upgraded": "dsh-m \u5DF2\u66F4\u65B0\u5230 v{v}\uFF0C\u91CD\u542F\u540E\u751F\u6548",
|
|
91
251
|
"self.failed": "\u81EA\u66F4\u65B0\u5931\u8D25\uFF1A{err}",
|
|
92
252
|
"registry.refreshed": "\u6536\u5F55\u6E05\u5355\u5DF2\u5F3A\u5236\u5237\u65B0",
|
|
@@ -120,7 +280,7 @@ var ZH = {
|
|
|
120
280
|
"readme.hide": "\u6536\u8D77 README",
|
|
121
281
|
"readme.loading": "\u52A0\u8F7D README\u2026 ",
|
|
122
282
|
"readme.none": "\uFF08\u8BE5\u63D2\u4EF6\u6CA1\u6709 README\uFF09",
|
|
123
|
-
"readme.truncated": "\
|
|
283
|
+
"readme.truncated": "\u2026\uFF08\u8D85\u8FC7 64KB \u5DF2\u622A\u65AD\uFF0C\u5B8C\u6574\u5185\u5BB9\u89C1\u63D2\u4EF6\u76EE\u5F55\uFF09",
|
|
124
284
|
"warn.unlink": "\u5378\u8F7D\u53EA\u79FB\u9664 profile \u5BF9\u672C\u5730\u76EE\u5F55\u7684\u5F15\u7528\uFF08{path}\uFF09\uFF0C\u4E0D\u4F1A\u5220\u9664\u76EE\u5F55\u672C\u8EAB\u3002",
|
|
125
285
|
"warn.core": "\u8FD9\u662F file: \u5B89\u88C5\u7684\u6838\u5FC3/\u5F52\u6863\u5305\uFF0C\u5378\u8F7D\u53EF\u80FD\u5F71\u54CD DSH \u529F\u80FD\uFF0C\u4E14\u9700\u8981\u624B\u52A8\u6062\u590D\u3002",
|
|
126
286
|
"profile.hint": "web profile\uFF1A{path}",
|
|
@@ -157,6 +317,7 @@ var EN = {
|
|
|
157
317
|
"badge.update": "Update",
|
|
158
318
|
"badge.market": "Via market",
|
|
159
319
|
"badge.nonmarket": "Non-market",
|
|
320
|
+
"badge.custom": "Custom",
|
|
160
321
|
"action.install": "Install",
|
|
161
322
|
"action.upgrade": "Upgrade",
|
|
162
323
|
"action.uninstall": "Uninstall",
|
|
@@ -174,6 +335,8 @@ var EN = {
|
|
|
174
335
|
"detail.listed.no": "Not in the registry",
|
|
175
336
|
"detail.path": "Path",
|
|
176
337
|
"detail.note": "Note",
|
|
338
|
+
"detail.links": "Details",
|
|
339
|
+
"link.home": "Homepage",
|
|
177
340
|
"manage.hint": "Installed \u2014 manage it on the Installed tab",
|
|
178
341
|
"version.failed": "version lookup failed",
|
|
179
342
|
"src.npm": "npm",
|
|
@@ -200,12 +363,59 @@ var EN = {
|
|
|
200
363
|
"settings.upgradeself": "Upgrade dsh-m",
|
|
201
364
|
"settings.upgradehint": "A restart is required after upgrading",
|
|
202
365
|
"settings.about": "About",
|
|
203
|
-
"settings.about.text": "
|
|
366
|
+
"settings.about.text": "A personal DSH plugin marketplace \u2014 browse, install, uninstall and upgrade, all local; registry overrides apply live.",
|
|
204
367
|
"src.override": "Custom source",
|
|
205
368
|
"src.jsdelivr": "jsDelivr (@main)",
|
|
206
369
|
"src.raw": "raw.githubusercontent (@main)",
|
|
207
370
|
"src.cache": "Local cache",
|
|
208
371
|
"src.bundled": "Bundled snapshot (fallback)",
|
|
372
|
+
"src.default.raw": "raw.githubusercontent (@main)",
|
|
373
|
+
"src.default.jsdelivr": "jsDelivr (@main)",
|
|
374
|
+
"src.default.cache": "Default registry cache",
|
|
375
|
+
"src.custom.url": "Custom URL source",
|
|
376
|
+
"src.custom.file": "Local file source",
|
|
377
|
+
"src.custom.cache": "Custom source (cache)",
|
|
378
|
+
"src.custom.unavailable": "Custom source (unavailable)",
|
|
379
|
+
"settings.address": "Registry address",
|
|
380
|
+
"settings.address.hint": "Empty = official default registry; accepts an HTTPS URL or a local absolute path / file://. Replaces (not merges) the default registry. Live effect.",
|
|
381
|
+
"settings.address.ph": "https://example.com/registry.json or /path/to/registry.json",
|
|
382
|
+
"settings.configured": "Configured address",
|
|
383
|
+
"settings.activecfg": "Active config",
|
|
384
|
+
"settings.effective": "Effective source",
|
|
385
|
+
"settings.status.label": "Config status",
|
|
386
|
+
"settings.status.loading": "Loading",
|
|
387
|
+
"settings.status.ready": "Applied",
|
|
388
|
+
"settings.status.pending": "Pending write (validated)",
|
|
389
|
+
"settings.status.rejected": "Rejected (previous config kept)",
|
|
390
|
+
"settings.status.unavailable": "Unavailable",
|
|
391
|
+
"settings.apply": "Validate & apply",
|
|
392
|
+
"settings.apply.applying": "Validating\u2026",
|
|
393
|
+
"settings.apply.ok": "Registry address applied (no restart needed)",
|
|
394
|
+
"settings.apply.failed": "Apply failed: {err}",
|
|
395
|
+
"settings.reset": "Restore default",
|
|
396
|
+
"settings.reset.ok": "Restored to the default registry",
|
|
397
|
+
"settings.download": "Download default registry.json",
|
|
398
|
+
"settings.download.downloading": "Downloading\u2026",
|
|
399
|
+
"settings.download.ok": "Default registry downloaded (current config unchanged)",
|
|
400
|
+
"settings.download.failed": "Download failed: {err}",
|
|
401
|
+
"settings.diagnose": "Check entries reachability",
|
|
402
|
+
"settings.diagnose.running": "Checking\u2026",
|
|
403
|
+
"settings.diagnose.failed": "Diagnose failed: {err}",
|
|
404
|
+
"settings.diagnose.result": "Probes {checked} \xB7 passed {passed} \xB7 failed {failed}{trunc}",
|
|
405
|
+
"settings.diagnose.truncated": " (showing first 100 issues)",
|
|
406
|
+
"settings.diagnose.none": "No issues found",
|
|
407
|
+
"settings.trust.hint": "\u26A0\uFE0F Custom registries are not validated by official CI. Only install entries from sources you trust.",
|
|
408
|
+
"settings.cache.hint": "Old custom-source caches are cleaned after switching (the default cache is kept); a failed custom source keeps its last good cache.",
|
|
409
|
+
"settings.warnings": "Maintenance notice",
|
|
410
|
+
"notice.default": "Official default registry \xB7 {count} listings",
|
|
411
|
+
"notice.custom": "Custom registry \xB7 {count} listings",
|
|
412
|
+
"notice.stale": "Served from local cache ({count} listings) \u2014 force refresh to update",
|
|
413
|
+
"notice.unavailable": "Registry unavailable \xB7 check the address in Settings",
|
|
414
|
+
"market.page.prev": "Previous",
|
|
415
|
+
"market.page.next": "Next",
|
|
416
|
+
"market.page.info": "Page {page} / {pages} \xB7 {total} listings",
|
|
417
|
+
"market.perf": "200+ listings: latest versions are queried for the current page only (50 per page); use search/category filters",
|
|
418
|
+
"notice.toolview.err": "Registry temporarily unavailable",
|
|
209
419
|
"self.upgraded": "dsh-m updated to v{v} \u2014 restart to take effect",
|
|
210
420
|
"self.failed": "Self-update failed: {err}",
|
|
211
421
|
"registry.refreshed": "Registry force-refreshed",
|
|
@@ -239,7 +449,7 @@ var EN = {
|
|
|
239
449
|
"readme.hide": "Hide README",
|
|
240
450
|
"readme.loading": "Loading README\u2026 ",
|
|
241
451
|
"readme.none": "(No README)",
|
|
242
|
-
"readme.truncated": "\
|
|
452
|
+
"readme.truncated": "\u2026(truncated at 64KB \u2014 see the plugin directory for full content)",
|
|
243
453
|
"warn.unlink": "Uninstalling only removes the profile's reference to the local directory ({path}); the directory itself is kept.",
|
|
244
454
|
"warn.core": "This is a core/archive package installed via file:. Uninstalling may affect DSH features and requires manual restore.",
|
|
245
455
|
"profile.hint": "web profile: {path}",
|
|
@@ -258,7 +468,7 @@ function lookup(key, params) {
|
|
|
258
468
|
const dict = browserLang() === "en" ? EN : ZH;
|
|
259
469
|
return interpolate(dict[key] ?? ZH[key] ?? key, params);
|
|
260
470
|
}
|
|
261
|
-
var
|
|
471
|
+
var CATEGORIES2 = ["market", "tools", "ui", "search", "media", "other"];
|
|
262
472
|
var CSS = `
|
|
263
473
|
.dshm-overlay{position:fixed;inset:0;z-index:2147483000;background:var(--dsw-alias-bg-mask-3,rgba(15,23,42,.48));display:flex;align-items:center;justify-content:center;padding:24px 16px;box-sizing:border-box}
|
|
264
474
|
.dshm-panel{width:min(920px,100%);height:min(680px,86vh);display:flex;flex-direction:column;background:var(--dsw-alias-bg-overlay,var(--dsw-alias-bg-layer-3,#fff));border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:14px;box-shadow:0 18px 48px rgba(2,6,23,.25);overflow:hidden;font-family:inherit;color:var(--dsw-alias-label-primary,inherit)}
|
|
@@ -281,7 +491,7 @@ var CSS = `
|
|
|
281
491
|
.dshm-btn.primary:hover{filter:brightness(1.08)}
|
|
282
492
|
.dshm-btn.danger{color:var(--dsw-alias-state-error-primary,#b91c1c);border-color:var(--dsw-alias-state-error-primary,#b91c1c)}
|
|
283
493
|
.dshm-btn.sm{padding:3px 9px;font-size:11px}
|
|
284
|
-
.dshm-input{flex:1;min-width:120px;border:1px solid var(--dsw-alias-border-l2,#c7d2fe);background:var(--dsw-alias-bg-layer-2,transparent);color:var(--dsw-alias-label-primary,inherit);border-radius:8px;padding:
|
|
494
|
+
.dshm-input{flex:1;min-width:120px;border:1px solid var(--dsw-alias-border-l2,#c7d2fe);background:var(--dsw-alias-bg-layer-2,transparent);color:var(--dsw-alias-label-primary,inherit);border-radius:8px;padding:5px 10px;font:inherit;font-size:12px;outline:none}
|
|
285
495
|
.dshm-input:focus{border-color:var(--dsw-alias-interactive-bg-selected,#4f46e5)}
|
|
286
496
|
.dshm-chips{display:flex;flex-wrap:wrap;gap:6px}
|
|
287
497
|
.dshm-chip{border:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:transparent;color:var(--dsw-alias-label-secondary,#4b5563);border-radius:999px;padding:2px 10px;font:inherit;font-size:11px;cursor:pointer}
|
|
@@ -306,12 +516,43 @@ var CSS = `
|
|
|
306
516
|
.dshm-banner{display:flex;align-items:center;gap:10px;padding:10px 14px;border-top:1px solid var(--dsw-alias-border-l2,#e5e7eb);background:var(--dsw-alias-state-warn-tertiary,#fffbeb);color:var(--dsw-alias-state-warn-primary,#b45309);font-size:12px}
|
|
307
517
|
.dshm-banner .dshm-banner-text{flex:1}
|
|
308
518
|
.dshm-row{display:flex;align-items:center;gap:8px}
|
|
309
|
-
.dshm-kv{display:grid;grid-template-columns:
|
|
310
|
-
.dshm-kv .k{color:var(--dsw-alias-label-caption,#6b7280)}
|
|
519
|
+
.dshm-kv{display:grid;grid-template-columns:96px 1fr;gap:6px 10px;font-size:12px;align-items:baseline}
|
|
520
|
+
.dshm-kv .k{color:var(--dsw-alias-label-caption,#6b7280);font-size:11px}
|
|
521
|
+
.dshm-section{background:var(--dsw-alias-bg-layer-2,rgba(38,49,72,.04));border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:12px;padding:12px 14px;display:flex;flex-direction:column;gap:9px;margin:0 0 10px}
|
|
522
|
+
.dshm-section:last-child{margin-bottom:2px}
|
|
523
|
+
.dshm-section-title{display:flex;align-items:center;gap:7px;font-weight:700;font-size:12px;letter-spacing:.2px;color:var(--dsw-alias-label-primary,inherit)}
|
|
524
|
+
.dshm-section-title::before{content:"";width:3px;height:11px;border-radius:2px;background:var(--dsw-alias-interactive-bg-selected,#4f46e5)}
|
|
525
|
+
.dshm-section-sub{margin-left:auto;font-weight:400;font-size:11px;color:var(--dsw-alias-label-caption,#9ca3af)}
|
|
526
|
+
.dshm-note{border-left:3px solid var(--dsw-alias-border-l2,#cbd5e1);padding:3px 10px;color:var(--dsw-alias-label-caption,#9ca3af);font-size:11px;line-height:17px;word-break:break-word}
|
|
527
|
+
.dshm-note.warn{border-left-color:var(--dsw-alias-state-warn-primary,#b45309)}
|
|
528
|
+
.dshm-code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;background:var(--dsw-alias-bg-layer-2,rgba(127,127,127,.12));padding:1px 7px;border-radius:5px;word-break:break-all}
|
|
311
529
|
.dshm-spin{display:inline-block;width:12px;height:12px;border:2px solid var(--dsw-alias-border-l2,#c7d2fe);border-top-color:var(--dsw-alias-interactive-bg-selected,#4f46e5);border-radius:50%;animation:dshm-rot .8s linear infinite;vertical-align:-2px}
|
|
312
530
|
@keyframes dshm-rot{to{transform:rotate(360deg)}}
|
|
313
531
|
.dshm-others{display:flex;align-items:center;gap:8px;padding:10px 12px;border:1px dashed var(--dsw-alias-border-l2,#e2e4e8);border-radius:10px;color:var(--dsw-alias-label-caption,#9ca3af);font-size:12px;line-height:18px}
|
|
314
|
-
.dshm-readme{max-height:
|
|
532
|
+
.dshm-readme{max-height:280px;overflow:auto;background:var(--dsw-alias-bg-layer-2,rgba(38,49,72,.04));border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:8px;padding:10px 12px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary,#4b5563);margin:0}
|
|
533
|
+
.dshm-readme.md{font-family:inherit;white-space:normal;word-break:break-word}
|
|
534
|
+
.dshm-readme.md h1,.dshm-readme.md h2,.dshm-readme.md h3,.dshm-readme.md h4,.dshm-readme.md h5,.dshm-readme.md h6{margin:8px 0 4px;font-weight:700;line-height:1.4;color:var(--dsw-alias-label-primary,inherit)}
|
|
535
|
+
.dshm-readme.md h1{font-size:15px}.dshm-readme.md h2{font-size:14px}.dshm-readme.md h3{font-size:13px}.dshm-readme.md h4,.dshm-readme.md h5,.dshm-readme.md h6{font-size:12px}
|
|
536
|
+
.dshm-readme.md>:first-child{margin-top:0}
|
|
537
|
+
.dshm-readme.md p{margin:4px 0}
|
|
538
|
+
.dshm-readme.md a{color:var(--dsw-alias-state-business-primary,#4d6bfe);text-decoration:none}
|
|
539
|
+
.dshm-readme.md a:hover{text-decoration:underline}
|
|
540
|
+
.dshm-readme.md code{background:rgba(127,127,127,.16);border-radius:4px;padding:1px 4px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px}
|
|
541
|
+
.dshm-readme.md pre{background:rgba(127,127,127,.12);border:1px solid var(--dsw-alias-border-l2,transparent);border-radius:8px;padding:8px 10px;overflow:auto;margin:6px 0}
|
|
542
|
+
.dshm-readme.md pre code{background:transparent;padding:0;font-size:11px;line-height:16px}
|
|
543
|
+
.dshm-readme.md img{max-height:20px;max-width:100%;vertical-align:middle}
|
|
544
|
+
.dshm-readme.md ul,.dshm-readme.md ol{margin:4px 0;padding-left:20px}
|
|
545
|
+
.dshm-readme.md li{margin:2px 0}
|
|
546
|
+
.dshm-readme.md blockquote{margin:6px 0;padding:2px 10px;border-left:3px solid var(--dsw-alias-border-l2,#cbd5e1);color:var(--dsw-alias-label-caption,#6b7280)}
|
|
547
|
+
.dshm-readme.md table{border-collapse:collapse;margin:6px 0;font-size:11px}
|
|
548
|
+
.dshm-readme.md th,.dshm-readme.md td{border:1px solid var(--dsw-alias-border-l2,#cbd5e1);padding:3px 8px;text-align:left}
|
|
549
|
+
.dshm-readme.md th{background:var(--dsw-alias-bg-layer-2,rgba(127,127,127,.1))}
|
|
550
|
+
.dshm-readme.md hr{border:0;border-top:1px solid var(--dsw-alias-border-l2,#cbd5e1);margin:8px 0}
|
|
551
|
+
.dshm-readme.md .dshm-md-note{margin-top:8px;padding-top:6px;border-top:1px dashed var(--dsw-alias-border-l2,#cbd5e1);color:var(--dsw-alias-label-caption,#9ca3af);font-size:11px}
|
|
552
|
+
.dshm-links{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-top:7px;padding-top:6px;border-top:1px solid var(--dsw-alias-border-l2,#e5e7eb);font-size:11px;color:var(--dsw-alias-label-caption,#6b7280)}
|
|
553
|
+
.dshm-links-k,.dshm-links-sep{color:var(--dsw-alias-label-caption,#9ca3af)}
|
|
554
|
+
.dshm-links a{color:var(--dsw-alias-state-business-primary,#4d6bfe);text-decoration:none;font-weight:500}
|
|
555
|
+
.dshm-links a:hover{text-decoration:underline}
|
|
315
556
|
.dshm-prog{display:flex;align-items:center;gap:8px;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#e5e7eb);border-radius:8px;font-size:12px;color:var(--dsw-alias-label-secondary,#4b5563)}
|
|
316
557
|
.dshm-prog .bar{flex:1;height:6px;border-radius:3px;background:var(--dsw-alias-bg-layer-2,rgba(38,49,72,.08));overflow:hidden;min-width:80px}
|
|
317
558
|
.dshm-prog .bar i{display:block;height:100%;background:var(--dsw-alias-interactive-bg-selected,#4f46e5);transition:width .3s}
|
|
@@ -330,11 +571,12 @@ function ensureCss() {
|
|
|
330
571
|
el.textContent = CSS;
|
|
331
572
|
document.head.appendChild(el);
|
|
332
573
|
}
|
|
333
|
-
async function api(method, params) {
|
|
574
|
+
async function api(method, params, signal) {
|
|
334
575
|
const res = await fetch(API, {
|
|
335
576
|
method: "POST",
|
|
336
577
|
headers: { "content-type": "application/json" },
|
|
337
|
-
body: JSON.stringify({ method, ...params || {} })
|
|
578
|
+
body: JSON.stringify({ method, ...params || {} }),
|
|
579
|
+
...signal ? { signal } : {}
|
|
338
580
|
});
|
|
339
581
|
const data = await res.json().catch(() => ({}));
|
|
340
582
|
if (!res.ok || data.ok === false) throw new Error(data.error || `API ${res.status}`);
|
|
@@ -356,6 +598,51 @@ function useAsync(fn, deps) {
|
|
|
356
598
|
}, [run]);
|
|
357
599
|
return { ...state, reload: run };
|
|
358
600
|
}
|
|
601
|
+
function useMarketData() {
|
|
602
|
+
const [query, setQuery] = useState(() => normalizeMarketQuery2({}));
|
|
603
|
+
const [data, setData] = useState(null);
|
|
604
|
+
const [loading, setLoading] = useState(true);
|
|
605
|
+
const [error, setError] = useState(null);
|
|
606
|
+
const genRef = useRef(0);
|
|
607
|
+
const abortRef = useRef(null);
|
|
608
|
+
const queryRef = useRef(query);
|
|
609
|
+
const fetchPage = useCallback((nextQuery, force) => {
|
|
610
|
+
const gen = ++genRef.current;
|
|
611
|
+
abortRef.current?.abort();
|
|
612
|
+
const ac = new AbortController();
|
|
613
|
+
abortRef.current = ac;
|
|
614
|
+
setLoading(true);
|
|
615
|
+
setError(null);
|
|
616
|
+
const params = {
|
|
617
|
+
query: nextQuery.query || void 0,
|
|
618
|
+
category: nextQuery.category || void 0,
|
|
619
|
+
offset: nextQuery.offset,
|
|
620
|
+
limit: nextQuery.limit,
|
|
621
|
+
...force ? { force: true } : {}
|
|
622
|
+
};
|
|
623
|
+
return api("market", params, ac.signal).then((raw) => {
|
|
624
|
+
if (genRef.current !== gen || ac.signal.aborted) return;
|
|
625
|
+
setData(normalizeMarketResponse2(raw));
|
|
626
|
+
setLoading(false);
|
|
627
|
+
}).catch((e) => {
|
|
628
|
+
if (genRef.current !== gen || ac.signal.aborted) return;
|
|
629
|
+
setError(String(e && e.message || e));
|
|
630
|
+
setLoading(false);
|
|
631
|
+
});
|
|
632
|
+
}, []);
|
|
633
|
+
const updateQuery = useCallback((patch, opts = {}) => {
|
|
634
|
+
const next = resetPageOnFilterChange2(queryRef.current, normalizeMarketQuery2({ ...queryRef.current, ...patch }));
|
|
635
|
+
queryRef.current = next;
|
|
636
|
+
setQuery(next);
|
|
637
|
+
if (opts.fetch !== false) fetchPage(next, opts.force);
|
|
638
|
+
}, [fetchPage]);
|
|
639
|
+
const reload = useCallback((force) => fetchPage(queryRef.current, force), [fetchPage]);
|
|
640
|
+
useEffect(() => {
|
|
641
|
+
fetchPage(queryRef.current, false);
|
|
642
|
+
return () => abortRef.current?.abort();
|
|
643
|
+
}, [fetchPage]);
|
|
644
|
+
return { query, data, loading, error, reload, updateQuery };
|
|
645
|
+
}
|
|
359
646
|
function Icon({ entry }) {
|
|
360
647
|
const [broken, setBroken] = useState(false);
|
|
361
648
|
const letter = String(entry.name || entry.id || "?").charAt(0).toUpperCase();
|
|
@@ -374,6 +661,181 @@ function Icon({ entry }) {
|
|
|
374
661
|
function Spin() {
|
|
375
662
|
return h("span", { className: "dshm-spin" });
|
|
376
663
|
}
|
|
664
|
+
function safeUrl(u) {
|
|
665
|
+
const t = String(u || "").trim();
|
|
666
|
+
if (/^(https?:\/\/|mailto:)/i.test(t)) return t;
|
|
667
|
+
if (/^[/#]/.test(t)) return t;
|
|
668
|
+
return "#";
|
|
669
|
+
}
|
|
670
|
+
function ExtLink({ href, className, children }) {
|
|
671
|
+
return h(
|
|
672
|
+
"a",
|
|
673
|
+
{
|
|
674
|
+
className: className || "dshm-md-a",
|
|
675
|
+
href: safeUrl(href),
|
|
676
|
+
target: "_blank",
|
|
677
|
+
rel: "noopener noreferrer",
|
|
678
|
+
onClick: (e) => e.stopPropagation()
|
|
679
|
+
},
|
|
680
|
+
children
|
|
681
|
+
);
|
|
682
|
+
}
|
|
683
|
+
function MdImg({ src, alt }) {
|
|
684
|
+
return h("img", {
|
|
685
|
+
className: "dshm-md-img",
|
|
686
|
+
src: safeUrl(src),
|
|
687
|
+
alt: alt || "",
|
|
688
|
+
referrerPolicy: "no-referrer",
|
|
689
|
+
onError: (e) => {
|
|
690
|
+
e.currentTarget.style.display = "none";
|
|
691
|
+
}
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
function mdInline(text, kb) {
|
|
695
|
+
const re = /(\[!\[[^\]]*\]\([^)]*\)\]\([^)]*\))|(!\[[^\]]*\]\([^)]*\))|(\[[^\]]*\]\([^)]*\))|(`[^`]+`)|(\*\*[^*]+\*\*)|(~~[^~]+~~)|(\*[^*\s][^*]*\*)|(<https?:\/\/[^>\s]+>)|(https?:\/\/[^\s<>()\[\]{}"'「」【】]+[^\s<>()\[\]{}"'「」【】.,;:!?…,。;:!?)】」"')])/g;
|
|
696
|
+
const src = String(text);
|
|
697
|
+
const nodes = [];
|
|
698
|
+
let last = 0;
|
|
699
|
+
let m;
|
|
700
|
+
let i = 0;
|
|
701
|
+
while (m = re.exec(src)) {
|
|
702
|
+
if (m.index > last) nodes.push(src.slice(last, m.index));
|
|
703
|
+
const tok = m[0];
|
|
704
|
+
const k = `${kb}-${i++}`;
|
|
705
|
+
if (tok.startsWith("[![")) {
|
|
706
|
+
const im = /^!\[([^\]]*)\]\(([^)]*)\)/.exec(tok.slice(1));
|
|
707
|
+
const lm = /\]\(([^)]*)\)\s*$/.exec(tok);
|
|
708
|
+
const img = h(MdImg, { src: im && im[2], alt: im && im[1] });
|
|
709
|
+
const href = lm && lm[1];
|
|
710
|
+
nodes.push(href && safeUrl(href) !== "#" ? h(ExtLink, { key: k, href }, img) : h("span", { key: k }, img));
|
|
711
|
+
} else if (tok.startsWith("![") || tok.startsWith("<![")) {
|
|
712
|
+
const im = /^!\[([^\]]*)\]\(([^)]*)\)$/.exec(tok);
|
|
713
|
+
nodes.push(h(MdImg, { key: k, src: im && im[2], alt: im && im[1] }));
|
|
714
|
+
} else if (tok.startsWith("[")) {
|
|
715
|
+
const lm = /^\[([^\]]*)\]\(([^)]*)\)$/.exec(tok);
|
|
716
|
+
nodes.push(h(ExtLink, { key: k, href: lm && lm[2] }, mdInline(lm ? lm[1] : tok, k)));
|
|
717
|
+
} else if (tok.startsWith("`")) {
|
|
718
|
+
nodes.push(h("code", { key: k }, tok.slice(1, -1)));
|
|
719
|
+
} else if (tok.startsWith("**")) {
|
|
720
|
+
nodes.push(h("strong", { key: k }, mdInline(tok.slice(2, -2), k)));
|
|
721
|
+
} else if (tok.startsWith("~~")) {
|
|
722
|
+
nodes.push(h("del", { key: k }, mdInline(tok.slice(2, -2), k)));
|
|
723
|
+
} else if (tok.startsWith("*")) {
|
|
724
|
+
nodes.push(h("em", { key: k }, mdInline(tok.slice(1, -1), k)));
|
|
725
|
+
} else if (tok.startsWith("<")) {
|
|
726
|
+
const u = tok.slice(1, -1);
|
|
727
|
+
nodes.push(h(ExtLink, { key: k, href: u }, u));
|
|
728
|
+
} else {
|
|
729
|
+
nodes.push(h(ExtLink, { key: k, href: tok }, tok.length > 72 ? `${tok.slice(0, 69)}\u2026` : tok));
|
|
730
|
+
}
|
|
731
|
+
last = m.index + tok.length;
|
|
732
|
+
}
|
|
733
|
+
if (last < src.length) nodes.push(src.slice(last));
|
|
734
|
+
return nodes;
|
|
735
|
+
}
|
|
736
|
+
function mdBlocks(lines, kb) {
|
|
737
|
+
const out = [];
|
|
738
|
+
let i = 0;
|
|
739
|
+
let n = 0;
|
|
740
|
+
const isFence = (s) => /^\s*```/.test(s);
|
|
741
|
+
const isHeading = (s) => /^#{1,6}\s+/.test(s);
|
|
742
|
+
const isHr = (s) => /^\s*(-{3,}|\*{3,}|_{3,})\s*$/.test(s);
|
|
743
|
+
const isQuote = (s) => /^\s*>/.test(s);
|
|
744
|
+
const isUl = (s) => /^\s*[-*+]\s+/.test(s);
|
|
745
|
+
const isOl = (s) => /^\s*\d+[.)]\s+/.test(s);
|
|
746
|
+
const isTableRow = (s) => s.includes("|") && /^\s*\|/.test(s);
|
|
747
|
+
while (i < lines.length) {
|
|
748
|
+
const line = lines[i];
|
|
749
|
+
if (!line.trim()) {
|
|
750
|
+
i++;
|
|
751
|
+
continue;
|
|
752
|
+
}
|
|
753
|
+
const k = `${kb}-b${n++}`;
|
|
754
|
+
if (isFence(line)) {
|
|
755
|
+
const buf2 = [];
|
|
756
|
+
i++;
|
|
757
|
+
while (i < lines.length && !/^\s*```\s*$/.test(lines[i])) buf2.push(lines[i++]);
|
|
758
|
+
i++;
|
|
759
|
+
out.push(h("pre", { key: k }, h("code", null, buf2.join("\n"))));
|
|
760
|
+
continue;
|
|
761
|
+
}
|
|
762
|
+
if (isHeading(line)) {
|
|
763
|
+
const hm = /^(#{1,6})\s+(.*)$/.exec(line);
|
|
764
|
+
out.push(h(`h${hm[1].length}`, { key: k }, mdInline(hm[2], k)));
|
|
765
|
+
i++;
|
|
766
|
+
continue;
|
|
767
|
+
}
|
|
768
|
+
if (isHr(line)) {
|
|
769
|
+
out.push(h("hr", { key: k }));
|
|
770
|
+
i++;
|
|
771
|
+
continue;
|
|
772
|
+
}
|
|
773
|
+
if (isQuote(line)) {
|
|
774
|
+
const buf2 = [];
|
|
775
|
+
while (i < lines.length && isQuote(lines[i])) buf2.push(lines[i++].replace(/^\s*>\s?/, ""));
|
|
776
|
+
out.push(h("blockquote", { key: k }, mdBlocks(buf2, k)));
|
|
777
|
+
continue;
|
|
778
|
+
}
|
|
779
|
+
if (isUl(line) || isOl(line)) {
|
|
780
|
+
const ordered = isOl(line);
|
|
781
|
+
const re = ordered ? /^\s*\d+[.)]\s+(.*)$/ : /^\s*[-*+]\s+(.*)$/;
|
|
782
|
+
const items = [];
|
|
783
|
+
while (i < lines.length && (ordered ? isOl(lines[i]) : isUl(lines[i]))) {
|
|
784
|
+
items.push(h("li", { key: `li${items.length}` }, mdInline(re.exec(lines[i])[1], `${k}-${items.length}`)));
|
|
785
|
+
i++;
|
|
786
|
+
}
|
|
787
|
+
out.push(h(ordered ? "ol" : "ul", { key: k }, items));
|
|
788
|
+
continue;
|
|
789
|
+
}
|
|
790
|
+
if (isTableRow(line) && i + 1 < lines.length && lines[i + 1].includes("-") && /^\s*\|?[\s:|-]+\|?\s*$/.test(lines[i + 1])) {
|
|
791
|
+
const cells = (s) => s.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map((c) => c.trim());
|
|
792
|
+
const head = cells(lines[i]);
|
|
793
|
+
i += 2;
|
|
794
|
+
const rows = [];
|
|
795
|
+
while (i < lines.length && isTableRow(lines[i])) {
|
|
796
|
+
rows.push(cells(lines[i]));
|
|
797
|
+
i++;
|
|
798
|
+
}
|
|
799
|
+
out.push(
|
|
800
|
+
h(
|
|
801
|
+
"table",
|
|
802
|
+
{ key: k },
|
|
803
|
+
h("thead", null, h("tr", null, head.map((c, x) => h("th", { key: x }, mdInline(c, `${k}h${x}`))))),
|
|
804
|
+
h("tbody", null, rows.map((r, y) => h("tr", { key: y }, r.map((c, x) => h("td", { key: x }, mdInline(c, `${k}${y}x${x}`))))))
|
|
805
|
+
)
|
|
806
|
+
);
|
|
807
|
+
continue;
|
|
808
|
+
}
|
|
809
|
+
const buf = [line];
|
|
810
|
+
i++;
|
|
811
|
+
while (i < lines.length && lines[i].trim() && !isFence(lines[i]) && !isHeading(lines[i]) && !isHr(lines[i]) && !isQuote(lines[i]) && !isUl(lines[i]) && !isOl(lines[i])) {
|
|
812
|
+
buf.push(lines[i]);
|
|
813
|
+
i++;
|
|
814
|
+
}
|
|
815
|
+
out.push(h("p", { key: k }, mdInline(buf.join(" "), k)));
|
|
816
|
+
}
|
|
817
|
+
return out;
|
|
818
|
+
}
|
|
819
|
+
function renderMarkdown(src) {
|
|
820
|
+
return mdBlocks(String(src || "").replace(/\r\n?/g, "\n").split("\n"), "md");
|
|
821
|
+
}
|
|
822
|
+
function officialLinks({ npm, github, homepage }) {
|
|
823
|
+
const links = [];
|
|
824
|
+
if (github) links.push(["GitHub", `https://github.com/${github}`]);
|
|
825
|
+
if (npm) links.push(["npm", `https://www.npmjs.com/package/${npm}`]);
|
|
826
|
+
if (!links.length && homepage) links.push([lookup("link.home"), homepage]);
|
|
827
|
+
return links;
|
|
828
|
+
}
|
|
829
|
+
function LinksRow(props) {
|
|
830
|
+
const links = officialLinks(props);
|
|
831
|
+
if (!links.length) return null;
|
|
832
|
+
const kids = [];
|
|
833
|
+
links.forEach(([label, href], idx) => {
|
|
834
|
+
if (idx) kids.push(h("span", { key: `sep${idx}`, className: "dshm-links-sep" }, "\xB7"));
|
|
835
|
+
kids.push(h(ExtLink, { key: label, href }, label));
|
|
836
|
+
});
|
|
837
|
+
return h("div", { className: "dshm-links" }, h("span", { className: "dshm-links-k" }, `${lookup("detail.links")}\uFF1A`), ...kids);
|
|
838
|
+
}
|
|
377
839
|
function TwoStepButton({ label, confirmLabel, className, onConfirm, disabled }) {
|
|
378
840
|
const [arm, setArm] = useState(false);
|
|
379
841
|
useEffect(() => {
|
|
@@ -440,28 +902,32 @@ function RestartBanner({ note, onDone }) {
|
|
|
440
902
|
phase === "idle" && !err ? h("button", { className: "dshm-btn sm", onClick: () => onDone(false) }, lookup("common.later")) : null
|
|
441
903
|
);
|
|
442
904
|
}
|
|
443
|
-
function MarketTab({ notify,
|
|
444
|
-
const {
|
|
445
|
-
const [q, setQ] = useState("");
|
|
446
|
-
const [cat, setCat] = useState(null);
|
|
905
|
+
function MarketTab({ notify, market }) {
|
|
906
|
+
const { data, loading, error, reload, query, updateQuery } = market;
|
|
447
907
|
const [openId, setOpenId] = useState(null);
|
|
448
908
|
const [busyId, setBusyId] = useState(null);
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
909
|
+
const [qInput, setQInput] = useState(query.query);
|
|
910
|
+
const debounceRef = useRef(null);
|
|
911
|
+
const items = data && data.items || [];
|
|
912
|
+
const total = data && data.total || 0;
|
|
913
|
+
const limit = data && data.limit || MARKET_PAGE_SIZE2;
|
|
914
|
+
const offset = data && data.offset || 0;
|
|
915
|
+
const page = total > 0 ? Math.floor(offset / limit) + 1 : 1;
|
|
916
|
+
const pages = total > 0 ? Math.max(1, Math.ceil(total / limit)) : 1;
|
|
917
|
+
const counts = data && data.categoryCounts || {};
|
|
918
|
+
const notice = data ? registryNotice2(data.registryState, total) : null;
|
|
919
|
+
const onSearchInput = (value) => {
|
|
920
|
+
setQInput(value);
|
|
921
|
+
if (debounceRef.current) clearTimeout(debounceRef.current);
|
|
922
|
+
debounceRef.current = setTimeout(() => updateQuery({ query: value }), 300);
|
|
923
|
+
};
|
|
459
924
|
const doInstall = async (it, version) => {
|
|
460
925
|
setBusyId(it.id);
|
|
461
926
|
try {
|
|
462
927
|
const res = await api("install", { id: it.id, ...version ? { version } : {} });
|
|
463
928
|
notify({
|
|
464
929
|
kind: "ok",
|
|
930
|
+
needsRestart: true,
|
|
465
931
|
text: lookup("notify.installed", { pkg: res.pkg, version: res.version ? ` v${res.version}` : "" }) + (res.usedAllowAllBuilds ? lookup("notify.allowbuilds") : "")
|
|
466
932
|
});
|
|
467
933
|
await reload(false);
|
|
@@ -474,75 +940,101 @@ function MarketTab({ notify, onCount }) {
|
|
|
474
940
|
return h(
|
|
475
941
|
React.Fragment,
|
|
476
942
|
null,
|
|
943
|
+
notice ? h(
|
|
944
|
+
"div",
|
|
945
|
+
{ className: notice.key === "notice.unavailable" ? "dshm-err" : "dshm-hint" },
|
|
946
|
+
lookup(notice.key, { count: notice.count })
|
|
947
|
+
) : null,
|
|
948
|
+
total > 200 ? h("div", { className: "dshm-hint" }, lookup("market.perf")) : null,
|
|
477
949
|
h(
|
|
478
950
|
"div",
|
|
479
951
|
{ className: "dshm-row" },
|
|
480
952
|
h("input", {
|
|
481
953
|
className: "dshm-input",
|
|
482
954
|
placeholder: lookup("search.ph"),
|
|
483
|
-
value:
|
|
484
|
-
onChange: (e) =>
|
|
955
|
+
value: qInput,
|
|
956
|
+
onChange: (e) => onSearchInput(e.target.value)
|
|
485
957
|
}),
|
|
486
958
|
h("button", { className: "dshm-btn", onClick: () => reload(true), title: lookup("settings.policy.v") }, loading ? Spin() : `\u21BB ${lookup("common.refresh")}`)
|
|
487
959
|
),
|
|
488
960
|
h(
|
|
489
961
|
"div",
|
|
490
962
|
{ className: "dshm-chips" },
|
|
491
|
-
h("button", { className: `dshm-chip${
|
|
492
|
-
|
|
493
|
-
const n =
|
|
963
|
+
h("button", { className: `dshm-chip${query.category === null ? " on" : ""}`, onClick: () => updateQuery({ category: null, offset: 0 }) }, lookup("cat.all")),
|
|
964
|
+
CATEGORIES2.map((key) => {
|
|
965
|
+
const n = typeof counts[key] === "number" ? counts[key] : 0;
|
|
494
966
|
return h(
|
|
495
967
|
"button",
|
|
496
|
-
{ key, className: `dshm-chip${
|
|
968
|
+
{ key, className: `dshm-chip${query.category === key ? " on" : ""}`, onClick: () => updateQuery({ category: query.category === key ? null : key, offset: 0 }) },
|
|
497
969
|
`${lookup("cat." + key)}${n ? ` ${n}` : ""}`
|
|
498
970
|
);
|
|
499
971
|
})
|
|
500
972
|
),
|
|
501
973
|
busyId ? h(ProgressLine, { key: "prog" }) : null,
|
|
502
974
|
loading && !data ? h("div", { className: "dshm-empty" }, lookup("market.loading"), Spin()) : error ? h("div", { className: "dshm-err" }, lookup("failed.load", { err: error })) : items.length === 0 ? h("div", { className: "dshm-empty" }, lookup("market.empty")) : h(
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
"
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
975
|
+
React.Fragment,
|
|
976
|
+
null,
|
|
977
|
+
h(
|
|
978
|
+
"div",
|
|
979
|
+
{ className: "dshm-cards" },
|
|
980
|
+
items.map((it) => Card({
|
|
981
|
+
key: it.id,
|
|
982
|
+
icon: h(Icon, { entry: it }),
|
|
983
|
+
name: it.name,
|
|
984
|
+
badges: [
|
|
985
|
+
it.outdated ? h("span", { className: "dshm-badge warn", key: "u" }, lookup("badge.update")) : null,
|
|
986
|
+
it.installed ? h("span", { className: "dshm-badge", key: "i" }, lookup("badge.installed")) : null,
|
|
987
|
+
h("span", { className: "dshm-badge info", key: "s" }, it.source === "npm" ? "npm" : "github")
|
|
988
|
+
],
|
|
989
|
+
desc: it.description,
|
|
990
|
+
sub: [
|
|
991
|
+
it.latestVersion ? lookup("sub.latest", { v: it.latestVersion }) : it.latestTag ? it.latestTag : it.latestSha ? lookup("sub.head", { sha: it.latestSha.slice(0, 7) }) : null,
|
|
992
|
+
it.installedVersion ? lookup("sub.installed", { v: it.installedVersion }) : null,
|
|
993
|
+
it.latestError ? lookup("version.failed") : null
|
|
994
|
+
].filter(Boolean).join(" \xB7 "),
|
|
995
|
+
links: h(LinksRow, { npm: it.npm, github: it.github, homepage: it.homepage }),
|
|
996
|
+
open: openId === it.id,
|
|
997
|
+
onToggle: () => setOpenId(openId === it.id ? null : it.id),
|
|
998
|
+
detail: DetailRows([
|
|
999
|
+
[lookup("detail.id"), it.id],
|
|
1000
|
+
[lookup("detail.source"), it.source === "npm" ? h(ExtLink, { href: `https://www.npmjs.com/package/${it.npm}` }, `npm \xB7 ${it.npm}`) : h(ExtLink, { href: `https://github.com/${it.github}` }, `GitHub \xB7 ${it.github}`)],
|
|
1001
|
+
[lookup("detail.latest"), it.latestVersion ? `v${it.latestVersion}` : it.latestTag ? it.latestTag : it.latestSha ? it.latestSha : it.latestError || "\u2014"],
|
|
1002
|
+
[lookup("detail.installed"), it.installedPkg ? `${it.installedPkg} v${it.installedVersion || "?"}` : lookup("installed.none")],
|
|
1003
|
+
[lookup("detail.tags"), (it.tags || []).join(", ") || "\u2014"],
|
|
1004
|
+
it.latestError ? [lookup("version.failed"), it.latestError] : null
|
|
1005
|
+
]),
|
|
1006
|
+
actions: [
|
|
1007
|
+
it.installed ? h("span", { className: "dshm-hint", key: "hint" }, lookup("manage.hint")) : h(
|
|
1008
|
+
"button",
|
|
1009
|
+
{
|
|
1010
|
+
key: "install",
|
|
1011
|
+
className: "dshm-btn primary sm",
|
|
1012
|
+
disabled: busyId === it.id,
|
|
1013
|
+
onClick: (e) => {
|
|
1014
|
+
e.stopPropagation();
|
|
1015
|
+
doInstall(it);
|
|
1016
|
+
}
|
|
1017
|
+
},
|
|
1018
|
+
busyId === it.id ? h(Spin) : lookup("action.install")
|
|
1019
|
+
)
|
|
1020
|
+
]
|
|
1021
|
+
}))
|
|
1022
|
+
),
|
|
1023
|
+
pages > 1 ? h(
|
|
1024
|
+
"div",
|
|
1025
|
+
{ className: "dshm-row", style: { justifyContent: "center", marginTop: "4px" } },
|
|
1026
|
+
h("button", {
|
|
1027
|
+
className: "dshm-btn sm",
|
|
1028
|
+
disabled: page <= 1 || loading,
|
|
1029
|
+
onClick: () => updateQuery({ offset: Math.max(0, offset - limit) })
|
|
1030
|
+
}, lookup("market.page.prev")),
|
|
1031
|
+
h("span", { className: "dshm-hint" }, lookup("market.page.info", { page, pages, total })),
|
|
1032
|
+
h("button", {
|
|
1033
|
+
className: "dshm-btn sm",
|
|
1034
|
+
disabled: page >= pages || loading,
|
|
1035
|
+
onClick: () => updateQuery({ offset: Math.min(total - 1, offset + limit) })
|
|
1036
|
+
}, lookup("market.page.next"))
|
|
1037
|
+
) : null
|
|
546
1038
|
)
|
|
547
1039
|
);
|
|
548
1040
|
}
|
|
@@ -586,10 +1078,15 @@ function ReadmeBlock({ pkg }) {
|
|
|
586
1078
|
live = false;
|
|
587
1079
|
};
|
|
588
1080
|
}, [pkg]);
|
|
589
|
-
if (state.loading) return h("div", { className: "dshm-hint" }, "
|
|
1081
|
+
if (state.loading) return h("div", { className: "dshm-hint" }, lookup("readme.loading"), Spin());
|
|
590
1082
|
if (state.err) return h("div", { className: "dshm-err" }, state.err);
|
|
591
|
-
if (!state.text) return h("div", { className: "dshm-hint" }, "
|
|
592
|
-
return h(
|
|
1083
|
+
if (!state.text) return h("div", { className: "dshm-hint" }, lookup("readme.none"));
|
|
1084
|
+
return h(
|
|
1085
|
+
"div",
|
|
1086
|
+
{ className: "dshm-readme md", onClick: (e) => e.stopPropagation() },
|
|
1087
|
+
renderMarkdown(state.text),
|
|
1088
|
+
state.truncated ? h("div", { className: "dshm-md-note" }, lookup("readme.truncated")) : null
|
|
1089
|
+
);
|
|
593
1090
|
}
|
|
594
1091
|
function uninstallGuard(it) {
|
|
595
1092
|
if (it.source === "link") {
|
|
@@ -614,6 +1111,7 @@ function InstalledTab({ notify, installed }) {
|
|
|
614
1111
|
const res = await api("uninstall", { pkg: it.pkg });
|
|
615
1112
|
notify({
|
|
616
1113
|
kind: "ok",
|
|
1114
|
+
needsRestart: true,
|
|
617
1115
|
text: lookup("notify.uninstalled", { pkg: res.pkg }) + (res.liveDisabled ? lookup("notify.livedisabled") : "") + (res.leftovers && res.leftovers.length ? lookup("notify.leftovers", { paths: res.leftovers.join(", ") }) : "")
|
|
618
1116
|
});
|
|
619
1117
|
await reload();
|
|
@@ -629,6 +1127,7 @@ function InstalledTab({ notify, installed }) {
|
|
|
629
1127
|
const res = await api("upgrade", { pkg: it.pkg });
|
|
630
1128
|
notify({
|
|
631
1129
|
kind: "ok",
|
|
1130
|
+
needsRestart: true,
|
|
632
1131
|
text: lookup("notify.upgraded", {
|
|
633
1132
|
pkg: res.pkg,
|
|
634
1133
|
from: res.fromVersion ? `v${res.fromVersion}` : "\u2014",
|
|
@@ -670,6 +1169,10 @@ function InstalledTab({ notify, installed }) {
|
|
|
670
1169
|
`v${it.version || "?"}`,
|
|
671
1170
|
{ npm: lookup("src.npm"), github: lookup("src.github"), link: lookup("src.link"), file: lookup("src.file"), unknown: lookup("src.unknown") }[it.source] || it.source
|
|
672
1171
|
].join(" \xB7 "),
|
|
1172
|
+
links: h(LinksRow, {
|
|
1173
|
+
npm: it.source === "npm" ? it.pkg : null,
|
|
1174
|
+
github: it.registryGithub || it.githubRepo || (it.spec.startsWith("github:") ? it.spec.slice(7).split("#")[0] : null)
|
|
1175
|
+
}),
|
|
673
1176
|
open: openPkg === it.pkg,
|
|
674
1177
|
onToggle: () => setOpenPkg(openPkg === it.pkg ? null : it.pkg),
|
|
675
1178
|
detail: readmePkg === it.pkg ? h(ReadmeBlock, { pkg: it.pkg }) : DetailRows([
|
|
@@ -716,32 +1219,114 @@ function InstalledTab({ notify, installed }) {
|
|
|
716
1219
|
)
|
|
717
1220
|
);
|
|
718
1221
|
}
|
|
719
|
-
function
|
|
1222
|
+
function regSourceLabel(data) {
|
|
1223
|
+
if (!data) return "\u2014";
|
|
1224
|
+
const map = {
|
|
1225
|
+
"default-raw": "src.default.raw",
|
|
1226
|
+
"default-jsdelivr": "src.default.jsdelivr",
|
|
1227
|
+
"default-cache": "src.default.cache",
|
|
1228
|
+
bundled: "src.bundled",
|
|
1229
|
+
"custom-url": "src.custom.url",
|
|
1230
|
+
"custom-file": "src.custom.file",
|
|
1231
|
+
"custom-cache": "src.custom.cache",
|
|
1232
|
+
"custom-unavailable": "src.custom.unavailable",
|
|
1233
|
+
// 旧字段兼容
|
|
1234
|
+
override: "src.override",
|
|
1235
|
+
jsdelivr: "src.jsdelivr",
|
|
1236
|
+
raw: "src.raw",
|
|
1237
|
+
cache: "src.cache"
|
|
1238
|
+
};
|
|
1239
|
+
return lookup(map[data.source] || data.source);
|
|
1240
|
+
}
|
|
1241
|
+
function configStatusLabel(status) {
|
|
1242
|
+
return lookup(`settings.status.${status || "loading"}` || "settings.status.loading");
|
|
1243
|
+
}
|
|
1244
|
+
var STATUS_BADGE = { ready: "", pending: "info", rejected: "warn", unavailable: "err", loading: "info" };
|
|
1245
|
+
function SettingsTab({ notify, onRegistryChanged }) {
|
|
720
1246
|
const reg = useAsync((force) => api("registry", force ? { force: true } : {}), []);
|
|
1247
|
+
const cfgState = useAsync(() => api("registry-config"), []);
|
|
721
1248
|
const self = useAsync(() => api("self-check"), []);
|
|
722
1249
|
const [busy, setBusy] = useState(false);
|
|
723
1250
|
const [upgrading, setUpgrading] = useState(false);
|
|
1251
|
+
const [draftAddress, setDraftAddress] = useState(null);
|
|
1252
|
+
const [applying, setApplying] = useState(false);
|
|
1253
|
+
const [downloading, setDownloading] = useState(false);
|
|
1254
|
+
const [diagnosing, setDiagnosing] = useState(false);
|
|
1255
|
+
const [applyError, setApplyError] = useState(null);
|
|
1256
|
+
const [diagnosticResult, setDiagnosticResult] = useState(null);
|
|
1257
|
+
const diagnoseAbort = useRef(null);
|
|
1258
|
+
const cfgData = cfgState.data;
|
|
1259
|
+
useEffect(() => {
|
|
1260
|
+
if (draftAddress === null && cfgData) setDraftAddress(cfgData.registryUrl ?? "");
|
|
1261
|
+
}, [cfgData, draftAddress]);
|
|
1262
|
+
useEffect(() => () => diagnoseAbort.current?.abort(), []);
|
|
724
1263
|
const refresh = async () => {
|
|
725
1264
|
setBusy(true);
|
|
726
1265
|
try {
|
|
727
1266
|
await reg.reload(true);
|
|
728
|
-
notify({ kind: "ok", text: lookup("registry.refreshed") });
|
|
1267
|
+
notify({ kind: "ok", text: lookup("registry.refreshed"), needsRestart: false });
|
|
729
1268
|
} finally {
|
|
730
1269
|
setBusy(false);
|
|
731
1270
|
}
|
|
732
1271
|
};
|
|
733
|
-
const
|
|
734
|
-
|
|
1272
|
+
const reloadRegistryState = async () => {
|
|
1273
|
+
await cfgState.reload().catch(() => void 0);
|
|
1274
|
+
};
|
|
1275
|
+
const applyAddress = async (raw) => {
|
|
1276
|
+
setApplying(true);
|
|
1277
|
+
setApplyError(null);
|
|
735
1278
|
try {
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
1279
|
+
await api("registry-config-apply", { registryUrl: raw });
|
|
1280
|
+
setDraftAddress(typeof raw === "string" ? raw.trim() : "");
|
|
1281
|
+
notify({ kind: "ok", text: raw.trim() === "" ? lookup("settings.reset.ok") : lookup("settings.apply.ok"), needsRestart: false });
|
|
1282
|
+
await reloadRegistryState();
|
|
1283
|
+
onRegistryChanged?.();
|
|
739
1284
|
} catch (e) {
|
|
740
|
-
|
|
1285
|
+
const message = String(e && e.message || e);
|
|
1286
|
+
setApplyError(message);
|
|
1287
|
+
await reloadRegistryState().catch(() => void 0);
|
|
741
1288
|
} finally {
|
|
742
|
-
|
|
1289
|
+
setApplying(false);
|
|
743
1290
|
}
|
|
744
1291
|
};
|
|
1292
|
+
const downloadDefault = async () => {
|
|
1293
|
+
setDownloading(true);
|
|
1294
|
+
try {
|
|
1295
|
+
const res = await api("registry-default-download");
|
|
1296
|
+
const text = JSON.stringify(res.registry, null, 2);
|
|
1297
|
+
const blob = new Blob([text], { type: "application/json;charset=utf-8" });
|
|
1298
|
+
const url = URL.createObjectURL(blob);
|
|
1299
|
+
const a = document.createElement("a");
|
|
1300
|
+
a.href = url;
|
|
1301
|
+
a.download = "registry.json";
|
|
1302
|
+
document.body.appendChild(a);
|
|
1303
|
+
a.click();
|
|
1304
|
+
a.remove();
|
|
1305
|
+
URL.revokeObjectURL(url);
|
|
1306
|
+
notify({ kind: "ok", text: lookup("settings.download.ok"), needsRestart: false });
|
|
1307
|
+
} catch (e) {
|
|
1308
|
+
notify({ kind: "err", text: lookup("settings.download.failed", { err: e && e.message || e }) });
|
|
1309
|
+
} finally {
|
|
1310
|
+
setDownloading(false);
|
|
1311
|
+
}
|
|
1312
|
+
};
|
|
1313
|
+
const runDiagnose = async () => {
|
|
1314
|
+
diagnoseAbort.current?.abort();
|
|
1315
|
+
const ac = new AbortController();
|
|
1316
|
+
diagnoseAbort.current = ac;
|
|
1317
|
+
setDiagnosing(true);
|
|
1318
|
+
setDiagnosticResult(null);
|
|
1319
|
+
try {
|
|
1320
|
+
const res = await api("registry-diagnose", {}, ac.signal);
|
|
1321
|
+
if (!ac.signal.aborted) setDiagnosticResult(res.check);
|
|
1322
|
+
} catch (e) {
|
|
1323
|
+
if (!ac.signal.aborted) notify({ kind: "err", text: lookup("settings.diagnose.failed", { err: e && e.message || e }) });
|
|
1324
|
+
} finally {
|
|
1325
|
+
if (!ac.signal.aborted) setDiagnosing(false);
|
|
1326
|
+
}
|
|
1327
|
+
};
|
|
1328
|
+
const snap = cfgData || {};
|
|
1329
|
+
const state = snap.registryState || (reg.data ? reg.data.registryState : null) || null;
|
|
745
1330
|
return h(
|
|
746
1331
|
React.Fragment,
|
|
747
1332
|
null,
|
|
@@ -749,22 +1334,79 @@ function SettingsTab({ notify }) {
|
|
|
749
1334
|
lookup("settings.registry"),
|
|
750
1335
|
h(
|
|
751
1336
|
"div",
|
|
752
|
-
{ className: "dshm-
|
|
753
|
-
h("
|
|
754
|
-
|
|
1337
|
+
{ className: "dshm-row", style: { flexDirection: "column", alignItems: "stretch", gap: "4px" } },
|
|
1338
|
+
h("input", {
|
|
1339
|
+
className: "dshm-input",
|
|
1340
|
+
placeholder: lookup("settings.address.ph"),
|
|
1341
|
+
value: draftAddress ?? "",
|
|
1342
|
+
onChange: (e) => setDraftAddress(e.target.value),
|
|
1343
|
+
spellcheck: "false"
|
|
1344
|
+
}),
|
|
1345
|
+
h("div", { className: "dshm-note" }, lookup("settings.address.hint"))
|
|
1346
|
+
),
|
|
1347
|
+
h(
|
|
1348
|
+
"div",
|
|
1349
|
+
{ className: "dshm-actions" },
|
|
1350
|
+
h("button", {
|
|
1351
|
+
className: "dshm-btn primary sm",
|
|
1352
|
+
disabled: applying || diagnosing || draftAddress === null,
|
|
1353
|
+
onClick: () => applyAddress(draftAddress ?? "")
|
|
1354
|
+
}, applying ? h("span", null, lookup("settings.apply.applying"), " ", h(Spin)) : lookup("settings.apply")),
|
|
1355
|
+
h("button", {
|
|
1356
|
+
className: "dshm-btn sm",
|
|
1357
|
+
disabled: applying || draftAddress === null || (draftAddress ?? "").trim() === "",
|
|
1358
|
+
onClick: () => applyAddress("")
|
|
1359
|
+
}, lookup("settings.reset")),
|
|
1360
|
+
h("button", {
|
|
1361
|
+
className: "dshm-btn sm",
|
|
1362
|
+
disabled: downloading,
|
|
1363
|
+
onClick: downloadDefault
|
|
1364
|
+
}, downloading ? h("span", null, lookup("settings.download.downloading"), " ", h(Spin)) : lookup("settings.download")),
|
|
1365
|
+
h("button", {
|
|
1366
|
+
className: "dshm-btn sm",
|
|
1367
|
+
disabled: diagnosing || applying,
|
|
1368
|
+
onClick: runDiagnose
|
|
1369
|
+
}, diagnosing ? h("span", null, lookup("settings.diagnose.running"), " ", h(Spin)) : lookup("settings.diagnose")),
|
|
1370
|
+
h("button", { className: "dshm-btn sm", disabled: busy || reg.loading, onClick: refresh }, busy || reg.loading ? h(Spin) : lookup("settings.force"))
|
|
1371
|
+
),
|
|
1372
|
+
applyError ? h("div", { className: "dshm-err" }, lookup("settings.apply.failed", { err: applyError })) : null,
|
|
1373
|
+
h(
|
|
1374
|
+
"div",
|
|
1375
|
+
{ className: "dshm-kv", style: { marginTop: "4px" } },
|
|
1376
|
+
h("span", { className: "k" }, lookup("settings.configured")),
|
|
1377
|
+
h("span", null, snap.registryUrl ? h("span", { className: "dshm-code" }, snap.registryUrl) : h("span", { className: "dshm-hint" }, "\uFF08\u9ED8\u8BA4\uFF09")),
|
|
1378
|
+
h("span", { className: "k" }, lookup("settings.activecfg")),
|
|
1379
|
+
h("span", null, snap.activeConfigAddress ? h("span", { className: "dshm-code" }, snap.activeConfigAddress) : h("span", { className: "dshm-hint" }, "\uFF08\u9ED8\u8BA4\uFF09")),
|
|
1380
|
+
h("span", { className: "k" }, lookup("settings.status.label")),
|
|
1381
|
+
h("span", null, h("span", { className: `dshm-badge ${STATUS_BADGE[snap.configStatus] || ""}` }, configStatusLabel(snap.configStatus))),
|
|
1382
|
+
h("span", { className: "k" }, lookup("settings.effective")),
|
|
1383
|
+
h("span", null, regSourceLabel(state), state && !state.isDefault ? h("span", { className: "dshm-badge info", style: { marginLeft: "6px" } }, lookup("badge.custom")) : null),
|
|
755
1384
|
h("span", { className: "k" }, lookup("settings.updated")),
|
|
756
|
-
h("span", null, fmtDate(
|
|
1385
|
+
h("span", null, fmtDate(state && state.fetchedAt)),
|
|
757
1386
|
h("span", { className: "k" }, lookup("settings.count")),
|
|
758
|
-
h("span", null,
|
|
1387
|
+
h("span", null, state ? lookup("settings.count.v", { n: state.count ?? 0 }) : "\u2014"),
|
|
759
1388
|
h("span", { className: "k" }, lookup("settings.policy")),
|
|
760
1389
|
h("span", null, lookup("settings.policy.v"))
|
|
761
1390
|
),
|
|
762
|
-
|
|
763
|
-
h(
|
|
1391
|
+
state && state.stale && state.status !== "unavailable" ? h("div", { className: "dshm-note" }, lookup("settings.cache.hint")) : null,
|
|
1392
|
+
state && !state.isDefault ? h("div", { className: "dshm-note warn" }, lookup("settings.trust.hint")) : null,
|
|
1393
|
+
snap.warnings && snap.warnings.length ? h("div", { className: "dshm-note warn" }, `${lookup("settings.warnings")}\uFF1A${snap.warnings.join("\uFF1B")}`) : null,
|
|
1394
|
+
state && state.errors && state.errors.length ? h("div", { className: "dshm-err" }, `${lookup("settings.remotehint")}\uFF1A${state.errors.slice(0, 5).join("\uFF1B")}`) : null,
|
|
1395
|
+
diagnosticResult ? h(
|
|
764
1396
|
"div",
|
|
765
|
-
{ className: "dshm-
|
|
766
|
-
|
|
767
|
-
|
|
1397
|
+
{ className: "dshm-hint", style: { wordBreak: "break-all" } },
|
|
1398
|
+
lookup("settings.diagnose.result", {
|
|
1399
|
+
checked: diagnosticResult.checked ?? 0,
|
|
1400
|
+
passed: diagnosticResult.passed ?? 0,
|
|
1401
|
+
failed: diagnosticResult.failed ?? 0,
|
|
1402
|
+
trunc: diagnosticResult.truncated ? lookup("settings.diagnose.truncated") : ""
|
|
1403
|
+
}),
|
|
1404
|
+
diagnosticResult.issues && diagnosticResult.issues.length ? h(
|
|
1405
|
+
"div",
|
|
1406
|
+
{ style: { marginTop: "4px" } },
|
|
1407
|
+
diagnosticResult.issues.slice(0, 100).map((iss, i) => h("div", { key: i, className: "dshm-err" }, `\xB7 [${iss.id}] ${iss.field}: ${iss.message}`))
|
|
1408
|
+
) : h("div", { className: "dshm-note" }, lookup("settings.diagnose.none"))
|
|
1409
|
+
) : null
|
|
768
1410
|
),
|
|
769
1411
|
Section(
|
|
770
1412
|
lookup("settings.self"),
|
|
@@ -788,17 +1430,33 @@ function SettingsTab({ notify }) {
|
|
|
788
1430
|
h("div", { className: "dshm-hint" }, lookup("settings.about.text"))
|
|
789
1431
|
)
|
|
790
1432
|
);
|
|
1433
|
+
async function upgradeSelf() {
|
|
1434
|
+
setUpgrading(true);
|
|
1435
|
+
try {
|
|
1436
|
+
const res = await api("self-upgrade");
|
|
1437
|
+
notify({ kind: "ok", text: lookup("self.upgraded", { v: res.version }), needsRestart: true });
|
|
1438
|
+
await self.reload();
|
|
1439
|
+
} catch (e) {
|
|
1440
|
+
notify({ kind: "err", text: lookup("failed.selfupdate", { err: e && e.message || e }) });
|
|
1441
|
+
} finally {
|
|
1442
|
+
setUpgrading(false);
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
791
1445
|
}
|
|
792
|
-
function
|
|
793
|
-
if (
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
}
|
|
797
|
-
function Section(title, ...children) {
|
|
1446
|
+
function Section(title, sub, ...children) {
|
|
1447
|
+
if (sub != null && typeof sub !== "string") {
|
|
1448
|
+
children = [sub, ...children];
|
|
1449
|
+
sub = null;
|
|
1450
|
+
}
|
|
798
1451
|
return h(
|
|
799
1452
|
"div",
|
|
800
|
-
{
|
|
801
|
-
h(
|
|
1453
|
+
{ className: "dshm-section" },
|
|
1454
|
+
h(
|
|
1455
|
+
"div",
|
|
1456
|
+
{ className: "dshm-section-title" },
|
|
1457
|
+
title,
|
|
1458
|
+
sub ? h("span", { className: "dshm-section-sub" }, sub) : null
|
|
1459
|
+
),
|
|
802
1460
|
...children
|
|
803
1461
|
);
|
|
804
1462
|
}
|
|
@@ -809,11 +1467,11 @@ function DetailRows(rows) {
|
|
|
809
1467
|
{ className: "dshm-kv" },
|
|
810
1468
|
list.flatMap(([k, v]) => [
|
|
811
1469
|
h("span", { className: "k", key: `${k}-k` }, k),
|
|
812
|
-
h("span", { key: `${k}-v`, style: { wordBreak: "break-all" } },
|
|
1470
|
+
h("span", { key: `${k}-v`, style: { wordBreak: "break-all" } }, v)
|
|
813
1471
|
])
|
|
814
1472
|
);
|
|
815
1473
|
}
|
|
816
|
-
function Card({ icon, name, badges, desc, sub, open, onToggle, detail, actions }) {
|
|
1474
|
+
function Card({ icon, name, badges, desc, sub, links, open, onToggle, detail, actions }) {
|
|
817
1475
|
return h(
|
|
818
1476
|
"div",
|
|
819
1477
|
{
|
|
@@ -832,6 +1490,7 @@ function Card({ icon, name, badges, desc, sub, open, onToggle, detail, actions }
|
|
|
832
1490
|
h("div", { className: "dshm-top" }, h("span", { className: "dshm-name" }, name), ...badges.filter(Boolean)),
|
|
833
1491
|
h("div", { className: "dshm-desc", style: open ? { WebkitLineClamp: "unset" } : null }, desc),
|
|
834
1492
|
sub ? h("div", { className: "dshm-sub" }, sub) : null,
|
|
1493
|
+
links || null,
|
|
835
1494
|
open ? h("div", { className: "dshm-detail" }, detail) : null,
|
|
836
1495
|
open && actions && actions.length ? h("div", { className: "dshm-actions" }, ...actions) : null
|
|
837
1496
|
)
|
|
@@ -844,10 +1503,14 @@ var TABS = [
|
|
|
844
1503
|
];
|
|
845
1504
|
function MarketPanel({ onClose }) {
|
|
846
1505
|
const [tab, setTab] = useState("market");
|
|
847
|
-
const market =
|
|
1506
|
+
const market = useMarketData();
|
|
848
1507
|
const installed = useAsync(() => api("installed"), []);
|
|
1508
|
+
const onRegistryChanged = useCallback(async () => {
|
|
1509
|
+
await market.reload(false);
|
|
1510
|
+
await installed.reload().catch(() => void 0);
|
|
1511
|
+
}, [market, installed]);
|
|
849
1512
|
const counts = {
|
|
850
|
-
market: market.data ? market.data.
|
|
1513
|
+
market: market.data ? market.data.total : null,
|
|
851
1514
|
installed: installed.data ? installed.data.items.length : null
|
|
852
1515
|
};
|
|
853
1516
|
const [banner, setBanner] = useState(null);
|
|
@@ -864,9 +1527,9 @@ function MarketPanel({ onClose }) {
|
|
|
864
1527
|
const t = setTimeout(() => setToast(null), 6e3);
|
|
865
1528
|
return () => clearTimeout(t);
|
|
866
1529
|
}, [toast]);
|
|
867
|
-
const notify = useCallback(({ kind, text }) => {
|
|
1530
|
+
const notify = useCallback(({ kind, text, needsRestart }) => {
|
|
868
1531
|
setToast({ kind, text });
|
|
869
|
-
if (kind === "ok") setBanner({ text: lookup("banner.done") });
|
|
1532
|
+
if (kind === "ok" && needsRestart) setBanner({ text: lookup("banner.done") });
|
|
870
1533
|
}, []);
|
|
871
1534
|
return h(
|
|
872
1535
|
"div",
|
|
@@ -905,7 +1568,7 @@ function MarketPanel({ onClose }) {
|
|
|
905
1568
|
{ className: "dshm-body" },
|
|
906
1569
|
tab === "market" ? h(MarketTab, { notify, market }) : null,
|
|
907
1570
|
tab === "installed" ? h(InstalledTab, { notify, installed }) : null,
|
|
908
|
-
tab === "settings" ? h(SettingsTab, { notify }) : null
|
|
1571
|
+
tab === "settings" ? h(SettingsTab, { notify, onRegistryChanged }) : null
|
|
909
1572
|
),
|
|
910
1573
|
toast ? h(
|
|
911
1574
|
"div",
|
|
@@ -1045,6 +1708,7 @@ function ToolCardRow({ it, onInstalled }) {
|
|
|
1045
1708
|
),
|
|
1046
1709
|
h("div", { className: "dshm-desc" }, it.description),
|
|
1047
1710
|
h("div", { className: "dshm-sub" }, `${it.id} \xB7 ${(it.tags || []).join("\u3001") || it.category}`),
|
|
1711
|
+
h(LinksRow, { npm: it.npm, github: it.github, homepage: it.homepage }),
|
|
1048
1712
|
h(
|
|
1049
1713
|
"div",
|
|
1050
1714
|
{ className: "dshm-actions" },
|
|
@@ -1070,10 +1734,10 @@ function SearchToolView(props) {
|
|
|
1070
1734
|
let live = true;
|
|
1071
1735
|
api("search", { query, category: args.category, limit: args.limit }).then((d) => {
|
|
1072
1736
|
if (live) setItems(d.items || []);
|
|
1073
|
-
}).catch((
|
|
1737
|
+
}).catch(() => {
|
|
1074
1738
|
if (live) {
|
|
1075
1739
|
setItems([]);
|
|
1076
|
-
setErr(
|
|
1740
|
+
setErr(lookup("notice.toolview.err"));
|
|
1077
1741
|
}
|
|
1078
1742
|
});
|
|
1079
1743
|
return () => {
|