feat(webui): redesign the admin dashboard around admin tasks

A sidebar replaces the flat tabs with seven pages, and one filter bar
sets the time range, comparison period and scope for all of them.

- Home: spend against budget, forecast, request rate, error rate,
  open breakers, top users and models, recent events and warnings.
- Spend: spend over time with comparison, budget burn-down, an
  attribution drill-down from group to user to model, pricing health
  and cost avoided by free models.
- Consumers: a directory with last seen and limit bars, an access
  matrix, and a detail page per user.
- Models: the catalog with billing prices, fleet latency and error
  rates, and provider health.
- Reliability: error, timeout, failover, 429 and 402 trends, events,
  and latency per provider.
- Config: the redacted config and a change helper that emits YAML or
  users.json snippets to paste into git.
- MCP & Agents: callers per target.

Page state lives in the URL hash, and old tab links map to the new
pages. The replaced views are removed. admin_assets_gen.go is
regenerated.

Claude-Session: https://claude.ai/code/session_01V5jYJNxpDFdJkyyExpADrv
This commit is contained in:
2026-09-23 16:41:01 +01:00
parent e8abb91dc8
commit ee49467e64
127 changed files with 11226 additions and 3414 deletions
+7 -6
View File
@@ -15,12 +15,13 @@ import { ratioTier } from '@/lib/usage-bars'
* `aria-valuetext`, so a screen reader announces the same number a
* sighted reader sees in the fill width and the `title` tooltip.
*
* Used two places (usage-columns.ts's numeric cells, UsageView.vue's
* group detail grid) — both pass a fully-computed BudgetRatio plus the
* caller's own human-readable `valueText`, so this component has no
* formatting opinion of its own (formatCost/formatExactInt stay the
* caller's job, same "logic lives in lib/, not the component" split
* every other shared component in this panel follows).
* Used across the panel (usage-columns.ts's numeric cells,
* ConsumerDirectory.vue's group detail grid, UserDetail.vue's headroom
* bars) — every caller passes a fully-computed BudgetRatio plus its own
* human-readable `valueText`, so this component has no formatting
* opinion of its own (formatCost/formatExactInt stay the caller's job,
* same "logic lives in lib/, not the component" split every other
* shared component in this panel follows).
*/
const props = defineProps<{
/** used / limit — may exceed 1 (a scope's usage window can roll past its limit before the next request is rejected). */