feat(web-shell): manage sessions from the sidebar (archive, unarchive, delete) - #6293
Conversation
…, delete) Add an Archive quick action and a "..." overflow menu (Rename / Archive / Delete) to each session row in the web-shell sidebar, plus a collapsible "Archived" section that lazily lists archived sessions with Restore / Delete. Thread the daemon's existing archiveState filter and archive/unarchive endpoints through the webui workspace facade and the useDaemonSessions hook; rename stays limited to the current live session.
|
Thanks for the PR, @wenshao! Template looks good ✓ Problem: This is a real feature gap, not a theoretical concern. Session archive/unarchive shipped end-to-end in the daemon and SDK (#6058) but was never surfaced in the web-shell sidebar. The PR closes that last-mile gap — browser users had no way to archive or manage past sessions. Direction: Clearly aligned with the session-management roadmap. Web-shell users managing their session history is a natural expectation once the backend supports it. No product-direction concerns. Approach: The scope is tight — 7 files, purely additive UI wiring plus two thin facade methods. No core changes, no SDK changes, no scope creep. The overflow menu pattern (rename/archive/delete) and the collapsible archived section are standard UI conventions. One observation: the sidebar's quick-action button changed from Rename to Archive, with Rename moving into the "…" menu. This is a reasonable UX tradeoff (archive is likely more common than rename), but worth flagging for the maintainer to weigh in on. Moving on to code review. 🔍 中文说明感谢贡献,@wenshao! 模板完整 ✓ 问题: 这是一个真实的功能缺口,不是理论性的担忧。会话归档/取消归档在 daemon 和 SDK 层已经端到端落地(#6058),但 web-shell 侧边栏一直没有暴露。本 PR 补上了这最后一公里——浏览器用户之前无法归档或管理过去的会话。 方向: 与会话管理路线图明确对齐。一旦后端支持了归档功能,web-shell 用户管理自己的会话历史是理所当然的期望。没有产品方向上的顾虑。 方案: 范围很收敛——7 个文件,纯增量的 UI 接线加两个薄 facade 方法。不改 core,不改 SDK,没有范围蔓延。溢出菜单模式(重命名/归档/删除)和可折叠的已归档区域是标准 UI 范式。一个观察:侧边栏的快捷操作按钮从"重命名"换成了"归档","重命名"移入了"…"菜单。这是一个合理的 UX 取舍(归档可能比重命名更常用),但值得 maintainer 确认。 进入代码审查 🔍 — Qwen Code · qwen3.7-max |
Code ReviewIndependent proposal: To surface session archive/unarchive in the web-shell sidebar, I'd add an Comparison: The PR matches and exceeds this — instead of adding individual inline buttons, it introduces a polished overflow "…" menu pattern (rename / archive / delete) and a separate archive quick-action button. This is better UX than scattered individual buttons. No simpler path was missed. Findings (non-blocking):
No critical blockers or AGENTS.md violations found. TestsTypecheck ( Real-Scenario TestingThis PR modifies a browser-based web-shell UI, not the CLI TUI. Tmux-based real-scenario testing does not apply here. The author provided Playwright evidence on macOS (archive → archived → restore round-trip verified, confirmed 中文说明代码审查独立方案: 要在 web-shell 侧边栏暴露会话归档/取消归档,我会给 对比: PR 的实现匹配并超出了这个方案——不是添加单独的按钮,而是引入了一个精致的"…"溢出菜单模式(重命名/归档/删除)和单独的归档快捷按钮。比分散的单独按钮体验更好。没有遗漏更简单的路径。 发现(非阻塞):
未发现关键阻塞问题或 AGENTS.md 违规。 测试侧边栏测试:11 个全部通过(5 个新增覆盖归档/恢复/溢出菜单)。webui 测试:251 个全部通过。类型检查无新增错误。 真实场景测试本 PR 修改的是基于浏览器的 web-shell UI,不是 CLI TUI。基于 tmux 的真实场景测试不适用。作者提供了 macOS 上的 Playwright 证据(归档→已归档→恢复往返验证通过,确认 — Qwen Code · qwen3.7-max |
|
This PR closes a clear, real gap: session archive/unarchive landed in the backend (#6058) but was never surfaced in the web-shell sidebar. The implementation is focused, well-tested, and follows project conventions. What I like: the overflow menu pattern is a clean UX improvement over scattered inline buttons. The code is thin wiring over existing SDK methods — no new abstractions, no scope creep. Both active and archived lists stay in sync after every mutation. Accessibility attributes are correct throughout. 11 sidebar tests (5 new) cover the core archive/restore/menu flows, and all 251 webui tests pass. One thing for the maintainer to confirm: the sidebar quick-action button changed from Rename to Archive (Rename moved into the "…" menu). This seems like the right tradeoff — archive is probably more common — but worth a second look. No blocking concerns. LGTM. ✅ 中文说明这个 PR 填补了一个明确、真实的功能缺口:会话归档/取消归档在后端(#6058)已经落地,但 web-shell 侧边栏一直没有暴露。实现聚焦、测试充分、遵循项目规范。 亮点:溢出菜单模式是对分散的按钮的一个干净的 UX 改进。代码是对现有 SDK 方法的薄接线——没有新的抽象,没有范围蔓延。每次操作后活跃和已归档列表保持同步。无障碍属性全部正确。11 个侧边栏测试(5 个新增)覆盖了核心的归档/恢复/菜单流程,251 个 webui 测试全部通过。 一个需要 maintainer 确认的点:侧边栏快捷操作按钮从"重命名"换成了"归档"("重命名"移入了"…"菜单)。这看起来是正确的取舍——归档可能比重命名更常用——但值得再确认一下。 无阻塞问题。LGTM. ✅ — Qwen Code · qwen3.7-max |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
No review findings. Downgraded from Approve to Comment: CI still running.
— qwen3.7-max via Qwen Code /review
ytahdn
left a comment
There was a problem hiding this comment.
LGTM — well-structured implementation with clean overflow menu pattern and proper accessibility attributes. All 262 tests pass.
A few non-blocking suggestions:
confirmDeleteSessionmissing busy guard:handleArchive/handleUnarchivecheckbusySessionIdRef.currentbefore proceeding, butconfirmDeleteSessiondoesn't. Consider adding the same guard for consistency.- Test coverage gaps: Three new code paths lack coverage —
isArchiveddelete routing, archived overflow menu items, and the delete-from-menu → confirm → delete full path. - Archive/unarchive button disabled state: These buttons don't reflect
busystate during operations, unlike the delete flow which has a confirm dialog as natural barrier.
— qwen3.7-max via Qwen Code /review
What this PR does
Adds session management to the web-shell sidebar. Each session row now has an Archive quick action plus a "…" overflow menu (Rename / Archive / Delete), and a new collapsible "Archived" section lazily lists archived sessions, each with Restore / Delete. Under the hood it threads the daemon's existing
archiveStatelist filter and thePOST /sessions/archive/POST /sessions/unarchiveendpoints up through thewebuiworkspace facade and theuseDaemonSessionshook. The daemon, ACP, and TypeScript SDK layers already shipped archive/unarchive in #6058 — this PR is the missing UI + facade wiring, with no changes to the SDK, daemon, or core.Why it's needed
Session archiving landed end-to-end in the daemon and TypeScript SDK (#6058) but was never surfaced in the web-shell UI, so browser users had no way to archive, restore, or manage past conversations from the sidebar — the active list only ever grew. This closes that last-mile gap so a growing workspace stays tidy without leaving the browser.
Reviewer Test Plan
How to verify
Run
qwen serve --webin a workspace that already has a few past sessions and open the sidebar. Hover a session row: an Archive (box) button and a "…" button appear. Click Archive → the session leaves the active list. Click "…" → a menu with Rename / Archive / Delete. Expand the "Archived" section at the bottom of the list → archived sessions appear with a count badge, each offering Restore / Delete. Click Restore → the session returns to the active list.Behavior tied to the daemon contract (worth confirming): rename is enabled only for the current (loaded) session — the daemon metadata endpoint is live-session-only; the current session's Archive/Delete are disabled (archiving would tear down its running turn); archived rows can't be opened directly (the daemon returns
409 session_archived), so their row offers Restore, not load; Delete uses the hard-delete endpoint (removes the transcript, behind a confirm dialog); after any archive/unarchive/delete both the active and archived lists refetch.Automated:
npx vitest runpasses inpackages/webui(251 tests) andpackages/web-shell(806 tests, incl. 11 sidebar tests — 5 new covering the archive quick action, the current-session guard, the overflow menu contents, and the archived expand → restore flow). Typecheck:tsc -p tsconfig.lib.json(web-shell) andtsc --noEmit(webui) are clean.Real end-to-end drive (macOS): seeded three sessions on disk, ran
qwen serve --web, and drove the real built bundle with Playwright — the archive → archived → restore round-trip works and the browser genuinely issuesPOST /sessions/archive(200) andPOST /sessions/unarchive(200), each followed by a re-list of both the active and archived directories (verified in the daemon log).Evidence (Before & After)
Before: the sidebar listed sessions with Rename/Delete inline only — no archive action and no way to see or restore archived sessions.
After:
Overflow "…" menu on a session row (Rename disabled because no session is the current one; Delete in danger red):
Archived section expanded (count badge + archived session with a Restore action), active list now one shorter:
Tested on
Environment
qwen serve --webserving the builtpackages/web-shell/dist; Playwright (headless Chromium) for the browser drive; unit tests viavitest.Risk & Scope
webuifacade delegation; the archive/unarchive/delete data paths are the daemon endpoints already shipped and tested in feat(daemon): Add session archive support #6058, so the new surface area is the sidebar interactions and the two facade methods.archiveStateto thewebuilistSessionsfacade option and two new facade/hook methods (archiveSession/unarchiveSession); no existing signatures change.Linked Issues
Builds on #6058 (daemon + SDK session archive support). No issue to auto-close.
中文说明
这个 PR 做了什么
给 web-shell 侧边栏加上会话管理。每个会话行现在有一个归档快捷按钮,外加一个 "…" 溢出菜单(重命名 / 归档 / 删除);列表底部新增一个可折叠的**"已归档"区域,懒加载列出已归档会话,各带恢复 / 删除**。底层把 daemon 现成的
archiveState列表过滤,以及POST /sessions/archive/POST /sessions/unarchive端点,透过webui的 workspace facade 和useDaemonSessionshook 接上来。daemon、ACP、TypeScript SDK 这几层在 #6058 已经实现了归档/取消归档——本 PR 只是补上缺失的 UI + facade 接线,不改 SDK、daemon、core。为什么需要
会话归档在 daemon 和 TypeScript SDK 层已经端到端落地(#6058),但一直没有在 web-shell UI 暴露,所以浏览器用户无法从侧边栏归档、恢复或管理历史会话——活跃列表只会越积越长。本 PR 补上这最后一公里,让工作区增长时也能在浏览器里保持整洁。
评审验证方案
如何验证
在一个已有若干历史会话的工作区运行
qwen serve --web并打开侧边栏。悬停某个会话行:出现归档(方框图标)按钮和 "…" 按钮。点归档 → 该会话从活跃列表消失。点 "…" → 弹出重命名 / 归档 / 删除菜单。展开列表底部的**"已归档"区域 → 已归档会话带计数徽章显示,各带恢复 / 删除**。点恢复 → 会话回到活跃列表。与 daemon 契约相关、值得确认的行为:重命名仅对当前(已加载)会话可用(daemon 的元数据端点只支持活跃会话);当前会话的归档/删除置灰(归档会强制结束其正在运行的 turn);已归档行不能直接打开(daemon 返回
409 session_archived),所以它给的是恢复而非加载;删除走硬删端点(删除 transcript,带二次确认);任何归档/取消归档/删除之后,活跃和已归档两个列表都会重新拉取。自动化:
npx vitest run在packages/webui(251 测试)和packages/web-shell(806 测试,含 11 个侧边栏测试——其中 5 个新增,覆盖归档快捷键、当前会话守卫、溢出菜单内容、以及展开已归档→恢复的流程)全部通过。类型检查tsc -p tsconfig.lib.json(web-shell)和tsc --noEmit(webui)干净。真实端到端(macOS):在磁盘上 seed 了三个会话,跑真
qwen serve --web,用 Playwright 驱动真实构建产物——归档 → 已归档 → 恢复往返正常,且浏览器确实发出POST /sessions/archive(200)与POST /sessions/unarchive(200),每次之后都重新列了活跃与归档两个目录(在 daemon 日志中确认)。证据(前 / 后)
之前:侧边栏只在行内提供重命名/删除——没有归档动作,也无法查看或恢复已归档会话。
之后:见上方英文部分的两张截图(会话行的"…"溢出菜单;展开的已归档区域,带计数徽章与恢复动作)。
测试平台
仅本地 macOS 测试(✅);Windows / Linux 未本地测试(⚠️ ),由 CI 覆盖。
环境
qwen serve --web服务构建后的packages/web-shell/dist;Playwright(无头 Chromium)做浏览器驱动;单测用vitest。风险与范围
webuifacade 委托;归档/取消归档/删除的数据路径是 feat(daemon): Add session archive support #6058 已发布并测试过的 daemon 端点,新增面主要是侧边栏交互与两个 facade 方法。webui的listSessionsfacade 选项加了可选的archiveState,并新增两个 facade/hook 方法(archiveSession/unarchiveSession);未改动任何既有签名。关联 Issue
基于 #6058(daemon + SDK 会话归档支持)。无需自动关闭的 issue。