Skip to content

refactor(ui): convert entity usage and usage page charts to shadcn/recharts - #32729

Merged
ryan-crabbe-berri merged 3 commits into
litellm_internal_stagingfrom
litellm_shadcn_charts_entity_usage
Jul 11, 2026
Merged

refactor(ui): convert entity usage and usage page charts to shadcn/recharts#32729
ryan-crabbe-berri merged 3 commits into
litellm_internal_stagingfrom
litellm_shadcn_charts_entity_usage

Conversation

@ryan-crabbe-berri

Copy link
Copy Markdown
Contributor

Relevant issues

Linear ticket

Pre-Submission checklist

Please complete all items before asking a LiteLLM maintainer to review your PR

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have received a Greptile Confidence Score of at least 4/5 before requesting a maintainer review (Greptile reviews automatically once the PR is opened; only comment @greptileai to re-request a review after pushing changes)

Delays in PR merge?

If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).

Screenshots / Proof of Fix

QA against live dev servers, comparing each chart side by side with the pre-change UI (screenshots to follow in a comment):

  1. run the proxy (python litellm/proxy/proxy_cli.py --config litellm/proxy/dev_config.yaml) and the dashboard dev server (npm run dev in ui/litellm-dashboard)
  2. seed spend so the charts are non-empty, ideally across two models/providers so the donuts have multiple slices: for i in 1 2 3; do curl -s http://localhost:4000/v1/chat/completions -H "Authorization: Bearer sk-..." -H "Content-Type: application/json" -d '{"model": "gpt-5.2", "messages": [{"role": "user", "content": "hi"}]}'; done
  3. open http://localhost:3000/usage (the legacy deep link http://localhost:4000/ui/?page=new_usage redirects here) and compare the global view: Daily Spend bars (cyan, $ formatted y axis, rich hover tooltip), the Top Public Model Names vertical bars, and the Spend by Provider donut, which must show the dollar total in the donut center and draw slices clockwise from 12 o'clock; flip the Show Zero Spend / Show Unknown toggles and watch the slices and center total update
  4. switch the usage view selector to Team (or Tag/Organization/Customer/Agent/User) to mount EntityUsage and compare the Cost tab: Daily Spend bars, the vertical Spend Per Team top-5 chart beside its table, and the Provider Usage donut (center total plus clockwise slices)
  5. drill-down check in the Top Virtual Keys card, in both the global and the entity view: click Chart View, hover a bar for the dark tooltip, then click the bar; the key info modal must open exactly as before
  6. in Top Models click Chart View and compare the vertical bars; then open the Model Activity or Key Activity tab, expand a model or key section and toggle its Model Usage card to Chart to check the last converted chart (KeyModelUsageView)

Type

🧹 Refactoring

Changes

