Skip to content

chore(ui): upgrade the dashboard to React 19 - #37411

Merged
ryan-crabbe-berri merged 5 commits into
litellm_internal_stagingfrom
litellm_react_19
Aug 19, 2026
Merged

chore(ui): upgrade the dashboard to React 19#37411
ryan-crabbe-berri merged 5 commits into
litellm_internal_stagingfrom
litellm_react_19

Conversation

@ryan-crabbe-berri

@ryan-crabbe-berri ryan-crabbe-berri commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

TLDR

Problem this solves:

  • Dashboard ran React 18 while Next 16 wants a React 19 peer
  • Base UI and shadcn upstream both assume the React 19 ref model
  • Test setup enforced an 18-only rule that 19 deliberately removed

How it solves it:

  • Bumps react and react-dom 18.3.1 to 19.2.8, plus matching @types
  • Widens one ref prop that useRef now types as nullable
  • Rewrites the ref assertions to the React 19 contract
  • Waits for a select popup to open before clicking its option
  • Stops the MCP edit form flashing a false no-OAuth-flow warning

User Flow

Before: nothing is broken for the end user, the dashboard just runs a React major behind the framework serving it

  1. An admin opens http://localhost:4000/ui/?page=api-keys and the page renders normally
  2. Every other dashboard page renders normally too
  3. The gap is invisible from the browser, it only shows up as a peer mismatch at install time and as upstream components the dashboard cannot adopt

After: the same pages render the same way on React 19

  1. An admin opens http://localhost:4000/ui/?page=api-keys and sees the same key table, filters, and modals
  2. Navigating to Models, Usage, Logs, Teams, and Playground shows the same content and the same interactions
  3. Nothing on screen changes, which is the point: the runtime moved forward with no visible behavior shift
  4. Opening an OAuth2 MCP server at http://localhost:4000/ui/?page=mcp-servers no longer flashes "This server has no OAuth flow set" before the saved flow appears

Relevant issues

Linear ticket

Pre-Submission checklist

  • 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)

Screenshots / Proof of Fix

To be added: this is a pure runtime upgrade with no intended visual change, so the proof is the same set of pages rendering identically before and after.

Type

🚄 Infrastructure

Caveats (if any)

  • tests/setupTests.ts no longer fails a test on dropped refs
  • That tripwire encoded React 18 behavior React 19 removed
  • Ref regressions are now caught by explicit per-component assertions
  • Three select tests were passing on timing luck, not on correctness
  • Roughly 20 more click a select option the same racy way

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

Bumps react and react-dom from 18.3.1 to 19.2.8 with matching @types. Next 16 already required a React 19 peer, so this aligns the dashboard with what the framework expects and unblocks Base UI and shadcn work that assumes the React 19 ref model.

React 19 passes ref through as a regular prop, so the setup file's forwardRef tripwire and the ref-forwarding test's forwardRef case no longer describe real behavior; both now assert the React 19 contract instead. useRef<T>(null) now yields RefObject<T | null>, which is the one prop type MessageList had to widen.
@ryan-crabbe-berri
ryan-crabbe-berri requested a review from a team August 19, 2026 02:08
@greptile-apps

greptile-apps Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR upgrades the dashboard from React 18 to React 19 and aligns its types and ref expectations with the new contract

  • Updates React, React DOM, and their type packages to matching React 19 releases
  • Widens MessageList's ref type to include its unmounted null state
  • Replaces React 18 dropped-ref warning enforcement with React 19 ref-as-prop assertions

Confidence Score: 4/5

The React 19 migration appears safe to merge, with a non-blocking gap in the replacement coverage for ref-forwarding regressions

The dependency and nullable-ref changes are internally consistent, but the new focused assertion does not preserve the removed suite-wide ref regression check

Files Needing Attention: ui/litellm-dashboard/tests/setupTests.ts and ui/litellm-dashboard/src/components/ui/ref-forwarding.test.tsx

Important Files Changed

Filename Overview
ui/litellm-dashboard/package.json Upgrades React, React DOM, and their types to mutually compatible React 19 versions
ui/litellm-dashboard/package-lock.json Resolves the React 19 dependency graph without an identified incompatible peer or duplicate React installation
ui/litellm-dashboard/src/app/(dashboard)/prompts/_components/prompt_editor_view/conversation_panel/MessageList.tsx Correctly widens the DOM ref prop for React 19's nullable RefObject typing
ui/litellm-dashboard/src/components/ui/ref-forwarding.test.tsx Adds a valid React 19 ref-as-prop assertion, but it does not replace the removed suite-wide regression coverage
ui/litellm-dashboard/tests/setupTests.ts Removes obsolete React 18 warning handling while also dropping suite-wide detection of ref regressions

Reviews (1): Last reviewed commit: "chore(ui): upgrade the dashboard to Reac..." | Re-trigger Greptile

);
}
});
afterEach(cleanup);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Suite-wide ref coverage removed

Replacing the global ref-warning check with cleanup leaves ref regressions outside the explicitly enumerated primitive tests undetected, reducing the suite's regression coverage.

Rule Used: What: Flag any modifications to existing tests and... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@ryan-crabbe-berri

Copy link
Copy Markdown
Contributor Author

The dropped-ref tripwire keyed on a React 18 warning that React 19 removed. Broad ref coverage returns with the forwardRef removal follow-up

…option

The option lands in the DOM one render before the popup finishes entering, while its positioner still carries pointer-events: none, so clicking it throws. Waiting on the option's text alone was a race that React 19's flush timing loses, which is why four ToolPolicies cases went red on the bump.

chooseSelectOption in test-utils opens the trigger, finds the option by role, waits for it to stop being pointer-blocked, then clicks. It also replaces the last-match-by-text hack, which only worked because the popup happens to portal after the table.
@codecov

codecov Bot commented Aug 19, 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) August 19, 2026 20:27
@tin-berri

Copy link
Copy Markdown
Contributor

Holding off on approving — ui-unit-tests is failing on a real regression, not a flake:

FAIL src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.test.tsx > MCPServerEdit OAuth flow prefill display > does not warn when the flow is already set

expected document not to contain element, found <div class="ant-alert-message">This server has no OAuth flow set</div> instead

With oauth2_flow: "client_credentials" prefilled, the "no OAuth flow set" warning is rendering when it shouldn't — contradicting the PR description's "no visible behavior shift" claim. Only 1/8466 tests failed, so this is narrow, but it looks like a genuine effect/ref-timing change under React 19 causing a prefill check in mcp_server_edit.tsx to run before the prefilled value is available. The rest of the diff (the RefObject type widening, the removal of the React-18-only ref-drop tripwire, and the new chooseSelectOption test helper fixing a real popup-timing race) all look correct and consistent with actual React 19 semantics — this is the one thing to chase down before merge.

…it form mounts

Form.useWatch returns undefined until its field mounts and registers, so a server with a stored flow rendered the "This server has no OAuth flow set" alert for the first commits of the form and then dropped it. The delegate switch two lines below already guards against exactly this by falling back to the stored value; the flow type now does the same.

React 19 makes the extra commit observable in CI, which is how the existing assertion caught it. The new test watches the DOM for the alert during mount rather than sampling it once, so the flash fails the suite instead of depending on flush timing.
…itellm_react_19

# Conflicts:
#	ui/litellm-dashboard/src/app/(dashboard)/mcp-servers/_components/mcp_server_edit.tsx
…ctOption

Same popup-still-entering race the ToolPolicies cases hit: the option text lands a render before the positioner drops pointer-events: none, so the click throws under React 19's flush timing.
@ryan-crabbe-berri
ryan-crabbe-berri merged commit f1e143a into litellm_internal_staging Aug 19, 2026
73 checks passed
@ryan-crabbe-berri
ryan-crabbe-berri deleted the litellm_react_19 branch August 19, 2026 21:18
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.

4 participants