Skip to content

refactor(ui): migrate logging-and-alerts, caching, policies to shadcn - #34468

Merged
yuneng-berri merged 4 commits into
litellm_internal_stagingfrom
litellm_/wonderful-northcutt-14b37d
Jul 24, 2026
Merged

refactor(ui): migrate logging-and-alerts, caching, policies to shadcn#34468
yuneng-berri merged 4 commits into
litellm_internal_stagingfrom
litellm_/wonderful-northcutt-14b37d

Conversation

@yuneng-berri

@yuneng-berri yuneng-berri commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • Three low-traffic routes still render antd and Tremor
  • Their colours are hardcoded, blocking any theme change
  • One page emitted invalid DOM nesting warnings

How it solves it:

  • Migrates 17 route-owned files onto shadcn primitives
  • Colour now comes from tokens, not utilities
  • Retires 53 antd import suppressions from the lint baseline

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

Before is commit 64aad5877a, after is commit b2cf17d4a2. Screenshots are attached below as before/after pairs for caching and policies. logging-and-alerts is not shown as a full-page pair because the parts this PR changes live behind its CloudZero Cost Tracking and Email Alerts tabs rather than on the landing tab; those two are attached on their own.

To reproduce locally, run the proxy and the dashboard dev server, then work through this list in order

  1. Start the proxy with python litellm/proxy/proxy_cli.py --config litellm/proxy/dev_config.yaml --detailed_debug --reload, and the dashboard with npm run dev in ui/litellm-dashboard
  2. Open http://localhost:3000/caching/ and confirm the four tabs, the two filter fields, the three stat cards and both charts render; the date range control is unchanged
  3. Click Cache Health, press Run Health Check, and confirm the status line, Error Details and Cache Details sections render and the disclosure triangles expand a truncated value
  4. Click Coordination Redis and open the Redis Type dropdown; it must show the label "Node (Single Instance)" in the closed control, not the raw value "node", and list all three types
  5. Open http://localhost:3000/policies/ and confirm the About Policies alert renders with a working dismiss control, and that the template cards show their complexity and tag badges
  6. Still on the Templates tab, press Use Template on any card; the guardrail selection dialog must open. This is the regression called out under Changes below, so it is worth exercising: confirm it opens, that Select All New and Deselect All work, and that confirming lands you on the Policies tab with the policy form prefilled
  7. Open http://localhost:3000/logging-and-alerts/, click CloudZero Cost Tracking, and confirm the empty-state panel and its Add CloudZero Integration button render
  8. Click Email Alerts and confirm the notification checkboxes reflect saved state and that the Email Server Settings fields render in two columns with their help text

The local visual gate photographed all 35 dashboard routes before and after. The three migrated routes were deliberately re-baselined; the other 32 stayed pixel-identical, so this change has no blast radius outside its own routes.

Type

🧹 Refactoring
🐛 Bug Fix

Changes

The analyzer scopes each route to the files it exclusively owns, and the three sets are disjoint, so this is one PR rather than three. Seventeen files moved onto shadcn primitives and lucide icons.

logging-and-alerts owns CloudZeroCostTracking.tsx, CloudZeroEmptyPlaceholder.tsx, CloudZeroIntegrationSettings.tsx, email_events/email_event_settings.tsx and email_settings.tsx. The antd Descriptions and Popconfirm on the CloudZero settings panel become a definition list and a controlled AlertDialog, which also keeps the export button's in-flight state instead of dismissing on click. email_settings.tsx additionally loses an invalid DOM nesting it had before: a Tremor TableCell rendered a <td> inside a <div>, and the help text put <div>s inside a <p>, both of which React was warning about on every render.

caching owns cache_dashboard.tsx, cache_health.tsx, cache_settings/RedisTypeSelector.tsx and coordination_redis_settings/CoordinationRedisTypeSelector.tsx. The two Tremor MultiSelects become the combobox-with-chips pattern already used on the usage page. Both Redis type selectors render their label through SelectValue rather than letting Base UI print the raw value.

