From 71cf7b9dd829122397fb3e6a2ea4f762c4568158 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Sat, 6 Dec 2025 16:57:13 -0800 Subject: [PATCH 1/2] Delete User Modal on Info Page --- .../src/components/entity_usage.test.tsx | 8 +-- .../view_logs/RequestResponsePanel.tsx | 8 ++- .../view_users/user_info_view.test.tsx | 25 ++++--- .../components/view_users/user_info_view.tsx | 72 ++++++++++--------- 4 files changed, 63 insertions(+), 50 deletions(-) diff --git a/ui/litellm-dashboard/src/components/entity_usage.test.tsx b/ui/litellm-dashboard/src/components/entity_usage.test.tsx index 2c070427ea..2b6234c039 100644 --- a/ui/litellm-dashboard/src/components/entity_usage.test.tsx +++ b/ui/litellm-dashboard/src/components/entity_usage.test.tsx @@ -245,9 +245,9 @@ describe("EntityUsage", () => { expect(mockTagDailyActivityCall).toHaveBeenCalled(); }); - await waitFor(() => { - expect(screen.getByText("$0.00")).toBeInTheDocument(); - expect(screen.getByText("Total Spend")).toBeInTheDocument(); - }); + expect(await screen.findByText("Tag Spend Overview")).toBeInTheDocument(); + expect(await screen.findByText("$-")).toBeInTheDocument(); + expect(screen.getByText("Total Spend")).toBeInTheDocument(); + expect(screen.getAllByText("0")[0]).toBeInTheDocument(); }); }); diff --git a/ui/litellm-dashboard/src/components/view_logs/RequestResponsePanel.tsx b/ui/litellm-dashboard/src/components/view_logs/RequestResponsePanel.tsx index 97a9272f1e..7e9901d8bd 100644 --- a/ui/litellm-dashboard/src/components/view_logs/RequestResponsePanel.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/RequestResponsePanel.tsx @@ -96,7 +96,9 @@ export function RequestResponsePanel({
- +
+ +
@@ -131,7 +133,9 @@ export function RequestResponsePanel({
{hasResponse ? ( - +
+ +
) : (
Response data not available
)} diff --git a/ui/litellm-dashboard/src/components/view_users/user_info_view.test.tsx b/ui/litellm-dashboard/src/components/view_users/user_info_view.test.tsx index 8d5927124a..3dd814143e 100644 --- a/ui/litellm-dashboard/src/components/view_users/user_info_view.test.tsx +++ b/ui/litellm-dashboard/src/components/view_users/user_info_view.test.tsx @@ -1,4 +1,4 @@ -import { render } from "@testing-library/react"; +import { render, screen } from "@testing-library/react"; import { describe, expect, it, vi } from "vitest"; import UserInfoView from "./user_info_view"; @@ -41,19 +41,24 @@ describe("UserInfoView", () => { possibleUIRoles: null, }; - it("should render the loading state and then the user email", async () => { - const { getByText, findAllByText } = render(); + it("should render the loading state", () => { + render(); - expect(getByText("Loading user data...")).toBeInTheDocument(); - - const emails = await findAllByText("test@example.com"); - expect(emails.length).toBeGreaterThan(0); + expect(screen.getByText("Loading user data...")).toBeInTheDocument(); }); - it("should render the user alias", async () => { - const { findAllByText } = render(); + it("should render the user email after loading", async () => { + render(); - const aliases = await findAllByText("Test Alias"); + const emails = await screen.findAllByText("test@example.com"); + expect(emails.length).toBeGreaterThan(0); + expect(screen.queryByText("Loading user data...")).not.toBeInTheDocument(); + }); + + it("should render the user alias after loading", async () => { + render(); + + const aliases = await screen.findAllByText("Test Alias"); expect(aliases.length).toBeGreaterThan(0); }); }); diff --git a/ui/litellm-dashboard/src/components/view_users/user_info_view.tsx b/ui/litellm-dashboard/src/components/view_users/user_info_view.tsx index 2caae7d861..c377b9c4cd 100644 --- a/ui/litellm-dashboard/src/components/view_users/user_info_view.tsx +++ b/ui/litellm-dashboard/src/components/view_users/user_info_view.tsx @@ -17,6 +17,7 @@ import { formatNumberWithCommas, copyToClipboard as utilCopyToClipboard } from " import { CopyIcon, CheckIcon } from "lucide-react"; import NotificationsManager from "../molecules/notifications_manager"; import { getBudgetDurationLabel } from "../common_components/budget_duration_dropdown"; +import DeleteResourceModal from "../common_components/DeleteResourceModal"; interface UserInfoViewProps { userId: string; @@ -60,6 +61,7 @@ export default function UserInfoView({ }: UserInfoViewProps) { const [userData, setUserData] = useState(null); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [isDeletingUser, setIsDeletingUser] = useState(false); const [isLoading, setIsLoading] = useState(true); const [isEditing, setIsEditing] = useState(startInEditMode); const [userModels, setUserModels] = useState([]); @@ -115,6 +117,7 @@ export default function UserInfoView({ const handleDelete = async () => { try { if (!accessToken) return; + setIsDeletingUser(true); await userDeleteCall(accessToken, [userId]); NotificationsManager.success("User deleted successfully"); if (onDelete) { @@ -124,9 +127,16 @@ export default function UserInfoView({ } catch (error) { console.error("Error deleting user:", error); NotificationsManager.fromBackend("Failed to delete user"); + } finally { + setIsDeleteModalOpen(false); + setIsDeletingUser(false); } }; + const cancelDelete = () => { + setIsDeleteModalOpen(false); + }; + const handleUserUpdate = async (formValues: Record) => { try { if (!accessToken || !userData) return; @@ -219,7 +229,7 @@ export default function UserInfoView({ icon={TrashIcon} variant="secondary" onClick={() => setIsDeleteModalOpen(true)} - className="flex items-center" + className="flex items-center text-red-500 border-red-500 hover:text-red-600 hover:border-red-600" > Delete User @@ -227,39 +237,33 @@ export default function UserInfoView({ )}
- {/* Delete Confirmation Modal */} - {isDeleteModalOpen && ( -
-
- - - - -
-
-
-
-

Delete User

-
-

Are you sure you want to delete this user?

-
-
-
-
-
- - -
-
-
-
- )} + From 99d95457b69a7d35df0fd0e7aa33a311f0882f76 Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Sat, 6 Dec 2025 17:00:58 -0800 Subject: [PATCH 2/2] Fixing tests --- ui/litellm-dashboard/src/components/entity_usage.test.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/litellm-dashboard/src/components/entity_usage.test.tsx b/ui/litellm-dashboard/src/components/entity_usage.test.tsx index 2b6234c039..2c070427ea 100644 --- a/ui/litellm-dashboard/src/components/entity_usage.test.tsx +++ b/ui/litellm-dashboard/src/components/entity_usage.test.tsx @@ -245,9 +245,9 @@ describe("EntityUsage", () => { expect(mockTagDailyActivityCall).toHaveBeenCalled(); }); - expect(await screen.findByText("Tag Spend Overview")).toBeInTheDocument(); - expect(await screen.findByText("$-")).toBeInTheDocument(); - expect(screen.getByText("Total Spend")).toBeInTheDocument(); - expect(screen.getAllByText("0")[0]).toBeInTheDocument(); + await waitFor(() => { + expect(screen.getByText("$0.00")).toBeInTheDocument(); + expect(screen.getByText("Total Spend")).toBeInTheDocument(); + }); }); });