feat(web-shell): revamp floating todo panel interactions#5069
Conversation
The "Current tasks" panel above the composer was a static display:
always expanded, rotate-to-front ordering with jumbled numbering,
no progress summary, and it vanished the instant the last item
completed.
- Collapsible header (persisted in localStorage); collapsed mode is a
single line showing progress + the current in-progress item
- Progress counter (completed/total) in the header
- Natural-order window anchored on the in-progress item replaces the
rotation: one completed context line above, pendings below, with
clickable "N completed" / "N more" summary lines that expand the
full list (and "Show less" to return)
- All-done moment: a finished list stays visible as "All tasks
completed" until the next user prompt instead of disappearing
instantly; historical finished lists stay hidden on session restore
- Locate button scrolls the transcript to the source TodoWrite/plan
message with a flash highlight (new MessageList imperative
scrollToMessage, callId fallback for compact-merged tool groups)
- Visual consistency: in_progress uses the accent color, PlanMessage
adopts the shared icon set, items ellipsize to one line with a
hover tooltip, and the number column scales past 9 items so the
status icons stay aligned
getFloatingTodos moves to utils/todos.ts and now reports
{todos, allCompleted, sourceMessageId, sourceCallId}; panel visibility
is a render-time state machine so the active-to-completed transition
does not unmount the panel for a frame. New i18n keys for en/zh-CN
and 17 new unit tests.
Code Coverage Summary
CLI Package - Full Text ReportCore Package - Full Text ReportFor detailed HTML reports, please see the 'coverage-reports-22.x-ubuntu-latest' artifact from the main CI run. |
|
@qwen-code /triage |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Hey @wenshao — the PR description is detailed and the screenshots are great, but it doesn't follow the PR template. The main gap is the Reviewer Test Plan — that's the section maintainers use to verify the change works. Could you restructure the body to match the template? Specifically:
- What this PR does / Why it's needed — your Summary covers this, just needs the headings
- Reviewer Test Plan — how a reviewer can confirm the collapsible panel, windowed ordering, locate-in-transcript, and all-done moment work as described. The "Tests" section lists unit test counts but doesn't tell a reviewer what to click or what to expect visually
- Risk & Scope / Linked Issues — missing entirely
The content is all here — it's mostly a restructure. Thanks!
中文说明
@wenshao PR 描述内容很详细,截图也很好,但没有按照 PR 模板 的格式来写。主要缺少的是 Reviewer Test Plan(审查者测试计划)——这是维护者用来验证功能是否正常工作的部分。能否按模板重新组织一下?具体来说:
- What this PR does / Why it's needed — Summary 部分已经覆盖了,只需要改一下标题
- Reviewer Test Plan — 审查者如何确认折叠面板、窗口排序、会话中定位、全部完成等功能是否正常。"Tests" 部分列出了单元测试数量,但没有告诉审查者具体要点击什么、视觉上应该看到什么
- Risk & Scope / Linked Issues — 完全缺失
内容都在,主要是重新组织一下格式。谢谢!
— Qwen Code · qwen3.7-max
Resolves a conflict in MessageList.tsx: my forwardRef wrapper (imperative scrollToMessage handle) coexists with main's new MessageList props (shellOutputMaxLines, showRetryHint, onRetryClick) — both sides kept. Also folds in the /review feedback on this PR: - scrollToMessage now engages the scrollCooldown guard and uses an instant (non-smooth) scroll, so the locate-induced scroll events can't flow through handleScroll and let Rule 3 (near-bottom -> resume follow) re-enable follow and yank the viewport back to the tail mid-stream - adds tests for getFloatingTodos on an all-completed plan message and for the getTodoStatusIcon glyph mapping
|
@qwen-code /triage |
|
Thanks for the PR, @wenshao! Template looks good ✓ — all required sections present and filled in, bilingual description is thorough. On direction: this is squarely in the web-shell UX improvement lane. The CHANGELOG shows prior todo panel work on the CLI side (#3507 sticky panel, #3647 compact panel), and the web-shell has been getting polish passes recently (#5005 keyboard shortcuts). Making the floating todo panel interactive and space-efficient is a natural next step — real friction points like the jumbled numbering, vanishing "done" moment, and inert "… and N more" text are well-identified. On approach: the scope is substantial (12 files, +1219/−495) but most of that is the TodoPanel component rewrite, which is inherently restructuring. The core logic additions are focused: Moving on to code review. 🔍 中文说明感谢贡献,@wenshao! 模板完整 ✓ —— 所有必要章节齐全,双语描述详尽。 方向:属于 web-shell UX 改进方向。CHANGELOG 中有 CLI 端 todo 面板的先例(#3507 粘性面板、#3647 紧凑面板),web-shell 最近也一直在打磨(#5005 快捷键)。把浮动任务面板做成可交互、省空间是顺理成章的事——编号错乱、完成时刻消失、"… 还有 N 个"不可点击等痛点定位准确。 方案:范围较大(12 个文件,+1219/−495),但大部分是 TodoPanel 组件的重构。核心逻辑增量很集中: 进入代码审查 🔍 — Qwen Code · qwen3.7-max |
Code ReviewRead the diff against my independent proposal. The PR's approach matches what I'd have done: extract No critical blockers found. A few observations:
Code follows project conventions throughout. No over-abstraction, no speculative features. Unit TestsRan the full web-shell test suite on the PR branch: All 245 tests pass. New tests for Dev Server Smoke TestStarted the Vite dev server from the PR branch in tmux: Server starts cleanly with no warnings or errors. The web-shell is a browser-based React app, so UI interactions (collapse, locate scroll, flash animation) can't be tested via tmux — they require a real browser. The PR author provides before/after screenshots and manual verification on macOS. The unit tests cover the logic layer comprehensively. 中文说明代码审查对照我的独立方案阅读了 diff。PR 的方案与我的思路一致:把 未发现关键阻塞问题。几个观察:
代码全程遵循项目规范。没有过度抽象,没有投机性功能。 单元测试在 PR 分支上运行了完整的 web-shell 测试套件:16 个文件 / 245 个测试全部通过。新增测试覆盖了 开发服务器冒烟测试在 tmux 中从 PR 分支启动 Vite 开发服务器,启动干净无警告或错误。web-shell 是基于浏览器的 React 应用,UI 交互(折叠、定位滚动、闪烁动画)无法通过 tmux 测试——需要真实浏览器。PR 作者提供了前后对比截图和 macOS 上的手动验证。单元测试全面覆盖了逻辑层。 — Qwen Code · qwen3.7-max |
|
Stepping back to look at the whole picture: this PR takes a static, space-wasting todo panel and turns it into something genuinely useful — collapsible, windowed, with a locate button and a proper "all done" moment. The motivation is clear, the before/after screenshots make the improvement obvious, and the implementation is solid. My independent proposal would have been: extract the logic, add collapse/expand with localStorage, window the list, add a locate button. That's essentially what this PR does, and it does it well. The 245/245 tests pass. The new tests are thorough — they cover the happy paths, edge cases (everything completed, anchor near the end, parallel agents), and the locate-button fallback logic. The dev server starts without warnings. The scope is large in raw numbers (12 files, ~1700 lines touched) but each file change serves a clear purpose and the diff is well-organized. No speculative features, no over-abstraction. The i18n coverage is complete for both languages. This is a well-executed UI improvement. Approving. ✅ 中文说明整体来看:这个 PR 把一个静态、占空间的任务面板改造成了真正好用的东西——可折叠、窗口化、带定位按钮和恰当的"全部完成"时刻。动机清晰,前后对比截图让改进一目了然,实现也很扎实。 我的独立方案会是:提取逻辑、用 localStorage 添加折叠/展开、窗口化列表、加定位按钮。这基本就是 PR 所做的事情,而且做得很好。 245/245 测试通过。新测试很全面——覆盖了正常路径、边界情况(全部完成、锚点靠近末尾、并行代理)和定位按钮的回退逻辑。开发服务器启动无警告。 范围在原始数字上较大(12 个文件,约 1700 行变更),但每个文件的变更都有明确目的,diff 组织良好。没有投机性功能,没有过度抽象。i18n 双语覆盖完整。 这是一个执行良好的 UI 改进。批准。✅ — Qwen Code · qwen3.7-max |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
The "Current tasks" panel above the composer was a static display:
always expanded, rotate-to-front ordering with jumbled numbering,
no progress summary, and it vanished the instant the last item
completed.
- Collapsible header (persisted in localStorage); collapsed mode is a
single line showing progress + the current in-progress item
- Progress counter (completed/total) in the header
- Natural-order window anchored on the in-progress item replaces the
rotation: one completed context line above, pendings below, with
clickable "N completed" / "N more" summary lines that expand the
full list (and "Show less" to return)
- All-done moment: a finished list stays visible as "All tasks
completed" until the next user prompt instead of disappearing
instantly; historical finished lists stay hidden on session restore
- Locate button scrolls the transcript to the source TodoWrite/plan
message with a flash highlight (new MessageList imperative
scrollToMessage, callId fallback for compact-merged tool groups)
- Visual consistency: in_progress uses the accent color, PlanMessage
adopts the shared icon set, items ellipsize to one line with a
hover tooltip, and the number column scales past 9 items so the
status icons stay aligned
getFloatingTodos moves to utils/todos.ts and now reports
{todos, allCompleted, sourceMessageId, sourceCallId}; panel visibility
is a render-time state machine so the active-to-completed transition
does not unmount the panel for a frame. New i18n keys for en/zh-CN
and 17 new unit tests.
What this PR does
Reworks the "Current tasks" floating panel above the Web Shell composer from a static display into an interactive, space-efficient component. It becomes collapsible (one-line summary with a progress counter, persisted across reloads), reorders the list into a natural-order window anchored on the in-progress item (with clickable summary lines that expand the full list), keeps a finished list visible as an "all done" moment until the next prompt instead of vanishing, adds a button that scrolls the transcript to the message the list came from and flash-highlights it, and aligns the status icons (
●/◐/○) with the rest of the UI — including keeping them aligned once the list grows past nine items.Why it's needed
The old panel was always fully expanded (up to ~6 rows occupying the space directly above the input), used a rotate-to-front ordering that produced jumbled numbering (
4. 5. … 1.) with completed items pushed below pending ones, had no progress summary, rendered an inert… and N moreline, and disappeared the instant the last item completed (so the "done" moment had no feedback). It also drifted from the transcript's own task rendering (✓/→vs●/◐/○). These are the friction points this PR removes.Reviewer Test Plan
How to verify
npm run devinpackages/web-shell), open a session, and give the agent a task that emits aTodoWritelist with 6+ items so the panel appears above the composer.▸ Current tasks 3/7 ◐ <current item>; reload the page — it stays collapsed (state is inlocalStorage).✓ N completed/… N moreto expand the full list, then Show less to collapse it back.●/◐/○icons stay vertically aligned (the number column widens for the two-digit indices).↗button — the transcript scrolls to theTodoWrite/plan message that produced the list and briefly flashes it. While the agent is streaming and that source message sits near the bottom, the viewport stays on the target instead of being pulled back to the tail (this is the/reviewfix in this PR).✓ All tasks completedand stays until you send the next prompt, then clears. Reload mid-session does not resurface a historical finished list.Expected = observed for each step above.
Evidence (Before & After)
The change is also summarized below and pinned by unit tests (
utils/todos.test.ts,components/MessageList.test.ts).completed/totalcounter in the header… and N more✓ All tasks completeduntil next prompt10.shifts the row)↗scrolls + flashes the source messageTested on
Verified locally on macOS: web-shell
tsc --noEmit(no new errors),vitest run(16 files / 245 tests pass), andnpm run build(app + lib + d.ts). Windows/Linux not run locally — covered by CI, which is green on all three.Environment (optional)
npm run dev/vitestinpackages/web-shell; webui rebuilt (npm run build --workspace=packages/webui) so theSendPromptOptions.retrytype resolves after merging main.Risk & Scope
hidden | active | completedstate machine adjusted during render (not in an effect) so the active→completed transition doesn't unmount the panel for a frame; the locate scroll engages the existingscrollCooldownguard to avoid fighting follow-mode. Both are contained toApp.tsx/MessageList.tsx.localStoragekeyweb-shell:todo-panel-collapsed;PlanMessageicons change✓/→→●/◐/○(intentional unification).Linked Issues
None.
中文说明
这个 PR 做了什么
把 Web Shell 输入框上方的"当前任务"浮动面板,从静态展示重构为可交互、省空间的组件:可折叠(单行摘要 + 进度计数,刷新后保持),把列表改为以"进行中"项为锚的自然顺序窗口(并提供可点击的摘要行展开完整列表),任务全部完成后保留为"全部完成"状态直到下一次输入而不是立即消失,新增按钮可滚动到产生该列表的消息并闪烁高亮,并把状态图标(
●/◐/○)与界面其它处统一——包括任务超过 9 个时仍保持对齐。为什么需要
旧面板始终完全展开(占用输入框正上方约 6 行),采用"进行中置顶"的旋转排序导致编号错乱(
4. 5. … 1.)且已完成项排在待办项下面,没有进度汇总,"… 以及其他 N 个"是不可点击的死文本,最后一项完成时面板瞬间消失(完成时刻没有任何反馈),并且与会话内的任务渲染(✓/→对●/◐/○)不一致。本 PR 消除这些摩擦点。审查者测试计划
如何验证
packages/web-shell下npm run dev),打开会话,让 agent 执行一个会产出 6 个以上TodoWrite条目的任务,使面板出现在输入框上方。▸ 当前任务 3/7 ◐ <当前项>;刷新页面 → 仍保持折叠(状态存于localStorage)。✓ 已完成 N 项/… 还有 N 项展开完整列表,再点 收起 折回。●/◐/○图标保持纵向对齐(序号列为两位数加宽)。↗按钮 → 会话滚动到产生该列表的TodoWrite/plan 消息并短暂闪烁。当 agent 正在流式输出且该源消息靠近底部时,视口停在目标上而不会被拽回底部(这是本 PR 的/review修复)。✓ 任务已全部完成并保留到你发送下一条输入后清除;会话中途刷新不会重新冒出历史已完成列表。每一步均为 预期 = 实际。
证据(前后对比)
截图见上方英文 Evidence 段。行为变化以下表总结,并由单元测试固定(
utils/todos.test.ts、components/MessageList.test.ts)。已完成/总数计数✓ 任务已全部完成,保留到下次输入10.推歪整行)↗滚动并闪烁源消息测试平台
仅在 macOS 本地验证:web-shell
tsc --noEmit(无新增错误)、vitest run(16 文件 / 245 测试通过)、npm run build(app + lib + d.ts)。Windows/Linux 未本地运行——由 CI 覆盖,三平台均为绿。运行环境(可选)
packages/web-shell下npm run dev/vitest;合并 main 后重建了 webui(npm run build --workspace=packages/webui)以使SendPromptOptions.retry类型可解析。风险与范围
hidden | active | completed状态机,在 render 期间(而非 effect 中)调整,使"活跃→完成"的转变不会让面板掉帧消失;定位滚动复用了已有的scrollCooldown守卫以避免与跟底模式冲突。两者都局限在App.tsx/MessageList.tsx。localStorage键web-shell:todo-panel-collapsed;PlanMessage图标由✓/→改为●/◐/○(有意统一)。关联 Issue
无。