Stage PR in the charts track of the shadcn migration (foundation: #32668). Converts the entity usage cluster, 9 tremor chart render sites across 6 files, to the shared shadcn/recharts wrappers: EntityUsage (Daily Spend bars, Spend Per Entity vertical bars, Provider Usage donut), SpendByProvider (donut), TopKeyView (the app's only interactive chart; its onValueChange drill-down into the key info modal keeps working and is now covered by a test), TopModelView, KeyModelUsageView and UsagePageView (Daily Spend and Top Models bars). Each site is the mechanical import swap the foundation was built for; data, props, heights, colors and the inline custom tooltips are unchanged. The two sole-chart Daily Spend cards and the KeyModelUsageView card also move from tremor Card/Title to the shadcn Card primitives, while everything else on these pages stays tremor until its own stage

The shared DonutChart gains strictly additive optional props to close a known parity gap: tremor donuts default to a center label showing valueFormatter(sum of the category) and draw from startAngle 90 to endAngle -270, and both donuts on these pages show a center dollar total today. New showLabel/label and startAngle/endAngle props forward that behavior to recharts; the defaults (label off, 0/360) preserve the wrapper's previous rendering so sibling stage PRs branching from the same base are unaffected. Both provider donuts pass showLabel startAngle={90} endAngle={-270}

DailyData and two site-local row types change from interface to type alias. Interfaces carry no implicit index signature, so they fail the wrappers' Record<string, unknown> data constraint while structurally identical type aliases satisfy it

Tests assert on real recharts SVG through the foundation's jsdom ResizeObserver setup: bar and sector counts, cyan fills, axis labels, donut center totals, slice angle geometry in the wrapper test, and a click on a TopKeyView bar fetching key info and opening the modal. UsagePageView.test.tsx drops its now-dead tremor BarChart/DonutChart mocks so the real wrappers render, a few assertions move to getAllByText where chart axis labels now legitimately duplicate table text, eslint-suppressions.json loses the stale no-restricted-imports entries for the files that no longer import tremor, and eslint-metrics.json is regenerated

…charts

Swap the tremor BarChart/DonutChart render sites in EntityUsage,
SpendByProvider, TopKeyView, TopModelView, KeyModelUsageView and
UsagePageView to the shared shadcn/recharts wrappers. Convert the two
sole-chart Daily Spend cards and the KeyModelUsageView card to the
shadcn Card primitives.

Close the donut parity gap with strictly additive optional DonutChart
props: showLabel/label render a center total (tremor showed
valueFormatter(sum) by default) and startAngle/endAngle forward to the
Pie so both provider donuts keep tremor's clockwise-from-12 layout.
Defaults preserve the previous wrapper behavior.

DailyData and two site-local row types move from interface to type
alias so they satisfy the wrappers' Record<string, unknown> constraint;
interfaces lack implicit index signatures.

Tests now assert on real recharts output: bar/sector counts, cyan
fills, axis labels, donut center totals, and the TopKeyView bar-click
drill-down into the key info modal. The dead tremor chart mocks in
UsagePageView.test.tsx are removed and lint metrics/suppressions are
regenerated for the dropped tremor imports.
@greptile-apps

greptile-apps Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR is the second stage of the shadcn/recharts migration for the usage pages, converting 9 tremor chart render sites across 6 files to the shared wrappers established in the foundation PR (#32668). The DonutChart wrapper gains three additive props (showLabel/label, startAngle/endAngle) to restore the tremor default of a center dollar total and clockwise-from-12 rendering; defaults are unchanged so sibling stage PRs are unaffected.

  • Mechanical import swaps: BarChart and DonutChart imports switch from @tremor/react to @/components/shared/charts in TopKeyView, TopModelView, EntityUsage, SpendByProvider, KeyModelUsageView, and UsagePageView; data, props, heights, colors, and inline custom tooltips are unchanged.
  • Card primitives: The two sole-chart Daily Spend cards and KeyModelUsageView move from tremor Card/Title to shadcn Card/CardHeader/CardContent/CardAction/CardTitle; everything else on these pages remains tremor until its own stage.
  • Type alias conversions: DailyData, ProviderSpendData, TopModel, and ExtendedDailyData are converted from interface to type alias to satisfy the wrappers' Record<string, unknown> data constraint; tests are added for bar/sector counts, cyan fills, axis labels, donut center totals, startAngle geometry, and the TopKeyView bar-click drill-down.

Confidence Score: 5/5

Safe to merge — this is a well-scoped chart library swap with no changes to data flow, API calls, or business logic.

Every changed file is a UI-layer refactor: import swaps, card primitive upgrades, and three strictly additive props on DonutChart whose defaults keep existing callers rendering identically. The interface-to-type-alias conversions are structurally equivalent and required for the wrappers' generic constraint. New tests exercise real recharts SVG output and the previously flagged concerns have both been addressed with regression tests.

No files require special attention.

Important Files Changed

Filename Overview
ui/litellm-dashboard/src/components/shared/charts/donut_chart.tsx Adds showLabel/label and startAngle/endAngle props; formattedCategoryTotal helper is correctly guarded inside the showCenterLabel branch so valueFormatter is never called when the label is hidden.
ui/litellm-dashboard/src/components/UsagePage/components/EntityUsage/EntityUsage.tsx Swaps tremor BarChart/DonutChart imports for shared wrappers, migrates the Daily Spend card to shadcn primitives, and threads showLabel/startAngle/endAngle into the provider donut; no functional changes to data or tooltips.
ui/litellm-dashboard/src/components/UsagePage/components/KeyModelUsageView.tsx Full card migrated from tremor Card/Title to shadcn primitives with CardAction hosting the Table/Chart toggle; BarChart import swapped.
ui/litellm-dashboard/src/components/UsagePage/components/UsagePageView.tsx Daily Spend card migrated to shadcn primitives; BarChart import swapped; tremor Card/Title for that card removed.
ui/litellm-dashboard/src/components/shared/charts/donut_chart.test.tsx Adds tests for hidden label default, formatter-not-called guard, explicit label override, empty data guard, and 3 o'clock vs 12 o'clock startAngle geometry.

Reviews (2): Last reviewed commit: "fix(ui): compute donut center label only..." | Re-trigger Greptile

Comment thread ui/litellm-dashboard/src/components/shared/charts/donut_chart.tsx Outdated
Comment thread ui/litellm-dashboard/src/components/activity_metrics.test.tsx Outdated
@codspeed-hq

codspeed-hq Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_shadcn_charts_entity_usage (a282bd9) with litellm_internal_staging (0ebcda3)1

Open in CodSpeed

Footnotes

  1. No successful run was found on litellm_internal_staging (173193d) during the generation of this report, so 0ebcda3 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

…itellm_shadcn_charts_entity_usage

# Conflicts:
#	ui/litellm-dashboard/eslint-metrics.json
@ryan-crabbe-berri

Copy link
Copy Markdown
Contributor Author

@greptileai re review. Both P2s addressed: the donut center label total is now computed by a helper invoked only inside the showCenterLabel render branch, with a regression test asserting the valueFormatter is never called when the label is hidden; the Model Usage assertion now checks the text renders inside a [data-slot="card-title"] element instead of a bare getByText. Also merged latest litellm_internal_staging (picked up the eslint-metrics.json removal and the merged sibling chart PRs)

@codecov

codecov Bot commented Jul 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@ryan-crabbe-berri
ryan-crabbe-berri enabled auto-merge (squash) July 11, 2026 23:02
@ryan-crabbe-berri
ryan-crabbe-berri merged commit 0710cf2 into litellm_internal_staging Jul 11, 2026
126 checks passed
@ryan-crabbe-berri
ryan-crabbe-berri deleted the litellm_shadcn_charts_entity_usage branch July 11, 2026 23:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants