Skip to content

refactor(ui): consolidate invitation flow into the dashboard layout - #32576

Merged
ryan-crabbe-berri merged 1 commit into
litellm_internal_stagingfrom
litellm_approuter_closeout
Jul 9, 2026
Merged

refactor(ui): consolidate invitation flow into the dashboard layout#32576
ryan-crabbe-berri merged 1 commit into
litellm_internal_stagingfrom
litellm_approuter_closeout

Conversation

@ryan-crabbe-berri

@ryan-crabbe-berri ryan-crabbe-berri commented Jul 9, 2026

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

This is a behavior-preserving refactor of the dashboard shell, so the proof is that the three entry points the index touches still behave identically. Run the dev proxy (and the UI dev server if you want the fast path), log in, then walk these in order and screenshot each:

  1. http://localhost:4000/ui/ renders the API Keys landing (virtual keys table), same as before
  2. http://localhost:4000/ui/?page=teams immediately redirects to http://localhost:4000/ui/teams (legacy bookmark back-compat still works)
  3. Generate an invitation link from Internal Users, open it in a fresh/incognito window, and confirm it lands on the onboarding form with no sidebar or navbar. The modern link already targets /ui/onboarding?invitation_id=; the legacy /ui/?invitation_id= shape now redirects to that same onboarding route with the params preserved
  4. Log out from an authed session on /ui/ and confirm it still bounces to the SSO login with a redirect_to back to where you were

Local checks captured at commit 6b9fc41: npx vitest run on the touched suites (layout, CreateKeyPage, migratedPages, ApiKeysDashboard, user_dashboard) all green, npm run build compiles every route, and make pre-commit passes.

Type

🧹 Refactoring

Changes

The App Router migration is finished; every page is a real path route and the legacy ?page= switch is already gone from the index. This is the closeout.

The /ui/ index page carried its own duplicate copy of teams state, a teams fetch, and keys/addKey plumbing, all so it could render a second UserDashboard for the invitation_id case. That was redundant because ApiKeysDashboard already renders UserDashboard sourcing its own data. The index is thinned to just render <ApiKeysDashboard />; the login redirect, the legacy ?page= deep-link redirect for old bookmarks, and the post-login return-URL handling all stay put

The invitation entry point now resolves in one place. Modern invitation links already point at the dedicated /onboarding route, so the dashboard layout redirects legacy /ui/?invitation_id= links there too, preserving the query params. It does this with migratedHref, the same base-path-aware redirect the index already uses for ?page=, so SERVER_ROOT_PATH deployments resolve correctly. This replaces the previous approach of importing the /onboarding route's page.tsx into another module and re-rendering it inline. With that gone, the now-unreachable if (invitation_id != null) return <Onboarding/> branch in the shared user_dashboard.tsx is deleted here as well, along with its dead Onboarding import and searchParams read. A layout test asserts the redirect and fails if it regresses

While mapping this out I found that legacyPageHref and the sidebar's migrated-vs-legacy href fallback are not dead: the parent-category nav nodes (agentic, tools, experimental, settings) are not page routes and still flow through the legacy path builder, so removing it would break their hrefs. It is intentionally left in place, which narrows this PR from the original closeout sketch

eslint-metrics.json is resynced. The change removes two any casts (no-explicit-any 1982 to 1980); the snapshot also picks up pre-existing drift on no-large-inline-object-arg (512 to 519) that the gate requires the file to match, since lint:metrics regenerates the whole snapshot rather than a single rule

@greptile-apps

greptile-apps Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR consolidates the invitation entry point into the (dashboard) layout and removes duplicate state from the index page. The legacy /ui/?invitation_id= URL shape now redirects to the dedicated /ui/onboarding route inside the layout, replacing the previous pattern of importing and re-rendering onboarding/page.tsx inline.

  • layout.tsx: LayoutContent detects invitation_id in search params, shows LoadingScreen, and fires router.replace toward migratedHref("onboarding") once authLoading clears, preventing the dashboard shell from mounting for invited users.
  • page.tsx: Teams state, UserDashboard branch, and invitation guard removed; the component now unconditionally renders <ApiKeysDashboard />; legacy ?page= redirect corrected to use explicitPage instead of the always-truthy page fallback.
  • user_dashboard.tsx: Dead if (invitation_id != null) return <Onboarding/> branch and its associated imports removed now that the layout handles the redirect upstream.

Confidence Score: 5/5

Safe to merge — the refactor is behavior-preserving, the new redirect path is covered by a focused layout test, and the removed code paths are genuinely unreachable.

The invitation redirect logic is centralized in one well-tested place. The layout suppresses child rendering when isInvitationFlow is true, so the page component's redirectToLogin can never race with the layout redirect. Removed branches in page.tsx and user_dashboard.tsx were dead code once the layout took ownership. The explicitPage vs page fix in the legacy redirect is a correctness improvement with no regressions. No auth paths, data mutations, or API calls are affected.

No files require special attention.

Important Files Changed

