Skip to content

chore(admin-ui): regenerate static export with trailingSlash: true#28112

Merged
mateo-berri merged 5 commits into
litellm_internal_stagingfrom
litellm_rebuild_admin_ui_static_export
May 26, 2026
Merged

chore(admin-ui): regenerate static export with trailingSlash: true#28112
mateo-berri merged 5 commits into
litellm_internal_stagingfrom
litellm_rebuild_admin_ui_static_export

Conversation

@mateo-berri

@mateo-berri mateo-berri commented May 17, 2026

Copy link
Copy Markdown
Collaborator

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

  • I have added meaningful tests
  • My PR passes all unit tests on make test-unit
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have requested a Greptile review by commenting @greptileai and received a Confidence Score of at least 4/5 before requesting a maintainer review

CI (LiteLLM team)

  • Branch creation CI run; Link:
  • CI run for the last commit; Link:
  • Merge / cherry-pick CI run; Links:

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 build inside ui/litellm-dashboard (with trailingSlash: true applied locally per #28106's diff) and copying ./out/. into litellm/proxy/_experimental/out/. Every previously top-level <name>.html is now under <name>/index.html; the only top-level HTML files left are index.html and 404.html, which Next.js requires by those exact names.

Type

Infrastructure

Changes

Regenerated litellm/proxy/_experimental/out/ from the dashboard build with trailingSlash: true so 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.mjs now sets trailingSlash: true, so the exported site uses <route>/index.html (including nested paths like MCP OAuth callback) instead of sibling *.html files under subfolders.

docker/Dockerfile.non_root drops the build step that moved top-level *.html into per-route folders; the image only copies _experimental/out and writes .litellm_ui_ready.

tests/test_litellm/proxy/test_proxy_server.py adds a guard on the checked-in export: no nested foo.html offenders, the MCP OAuth callback page exists at the expected path, and FastAPI StaticFiles serves /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.

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.
@greptile-apps

greptile-apps Bot commented May 17, 2026

Copy link
Copy Markdown
Contributor

Too many files changed for review. (801 files found, 100 file limit)

@codecov

codecov Bot commented May 17, 2026

Copy link
Copy Markdown

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.
@mateo-berri mateo-berri requested a review from yuneng-berri May 25, 2026 16:10
@mateo-berri mateo-berri enabled auto-merge (squash) May 25, 2026 18:24
@mateo-berri mateo-berri merged commit 48d7e15 into litellm_internal_staging May 26, 2026
109 of 114 checks passed

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

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: true already 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.

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,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 8ca7f0b. Configure here.

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