Repository navigation
Conversation
A help popover closed the moment the pointer left its button, so it was gone before the pointer could cross the gap onto it. Someone using a screen magnifier, who moves the pointer to pan the view, could not read a popover wider than the magnified area. Leaving the button now hides the popover only after 300 ms, and the pointer on the popover keeps it open until it leaves the popover too, as WCAG 1.4.13 asks of content shown on hover. Escape still hides it.
The bars carried their day and count in a title attribute, which a touch screen never shows and which looked nothing like the rest of the page. They now use data-help, and help.js serves any element with it. A tap opened and closed the popover at once: it sends mouseenter, and focuses a button, both of which opened it, just before the click that toggled it shut. Only a mouse now hovers, and the click goes by the state before the press. Tapping another bar moves the popover there.
The chart had no title, and a bar's popover showed a date and a bare number, so it was left to the user to guess what was counted and over which period. The window is the last 30 days, not the month, which the day-of-month axis made easy to mistake. The chart now has a heading that says so, with a help button explaining that it counts every key's tokens per UTC day, and that the allowance is measured in cost. LiteLLM's daily activity carries each day's spend next to its tokens, which was not read. A bar now shows both, "2026-10-25: 12,316,429 tokens · $0.21", and the total above the chart shows the window's cost, which ties the chart to the allowance bars above it.
Odrec
left a comment
There was a problem hiding this comment.
Reading spend from the daily activity is right, and it is summed the same way as the tokens, split pages included. Two of the new figures can be wrong, and some of the new wiring has no test.
- The heading always says "per day", but
usageBarsdraws weeks above 62 days and months above 730, as usage-limits.md documents forUSAGE_HISTORY_DAYS. With 365 the card reads "Tokens per day, last 365 days" over 53 weekly bars, and the help says to tap a day. The "30 days" indash.usagestats.noteis still hard-coded, so with any other window the note and the heading disagree. - The total covers one day more than the bars.
Historyasks forstart_date= today − 30 (usage.go:83, pinned by history_test.go:69), LiteLLM's start_date is inclusive (checked on the dev gateway), so 31 days come back;usageBarsdraws 30 anduserUsageadds all of them intoTotaland nowSpend. A day at today − 30 with 1,000 tokens and $5 plus 10 tokens and $0.01 today gives Total 1010 and Spend 5.01 against bars of 10 and $0.01. The token total and the model table did this before, but with the cost and "last 30 days" above it the page now states it.start_date= today − (days − 1) fixes all three. - Remove
rep.Spend += d.SpendinuserUsage:go test ./internal/handlers/stays green and the total always reads $0.00, sinceTestDashboardRendersUsagebuilds the report by hand. Removerep.WindowDays = …: stays green, and the heading says "last 0 days". Drop|| d.Spend > 0inHistory:go test ./internal/litellm/stays green. Remove the chart'srole="img" aria-label: stays green. Misspell the chart help key: stays green, becauseTestDashboardRendersNoRawCatalogueKeysstrips tags and never seesdata-help. - The aria-label repeats the heading right above it, so a screen reader hears the title twice and no figure; the total would give it something to say.
| "dash.usagestats.note": {DE: "Ihr Kontingent wird in Kosten gemessen; die Verlaufsgrafik zeigt die Tokens, die Sie in den letzten 30 Tagen mit all Ihren Schlüsseln verbraucht haben, und läuft mit einem neu erzeugten Schlüssel weiter. Das längste Kontingent gilt für Sie, nicht für den einzelnen Schlüssel: Ein neu erzeugter Schlüssel setzt es nicht zurück.", EN: "Your allowance is measured in cost; the history chart shows the tokens you used over the last 30 days with all your keys, and carries on when you generate a new key. The longest allowance applies to you rather than to a single key, so generating a new key does not reset it."}, | ||
| "dash.usagestats.perkey": {DE: "Kürzere Kontingente gelten pro Schlüssel und schützen vor unbeabsichtigt hohem Verbrauch; mit einem neuen Schlüssel beginnen sie von vorn.", EN: "Shorter ones apply per key, as a guard against runaway spend, and start over with a new key."}, | ||
| "dash.usagestats.total": {DE: "insgesamt", EN: "in total"}, | ||
| "dash.usagestats.chart": {DE: "Tokens pro Tag, letzte %d Tage", EN: "Tokens per day, last %d days"}, |
There was a problem hiding this comment.
Above 62 days the bars are weeks and above 730 months (usageBars), so this reads "per day" over weekly bars. The noun could follow the bucket size, carried in usageReport.
| rep.WindowDays = u.usage.windowDays | ||
| for _, d := range days { | ||
| rep.Total += d.Tokens | ||
| rep.Spend += d.Spend |
There was a problem hiding this comment.
This sums every day History returned, 31 of them (start_date = today − 30 is inclusive), while the bars show 30. Asking for today − (days − 1) in usage.go:83 keeps the total, the bars and the model table on one window. Removing this line also leaves go test ./internal/handlers/ green.
Note
Depends on #206 and #208, which need to be reviewed and merged first. This branch is built on top of them, so its diff also contains their commits.
The usage chart on the dashboard had no title, and a bar's popover showed only a date and a bare number. Users had to guess what was being counted and over which period. The window is the last 30 days, not the current month, and the day-of-month labels on the axis made that easy to get wrong.
Changes
2026-10-25: 12,316,429 tokens · $0.21.35,384,081 tokens · $12.34 in total. This connects the chart to the allowance bars above it.LiteLLM's
/user/daily/activityalready returned each day'sspendalongside the tokens, but the portal didn't read it.DailyUsageand the chart bars now carry it, and costs are formatted with the configuredBUDGET_UNIT, like the allowance figures.Testing
spend, including a day split over two pages, and summing it into daily, weekly and monthly bars.