policies owns ai_suggestion_modal.tsx, guardrail_selection_modal.tsx, impact_preview_alert.tsx, index.tsx, pipeline_flow_builder.tsx, policy_info.tsx, policy_templates.tsx and template_parameter_modal.tsx. Two behaviours needed care rather than a straight swap. GuardrailSelectionModal and TemplateParameterModal moved from inside the Policies tab panel up to the panel root: Base UI Tabs mounts only the active panel where Tremor mounted all of them, and both dialogs are opened from the Templates tab, so leaving them nested made Use Template silently do nothing. Separately, the competitor-names control was an antd Select mode="tags", which accepts values the user types; Base UI's combobox only selects from a fixed item list, so that one is a small controlled tag input rather than a combobox, preserving type-to-add, comma separation and backspace-to-remove.

Three files the analyzer listed are deliberately untouched, and each is worth calling out.

impact_popover.tsx stays on antd. Its existing test replaces the antd module with a stub that fabricates the popover trigger and renders the popover body eagerly, so every assertion in it is bound to antd's module shape rather than to rendered markup. Migrating the component makes all twelve of those tests fail, and the rule this migration follows is that a component's test must pass before and after without being edited. Rewriting that test needs the component to expose an accessible trigger first, which is a behaviour change and belongs in its own PR.

cache_settings/cacheSettingsFields.ts and coordination_redis_settings/coordinationRedisFields.ts are listed as migratable because they are not form files by the analyzer's definition, but their only antd surface is type CacheFieldRule = NonNullable<FormItemProps["rules"]>[number]. Those rules are consumed solely by CacheFormField.tsx and the settings index.tsx, both of which are deferred antd forms. There is no markup to migrate and retyping the rules would break the deferred forms.

Everything the analyzer bucketed as shared is untouched, so DeleteResourceModal.tsx (23 pages), message_manager.tsx and notifications_manager.tsx (53 pages each) and shared/usage_date_picker.tsx (2 pages) keep their current implementation. The deferred antd forms on these routes are likewise untouched. Both of those mean these routes still import antd after this PR, which is expected.

Tests come first, in their own commit that changes no component. Seven components had no test at all and now have one; cache_dashboard's existing test asserted a global count of card nodes, which any new card would have broken, so its chart lookups are now anchored on each chart's own title. Every one of those tests was proven green against the antd and Tremor components before the migration commit, and none of them is edited by the migration commit.

radio-group is added through the shadcn CLI for the competitor-discovery mode toggle; it is the only new primitive.

One bug is fixed rather than carried forward. A template with no LLM enrichment rendered every parameter field twice, because nonEnrichmentParams is the whole parameter list when there is no enrichment and a second no-enrichment branch mapped that same list again. It predates this migration; the field is now rendered once and the test asserts exactly one input per parameter, so the duplicate branch cannot come back unnoticed.

Worth noting for reviewers comparing behaviour: clicking the checkbox on a suggested template in the AI suggestion modal used to be a no-op. antd's Checkbox fired its own handler and also let the click bubble to the row's handler, so the two toggles cancelled. Base UI does not, so that control now works; this was measured on both versions rather than inferred.

Final Attestation

  • The tests check the right things, including the edge cases, and regressions in the respective real-world customer use-cases are not possible after this PR

…re the shadcn migration

Establishes the regression net for the upcoming markup migration of these
three routes. Every assertion here is written against the current antd and
Tremor components and passes against them, so it carries no knowledge of the
markup that replaces them and stays meaningful afterwards.

Adds characterisation tests for the seven components that had none, and
rewrites cache_dashboard's chart-card lookup to anchor on each chart's own
title instead of asserting a global count of card nodes, which would break the
moment another card appears on the page.

No component is touched in this commit.
Markup-only migration of the 17 files these three routes exclusively own,
replacing antd and Tremor with the installed shadcn (base-vega) primitives and
lucide icons. No route behaviour changes; the tests written in the previous
commit are untouched here and pass against both the old and the new markup.

Colour now comes from tokens rather than from hardcoded utilities, so the
health-check button, the alerts and the badges no longer pin their own palette.
email_settings also loses an invalid DOM nesting (a table cell inside a div, and
a div inside a paragraph) that React had been warning about.

Two modals on the policies page moved from the Policies panel up to the panel
root. Base UI Tabs mounts only the active panel, unlike Tremor, and both are
opened from the Templates tab, so leaving them nested would have made "Use
Template" do nothing.

Retires 53 antd import suppressions from the eslint baseline.
@greptile-apps

