Add per-pane usage averages and custom date ranges - #606
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
React Doctor found 1 new issue in 1 file · 1 warning · score 90 / 100 (Great) · 0 fixed · vs 1 warning
Reviewed by React Doctor for commit |
| setRefreshing(false); | ||
| if (id === requestId.current) { | ||
| setLoading(false); | ||
| setRefreshing(false); |
There was a problem hiding this comment.
React Doctor · react-doctor/no-loading-flag-reset-outside-finally (warning)
This resets a loading/busy flag only on the success path: if the awaited call rejects the reset never runs and the flag stays stuck truthy (a spinner that never stops, a button disabled forever). Move the reset into a finally block, or mirror it on every catch, so it clears on rejection too.
Fix → A trailing setLoading(false) after an await never runs if the awaited call rejects, so the flag stays stuck truthy; reset it in a finally block (or mirror the reset on every catch) so it clears on both paths.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 43c68b2075
ℹ️ 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".
| export function usageDateBounds(range: UsageDateRange) { | ||
| const start = new Date(`${range.start}T00:00:00`); | ||
| const end = new Date(`${range.end}T00:00:00`); | ||
| end.setDate(end.getDate() + 1); | ||
| return { fromMs: start.getTime(), toMs: end.getTime() - 1 }; |
There was a problem hiding this comment.
Align daily buckets with the custom range timezone
When a custom interval longer than two days is selected outside UTC, these local-midnight bounds are passed into a report whose automatic daily series still floors timestamps to UTC-day boundaries (main/src/services/usage/usageAggregator.ts:323,360), while the renderer formats those boundaries as local dates (UsageView.tsx:294). For example, March 8–10 in America/Los_Angeles can produce buckets labeled March 7–10 and split a selected local day between bars, so the time chart does not represent the requested calendar days. The custom-range path needs timezone-aligned bucketing or local regrouping of hourly data.
Useful? React with 👍 / 👎.
| initialRange={customRange ?? { | ||
| start: localDateString(new Date(Date.now() - rangeDays * DAY_MS)), | ||
| end: localDateString(new Date()), |
There was a problem hiding this comment.
Seed inclusive ranges with one fewer calendar day
When no custom range exists, opening the dialog after selecting 30d seeds today - 30 days through today, which is 31 inclusive calendar dates; after 24h it similarly expands to two full dates. Applying the untouched defaults therefore requests more history than the selected preset suggests. Calculate the start as rangeDays - 1 calendar days before today (using calendar arithmetic so DST does not shift the date).
Useful? React with 👍 / 👎.
| const rangeLabel = customRange | ||
| ? `${customRange.start} to ${customRange.end}` | ||
| : RANGE_OPTIONS.find(o => o.days === rangeDays)?.label ?? `${rangeDays}d`; |
There was a problem hiding this comment.
Announce the custom interval in the chart label
When a custom range is active, rangeDays retains the previous preset, and the AreaChart at line 658 still announces Token usage over the last ${rangeDays} days. A screen-reader user selecting a custom historical interval therefore hears a false range even though this new rangeLabel contains the correct dates. Use the custom label in the chart's accessible name when customRange is set.
Useful? React with 👍 / 👎.
Usage & Limits now shows tokens, estimated API cost, and recorded messages per pane for the selected period and provider. The default average can be switched to a mean that removes the highest and lowest 10% of values independently for each metric, with sample counts and definitions visible.
A calendar button adds custom inclusive local dates alongside 24h/7d/30d/90d presets. Both features reuse the existing report; no additional summary queries, transcript rescans, dependencies, or schema changes are needed. Leaderboard changes are deferred.
Tokens per pane excludes cache reads. Empty panes and unattributed usage are excluded; archived panes with recorded usage are included. Missing model pricing makes the cost summary unavailable. Custom ranges cover available indexed history, subject to the existing 180-day retention window. Trim selection survives filter changes, and late responses/rescan completions cannot replace the current-filter report.
Validation:
pnpm lintandpnpm typecheckpassed.pnpm --filter frontend buildandpnpm build:mainpassed.Screenshots (fixture data):