mirror of
https://github.com/Routstr/routstrd.git
synced 2026-10-30 07:37:40 +00:00
Rename the second usage-monitor tab from Today to History and draw usage over time as a bar chart instead of the text lists and horizontal hourly bars. - daemon: add a zero-filled `timeline` series to the windowed summary, bucketed per window (hours for 24h, days for 7d/30d, months for all). Months are folded from daily aggregates since the SDK has no month grouping. - tui: renderHistory draws a vertical spend chart with a y-axis, x labels and an independently scaled token sparkline plus legend; the [W] selector now drives the tab (it was hidden on it before). - renderBox truncates overlong lines so a large number can't push the right border out. - docs: SKILL.md wording + docs/plans/tui-history-charts.md. Tests: daemon timeline buckets; chart axis/labels/sparkline/legend, empty state, and full-width alignment.
64 lines
2.8 KiB
Markdown
64 lines
2.8 KiB
Markdown
# TUI "History" tab with adaptive bar charts
|
|
|
|
> **Status:** implemented. Branch `feat/tui-history-charts`
|
|
> (worktree `.worktrees/tui-history-charts`, based on `main` @ `5069b2d`).
|
|
|
|
## Goal
|
|
|
|
Replace the old **Today** tab (a totals box + a text "Recent Days" list + a
|
|
horizontal hourly bar list) with a **History** tab that draws usage over time
|
|
as bar charts, with the bucketing driven by the existing `[W]` time-window
|
|
selector.
|
|
|
|
| `[W]` window | Bucket | Bars |
|
|
| ------------ | ------ | ---- |
|
|
| `24h` | hour | 24 |
|
|
| `7d` | day | 7 |
|
|
| `30d` | day | 30 |
|
|
| `All` | month | one per calendar month since first usage |
|
|
|
|
Y-axis is total spend; a token sparkline shares the x-axis (scaled
|
|
independently to peak tokens, with both totals in the legend). This also makes
|
|
the tab window-aware: the selector was previously hidden on it.
|
|
|
|
## Backend — `src/daemon/http/usage-summary.ts`
|
|
|
|
- New `TimelineBucket` (`hour` | `day` | `month`), `TimelinePoint` and
|
|
`Timeline` types; `WindowedStats` gains a required `timeline: Timeline`.
|
|
- `buildTimeline(driver, baseFilter, window, now, tzOffsetMinutes)`:
|
|
- `today` (24h) → `aggregate({ groupBy: "hour" })` over the last 24
|
|
local-aligned hours. The SDK's `hour` key is `HH` with no date, so the
|
|
window is aligned to whole hours (each hour-of-day appears at most once).
|
|
- `7d` / `30d` → `aggregate({ groupBy: "day" })` over the last N days.
|
|
- `all` → `aggregate({ groupBy: "day" })` with no `after`, folded into
|
|
`YYYY-MM` months. The SDK has no `month` grouping, hence the fold.
|
|
- Every series is zero-filled so the x-axis is evenly spaced.
|
|
- `buildTimeline` is called once per summary build (after `buildAggregates`)
|
|
and attached to both the all-time and windowed blocks. The zero-data
|
|
short-circuit returns an empty timeline.
|
|
|
|
## TUI
|
|
|
|
- `types.ts` — `TabId` `"today"` → `"history"`; re-export the timeline types.
|
|
- `constants.ts` — tab renamed to `History`; `tabSupportsWindow` now excludes
|
|
only Overview and Recent.
|
|
- `render.ts` — `renderToday` replaced by `renderHistory` +
|
|
`renderTimelineChart` (vertical bars, y-axis gutter, x labels, token
|
|
sparkline, legend). Long series are merged to fit narrow terminals.
|
|
- `data.ts` — the old-daemon fallback `windowFromAllTime` supplies an empty
|
|
timeline.
|
|
|
|
## Tests
|
|
|
|
- `src/daemon/http/usage-summary.test.ts` — hourly / 7-day / 30-day /
|
|
month-folded timelines, including zero-fill and window totals.
|
|
- `src/tui/usage/render.test.ts` — axis, labels, sparkline, legend, empty
|
|
state, and full-width alignment of every rendered line.
|
|
|
|
## Notes / limits
|
|
|
|
- Daemons too old to return `timeline` still render: the History tab falls
|
|
back to an empty chart rather than erroring.
|
|
- The 24h window is hour-aligned rather than a rolling `now - 24h`, so each
|
|
hour-of-day appears once and the `HH` keys stay unambiguous.
|