greptile-apps Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR migrates the caching, policies, and logging-and-alerts routes from Ant Design and Tremor components to shadcn primitives.

  • Replaces route-owned controls, dialogs, tabs, cards, and icons with token-based shadcn equivalents.
  • Fixes checkbox selection behavior in the AI suggestion modal and duplicate plain-parameter rendering in the template modal.
  • Adds focused component tests and removes obsolete lint suppressions.

Confidence Score: 5/5

The PR appears safe to merge based on the eligible follow-up findings.

No blocking failure remains in the fixes associated with the previous review threads.

Important Files Changed

Filename Overview
ui/litellm-dashboard/src/app/(dashboard)/policies/_components/ai_suggestion_modal.tsx Migrates the modal to shadcn components and replaces the checkbox callback involved in the previous interaction defect.
ui/litellm-dashboard/src/app/(dashboard)/policies/_components/template_parameter_modal.tsx Consolidates parameter rendering so plain template parameters appear once and migrates the modal controls to shadcn.
ui/litellm-dashboard/src/app/(dashboard)/caching/_components/cache_dashboard.tsx Migrates caching tabs, filters, cards, and refresh controls to shadcn primitives.
ui/litellm-dashboard/src/components/CloudZeroCostTracking/CloudZeroIntegrationSettings.tsx Migrates the CloudZero integration settings and confirmation flow to shadcn components.
ui/litellm-dashboard/src/components/email_settings.tsx Migrates email settings presentation while correcting invalid DOM nesting.

Reviews (2): Last reviewed commit: "fix(ui): render each policy template par..." | Re-trigger Greptile

A template with no LLM enrichment rendered every parameter field twice: the
shared list already covers them, because nonEnrichmentParams is the full
parameter list when there is no enrichment, and a second no-enrichment branch
mapped the same list again.

Predates the shadcn migration and was carried forward by it. The test now
asserts exactly one field per parameter, and fails if the duplicate branch
comes back.
@yuneng-berri

Copy link
Copy Markdown
Contributor Author

@greptileai

@yuneng-berri
yuneng-berri enabled auto-merge July 24, 2026 06:32
@devin-ai-integration

Copy link
Copy Markdown
Contributor

UI QA — shadcn / Base UI migration (caching, policies, logging-and-alerts)

Ran the PR branch's dashboard dev server against a local proxy, logged in as admin, and walked all three migrated routes end to end following the runbook. Every core scenario passes and there are no visual regressions on the migrated surfaces

Full walkthrough recording:

QA walkthrough

Use Template -> guardrail dialog end to end (key regression)

The guardrail selection dialog opens from a lazily-mounted tab panel, Select All New and Deselect All toggle the count correctly, and confirming closes the dialog, switches to the Policies tab, and lands on a pre-filled Create New Policy form

Guardrail selection dialog
Prefilled policy form

Caching: analytics, Cache Health, Coordination Redis label fix

Analytics tab renders the four tabs, both filters, three stat cards, both charts and the date range control

Caching analytics

Cache Health run shows the status line plus Error Details and Cache Details with working disclosure triangles

Cache Health

Coordination Redis closed control shows the label "Node (Single Instance)" rather than the raw value "node", and lists all three types

Redis Type dropdown

Policies: About alert and template badges

The About Policies alert renders with a working dismiss control, and the template cards show their complexity and tag badges

Policies templates and badges

Logging and Alerts: CloudZero empty state and Email Alerts layout

CloudZero Cost Tracking empty state renders with its Add CloudZero Integration button

CloudZero empty state

Email Alerts shows saved checkbox state and the Email Server Settings fields in a two-column grid with help text

Email Alerts

Fixed behaviors

Template parameter field renders exactly once (one label, one input)

Parameter renders once

The AI suggestion checkbox toggle could not be verified through the UI: the "Use AI to find templates" matcher returned zero matches across models and prompts, so no suggestion cards rendered. The empty state itself renders correctly, and the checkbox fix is covered by the added unit test

AI matcher zero matches

One item outside this PR's scope: the still-Ant/Tremor Alerting Settings tab logs a React hydration warning (<td> nested in <div> for slack_alerting); it appears pre-existing and is flagged only for awareness

Tested by Devin: https://app.devin.ai/sessions/91b4964baa804ec48b67cda75da9095a

@yuneng-berri
yuneng-berri merged commit 33b9524 into litellm_internal_staging Jul 24, 2026
76 checks passed
@yuneng-berri
yuneng-berri deleted the litellm_/wonderful-northcutt-14b37d branch July 24, 2026 14:08
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