dsh-vscode-mode 0.23.1 → 0.23.3
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 +3 -0
- package/lib/client.js +234 -47
- package/lib/client.js.map +2 -2
- package/lib/index.js +221 -46
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client/missingReview.ts +24 -0
- package/src/client/reviewBatch.ts +5 -0
- package/src/client/ui/EditorView.ts +172 -19
- package/src/client/ui/OfficialDiffBar.tsx +18 -3
- package/src/client/ui/SidecarDiffBar.tsx +3 -2
- package/src/client/ui/reviewAllRow.tsx +5 -4
- package/src/missingReview.ts +44 -5
- package/src/officialCapture.ts +11 -0
- package/src/reviewDb.ts +23 -0
- package/src/reviewRpc.ts +140 -37
- package/src/rpc.ts +6 -2
- package/src/shared/review.ts +2 -1
- package/src/shared/rpc.ts +4 -1
package/README.md
CHANGED
|
@@ -521,6 +521,7 @@ DSH 每次启动监听随机端口,`http://127.0.0.1:<port>` 就是浏览器 o
|
|
|
521
521
|
|
|
522
522
|
官方 `dsh plugin` 方式,三选一。下面以 `web` profile 为例;Desktop 或其他命名
|
|
523
523
|
profile 请替换为实际目标,不要把示例目录当成当前运行 profile。升级前可阅读
|
|
524
|
+
**v0.23.2** 修复 Keep 在非活跃端(桌面端)点了没反应,共两处成因。①权限:`edrv.review.decide` 原先一律要求本端活跃会话,而同端详情接口的 `capability.keep` 只按审查库推导,于是会话在另一实例时按钮亮着、点击后抛错并被兜底成 HTTP 500「DSH 请求失败(HTTP 500)」。现按写入副作用区分——官方记录 Keep 只写共享审查库(`BEGIN IMMEDIATE` + operationId 幂等 + `id/seq/revision/current/decision` CAS,库为每工作区 SQLite 且 `WAL + busy_timeout=2000`),冷端放行;官方 Undo 需校验会话证据并写回源文件、待审投影条目写本机待审 JSON(无跨进程锁),两者仍限本端活跃会话,并返回可读的跨端原因而非 500。详情响应新增 `capability.live`,冷端差异栏禁用 Undo 并给出跨端说明、Keep 提示补一句「写入共享审查库,仍可执行」,批量预检对冷端待审条目给出准确原因。②选中目标:已结算(`oldText === newText`,累计净变化为零)的待审投影 `capability` 恒为不可 Keep,但单文件通道把它排在官方记录之前、客户端取 `items[0]`,同路径官方待审行又被历史过滤掉,于是差异栏「待审 0」、Keep 禁用、点击无反应。现 `pendingPageOf()` 在交给官方审查通道前剔除已结算投影,官方待审记录重新成为审查目标。另外详情未加载时点 Keep 不再静默返回,改为可读提示;打开文件时若某条官方记录的改动已全部不在当前文件中(无可定位差异且缓冲区干净),自动按 Keep 结案(只标记不写盘),差异栏不再显示「本记录 N 处改动均已不在当前文件中」这类失效叙事;官方元数据首次载入期间差异栏显示 `—` 而不是按历史记录报数,避免重启瞬间闪出几十条假待审。验证:typecheck 0 error、目标单测 57/57、`pnpm build` 通过,并用真实工作区审查库探针确认差异栏首条已回到官方记录且 `capability={keep:true,undo:true,live:true}`;桌面端 GUI 点按验收因 App 重启后恢复的是另一个会话而未完成,缺口保留,见 [0.23.2 发布说明](docs/release-0.23.2.md)。以下保留历史版本事实:
|
|
524
525
|
**v0.23.1** 修复「Keep All / Undo All」在工作区待审超过一页时必定中止:批量按钮原先复用官方审查的分页接口逐页取待审条目,并把每页返回的展示用计数当成全量总数校验,因此官方待审超过 50 条(本仓库常态约 150 条)时会先报「待审记录在分页期间变化」或最终报「待审记录数量不完整」,实际一条都不会被决策(已完成 0 项)。现在批量操作改走一次性完整快照——`edrv.review.list` 新增 `all: true` 参数,服务端循环分页取全官方待审行,与工作区历史改动投影按路径去重后返回 `nextCursor: null` 与真实总数(`pending`),客户端单次取快照、校验条目唯一且仍为待审后才逐项决策;快照总量超过 2000 条时明确拒绝并提示分批处理,条目在决策途中变化则继续整批中止、不做部分写入。差异栏的日常浏览仍走原分页接口,展示行为不变。本版修复只经单测与真实审查库只读核对,未在重启后的 GUI 上点按批量按钮验证,缺口保留,见 [0.23.1 发布说明](docs/release-0.23.1.md)。以下保留历史版本事实:
|
|
525
526
|
**v0.23.0** 的快捷菜单:编辑器内一个可拖动悬浮按钮,点开是自定义菜单树(组 / 按钮,最多 5 层),按钮可携带提示词并直接发送给 AI 或只填入输入框;配置存于 `<DSH_HOME>/dsh-vscode-mode/data/quick-menu.json`,带 `revision` 乐观锁与损坏降级;节点可限定生效工作区(默认全部),按钮可绑定技能与规则,发送时按当前会话可见性校验后只拼装通过的绑定。新增 `skills.list` 只读 RPC 枚举「全局技能 + 当前工作区技能」作为候选,配置界面的工作区、技能、规则全部改为下拉弹层/多选下拉,菜单设置重排为四段并统一按钮盒模型(修掉「导入 JSON」下移不居中)。本版**未做 GUI 真机验收**(本机 pnpm store 损坏、插件未部署),缺口已获用户接受,见 [0.23.0 发布说明](docs/release-0.23.0.md)。以下保留历史版本事实:
|
|
526
527
|
**v0.22.0** 的累计基线待审(非 UI 能力对齐 dsh-diff-approval):同一文件的多次编辑折叠成一条待审、基线保留最早内容,A→B→C 显示 A→C、A→B→A 自然归零;Keep 只推进基线不改磁盘,Revert 走版本守卫写回并读回校验,撤销/重做用游标模型跨重启保留;新增 `str_replace_editor` 预像配对、`fs/observed` 终像、已入列路径的外部改动吸收与缺失/不可读生命周期、git/svn/Perforce 基线导入,以及旧 sidecar 写入口对已接管路径的服务端拒绝。差异仍在编辑器内行内展示、块级 Keep/Undo 用药丸,文件级在差异栏;详情面板与批注(含「让 AI 应答」)本版移除。验收边界:p4 仅有假 shell 单测(本机无 Perforce 客户端),「让 AI 应答」随批注一并下线故不再验证;本版未在宿主上重启验收 GUI 全流程,见 [0.22.0 发布说明](docs/release-0.22.0.md)。以下保留历史版本事实:
|
|
@@ -879,6 +880,8 @@ Keep All / Undo All 却是亮的。修复:单文件 Keep / Undo 覆盖冲突
|
|
|
879
880
|
完整变更见 [GitHub Releases](https://github.com/Lenonss/DSH_VsCodeMode/releases)。
|
|
880
881
|
近期关键版本:
|
|
881
882
|
|
|
883
|
+
- **v0.23.3**:修复 issue #13(已删除文件的差异条目把人卡死)与 #12(重启后成串「采集不完整」)。①文件在磁盘上被删掉时,客户端申请整文件删除预览被「已有官方审查记录」拒绝,而拒绝只是一条普通 `Error`,于是落到通用加载失败分支——「文件加载失败:…」+ 进度钉在 0%、重试同错、标签页关不掉;`edrv.review.detail` 还把 Undo 不可用解释成「缺少可验证的原始字节」,而真实原因是文件已不在。现缺失文件预览的可预期拒绝带稳定码(`official-covered` / `official-decided` / `no-records` / `no-evidence` / `too-large`),客户端据此显示「文件已在磁盘删除(· 有官方待审改动)」终态:标题 + 原因 + 重试 / 关闭标签页,不再画 0% 进度条;官方待审记录在磁盘已删除时给出「Keep 按删除结案、Undo 需要读写该文件」的准确原因(Keep 语义不变,仍只写共享审查库),记录都已结案时提示可直接关闭;`!review` 的磁盘状态抖动改为最多重读 2 次后给终态,消除缺失↔重现的无限递归。v0.22.0 起 `hasOfficial()` 已用 `typeof path !== 'string'` 守卫堵掉把不透明 FsTarget 绑进 SQL 导致的 `Unknown named parameter 'targetKey'`,本版不再复现。②官方 `workspace/changes` 的 summary 只存在宿主内存里,插件启动补采原先无条件把历史事件全部入队,重启后每一轮都必然抛「summary 已失效或尚不可用」并写成不可修复的 `gap`(面板成串「轮次 N 采集不完整」);现补采先 `summary()` 探测再入队,失效事件只记一条汇总日志。验证:typecheck 与基线同为 37 个既有错误(`fflate/browser` 依赖缺失)、零新增;定向单测 111/111(含新增 `tests/deletedFileReview.test.ts` 5 例与 `tests/officialBackfill.test.ts` 2 例)、EditorView 相关 82/82;`npm run build` 四个 bundle 通过。见 [发布说明](docs/release-0.23.3.md)。
|
|
884
|
+
- **v0.23.2**:修复 Keep 在非活跃端(桌面端)点了没反应,两处成因。①`edrv.review.decide` 原先一律要求本端活跃会话,而能力位只按审查库推导,会话在另一实例时按钮亮着、点击后抛错被兜底成 HTTP 500。现按写入副作用区分:官方记录 Keep 只写共享审查库(`BEGIN IMMEDIATE` + 幂等键 + 版本 CAS),冷端放行;官方 Undo(校验证据并写回源文件)与待审投影条目(本机 JSON 无跨进程锁)仍限活跃端,返回可读跨端原因而非 500;详情新增 `capability.live`,冷端禁用 Undo 并说明、Keep 提示补「写入共享审查库,仍可执行」。②已结算待审投影的 `capability.keep` 恒为假,却因排在 `items[0]`、同路径官方待审行被历史过滤,把官方记录挤出差异栏(表现为「待审 0」+Keep 禁用+点击无反应);现 `pendingPageOf()` 剔除已结算投影,官方记录重新成为审查目标。另详情未加载时点 Keep 不再静默失败;打开文件时若某条官方记录的改动已全部不在当前文件中(无可定位差异且缓冲区干净),自动按 Keep 结案(只标记不写盘),差异栏不再显示「本记录 N 处改动均已不在当前文件中」;官方元数据首次载入期间差异栏显示 `—` 而非按历史记录报数,重启瞬间不再闪出几十条假待审。验证:typecheck 0 error、目标单测 57/57、build 通过、真实审查库探针确认首条回到官方记录且 `capability={keep:true,undo:true,live:true}`;桌面端 GUI 点按验收因重启后恢复的是另一个会话未完成,缺口保留。发布不自动部署,升级后重启 DSH 并刷新页面。见 [发布说明](docs/release-0.23.2.md)。
|
|
882
885
|
- **v0.23.1**:修复 Keep All / Undo All 在待审超过一页时必定中止——批量按钮原先复用分页接口并把每页的展示用计数当全量总数校验,官方待审 150 条时先报「待审记录在分页期间变化」或最终报「待审记录数量不完整」,实际 0 项被决策。现改为一次性完整快照(`edrv.review.list` 新增 `all: true`,服务端循环取全并与历史改动投影去重,`nextCursor: null`、`pending` 为真实总数),客户端单次取快照、校验唯一且仍待审后逐项决策;超过 2000 条明确拒绝并提示分批,途中变化仍整批中止不部分写入。差异栏浏览仍走原分页接口。本版未在重启后的 GUI 点按验证,缺口保留;发布不自动部署,升级后重启 DSH 并刷新页面。见 [发布说明](docs/release-0.23.1.md)。
|
|
883
886
|
- **v0.23.0**:新增快捷菜单——可拖动悬浮按钮 + 自定义菜单树(组/按钮,最多 5 层),按钮携带提示词并「直接发送给 AI」或「只填入输入框」;配置存 `<DSH_HOME>/dsh-vscode-mode/data/quick-menu.json`,带 `revision` 乐观锁、冲突重拉不覆盖、损坏降级。节点可限定工作区(默认全部、子节点继承),按钮可绑定技能与规则,发送时按会话可见性校验后只拼装通过的绑定(规则支持引用/内联)。新增 `skills.list` 只读 RPC 枚举全局技能 + 当前工作区技能;配置界面工作区改下拉弹层、技能/规则改分组多选下拉并移除手输技能名,菜单设置重排四段、统一按钮盒模型并修掉「导入 JSON」下移不居中。本版 GUI 未真机验收(pnpm store 损坏、插件未部署),缺口已获用户接受;发布不自动部署,升级后重启 DSH 并刷新页面。见 [发布说明](docs/release-0.23.0.md)。
|
|
884
887
|
- **v0.22.0**:新增累计基线待审——同文件多次编辑折叠成一条、基线保留最早内容(A→B→C 显示 A→C、A→B→A 归零);Keep 只推进基线不改磁盘,Revert 带版本守卫写回并读回,撤销/重做游标模型跨重启保留;补 `str_replace_editor` 预像配对、外部改动吸收与缺失生命周期、git/svn/Perforce 基线导入、旧入口服务端拒绝。差异仍在编辑器内行内展示,详情面板与批注(含「让 AI 应答」)移除。p4 仅假 shell 单测(本机无 Perforce 客户端),GUI 全流程未重启验收;发布不自动部署,升级后重启 DSH 并刷新页面。见 [发布说明](docs/release-0.22.0.md)。
|
package/lib/client.js
CHANGED
|
@@ -3554,6 +3554,10 @@ window.__ModuleLoader__.load({
|
|
|
3554
3554
|
}
|
|
3555
3555
|
}
|
|
3556
3556
|
//#endregion
|
|
3557
|
+
//#region src/shared/pendingReview.ts
|
|
3558
|
+
/** 待审条目在面板列表里的 id 前缀;客户端与 Host 共用这一份口径。 */
|
|
3559
|
+
const PENDING_PREFIX = "pending:";
|
|
3560
|
+
//#endregion
|
|
3557
3561
|
//#region src/client/reviewBatch.ts
|
|
3558
3562
|
/**
|
|
3559
3563
|
* @public
|
|
@@ -3589,6 +3593,7 @@ window.__ModuleLoader__.load({
|
|
|
3589
3593
|
for (const item of items) {
|
|
3590
3594
|
port.guard();
|
|
3591
3595
|
const detail = await port.detail(item.id);
|
|
3596
|
+
if (detail.capability.live === false && item.id.startsWith("pending:")) throw new Error(`${item.display}:待审条目需要在会话活跃的一端判定,请先在那一端处理或在本端打开该会话`);
|
|
3592
3597
|
if (!detail.item.current || detail.item.seq !== item.seq || detail.item.revision !== item.revision || !detail.capability.keep) throw new Error(`${item.display}:审查版本变化,请刷新后重试`);
|
|
3593
3598
|
if (reject && !detail.capability.undo) throw new Error(`${item.display}:${detail.capability.reason}`);
|
|
3594
3599
|
details.push(detail);
|
|
@@ -3754,10 +3759,6 @@ window.__ModuleLoader__.load({
|
|
|
3754
3759
|
return reviewBlocks(diff).map(placeRegion);
|
|
3755
3760
|
}
|
|
3756
3761
|
//#endregion
|
|
3757
|
-
//#region src/shared/pendingReview.ts
|
|
3758
|
-
/** 待审条目在面板列表里的 id 前缀;客户端与 Host 共用这一份口径。 */
|
|
3759
|
-
const PENDING_PREFIX = "pending:";
|
|
3760
|
-
//#endregion
|
|
3761
3762
|
//#region src/shared/pathKey.ts
|
|
3762
3763
|
/**
|
|
3763
3764
|
* 路径比较口径:Host 与客户端共用同一套「远端 / 盘符 / 相对路径」判定,只在平台折叠上分工。
|
|
@@ -377891,6 +377892,25 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
377891
377892
|
}
|
|
377892
377893
|
//#endregion
|
|
377893
377894
|
//#region src/client/missingReview.ts
|
|
377895
|
+
/**
|
|
377896
|
+
* @public
|
|
377897
|
+
* @author ddj 2026年10月31号
|
|
377898
|
+
* @description: 把 missingReview 的失败归并成「文件已删除」终态。只有确认删除的拒绝码才是终态;
|
|
377899
|
+
* 会话缺失、权限、文件重新出现等失败返回 null,调用方继续走通用加载失败(可重试、保留跨端提示)。
|
|
377900
|
+
* @param failure RPC 失败结果(error 必填,code 可选)
|
|
377901
|
+
* @returns 终态信息或 null
|
|
377902
|
+
*/
|
|
377903
|
+
function goneStateOf(failure) {
|
|
377904
|
+
const code = failure?.code;
|
|
377905
|
+
const official = code === "official-covered";
|
|
377906
|
+
if (!official && code !== "official-decided" && code !== "no-records" && code !== "no-evidence" && code !== "too-large") return null;
|
|
377907
|
+
const message = String(failure?.error ?? "文件已在磁盘删除").replace(/^Error:\s*/, "");
|
|
377908
|
+
return {
|
|
377909
|
+
title: official ? "文件已在磁盘删除 · 有官方待审改动" : "文件已在磁盘删除",
|
|
377910
|
+
message,
|
|
377911
|
+
official
|
|
377912
|
+
};
|
|
377913
|
+
}
|
|
377894
377914
|
/** @public @author ddj 2026年10月28号 @param review Frozen complete snapshot. @returns One whole-file deletion, including empty files; no invented current lines. */
|
|
377895
377915
|
function missingRegion(review) {
|
|
377896
377916
|
return {
|
|
@@ -382531,7 +382551,8 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
382531
382551
|
* @returns 持久化的全工作区控制条
|
|
382532
382552
|
*/
|
|
382533
382553
|
function ReviewAllRow(props) {
|
|
382534
|
-
const
|
|
382554
|
+
const known = typeof props.total === "number";
|
|
382555
|
+
const total = known ? props.total : 0;
|
|
382535
382556
|
const current = total && props.current > 0 ? props.current : 0;
|
|
382536
382557
|
const disabled = props.busy || !!props.unavailable || !props.pending;
|
|
382537
382558
|
return /* @__PURE__ */ react$1.default.createElement("div", {
|
|
@@ -382544,7 +382565,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
382544
382565
|
className: "edrv-review-total",
|
|
382545
382566
|
onClick: props.onOpen,
|
|
382546
382567
|
title: "打开当前工作区全部待审差异文件"
|
|
382547
|
-
}, "差异文件 ", /* @__PURE__ */ react$1.default.createElement("strong", null, current
|
|
382568
|
+
}, "差异文件 ", /* @__PURE__ */ react$1.default.createElement("strong", null, known ? `${current} / ${total}` : "—")), /* @__PURE__ */ react$1.default.createElement("span", { className: "edrv-review-all-actions" }, /* @__PURE__ */ react$1.default.createElement(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
382548
382569
|
size: "sm",
|
|
382549
382570
|
variant: "ghost",
|
|
382550
382571
|
onClick: props.onKeepAll,
|
|
@@ -382591,6 +382612,19 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
382591
382612
|
"aria-hidden": "true"
|
|
382592
382613
|
}, /* @__PURE__ */ react$1.default.createElement("path", { d: marks[mark] }));
|
|
382593
382614
|
}
|
|
382615
|
+
/**
|
|
382616
|
+
* @private
|
|
382617
|
+
* @author ddj 2026年10月31号
|
|
382618
|
+
* @description: Keep 按钮提示。会话不在本端活跃时 Keep 仍可执行(只写共享审查库),
|
|
382619
|
+
* 提示里补一句说明,免得用户把它当成跨端不可用的按钮。
|
|
382620
|
+
* @param hint 差异栏给出的 Keep 说明
|
|
382621
|
+
* @param live 会话是否在本端活跃
|
|
382622
|
+
* @returns 按钮 title 文本
|
|
382623
|
+
*/
|
|
382624
|
+
function keepTitle(hint, live) {
|
|
382625
|
+
if (live) return hint;
|
|
382626
|
+
return `${hint}(会话在另一端激活:Keep 写入共享审查库,仍可执行)`;
|
|
382627
|
+
}
|
|
382594
382628
|
/** @public @author ddj 2026年10月27号 @param props Existing review callbacks and immutable record metadata. @returns Responsive review toolbar; no disk or decision side effects until an explicit action. */
|
|
382595
382629
|
function OfficialDiffBar(props) {
|
|
382596
382630
|
const { official, pendingRegions = [], staleRegions = [], diffIdx = 0 } = props;
|
|
@@ -382647,7 +382681,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
382647
382681
|
role: "region",
|
|
382648
382682
|
"aria-label": "文件差异审查"
|
|
382649
382683
|
}, /* @__PURE__ */ react$1.default.createElement(ReviewAllRow, {
|
|
382650
|
-
total: props.fileTotal ??
|
|
382684
|
+
total: props.fileTotal ?? null,
|
|
382651
382685
|
current: (props.fileTotal ?? 0) && (props.fileIdx ?? -1) >= 0 ? (props.fileIdx ?? 0) + 1 : 0,
|
|
382652
382686
|
busy: props.reviewBatchBusy,
|
|
382653
382687
|
unavailable: props.batchUnavailable,
|
|
@@ -382692,7 +382726,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
382692
382726
|
icon: barIcon("check"),
|
|
382693
382727
|
onClick: props.onAcceptFile,
|
|
382694
382728
|
disabled: props.reviewBatchBusy || !detail?.capability.keep,
|
|
382695
|
-
title: detail?.capability.keep ? view.keepHint : detail?.capability.reason
|
|
382729
|
+
title: detail?.capability.keep ? keepTitle(view.keepHint, detail.capability.live !== false) : detail?.capability.reason
|
|
382696
382730
|
}, "Keep"), /* @__PURE__ */ react$1.default.createElement(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
382697
382731
|
open: menu === "more",
|
|
382698
382732
|
anchor: moreTrigger,
|
|
@@ -382780,7 +382814,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
382780
382814
|
role: "region",
|
|
382781
382815
|
"aria-label": "文件差异审查"
|
|
382782
382816
|
}, /* @__PURE__ */ react$1.default.createElement(ReviewAllRow, {
|
|
382783
|
-
total: props.fileTotal ??
|
|
382817
|
+
total: props.fileTotal ?? null,
|
|
382784
382818
|
current: (props.fileTotal ?? 0) && (props.fileIdx ?? -1) >= 0 ? (props.fileIdx ?? 0) + 1 : 0,
|
|
382785
382819
|
busy,
|
|
382786
382820
|
pending: props.allPendingCount,
|
|
@@ -393558,6 +393592,9 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
393558
393592
|
const aiStatusTimer = react$1.default.useRef(null);
|
|
393559
393593
|
const [error, setError] = react$1.default.useState(null);
|
|
393560
393594
|
const [loadError, setLoadError] = react$1.default.useState(null);
|
|
393595
|
+
const [goneFile, setGoneFile] = react$1.default.useState(null);
|
|
393596
|
+
const missingReadRef = react$1.default.useRef(/* @__PURE__ */ new Map());
|
|
393597
|
+
const goneNow = goneFile && goneFile.path === active && goneFile.sessionId === sessionId ? goneFile : null;
|
|
393561
393598
|
const [largeCandidate, setLargeCandidate] = react$1.default.useState(null);
|
|
393562
393599
|
const [pagedFile, setPagedFile] = react$1.default.useState(null);
|
|
393563
393600
|
const [pageChanged, setPageChanged] = react$1.default.useState(null);
|
|
@@ -393802,6 +393839,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
393802
393839
|
review.page
|
|
393803
393840
|
]);
|
|
393804
393841
|
const reviewOpsRef = react$1.default.useRef(/* @__PURE__ */ new Map());
|
|
393842
|
+
const settledRef = react$1.default.useRef(/* @__PURE__ */ new Set());
|
|
393805
393843
|
const [officialDetail, setOfficialDetail] = react$1.default.useState(null);
|
|
393806
393844
|
const [officialRecords, setOfficialRecords] = react$1.default.useState([]);
|
|
393807
393845
|
const [selectedReview, setSelectedReview] = react$1.default.useState(null);
|
|
@@ -393816,7 +393854,9 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
393816
393854
|
react$1.default.useEffect(() => {
|
|
393817
393855
|
const controller = new AbortController();
|
|
393818
393856
|
const pendingPath = (review.page?.items ?? []).filter((item) => String(item.id).startsWith(PENDING_PREFIX)).map((item) => item.currentPath || item.path).find((path) => sameFile(path, active));
|
|
393819
|
-
const
|
|
393857
|
+
const coveredPath = review.page?.overview?.coveredPaths.find((path) => sameFile(path, active));
|
|
393858
|
+
const reviewPath = coveredPath ?? pendingPath;
|
|
393859
|
+
dbg(sessionId, `[DEBUG reviewPath] active=${active ?? "(null)"} covered=${coveredPath ?? "(none)"} pending=${pendingPath ?? "(none)"} coveredCount=${review.page?.overview?.coveredPaths.length ?? -1} items=${review.page?.items?.length ?? -1} overview=${review.page?.overview ? 1 : 0}`);
|
|
393820
393860
|
if (!active || !reviewPath) {
|
|
393821
393861
|
setOfficialDetail(null);
|
|
393822
393862
|
setOfficialRecords([]);
|
|
@@ -393832,6 +393872,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
393832
393872
|
if (controller.signal.aborted) return;
|
|
393833
393873
|
if (!page.ok) throw new Error(page.error);
|
|
393834
393874
|
const selected = page.page.items.find((item) => item.id === selectedReview) ?? page.page.items[0];
|
|
393875
|
+
dbg(sessionId, `[DEBUG reviewList] path=${reviewPath} items=${page.page.items.length} waiting=${page.page.pending} selected=${selected?.id ?? "(none)"}`);
|
|
393835
393876
|
if (!selected) {
|
|
393836
393877
|
setOfficialRecords([]);
|
|
393837
393878
|
setOfficialDetail(null);
|
|
@@ -393842,6 +393883,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
393842
393883
|
id: selected.id
|
|
393843
393884
|
}, controller.signal);
|
|
393844
393885
|
if (controller.signal.aborted) return;
|
|
393886
|
+
dbg(sessionId, `[DEBUG reviewDetail] id=${selected.id} ok=${result.ok ? 1 : 0} keep=${result.ok ? result.detail.capability?.keep === true ? 1 : 0 : "-"} live=${result.ok ? String(result.detail.capability?.live) : "-"} err=${result.ok ? "" : String(result.error).slice(0, 120)}`);
|
|
393845
393887
|
if (!result.ok) throw new Error(result.error);
|
|
393846
393888
|
setOfficialRecords((previous) => JSON.stringify(previous) === JSON.stringify(page.page.items) ? previous : page.page.items);
|
|
393847
393889
|
setOfficialDetail((previous) => JSON.stringify(previous) === JSON.stringify(result.detail) ? previous : result.detail);
|
|
@@ -393929,6 +393971,20 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
393929
393971
|
const staleAmbiguous = staleRegions.filter((region) => region.staleReason === "ambiguous").length;
|
|
393930
393972
|
const noBlocks = !!officialDetail && (officialDetail.diff.kind !== "text" || officialDetail.diff.hunks.length === 0);
|
|
393931
393973
|
const decideRegions = react$1.default.useMemo(() => [...pendingRegions, ...staleRegions], [pendingRegions, staleRegions]);
|
|
393974
|
+
react$1.default.useEffect(() => {
|
|
393975
|
+
if (!officialDetail || contentReady !== true || batchBusyRef.current) return;
|
|
393976
|
+
if (pendingRegions.length > 0 || staleRegions.length === 0) return;
|
|
393977
|
+
if (noBlocks || officialDetail.capability?.keep !== true) return;
|
|
393978
|
+
if (dirtyRef.current[active]) return;
|
|
393979
|
+
settleInvisibleRecord(officialDetail);
|
|
393980
|
+
}, [
|
|
393981
|
+
officialDetail,
|
|
393982
|
+
contentReady,
|
|
393983
|
+
pendingRegions,
|
|
393984
|
+
staleRegions,
|
|
393985
|
+
noBlocks,
|
|
393986
|
+
active
|
|
393987
|
+
]);
|
|
393932
393988
|
hoverRegionsRef.current = pendingRegions;
|
|
393933
393989
|
lineRegionMapRef.current = react$1.default.useMemo(() => {
|
|
393934
393990
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -394425,7 +394481,38 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
394425
394481
|
* @param force 强制走 RPC(reloadFile 用,跳过 model 复用)
|
|
394426
394482
|
* @param version 已知磁盘版本(缺省走 RPC 返回值)
|
|
394427
394483
|
*/
|
|
394428
|
-
/**
|
|
394484
|
+
/**
|
|
394485
|
+
* 把「文件已在磁盘删除」记成终态面板:不占进度条、不反复重试,并允许直接关闭页签。
|
|
394486
|
+
* 只有确认删除的原因才走终态;会话/权限类失败仍回退通用加载失败,保留跨端提示。
|
|
394487
|
+
* @private @author ddj 2026年10月31号
|
|
394488
|
+
* @param path 目标文件
|
|
394489
|
+
* @param sid 会话 id
|
|
394490
|
+
* @param seq 加载序号(过期响应丢弃)
|
|
394491
|
+
* @param failure 宿主拒绝原因(可带稳定 code)
|
|
394492
|
+
*/
|
|
394493
|
+
function settleGone(path, sid, seq, failure) {
|
|
394494
|
+
if (!loadCurrent(path, seq)) return;
|
|
394495
|
+
const error = failure && typeof failure === "object" ? failure : { error: failure };
|
|
394496
|
+
const gone = goneStateOf(error) ?? (error.deleted === true ? {
|
|
394497
|
+
title: "文件已在磁盘删除",
|
|
394498
|
+
official: false,
|
|
394499
|
+
message: String(error.error ?? "")
|
|
394500
|
+
} : null);
|
|
394501
|
+
if (!gone) {
|
|
394502
|
+
failLoad(path, sid, seq, String(error.error ?? error));
|
|
394503
|
+
return;
|
|
394504
|
+
}
|
|
394505
|
+
stampLoad(path, sid, seq, gone.message);
|
|
394506
|
+
setLoadError(null);
|
|
394507
|
+
setError(null);
|
|
394508
|
+
setGoneFile({
|
|
394509
|
+
...gone,
|
|
394510
|
+
path,
|
|
394511
|
+
sessionId: sid
|
|
394512
|
+
});
|
|
394513
|
+
setStatus(gone.official ? "文件已删除 · 差异栏可 Keep 结案" : "文件已删除");
|
|
394514
|
+
}
|
|
394515
|
+
/** @private @author ddj 2026年10月28号 / 2026年10月31号 @param path Missing text file. @param sid Owning session. @param seq Loader generation. @sideEffects Loads deletion evidence without creating or saving the file. */
|
|
394429
394516
|
async function loadMissing(path, sid, seq) {
|
|
394430
394517
|
try {
|
|
394431
394518
|
const result = await rpc("edrv.missingReview", {
|
|
@@ -394434,13 +394521,23 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
394434
394521
|
});
|
|
394435
394522
|
if (!loadCurrent(path, seq)) return;
|
|
394436
394523
|
if (!result.ok) {
|
|
394437
|
-
|
|
394524
|
+
settleGone(path, sid, seq, result);
|
|
394438
394525
|
return;
|
|
394439
394526
|
}
|
|
394440
394527
|
if (!result.review) {
|
|
394441
|
-
|
|
394528
|
+
const attempts = (missingReadRef.current.get(path) ?? 0) + 1;
|
|
394529
|
+
missingReadRef.current.set(path, attempts);
|
|
394530
|
+
if (attempts <= 2) {
|
|
394531
|
+
loadContent(path, sid, true);
|
|
394532
|
+
return;
|
|
394533
|
+
}
|
|
394534
|
+
settleGone(path, sid, seq, {
|
|
394535
|
+
deleted: true,
|
|
394536
|
+
error: "文件状态在磁盘上反复变化,请稍后重试,或关闭该标签页"
|
|
394537
|
+
});
|
|
394442
394538
|
return;
|
|
394443
394539
|
}
|
|
394540
|
+
missingReadRef.current.delete(path);
|
|
394444
394541
|
if (dirtyRef.current[path] || savingRef.current.has(path)) {
|
|
394445
394542
|
failLoad(path, sid, seq, "文件已删除,但有未保存编辑;请先处理本地缓冲");
|
|
394446
394543
|
return;
|
|
@@ -394453,6 +394550,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
394453
394550
|
};
|
|
394454
394551
|
missingRef.current.set(path, preview);
|
|
394455
394552
|
setMissingPreview(preview);
|
|
394553
|
+
setGoneFile(null);
|
|
394456
394554
|
setContent("");
|
|
394457
394555
|
setContentPath(path);
|
|
394458
394556
|
setLoadError(null);
|
|
@@ -394477,6 +394575,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
394477
394575
|
status: "loading"
|
|
394478
394576
|
});
|
|
394479
394577
|
setLoadError(null);
|
|
394578
|
+
setGoneFile(null);
|
|
394480
394579
|
setLargeCandidate(null);
|
|
394481
394580
|
setPagedFile(null);
|
|
394482
394581
|
setPageChanged(null);
|
|
@@ -396783,18 +396882,17 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
396783
396882
|
hunkIndex: r.idx,
|
|
396784
396883
|
decision: reject ? "rejected" : "accepted"
|
|
396785
396884
|
});
|
|
396786
|
-
/**
|
|
396787
|
-
|
|
396788
|
-
|
|
396789
|
-
|
|
396790
|
-
|
|
396791
|
-
|
|
396792
|
-
|
|
396793
|
-
|
|
396794
|
-
|
|
396795
|
-
|
|
396796
|
-
const
|
|
396797
|
-
const undoVersion = undoModel?.getVersionId?.();
|
|
396885
|
+
/**
|
|
396886
|
+
* @private
|
|
396887
|
+
* @author ddj 2026年10月31号
|
|
396888
|
+
* @description: 提交一条官方记录的判定;operationId 按决策键复用,网络重试保持幂等。
|
|
396889
|
+
* @param detail 目标记录(含冻结的 seq / revision)
|
|
396890
|
+
* @param reject true=Undo
|
|
396891
|
+
* @param blockId 可选的连续块;缺省为整文件
|
|
396892
|
+
* @returns 成功返回提交结果,失败抛出 host 给出的原因
|
|
396893
|
+
*/
|
|
396894
|
+
async function submitOfficialDecision(detail, reject, blockId) {
|
|
396895
|
+
const source = detail.item;
|
|
396798
396896
|
const opKey = JSON.stringify([
|
|
396799
396897
|
sessionId,
|
|
396800
396898
|
source.id,
|
|
@@ -396808,25 +396906,68 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
396808
396906
|
operationId = crypto.randomUUID();
|
|
396809
396907
|
reviewOpsRef.current.set(opKey, operationId);
|
|
396810
396908
|
}
|
|
396909
|
+
const result = await rpc("edrv.review.decide", {
|
|
396910
|
+
sessionId,
|
|
396911
|
+
id: source.id,
|
|
396912
|
+
seq: source.seq,
|
|
396913
|
+
revision: source.revision,
|
|
396914
|
+
operationId,
|
|
396915
|
+
scope: blockId ? "hunk" : "file",
|
|
396916
|
+
blockId,
|
|
396917
|
+
decision: reject ? "rejected" : "accepted"
|
|
396918
|
+
});
|
|
396919
|
+
if (!result.ok) throw new Error(result.error);
|
|
396920
|
+
reviewOpsRef.current.delete(opKey);
|
|
396921
|
+
return result;
|
|
396922
|
+
}
|
|
396923
|
+
/**
|
|
396924
|
+
* @private
|
|
396925
|
+
* @author ddj 2026年10月31号
|
|
396926
|
+
* @description: 结案一条改动已不在当前文件中的官方记录:等价于 Keep(只标记已采纳,不改写磁盘)。
|
|
396927
|
+
* 这类记录没有可见差异可审,留在差异栏只会让用户去处理一个不存在的东西。
|
|
396928
|
+
* @param detail 待结案的记录
|
|
396929
|
+
*/
|
|
396930
|
+
async function settleInvisibleRecord(detail) {
|
|
396931
|
+
if (batchBusyRef.current) return;
|
|
396932
|
+
const settled = settledRef.current;
|
|
396933
|
+
if (settled.has(detail.item.id)) return;
|
|
396934
|
+
settled.add(detail.item.id);
|
|
396935
|
+
batchBusyRef.current = true;
|
|
396811
396936
|
try {
|
|
396812
|
-
|
|
396813
|
-
|
|
396814
|
-
|
|
396815
|
-
|
|
396816
|
-
|
|
396817
|
-
|
|
396818
|
-
|
|
396819
|
-
|
|
396820
|
-
|
|
396821
|
-
|
|
396822
|
-
|
|
396823
|
-
|
|
396937
|
+
await submitOfficialDecision(detail, false);
|
|
396938
|
+
refreshReview(sessionId);
|
|
396939
|
+
} catch (cause) {
|
|
396940
|
+
settled.delete(detail.item.id);
|
|
396941
|
+
dbg(sessionId, `[DEBUG settleInvisible] id=${detail.item.id} err=${String(cause).slice(0, 160)}`);
|
|
396942
|
+
} finally {
|
|
396943
|
+
batchBusyRef.current = false;
|
|
396944
|
+
}
|
|
396945
|
+
}
|
|
396946
|
+
/** @private @author ddj 2026年10月27号 @param reject Undo instead of Keep. @param blockId Optional contiguous block. @returns Persisted decision result; never reloads over a dirty buffer. */
|
|
396947
|
+
async function decideOfficial(reject, blockId) {
|
|
396948
|
+
dbg(sessionId, `[DEBUG decideOfficial] reject=${reject ? 1 : 0} detail=${officialDetail ? 1 : 0} busy=${batchBusyRef.current ? 1 : 0} active=${active ?? "(null)"}`);
|
|
396949
|
+
if (!officialDetail || batchBusyRef.current) {
|
|
396950
|
+
if (!officialDetail && !batchBusyRef.current) setError("官方差异详情尚未加载完成,请稍后重试;若一直如此,请切换文件或刷新页面。");
|
|
396951
|
+
return false;
|
|
396952
|
+
}
|
|
396953
|
+
if (reject && (dirtyRef.current[active] || savingRef.current.has(active) || saveTimerRef.current.isPending())) {
|
|
396954
|
+
setError("存在未保存或正在保存的修改,请等待完成后重试");
|
|
396955
|
+
return false;
|
|
396956
|
+
}
|
|
396957
|
+
batchBusyRef.current = true;
|
|
396958
|
+
const detail = officialDetail;
|
|
396959
|
+
const undoPath = active;
|
|
396960
|
+
const undoModel = editorRef.current?.getModel?.();
|
|
396961
|
+
const undoVersion = undoModel?.getVersionId?.();
|
|
396962
|
+
try {
|
|
396963
|
+
await submitOfficialDecision(detail, reject, blockId);
|
|
396824
396964
|
if (reject && activeRef.current === undoPath && !dirtyRef.current[undoPath] && !savingRef.current.has(undoPath) && undoModel?.getVersionId?.() === undoVersion) reloadFile(true);
|
|
396825
396965
|
else if (reject) setError("Undo 已完成,编辑器在等待期间变化;未覆盖当前缓冲区,请核对磁盘后刷新");
|
|
396826
396966
|
refreshReview(sessionId);
|
|
396827
396967
|
setStatus(reject ? "已 Undo 选中差异" : "已 Keep 选中差异");
|
|
396828
396968
|
return true;
|
|
396829
396969
|
} catch (cause) {
|
|
396970
|
+
dbg(sessionId, `[DEBUG decideOfficialFail] id=${detail.item.id} reject=${reject ? 1 : 0} err=${String(cause).slice(0, 160)}`);
|
|
396830
396971
|
setError(String(cause));
|
|
396831
396972
|
return false;
|
|
396832
396973
|
} finally {
|
|
@@ -397043,13 +397184,24 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
397043
397184
|
}
|
|
397044
397185
|
return operationId;
|
|
397045
397186
|
}
|
|
397187
|
+
/**
|
|
397188
|
+
* @private
|
|
397189
|
+
* @author ddj 2026年10月31号
|
|
397190
|
+
* @description: 批量操作要求官方待审列表已就绪;切换会话后列表还在载入时,
|
|
397191
|
+
* 先触发一次刷新并给出可读提示,而不是直接报错中止(用户看到红色「尚未就绪」会以为功能坏了)。
|
|
397192
|
+
* @param action 面向用户的动作名
|
|
397193
|
+
* @returns 列表已就绪时为 true
|
|
397194
|
+
*/
|
|
397195
|
+
function reviewReadyForBatch(action) {
|
|
397196
|
+
if (review.page?.overview) return true;
|
|
397197
|
+
refreshReview(sessionId);
|
|
397198
|
+
setStatus(`官方待审列表正在载入,载入完成后请再次点击${action}`);
|
|
397199
|
+
return false;
|
|
397200
|
+
}
|
|
397046
397201
|
/** @private @author ddj 2026年10月27号 @param reject Undo or Keep all workspace pending records, including previous rounds. @returns Explicit partial results; legacy proceeds only when official stage fully succeeds. */
|
|
397047
397202
|
async function actReviewAll(reject) {
|
|
397048
397203
|
if (batchBusyRef.current) return;
|
|
397049
|
-
if (!
|
|
397050
|
-
setError("官方待审列表尚未就绪,未执行批量操作");
|
|
397051
|
-
return;
|
|
397052
|
-
}
|
|
397204
|
+
if (!reviewReadyForBatch(reject ? "Undo All" : "Keep All")) return;
|
|
397053
397205
|
if (!sum.pendingFiles.length) return;
|
|
397054
397206
|
const token = reviewLifeRef.current;
|
|
397055
397207
|
const undoPath = activeRef.current;
|
|
@@ -397116,10 +397268,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
397116
397268
|
/** @private @author ddj 2026年10月27号 @param reject Whether to undo pending files. @description Open a DSH confirmation without starting any mutations. */
|
|
397117
397269
|
function askReviewAll(reject) {
|
|
397118
397270
|
if (batchBusyRef.current || !sum.pendingFiles.length) return;
|
|
397119
|
-
if (!
|
|
397120
|
-
setError("官方待审列表尚未就绪,未执行批量操作");
|
|
397121
|
-
return;
|
|
397122
|
-
}
|
|
397271
|
+
if (!reviewReadyForBatch(reject ? "Undo All" : "Keep All")) return;
|
|
397123
397272
|
setReviewAllPrompt({
|
|
397124
397273
|
reject,
|
|
397125
397274
|
count: sum.pendingFiles.length,
|
|
@@ -398458,6 +398607,37 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
398458
398607
|
className: "edrv-pill edrv-pill-ghost",
|
|
398459
398608
|
onClick: retry
|
|
398460
398609
|
}, "重试") : null);
|
|
398610
|
+
/**
|
|
398611
|
+
* 渲染缺失文件终态面板:说明 + 重试 + 关闭页签(不显示进度条,避免卡在 0%)。
|
|
398612
|
+
* @private @author ddj 2026年10月31号
|
|
398613
|
+
* @param gone 终态信息
|
|
398614
|
+
* @param retry 重新读取回调
|
|
398615
|
+
* @param close 关闭该标签页回调
|
|
398616
|
+
* @returns 终态面板 React 元素
|
|
398617
|
+
*/
|
|
398618
|
+
const goneBody = (gone, retry, close) => react$1.default.createElement("div", {
|
|
398619
|
+
className: "edrv-empty edrv-loading",
|
|
398620
|
+
"aria-live": "polite",
|
|
398621
|
+
role: "status"
|
|
398622
|
+
}, react$1.default.createElement("div", { className: "edrv-loading-title" }, gone.title), react$1.default.createElement("div", { style: {
|
|
398623
|
+
fontSize: 12,
|
|
398624
|
+
maxWidth: 460,
|
|
398625
|
+
lineHeight: 1.6
|
|
398626
|
+
} }, gone.message), gone.official ? react$1.default.createElement("div", { style: {
|
|
398627
|
+
fontSize: 12,
|
|
398628
|
+
maxWidth: 460,
|
|
398629
|
+
lineHeight: 1.6,
|
|
398630
|
+
opacity: .8
|
|
398631
|
+
} }, "待审改动在差异栏:Keep 保留删除结果并结案;Undo 需要该文件的原始内容,磁盘已删除时不可用。") : null, react$1.default.createElement("div", { style: {
|
|
398632
|
+
display: "flex",
|
|
398633
|
+
gap: 8
|
|
398634
|
+
} }, react$1.default.createElement("button", {
|
|
398635
|
+
className: "edrv-pill edrv-pill-ghost",
|
|
398636
|
+
onClick: retry
|
|
398637
|
+
}, "重试"), react$1.default.createElement("button", {
|
|
398638
|
+
className: "edrv-pill edrv-pill-ghost",
|
|
398639
|
+
onClick: close
|
|
398640
|
+
}, "关闭标签页")));
|
|
398461
398641
|
let body;
|
|
398462
398642
|
if (activePlan) {
|
|
398463
398643
|
const labels = PLAN_MD_LABELS;
|
|
@@ -398498,6 +398678,12 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
398498
398678
|
}
|
|
398499
398679
|
}, "重试"));
|
|
398500
398680
|
else if (!active) body = react$1.default.createElement("div", { className: "edrv-empty" }, react$1.default.createElement("div", null, "暂无打开的文件"), react$1.default.createElement("div", { style: { fontSize: 12 } }, "使用右上搜索框 (" + (chordOf("edrv.quickOpen") ?? "Ctrl+P") + ") 打开工作区文件;" + (chordOf("edrv.showCommands") ?? "Ctrl+Shift+P") + " 打开命令栏;agent 修改文件后顶部会出现差异角标"));
|
|
398681
|
+
else if (goneNow) body = goneBody(goneNow, () => {
|
|
398682
|
+
missingReadRef.current.delete(goneNow.path);
|
|
398683
|
+
loadContent(active, sessionId, true);
|
|
398684
|
+
}, () => {
|
|
398685
|
+
closeTab(goneNow.path);
|
|
398686
|
+
});
|
|
398501
398687
|
else if (content === null && loadError && isSessionMissingError(loadError)) body = react$1.default.createElement("div", {
|
|
398502
398688
|
className: "edrv-empty edrv-loading",
|
|
398503
398689
|
"aria-live": "polite"
|
|
@@ -398617,6 +398803,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
398617
398803
|
const sessionDown = isSessionMissingError(rawReviewError);
|
|
398618
398804
|
const reviewErrorTone = sessionDown ? "info" : "error";
|
|
398619
398805
|
const reviewErrorText = !rawReviewError ? void 0 : sessionDown ? SESSION_DOWN_NOTICE : sessionErrorText(rawReviewError);
|
|
398806
|
+
const reviewLoading = review.page === null && !review.error;
|
|
398620
398807
|
const buildDockSnapshot = () => ({
|
|
398621
398808
|
mode: editorDockMode(active),
|
|
398622
398809
|
missingDeletion: !!missingNow,
|
|
@@ -398644,7 +398831,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
398644
398831
|
onUndoFile: undoFile,
|
|
398645
398832
|
onAcceptAllFiles: acceptAllFiles,
|
|
398646
398833
|
onUndoAllFiles: undoAllFiles,
|
|
398647
|
-
allPendingCount: allPending.length + (review.page?.pending ?? 0),
|
|
398834
|
+
allPendingCount: reviewLoading ? 0 : allPending.length + (review.page?.pending ?? 0),
|
|
398648
398835
|
reviewBatchBusy,
|
|
398649
398836
|
batchUnavailable: !review.page?.overview ? "官方待审列表尚未就绪" : void 0,
|
|
398650
398837
|
onRollback: rollbackFile,
|
|
@@ -398661,7 +398848,7 @@ td.UniverTableCell, th.UniverTableCell{mso-padding-alt:0cm 5.4pt 0cm 5.4pt;}
|
|
|
398661
398848
|
contentReady,
|
|
398662
398849
|
diffTotal: displayDiffTotal(contentReady, pendingRegions.length, sum.files.find((file) => sameFile(file.path, active))?.pending ?? 0),
|
|
398663
398850
|
fileIdx,
|
|
398664
|
-
fileTotal: sum.pendingFiles.length,
|
|
398851
|
+
fileTotal: reviewLoading ? null : sum.pendingFiles.length,
|
|
398665
398852
|
onPrevDiff: () => gotoDiff(-1),
|
|
398666
398853
|
onNextDiff: () => gotoDiff(1),
|
|
398667
398854
|
onPrevFile: () => gotoFile(-1),
|
package/lib/client.js.map
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: package/lib/client.js.map
|
|
3
|
-
size:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 35677585 bytes
|
|
4
|
+
sha256: df1afa8466a7852d100cfbc6a1f44e61beabd3b1808a262562e920ac06b96865
|