chore(admin-ui): regenerate static export with trailingSlash: true#28112
Conversation
Rebuilds litellm/proxy/_experimental/out/ from ui/litellm-dashboard with `trailingSlash: true` enabled in next.config.mjs. Next.js now emits every route as <dir>/index.html (e.g. mcp/oauth/callback/index.html) instead of <dir>.html with a sibling metadata-only directory, which fixes the 404 on extensionless URLs served through FastAPI's StaticFiles(html=True) mount. This is the build artifact half of the fix; the config change, Dockerfile cleanup, and regression test live in the follow-up source PR that stacks on top of this branch.
|
Too many files changed for review. ( |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Linear and other OAuth providers redirect the user back to /ui/mcp/oauth/callback?code=...&state=... after the consent step. The packaged Next.js static export only produced /ui/mcp/oauth/callback.html, so FastAPI's StaticFiles served a 404 on the extensionless URL and the OAuth handshake never completed. The Dockerfile.non_root build step tried to paper over this at image-build time with `for html_file in *.html; do ...`, but that shell glob does not recurse, so nested routes like mcp/oauth/callback.html were left stranded next to an empty mcp/oauth/callback/ directory containing only Next.js metadata. The runtime restructure step in proxy_server.py was then skipped because the .litellm_ui_ready marker had already been dropped. Set trailingSlash: true in the dashboard's Next.js config so the export emits every nested route as <dir>/index.html natively. The Dockerfile loop is now a no-op for the bundled UI and has been removed; the .litellm_ui_ready marker is still written so the proxy keeps skipping the redundant Python restructure step at startup. Stacks on top of the static export regeneration in the parent branch.
…itellm_rebuild_admin_ui_static_export
…itellm_rebuild_admin_ui_static_export
48d7e15
into
litellm_internal_staging
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: E2E script restructuring loop conflicts with trailingSlash config
- Removed the now-unnecessary HTML restructuring loop from run_e2e.sh since
trailingSlash: truealready emits routes as /index.html and the loop would incorrectly relocate root-level special files like 404.html and _not-found.html, matching the equivalent removal in Dockerfile.non_root.
- Removed the now-unnecessary HTML restructuring loop from run_e2e.sh since
You can send follow-ups to the cloud agent here.
Reviewed by Cursor Bugbot for commit 8ca7f0b. Configure here.
| }, | ||
| basePath: "", | ||
| assetPrefix: "/litellm-asset-prefix", | ||
| trailingSlash: true, |
There was a problem hiding this comment.
E2E script restructuring loop conflicts with trailingSlash config
Medium Severity
Adding trailingSlash: true changes the Next.js export format so routes are already output as <route>/index.html. However, ui/litellm-dashboard/e2e_tests/run_e2e.sh (lines 111-118) still runs a find ... -name '*.html' ! -name 'index.html' loop that moves any non-index.html HTML files into subdirectories. With the new config, this loop will incorrectly move special files like _not-found.html (or 404.html if still generated at root) into _not-found/index.html, potentially conflicting with Next.js internal routing expectations. The script's comment even says "Next.js export produces login.html" which is no longer true with trailingSlash: true.
Reviewed by Cursor Bugbot for commit 8ca7f0b. Configure here.


Relevant issues
Stacked under #28106. Split out of that PR so the source change and regression test can be reviewed without 800+ build-artifact diffs in the way.
Linear ticket
N/A
Pre-Submission checklist
make test-unit@greptileaiand received a Confidence Score of at least 4/5 before requesting a maintainer reviewCI (LiteLLM team)
Screenshots / Proof of Fix
The proof of fix lives in the source PR #28106; this PR is purely the rebuilt
litellm/proxy/_experimental/out/artifact that the source PR depends on. Once both land, the curl and browser flow shown in #28106 produces the same result against the deployed image.The artifact was regenerated by running
npm run buildinsideui/litellm-dashboard(withtrailingSlash: trueapplied locally per #28106's diff) and copying./out/.intolitellm/proxy/_experimental/out/. Every previously top-level<name>.htmlis now under<name>/index.html; the only top-level HTML files left areindex.htmland404.html, which Next.js requires by those exact names.Type
Infrastructure
Changes
Regenerated
litellm/proxy/_experimental/out/from the dashboard build withtrailingSlash: trueso every nested route lives at<dir>/index.html. No source code changes in this PR; the config change, Dockerfile cleanup, and regression test are in the stacked source PR.Note
Low Risk
Packaging and static-asset layout changes with regression tests; no auth or API logic changes in this diff.
Overview
Aligns the admin dashboard static export with directory-style routes so extensionless
/ui/...paths work without a Docker-time HTML reshuffle.ui/litellm-dashboard/next.config.mjsnow setstrailingSlash: true, so the exported site uses<route>/index.html(including nested paths like MCP OAuth callback) instead of sibling*.htmlfiles under subfolders.docker/Dockerfile.non_rootdrops the build step that moved top-level*.htmlinto per-route folders; the image only copies_experimental/outand writes.litellm_ui_ready.tests/test_litellm/proxy/test_proxy_server.pyadds a guard on the checked-in export: no nestedfoo.htmloffenders, the MCP OAuth callback page exists at the expected path, and FastAPIStaticFilesserves/ui/mcp/oauth/callback(with trailing-slash redirect) for OAuth return URLs.Reviewed by Cursor Bugbot for commit 8ca7f0b. Bugbot is set up for automated code reviews on this repo. Configure here.