From db1ea2d588038d1bdd9852b680c6c90a213e705e Mon Sep 17 00:00:00 2001 From: ryan-crabbe-berri Date: Fri, 19 Jun 2026 12:46:33 -0700 Subject: [PATCH] fix(ui): make key detail panel scroll so the edit form Save button stays reachable The key detail/edit panel wraps its content in a div meant to be the internal scroll container (overflow-y-auto) but sizes it with h-full. h-full only resolves when every ancestor has a definite height, and the chain breaks: a Tremor Grid and Col with no height sit between this div and the only fixed height in the tree (h-[75vh] in user_dashboard). So h-full collapses to auto, the panel grows to fit content and never scrolls internally, and reaching "Save Changes" falls back to the whole window scrolling. In any constrained-height shell that window scroll isn't available, so a long edit form's footer is cut off and the user cannot save from the UI. Add max-h-[85vh] to the container. A viewport-relative max-height always resolves regardless of ancestor heights, so the panel becomes a real bounded scroll container and the Save button is always reachable. The fix lives on the KeyInfoView component, so it covers every caller (keys page, team keys, usage, logs) without touching the shared dashboard layout or the table view. --- .../templates/key_info_view.test.tsx | 18 ++++++++++++++++++ .../src/components/templates/key_info_view.tsx | 2 +- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/ui/litellm-dashboard/src/components/templates/key_info_view.test.tsx b/ui/litellm-dashboard/src/components/templates/key_info_view.test.tsx index c762e1ac14b..5fbcf3daafe 100644 --- a/ui/litellm-dashboard/src/components/templates/key_info_view.test.tsx +++ b/ui/litellm-dashboard/src/components/templates/key_info_view.test.tsx @@ -163,6 +163,24 @@ describe("KeyInfoView", () => { }); }); + it("bounds the detail panel scroll container to the viewport so edit form actions stay reachable", async () => { + vi.mocked(useAuthorized).mockReturnValue(baseUseAuthorizedMock); + + const { container } = renderWithProviders( + {}} + keyId={"test-key-id"} + onKeyDataUpdate={() => {}} + teams={[]} + />, + ); + + const scrollContainer = container.querySelector(".overflow-y-auto"); + expect(scrollContainer).not.toBeNull(); + expect(scrollContainer!.className).toContain("max-h-[85vh]"); + }); + it("should not render tags in metadata textarea", async () => { vi.mocked(useAuthorized).mockReturnValue(baseUseAuthorizedMock); diff --git a/ui/litellm-dashboard/src/components/templates/key_info_view.tsx b/ui/litellm-dashboard/src/components/templates/key_info_view.tsx index 018880b70aa..9fe91cb164b 100644 --- a/ui/litellm-dashboard/src/components/templates/key_info_view.tsx +++ b/ui/litellm-dashboard/src/components/templates/key_info_view.tsx @@ -412,7 +412,7 @@ export default function KeyInfoView({ }; return ( -
+