2026-05-16 07:38:45 +08:00
|
|
|
|
# 4-28 Trash Restore Location Reveal Focus v1
|
|
|
|
|
|
|
|
|
|
|
|
> 状态:process
|
|
|
|
|
|
> 创建时间:2026-05-15
|
|
|
|
|
|
> 所属主线:04-tree-domain / VSCode Explorer 文件树与垃圾箱闭环
|
|
|
|
|
|
> 来源:`design/10-review/07-vscode-explorer-filetree-trash-gap-review.md` 阶段 6
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 目标
|
|
|
|
|
|
|
|
|
|
|
|
页面进入垃圾箱前必须记录可恢复的位置快照;恢复时优先回到删除前父节点与排序位置,并在 UI 中 reveal / focus 恢复对象。若原父节点已不存在或仍在垃圾箱,应显式 fallback 到根目录并提示用户。
|
|
|
|
|
|
|
|
|
|
|
|
## 2. 已落地范围
|
|
|
|
|
|
|
|
|
|
|
|
- `documents` schema 新增 `restore_parent_id` 与 `restore_sort_order`。
|
|
|
|
|
|
- `documents.softDelete` 对页面子树写入删除前 `parent_id / sort_order` 快照。
|
|
|
|
|
|
- `documents.restore`:
|
|
|
|
|
|
- 读取同 workspace 当前文档集合。
|
|
|
|
|
|
- 父节点仍存在或属于本次级联恢复子树时,恢复到原父节点。
|
|
|
|
|
|
- 父节点已不存在或仍在垃圾箱时,恢复到根目录。
|
|
|
|
|
|
- 恢复时回写 `parent_id / sort_order`,并对目标父级兄弟节点重新编号,避免恢复到原排序位时产生重复 `sort_order`。
|
|
|
|
|
|
- 清空恢复位置快照。
|
|
|
|
|
|
- 返回 `restore_location.parent_id / sort_order / fallback_reason`。
|
|
|
|
|
|
- `/api/tree/commands restore` 读取页面 meta 时允许包含已删除页面,避免垃圾箱页面在进入 restore mutation 前被 `getMeta` 过滤成 404。
|
|
|
|
|
|
- `restoreDocumentCommand` 透传恢复位置结果。
|
|
|
|
|
|
- Sidebar 垃圾箱恢复后刷新数据、展开恢复父链、滚动并 focus 恢复行;发生 fallback 时提示“原父页面已不存在,已恢复到根目录”。
|
|
|
|
|
|
|
|
|
|
|
|
## 3. 设计口径
|
|
|
|
|
|
|
|
|
|
|
|
- 当前记录的是稳定数据位置:`parent_id / sort_order`。
|
|
|
|
|
|
`view path / expanded path` 不持久化到 Convex,恢复后由 Sidebar 根据当前父链展开得到。
|
|
|
|
|
|
- 子树恢复只恢复与父节点同一 `deleted_at` 批次的子节点,避免把更早独立删除的子页面误恢复。
|
|
|
|
|
|
- fallback 策略先固定为“恢复到根目录 + 明示提示”,不在本阶段引入位置选择弹窗。
|
|
|
|
|
|
- `sort_order` 会按当前兄弟数量 clamp;如果原位置越界,则放到可解释的最近位置。
|
|
|
|
|
|
|
|
|
|
|
|
## 4. 已验证
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cd /mnt/Data1T/mnote/wolai-frontend
|
|
|
|
|
|
pnpm test src/lib/documents/tree-command-client.test.ts src/lib/documents/restore-location.test.ts src/components/sidebar/tree-shell-host.test.tsx src/components/sidebar/sidebar-sync.test.ts
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
结果:4 个测试文件通过,20 项测试通过。
|
|
|
|
|
|
|
|
|
|
|
|
补充 route 与排序回归:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cd /mnt/Data1T/mnote/wolai-frontend
|
|
|
|
|
|
pnpm test src/lib/documents/tree-command-client.test.ts src/lib/documents/restore-location.test.ts src/components/sidebar/tree-shell-host.test.tsx src/components/sidebar/sidebar-sync.test.ts src/app/api/tree/commands/route.test.ts
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
结果:5 个测试文件通过,32 项测试通过。
|
|
|
|
|
|
|
|
|
|
|
|
真实浏览器 smoke:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cd /mnt/Data1T/mnote/wolai-frontend
|
|
|
|
|
|
npx convex dev --once --tail-logs disable --env-file ../.env.all --run ping:ping
|
|
|
|
|
|
|
|
|
|
|
|
cd /mnt/Data1T/mnote
|
|
|
|
|
|
node scripts/task429-trash-restore-location-reveal-smoke.js
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
结果:通过。脚本使用一次性用户 / workspace,在 3000 主入口验证:
|
|
|
|
|
|
|
|
|
|
|
|
- 删除子页面后通过 `tree.node.restore` 恢复,返回 `restore_location.parent_id` 为原父页面、`sort_order` 为原排序位。
|
|
|
|
|
|
- 原排序位已被兄弟页面占用时,兄弟页面被后移,Convex 中不产生重复 `sort_order`。
|
|
|
|
|
|
- 当前浏览器页面不刷新,恢复后的页面行重新出现在侧边栏树中。
|
|
|
|
|
|
- 构造 `restore_parent_id` 指向缺失父节点的历史数据,恢复后返回 `fallback_reason: parent_missing_or_deleted`,并落到根目录。
|
|
|
|
|
|
|
|
|
|
|
|
局部 TypeScript 筛查:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
cd /mnt/Data1T/mnote/wolai-frontend
|
|
|
|
|
|
pnpm exec tsc --noEmit --pretty false 2>&1 | rg "convex/documents.ts\\((160|161|162|163|164|165|166|167|168|169|170|171|172|173|174|175)"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
结果:阶段 6 修改附近无新增 TypeScript 报错。全量 `tsc` 仍受仓库既有错误影响,未作为本阶段完成条件。
|
|
|
|
|
|
|
2026-05-21 11:01:17 +08:00
|
|
|
|
## 5. 待补(Worker C 2026-05-21 追加 local folder restore focus 缺口)
|
2026-05-16 07:38:45 +08:00
|
|
|
|
|
2026-05-21 11:01:17 +08:00
|
|
|
|
### 5.1 Convex 页面(已有部分证据)
|
|
|
|
|
|
|
|
|
|
|
|
- React Sidebar Drawer 的恢复后 DOM focus 仍需在 React 入口可稳定渲染页面树时补浏览器证据;当前 3000 主壳 smoke(`task429`)已覆盖"恢复后无需刷新可见 / reveal",fallback 提示仍由 React Drawer 代码路径负责。
|
2026-05-16 07:38:45 +08:00
|
|
|
|
- 双浏览器 no-refresh:A 恢复页面后,B 不刷新即可看到位置变化;该项归入阶段 8 的实时刷新矩阵。
|
2026-05-21 11:01:17 +08:00
|
|
|
|
- 已知源码问题:`selectSidebarFileTreeDocument` 存在且工作(create / navigate 路径调用),但 restore 路径不调用。
|
|
|
|
|
|
|
|
|
|
|
|
### 5.2 Local folder 非 md 资源 restore focus(新发现缺口,Worker C 2026-05-21 审计)
|
|
|
|
|
|
|
|
|
|
|
|
当前状态:**完全未实现**。审计证据及源码对照:
|
|
|
|
|
|
|
|
|
|
|
|
| 检查项 | 状态 | 证据来源 |
|
|
|
|
|
|
|--------|------|----------|
|
|
|
|
|
|
| `selectSidebarFileTreeDocument` 是否从 restore 路径调用 | ❌ 否 | `layout.rs:1274,1296,1333,9278`(仅 create/navigate/activate 路径调用) |
|
|
|
|
|
|
| restore 后 filetree 行是否有 `data-active` / `data-selected` | ❌ 无 | `task473` gap smoke 结果:`data-active="false"`、`data-selected="false"` |
|
|
|
|
|
|
| restore 后是否 `scrollIntoView` 或 `focus()` | ❌ 无 | 同上 |
|
|
|
|
|
|
| trash workbench 的 restore 后 filetree 同步机制 | 轮询 1200ms | `layout.rs:1991-2004` (`startLocalFolderSidebarWatch`) |
|
|
|
|
|
|
| trash workbench 的 restore 后是否调用 `refreshLocalFolderSidebarSnapshot` | ❌ 否,只调 `refresh()`(自身 workbench) | `gateway.rs:1064-1065` |
|
|
|
|
|
|
| `selectSidebarFileTreeDocument` 是否支持 `local-file:` row-id | ❌ 否,只查 `doc:` | `layout.rs:4138` |
|
|
|
|
|
|
|
|
|
|
|
|
### 5.3 下一步建议(供 Codex 参考,不在此阶段修改 Rust)
|
|
|
|
|
|
|
|
|
|
|
|
1. **短路径(仅 focus 现有行)**:trash workbench inline script 的 restore `.then()` 中设置 `window.__mnoteRestoredDocumentId = entryId`;下一轮 filetree poll 检测此值并 focus 对应行。
|
|
|
|
|
|
2. **中路径**:`gateway.rs` trash workbench script 中 restore 成功后也调用 `refreshLocalFolderSidebarSnapshot()` 并传入 focus 参数。
|
|
|
|
|
|
3. **长路径**:扩展 `selectSidebarFileTreeDocument` 支持 `local-file:` 行 ID;restore 完成后通过 `CustomEvent` 跨 trash 页 → 主页面通信。
|
|
|
|
|
|
4. **smoke 回归**:`task473` 已记录当前缺口。后续实现后复跑 `task473` 应观察到 `data-selected="true"` 或 `data-active="true"` 出现。
|
|
|
|
|
|
|
|
|
|
|
|
### 5.4 2026-05-21 浏览器复核
|
|
|
|
|
|
|
|
|
|
|
|
- Codex 独立复跑 `node --check scripts/task473-local-folder-trash-restore-no-refresh-focus-gap-smoke.js` 与 `node scripts/task473-local-folder-trash-restore-no-refresh-focus-gap-smoke.js`:`ok:true`,`restoreNavFree.delta=0`,`fileReappearsInFiletree=true`。
|
|
|
|
|
|
- Reasonix Browser Worker 输出目录:`tmp/reasonix-batch-a-browser-task473-2026-05-21/`,结论 `PASS_WITH_KNOWN_GAP`。
|
|
|
|
|
|
- 复核结论:local folder 非 md 资源 restore 后已证明 no-refresh 与行恢复;focus/reveal 仍未实现,不能归档为完成。
|