From 4544f7dbaddef304799718c7f3899f1bf95b7ba4 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Fri, 14 Aug 2026 07:10:13 -0700 Subject: [PATCH] revert(ui): keep the onboarding link modal on antd The invitation dialog opens over the still-antd Invite User modal. Lifting only the shadcn dialog content above antd's mask leaves its own backdrop underneath, so an outside click reaches the wrong modal. Adding a second backdrop stops that but does not restore dismissal, and the same hazard already ships in three guardrails modals, so the stacking needs one shared fix rather than a fourth local workaround. --- ui/litellm-dashboard/eslint-suppressions.json | 3 + .../src/components/onboarding_link.test.tsx | 91 +------------------ .../src/components/onboarding_link.tsx | 65 +++++++------ 3 files changed, 42 insertions(+), 117 deletions(-) diff --git a/ui/litellm-dashboard/eslint-suppressions.json b/ui/litellm-dashboard/eslint-suppressions.json index 2e72df1225b..e0ad8ca1606 100644 --- a/ui/litellm-dashboard/eslint-suppressions.json +++ b/ui/litellm-dashboard/eslint-suppressions.json @@ -2848,6 +2848,9 @@ "src/components/onboarding_link.tsx": { "local/filename-pascal-case": { "count": 1 + }, + "no-restricted-imports": { + "count": 2 } }, "src/components/organisms/RegenerateKeyModal.tsx": { diff --git a/ui/litellm-dashboard/src/components/onboarding_link.test.tsx b/ui/litellm-dashboard/src/components/onboarding_link.test.tsx index a7d5a2cd4f6..039d5e250da 100644 --- a/ui/litellm-dashboard/src/components/onboarding_link.test.tsx +++ b/ui/litellm-dashboard/src/components/onboarding_link.test.tsx @@ -1,22 +1,5 @@ -import { describe, it, expect, vi } from "vitest"; -import { render, screen } from "@testing-library/react"; -import userEvent from "@testing-library/user-event"; -import OnboardingModal, { buildOnboardingUrl, InvitationLink } from "./onboarding_link"; - -vi.mock("./molecules/notifications_manager", () => ({ default: { success: vi.fn() } })); - -const invitation: InvitationLink = { - id: "inv-123", - user_id: "user-abc", - is_accepted: false, - accepted_at: null, - expires_at: new Date("2026-09-01"), - created_at: new Date("2026-08-01"), - created_by: "admin", - updated_at: new Date("2026-08-01"), - updated_by: "admin", - has_user_setup_sso: false, -}; +import { describe, it, expect } from "vitest"; +import { buildOnboardingUrl } from "./onboarding_link"; describe("buildOnboardingUrl", () => { it("points the invitation link at the dedicated /ui/onboarding route", () => { @@ -85,73 +68,3 @@ describe("buildOnboardingUrl", () => { ).toBe(""); }); }); - -describe("OnboardingModal", () => { - it("renders nothing until it is opened", () => { - render( - , - ); - - expect(screen.queryByText("http://localhost:4000/ui/onboarding?invitation_id=inv-123")).not.toBeInTheDocument(); - }); - - it("shows the invitation url, the user id and an invitation-flavoured copy button", async () => { - render( - , - ); - - expect(await screen.findByText("http://localhost:4000/ui/onboarding?invitation_id=inv-123")).toBeInTheDocument(); - expect(screen.getByText("user-abc")).toBeInTheDocument(); - expect(screen.getAllByText("Invitation Link").length).toBeGreaterThan(0); - expect(screen.getByRole("button", { name: "Copy invitation link" })).toBeInTheDocument(); - expect(screen.getByText(/Copy and send the generated link to onboard this user/)).toBeInTheDocument(); - }); - - it("switches every label and the url to the reset-password flow", async () => { - render( - , - ); - - expect( - await screen.findByText("http://localhost:4000/ui/onboarding?invitation_id=inv-123&action=reset_password"), - ).toBeInTheDocument(); - expect(screen.getAllByText("Reset Password Link").length).toBeGreaterThan(0); - expect(screen.getByRole("button", { name: "Copy password reset link" })).toBeInTheDocument(); - expect( - screen.getByText(/Copy and send the generated link to the user to reset their password/), - ).toBeInTheDocument(); - }); - - it("closes through setIsInvitationLinkModalVisible when the close control is used", async () => { - const user = userEvent.setup(); - const setVisible = vi.fn(); - render( - , - ); - - await user.click(await screen.findByRole("button", { name: /close/i })); - - expect(setVisible).toHaveBeenCalledWith(false); - }); -}); diff --git a/ui/litellm-dashboard/src/components/onboarding_link.tsx b/ui/litellm-dashboard/src/components/onboarding_link.tsx index f24e3709794..b5f3c6d3e17 100644 --- a/ui/litellm-dashboard/src/components/onboarding_link.tsx +++ b/ui/litellm-dashboard/src/components/onboarding_link.tsx @@ -1,7 +1,7 @@ import React from "react"; +import { Button, Modal, Typography } from "antd"; import { CopyToClipboard } from "react-copy-to-clipboard"; -import { Button } from "@/components/ui/button"; -import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog"; +import { Text } from "@tremor/react"; import NotificationsManager from "./molecules/notifications_manager"; export interface InvitationLink { @@ -58,7 +58,10 @@ export default function OnboardingModal({ invitationLinkData, modalType = "invitation", }: OnboardingProps) { - const linkLabel = modalType === "invitation" ? "Invitation Link" : "Reset Password Link"; + const { Paragraph } = Typography; + const handleInvitationOk = () => { + setIsInvitationLinkModalVisible(false); + }; const handleInvitationCancel = () => { setIsInvitationLinkModalVisible(false); @@ -73,30 +76,36 @@ export default function OnboardingModal({ }); return ( - !open && handleInvitationCancel()}> - - - {linkLabel} - -

- {modalType === "invitation" - ? "Copy and send the generated link to onboard this user to the proxy." - : "Copy and send the generated link to the user to reset their password."} -

-
- User ID - {invitationLinkData?.user_id} -
-
- {linkLabel} - {getInvitationUrl()} -
-
- NotificationsManager.success("Copied!")}> - - -
-
-
+ + + {modalType === "invitation" + ? "Copy and send the generated link to onboard this user to the proxy." + : "Copy and send the generated link to the user to reset their password."} + +
+ User ID + {invitationLinkData?.user_id} +
+
+ {modalType === "invitation" ? "Invitation Link" : "Reset Password Link"} + + {getInvitationUrl()} + +
+
+ NotificationsManager.success("Copied!")}> + + +
+
); }