refactor(ui): convert projects page chart to shadcn/recharts - #32722
Conversation
Greptile SummaryReplaces the last remaining
Confidence Score: 5/5A purely mechanical import swap with no logic changes; the shared wrapper accepts all props that were passed to the tremor component, and the new test suite covers the key rendering invariants. The production change is a single-line import swap; the call site, prop values, and surrounding layout are all untouched. The wrapper's BarChart fully supports every prop used here (layout, colors, valueFormatter, yAxisWidth, showLegend, style). The added tests exercise bar count/color, axis labels, height scaling, and the empty state against the real recharts DOM output. No files require special attention.
|
| Filename | Overview |
|---|---|
| ui/litellm-dashboard/src/app/(dashboard)/projects/_components/ProjectDetailsPage.tsx | Single-line import swap from @tremor/react to @/components/shared/charts; all existing props (layout, colors, valueFormatter, yAxisWidth, showLegend, style height) are fully supported by the shared wrapper. |
| ui/litellm-dashboard/src/app/(dashboard)/projects/_components/ProjectDetailsPage.test.tsx | Adds a 'Spend by Model chart' describe block with five tests covering bar count/color, legend absence, y-axis ordering, x-axis dollar formatting, dynamic height calculation, and empty-state rendering; uses recharts 3 DOM classes that are built dynamically at runtime. |
Reviews (2): Last reviewed commit: "refactor(ui): convert projects page char..." | Re-trigger Greptile
|
@greptileai re review. Both P1s are incorrect: recharts 3 builds those classes dynamically in CartesianAxis.js via "recharts-cartesian-axis-tick-labels recharts-".concat(axisType, "-tick-labels"), so .recharts-yAxis-tick-labels and .recharts-xAxis-tick-labels do exist at runtime. A literal grep misses them, and the flagged assertions pass non-vacuously (21/21 in the file; an empty NodeList would fail expect([]).toEqual([...]) loudly) |
d37ba79
into
litellm_internal_staging
Relevant issues
Linear ticket
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
@greptileaito 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 on the project details page (screenshots to follow in a comment):
python litellm/proxy/proxy_cli.py --config litellm/proxy/dev_config.yaml) and the dashboard dev server (npm run devin ui/litellm-dashboard)enableProjectsUIflag) and click the ID of a project that already has spend; the "Spend by Model" card holds the converted chartcurl -s http://localhost:4000/key/generate -H "Authorization: Bearer sk-1234" -H "Content-Type: application/json" -d '{"project_id": "<project id>"}', then send a few completions through that key across two models from your config so multiple bars render, e.g.for m in gpt-5.2 claude-sonnet-5; do curl -s http://localhost:4000/v1/chat/completions -H "Authorization: Bearer <key>" -H "Content-Type: application/json" -d '{"model": "'$m'", "messages": [{"role": "user", "content": "hi"}]}'; done, and reload the project page once the spend tracker flushesBefore (staging, tremor BarChart) and after (this branch, recharts through the shared wrapper) should look near-identical; "cyan" maps to the same cyan-500 the tremor palette used


Type
🧹 Refactoring
Changes
Converts the last tremor chart on the projects page, the "Spend by Model" horizontal BarChart in ProjectDetailsPage, to the shared shadcn/recharts
BarChartwrapper from #32668. The change is an import swap; every prop stays as-is (vertical layout, single cyan "spend" series,$four-decimal valueFormatter on the value axis and tooltip, 140px category axis, legend off, and the dynamic height of 40px per model with a 120px floor carried through the wrapper'sstyleprop). The surrounding antd Card, Row/Col grid, and the antd Empty fallback for projects without spend stay untouched; the card was never tremor, so unlike the pilot there is no Card conversion hereOne known deviation from tremor: the wrapper renders every category label on the vertical axis (
interval={0}) instead of thinning them, which is the desired behavior here since the chart already grows 40px per model rowProjectDetailsPage.test.tsx gains a "Spend by Model chart" block asserting against the real recharts SVG (via the scoped jsdom ResizeObserver mock): one cyan-500 bar series with a rectangle per model and no legend, category ticks sorted by spend descending,
$x.xxxxvalue axis ticks, the 40px-per-model/120px-floor container height, and the empty state whenmodel_spendis empty