Filename Overview
ui/litellm-dashboard/src/app/(dashboard)/layout.tsx Adds legacy-invitation-link redirect in LayoutContent: when invitation_id is present, shows LoadingScreen and calls router.replace toward /onboarding, suppressing the dashboard shell for that flow.
ui/litellm-dashboard/src/app/(dashboard)/layout.test.tsx Adds a new test asserting that invitation_id in search params causes router.replace to be called with /onboarding and suppresses dashboard shell rendering; wires up replaceMock and mutable searchParamsValue properly.
ui/litellm-dashboard/src/app/(dashboard)/page.tsx Removes duplicate teams state, UserDashboard branch, and invitation_id check; fixes legacy-redirect to use explicitPage instead of the defaulted page variable; renders ApiKeysDashboard unconditionally.
ui/litellm-dashboard/src/components/user_dashboard.tsx Removes now-dead invitation_id early-return branch and the Onboarding import/useSearchParams call that supported it; no functional change to the component's normal rendering path.
ui/litellm-dashboard/eslint-metrics.json Snapshot resynced: no-explicit-any decremented by 2 (two any casts removed); no-large-inline-object-arg incremented by 7 reflecting pre-existing drift captured by the full regeneration.

Reviews (2): Last reviewed commit: "refactor(ui): consolidate invitation flo..." | Re-trigger Greptile

Comment thread ui/litellm-dashboard/src/app/(dashboard)/layout.tsx Outdated
@codecov

codecov Bot commented Jul 9, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing litellm_approuter_closeout (6b9fc41) with litellm_internal_staging (131aa05)

Open in CodSpeed

The App Router migration is complete: every page is a path route and the
legacy `?page=` switch is gone from the index. This closes it out.

The `/ui/` index (page.tsx) kept its own duplicate copy of teams state, a
teams fetch, and keys/addKey plumbing solely to feed a second `UserDashboard`
render for the `invitation_id` case. That was redundant: `ApiKeysDashboard`
already renders `UserDashboard` sourcing its own data, so the index is thinned
to just render `<ApiKeysDashboard />`. The login redirect, the legacy `?page=`
deep-link redirect for old bookmarks, and the post-login return-URL handling
stay on the index.

The invitation entry point now resolves in one place. Modern invitation links
already point at the dedicated `/onboarding` route; the dashboard layout now
redirects legacy `/ui/?invitation_id=` links there too (via `migratedHref`,
the same base-aware redirect the index uses for `?page=`), instead of
re-rendering that route's page component inline. This removes an import of one
route's `page.tsx` into another module, and lets the now-unreachable
`if (invitation_id) return <Onboarding/>` branch in the shared
`user_dashboard.tsx` be deleted along with its dead `Onboarding` import and
`searchParams` read. A layout test asserts the redirect and fails if it
regresses.

`legacyPageHref` and the sidebar's migrated-vs-legacy href fallback are left
in place; they are still live for the parent-category nav nodes (agentic,
tools, experimental, settings) that are not page routes.

eslint-metrics.json is resynced: -2 no-explicit-any from the removed `any`
casts, plus pre-existing drift the gate requires the snapshot to match.
@ryan-crabbe-berri
ryan-crabbe-berri force-pushed the litellm_approuter_closeout branch from 184ba4e to 6b9fc41 Compare July 9, 2026 18:17
@ryan-crabbe-berri

Copy link
Copy Markdown
Contributor Author

@greptileai re review

@ryan-crabbe-berri
ryan-crabbe-berri enabled auto-merge (squash) July 9, 2026 18:59
@ryan-crabbe-berri
ryan-crabbe-berri merged commit 1d9a86e into litellm_internal_staging Jul 9, 2026
126 checks passed
@ryan-crabbe-berri
ryan-crabbe-berri deleted the litellm_approuter_closeout branch July 9, 2026 18:59
edelauna pushed a commit to edelauna/litellm that referenced this pull request Jul 22, 2026
…erriAI#32576)

The App Router migration is complete: every page is a path route and the
legacy `?page=` switch is gone from the index. This closes it out.

The `/ui/` index (page.tsx) kept its own duplicate copy of teams state, a
teams fetch, and keys/addKey plumbing solely to feed a second `UserDashboard`
render for the `invitation_id` case. That was redundant: `ApiKeysDashboard`
already renders `UserDashboard` sourcing its own data, so the index is thinned
to just render `<ApiKeysDashboard />`. The login redirect, the legacy `?page=`
deep-link redirect for old bookmarks, and the post-login return-URL handling
stay on the index.

The invitation entry point now resolves in one place. Modern invitation links
already point at the dedicated `/onboarding` route; the dashboard layout now
redirects legacy `/ui/?invitation_id=` links there too (via `migratedHref`,
the same base-aware redirect the index uses for `?page=`), instead of
re-rendering that route's page component inline. This removes an import of one
route's `page.tsx` into another module, and lets the now-unreachable
`if (invitation_id) return <Onboarding/>` branch in the shared
`user_dashboard.tsx` be deleted along with its dead `Onboarding` import and
`searchParams` read. A layout test asserts the redirect and fails if it
regresses.

`legacyPageHref` and the sidebar's migrated-vs-legacy href fallback are left
in place; they are still live for the parent-category nav nodes (agentic,
tools, experimental, settings) that are not page routes.

eslint-metrics.json is resynced: -2 no-explicit-any from the removed `any`
casts, plus pre-existing drift the gate requires the snapshot to match.
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