Skip to content

feat: add all-tools period aggregation views#158

Merged
mike1858 merged 3 commits into
Piebald-AI:mainfrom
jimyag:feat/all-tools-period-views
May 14, 2026
Merged

feat: add all-tools period aggregation views#158
mike1858 merged 3 commits into
Piebald-AI:mainfrom
jimyag:feat/all-tools-period-views

Conversation

@jimyag
Copy link
Copy Markdown
Contributor

@jimyag jimyag commented May 13, 2026

Summary

This PR adds broader period-based aggregation support to the TUI and introduces a combined All Tools view so reviewers can inspect total usage across all tracked tools in one place.

Key Changes

  • add daily, weekly, monthly, and yearly aggregation modes in the TUI
  • use ISO week grouping for weekly views, with weeks starting on Monday
  • add an All Tools tab that combines usage from every analyzer and supports the same period switching, search, and drilldown behavior as individual tool tabs
  • generalize period filtering so session drilldown and totals work consistently across day/week/month/year views
  • extend TUI tests to cover weekly/yearly aggregation, period matching, and the combined tab behavior

Testing

  • cargo fmt --all --quiet
  • cargo build --quiet
  • cargo test --quiet
  • cargo clippy --quiet -- -D warnings
  • cargo doc --quiet

Summary by CodeRabbit

  • New Features

    • Added weekly and yearly aggregation modes, enabling broader time-period views beyond daily and monthly.
    • Introduced "All Tools" combined view for cross-tool data aggregation.
    • Enhanced navigation with period-based jumping (week/month/year drilling).
  • Improvements

    • Improved session filtering to respect selected time periods.
    • Refined UI state management for time-period filtering.

Review Change Stack

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 13, 2026

Warning

Rate limit exceeded

@jimyag has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 50 minutes and 18 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 49ccdf16-b773-4a68-be0f-d94a7f01ddb0

📥 Commits

Reviewing files that changed from the base of the PR and between 7ebacec and 26ddf91.

📒 Files selected for processing (3)
  • src/tui.rs
  • src/tui/logic.rs
  • src/tui/tests.rs
📝 Walkthrough

Walkthrough

The PR introduces weekly and yearly aggregation support to the TUI by generalizing day-based filtering into a PeriodFilter enum and refactoring date-matching, aggregation, and UI state to support multiple temporal scopes. Navigation, drilling, and rendering all adapt to the new period-based model with an added synthetic "All Tools" combined view.

Changes

Weekly/Yearly Period Aggregation

Layer / File(s) Summary
PeriodFilter enum and period-aware helpers
src/tui.rs (60–322)
PeriodFilter enum with Day/Week/Month/Year variants includes parsing, matching, and display logic; AggregateViewMode::next() cycles view modes; filtered_session_count() and formatting helpers compute session row counts and display period labels for week/year aggregations.
Date parsing and period-based aggregation
src/tui/logic.rs (8–335)
Adds chrono imports and introduces ISO week parsing, year-matching, and week-key interpretation; aggregate_daily_stats_by_period() generic function groups daily stats by period (YYYY-MM / YYYY-Www / YYYY) with representative dates and summed metrics; month/week/year rollups rewritten to use the shared helper.
UI state and display stats computation
src/tui.rs (333–521)
UiState now tracks session_period_filters Vec instead of day filters; build_display_stats() aggregates an "All Tools" synthetic tab with combined daily stats and sessions, prepended to per-analyzer tabs; run_app initializes and recomputes display stats on stats updates.
Navigation, drilling, and input handling
src/tui.rs (569–1028)
Left/right/up/down/home/end navigation updated to use display_stats bounds and filtered_session_count() with period filters; Enter-drill computes and stores a PeriodFilter for session filtering; Ctrl+T resets period filters; view-mode cycling uses next().
Rendering: UI output and display updates
src/tui.rs (1053–2429)
draw_ui accepts display_stats and updates tab/analyzer selection; draw_session_stats_table filters rows by period; draw_summary_stats applies period filtering and shows "Totals for " titles; aggregate period headers/labels updated for Weekly/Yearly modes; help text labels adjusted.
Imports and test coverage
src/tui.rs (16–26), src/tui/tests.rs (3–644)
Import adjustments add aggregation functions; tests updated for PeriodFilter and "All Tools" tab; new tests for ISO week/year matching, period-based aggregation, and week/year display formatting.

Sequence Diagram

