From a4fecc74fbd73953c87ad0d058c921096c0aa2ea Mon Sep 17 00:00:00 2001 From: yuneng-jiang Date: Wed, 14 Jan 2026 15:47:50 -0800 Subject: [PATCH] Add search to key edit team dropdown --- .../templates/key_edit_view.test.tsx | 30 +++++++++++++++-- .../components/templates/key_edit_view.tsx | 32 ++++++++----------- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/ui/litellm-dashboard/src/components/templates/key_edit_view.test.tsx b/ui/litellm-dashboard/src/components/templates/key_edit_view.test.tsx index 85c6192693e..03e1085937d 100644 --- a/ui/litellm-dashboard/src/components/templates/key_edit_view.test.tsx +++ b/ui/litellm-dashboard/src/components/templates/key_edit_view.test.tsx @@ -1,8 +1,8 @@ -import { waitFor } from "@testing-library/react"; -import { renderWithProviders } from "../../../tests/test-utils"; +import { fireEvent, waitFor } from "@testing-library/react"; import { describe, expect, it, vi } from "vitest"; -import { KeyEditView } from "./key_edit_view"; +import { renderWithProviders } from "../../../tests/test-utils"; import { KeyResponse } from "../key_team_helpers/key_list"; +import { KeyEditView } from "./key_edit_view"; // Mock window.matchMedia Object.defineProperty(window, "matchMedia", { @@ -143,4 +143,28 @@ describe("KeyEditView", () => { expect(metadataTextarea).toHaveValue("{}"); }); }); + + it("should call onCancel when cancel button is clicked", async () => { + const onCancelMock = vi.fn(); + const { getByText } = renderWithProviders( + {}} + accessToken={""} + userID={""} + userRole={""} + premiumUser={false} + />, + ); + + await waitFor(() => { + expect(getByText("Cancel")).toBeInTheDocument(); + }); + + const cancelButton = getByText("Cancel"); + fireEvent.click(cancelButton); + + expect(onCancelMock).toHaveBeenCalledTimes(1); + }); }); diff --git a/ui/litellm-dashboard/src/components/templates/key_edit_view.tsx b/ui/litellm-dashboard/src/components/templates/key_edit_view.tsx index d655489abf1..836ebb385f1 100644 --- a/ui/litellm-dashboard/src/components/templates/key_edit_view.tsx +++ b/ui/litellm-dashboard/src/components/templates/key_edit_view.tsx @@ -1,7 +1,9 @@ import GuardrailSelector from "@/components/guardrails/GuardrailSelector"; +import { InfoCircleOutlined } from "@ant-design/icons"; import { TextInput, Button as TremorButton } from "@tremor/react"; import { Form, Input, Select, Switch, Tooltip } from "antd"; import { useEffect, useState } from "react"; +import AgentSelector from "../agent_management/AgentSelector"; import { mapInternalToDisplayNames } from "../callback_info_helpers"; import KeyLifecycleSettings from "../common_components/KeyLifecycleSettings"; import PassThroughRoutesSelector from "../common_components/PassThroughRoutesSelector"; @@ -10,15 +12,13 @@ import { extractLoggingSettings, formatMetadataForDisplay, stripTagsFromMetadata import { KeyResponse } from "../key_team_helpers/key_list"; import MCPServerSelector from "../mcp_server_management/MCPServerSelector"; import MCPToolPermissions from "../mcp_server_management/MCPToolPermissions"; -import AgentSelector from "../agent_management/AgentSelector"; import NotificationsManager from "../molecules/notifications_manager"; -import { fetchMCPAccessGroups, getPromptsList, modelAvailableCall, tagListCall } from "../networking"; +import { getPromptsList, modelAvailableCall, tagListCall } from "../networking"; import { fetchTeamModels } from "../organisms/create_key_button"; import NumericalInput from "../shared/numerical_input"; import { Tag } from "../tag_management/types"; import EditLoggingSettings from "../team/EditLoggingSettings"; import VectorStoreSelector from "../vector_store_management/VectorStoreSelector"; -import { InfoCircleOutlined } from "@ant-design/icons"; interface KeyEditViewProps { keyData: KeyResponse; @@ -82,13 +82,10 @@ export function KeyEditView({ premiumUser = false, }: KeyEditViewProps) { const [form] = Form.useForm(); - const [userModels, setUserModels] = useState([]); const [promptsList, setPromptsList] = useState([]); const [tagsList, setTagsList] = useState>({}); const team = teams?.find((team) => team.team_id === keyData.team_id); const [availableModels, setAvailableModels] = useState([]); - const [mcpAccessGroups, setMcpAccessGroups] = useState([]); - const [mcpAccessGroupsLoaded, setMcpAccessGroupsLoaded] = useState(false); const [disabledCallbacks, setDisabledCallbacks] = useState( Array.isArray(keyData.metadata?.litellm_disabled_callbacks) ? mapInternalToDisplayNames(keyData.metadata.litellm_disabled_callbacks) @@ -98,18 +95,6 @@ export function KeyEditView({ const [rotationInterval, setRotationInterval] = useState(keyData.rotation_interval || ""); const [isKeySaving, setIsKeySaving] = useState(false); - const fetchMcpAccessGroups = async () => { - if (!accessToken) return; - if (mcpAccessGroupsLoaded) return; - try { - const groups = await fetchMCPAccessGroups(accessToken); - setMcpAccessGroups(groups); - setMcpAccessGroupsLoaded(true); - } catch (error) { - console.error("Failed to fetch MCP access groups:", error); - } - }; - useEffect(() => { const fetchModels = async () => { if (!userID || !userRole || !accessToken) return; @@ -526,7 +511,16 @@ export function KeyEditView({ - { + const team = teams?.find((t) => t.team_id === option?.value); + if (!team) return false; + return team.team_alias?.toLowerCase().includes(input.toLowerCase()) ?? false; + }} + > {/* Only show All Team Models if team has models */} {teams?.map((team) => (