From 103830ee86081046704d010cc84ae9e686dd40f7 Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Wed, 19 Aug 2026 15:13:56 -0700 Subject: [PATCH] fix(ui): drop the error toast for a superseded user search --- .../create_key_button.integration.test.tsx | 58 +++++++++++++++++++ .../organisms/create_key_button.tsx | 2 +- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/ui/litellm-dashboard/src/components/organisms/create_key_button.integration.test.tsx b/ui/litellm-dashboard/src/components/organisms/create_key_button.integration.test.tsx index dbeaf7998e6..d0add6fb12a 100644 --- a/ui/litellm-dashboard/src/components/organisms/create_key_button.integration.test.tsx +++ b/ui/litellm-dashboard/src/components/organisms/create_key_button.integration.test.tsx @@ -3,6 +3,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { act, renderWithProviders, screen, testQueryClient, waitFor } from "../../../tests/test-utils"; import type { Team } from "../key_team_helpers/key_list"; import { keyCreateCall, keyCreateServiceAccountCall, modelAvailableCall, userFilterUICall } from "../networking"; +import { toast } from "@/lib/toast"; import CreateKey from "./create_key_button"; const state = vi.hoisted(() => ({ @@ -21,6 +22,16 @@ const state = vi.hoisted(() => ({ projects: [] as { project_id: string; project_alias: string; team_id?: string; models?: string[] }[], })); +vi.mock("@/lib/toast", () => ({ + toast: { + success: vi.fn(), + info: vi.fn(), + warning: vi.fn(), + error: vi.fn(), + fromError: vi.fn(), + dismiss: vi.fn(), + }, +})); vi.mock("@/app/(dashboard)/hooks/useAuthorized", () => ({ default: () => state.authorized })); vi.mock("@/app/(dashboard)/hooks/useCan", () => ({ default: (capability: string) => state.can[capability] ?? true, @@ -225,6 +236,7 @@ describe("CreateKey", () => { .mockClear() .mockResolvedValue({ key: "sk-service-account", soft_budget: null }); vi.mocked(userFilterUICall).mockClear().mockResolvedValue([]); + vi.mocked(toast.fromError).mockClear(); vi.mocked(modelAvailableCall) .mockClear() .mockResolvedValue({ data: [{ id: "gpt-4" }] }); @@ -895,6 +907,52 @@ describe("CreateKey", () => { }); await screen.findByTitle("alice.smith@example.com (u-smith)"); }); + + it("only warns about a failed search when it is the one the box is waiting on", async () => { + const answers = new Map< + string, + { resolve: (users: { user_id: string; user_email: string }[]) => void; reject: (error: Error) => void } + >(); + vi.mocked(userFilterUICall).mockImplementation( + (_accessToken, params) => + new Promise((resolve, reject) => { + answers.set(params.get("user_email") ?? "", { resolve, reject }); + }) as never, + ); + + const user = userEvent.setup(); + renderCreateKey({ autoOpenCreate: true, prefillData: { owned_by: "another_user" } }); + const search = antdSearchInput(await screen.findByText("Type email to search for users")); + + await user.type(search, "ali"); + await waitFor(() => expect(answers.has("ali")).toBe(true), { timeout: 3000 }); + + await user.type(search, "ce.smith@example.com"); + await waitFor(() => expect(answers.has("alice.smith@example.com")).toBe(true), { timeout: 3000 }); + + await act(async () => { + answers + .get("alice.smith@example.com") + ?.resolve([{ user_id: "u-smith", user_email: "alice.smith@example.com" }]); + }); + await screen.findByTitle("alice.smith@example.com (u-smith)"); + + await act(async () => { + answers.get("ali")?.reject(new Error("search failed")); + }); + + expect(toast.fromError).not.toHaveBeenCalled(); + expect(screen.getByTitle("alice.smith@example.com (u-smith)")).toBeInTheDocument(); + + await user.type(search, "x"); + await waitFor(() => expect(answers.has("alice.smith@example.comx")).toBe(true), { timeout: 3000 }); + + await act(async () => { + answers.get("alice.smith@example.comx")?.reject(new Error("search failed")); + }); + + expect(toast.fromError).toHaveBeenCalledTimes(1); + }); }); describe("created key display", () => { diff --git a/ui/litellm-dashboard/src/components/organisms/create_key_button.tsx b/ui/litellm-dashboard/src/components/organisms/create_key_button.tsx index b98cc4205bf..ea11a210470 100644 --- a/ui/litellm-dashboard/src/components/organisms/create_key_button.tsx +++ b/ui/litellm-dashboard/src/components/organisms/create_key_button.tsx @@ -587,7 +587,7 @@ const CreateKey: React.FC = ({ team, teams, data, addKey, autoOp setUserOptions(options); } catch (error) { console.error("Error fetching users:", error); - toast.fromError("Failed to search for users"); + if (isLatestSearch()) toast.fromError("Failed to search for users"); } finally { if (isLatestSearch()) setUserSearchLoading(false); }