sequenceDiagram
  participant User as User Input
  participant NavLogic as Navigation Logic
  participant DisplayStats as Display Stats
  participant PeriodFilter as Period Filters
  participant Sessions as Session Table
  participant Render as Render Engine
  User ->> NavLogic: Enter (drill aggregate→session)
  NavLogic ->> DisplayStats: Get selected aggregate period
  DisplayStats ->> PeriodFilter: Compute PeriodFilter (week/month/year)
  PeriodFilter ->> Sessions: Filter sessions by period
  Sessions ->> Render: Render filtered session table
  Render ->> User: Display period-filtered sessions
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Piebald-AI/splitrail#133: Both PRs refactor TUI date filtering and aggregation logic; this PR generalizes PeriodFilter and aggregate_daily_stats_by_period for week/year/month support, while the retrieved PR adds the initial monthly aggregation foundation.

Suggested reviewers

  • mike1858

Poem

🐰 With periods now swinging week by week,
And year-long stats at users' peak,
The TUI hops through time's vast span—
From day to week to month's grand plan!
Filtering flows through period's embrace,
At last, aggregation finds its place! 🌙

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 76.60% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main changes: introducing period-based aggregation (daily, weekly, monthly, yearly) and an 'All Tools' combined view for the TUI.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (4)
src/tui.rs (2)

2426-2435: 💤 Low value

Simplify update_period_filters — the truncate is redundant after resize.

Vec::resize(new_len, value) already truncates when new_len < current_len, so the explicit truncate (and the old_len capture) are dead code that misleads readers about what resize does.

♻️ Proposed simplification
 fn update_period_filters(filters: &mut Vec<Option<PeriodFilter>>, filtered_count: &usize) {
-    let old_len = filters.len();
     filters.resize(*filtered_count, None);
-    if *filtered_count < old_len {
-        filters.truncate(*filtered_count);
-    }
 }
🤖 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 `@src/tui.rs` around lines 2426 - 2435, The function update_period_filters
contains redundant code: it captures old_len and calls truncate after calling
filters.resize(*filtered_count, None), but Vec::resize already truncates when
new_len < current_len; remove the dead old_len binding and the explicit
filters.truncate(*filtered_count) call, leaving only
filters.resize(*filtered_count, None) in update_period_filters to simplify and
clarify intent.

348-380: 💤 Low value

Optional: surface the source analyzer in the "All Tools" session view.

combined_sessions mixes SessionAggregates from every analyzer, but the session table (draw_session_stats_table) doesn't render analyzer_name. On the "All Tools" tab, two sessions from different tools with similar names/IDs are indistinguishable to the user. Consider adding an analyzer column (or prefixing the session label) when the tab is "All Tools".

🤖 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 `@src/tui.rs` around lines 348 - 380, The combined "All Tools" session list
loses source analyzer context because combined_sessions aggregates
SessionAggregate items without recording which analyzer they came from; update
the loop that builds combined_sessions to attach the source analyzer to each
SessionAggregate (e.g., set a new or existing field like analyzer_name or prefix
the session label) when pushing into combined_sessions in the block that
iterates filtered_stats and calls view.session_aggregates.iter().cloned(); then
update draw_session_stats_table to render the analyzer column (or parse the
prefixed label) so the "All Tools" AnalyzerStatsView shows which analyzer
produced each session.
src/tui/tests.rs (1)

105-124: 💤 Low value

Test name is stale — it now exercises period filters, not day filters.

The body uses PeriodFilter and update_period_filters, but the function name still says "day_filters", which makes it harder to find/grep when revisiting this area.

