Skip to content
This repository was archived by the owner on Jul 30, 2026. It is now read-only.

refactor(tui): store list interaction per tab - #108

Merged
makoMakoGo merged 3 commits into
personal/local-clientsfrom
codex/issue-98-tui-interaction-state
Jul 4, 2026
Merged

refactor(tui): store list interaction per tab#108
makoMakoGo merged 3 commits into
personal/local-clientsfrom
codex/issue-98-tui-interaction-state

Conversation

@makoMakoGo

@makoMakoGo makoMakoGo commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Summary

  • Store list selection, scroll, and visible capacity in per-tab ListInteraction state.
  • Remove the daily/period parent-list shadow fields and route detail entry/exit through stored tab interactions.
  • Consolidate Daily and Period detail sort context handling into one parameterized state path.
  • Preserve the parent list visible capacity when leaving Daily/Period detail so detail viewport height cannot overwrite parent tab state.
  • Reset only the Hourly tab interaction when toggling Hourly table/profile view, leaving other tabs' stored interactions intact.

Closes #98

Built on the current personal/local-clients baseline.

Interaction Checklist

  • Tab switching preserves each tab's own selection/scroll state: covered by test_switch_tab_preserves_each_tab_list_interaction.
  • Switching away from Daily detail restores the parent Daily list state when returning: covered by test_switch_tab_from_daily_detail_restores_daily_parent_state.
  • Exiting Daily/Period detail restores the parent list's full ListInteraction, including visible: covered by test_esc_from_daily_detail_restores_daily_selection and test_esc_from_weekly_detail_restores_week_selection.
  • Toggling Hourly table/profile view resets only Hourly state and preserves other tabs' stored interactions: covered by test_hourly_view_toggle_preserves_other_tab_interactions.
  • Detail enter/exit and sort switching remain covered by the existing Daily/Period detail tests.
  • Mouse click and scroll paths remain covered by the existing app mouse tests.
  • Resize clamp behavior remains covered by the existing resize tests.

Validation

  • rg -n "daily_list_|period_list_" crates/tokscale-cli/src/tui/app.rs returns no matches
  • cargo fmt --all --check
  • cargo clippy --workspace --all-targets
  • cargo test -p tokscale-cli test_esc_from_daily_detail_restores_daily_selection (1 passed, 817 filtered out)
  • cargo test -p tokscale-cli test_esc_from_weekly_detail_restores_week_selection (1 passed, 817 filtered out)
  • cargo test -p tokscale-cli test_hourly_view_toggle_preserves_other_tab_interactions (1 passed, 817 filtered out)
  • cargo test -p tokscale-cli test_hourly_view_mode_toggle (1 passed, 818 filtered out)
  • cargo test -p tokscale-cli switch_tab (8 passed, 810 filtered out)
  • cargo test -p tokscale-cli (817 passed, 1 ignored)
  • cargo test -p tokscale-core test_driver_uses_simple_file_adapter_when_only_amp_requested (1 passed, 1074 filtered out)
  • cargo test --workspace (1889 passed, 4 ignored)
  • git diff --name-status fork/personal/local-clients...HEAD shows only crates/tokscale-cli/src/tui/app.rs

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@makoMakoGo, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 41 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9cf4afeb-750f-4bb2-b544-15f562b13700

📥 Commits

Reviewing files that changed from the base of the PR and between d25d380 and da8e732.

📒 Files selected for processing (1)
  • crates/tokscale-cli/src/tui/app.rs

Walkthrough

本次改动重构了 TUI App 的列表选中/滚动状态管理,引入按 Tab 索引的 list_interactions 映射与按类型索引的 detail_sort_contexts 映射,替换了原先针对 Daily/Period 各自维护的分散字段,并更新了 Tab 切换、详情进出、鼠标/键盘事件处理及相关测试。

Changes

列表交互与详情排序状态统一

