feat(usage): break usage down by request type or SDK - #8343
feat(usage): break usage down by request type or SDK#8343talissoncosta wants to merge 33 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 8 included reviews per hour; 3 remain after this review. 📝 WalkthroughWalkthroughAdds request-type and SDK usage aggregation with ranked rows and empty-state handling. Adds the Estimated code review effort: 3 (Moderate) | ~30 minutes Merge Risk: 🟠 High · up to This PR adds usage breakdowns, but the current implementation can fail to render and can display stale or misleading totals—or remain stuck loading—when scope requests fail or change. These correctness and availability risks should be fixed before merging. ✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
6a7bc06 to
dbf1eed
Compare
80bb450 to
35abec8
Compare
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two defects in the per-scope breakdown: - totals were keyed by name, so two projects sharing one would overwrite each other. They key on the scope now - totals were never cleared, so changing the period or project left the previous numbers on screen while the new requests were in flight, with nothing to mark them stale. They reset when the query identity changes The section also waits for every scope rather than filling in, because a partial list ranks wrongly and ranking is the point. Extracts shared/BarTrack from UsageBar and UsageBreakdownRow, which had near-identical markup and each hand-wrote the same transition and reduced-motion guard. Rows carry the colour each request type has always had on the usage page. Also: the barrel exports the container, so callers stop reaching past it; UsageBreakdownList replaces a function-in-render; skipToken replaces a cast; and the row's flex, spacing and border move to utilities. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
BarTrack led with the noun and named the groove. Everything else here is <Noun>Bar: ButterBar, CalloutBar, DistributionBar, UsageBar. Not ProgressBar: half its callers compare values against the largest row rather than tracking a task, which is why the progressbar semantics are optional rather than built in. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ARIA reserves progressbar for a task advancing and meter for a value inside a known range. Usage against a plan allowance is the second, so a screen reader was told a task was underway. Changes what ProjectUsageTab and EnvironmentOverrideUsage announce as well, since they share the bar. No selectors depend on the old role. Note that meter has patchier assistive-tech support than progressbar, which is the trade being taken deliberately. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
They were the legend for a stacked chart that is no longer there. Without it the colour distinguished nothing the adjacent label and the bar length did not already, and only request-type rows had one, so the same section looked colour-coded on one dimension and plain on the next. A categorical palette is still available in CHART_COLOURS if a chart ever needs one; it does not have to live on a breakdown row to be reachable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three of them, so they move into components/ and drop the prefix the path already supplies: Row, List, ScopeTotal. The pair also matches UsageDashboard now. The bare name is the container, so the folder, the file and the default export agree, and callers stop reaching past the barrel for it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Switching to project or environment showed "No usage recorded" before the key list had even arrived: with no scopes yet there was nothing to wait on, so the section read as empty rather than loading. The select also had no accessible name, same as the page filters. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Row explained its bar-versus-share split in the docblock and again on each prop. List repeated the view's needsProject comment verbatim. ValueBar made the meter-versus-comparison point twice. ScopeTotal and useScopedBreakdown were each a paragraph longer than the thing they explain. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
It is a section of the new dashboard, so it sits in pages/usage/components alongside UsageMeter and UsageOverTime rather than in the folder the old page is being deleted from. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A scoped request that failed never reported, so the section counted it as still in flight and waited on it forever. One failed project left the whole breakdown spinning. Failure now answers with null: the scope drops out of the ranking rather than holding up the rest. Scope lists also read currentData rather than data, since RTK keeps the previous result while new arguments are in flight, so switching project briefly listed the old project's environments. The organisation is part of the totals identity for the same reason. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The section's queries, dimension state and row derivation were in the component. They are now in useUsageBreakdown, leaving 42 lines that wire the hook to the view. The split existed to separate stateful logic from rendering, which is what a hook does without needing a second component to hold it. ScopeTotal still renders, because project and environment need one request per key and a hook cannot mount a query per item of a list that changes length. Also drops a guard that could not fire: with no project selected the environments query is skipped, so scopes is already empty. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
UsageBreakdown is now the component: five props in, no queries. The wiring moved up to UsageDashboardPage, which is allowed to fetch, so nothing needs a suffix to distinguish it from the part that renders. The dashboard takes the breakdown through a slot, the same way it already takes filters and for the same reason: what goes in there fetches per key. It also sheds organisationId, billingPeriod and projectId, which it only ever forwarded. Both story sets still work. UsageBreakdown renders from props, and the dashboard stories omit the slot. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Restores the palette the four types have always had on the usage page, using the chart tokens rather than the status ones: these are categorical, and Identities is not "success". Uses the ColorSwatch component rather than a hand-rolled span, which also makes the swatch aria-hidden, since it is decorative and the label beside it already names the row. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The page docblock still referred to "the view", which no longer exists. ValueBar's className comment described the prop rather than explaining it, totalOf's repeated its own name, and the hook's docblock took two sentences to say one thing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Eight lines explaining a role attribute that is visible two lines below it. The reasoning is in the commit that made the change. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Seven lines became four. Dropped "it draws nothing", which the return says, and the group_by aside, which is a wish rather than a warning. Kept why it is one request per key and why it cannot be a loop of hooks, since the obvious refactor of both reintroduces a bug. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Same sweep as the base branch. The record is in frontend/USAGE_DASHBOARD_DECISIONS.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The usage endpoint types environment_id as an IntegerField, so it wanted the environment's numeric id and we were sending its api_key. Nothing matched, every environment came back with no usage, and the rows were filtered out, so the section read "No usage recorded" for every project. Also from a pass over the review patterns on #8320: - ScopeTotal reads currentData rather than data. RTK keeps the previous result while new arguments are in flight, so a period change reported the old period's totals as current, right after they had been cleared - long row labels ellipsise instead of wrapping, with the full name on hover Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… value A scope only reported once it produced a total, so anything that finished without one never answered and the section waited on it forever. It now reports as soon as fetching stops, with null when there is nothing to show. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Row, List and ScopeTotal were flat files in components/. Each now has a folder and a barrel, per the component structure rule. Row in particular had its own stylesheet sitting beside it. Names the tri-state a scope reports while it is doing so: undefined is still in flight, null is answered with nothing, a number is answered. That was written out three times. UsageScope moves to utils alongside it so the components take their types from one place rather than from each other. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both cost one usage request per key, and the endpoint is throttled at five a minute per user via InfluxQueryThrottle. An organisation with a handful of projects gets 429s on first use, and a throttled scope reported null, which the list turned into zero, so the breakdown showed zeros rather than an error. Ranking is the point of a breakdown, and a partial list ranks wrongly: a throttled scope could be the largest. Better to ship the two dimensions that are always right than four that mislead. Request type and SDK derive from the payload the page already holds, so they cost nothing extra. The other two come back on a group_by. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The label was a rigid 280px, so with the value and share columns and the gaps the row needed about 440px before anything could give. It now shrinks and truncates instead, which is what the ellipsis on the name was always for. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
REQUEST_TYPES and RequestTypeKey were exported but only ever used inside this module. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Row and List are internal to the breakdown, so re-exporting their props types from their barrels put names into the world that nothing can sensibly import. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Each row rounded its own share, so three equal rows read 33% and totalled 99%. The shares are worked out across the whole list now, with the spare points going to the largest remainders. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A row worth a fraction of a percent of the largest rounded to a zero width bar, so a real contributor looked like nothing at all. Anything above zero now draws at least one percent. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The section changed scope with the page filters and never said so, and the control that changes it sits at the top of the page rather than beside the numbers it affects. The header now names the project and the period. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
docs/if required so people know about the feature.Changes
Closes #8186.
A section under the chart showing where the usage came from, with a menu for request type or SDK. Ranked rows, totals only, no plan limit, since a single request type has no allowance of its own. Both dimensions come from the response the charts already fetch, so it costs no extra requests.
Project and environment are split out into #8362, blocked on #8361. Each costs one request per key against an endpoint throttled at 5/min per user, so a multi-project org would get 429s and a partial ranking. Nothing is lost today: the current page has a project filter, not a project ranking.
Two changes reach outside the feature:
shared/ValueBaris extracted fromUsageBar, same track-and-fill markup.ProjectUsageTabandEnvironmentOverrideUsagerender it unchangedrole="meter"instead ofrole="progressbar". ARIA reserves progressbar for a task advancing. Meter has patchier screen reader support, so it is a deliberate tradeHow did you test this code?
8 unit tests over the derivations.
With
usage_dashboardon:ValueBar