♻️ Proposed rename
-fn test_update_window_offsets_and_day_filters_resize() {
+fn test_update_window_offsets_and_period_filters_resize() {
🤖 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 `@src/tui/tests.rs` around lines 105 - 124, The test function name is
misleading — it references "day_filters" but the body exercises PeriodFilter and
update_period_filters; rename the test fn to reflect that (e.g., change
test_update_window_offsets_and_day_filters_resize to
test_update_window_offsets_and_period_filters_resize) so it matches the tested
symbols (PeriodFilter, update_period_filters, update_window_offsets) and
improves discoverability.
src/tui/logic.rs (1)

256-284: ⚡ Quick win

Doc comment for aggregate_daily_stats_by_period is stale.

The doc still describes the previous monthly-only behavior ("Roll up daily statistics into monthly totals", "Groups daily stats by year-month..."). Since this is now the generic helper, the description is misleading. Move the monthly-specific docs to aggregate_daily_stats_by_month and add a generic description here.

📝 Proposed doc update
-/// Roll up daily statistics into monthly totals.
-///
-/// Groups daily stats by year-month (YYYY-MM) and sums all metrics. Each month
-/// entry uses day 1 of that month as its representative date. Returns a new
-/// map with monthly aggregated data.
+/// Roll up daily statistics into periods derived by `period_key_fn`.
+///
+/// `period_key_fn` returns `(period_key, representative_date)` for each `DailyStats`,
+/// and all entries sharing the same key are summed via `DailyStats += &DailyStats`.
 fn aggregate_daily_stats_by_period<F>(
     daily_stats: &BTreeMap<String, DailyStats>,
     mut period_key_fn: F,
 ) -> BTreeMap<String, DailyStats>
 where
     F: FnMut(&DailyStats) -> (String, CompactDate),
 {
...
 }
+
+/// Roll up daily statistics into monthly totals.
+///
+/// Groups daily stats by year-month (`YYYY-MM`) and sums all metrics. Each month
+/// entry uses day 1 of that month as its representative date.
 pub fn aggregate_daily_stats_by_month(
🤖 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 `@src/tui/logic.rs` around lines 256 - 284, The doc comment for
aggregate_daily_stats_by_period incorrectly describes monthly-only behavior;
replace it with a generic description that explains this function groups
DailyStats using the provided period_key_fn (which returns a (period_key,
representative_date)) and returns a new BTreeMap of aggregated DailyStats by
period, and move the existing month-specific wording ("Roll up daily statistics
into monthly totals", "Groups daily stats by year-month...") into the doc
comment for aggregate_daily_stats_by_month so that
aggregate_daily_stats_by_period's docs accurately reflect its generic helper
role.
🤖 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 `@src/tui.rs`:
- Around line 2426-2435: The function update_period_filters contains redundant
code: it captures old_len and calls truncate after calling
filters.resize(*filtered_count, None), but Vec::resize already truncates when
new_len < current_len; remove the dead old_len binding and the explicit
filters.truncate(*filtered_count) call, leaving only
filters.resize(*filtered_count, None) in update_period_filters to simplify and
clarify intent.
- Around line 348-380: The combined "All Tools" session list loses source
analyzer context because combined_sessions aggregates SessionAggregate items
without recording which analyzer they came from; update the loop that builds
combined_sessions to attach the source analyzer to each SessionAggregate (e.g.,
set a new or existing field like analyzer_name or prefix the session label) when
pushing into combined_sessions in the block that iterates filtered_stats and
calls view.session_aggregates.iter().cloned(); then update
draw_session_stats_table to render the analyzer column (or parse the prefixed
label) so the "All Tools" AnalyzerStatsView shows which analyzer produced each
session.

In `@src/tui/logic.rs`:
- Around line 256-284: The doc comment for aggregate_daily_stats_by_period
incorrectly describes monthly-only behavior; replace it with a generic
description that explains this function groups DailyStats using the provided
period_key_fn (which returns a (period_key, representative_date)) and returns a
new BTreeMap of aggregated DailyStats by period, and move the existing
month-specific wording ("Roll up daily statistics into monthly totals", "Groups
daily stats by year-month...") into the doc comment for
aggregate_daily_stats_by_month so that aggregate_daily_stats_by_period's docs
accurately reflect its generic helper role.

In `@src/tui/tests.rs`:
- Around line 105-124: The test function name is misleading — it references
"day_filters" but the body exercises PeriodFilter and update_period_filters;
rename the test fn to reflect that (e.g., change
test_update_window_offsets_and_day_filters_resize to
test_update_window_offsets_and_period_filters_resize) so it matches the tested
symbols (PeriodFilter, update_period_filters, update_window_offsets) and
improves discoverability.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7b61e13a-223f-450f-bb3f-547d85733292

📥 Commits

Reviewing files that changed from the base of the PR and between 3b165c6 and 7ebacec.

📒 Files selected for processing (3)
  • src/tui.rs
  • src/tui/logic.rs
  • src/tui/tests.rs

@jimyag
Copy link
Copy Markdown
Contributor Author

jimyag commented May 13, 2026

image image image image

jimyag and others added 2 commits May 13, 2026 11:19
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Member

@mike1858 mike1858 left a comment

Choose a reason for hiding this comment

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

LGTM

@mike1858 mike1858 merged commit 44dbd9c into Piebald-AI:main May 14, 2026
6 checks passed
@jimyag jimyag deleted the feat/all-tools-period-views branch May 15, 2026 02:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants