feat(panel): Insights dashboard, home KPI deltas, and daily activity trend#239
Merged
Conversation
New panel-only GetReport names (no CLI/SQLite mirror): usage_by_day, punchcard, durations, duration_stats, subagents. All reuse buildWhere and the stringly runReport contract; durations share one clamped EPOCH-span subquery, subagents group fan-out by the parent's agent while window filters apply to the children. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
charts.StackedColumns renders per-label columns with one stacked segment per series, palette-matched to PaletteColor for HTML legends. Normalize turns it into a share-of-total view; Overlay draws a line on its own max-scale with an end marker (cumulative spend). Deterministic output, golden-tested like Area/Donut. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…artial parseDashboardWindow, dashboardReportRequest, and buildDashboardActiveFilters move to handlers_filters.go; the filter drawer + active-chips markup moves to a shared dashboard_filters.html partial parameterized by PageTitle/FilterAction. No behavior change — prepares the Insights page to reuse the same filter chrome. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New /insights route behind the same session gate, sharing the home filter chrome. Cards: spend & tokens per day (priced panel-side, with cumulative overlay and ISO-week bucketing past 120 days), weekly model share (top-4 + other, normalized), weekday × local-hour punch card (UTC rotation with day carry, heatmap color levels), streak/consistency and schedule-profile KPIs, session-duration histogram with percentile stats, and subagent fan-out. last=all clamps daily-resolution charts to trailing 365d so the zero-filled day span stays bounded. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every KPI gains a ±% badge against the immediately-preceding window of equal length (5 extra RPCs in the existing fan-out; skipped for last=all). Movement tones: up is good for volume KPIs, bad for the error rate, and always neutral for est. spend. buildUsage now returns numeric cost so deltas and labels share one source. New Activity trend card stacks sessions per day (ISO weeks past 120 days) by agent via the windowed heatmap report, clamped to trailing 365d for last=all. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Server: the five panel-only GetReport names and their shapes. Panel: GET /insights route, the Insights screen spec (cards, states, UTC/DST caveats), the Home activity-trend card and KPI delta badges, the StackedColumns chart helper, and the punch card as an HTML-grid component. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Embed frappe-charts.min.umd.js (v1.6.2, MIT, ~18 KB gzip) via the existing assets embed.FS and load it (plus charts-init.js) from base.html. The library self-injects its CSS; no separate stylesheet. Vendoring a prebuilt UMD file is not a build step — same posture as htmx/alpine. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add --chart-1..8 to tokens.css for the dark, light, and system-light themes, replacing the monochromatic blue->gray donut ramp. charts-init.js reads these so a theme swap recolors every chart and its legend dots. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop the server-side SVG Donut/Area/StackedColumns helpers and their golden tests in favor of charts.Spec, a JSON-serializable chart spec rendered client-side by Frappe Charts. spec_test.go asserts the JSON shape (script-close escaping, has-data, omitempty) in place of golden SVG. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rewrite buildModelUsage/buildHourChart/buildActivityTrend (home) and buildSpendTrend/buildModelShare (insights) to produce charts.Spec instead of template.HTML SVG; legend rows carry a palette index. Model-share is pre-normalized to 100% in Go (Frappe has no percentage-stacked mode); the spend cumulative overlay is dropped (no secondary axis) — the running total stays in the card subtitle. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add charts-init.js (parses each card's JSON island, resolves the palette, renders with animation + hover tooltips, re-renders on htmx swap / theme flip) and charts.css (re-skins Frappe's axis/gridline/tooltip chrome with the design tokens, hides its built-in legend). Templates emit a [data-chart] container + JSON island per card with palette-indexed legend dots. Remove the now-dead .area-chart/.donut/.trend-chart svg rules. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Update INTENT, architecture/panel.md, the panel design brief/components/screens, agents.md, the panel-rendering skill, and both panel-ui-reviewer configs to describe Frappe Charts fed a Go-built JSON spec. Note the explicit carve-out that vendoring a prebuilt UMD via embed.FS is not a build step. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Trim the insights/dashboard comments to the repo's sparse style: drop narration of self-evident code and compress multi-line docstrings to one line, keeping only terse rationale. No behaviour change. gen/ regenerated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-analytics # Conflicts: # docs/panel/screens.md # internal/panel/charts/donut.go # internal/panel/handlers_dashboard.go
Frappe Charts paints axis and grid lines with inline style attributes (style="stroke: #dadada"), which outrank any stylesheet selector, so the existing token-based override never applied and charts rendered light-gray lines on the dark theme. Re-skin them with !important and a new --chart-grid token, quieter than --divider on both themes. Lighten the tooltip shadow while there. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…r dots) xAxisMode 'tick' drops the full-height vertical gridline per x label, shortenYAxisNumbers compacts the y scale (800000000 -> 800M), and line charts get smaller dots, hidden entirely on dense series (>24 points) where they read as a string of beads. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Expands the panel's analytics surface with nine user-confirmed additions, split between the Home dashboard and a new Insights page (hybrid layout).
Home
last=all.New
/insightspage (same filter chrome as Home, shared via a newdashboard_filters.htmlpartial)internal/pricingServer — five new panel-only
GetReportnames (no proto schema change, no CLI/SQLite mirror):usage_by_day,punchcard,durations,duration_stats,subagents.Charts — new deterministic
charts.StackedColumnsSVG helper (Normalizefor share views,Overlayfor cumulative lines), golden-tested like Area/Donut.Testing
just cigreen (tidy-check, gen-check, vet, lint, test-race, CLI integration, build), with the server analytics e2e running against a real Postgres 17🤖 Generated with Claude Code
Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.