fix(cli): hide completed sticky todos#4635
Conversation
wenshao
left a comment
There was a problem hiding this comment.
[Suggestion] getStickyTodosLayoutKey in packages/cli/src/ui/utils/todoSnapshot.ts also needs to be updated to mirror the new completed-todo filtering. Currently it serializes the raw todos array (without sorting or filtering) into the layout key used as a useLayoutEffect dependency in AppContainer.tsx for footer height measurement. When a todo transitions to completed, the rendered sticky panel shrinks but the layout key stays the same, so controlsHeight goes stale — causing a transient scroll-region miscalculation until the next unrelated trigger (buffer change, terminal resize) re-measures.
Suggested fix: apply the same getOrderedStickyTodos + .filter(status !== 'completed') in getStickyTodosLayoutKey, and include todo.status in the serialized key so status transitions trigger re-measurement.
— qwen3.7-max via Qwen Code /review
| const orderedTodos = useMemo(() => getOrderedStickyTodos(todos), [todos]); | ||
| const orderedOpenTodos = useMemo( | ||
| () => | ||
| getOrderedStickyTodos(todos).filter( |
There was a problem hiding this comment.
[Suggestion] This filter introduces a cross-file consistency gap: getStickyTodosLayoutKey in todoSnapshot.ts still computes its layout key from the raw, unsorted, unfiltered todos array. The layout key is used as a useLayoutEffect dependency in AppContainer.tsx for footer height re-measurement. When a todo transitions to completed, the component correctly hides it, but the layout key doesn't change — leaving controlsHeight stale by the height delta of the hidden row(s). This manifests as a transient scroll-region glitch that self-corrects on the next terminal event.
Consider updating getStickyTodosLayoutKey to apply the same getOrderedStickyTodos(todos).filter(t => t.status !== 'completed') and include todo.status in the serialized entries. Also worth cleaning up: strikethrough={todo.status === 'completed'} and STATUS_ICONS.completed are now dead code since completed items never reach the render loop.
— qwen3.7-max via Qwen Code /review
|
Addressed in The layout key now mirrors the rendered sticky todo set:
Validation run locally:
No package-lock change is included. |
wenshao
left a comment
There was a problem hiding this comment.
R2 re-review after the getStickyTodosLayoutKey update — that suggestion is fully addressed. This round found 0 Critical + 5 Suggestions (2 inline below, 3 additional):
- Dead code (not in diff):
STATUS_ICONS.completed(L31) andstrikethrough={todo.status === 'completed'}(L108) are now unreachable since completed todos are filtered before the render loop. Consider removing both. getStickyTodosRenderKeymismatch (L134-140): The memo comparator still usesgetStickyTodosRenderKeywhich serializes ALL todos including completed. Content changes to completed todos trigger a re-render with no visible effect. Consider filtering completed todos in the render key too.
— qwen3.7-max via Qwen Code /review
| }); | ||
|
|
||
| it('hides the sticky panel when every task is completed', () => { | ||
| const todos: TodoItem[] = [ |
There was a problem hiding this comment.
[Suggestion] This assertion (not.toContain('... and 9 more')) only excludes the old incorrect count. If a future refactor accidentally produces ... and 8 more or ... and 3 more, this test would still pass.
A broader assertion would catch more regressions:
expect(output).not.toContain('... and');This confirms the hidden-item summary is entirely absent (since all 9 filtered-out completed items are excluded from the count).
— qwen3.7-max via Qwen Code /review
| const visibleTodos = todos.slice(0, visibleTodoCount); | ||
| const hasHiddenTodos = todos.length > visibleTodos.length; | ||
| const orderedOpenTodos = getOrderedStickyTodos(todos).filter( | ||
| (todo) => todo.status !== 'completed', |
There was a problem hiding this comment.
[Suggestion] This getOrderedStickyTodos(todos).filter((todo) => todo.status !== 'completed') is identical to the one in StickyTodoList.tsx:48-52. If the filter predicate changes in one place but not the other, the layout key will diverge from what the component actually renders — causing stale controlsHeight or missed re-layouts.
Consider extracting a shared helper (e.g. getOpenStickyTodos) in this file and calling it from both getStickyTodosLayoutKey and the component.
Also: getStickyTodosLayoutKey lacks a test for the all-completed input case (where orderedOpenTodos is empty). Since this function is exported, a quick assertion against JSON.stringify({ ..., todos: [] }) would guard against future regressions.
— qwen3.7-max via Qwen Code /review
Verification ReportBranch: Test Results
Code Review Notes
Verdict✅ Ready to merge — all PR-specific checks pass, behavior changes are well-tested with updated and new test cases. Verified by wenshao |
BZ-D
left a comment
There was a problem hiding this comment.
LGTM. 完成的 todo 隐藏后编号保留原始顺序、layout key 与渲染逻辑保持同步,全部完成时 panel 正确隐藏。
Summary
Current taskspanel.Fixes #4631
Test Plan