Skip to content

feat(usage): refine usage dashboard UI and date range picker#2002

Open
yovinchen wants to merge 7 commits intofarion1231:mainfrom
yovinchen:feat/usage-dashboard-refinement
Open

feat(usage): refine usage dashboard UI and date range picker#2002
yovinchen wants to merge 7 commits intofarion1231:mainfrom
yovinchen:feat/usage-dashboard-refinement

Conversation

@yovinchen
Copy link
Copy Markdown
Collaborator

@yovinchen yovinchen commented Apr 11, 2026

Summary

  • Calendar date range picker redesign: Auto-switch from start to end field after selection, smart date swap when start > end, cross-month click navigation, click month title to jump to today; removed 30-day range limit; simplified layout and code
  • Request log table compaction: Merged cache hit/creation columns into input column as subtitle (R66,012·W148); moved multiplier below cost (shown only when ≠1); compressed filter bar to single row; centered all headers; shortened time format; changed timing to seconds; reduced cost to 4 decimal places
  • Filter bar optimization: Removed refresh button and button labels (search/reset now icon-only); Select filters apply immediately; removed per-field clear buttons, kept single global reset; Input fields support Enter key search
  • Backend enhancements: Usage stats service and query hooks improvements
  • i18n: Added cache short label translations (zh/en/ja)

Changes

Commit Description
feat(usage): enhance usage stats backend and query hooks Backend service + API + type definition enhancements
feat(usage): redesign calendar date range picker Calendar picker component rewrite + usageRange utility
refactor(usage): streamline dashboard layout and stats components Dashboard panel simplification
refactor(usage): compact request log table Table column merging and centered layout
feat(i18n): add cache short labels Cache short label internationalization

Test plan

  • Verify calendar picker: auto-switch to end field after start selection, auto-swap when start > end, cross-month navigation on click
  • Verify request log table: cache info shown below input in single line, multiplier below cost, time format as MM/DD HH:MM
  • Verify filter bar: Select applies immediately, Enter triggers search, reset button clears all filters
  • Verify i18n: cache short labels display correctly in zh/en/ja
  • Verify typecheck passes

#1948

@farion1231
Copy link
Copy Markdown
Owner

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 654e537746

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +480 to +484
rollup_conditions.push("r.date >= date(?, 'unixepoch', 'localtime')".to_string());
rollup_params.push(Box::new(start));
}
if let Some(end) = end_date {
rollup_conditions.push("r.date <= date(?, 'unixepoch', 'localtime')".to_string());
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve time precision when filtering rollup stats

The new provider/model time filtering converts start_date/end_date to whole days for usage_daily_rollups (date(?, 'unixepoch', 'localtime')), which causes boundary-day overcounting for custom ranges that start or end mid-day. This is especially visible when the range reaches rolled-up history (older than retention): rows outside the selected time window are still included from the full day aggregate, so provider/model totals no longer match the requested interval. The same pattern appears in get_model_stats, so both endpoints should use precise boundary handling for rollup data.

Useful? React with 👍 / 👎.

Comment on lines 55 to 59
const { data: result, isLoading } = useRequestLogs({
filters: effectiveFilters,
timeMode: appliedTimeMode,
rollingWindowSeconds: ONE_DAY_SECONDS,
range,
page,
pageSize,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3 Badge Reset log pagination when dashboard range changes

The table keeps the previous page when the external dashboard range changes, so switching from a large window to a small one can query an out-of-range offset and render an empty table with an inconsistent paginator (for example, 6 / 1) until the user manually clicks back. Since range is now a top-level filter, pagination should be reset to page 0 whenever it changes to avoid false "no data" states.

Useful? React with 👍 / 👎.

The usage dashboard mixed second-precision detail rows with day-level rollups, which caused custom half-day ranges to overcount historical rollup data and left the request log paginator on stale pages after top-level filter changes.

This change limits rollups to fully covered local days, aligns multi-day trend buckets with natural local days, and resets request log pagination when the dashboard range or app filter changes.

Constraint: usage_daily_rollups stores only daily aggregates after pruning old detail rows
Rejected: Include partial boundary rollups proportionally | historical intra-day detail is unavailable after pruning
Rejected: Force RequestLogTable remount on range change | would discard local draft filters unnecessarily
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep summary, trends, provider stats, and model stats on the same rollup-boundary rules
Tested: cargo test --manifest-path src-tauri/Cargo.toml usage_stats
Tested: pnpm exec vitest run tests/components/RequestLogTable.test.tsx
Tested: pnpm typecheck
Not-tested: Manual UI validation in the Tauri app
@yovinchen
Copy link
Copy Markdown
Collaborator Author

@codex review

1 similar comment
@yovinchen
Copy link
Copy Markdown
Collaborator Author

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f11baaff19

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +169 to +173
if local.time().num_seconds_from_midnight() == (24 * 60 * 60 - 1) {
Some(day.format("%Y-%m-%d").to_string())
} else {
day.pred_opt()
.map(|prev| prev.format("%Y-%m-%d").to_string())
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Include end-day rollups for minute-precision ranges

The end boundary only counts a rollup day when the timestamp is exactly 23:59:59. Our custom picker submits minute precision (e.g., 23:59:00), so a user-selected full end day is treated as partial and shifted to the previous day. In ranges where boundary-day detail rows have already been pruned and only usage_daily_rollups remain, this drops the selected end day entirely and undercounts summary/trend/provider/model stats.

Useful? React with 👍 / 👎.

Comment on lines +106 to +110
...draftFilters,
appType: v === "all" ? undefined : v,
})
}
};
setDraftFilters(next);
setAppliedFilters(next);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Prevent select changes from applying unsaved text drafts

This immediate-apply path builds next from draftFilters and writes it into appliedFilters, so changing a select also applies any unsubmitted provider/model text the user is still editing. That breaks the current interaction contract where text inputs apply on Enter/Search, and can unexpectedly change result sets when users only intended to change app/status.

Useful? React with 👍 / 👎.

The latest review surfaced two interaction bugs in the usage dashboard: rollup-backed stats undercounted end days selected via the minute-precision picker, and immediate select changes accidentally applied unsubmitted text drafts from the request log filters.

This change treats 23:59 as a fully selected local end day for rollup inclusion and narrows select-side state syncing so app/status updates do not commit provider/model drafts.

Constraint: The custom range picker emits minute-precision timestamps, while rollups are stored at day granularity
Rejected: Require exact 23:59:59 end timestamps | unreachable from the current picker UI
Rejected: Rebuild applied filters from the full draft state on select changes | silently commits unsaved text input
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep request-log text fields on explicit apply semantics even when select filters remain immediate
Tested: cargo test --manifest-path src-tauri/Cargo.toml usage_stats
Tested: pnpm exec vitest run tests/components/RequestLogTable.test.tsx
Tested: pnpm typecheck
Not-tested: Manual Tauri dashboard interaction
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