Layer / File(s) Summary
数据结构定义与字段迁移
crates/tokscale-cli/src/tui/app.rs
新增 DetailSortContextKind/DetailSortContext 类型;App 结构体移除分散的 Daily/Period 索引/滚动/排序字段,改为 list_interactions: HashMap<Tab, ListInteraction>detail_sort_contexts: HashMap<DetailSortContextKind, DetailSortContext>,并更新初始化逻辑。
列表交互核心管理方法
crates/tokscale-cli/src/tui/app.rs
新增获取/设置/持久化/恢复 ListInteraction 的方法集合;clamp_selection 改为操作当前 ListInteraction;apply_list_move 改为通过统一接口应用移动。
Tab 切换与输入事件处理
crates/tokscale-cli/src/tui/app.rs
update_data、键盘/鼠标 Tab 切换、图表单元格取消选择等逻辑改为持久化/恢复目标 Tab 的交互状态,不再调用旧的 reset_selection;jump_to_today 增加交互持久化。
详情排序上下文统一实现
crates/tokscale-cli/src/tui/app.rs
persist_current_sort 与进入/离开/清空详情排序上下文改为基于 DetailSortContextKind 的通用流程,取代 Daily/Period 两套重复代码;set_sort 重置策略同步更新。
Daily/Period 详情进入退出回锚逻辑
crates/tokscale-cli/src/tui/app.rs
进入详情前持久化当前列表交互,退出详情时基于 stored_list_interaction 重新计算并锚定 selected/scroll/visible 状态。
测试用例更新
crates/tokscale-cli/src/tui/app.rs
新增/替换 Tab 切换恢复选中、各 Tab 交互独立保持的测试;更新 Daily/Weekly 详情关闭场景中 stored_list_interaction 相关断言。

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant KeyboardHandler as 键盘/鼠标处理
    participant App
    participant ListInteractions as list_interactions映射

    User->>KeyboardHandler: 切换到目标Tab
    KeyboardHandler->>App: switch_tab(target)
    App->>ListInteractions: persist_current_list_interaction()
    App->>ListInteractions: stored_list_interaction(target)
    ListInteractions-->>App: 返回目标Tab的selected/scroll/visible
    App->>App: set_current_list_interaction(restored)
    App-->>User: 渲染恢复后的列表选中/滚动状态
Loading
sequenceDiagram
    participant User
    participant App
    participant ListInteractions as list_interactions映射
    participant DetailSortContexts as detail_sort_contexts映射

    User->>App: 进入Daily/Period详情
    App->>ListInteractions: persist_list_interaction_for(tab)
    App->>DetailSortContexts: enter_detail_sort_context(kind)
    User->>App: 关闭详情(ESC)
    App->>ListInteractions: stored_list_interaction(tab)
    ListInteractions-->>App: 返回stored selected/scroll/visible
    App->>App: 重建并锚定当前ListInteraction
    App->>DetailSortContexts: leave_detail_sort_context(kind)
Loading

Poem

兔子搬家不再乱翻箱,
每个 Tab 都有自己的小抽屉~
选中滚动都记牢,
排序状态也归位好,
跳来跳去不迷路,
🐇✨ 测试全绿蹦蹦跳!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed 实现了按 Tab 迁移列表交互状态、移除影子字段,并统一了 Daily/Period 详情排序上下文。
Out of Scope Changes check ✅ Passed 变更与 #98 的 TUI 交互迁移目标一致,未见明显无关或越界的改动。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了此次将 TUI 列表交互状态按 Tab 持久化的主要重构。
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/issue-98-tui-interaction-state

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@makoMakoGo makoMakoGo left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

看完 #98 的决策记录和这版 diff 后,整体方向是对的:daily/period 的影子字段已经被收进 ListInteraction/detail sort context,switch_tab 也从手写搬运变成统一 persist/restore。下面两个 inline 是同一个恢复路径问题:退出 detail 时应使用保存的 parent ListInteraction.visible,而不是当前 detail renderer 留下的 self.max_visible_items。

Comment thread crates/tokscale-cli/src/tui/app.rs Outdated
Comment thread crates/tokscale-cli/src/tui/app.rs Outdated
@makoMakoGo
makoMakoGo changed the base branch from codex/issue-91-local-only-surface to personal/local-clients July 4, 2026 04:42
@makoMakoGo
makoMakoGo force-pushed the codex/issue-98-tui-interaction-state branch from b2f7a2d to bdca036 Compare July 4, 2026 04:42

@makoMakoGo makoMakoGo left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

重新 review 了当前 head bdca036

结论:方向仍然对,但现在还不该合。之前两条 inline 仍然适用于当前文件内容:close_daily_detailclose_period_detail 在恢复 parent list viewport 时仍从 self.max_visible_items 取 visible capacity,而不是从保存的 parent ListInteraction.visible 取值。这会把 detail renderer 的可见行数混入 Daily/Monthly/Weekly parent list state,随后 clamp_selection() 又会把这个混入后的状态持久化回 tab。

建议修法保持很小:Daily 用 daily_interaction.visible.max(1),Period 用 period_interaction.visible.max(1);更干净的是直接构造/恢复一个完整的 parent ListInteraction { selected, scroll, visible },不要在 close path 上混用 detail 的 self.max_visible_items。请同时补一个 parent/detail visible capacity 不同的回归测试。

注:GitHub 不允许我在自己的 PR 上提交 Request changes,所以这里用 comment review 表达同等结论。

@codspeed-hq

codspeed-hq Bot commented Jul 4, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 27 untouched benchmarks


Comparing codex/issue-98-tui-interaction-state (da8e732) with personal/local-clients (4f47596)

Open in CodSpeed

@makoMakoGo
makoMakoGo marked this pull request as ready for review July 4, 2026 04:55

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
crates/tokscale-cli/src/tui/app.rs (1)

