dsh-plugin-versions 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/client.js +64 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ DSH 官方的「版本」区块和更新按钮只出现在 **从 registry 安装
|
|
|
10
10
|
|
|
11
11
|
- 插件页新增第 4 个标签页「版本一览」(`plugins.tab`,`order: 40`)
|
|
12
12
|
- 先渲染本地版本,再逐行后台查 registry;只查 `updatable && !official` 的行,串行执行,避免同时打出一堆 pnpm 子进程
|
|
13
|
+
- 结果缓存在 `localStorage`(`dsh-plugin-versions:cache:v1`):再次打开先秒出上次的版本与状态,同时后台重新检查并逐行替换,表头显示「检查于 HH:MM」
|
|
13
14
|
- 状态分档:`可更新到 x` / `已是最新` / `随 DSH 更新` / `无官方版本区块` / 检查中… / 检查失败(附错误原文前 300 字)
|
|
14
15
|
- 可更新的行排前面,其余按包名排序
|
|
15
16
|
- 点一行 → `openPackage(name)` 打开官方组合包详情页,并自动滚到底,直接落在「版本」区块
|
package/client.js
CHANGED
|
@@ -129,11 +129,52 @@ window.__ModuleLoader__.load({
|
|
|
129
129
|
);
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
const CACHE_KEY = "dsh-plugin-versions:cache:v1";
|
|
133
|
+
|
|
134
|
+
function readCache() {
|
|
135
|
+
try {
|
|
136
|
+
const raw = window.localStorage.getItem(CACHE_KEY);
|
|
137
|
+
if (!raw) return null;
|
|
138
|
+
const d = JSON.parse(raw);
|
|
139
|
+
if (!d || typeof d !== "object" || !Array.isArray(d.bundles) || !d.rows) return null;
|
|
140
|
+
return d;
|
|
141
|
+
} catch (e) { return null; }
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function writeCache(bundles, rows, at) {
|
|
145
|
+
try {
|
|
146
|
+
const keep = {};
|
|
147
|
+
Object.keys(rows || {}).forEach((k) => {
|
|
148
|
+
const r = rows[k];
|
|
149
|
+
if (r && r.status === "ready") keep[k] = r;
|
|
150
|
+
});
|
|
151
|
+
window.localStorage.setItem(CACHE_KEY, JSON.stringify({
|
|
152
|
+
at: at || Date.now(),
|
|
153
|
+
bundles: bundles || [],
|
|
154
|
+
rows: keep
|
|
155
|
+
}));
|
|
156
|
+
} catch (e) { /* 缓存写失败不影响使用 */ }
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function clockText(ms) {
|
|
160
|
+
try {
|
|
161
|
+
const d = new Date(ms);
|
|
162
|
+
return String(d.getHours()).padStart(2, "0") + ":" + String(d.getMinutes()).padStart(2, "0");
|
|
163
|
+
} catch (e) { return ""; }
|
|
164
|
+
}
|
|
165
|
+
|
|
132
166
|
function VersionsTab(props) {
|
|
133
167
|
const ctx = props.ctx;
|
|
134
168
|
const openPackage = props.openPackage;
|
|
135
|
-
const
|
|
136
|
-
const [
|
|
169
|
+
const cached = readCache();
|
|
170
|
+
const [state, setState] = React.useState(
|
|
171
|
+
cached
|
|
172
|
+
? { status: "ready", bundles: cached.bundles, error: null }
|
|
173
|
+
: { status: "loading", bundles: [], error: null }
|
|
174
|
+
);
|
|
175
|
+
const [rows, setRows] = React.useState(cached ? cached.rows : {});
|
|
176
|
+
const [checkedAt, setCheckedAt] = React.useState(cached ? cached.at || 0 : 0);
|
|
177
|
+
const [refreshing, setRefreshing] = React.useState(true);
|
|
137
178
|
const [nonce, setNonce] = React.useState(0);
|
|
138
179
|
const [pmState, setPmState] = React.useState(null);
|
|
139
180
|
|
|
@@ -153,8 +194,7 @@ window.__ModuleLoader__.load({
|
|
|
153
194
|
|
|
154
195
|
const load = (pm) => {
|
|
155
196
|
setPmState(pm);
|
|
156
|
-
|
|
157
|
-
setRows({});
|
|
197
|
+
setRefreshing(true);
|
|
158
198
|
Promise.resolve().then(() => pm.listBundles()).then((res) => {
|
|
159
199
|
if (cancelled) return;
|
|
160
200
|
if (res && res.ok === false) {
|
|
@@ -163,7 +203,9 @@ window.__ModuleLoader__.load({
|
|
|
163
203
|
return;
|
|
164
204
|
}
|
|
165
205
|
const value = res && res.ok === true ? res.value : res;
|
|
166
|
-
|
|
206
|
+
const list = Array.isArray(value) ? value : [];
|
|
207
|
+
setState({ status: "ready", bundles: list, error: null });
|
|
208
|
+
setRows((prev) => { writeCache(list, prev, Date.now()); return prev; });
|
|
167
209
|
}).catch((err) => {
|
|
168
210
|
if (cancelled) return;
|
|
169
211
|
setState({ status: "error", bundles: [], error: String((err && err.message) || err) });
|
|
@@ -182,7 +224,6 @@ window.__ModuleLoader__.load({
|
|
|
182
224
|
setState({ status: "error", bundles: [], error: "拿不到 pluginManager。" + why });
|
|
183
225
|
};
|
|
184
226
|
|
|
185
|
-
setState({ status: "loading", bundles: [], error: null });
|
|
186
227
|
attempt();
|
|
187
228
|
return () => { cancelled = true; if (timer) clearTimeout(timer); };
|
|
188
229
|
}, [nonce]);
|
|
@@ -194,7 +235,9 @@ window.__ModuleLoader__.load({
|
|
|
194
235
|
(async () => {
|
|
195
236
|
for (const b of queue) {
|
|
196
237
|
if (cancelled) return;
|
|
197
|
-
setRows((prev) =>
|
|
238
|
+
setRows((prev) => (prev[b.name] && prev[b.name].status === "ready")
|
|
239
|
+
? prev
|
|
240
|
+
: Object.assign({}, prev, { [b.name]: { status: "loading" } }));
|
|
198
241
|
let next;
|
|
199
242
|
try {
|
|
200
243
|
const res = await pmState.listVersions(b.name, {});
|
|
@@ -208,8 +251,15 @@ window.__ModuleLoader__.load({
|
|
|
208
251
|
next = { status: "error", error: String((err && err.message) || err) };
|
|
209
252
|
}
|
|
210
253
|
if (cancelled) return;
|
|
211
|
-
setRows((prev) =>
|
|
254
|
+
setRows((prev) => {
|
|
255
|
+
const nextRows = Object.assign({}, prev, { [b.name]: next });
|
|
256
|
+
writeCache(state.bundles, nextRows, Date.now());
|
|
257
|
+
return nextRows;
|
|
258
|
+
});
|
|
212
259
|
}
|
|
260
|
+
if (cancelled) return;
|
|
261
|
+
setCheckedAt(Date.now());
|
|
262
|
+
setRefreshing(false);
|
|
213
263
|
})();
|
|
214
264
|
return () => { cancelled = true; };
|
|
215
265
|
}, [state.status, state.bundles, pmState]);
|
|
@@ -220,11 +270,16 @@ window.__ModuleLoader__.load({
|
|
|
220
270
|
const failed = installed.filter((b) => rows[b.name] && rows[b.name].status === "error").length;
|
|
221
271
|
const pending = installed.filter((b) => b.updatable === true && b.official !== true && !rows[b.name]).length;
|
|
222
272
|
const header = h("div", { style: S.bar },
|
|
223
|
-
h("span", { style: { opacity: 0.45, fontSize: "11px" } }, "版本一览
|
|
273
|
+
h("span", { style: { opacity: 0.45, fontSize: "11px" } }, "版本一览 v11"),
|
|
224
274
|
h("span", { style: S.muted },
|
|
225
275
|
state.status === "loading" ? "正在读取已安装组合包…" :
|
|
226
276
|
state.status === "error" ? "读取失败" :
|
|
227
277
|
((newer > 0 ? newer + " 个可更新" : (pending > 0 ? "正在检查…" : "全部已是最新")) + (failed > 0 ? " · " + failed + " 个检查失败" : "") + " · 共 " + installed.length + " 个已安装")),
|
|
278
|
+
h("span", { style: { opacity: 0.5, fontSize: "11px", marginLeft: "8px" } },
|
|
279
|
+
checkedAt ? ("检查于 " + clockText(checkedAt)) : ""),
|
|
280
|
+
refreshing && state.status !== "loading"
|
|
281
|
+
? h("span", { style: { opacity: 0.5, fontSize: "11px", marginLeft: "6px" } }, "刷新中…")
|
|
282
|
+
: null,
|
|
228
283
|
h("span", { style: { flex: "1 1 auto" } }),
|
|
229
284
|
h("button", { style: S.btn, onClick: () => setNonce(nonce + 1), disabled: state.status === "loading" }, "刷新")
|
|
230
285
|
);
|
package/package.json
CHANGED