dsh-m 0.9.73 → 0.9.75
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 +191 -21
- 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.75 功能:操作记录信息增强——行内时刻/按日分组/开关方向/耗时/版本变迁/来源标记(数据零迁移)
|
|
12
|
+
|
|
13
|
+
- **背景(主人设置页实拍:开关记录读不出「开还是关」)**:操作记录行只有「状态 + 类型 + 包名」三要素——开关看不出方向(截图里连续两条 `开关 @iasiv5/dsh-quota-watch` 无法分辨先后开/关)、无任何时间、看不出耗时、看不出对话区发起还是界面点击、升级不知道版本从哪到哪。而这些信息**全部已在每条记录里**(`createdAt`/`updatedAt` 是 store 打点常态、`meta.on` 0.4.0 起就随开关入账、`meta.session` 是泵拾取标记)——纯展示层缺口,非数据缺失;浏览器 localStorage(`dshm-operations`)里的存量旧记录升级后立即可读,零迁移。
|
|
14
|
+
- **方案(展示派生全部收敛纯函数模块)**:新增 `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` 描边自适应主题。
|
|
15
|
+
- **数据管道(唯一一处非展示层改动)**:执行泵成功路径支持执行器回传 `value.opMeta` 并入记录 meta——底座取**落账时实读**的当前 meta(入队快照会丢拾取阶段追加的 session 标记,破「陈旧快照不回卷」保证,评审自纠);失败路径不入账(结果不可信)。恢复路径(`dispatchRestored`)成功值统一接进成功值通道(`value = r`)——生产实现今日返回 `{ ok: true }`,对现有流零行为变化;两处 `doUpgrade` 调用点把 `fromVersion/version/sha` 管道为 `opMeta`。
|
|
16
|
+
- **验证**:1375 项测试全绿(0.9.74 基线 1339 + 新增 36:`client-operations-view` 27 用例含格式化 TZ 无关派生/分组序/行 VM 回退/新病灶负向锚(`targetText` 与无计数旧键不得残留)+ 泵 opMeta 4 用例(done/warned 入账、失败与脏输入不入、恢复路径入账、session 保留))、typecheck 零错误;构建产物含新规则逐字锚。
|
|
17
|
+
|
|
18
|
+
### 0.9.74 功能:详情截图条滚轮横滚——裸滚轮 deltaY 安全映射 scrollLeft(钢人三红线)
|
|
19
|
+
|
|
20
|
+
- **背景(主人验收 0.9.73 实拍反馈)**:截图条是横滚容器,鼠标滚轮在横滚容器上默认纵滚祖先(弹窗)——图片多时纯鼠标用户只能拖 ~700px 细滚动条(离散目标上的连续输入,精度成本极高);触控板双指横滑(deltaX)与 Shift+滚轮虽有原生路径,但属隐藏知识不可达。
|
|
21
|
+
- **判定(新纯函数 `shotWheelAction`,src/client/wheel-strip.js,Node tests 直测)**:钢人三红线——①可滚才拦:scrollWidth ≤ clientWidth(+1 亚像素容差,0.9.72 同款口径) 零劫持,不满行的多数条目行为与今日一致,杜绝「静态劫持表达动态适用前提」的滚轮黑洞同构病复发;②到头放行:已到 deltaY 方向边界时零动作,纵滚还给弹窗(横向有得滚才借道、借完即还);③deltaX 不碰:|deltaX| ≥ |deltaY|(触控板横滑)不劫持不重复喂。非有限输入安全短路。
|
|
22
|
+
- **接线**:DetailModal 手动 `addEventListener("wheel", …, {passive:false})`(React onWheel 走 document 级 passive 委托,preventDefault 无效);deps=visible.length 随截图条存在性(条件渲染/primary 异步到达/坏图剔除)重挂;布局入参逐事件现读,无缓存失效问题。灯箱、走链、键盘导航零变化。
|
|
23
|
+
- **验证**:1339 项测试全绿(新增 client-wheel-strip 7 项:三红线逐条 + 容差边界 + 安全短路 + 接线源锚三件;img-chain ①锚放宽容 props 前缀)、typecheck 零错误。
|
|
24
|
+
|
|
11
25
|
### 0.9.73 修复:详情截图条统一瓷砖——「大小不一 + 预览图盖住左右邻图」(flex 收缩外溢根治)
|
|
12
26
|
|
|
13
27
|
- **根因(主人详情弹窗实拍:缩略图大小参差,图片压在左右邻图上)**:两处机制缺陷叠加——① `.dsvm-shotbox` 无固定几何(盒 min 120×84 / img max 220×130),跟着图片固有比例走,16:9、4:3、竖图、小原图各渲各的,「大的大小的小」;②盒子显式 `min-width:120px` 顶掉了 flex 的 automatic minimum size——8 张截图自然总宽(~1.7k px)远超弹窗内容宽(~688px)触发 flex 收缩时,盒子被压到 120px 地板而盒内 `<img>`(替换元素)不受盒宽约束保持固有宽度,加上盒子 `overflow:visible`,图片居中外溢每侧盖住邻图 ~44px——且发生在滚动条出现之前,两症状同屏;加载完成瞬间行高还随最高图 84→130px 跳变(CLS)。
|
|
@@ -538,6 +552,20 @@ The full release history of dsh-m, maintained bilingually: **Chinese first, Engl
|
|
|
538
552
|
|
|
539
553
|
## English
|
|
540
554
|
|
|
555
|
+
### Feature in 0.9.75 — operations log enrichment: inline clock/day groups/toggle direction/duration/upgrade versions/chat source (zero data migration)
|
|
556
|
+
|
|
557
|
+
- **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.
|
|
558
|
+
- **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.
|
|
559
|
+
- **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`.
|
|
560
|
+
- **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.
|
|
561
|
+
|
|
562
|
+
### Feature in 0.9.74 — screenshot-strip wheel hscroll: bare-wheel deltaY safely mapped to scrollLeft (steelman's three red lines)
|
|
563
|
+
|
|
564
|
+
- **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.
|
|
565
|
+
- **Decision (new pure predicate `shotWheelAction`, src/client/wheel-strip.js, Node-tested)**: steelman's three red lines — ① intercept only when scrollable: zero hijack while scrollWidth ≤ clientWidth (+1 sub-pixel tolerance, same rule as 0.9.72's useScrollableContain), so most entries (1-2 images) behave exactly as today — no relapse of the "static hijack expressing a dynamic precondition" wheel black-hole disease; ② release at the edge: zero action once the delta direction has no horizontal room left, handing vertical scroll back to the modal (borrow the scroll only while there is room); ③ never touch deltaX: |deltaX| ≥ |deltaY| (trackpad hscroll) passes through untouched. Non-finite inputs short-circuit safely.
|
|
566
|
+
- **Wiring**: DetailModal attaches a manual `addEventListener("wheel", …, {passive:false})` (React's onWheel rides the document-level passive delegation where preventDefault is a no-op); deps=visible.length re-attach as the strip's existence changes (conditional render / async primary shots / broken-shot eviction); layout inputs are read per event — nothing cached. Lightbox, image chain, and keyboard navigation unchanged.
|
|
567
|
+
- **Verification**: 1339 tests green (new client-wheel-strip, 7 cases: three red lines + tolerance edges + safe short-circuit + wiring anchors; the img-chain ① anchor widened to allow props prefixes), typecheck clean.
|
|
568
|
+
|
|
541
569
|
### Fix in 0.9.73 — detail screenshot strip unified tiles: inconsistent sizes and previews overlapping neighboring thumbnails (flex-shrink overflow fixed at the root)
|
|
542
570
|
|
|
543
571
|
- **Root cause (owner screenshot: jagged thumbnails with images spilling over their left/right neighbors)**: two defects stacked — ① `.dsvm-shotbox` had no fixed geometry (box min 120×84 / img max 220×130) and followed each image's intrinsic aspect ratio, so 16:9, 4:3, portrait and small originals all rendered at their own size; ② the explicit `min-width:120px` overrode the flex automatic minimum size — with eight screenshots' natural total width (~1.7k px) far exceeding the modal content width (~688px), flex-shrink squeezed each box to its 120px floor while the inner `<img>` (a replaced element) kept its intrinsic width, and with `overflow:visible` on the box each image spilled out centered, covering ~44px of each neighbor — all before the scrollbar even appeared; the row height also jumped 84→130px when the tallest image loaded (CLS).
|
package/lib/client.js
CHANGED
|
@@ -494,6 +494,28 @@ var init_lightbox = __esm({
|
|
|
494
494
|
}
|
|
495
495
|
});
|
|
496
496
|
|
|
497
|
+
// src/client/wheel-strip.js
|
|
498
|
+
var wheel_strip_exports = {};
|
|
499
|
+
__export(wheel_strip_exports, {
|
|
500
|
+
shotWheelAction: () => shotWheelAction
|
|
501
|
+
});
|
|
502
|
+
function shotWheelAction({ deltaX, deltaY, scrollWidth, clientWidth, scrollLeft }) {
|
|
503
|
+
const inputs = [deltaX, deltaY, scrollWidth, clientWidth, scrollLeft];
|
|
504
|
+
if (!inputs.every(Number.isFinite)) return { scrollBy: 0, preventDefault: false };
|
|
505
|
+
if (scrollWidth <= clientWidth + 1) return { scrollBy: 0, preventDefault: false };
|
|
506
|
+
if (deltaY === 0 || Math.abs(deltaX) >= Math.abs(deltaY)) return { scrollBy: 0, preventDefault: false };
|
|
507
|
+
const maxScrollLeft = scrollWidth - clientWidth;
|
|
508
|
+
const atEnd = scrollLeft >= maxScrollLeft - 1;
|
|
509
|
+
const atStart = scrollLeft <= 0;
|
|
510
|
+
if (deltaY > 0 && atEnd || deltaY < 0 && atStart) return { scrollBy: 0, preventDefault: false };
|
|
511
|
+
return { scrollBy: deltaY, preventDefault: true };
|
|
512
|
+
}
|
|
513
|
+
var init_wheel_strip = __esm({
|
|
514
|
+
"src/client/wheel-strip.js"() {
|
|
515
|
+
"use strict";
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
|
|
497
519
|
// src/client/window-drag.js
|
|
498
520
|
var window_drag_exports = {};
|
|
499
521
|
__export(window_drag_exports, {
|
|
@@ -1489,6 +1511,7 @@ function createOpsPump(store, getCtx) {
|
|
|
1489
1511
|
} else if (ctx && ctx.dispatchRestored) {
|
|
1490
1512
|
const r = await ctx.dispatchRestored(queued);
|
|
1491
1513
|
if (!r || !r.ok) err = Object.assign(new Error(r && r.error || "unknown"), r && r.issue ? { issue: r.issue } : {});
|
|
1514
|
+
else value = r;
|
|
1492
1515
|
} else {
|
|
1493
1516
|
err = new Error("\u65E0\u6267\u884C\u4E0A\u4E0B\u6587\uFF08\u9762\u677F\u672A\u6302\u8F7D\uFF09");
|
|
1494
1517
|
}
|
|
@@ -1496,7 +1519,13 @@ function createOpsPump(store, getCtx) {
|
|
|
1496
1519
|
err = e;
|
|
1497
1520
|
}
|
|
1498
1521
|
if (!err) {
|
|
1499
|
-
|
|
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
|
+
});
|
|
1500
1529
|
if (waitersEntry) waitersEntry.resolve(value);
|
|
1501
1530
|
} else {
|
|
1502
1531
|
const isInput = Boolean(err.issue);
|
|
@@ -1564,6 +1593,90 @@ var init_operations = __esm({
|
|
|
1564
1593
|
}
|
|
1565
1594
|
});
|
|
1566
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
|
+
session: meta.session === true,
|
|
1669
|
+
version,
|
|
1670
|
+
target: typeof rec.target === "string" ? rec.target : ""
|
|
1671
|
+
};
|
|
1672
|
+
}
|
|
1673
|
+
var init_operations_view = __esm({
|
|
1674
|
+
"src/client/operations-view.js"() {
|
|
1675
|
+
"use strict";
|
|
1676
|
+
init_operations();
|
|
1677
|
+
}
|
|
1678
|
+
});
|
|
1679
|
+
|
|
1567
1680
|
// src/client/favorites.js
|
|
1568
1681
|
var favorites_exports = {};
|
|
1569
1682
|
__export(favorites_exports, {
|
|
@@ -1758,6 +1871,7 @@ var { DEFAULT_PAGE_SIZE: DEFAULT_PAGE_SIZE2, MARKET_PAGE_SIZES: MARKET_PAGE_SIZE
|
|
|
1758
1871
|
var { readMarketSnapshot: readMarketSnapshot2, writeMarketSnapshot: writeMarketSnapshot2, isDefaultFirstPageQuery: isDefaultFirstPageQuery2 } = (init_market_snapshot(), __toCommonJS(market_snapshot_exports));
|
|
1759
1872
|
var { backdropCloseHandlers: backdropCloseHandlers2 } = (init_backdrop(), __toCommonJS(backdrop_exports));
|
|
1760
1873
|
var { lbStep: lbStep2, lbNeighbors: lbNeighbors2, swipeDir: swipeDir2 } = (init_lightbox(), __toCommonJS(lightbox_exports));
|
|
1874
|
+
var { shotWheelAction: shotWheelAction2 } = (init_wheel_strip(), __toCommonJS(wheel_strip_exports));
|
|
1761
1875
|
var { dragSlop: dragSlop2, grabOffset: grabOffset2, titlebarTopInset: titlebarTopInset2, clampPoint: clampPoint2, loadPanelPos: loadPanelPos2, savePanelPos: savePanelPos2, isDragTarget: isDragTarget2 } = (init_window_drag(), __toCommonJS(window_drag_exports));
|
|
1762
1876
|
var { WESERV_TIMEOUT_MS: WESERV_TIMEOUT_MS2, weservUrl: weservUrl2, serviceBucketOf: serviceBucketOf2, tierOrder: tierOrder2, nextTier: nextTier2, needsTimeout: needsTimeout2, preferredTier: preferredTier2, rememberSuccess: rememberSuccess2 } = (init_img_chain(), __toCommonJS(img_chain_exports));
|
|
1763
1877
|
var { createMarkdown: createMarkdown2 } = (init_markdown(), __toCommonJS(markdown_exports));
|
|
@@ -1769,6 +1883,7 @@ var { RESTART_POLL_MS: RESTART_POLL_MS2, RESTART_DEADLINE_MS: RESTART_DEADLINE_M
|
|
|
1769
1883
|
var { refreshAfterMutation: refreshAfterMutation2 } = (init_view_refresh(), __toCommonJS(view_refresh_exports));
|
|
1770
1884
|
var { applyInstalledUpdates: applyInstalledUpdates2, installedUpdateStats: installedUpdateStats2 } = (init_installed_updates(), __toCommonJS(installed_updates_exports));
|
|
1771
1885
|
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));
|
|
1886
|
+
var { groupOpsByDay: groupOpsByDay2, opRowVm: opRowVm2, opUpgradeMeta: opUpgradeMeta2 } = (init_operations_view(), __toCommonJS(operations_view_exports));
|
|
1772
1887
|
var { createFavoritesStore: createFavoritesStore2, partitionStale: partitionStale2 } = (init_favorites(), __toCommonJS(favorites_exports));
|
|
1773
1888
|
var { readSelfCheckCache: readSelfCheckCache2, writeSelfCheckCache: writeSelfCheckCache2, clearSelfCheckCache: clearSelfCheckCache2, deriveChipState: deriveChipState2 } = (init_self_check(), __toCommonJS(self_check_exports));
|
|
1774
1889
|
var { shouldShowInstallCmd: shouldShowInstallCmd2 } = (init_install_cmd(), __toCommonJS(install_cmd_exports));
|
|
@@ -1828,6 +1943,11 @@ var ZH = {
|
|
|
1828
1943
|
"op.status.warned": "\u5E26\u8B66\u544A",
|
|
1829
1944
|
"op.status.failed": "\u5931\u8D25",
|
|
1830
1945
|
"op.status.superseded": "\u5DF2\u8DF3\u8FC7",
|
|
1946
|
+
"op.day.today": "\u4ECA\u5929",
|
|
1947
|
+
"op.day.yesterday": "\u6628\u5929",
|
|
1948
|
+
"op.session": "\u5BF9\u8BDD",
|
|
1949
|
+
"op.session.tip": "\u5BF9\u8BDD\u533A\u53D1\u8D77\uFF08\u975E\u754C\u9762\u70B9\u51FB\uFF09",
|
|
1950
|
+
"settings.ops.group.done.n": "\u5DF2\u7ED3\u675F\uFF08{n}\uFF09",
|
|
1831
1951
|
"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",
|
|
1832
1952
|
"favorites.stale": "{n} \u6761\u6536\u85CF\u5DF2\u4ECE\u76EE\u5F55\u4E0B\u67B6",
|
|
1833
1953
|
"favorites.clean": "\u6E05\u7406\u5931\u6548\u6536\u85CF",
|
|
@@ -1992,7 +2112,6 @@ var ZH = {
|
|
|
1992
2112
|
"settings.ops": "\u64CD\u4F5C\u8BB0\u5F55",
|
|
1993
2113
|
"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",
|
|
1994
2114
|
"settings.ops.group.active": "\u8FDB\u884C\u4E2D",
|
|
1995
|
-
"settings.ops.group.done": "\u5DF2\u7ED3\u675F",
|
|
1996
2115
|
"settings.ops.reddot": "\u5B58\u5728\u5931\u8D25\u6216\u5E26\u8B66\u544A\u7684\u64CD\u4F5C\u8BB0\u5F55",
|
|
1997
2116
|
"registry.refreshed": "\u6536\u5F55\u6E05\u5355\u5DF2\u5F3A\u5236\u5237\u65B0",
|
|
1998
2117
|
"notify.installed": "\u5DF2\u5B89\u88C5 {pkg}{version}",
|
|
@@ -2119,6 +2238,11 @@ var EN = {
|
|
|
2119
2238
|
"op.status.warned": "Warned",
|
|
2120
2239
|
"op.status.failed": "Failed",
|
|
2121
2240
|
"op.status.superseded": "Skipped",
|
|
2241
|
+
"op.day.today": "Today",
|
|
2242
|
+
"op.day.yesterday": "Yesterday",
|
|
2243
|
+
"op.session": "Chat",
|
|
2244
|
+
"op.session.tip": "Initiated from chat (not a UI click)",
|
|
2245
|
+
"settings.ops.group.done.n": "Ended ({n})",
|
|
2122
2246
|
"favorites.hint": "No favorites yet \u2014 tap \u2606 on a plugin card in Community/Curated to bookmark it",
|
|
2123
2247
|
"favorites.stale": "{n} favorites no longer in the catalog",
|
|
2124
2248
|
"favorites.clean": "Clean up stale favorites",
|
|
@@ -2283,7 +2407,6 @@ var EN = {
|
|
|
2283
2407
|
"settings.ops": "Operations",
|
|
2284
2408
|
"settings.ops.empty": "No operations yet. History of installs, upgrades, uninstalls, toggles and registry / community catalog settings will appear here.",
|
|
2285
2409
|
"settings.ops.group.active": "Active",
|
|
2286
|
-
"settings.ops.group.done": "Finished",
|
|
2287
2410
|
"settings.ops.reddot": "Failed or warned operations exist",
|
|
2288
2411
|
"registry.refreshed": "Registry force-refreshed",
|
|
2289
2412
|
"notify.installed": "Installed {pkg}{version}",
|
|
@@ -2582,6 +2705,16 @@ var CSS = `
|
|
|
2582
2705
|
.dsvm-opkind{color:var(--dsw-alias-label-secondary,#4b5563)}
|
|
2583
2706
|
.dsvm-optarget{font-weight:500;overflow-wrap:anywhere}
|
|
2584
2707
|
.dsvm-opnote{color:var(--dsw-alias-label-caption,#6b7280);font-size:11px;overflow-wrap:anywhere}
|
|
2708
|
+
/* 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\u4E0E
|
|
2709
|
+
\u5BF9\u8BDD\u6765\u6E90\u5FBD\u7AE0\u3001\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
|
|
2710
|
+
\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 */
|
|
2711
|
+
.dsvm-optime,.dsvm-opdur{font-size:11px;color:var(--dsw-alias-label-caption,#9ca3af);font-variant-numeric:tabular-nums}
|
|
2712
|
+
.dsvm-opday{font-size:11px;font-weight:600;color:var(--dsw-alias-label-caption,#9ca3af);margin:6px 0 0}
|
|
2713
|
+
.dsvm-opgroup.done .dsvm-opday:first-child{margin-top:0}
|
|
2714
|
+
.dsvm-opdir,.dsvm-opsession{font-size:11px;line-height:16px;padding:0 6px;border-radius:8px;border:1px solid currentColor}
|
|
2715
|
+
.dsvm-opdir.on{color:#15803d}
|
|
2716
|
+
.dsvm-opdir.off,.dsvm-opsession{color:var(--dsw-alias-label-secondary,#4b5563)}
|
|
2717
|
+
.dsvm-opver{font-size:11px;color:var(--dsw-alias-label-secondary,#4b5563);font-variant-numeric:tabular-nums;overflow-wrap:anywhere}
|
|
2585
2718
|
.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}
|
|
2586
2719
|
.dsvm-favbtn:hover{color:var(--dsw-alias-state-business-primary,#4d6bfe)}
|
|
2587
2720
|
.dsvm-favbtn.on{color:#e0a33c}
|
|
@@ -3457,6 +3590,19 @@ function DetailModal({ it, labels, busy, onClose, onInstall, onUpgrade, upgradeB
|
|
|
3457
3590
|
useEffect(() => {
|
|
3458
3591
|
if (closeRef.current) closeRef.current.focus();
|
|
3459
3592
|
}, []);
|
|
3593
|
+
const shotRowRef = useRef(null);
|
|
3594
|
+
useEffect(() => {
|
|
3595
|
+
const row = shotRowRef.current;
|
|
3596
|
+
if (!row || typeof row.addEventListener !== "function") return;
|
|
3597
|
+
const onWheel = (e) => {
|
|
3598
|
+
const action = shotWheelAction2({ deltaX: e.deltaX, deltaY: e.deltaY, scrollWidth: row.scrollWidth, clientWidth: row.clientWidth, scrollLeft: row.scrollLeft });
|
|
3599
|
+
if (!action.preventDefault) return;
|
|
3600
|
+
e.preventDefault();
|
|
3601
|
+
row.scrollLeft += action.scrollBy;
|
|
3602
|
+
};
|
|
3603
|
+
row.addEventListener("wheel", onWheel, { passive: false });
|
|
3604
|
+
return () => row.removeEventListener("wheel", onWheel);
|
|
3605
|
+
}, [visible.length]);
|
|
3460
3606
|
useEffect(() => {
|
|
3461
3607
|
const onKey = (e) => {
|
|
3462
3608
|
if (e.key === "Escape") {
|
|
@@ -3554,7 +3700,7 @@ function DetailModal({ it, labels, busy, onClose, onInstall, onUpgrade, upgradeB
|
|
|
3554
3700
|
) : null,
|
|
3555
3701
|
visible.length ? h(
|
|
3556
3702
|
"div",
|
|
3557
|
-
{ className: "dsvm-shotrow" },
|
|
3703
|
+
{ ref: shotRowRef, className: "dsvm-shotrow" },
|
|
3558
3704
|
...shots.map((src, i) => h(Shot, { key: `${i}:${src}`, src, onClick: () => setLb(visible.indexOf(src)), onBroken: breakShot }))
|
|
3559
3705
|
) : null,
|
|
3560
3706
|
it.community === true ? h(
|
|
@@ -3724,7 +3870,11 @@ function MarketTab({ notify, markets, onMutation, ops, favorites, profileKind, o
|
|
|
3724
3870
|
};
|
|
3725
3871
|
const doUpgrade = async (it) => {
|
|
3726
3872
|
try {
|
|
3727
|
-
const res = await ops.runOp("upgrade", it.installedPkg, () =>
|
|
3873
|
+
const res = await ops.runOp("upgrade", it.installedPkg, async () => {
|
|
3874
|
+
const r = await api("upgrade", { pkg: it.installedPkg });
|
|
3875
|
+
const m = opUpgradeMeta2(r);
|
|
3876
|
+
return m ? { ...r, opMeta: m } : r;
|
|
3877
|
+
});
|
|
3728
3878
|
const note = upgradeNotify2(res.activation);
|
|
3729
3879
|
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) : "");
|
|
3730
3880
|
notify({ kind: "ok", needsRestart: note.needsRestart, text });
|
|
@@ -4129,7 +4279,11 @@ function InstalledTab({ notify, installed, updates, onMutation, ops }) {
|
|
|
4129
4279
|
};
|
|
4130
4280
|
const doUpgrade = async (it) => {
|
|
4131
4281
|
try {
|
|
4132
|
-
const res = await ops.runOp("upgrade", it.pkg, () =>
|
|
4282
|
+
const res = await ops.runOp("upgrade", it.pkg, async () => {
|
|
4283
|
+
const r = await api("upgrade", { pkg: it.pkg });
|
|
4284
|
+
const m = opUpgradeMeta2(r);
|
|
4285
|
+
return m ? { ...r, opMeta: m } : r;
|
|
4286
|
+
});
|
|
4133
4287
|
const note = upgradeNotify2(res.activation);
|
|
4134
4288
|
notify({
|
|
4135
4289
|
kind: "ok",
|
|
@@ -4691,19 +4845,28 @@ function OperationsCard({ records, onClearFinished, onRemove }) {
|
|
|
4691
4845
|
const finished = records.filter((r) => active.indexOf(r) < 0).slice(-50);
|
|
4692
4846
|
const clearable = records.some((r) => TERMINAL_CLEARABLE2.has(r.status));
|
|
4693
4847
|
const [scrollRef, scrollCls] = useScrollableContain(finished.length);
|
|
4694
|
-
const
|
|
4695
|
-
const row = (r) =>
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
h(
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4848
|
+
const dayGroups = useMemo(() => groupOpsByDay2(finished), [records]);
|
|
4849
|
+
const row = (r) => {
|
|
4850
|
+
const vm = opRowVm2(r);
|
|
4851
|
+
const tip = [vm.full, vm.durText, r.error || r.warning || ""].filter(Boolean).join(" \xB7 ");
|
|
4852
|
+
return h(
|
|
4853
|
+
"div",
|
|
4854
|
+
{ key: r.id, className: `dsvm-oprow ${OP_STATUS_CLS[r.status] || ""}` },
|
|
4855
|
+
vm.clock ? h("span", { className: "dsvm-optime", title: vm.full }, vm.clock) : null,
|
|
4856
|
+
h("span", { className: "dsvm-opstatus" }, lookup("op.status." + r.status)),
|
|
4857
|
+
h("span", { className: "dsvm-opkind" }, lookup("op.kind." + r.kind)),
|
|
4858
|
+
vm.dir ? h("span", { className: `dsvm-opdir ${vm.dir}` }, lookup(vm.dir === "on" ? "op.state.on" : "op.state.off")) : null,
|
|
4859
|
+
vm.session ? h("span", { className: "dsvm-opsession", title: lookup("op.session.tip") }, lookup("op.session")) : null,
|
|
4860
|
+
h("span", { className: "dsvm-optarget", title: tip || void 0 }, vm.target),
|
|
4861
|
+
vm.version ? h("span", { className: "dsvm-opver", title: tip || void 0 }, vm.version) : null,
|
|
4862
|
+
vm.durText ? h("span", { className: "dsvm-opdur" }, vm.durText) : null,
|
|
4863
|
+
r.status === "running" ? Spin() : null,
|
|
4864
|
+
r.error ? h("span", { className: "dsvm-opnote" }, r.error) : null,
|
|
4865
|
+
r.warning ? h("span", { className: "dsvm-opnote" }, r.warning) : null,
|
|
4866
|
+
// 单条移除(终审·新伤2):input/failed/superseded 行给出口(对话区来源的 input 不再永挂)
|
|
4867
|
+
(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
|
|
4868
|
+
);
|
|
4869
|
+
};
|
|
4707
4870
|
return h(
|
|
4708
4871
|
"div",
|
|
4709
4872
|
{ className: "dshm-section dshm-ops-card" },
|
|
@@ -4713,7 +4876,7 @@ function OperationsCard({ records, onClearFinished, onRemove }) {
|
|
|
4713
4876
|
finished.length ? h(
|
|
4714
4877
|
"div",
|
|
4715
4878
|
{ className: "dsvm-ops-caption", style: { marginTop: active.length ? "7px" : "0" } },
|
|
4716
|
-
lookup("settings.ops.group.done")
|
|
4879
|
+
lookup("settings.ops.group.done.n", { n: finished.length })
|
|
4717
4880
|
) : null,
|
|
4718
4881
|
finished.length ? h(
|
|
4719
4882
|
"div",
|
|
@@ -4726,7 +4889,14 @@ function OperationsCard({ records, onClearFinished, onRemove }) {
|
|
|
4726
4889
|
h(
|
|
4727
4890
|
"div",
|
|
4728
4891
|
{ className: "dsvm-opgroup done" },
|
|
4729
|
-
...
|
|
4892
|
+
...dayGroups.map(
|
|
4893
|
+
(g) => h(
|
|
4894
|
+
React.Fragment,
|
|
4895
|
+
{ key: g.key || "op-day-unknown" },
|
|
4896
|
+
g.key ? h("div", { className: "dsvm-opday" }, g.kind === "today" ? lookup("op.day.today") : g.kind === "yesterday" ? lookup("op.day.yesterday") : g.key) : null,
|
|
4897
|
+
...g.records.map(row)
|
|
4898
|
+
)
|
|
4899
|
+
)
|
|
4730
4900
|
)
|
|
4731
4901
|
) : null,
|
|
4732
4902
|
finished.length ? h(
|