1578-1591: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

过往关于 visible 容量被 detail 视口污染的问题已修复:此处已改用 daily_interaction.visible 而非 self.max_visible_items,parent 列表容量得到保留。

另外,close_daily_detailclose_period_detail(Line 1646-1659)的回锚逻辑(restored_index 回退、viewport_still_holds 判断、scroll 计算、重建 ListInteraction)几乎完全一致——而这正是之前需要在两处分别修复 visible 污染 bug 的位置。建议抽取一个共用 helper(入参:tabrestored_index),让两条退出路径共享同一实现,避免后续再次出现分歧性缺陷。

♻️ 建议:抽取共用回锚 helper
fn reanchor_from_stored(&mut self, tab: Tab, restored_index: usize) {
    let stored = self.stored_list_interaction(tab);
    let max_visible = stored.visible.max(1);
    let viewport_still_holds =
        restored_index >= stored.scroll && restored_index < stored.scroll + max_visible;
    let scroll = if viewport_still_holds {
        stored.scroll
    } else {
        restored_index.saturating_sub(max_visible / 2)
    };
    self.set_current_list_interaction(ListInteraction {
        selected: restored_index,
        scroll,
        visible: stored.visible,
    });
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/tokscale-cli/src/tui/app.rs` around lines 1578 - 1591, There are two
near-identical re-anchoring paths in close_daily_detail and close_period_detail
that rebuild ListInteraction after restoring the selected index, and they should
be unified to avoid future divergence. Extract a shared helper on App, such as
reanchor_from_stored(tab, restored_index), that encapsulates the
stored_list_interaction lookup, viewport_still_holds check, scroll calculation,
and set_current_list_interaction call, and have both close_*_detail flows
delegate to it. Keep the helper using the stored interaction’s visible value so
the restored list state stays consistent across both tabs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@crates/tokscale-cli/src/tui/app.rs`:
- Around line 1578-1591: There are two near-identical re-anchoring paths in
close_daily_detail and close_period_detail that rebuild ListInteraction after
restoring the selected index, and they should be unified to avoid future
divergence. Extract a shared helper on App, such as reanchor_from_stored(tab,
restored_index), that encapsulates the stored_list_interaction lookup,
viewport_still_holds check, scroll calculation, and set_current_list_interaction
call, and have both close_*_detail flows delegate to it. Keep the helper using
the stored interaction’s visible value so the restored list state stays
consistent across both tabs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4b1cf90d-c446-4972-a778-24af6ff8f0cb

📥 Commits

Reviewing files that changed from the base of the PR and between 4f47596 and d25d380.

📒 Files selected for processing (1)
  • crates/tokscale-cli/src/tui/app.rs

@makoMakoGo makoMakoGo left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed current head d25d3805.

之前指出的 Daily/Period detail 退出问题已经修掉:close_daily_detail / close_period_detail 现在都用 parent ListInteraction.visible 计算 viewport,并通过完整 ListInteraction { selected, scroll, visible } 恢复当前状态,不再把 detail 页面的 self.max_visible_items 写回 parent tab。

新增的 Daily / Weekly 回归测试也覆盖了 parent visible=2、detail visible=5 的污染场景,并断言退出后当前 max_visible_items 与 stored parent interaction visible 都恢复为 2。

我没有新的 blocking finding。之前两个 inline thread 已标记 resolved。注:我仍然不能在自己的 PR 上提交正式 Approve,所以这里用 comment review 表达 LGTM。

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 1 file

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread crates/tokscale-cli/src/tui/app.rs Outdated

@makoMakoGo makoMakoGo left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed current head da8e732.

The Hourly v regression flagged by cubic is fixed cleanly. The key handler now calls reset_hourly_view_interaction() instead of the broad reset_selection() path, and the old broad reset helper has been removed rather than left around with ambiguous semantics. The new helper only resets the current Hourly list interaction and the hourly profile text viewport scroll, so stored interactions for Models/Daily/etc. are preserved.

The added test_hourly_view_toggle_preserves_other_tab_interactions covers the intended boundary: Models and Daily both save non-zero interactions, Hourly toggles table/profile and resets its own state, then switching back restores Models and Daily selected/scroll/visible.

Previously resolved Daily/Period detail visible restoration still looks correct, and the old review threads plus cubic's P2 thread are resolved. I found no new blocking issues. Since this is the author's own PR, I can only leave a comment review here; semantically this is LGTM pending the remaining in-progress workflows completing successfully.

@makoMakoGo
makoMakoGo merged commit 72b27dc into personal/local-clients Jul 4, 2026
8 checks passed
@makoMakoGo
makoMakoGo deleted the codex/issue-98-tui-interaction-state branch July 4, 2026 15:14
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A3: 完成 TUI interaction seam 迁移

1 participant