The Usage tab shows a bar for each configured limit. It turns amber at
80% and red at 100%. The tab also shows rejected requests per day, a
projected month-end cost with budget headroom, and CSV export for users
and groups. Names link to Charts with the matching scope.
The Charts tab ranks models over the full 24h, 30d or 12mo window. A
provider filter is applied on the server, and the ranking can be
exported as CSV. A new Events tab lists recent failures, filtered by
kind and user. The selected tab, filters and scope live in the URL
hash. Polling stops while the page is hidden. Views show which replica
answered, and a banner lists configuration warnings.
CSV cells that start with a formula character are neutralised. Links
sit outside the accordion buttons, so both controls keep their
accessible names. admin_assets_gen.go is regenerated.
Claude-Session: https://claude.ai/code/session_01V5jYJNxpDFdJkyyExpADrv
Chart and ranking fetches carry a request id, and a superseded response
is dropped. Changing a selection clears the old data at once, so old
numbers never show under new labels or units. The auto-refresh tick
skips while a fetch is still in flight. "Loading..." shows only until
the first result for a selection arrives. Dashboard polls do not
overlap.
Users in several groups are counted and searched in every group. The
Models tab labels its windows as the current UTC bucket. Hour labels
are marked UTC. The Members column sorts numerically. Target access
shows "All groups" for null and "No groups" for []. The UI shows the
server's own error message. Cost axis ticks use the currency
formatter. npm run dev proxies /admin/api. Nine unused shadcn
components are removed.
admin_assets_gen.go is regenerated from the new build.
Claude-Session: https://claude.ai/code/session_01V5jYJNxpDFdJkyyExpADrv
Operator scope addition: raw token/request counts reaching millions/
billions were unreadable as bare digits. formatCompactCount (lib/
format.ts, shipped in the previous commit alongside this feature's own
helpers) renders an SI-style label: below 10,000 the exact integer with
thousands separators, at or above it three significant figures with a
k/M/B suffix ("12.3k", "456k", "1.23M", "45.6M", "1.23B") —
every digit past the third significant one is FLOORED, never rounded,
the same honesty rule formatRatePercent already applies to the
success-rate badge: a count of 999,950 must read "999k", never
"1,000k", since it has not actually crossed that boundary.
CompactNumber.vue is the one shared, reusable presentational component
(component-first: no per-call-site wrapper markup) — renders the
compact form as text, with the exact value on both title and aria-label,
mirroring ProviderRateBadge.vue/ModelChip.vue's own hover-parity
pattern.
Applied everywhere a count renders: usage-columns.ts's numericColumn
(reqMin/reqDay/tokIn-out per day and month — cost columns explicitly
opt out via a new compact:false argument, since formatCost already
shows full precision), target-columns.ts's MCP/agent request counters,
UsageView.vue's Total card and group-accordion trigger/detail stat
grid, and UsageChart.vue's Chart.js y-axis ticks (compact only — no
room for the raw figure on an axis label) and tooltip labels (compact
form WITH the precise raw value alongside, e.g. "Tokens in: 1.23M
(1,234,567)").
Sorting is unaffected by construction: every numericColumn's accessorFn
still returns the raw number (what getSortedRowModel actually sorts by)
regardless of what the cell renders — usage-columns.spec.ts pins this
directly, including a sort-order assertion that would fail under a
lexicographic (string) sort but passes under the numeric one.
Component-first admin-panel rework (operator directive), replacing
hand-rolled patterns with the actual shadcn-vue library components
rather than working around them.
- Providers (OverviewView) and Groups (UsageView) now render as a real
shadcn-vue Accordion: trigger is the summary line, content holds the
detail (base URL, last refresh/error, model chips for providers;
full stat grid + member users for groups) — the earlier hand-rolled
second-<TableRow> toggle is retired. lib/provider-expand.ts's tested
two-set expand-state module is unchanged; only the template now
adapts it to Accordion's type="multiple" v-model via a writable
computed instead of driving a plain v-if.
- Usage view: expanding a group shows its member users' own usage rows
— a client-side join on AdminUsageEntryView.groupName, which admin.go
already sets per user (verified via admin_test.go's existing
TestAdminUsage_MathAgainstSeededCounters; no backend change needed).
- New DataTable.vue: the shadcn-vue DataTable pattern
(@tanstack/vue-table, pinned to ^8.21.3 — the version whose API
matches the documented pattern; npm's default "latest" resolves to
v9, a breaking rewrite with a different API) factored into one
reusable, generic component so every real table (users usage,
aliases, a group's nested member list) gets clickable sortable
headers with asc/desc indicators for free. usage-columns.ts holds
the shared ColumnDef set; UsageTable.vue now delegates to DataTable.
Groups themselves cannot be a literal <table> (Accordion wraps
content in a <div>, illegal inside <tbody>), so their own
sortability is driven by the same columns headlessly, surfaced as a
small header-button toolbar above the Accordion.
- Aliases table: alias id gets the ModelChip copy treatment (the alias
name is the routable string); target stays plain text.
- App.vue: dropped the max-w-6xl container — the panel now uses the
full viewport width with responsive gutters (px-4 sm:px-6 lg:px-8).
Table.vue already wraps every table in its own overflow-x-auto
container, so a wide table still scrolls itself, never the page.
shadcn-vue add accordion re-added @lucide/vue and required swapping
its Chevron icons for FontAwesome (webui/README.md's own documented
trap); components.json's iconLibrary/font keys stayed absent
(verified main.css byte-identical after the add).
Browser-verified against the real integration stack (real /admin over
the Yaegi plugin, strict CSP incl. style-src 'self'): provider/group
accordion expand, search auto-expand through the new Accordion
adapter, sort toggles on aliases/users/groups-toolbar/nested-member
tables, alias copy-to-clipboard, full-width at 1920px. Zero console
errors (one unrelated MetaMask extension log).