dsh-m 0.9.74 → 0.9.76
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/CHANGELOG.md +28 -0
- package/lib/client.js +157 -27
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,20 @@ The full release history of dsh-m, maintained bilingually: **Chinese first, Engl
|
|
|
8
8
|
|
|
9
9
|
## 中文
|
|
10
10
|
|
|
11
|
+
### 0.9.76 修复:三项展示层退役与吸顶跳动根治——「对话」徽章/「版本无关」徽章退役 + 分类行滚动锚定自激断路
|
|
12
|
+
|
|
13
|
+
- **① 「对话」来源徽章退役(主人实拍:界面全点按钮却全员误标「对话」)**:`meta.session` 是 0.7.0 终审·新伤1 的**泵所有权标记**(restore 跳过 / replaceAll 不回卷 / persist 时剥离),GUI 的 `runOp` 与对话区镜像两路无条件同打同一标——它区分不了来源,且重载后徽章整体蒸发。修复:opRowVm 删 session 派生、行渲染删徽章、CSS 与 i18n 键退役;`meta.session` 本职不动(数据模型零变更),来源区分留待未来 `meta.origin` 承载。
|
|
14
|
+
- **② 「版本无关」徽章退役(市场卡 + Modal 头)**:英文标签 Version-independent 19 字符把卡片最高价值资产——插件名——挤成 `D...`/`O...`;且同一事实在卡片描述文案(「版本无关,详见仓库。」)与 Modal Compat 行已双处存在,卡片徽章边际信息为零。设计原则落定:**卡片徽章行只放「别处拿不到且影响当下决策」的信息**(已实测/安装态/供给源),版本无关属详规层,由 Modal Compat 行(`modal.decoupled.*`)唯一承载;`snapshotOf` 数据字段保留(收藏/快照完整性);`badge.decoupled` 与 `badge.decoupled.tip` 两键退役。
|
|
15
|
+
- **③ 市场 tab 分类行吸顶高频跳动根治(主人实拍:三 tab 来回切换偶发疯狂上下蹦跳)**:Chrome 滚动锚定把「吸顶 stuck 翻转的高度变化」翻译成 scrollTop 补偿,哨兵(sticky wrap 内 top:-5px)被来回送进/送出视口 → IO stuck 每帧翻转 → sticky bar 在钉住/流内两形态间高频瞬移。触发面:tab 条件渲染重挂(stuck=false + IO 重新武装)× `.dshm-body` 保留的 scrollTop 落在哨兵边界 ±30px 敏感带(翻页 `scrollIntoView` 会把 scrollTop 送到 bar 边缘,命中概率大增)。修复:`.dshm-body` `overflow-anchor:none` 一行断驱动器;吸顶/哨兵/+N 裁剪几何零变更。非本批回归——吸顶/IO 为 0.9.52-0.9.59 机制,长期潜伏的边界 bug。
|
|
16
|
+
- **验证**:1379 项测试全绿(render-smoke 新增退役负向锚与锚定停用/吸顶几何契约锚)、typecheck 零错误;三项均为展示层修复,数据模型零迁移;client-only——刷新页面即生效。
|
|
17
|
+
|
|
18
|
+
### 0.9.75 功能:操作记录信息增强——行内时刻/按日分组/开关方向/耗时/版本变迁/来源标记(数据零迁移)
|
|
19
|
+
|
|
20
|
+
- **背景(主人设置页实拍:开关记录读不出「开还是关」)**:操作记录行只有「状态 + 类型 + 包名」三要素——开关看不出方向(截图里连续两条 `开关 @iasiv5/dsh-quota-watch` 无法分辨先后开/关)、无任何时间、看不出耗时、看不出对话区发起还是界面点击、升级不知道版本从哪到哪。而这些信息**全部已在每条记录里**(`createdAt`/`updatedAt` 是 store 打点常态、`meta.on` 0.4.0 起就随开关入账、`meta.session` 是泵拾取标记)——纯展示层缺口,非数据缺失;浏览器 localStorage(`dshm-operations`)里的存量旧记录升级后立即可读,零迁移。
|
|
21
|
+
- **方案(展示派生全部收敛纯函数模块)**:新增 `src/client/operations-view.js`(`fmtOpClock`/`fmtOpFull`/`opDayKey`/`fmtOpDuration`/`opUpgradeMeta`/`groupOpsByDay`/`opRowVm`,Node tests 直测,惯例同 toggle-view):① 行内 `HH:mm`(tabular-nums 对齐,title 完整到秒);② 已结束**按日分组**,组头 今天/昨天/YYYY-MM-DD,**新组在上、组内新→旧**——最新一条贴「已结束」标题可见,不再沉底滚动找;③ 开关/社区开关按 `meta.on` 渲染 `开`(绿)/`关`(灰)徽章——原「社区开关专属方向渲染」(0.9.71 评审 M1 `targetText`)退役为泛化实现;④ 终态耗时 `<1s/42s/1m02s/3h05m`(免翻译);⑤ 升级行版本变迁 `v0.9.71→v0.9.72`(github 源回退 sha 前 7 位,与 notify.upgraded 口径一致);⑥ `meta.session` 行加「对话」来源徽章;⑦ 「已结束(N)」计数(无计数旧键 `settings.ops.group.done` 退役)。字段缺席逐段省略,旧行形态优雅回退;字号守 0.9.67 十二 px 家族,徽章 `currentColor` 描边自适应主题。
|
|
22
|
+
- **数据管道(唯一一处非展示层改动)**:执行泵成功路径支持执行器回传 `value.opMeta` 并入记录 meta——底座取**落账时实读**的当前 meta(入队快照会丢拾取阶段追加的 session 标记,破「陈旧快照不回卷」保证,评审自纠);失败路径不入账(结果不可信)。恢复路径(`dispatchRestored`)成功值统一接进成功值通道(`value = r`)——生产实现今日返回 `{ ok: true }`,对现有流零行为变化;两处 `doUpgrade` 调用点把 `fromVersion/version/sha` 管道为 `opMeta`。
|
|
23
|
+
- **验证**:1375 项测试全绿(0.9.74 基线 1339 + 新增 36:`client-operations-view` 27 用例含格式化 TZ 无关派生/分组序/行 VM 回退/新病灶负向锚(`targetText` 与无计数旧键不得残留)+ 泵 opMeta 4 用例(done/warned 入账、失败与脏输入不入、恢复路径入账、session 保留))、typecheck 零错误;构建产物含新规则逐字锚。
|
|
24
|
+
|
|
11
25
|
### 0.9.74 功能:详情截图条滚轮横滚——裸滚轮 deltaY 安全映射 scrollLeft(钢人三红线)
|
|
12
26
|
|
|
13
27
|
- **背景(主人验收 0.9.73 实拍反馈)**:截图条是横滚容器,鼠标滚轮在横滚容器上默认纵滚祖先(弹窗)——图片多时纯鼠标用户只能拖 ~700px 细滚动条(离散目标上的连续输入,精度成本极高);触控板双指横滑(deltaX)与 Shift+滚轮虽有原生路径,但属隐藏知识不可达。
|
|
@@ -545,6 +559,20 @@ The full release history of dsh-m, maintained bilingually: **Chinese first, Engl
|
|
|
545
559
|
|
|
546
560
|
## English
|
|
547
561
|
|
|
562
|
+
### Fix in 0.9.76 — three presentation-layer retirements and sticky-chips jitter fixed at the root: "Chat" badge / "Version-independent" badge retired + scroll-anchoring self-excitation cut on the category row
|
|
563
|
+
|
|
564
|
+
- **① "Chat" source badge retired (owner screenshot: every row flagged despite all-UI clicks)**: `meta.session` is the **pump-ownership marker** from the 0.7.0 final review (restore skip / replaceAll no-rollback / stripped on persist) — both the GUI `runOp` path and the chat-mirror path set it unconditionally, so it cannot distinguish origins, and the badge vanishes entirely after a page reload. Fix: opRowVm drops the session derivation; the row badge, its CSS and i18n keys retire; `meta.session` keeps its day job (zero data-model change); a future `meta.origin` would be the honest carrier for source attribution.
|
|
565
|
+
- **② "Version-independent" badge retired (market card + modal head)**: the 19-character English label squeezed the card's highest-value asset — the plugin name — into `D...`/`O...`, while the same fact already lived twice next to it (the card description text and the modal Compat row), leaving the card badge zero marginal information. Design rule settled: **card badge rows carry only information unavailable elsewhere and relevant to the decision at hand** (verified / installed / source); decoupled belongs to the detail layer, solely carried by the modal Compat row (`modal.decoupled.*`); `snapshotOf` keeps the data field (favorites/snapshot integrity); `badge.decoupled` and `badge.decoupled.tip` retire.
|
|
566
|
+
- **③ Market-tab category-row high-frequency jitter fixed at the root (owner screenshot: wild bouncing after switching tabs back)**: Chrome scroll anchoring translated every stuck-toggle height change into a scrollTop compensation, shoving the sentinel (top:-5px inside the sticky wrap) in and out of the viewport → IO flipped stuck every frame → the sticky bar teleported between pinned and in-flow shapes. Trigger surface: conditional tab remount (stuck=false + re-armed IO) × `.dshm-body`'s preserved scrollTop landing in the ±30px sentinel boundary band (pagination `scrollIntoView` parks scrollTop right at the bar edge, raising the odds). Fix: one line — `.dshm-body` `overflow-anchor:none` — cuts the loop at its driver; sticky/sentinel/+N clip geometry untouched. Not a regression from this batch — the sticky/IO machinery dates to 0.9.52–0.9.59; a long-latent boundary bug.
|
|
567
|
+
- **Verification**: 1379 tests all green (render-smoke gains retirement negative anchors plus anchoring-off / sticky-geometry contract anchors), typecheck clean; all three are presentation-layer fixes with zero data-model migration; client-only — a page refresh takes effect.
|
|
568
|
+
|
|
569
|
+
### Feature in 0.9.75 — operations log enrichment: inline clock/day groups/toggle direction/duration/upgrade versions/chat source (zero data migration)
|
|
570
|
+
|
|
571
|
+
- **Background (owner screenshot: toggle records unreadable as on/off)**: each operations row carried only "status + kind + package" — a toggle showed no direction (two consecutive `toggle @iasiv5/dsh-quota-watch` rows in the screenshot were indistinguishable), no timestamp, no duration, no chat-vs-UI source, no upgrade from→to versions. Yet **all of this already exists per record** (`createdAt`/`updatedAt` are store bookkeeping, `meta.on` has been recorded with every toggle since 0.4.0, `meta.session` is the pump pickup marker) — a pure presentation gap, not missing data. Existing records in browser localStorage (`dshm-operations`) become readable right after upgrade, zero migration.
|
|
572
|
+
- **Approach (all display derivation in one pure module)**: new `src/client/operations-view.js` (`fmtOpClock`/`fmtOpFull`/`opDayKey`/`fmtOpDuration`/`opUpgradeMeta`/`groupOpsByDay`/`opRowVm`, directly unit-tested, same convention as toggle-view): ① inline `HH:mm` (tabular-nums, full-to-second time in title); ② finished records **grouped by local day**, headers Today/Yesterday/YYYY-MM-DD, **newest group on top, newest-first within** — the latest row sits right under the "Ended" caption instead of sinking to the scroll bottom; ③ toggles render an `On` (green) / `Off` (grey) badge from `meta.on` — the 0.9.71 community-toggle-only direction rendering (`targetText`) retires into this generalized path; ④ terminal duration `<1s/42s/1m02s/3h05m` (translation-free); ⑤ upgrade rows show `v0.9.71→v0.9.72` (github source falls back to 7-char sha, consistent with notify.upgraded); ⑥ `meta.session` rows get a "Chat" source badge; ⑦ "Ended (N)" count (the count-less key `settings.ops.group.done` retires). Missing fields omit their segment — old records degrade to the previous row shape; 12px type-family discipline (0.9.67) kept, badges use `currentColor` borders to follow the theme.
|
|
573
|
+
- **Data plumbing (the single non-presentation change)**: the pump's success path now merges an executor-returned `value.opMeta` into the record meta — the merge base is the **freshly read** meta at finalize time (the enqueue snapshot lacks the pickup-time session marker and would break the stale-snapshot no-rollback guarantee; caught in self-review); failures never merge (result untrustworthy). The restored path (`dispatchRestored`) now routes its success value through the same channel (`value = r`) — the production implementation returns `{ ok: true }` today, so existing flows are behavior-unchanged; both `doUpgrade` call sites pipe `fromVersion/version/sha` into `opMeta`.
|
|
574
|
+
- **Verification**: 1375 tests all green (0.9.74 baseline 1339 + 36 new: `client-operations-view` 27 cases covering TZ-agnostic time formatting, group ordering, row-VM fallbacks, and negative anchors against the retired `targetText`/count-less key; 4 pump opMeta cases covering done/warned merge, failure & dirty-input rejection, restored-path merge, session preservation), typecheck clean; build artifact carries the new rules verbatim.
|
|
575
|
+
|
|
548
576
|
### Feature in 0.9.74 — screenshot-strip wheel hscroll: bare-wheel deltaY safely mapped to scrollLeft (steelman's three red lines)
|
|
549
577
|
|
|
550
578
|
- **Background (owner feedback while verifying 0.9.73)**: the strip is a horizontal scroll container, and a mouse wheel over it scrolls the ancestor (the modal) by default — with many screenshots, mouse-only users must drag a ~700px thin scrollbar (continuous input on a discrete target); trackpad two-finger hscroll (deltaX) and Shift+wheel exist natively but are hidden knowledge.
|
package/lib/client.js
CHANGED
|
@@ -1511,6 +1511,7 @@ function createOpsPump(store, getCtx) {
|
|
|
1511
1511
|
} else if (ctx && ctx.dispatchRestored) {
|
|
1512
1512
|
const r = await ctx.dispatchRestored(queued);
|
|
1513
1513
|
if (!r || !r.ok) err = Object.assign(new Error(r && r.error || "unknown"), r && r.issue ? { issue: r.issue } : {});
|
|
1514
|
+
else value = r;
|
|
1514
1515
|
} else {
|
|
1515
1516
|
err = new Error("\u65E0\u6267\u884C\u4E0A\u4E0B\u6587\uFF08\u9762\u677F\u672A\u6302\u8F7D\uFF09");
|
|
1516
1517
|
}
|
|
@@ -1518,7 +1519,13 @@ function createOpsPump(store, getCtx) {
|
|
|
1518
1519
|
err = e;
|
|
1519
1520
|
}
|
|
1520
1521
|
if (!err) {
|
|
1521
|
-
|
|
1522
|
+
const opMeta = value && typeof value === "object" && value.opMeta && typeof value.opMeta === "object" ? value.opMeta : null;
|
|
1523
|
+
const cur = opMeta ? store.list().find((x) => x.id === queued.id) : null;
|
|
1524
|
+
finalize({
|
|
1525
|
+
status: value && value.opWarning ? "warned" : "done",
|
|
1526
|
+
warning: value && value.opWarning,
|
|
1527
|
+
...opMeta ? { meta: { ...cur && cur.meta || {}, ...opMeta } } : {}
|
|
1528
|
+
});
|
|
1522
1529
|
if (waitersEntry) waitersEntry.resolve(value);
|
|
1523
1530
|
} else {
|
|
1524
1531
|
const isInput = Boolean(err.issue);
|
|
@@ -1586,6 +1593,89 @@ var init_operations = __esm({
|
|
|
1586
1593
|
}
|
|
1587
1594
|
});
|
|
1588
1595
|
|
|
1596
|
+
// src/client/operations-view.js
|
|
1597
|
+
var operations_view_exports = {};
|
|
1598
|
+
__export(operations_view_exports, {
|
|
1599
|
+
fmtOpClock: () => fmtOpClock,
|
|
1600
|
+
fmtOpDuration: () => fmtOpDuration,
|
|
1601
|
+
fmtOpFull: () => fmtOpFull,
|
|
1602
|
+
groupOpsByDay: () => groupOpsByDay,
|
|
1603
|
+
opDayKey: () => opDayKey,
|
|
1604
|
+
opRowVm: () => opRowVm,
|
|
1605
|
+
opUpgradeMeta: () => opUpgradeMeta,
|
|
1606
|
+
pad2: () => pad2
|
|
1607
|
+
});
|
|
1608
|
+
function pad2(n) {
|
|
1609
|
+
return String(n).padStart(2, "0");
|
|
1610
|
+
}
|
|
1611
|
+
function fmtOpClock(ts) {
|
|
1612
|
+
const d = new Date(ts);
|
|
1613
|
+
return `${pad2(d.getHours())}:${pad2(d.getMinutes())}`;
|
|
1614
|
+
}
|
|
1615
|
+
function fmtOpFull(ts) {
|
|
1616
|
+
const d = new Date(ts);
|
|
1617
|
+
return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())} ${fmtOpClock(ts)}:${pad2(d.getSeconds())}`;
|
|
1618
|
+
}
|
|
1619
|
+
function opDayKey(ts) {
|
|
1620
|
+
const d = new Date(ts);
|
|
1621
|
+
return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
|
|
1622
|
+
}
|
|
1623
|
+
function fmtOpDuration(ms) {
|
|
1624
|
+
if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0) return "";
|
|
1625
|
+
if (ms < 1e3) return "<1s";
|
|
1626
|
+
const s = Math.floor(ms / 1e3);
|
|
1627
|
+
if (s < 60) return `${s}s`;
|
|
1628
|
+
const m = Math.floor(s / 60);
|
|
1629
|
+
if (m < 60) return `${m}m${pad2(s % 60)}s`;
|
|
1630
|
+
const hr = Math.floor(m / 60);
|
|
1631
|
+
return `${hr}h${pad2(m % 60)}m`;
|
|
1632
|
+
}
|
|
1633
|
+
function opUpgradeMeta(res) {
|
|
1634
|
+
if (!res || typeof res !== "object") return null;
|
|
1635
|
+
const from = res.fromVersion ? String(res.fromVersion) : "";
|
|
1636
|
+
const to = res.version ? String(res.version) : res.sha ? String(res.sha).slice(0, 7) : "";
|
|
1637
|
+
return from || to ? { from, to } : null;
|
|
1638
|
+
}
|
|
1639
|
+
function groupOpsByDay(records, now = Date.now()) {
|
|
1640
|
+
const list = Array.isArray(records) ? records.filter(Boolean) : [];
|
|
1641
|
+
const todayKey = opDayKey(now);
|
|
1642
|
+
const yesterdayKey = opDayKey(now - 864e5);
|
|
1643
|
+
const byDay = /* @__PURE__ */ new Map();
|
|
1644
|
+
for (const r of list) {
|
|
1645
|
+
const key = r && Number.isFinite(r.createdAt) ? opDayKey(r.createdAt) : "";
|
|
1646
|
+
if (!byDay.has(key)) byDay.set(key, []);
|
|
1647
|
+
byDay.get(key).push(r);
|
|
1648
|
+
}
|
|
1649
|
+
const kindOf = (key) => key === todayKey ? "today" : key === yesterdayKey ? "yesterday" : "date";
|
|
1650
|
+
return [...byDay.entries()].sort((a, b) => a[0] < b[0] ? 1 : a[0] > b[0] ? -1 : 0).map(([key, rs]) => ({ key, kind: kindOf(key), records: rs.slice().reverse() }));
|
|
1651
|
+
}
|
|
1652
|
+
function opRowVm(r) {
|
|
1653
|
+
const rec = r || {};
|
|
1654
|
+
const meta = rec.meta && typeof rec.meta === "object" ? rec.meta : {};
|
|
1655
|
+
const ts = Number.isFinite(rec.createdAt) ? rec.createdAt : null;
|
|
1656
|
+
const durMs = rec.status && TERMINAL_CLEARABLE.has(rec.status) && Number.isFinite(rec.createdAt) && Number.isFinite(rec.updatedAt) ? Math.max(0, rec.updatedAt - rec.createdAt) : null;
|
|
1657
|
+
const isToggle = rec.kind === "toggle" || rec.kind === "community-toggle";
|
|
1658
|
+
let version = "";
|
|
1659
|
+
if (rec.kind === "upgrade") {
|
|
1660
|
+
const m = opUpgradeMeta({ fromVersion: meta.from, version: meta.to });
|
|
1661
|
+
if (m) version = `${m.from ? `v${m.from}` : ""}\u2192${m.to ? `v${m.to}` : ""}`;
|
|
1662
|
+
}
|
|
1663
|
+
return {
|
|
1664
|
+
clock: ts === null ? "" : fmtOpClock(ts),
|
|
1665
|
+
full: ts === null ? "" : fmtOpFull(ts),
|
|
1666
|
+
durText: durMs === null ? "" : fmtOpDuration(durMs),
|
|
1667
|
+
dir: isToggle && typeof meta.on === "boolean" ? meta.on ? "on" : "off" : null,
|
|
1668
|
+
version,
|
|
1669
|
+
target: typeof rec.target === "string" ? rec.target : ""
|
|
1670
|
+
};
|
|
1671
|
+
}
|
|
1672
|
+
var init_operations_view = __esm({
|
|
1673
|
+
"src/client/operations-view.js"() {
|
|
1674
|
+
"use strict";
|
|
1675
|
+
init_operations();
|
|
1676
|
+
}
|
|
1677
|
+
});
|
|
1678
|
+
|
|
1589
1679
|
// src/client/favorites.js
|
|
1590
1680
|
var favorites_exports = {};
|
|
1591
1681
|
__export(favorites_exports, {
|
|
@@ -1792,6 +1882,7 @@ var { RESTART_POLL_MS: RESTART_POLL_MS2, RESTART_DEADLINE_MS: RESTART_DEADLINE_M
|
|
|
1792
1882
|
var { refreshAfterMutation: refreshAfterMutation2 } = (init_view_refresh(), __toCommonJS(view_refresh_exports));
|
|
1793
1883
|
var { applyInstalledUpdates: applyInstalledUpdates2, installedUpdateStats: installedUpdateStats2 } = (init_installed_updates(), __toCommonJS(installed_updates_exports));
|
|
1794
1884
|
var { createOperationsStore: createOperationsStore2, restoreRecords: restoreRecords2, createOpsPump: createOpsPump2, opAppliesTo: opAppliesTo2, TERMINAL_CLEARABLE: TERMINAL_CLEARABLE2, upgradeNotify: upgradeNotify2, REGISTRY_DEFAULT_TARGET: REGISTRY_DEFAULT_TARGET2 } = (init_operations(), __toCommonJS(operations_exports));
|
|
1885
|
+
var { groupOpsByDay: groupOpsByDay2, opRowVm: opRowVm2, opUpgradeMeta: opUpgradeMeta2 } = (init_operations_view(), __toCommonJS(operations_view_exports));
|
|
1795
1886
|
var { createFavoritesStore: createFavoritesStore2, partitionStale: partitionStale2 } = (init_favorites(), __toCommonJS(favorites_exports));
|
|
1796
1887
|
var { readSelfCheckCache: readSelfCheckCache2, writeSelfCheckCache: writeSelfCheckCache2, clearSelfCheckCache: clearSelfCheckCache2, deriveChipState: deriveChipState2 } = (init_self_check(), __toCommonJS(self_check_exports));
|
|
1797
1888
|
var { shouldShowInstallCmd: shouldShowInstallCmd2 } = (init_install_cmd(), __toCommonJS(install_cmd_exports));
|
|
@@ -1813,8 +1904,6 @@ var ZH = {
|
|
|
1813
1904
|
"sub.snapshot": "v{v}\uFF08\u76EE\u5F55\u5FEB\u7167\uFF09",
|
|
1814
1905
|
"badge.verified": "\u5DF2\u5B9E\u6D4B",
|
|
1815
1906
|
"badge.internal": "\u4F5C\u8005\u81EA\u7528",
|
|
1816
|
-
"badge.decoupled": "\u7248\u672C\u65E0\u5173",
|
|
1817
|
-
"badge.decoupled.tip": "DSH \u5347\u7EA7\u65E0\u9700\u8DDF\u968F\u9002\u914D",
|
|
1818
1907
|
"modal.category": "\u5206\u7C7B",
|
|
1819
1908
|
"modal.added": "\u6536\u5F55\u65E5\u671F",
|
|
1820
1909
|
"modal.dlwindow": "\u4E0B\u8F7D\u91CF\uFF0830 \u5929\u7A97\u53E3\uFF09",
|
|
@@ -1851,6 +1940,9 @@ var ZH = {
|
|
|
1851
1940
|
"op.status.warned": "\u5E26\u8B66\u544A",
|
|
1852
1941
|
"op.status.failed": "\u5931\u8D25",
|
|
1853
1942
|
"op.status.superseded": "\u5DF2\u8DF3\u8FC7",
|
|
1943
|
+
"op.day.today": "\u4ECA\u5929",
|
|
1944
|
+
"op.day.yesterday": "\u6628\u5929",
|
|
1945
|
+
"settings.ops.group.done.n": "\u5DF2\u7ED3\u675F\uFF08{n}\uFF09",
|
|
1854
1946
|
"favorites.hint": "\u8FD8\u6CA1\u6709\u6536\u85CF\u2014\u2014\u53BB\u793E\u533A/\u7CBE\u9009\u9875\u70B9\u63D2\u4EF6\u5361\u7247\u53F3\u4E0A\u89D2\u7684 \u2606 \u6536\u85CF",
|
|
1855
1947
|
"favorites.stale": "{n} \u6761\u6536\u85CF\u5DF2\u4ECE\u76EE\u5F55\u4E0B\u67B6",
|
|
1856
1948
|
"favorites.clean": "\u6E05\u7406\u5931\u6548\u6536\u85CF",
|
|
@@ -2015,7 +2107,6 @@ var ZH = {
|
|
|
2015
2107
|
"settings.ops": "\u64CD\u4F5C\u8BB0\u5F55",
|
|
2016
2108
|
"settings.ops.empty": "\u6682\u65E0\u64CD\u4F5C\u8BB0\u5F55\u3002\u5B89\u88C5\u3001\u5347\u7EA7\u3001\u5378\u8F7D\u3001\u5F00\u5173\u4E0E\u4F9B\u7ED9\u9762\u8BBE\u7F6E\uFF08\u6E05\u5355\u6E90\u3001\u793E\u533A\u76EE\u5F55\uFF09\u7684\u6267\u884C\u5386\u53F2\u5C06\u5728\u8FD9\u91CC\u663E\u793A\u3002",
|
|
2017
2109
|
"settings.ops.group.active": "\u8FDB\u884C\u4E2D",
|
|
2018
|
-
"settings.ops.group.done": "\u5DF2\u7ED3\u675F",
|
|
2019
2110
|
"settings.ops.reddot": "\u5B58\u5728\u5931\u8D25\u6216\u5E26\u8B66\u544A\u7684\u64CD\u4F5C\u8BB0\u5F55",
|
|
2020
2111
|
"registry.refreshed": "\u6536\u5F55\u6E05\u5355\u5DF2\u5F3A\u5236\u5237\u65B0",
|
|
2021
2112
|
"notify.installed": "\u5DF2\u5B89\u88C5 {pkg}{version}",
|
|
@@ -2104,8 +2195,6 @@ var EN = {
|
|
|
2104
2195
|
"sub.snapshot": "v{v} (catalog snapshot)",
|
|
2105
2196
|
"badge.verified": "Verified",
|
|
2106
2197
|
"badge.internal": "Author's own",
|
|
2107
|
-
"badge.decoupled": "Version-independent",
|
|
2108
|
-
"badge.decoupled.tip": "Survives DSH upgrades without per-release adaptation",
|
|
2109
2198
|
"modal.category": "Category",
|
|
2110
2199
|
"modal.added": "Added",
|
|
2111
2200
|
"modal.dlwindow": "Downloads (30-day window)",
|
|
@@ -2142,6 +2231,9 @@ var EN = {
|
|
|
2142
2231
|
"op.status.warned": "Warned",
|
|
2143
2232
|
"op.status.failed": "Failed",
|
|
2144
2233
|
"op.status.superseded": "Skipped",
|
|
2234
|
+
"op.day.today": "Today",
|
|
2235
|
+
"op.day.yesterday": "Yesterday",
|
|
2236
|
+
"settings.ops.group.done.n": "Ended ({n})",
|
|
2145
2237
|
"favorites.hint": "No favorites yet \u2014 tap \u2606 on a plugin card in Community/Curated to bookmark it",
|
|
2146
2238
|
"favorites.stale": "{n} favorites no longer in the catalog",
|
|
2147
2239
|
"favorites.clean": "Clean up stale favorites",
|
|
@@ -2306,7 +2398,6 @@ var EN = {
|
|
|
2306
2398
|
"settings.ops": "Operations",
|
|
2307
2399
|
"settings.ops.empty": "No operations yet. History of installs, upgrades, uninstalls, toggles and registry / community catalog settings will appear here.",
|
|
2308
2400
|
"settings.ops.group.active": "Active",
|
|
2309
|
-
"settings.ops.group.done": "Finished",
|
|
2310
2401
|
"settings.ops.reddot": "Failed or warned operations exist",
|
|
2311
2402
|
"registry.refreshed": "Registry force-refreshed",
|
|
2312
2403
|
"notify.installed": "Installed {pkg}{version}",
|
|
@@ -2446,7 +2537,14 @@ var CSS = `
|
|
|
2446
2537
|
.dshm-seg .dshm-count{font-size:11px;font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-caption,#9ca3af);margin:0}
|
|
2447
2538
|
.dshm-seg button.on .dshm-count{color:var(--dsw-alias-state-business-primary,#4d6bfe)}
|
|
2448
2539
|
.dshm-spacer{flex:1}
|
|
2449
|
-
.
|
|
2540
|
+
/* 0.9.76 \u5206\u7C7B\u884C\u5438\u9876\u9AD8\u9891\u8DF3\u52A8\u6839\u6CBB\uFF1AChrome \u6EDA\u52A8\u951A\u5B9A\uFF08scroll anchoring\uFF09\u628A\u300C\u5438\u9876\u6536\u5C55\u7684
|
|
2541
|
+
\u9AD8\u5EA6\u53D8\u5316\u300D\u7FFB\u8BD1\u6210 scrollTop \u8865\u507F\uFF08\u2248\u4E00\u4E2A\u884C\u9AD8\uFF09\uFF0C\u54E8\u5175\uFF08wrap \u5185 top:-5px\uFF09\u56E0\u6B64\u88AB\u6765\u56DE\u9001\u8FDB/
|
|
2542
|
+
\u9001\u51FA\u89C6\u53E3 \u2192 IO stuck \u6BCF\u5E27\u7FFB\u8F6C \u2192 chips \u884C\u9AD8\u9891\u8E66\u8DF3\u3002\u89E6\u53D1\u6761\u4EF6\uFF1Atab \u6761\u4EF6\u6E32\u67D3\u91CD\u6302\u56DE\u5230\u5E02\u573A
|
|
2543
|
+
\uFF08stuck=false + IO \u91CD\u65B0\u6B66\u88C5\uFF09\u4E14 .dshm-body \u4FDD\u7559\u7684 scrollTop \u6070\u843D\u5728\u54E8\u5175\u8FB9\u754C \xB130px \u5E26\u5185
|
|
2544
|
+
\uFF08\u7FFB\u9875 scrollIntoView \u4F1A\u628A scrollTop \u7CBE\u786E\u9001\u5230 bar \u8FB9\u7F18\uFF0C\u547D\u4E2D\u6982\u7387\u5927\u589E\uFF09\u3002\u951A\u5B9A\u5728\u672C\u6EDA\u52A8
|
|
2545
|
+
\u5BB9\u5668\u505C\u7528\u540E\uFF0Cstuck \u7FFB\u8F6C\u4E0D\u518D\u79FB\u52A8\u54E8\u5175\uFF0C\u5FAA\u73AF\u5728\u9A71\u52A8\u5668\u5904\u65AD\u5F00\uFF1B\u9762\u677F\u5185\u5BB9\u53EA\u5411\u4E0B\u5206\u9875\u8FFD\u52A0\u3001
|
|
2546
|
+
\u65E0\u4E0A\u65B9\u61D2\u52A0\u8F7D\u5E03\u5C40\uFF0C\u951A\u5B9A\u635F\u5931\u8D8B\u96F6\u3002 */
|
|
2547
|
+
.dshm-body{flex:1;overflow:auto;padding:14px;display:flex;flex-direction:column;gap:12px;overflow-anchor:none}
|
|
2450
2548
|
.dshm-hint{color:var(--dsw-alias-label-caption,#6b7280);font-size:12px;line-height:18px;margin:0}
|
|
2451
2549
|
.dshm-err{color:var(--dsw-alias-state-error-primary,#b91c1c);font-size:12px;line-height:18px}
|
|
2452
2550
|
.dshm-ok{color:var(--dsw-alias-state-success-primary,#047857);font-size:12px;line-height:18px;word-break:break-word}
|
|
@@ -2605,6 +2703,17 @@ var CSS = `
|
|
|
2605
2703
|
.dsvm-opkind{color:var(--dsw-alias-label-secondary,#4b5563)}
|
|
2606
2704
|
.dsvm-optarget{font-weight:500;overflow-wrap:anywhere}
|
|
2607
2705
|
.dsvm-opnote{color:var(--dsw-alias-label-caption,#6b7280);font-size:11px;overflow-wrap:anywhere}
|
|
2706
|
+
/* 0.9.75 \u64CD\u4F5C\u8BB0\u5F55\u4FE1\u606F\u589E\u5F3A\uFF1A\u884C\u5185\u65F6\u95F4/\u8017\u65F6\uFF08tabular-nums \u5BF9\u9F50\uFF09\u3001\u6309\u65E5\u5206\u7EC4\u5934\u3001\u5F00\u5173\u65B9\u5411\u5FBD\u7AE0\u3001
|
|
2707
|
+
\u5347\u7EA7\u7248\u672C\u53D8\u8FC1\u3002\u5B57\u53F7\u5B88 0.9.67 \u7684 12px \u5BB6\u65CF\uFF08\u6B21\u7EA7 11px\uFF09\uFF0C\u989C\u8272\u6CBF\u7528\u65E2\u6709\u8BED\u4E49\uFF1A
|
|
2708
|
+
\u65B9\u5411\u300C\u5F00\u300D\u7528 ok \u540C\u6B3E\u7EFF\uFF0C\u300C\u5173\u300D\u7528\u6B21\u7EA7\u7070\uFF1B\u5FBD\u7AE0 currentColor \u63CF\u8FB9\u81EA\u9002\u5E94\u6DF1\u6D45\u4E3B\u9898\u3002
|
|
2709
|
+
\uFF080.9.76\uFF1A\u300C\u5BF9\u8BDD\u300D\u6765\u6E90\u5FBD\u7AE0\u968F\u5176 CSS \u9000\u5F79\u2014\u2014meta.session \u662F\u6CF5\u6240\u6709\u6743\u6807\u8BB0\u975E\u6765\u6E90\u8BED\u4E49\u3002\uFF09 */
|
|
2710
|
+
.dsvm-optime,.dsvm-opdur{font-size:11px;color:var(--dsw-alias-label-caption,#9ca3af);font-variant-numeric:tabular-nums}
|
|
2711
|
+
.dsvm-opday{font-size:11px;font-weight:600;color:var(--dsw-alias-label-caption,#9ca3af);margin:6px 0 0}
|
|
2712
|
+
.dsvm-opgroup.done .dsvm-opday:first-child{margin-top:0}
|
|
2713
|
+
.dsvm-opdir{font-size:11px;line-height:16px;padding:0 6px;border-radius:8px;border:1px solid currentColor}
|
|
2714
|
+
.dsvm-opdir.on{color:#15803d}
|
|
2715
|
+
.dsvm-opdir.off{color:var(--dsw-alias-label-secondary,#4b5563)}
|
|
2716
|
+
.dsvm-opver{font-size:11px;color:var(--dsw-alias-label-secondary,#4b5563);font-variant-numeric:tabular-nums;overflow-wrap:anywhere}
|
|
2608
2717
|
.dsvm-favbtn{appearance:none;border:0;background:transparent;color:var(--dsw-alias-label-caption,#9ca3af);font-size:15px;line-height:1;cursor:pointer;padding:0 2px;margin-left:auto}
|
|
2609
2718
|
.dsvm-favbtn:hover{color:var(--dsw-alias-state-business-primary,#4d6bfe)}
|
|
2610
2719
|
.dsvm-favbtn.on{color:#e0a33c}
|
|
@@ -3547,7 +3656,6 @@ function DetailModal({ it, labels, busy, onClose, onInstall, onUpgrade, upgradeB
|
|
|
3547
3656
|
it.deprecated === true ? h("span", { className: "dshm-badge warn" }, lookup("badge.deprecated")) : null,
|
|
3548
3657
|
it.community !== true && Array.isArray(it.verified) && it.verified.length ? h("span", { className: "dshm-badge", title: it.verified.join("\u3001") }, lookup("badge.verified")) : null,
|
|
3549
3658
|
it.audience === "internal" ? h("span", { className: "dshm-badge" }, lookup("badge.internal")) : null,
|
|
3550
|
-
it.decoupled === true ? h("span", { className: "dshm-badge", title: lookup("badge.decoupled.tip") }, lookup("badge.decoupled")) : null,
|
|
3551
3659
|
it.installed ? h("span", { className: "dshm-badge" }, lookup("badge.installed")) : null,
|
|
3552
3660
|
it.community === true ? h("span", { className: "dshm-badge info" }, lookup("badge.community")) : null,
|
|
3553
3661
|
h("span", { className: "dshm-badge info" }, it.source === "npm" ? "npm" : "github"),
|
|
@@ -3760,7 +3868,11 @@ function MarketTab({ notify, markets, onMutation, ops, favorites, profileKind, o
|
|
|
3760
3868
|
};
|
|
3761
3869
|
const doUpgrade = async (it) => {
|
|
3762
3870
|
try {
|
|
3763
|
-
const res = await ops.runOp("upgrade", it.installedPkg, () =>
|
|
3871
|
+
const res = await ops.runOp("upgrade", it.installedPkg, async () => {
|
|
3872
|
+
const r = await api("upgrade", { pkg: it.installedPkg });
|
|
3873
|
+
const m = opUpgradeMeta2(r);
|
|
3874
|
+
return m ? { ...r, opMeta: m } : r;
|
|
3875
|
+
});
|
|
3764
3876
|
const note = upgradeNotify2(res.activation);
|
|
3765
3877
|
const text = lookup("notify.upgraded", { pkg: res.pkg, from: res.fromVersion ? `v${res.fromVersion}` : "\u2014", to: res.version ? `v${res.version}` : res.sha ? res.sha.slice(0, 7) : "latest" }) + (res.buildApprovals && res.buildApprovals.length ? lookup("notify.builds", { names: res.buildApprovals.join(", ") }) : res.fallbackAllBuilds ? lookup("notify.builds.fallback") : "") + (note.suffixKey ? lookup(note.suffixKey) : "");
|
|
3766
3878
|
notify({ kind: "ok", needsRestart: note.needsRestart, text });
|
|
@@ -3941,7 +4053,6 @@ function MarketTab({ notify, markets, onMutation, ops, favorites, profileKind, o
|
|
|
3941
4053
|
it.deprecated === true ? h("span", { className: "dshm-badge warn", key: "dep" }, lookup("badge.deprecated")) : null,
|
|
3942
4054
|
it.community !== true && Array.isArray(it.verified) && it.verified.length ? h("span", { className: "dshm-badge", key: "v", title: it.verified.join("\u3001") }, lookup("badge.verified")) : null,
|
|
3943
4055
|
it.audience === "internal" ? h("span", { className: "dshm-badge dshm-badge-internal", key: "internal" }, lookup("badge.internal")) : null,
|
|
3944
|
-
it.decoupled === true ? h("span", { className: "dshm-badge", key: "decoupled", title: lookup("badge.decoupled.tip") }, lookup("badge.decoupled")) : null,
|
|
3945
4056
|
it.outdated ? h("span", { className: "dshm-badge warn", key: "u" }, lookup("badge.update")) : null,
|
|
3946
4057
|
it.installed ? h("span", { className: "dshm-badge", key: "i" }, lookup("badge.installed")) : null,
|
|
3947
4058
|
it.community === true ? h("span", { className: "dshm-badge info", key: "c" }, lookup("badge.community")) : null,
|
|
@@ -4165,7 +4276,11 @@ function InstalledTab({ notify, installed, updates, onMutation, ops }) {
|
|
|
4165
4276
|
};
|
|
4166
4277
|
const doUpgrade = async (it) => {
|
|
4167
4278
|
try {
|
|
4168
|
-
const res = await ops.runOp("upgrade", it.pkg, () =>
|
|
4279
|
+
const res = await ops.runOp("upgrade", it.pkg, async () => {
|
|
4280
|
+
const r = await api("upgrade", { pkg: it.pkg });
|
|
4281
|
+
const m = opUpgradeMeta2(r);
|
|
4282
|
+
return m ? { ...r, opMeta: m } : r;
|
|
4283
|
+
});
|
|
4169
4284
|
const note = upgradeNotify2(res.activation);
|
|
4170
4285
|
notify({
|
|
4171
4286
|
kind: "ok",
|
|
@@ -4727,19 +4842,27 @@ function OperationsCard({ records, onClearFinished, onRemove }) {
|
|
|
4727
4842
|
const finished = records.filter((r) => active.indexOf(r) < 0).slice(-50);
|
|
4728
4843
|
const clearable = records.some((r) => TERMINAL_CLEARABLE2.has(r.status));
|
|
4729
4844
|
const [scrollRef, scrollCls] = useScrollableContain(finished.length);
|
|
4730
|
-
const
|
|
4731
|
-
const row = (r) =>
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
h(
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4845
|
+
const dayGroups = useMemo(() => groupOpsByDay2(finished), [records]);
|
|
4846
|
+
const row = (r) => {
|
|
4847
|
+
const vm = opRowVm2(r);
|
|
4848
|
+
const tip = [vm.full, vm.durText, r.error || r.warning || ""].filter(Boolean).join(" \xB7 ");
|
|
4849
|
+
return h(
|
|
4850
|
+
"div",
|
|
4851
|
+
{ key: r.id, className: `dsvm-oprow ${OP_STATUS_CLS[r.status] || ""}` },
|
|
4852
|
+
vm.clock ? h("span", { className: "dsvm-optime", title: vm.full }, vm.clock) : null,
|
|
4853
|
+
h("span", { className: "dsvm-opstatus" }, lookup("op.status." + r.status)),
|
|
4854
|
+
h("span", { className: "dsvm-opkind" }, lookup("op.kind." + r.kind)),
|
|
4855
|
+
vm.dir ? h("span", { className: `dsvm-opdir ${vm.dir}` }, lookup(vm.dir === "on" ? "op.state.on" : "op.state.off")) : null,
|
|
4856
|
+
h("span", { className: "dsvm-optarget", title: tip || void 0 }, vm.target),
|
|
4857
|
+
vm.version ? h("span", { className: "dsvm-opver", title: tip || void 0 }, vm.version) : null,
|
|
4858
|
+
vm.durText ? h("span", { className: "dsvm-opdur" }, vm.durText) : null,
|
|
4859
|
+
r.status === "running" ? Spin() : null,
|
|
4860
|
+
r.error ? h("span", { className: "dsvm-opnote" }, r.error) : null,
|
|
4861
|
+
r.warning ? h("span", { className: "dsvm-opnote" }, r.warning) : null,
|
|
4862
|
+
// 单条移除(终审·新伤2):input/failed/superseded 行给出口(对话区来源的 input 不再永挂)
|
|
4863
|
+
(r.status === "input" || r.status === "failed" || r.status === "superseded") && onRemove ? h("button", { className: "dshm-xbtn", title: lookup("op.remove"), onClick: () => onRemove(r.id) }, h(XIcon)) : null
|
|
4864
|
+
);
|
|
4865
|
+
};
|
|
4743
4866
|
return h(
|
|
4744
4867
|
"div",
|
|
4745
4868
|
{ className: "dshm-section dshm-ops-card" },
|
|
@@ -4749,7 +4872,7 @@ function OperationsCard({ records, onClearFinished, onRemove }) {
|
|
|
4749
4872
|
finished.length ? h(
|
|
4750
4873
|
"div",
|
|
4751
4874
|
{ className: "dsvm-ops-caption", style: { marginTop: active.length ? "7px" : "0" } },
|
|
4752
|
-
lookup("settings.ops.group.done")
|
|
4875
|
+
lookup("settings.ops.group.done.n", { n: finished.length })
|
|
4753
4876
|
) : null,
|
|
4754
4877
|
finished.length ? h(
|
|
4755
4878
|
"div",
|
|
@@ -4762,7 +4885,14 @@ function OperationsCard({ records, onClearFinished, onRemove }) {
|
|
|
4762
4885
|
h(
|
|
4763
4886
|
"div",
|
|
4764
4887
|
{ className: "dsvm-opgroup done" },
|
|
4765
|
-
...
|
|
4888
|
+
...dayGroups.map(
|
|
4889
|
+
(g) => h(
|
|
4890
|
+
React.Fragment,
|
|
4891
|
+
{ key: g.key || "op-day-unknown" },
|
|
4892
|
+
g.key ? h("div", { className: "dsvm-opday" }, g.kind === "today" ? lookup("op.day.today") : g.kind === "yesterday" ? lookup("op.day.yesterday") : g.key) : null,
|
|
4893
|
+
...g.records.map(row)
|
|
4894
|
+
)
|
|
4895
|
+
)
|
|
4766
4896
|
)
|
|
4767
4897
|
) : null,
|
|
4768
4898
|
finished.length ? h(
|