From ce5c4c1bf914189cda1fb73ebf8ae4118de0a6a5 Mon Sep 17 00:00:00 2001 From: Yuneng Jiang Date: Wed, 5 Aug 2026 18:07:17 -0700 Subject: [PATCH] refactor(ui): drop dead locals and unused React state across the dashboard Removes declarations nothing reads, along with the writes that fed them, so the remaining code says what it actually does. Where a declaration was dead but its initializer had a real effect, the call survives and only the binding goes: spies stay installed, renders still run, and every awaited request keeps its await. Pure computations are deleted whole rather than left as statements that build a value and throw it away. Dead useState pairs are removed outright instead of being elided to const [, setX], which would keep a hook and every write to a value nothing reads. Three chains turned out to be dead end to end and are removed with their fetches: the tool detail team list, the Teams MCP access group load, and the user dashboard proxy settings load. ColumnMeta's declaration merging in columnMeta.ts and view_logs/table.tsx is a false positive; TypeScript requires those type parameters to match the upstream signature exactly, so both get a scoped suppression instead. --- ui/litellm-dashboard/eslint-suppressions.json | 14 +-- .../agents/_components/add_agent_form.tsx | 6 +- .../caching/_components/cache_health.tsx | 3 - .../_components/add_guardrail_form.tsx | 115 +----------------- .../(dashboard)/hooks/teams/useTeams.test.ts | 3 - .../(dashboard)/hooks/useAuthorized.test.ts | 2 +- .../policies/_components/add_policy_form.tsx | 5 - .../policies/_components/policy_info.tsx | 4 - .../VersionHistorySidePanel.test.tsx | 4 +- .../UsageViewSelect/UsageViewSelect.test.tsx | 9 +- .../AIHub/UsefulLinksManagement.tsx | 4 - .../EntityUsageExport/utils.test.ts | 8 +- .../Modals/EditSSOSettingsModal.test.tsx | 2 +- ui/litellm-dashboard/src/components/Teams.tsx | 92 +------------- .../src/components/ToolDetail.tsx | 27 ---- .../add_model/handle_add_model_submit.tsx | 2 +- .../add_model/model_connection_test.tsx | 5 +- .../edit_auto_router_modal.tsx | 13 -- .../components/llm_calls/chat_completion.tsx | 6 - .../organisms/create_key_button.tsx | 29 ----- .../organization/organization_view.tsx | 4 +- .../src/components/per_user_usage.tsx | 4 - .../src/components/price_data_reload.tsx | 8 -- .../components/shared/DataTable/columnMeta.ts | 1 + .../components/team/LoggingSettings.test.tsx | 2 - .../src/components/team/TeamInfo.tsx | 45 +------ .../KeyInfoView.handleKeyUpdate.test.tsx | 12 +- .../templates/key_edit_view.test.tsx | 4 +- .../components/templates/key_info_view.tsx | 6 +- .../src/components/user_dashboard.tsx | 52 +------- .../SimpleToolCallBlock.test.tsx | 2 +- .../src/components/view_logs/table.tsx | 1 + 32 files changed, 39 insertions(+), 455 deletions(-) diff --git a/ui/litellm-dashboard/eslint-suppressions.json b/ui/litellm-dashboard/eslint-suppressions.json index 50b652ff57e..e5d17d49a33 100644 --- a/ui/litellm-dashboard/eslint-suppressions.json +++ b/ui/litellm-dashboard/eslint-suppressions.json @@ -42,9 +42,6 @@ }, "react-hooks/set-state-in-effect": { "count": 2 - }, - "unused-imports/no-unused-imports": { - "count": 1 } }, "src/app/(dashboard)/agents/_components/agent_card_discovery.tsx": { @@ -2440,7 +2437,7 @@ "count": 2 }, "react-hooks/set-state-in-effect": { - "count": 3 + "count": 1 } }, "src/components/TeamsPage/teamTableColumns.tsx": { @@ -2448,11 +2445,6 @@ "count": 1 } }, - "src/components/ToolDetail.tsx": { - "unused-imports/no-unused-imports": { - "count": 1 - } - }, "src/components/UIAccessControlForm.tsx": { "no-restricted-imports": { "count": 2 @@ -3383,7 +3375,7 @@ "count": 2 }, "prefer-const": { - "count": 4 + "count": 2 }, "react-hooks/set-state-in-effect": { "count": 4 @@ -4005,7 +3997,7 @@ "count": 1 }, "react-hooks/set-state-in-effect": { - "count": 2 + "count": 1 } }, "src/components/vector_store_management/VectorStoreSelector.test.tsx": { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/agents/_components/add_agent_form.tsx b/ui/litellm-dashboard/src/app/(dashboard)/agents/_components/add_agent_form.tsx index e35388b78da..677ba9e6285 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/agents/_components/add_agent_form.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/agents/_components/add_agent_form.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from "react"; -import { Modal, Form, Select, Input, Steps, Radio, Tag, Divider, Switch, InputNumber, Collapse } from "antd"; +import { Modal, Form, Select, Input, Steps, Radio, Tag, Divider, Switch, InputNumber } from "antd"; import MessageManager from "@/components/molecules/message_manager"; import { Logo } from "@/components/molecules/logo/Logo"; import { Button } from "@tremor/react"; @@ -47,7 +47,6 @@ const AddAgentForm: React.FC = ({ visible, onClose, accessTok const [isSubmitting, setIsSubmitting] = useState(false); const [agentType, setAgentType] = useState("a2a"); const [agentTypeMetadata, setAgentTypeMetadata] = useState([]); - const [loadingMetadata, setLoadingMetadata] = useState(false); // Step 3: key assignment state const [keyAssignOption, setKeyAssignOption] = useState<"create_new" | "existing_key" | "skip">("create_new"); @@ -82,14 +81,11 @@ const AddAgentForm: React.FC = ({ visible, onClose, accessTok // Fetch agent type metadata on mount useEffect(() => { const fetchMetadata = async () => { - setLoadingMetadata(true); try { const metadata = await getAgentCreateMetadata(); setAgentTypeMetadata(metadata); } catch (error) { console.error("Error fetching agent metadata:", error); - } finally { - setLoadingMetadata(false); } }; fetchMetadata(); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/caching/_components/cache_health.tsx b/ui/litellm-dashboard/src/app/(dashboard)/caching/_components/cache_health.tsx index 85649c1cf26..0f52bed874d 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/caching/_components/cache_health.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/caching/_components/cache_health.tsx @@ -20,14 +20,11 @@ const deepParse = (input: any) => { // TableClickableErrorField component with copy-to-clipboard functionality const TableClickableErrorField: React.FC<{ label: string; value: string | null | undefined }> = ({ label, value }) => { const [isExpanded, setIsExpanded] = React.useState(false); - const [copied, setCopied] = React.useState(false); const safeValue = value?.toString() || "N/A"; const truncated = safeValue.length > 50 ? safeValue.substring(0, 50) + "..." : safeValue; const handleCopy = () => { navigator.clipboard.writeText(safeValue); - setCopied(true); - setTimeout(() => setCopied(false), 2000); }; return ( diff --git a/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/add_guardrail_form.tsx b/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/add_guardrail_form.tsx index 251ce631beb..5f15eaceb28 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/add_guardrail_form.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/guardrails/_components/add_guardrail_form.tsx @@ -1,4 +1,4 @@ -import { Form, Input, Modal, Select, Tag, Typography, Button } from "antd"; +import { Form, Input, Modal, Select, Tag, Button } from "antd"; import React, { useEffect, useMemo, useState } from "react"; import NotificationsManager from "@/components/molecules/notifications_manager"; import { @@ -30,7 +30,6 @@ import LLMJudgeFields from "./llm_judge/LLMJudgeFields"; import PiiConfiguration from "./pii_configuration"; import ToolPermissionRulesEditor, { ToolPermissionConfig } from "./tool_permission/ToolPermissionRulesEditor"; -const { Title, Text, Link } = Typography; const { Option } = Select; // Define human-friendly descriptions for each mode @@ -163,11 +162,6 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a const [currentStep, setCurrentStep] = useState(0); const [providerParams, setProviderParams] = useState(null); - // Azure Text Moderation state - const [selectedCategories, setSelectedCategories] = useState([]); - const [globalSeverityThreshold, setGlobalSeverityThreshold] = useState(2); - const [categorySpecificThresholds, setCategorySpecificThresholds] = useState<{ [key: string]: number }>({}); - // Content Filter state const [selectedPatterns, setSelectedPatterns] = useState([]); const [blockedWords, setBlockedWords] = useState([]); @@ -297,11 +291,6 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a setSelectedEntities([]); setSelectedActions({}); - // Reset Azure Text Moderation selections when changing provider - setSelectedCategories([]); - setGlobalSeverityThreshold(2); - setCategorySpecificThresholds({}); - // Reset Content Filter selections setSelectedPatterns([]); setBlockedWords([]); @@ -335,24 +324,6 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a })); }; - // Azure Text Moderation handlers - const handleCategorySelect = (category: string) => { - setSelectedCategories((prev) => - prev.includes(category) ? prev.filter((c) => c !== category) : [...prev, category], - ); - }; - - const handleGlobalSeverityChange = (threshold: number) => { - setGlobalSeverityThreshold(threshold); - }; - - const handleCategorySeverityChange = (category: string, threshold: number) => { - setCategorySpecificThresholds((prev) => ({ - ...prev, - [category]: threshold, - })); - }; - const nextStep = async () => { try { // Validate current step fields @@ -388,53 +359,11 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a setCurrentStep(currentStep - 1); }; - const handleAddAndContinue = (competitorIntentOnly?: boolean) => { - // Competitor intent only: just advance to next step (no category to add) - if (competitorIntentOnly) { - setCurrentStep(currentStep + 1); - return; - } - - if (!pendingCategorySelection || !guardrailSettings) return; - - const contentFilterSettings = guardrailSettings.content_filter_settings; - if (!contentFilterSettings) return; - - const category = contentFilterSettings.content_categories?.find((c) => c.name === pendingCategorySelection); - if (!category) return; - - // Check if already added - if (selectedContentCategories.some((c) => c.category === pendingCategorySelection)) { - setPendingCategorySelection(""); - setCurrentStep(currentStep + 1); - return; - } - - // Add the category - setSelectedContentCategories([ - ...selectedContentCategories, - { - id: `category-${Date.now()}`, - category: category.name, - display_name: category.display_name, - action: category.default_action as "BLOCK" | "MASK", - severity_threshold: "medium", - }, - ]); - - // Clear pending selection and advance to next step - setPendingCategorySelection(""); - setCurrentStep(currentStep + 1); - }; - const resetForm = () => { form.resetFields(); setSelectedProvider(null); setSelectedEntities([]); setSelectedActions({}); - setSelectedCategories([]); - setGlobalSeverityThreshold(2); - setCategorySpecificThresholds({}); setSelectedPatterns([]); setBlockedWords([]); setSelectedContentCategories([]); @@ -965,48 +894,6 @@ const AddGuardrailForm: React.FC = ({ visible, onClose, a } }; - const renderStepButtons = () => { - const totalSteps = shouldRenderContentFilterConfigSettings(selectedProvider) ? 5 : 2; - const isLastStep = currentStep === totalSteps - 1; - const isCategoriesStep = shouldRenderContentFilterConfigSettings(selectedProvider) && currentStep === 1; - const hasPendingCategory = pendingCategorySelection !== ""; - const hasCompetitorIntentConfigured = - competitorIntentEnabled && (competitorIntentConfig?.brand_self?.length ?? 0) > 0; - const canContinueFromCategoriesStep = hasPendingCategory || hasCompetitorIntentConfigured; - - return ( -
- {currentStep > 0 && } - {isCategoriesStep ? ( - <> - - - - ) : ( - <> - {!isLastStep && ( - - )} - {isLastStep && ( - - )} - - )} - -
- ); - }; - const renderEndpointSettings = () => { return (
diff --git a/ui/litellm-dashboard/src/app/(dashboard)/hooks/teams/useTeams.test.ts b/ui/litellm-dashboard/src/app/(dashboard)/hooks/teams/useTeams.test.ts index 28320b76597..66dfc43cebb 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/hooks/teams/useTeams.test.ts +++ b/ui/litellm-dashboard/src/app/(dashboard)/hooks/teams/useTeams.test.ts @@ -436,9 +436,6 @@ describe("useTeam", () => { showSSOBanner: false, }); - // Import useQueryClient to get access to query client - const { useQueryClient } = await import("@tanstack/react-query"); - // Manually test the queryFn logic by calling it directly // This simulates what would happen if enabled check was bypassed const testQueryFn = async () => { diff --git a/ui/litellm-dashboard/src/app/(dashboard)/hooks/useAuthorized.test.ts b/ui/litellm-dashboard/src/app/(dashboard)/hooks/useAuthorized.test.ts index bb14f6c3d21..1ca0581a391 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/hooks/useAuthorized.test.ts +++ b/ui/litellm-dashboard/src/app/(dashboard)/hooks/useAuthorized.test.ts @@ -305,7 +305,7 @@ describe("useAuthorized", () => { const token = createJwt(decodedPayload); document.cookie = `token=${token}; path=/;`; - const { result } = renderHook(() => useAuthorized(), { wrapper }); + renderHook(() => useAuthorized(), { wrapper }); await waitFor(() => { expect(clearTokenCookiesMock).toHaveBeenCalled(); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/add_policy_form.tsx b/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/add_policy_form.tsx index 8da2d3af36f..74e8bd3c6d9 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/add_policy_form.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/add_policy_form.tsx @@ -8,7 +8,6 @@ import NotificationsManager from "@/components/molecules/notifications_manager"; import useAuthorized from "@/app/(dashboard)/hooks/useAuthorized"; const { Text } = Typography; -const { Option } = Select; interface AddPolicyFormProps { visible: boolean; @@ -162,7 +161,6 @@ const AddPolicyForm: React.FC = ({ const [form] = Form.useForm(); const [isSubmitting, setIsSubmitting] = useState(false); const [resolvedGuardrails, setResolvedGuardrails] = useState([]); - const [isLoadingResolved, setIsLoadingResolved] = useState(false); const [modelConditionType, setModelConditionType] = useState<"model" | "regex">("model"); const [availableModels, setAvailableModels] = useState([]); const [step, setStep] = useState<"pick_mode" | "simple_form">("pick_mode"); @@ -231,14 +229,11 @@ const AddPolicyForm: React.FC = ({ const loadResolvedGuardrails = async (policyId: string) => { if (!accessToken) return; - setIsLoadingResolved(true); try { const data = await getResolvedGuardrails(accessToken, policyId); setResolvedGuardrails(data.resolved_guardrails || []); } catch (error) { console.error("Failed to load resolved guardrails:", error); - } finally { - setIsLoadingResolved(false); } }; diff --git a/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/policy_info.tsx b/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/policy_info.tsx index c49093f3238..0a5c7ef1186 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/policy_info.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/policies/_components/policy_info.tsx @@ -53,7 +53,6 @@ const PolicyInfoView: React.FC = ({ const [policy, setPolicy] = useState(null); const [isLoading, setIsLoading] = useState(true); const [resolvedGuardrails, setResolvedGuardrails] = useState([]); - const [isLoadingResolved, setIsLoadingResolved] = useState(false); const fetchPolicy = useCallback(async () => { if (!accessToken || !policyId) return; @@ -64,14 +63,11 @@ const PolicyInfoView: React.FC = ({ setPolicy(data); // Also fetch resolved guardrails - setIsLoadingResolved(true); try { const resolvedData = await getResolvedGuardrails(accessToken, policyId); setResolvedGuardrails(resolvedData.resolved_guardrails || []); } catch (error) { console.error("Error fetching resolved guardrails:", error); - } finally { - setIsLoadingResolved(false); } } catch (error) { console.error("Error fetching policy:", error); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/prompts/_components/prompt_editor_view/VersionHistorySidePanel.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/prompts/_components/prompt_editor_view/VersionHistorySidePanel.test.tsx index c76c64b89a6..97f671b1b71 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/prompts/_components/prompt_editor_view/VersionHistorySidePanel.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/prompts/_components/prompt_editor_view/VersionHistorySidePanel.test.tsx @@ -182,7 +182,7 @@ describe("VersionHistorySidePanel", () => { render(); await waitFor(() => { - const versionItems = screen.getAllByTestId("tag"); + screen.getAllByTestId("tag"); // Should have Active tag for the selected version expect(screen.getByText("Active")).toBeInTheDocument(); }); @@ -464,7 +464,7 @@ describe("VersionHistorySidePanel", () => { render(); await waitFor(() => { - const versionElements = screen.getAllByTestId("tag"); + screen.getAllByTestId("tag"); // Verify versions are displayed as they come from the API expect(screen.getByText("v2")).toBeInTheDocument(); }); diff --git a/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/UsageViewSelect/UsageViewSelect.test.tsx b/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/UsageViewSelect/UsageViewSelect.test.tsx index b33129fcdb4..aa9ff921ee1 100644 --- a/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/UsageViewSelect/UsageViewSelect.test.tsx +++ b/ui/litellm-dashboard/src/app/(dashboard)/usage/_components/components/UsageViewSelect/UsageViewSelect.test.tsx @@ -7,13 +7,10 @@ vi.mock("antd", async () => { function Select(props: any) { const { value, onChange, options, optionRender, labelRender, ...rest } = props; - const selectedOption = options?.find((opt: any) => opt.value === value); - const renderedLabel = labelRender ? labelRender({ value, label: selectedOption?.label }) : selectedOption?.label; - const optionElements = options?.map((opt: any) => { - const rendered = optionRender ? optionRender({ value: opt.value, label: opt.label }) : opt.label; - return React.createElement("option", { key: opt.value, value: opt.value }, opt.label); - }); + const optionElements = options?.map((opt: any) => + React.createElement("option", { key: opt.value, value: opt.value }, opt.label), + ); const optionRenderOutputs = options ?.map((opt: any) => { diff --git a/ui/litellm-dashboard/src/components/AIHub/UsefulLinksManagement.tsx b/ui/litellm-dashboard/src/components/AIHub/UsefulLinksManagement.tsx index 42acfd94185..f29504fac50 100644 --- a/ui/litellm-dashboard/src/components/AIHub/UsefulLinksManagement.tsx +++ b/ui/litellm-dashboard/src/components/AIHub/UsefulLinksManagement.tsx @@ -23,7 +23,6 @@ const UsefulLinksManagement: React.FC = ({ accessTok const [links, setLinks] = useState([]); const [newLink, setNewLink] = useState({ url: "", displayName: "" }); const [editingLink, setEditingLink] = useState(null); - const [loading, setLoading] = useState(false); const [isExpanded, setIsExpanded] = useState(true); const [isRearranging, setIsRearranging] = useState(false); const [originalLinksOrder, setOriginalLinksOrder] = useState([]); @@ -32,7 +31,6 @@ const UsefulLinksManagement: React.FC = ({ accessTok if (!accessToken) return; try { - setLoading(true); const response = await getPublicModelHubInfo(); if (response && response.useful_links) { @@ -73,8 +71,6 @@ const UsefulLinksManagement: React.FC = ({ accessTok } catch (error) { console.error("Error fetching useful links:", error); setLinks([]); - } finally { - setLoading(false); } }; diff --git a/ui/litellm-dashboard/src/components/EntityUsageExport/utils.test.ts b/ui/litellm-dashboard/src/components/EntityUsageExport/utils.test.ts index dfeecdc4fa6..e91b7b73a1e 100644 --- a/ui/litellm-dashboard/src/components/EntityUsageExport/utils.test.ts +++ b/ui/litellm-dashboard/src/components/EntityUsageExport/utils.test.ts @@ -1876,7 +1876,7 @@ describe("EntityUsageExport utils", () => { it("should create CSV file and trigger download", () => { const createObjectURLSpy = vi.spyOn(window.URL, "createObjectURL").mockReturnValue("blob:mock-url"); - const revokeObjectURLSpy = vi.spyOn(window.URL, "revokeObjectURL"); + vi.spyOn(window.URL, "revokeObjectURL"); const createElementSpy = vi.spyOn(document, "createElement"); const appendChildSpy = vi.spyOn(document.body, "appendChild"); const removeChildSpy = vi.spyOn(document.body, "removeChild"); @@ -1892,7 +1892,7 @@ describe("EntityUsageExport utils", () => { it("should generate correct filename", () => { const anchorElement = document.createElement("a"); - const createElementSpy = vi.spyOn(document, "createElement").mockReturnValue(anchorElement); + vi.spyOn(document, "createElement").mockReturnValue(anchorElement); const today = new Date().toISOString().split("T")[0]; @@ -1935,7 +1935,7 @@ describe("EntityUsageExport utils", () => { it("should create JSON file and trigger download", () => { const createObjectURLSpy = vi.spyOn(window.URL, "createObjectURL").mockReturnValue("blob:mock-url"); - const revokeObjectURLSpy = vi.spyOn(window.URL, "revokeObjectURL"); + vi.spyOn(window.URL, "revokeObjectURL"); const createElementSpy = vi.spyOn(document, "createElement"); const appendChildSpy = vi.spyOn(document.body, "appendChild"); const removeChildSpy = vi.spyOn(document.body, "removeChild"); @@ -1955,7 +1955,7 @@ describe("EntityUsageExport utils", () => { it("should generate correct filename", () => { const anchorElement = document.createElement("a"); - const createElementSpy = vi.spyOn(document, "createElement").mockReturnValue(anchorElement); + vi.spyOn(document, "createElement").mockReturnValue(anchorElement); const today = new Date().toISOString().split("T")[0]; const mockDateRange: DateRangePickerValue = { diff --git a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/Modals/EditSSOSettingsModal.test.tsx b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/Modals/EditSSOSettingsModal.test.tsx index 7415683af83..7536286b404 100644 --- a/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/Modals/EditSSOSettingsModal.test.tsx +++ b/ui/litellm-dashboard/src/components/Settings/AdminSettings/SSOSettings/Modals/EditSSOSettingsModal.test.tsx @@ -320,7 +320,7 @@ describe("EditSSOSettingsModal", () => { useEditSSOSettings: { mutateAsync: mockMutateAsync, isPending: false }, }); - const { mockOnSuccess } = renderComponent(); + renderComponent(); fireEvent.click(screen.getByTestId(TEST_IDS.TRIGGER_FORM_SUBMIT)); diff --git a/ui/litellm-dashboard/src/components/Teams.tsx b/ui/litellm-dashboard/src/components/Teams.tsx index edf376cb8d4..95642b93019 100644 --- a/ui/litellm-dashboard/src/components/Teams.tsx +++ b/ui/litellm-dashboard/src/components/Teams.tsx @@ -22,16 +22,13 @@ import AgentSelector from "./agent_management/AgentSelector"; import ModelAliasManager from "./common_components/ModelAliasManager"; import PremiumLoggingSettings from "./common_components/PremiumLoggingSettings"; import RouterSettingsAccordion, { RouterSettingsAccordionValue } from "./common_components/RouterSettingsAccordion"; -import { - fetchAvailableModelsForTeamOrKey, - unfurlWildcardModelsInList, -} from "./key_team_helpers/fetch_available_models_team_key"; +import { fetchAvailableModelsForTeamOrKey } from "./key_team_helpers/fetch_available_models_team_key"; import type { Team } from "./key_team_helpers/key_list"; import MCPServerSelector from "./mcp_server_management/MCPServerSelector"; import MCPToolPermissions from "./mcp_server_management/MCPToolPermissions"; import NotificationsManager from "./molecules/notifications_manager"; import { extractProxyErrorMessage } from "@/lib/http/client"; -import { Organization, fetchMCPAccessGroups, getGuardrailsList, getPoliciesList, teamDeleteCall } from "./networking"; +import { Organization, getGuardrailsList, getPoliciesList, teamDeleteCall } from "./networking"; import NumericalInput from "./shared/numerical_input"; import VectorStoreSelector from "./vector_store_management/VectorStoreSelector"; import SearchToolSelector from "./search_tools/SearchToolSelector"; @@ -43,35 +40,10 @@ interface TeamProps { premiumUser?: boolean; } -interface EditTeamModalProps { - visible: boolean; - onCancel: () => void; - team: any; // Assuming TeamType is a type representing your team object - onSubmit: (data: FormData) => void; // Assuming FormData is the type of data to be submitted -} - import DeleteResourceModal from "./common_components/DeleteResourceModal"; import { teamCreateCall } from "./networking"; import { ModelSelect } from "./ModelSelect/ModelSelect"; -const getOrganizationModels = (organization: Organization | null, userModels: string[]) => { - let tempModelsToPick = []; - - if (organization) { - if (organization.models.length > 0) { - tempModelsToPick = organization.models; - } else { - // show all available models if the team has no models set - tempModelsToPick = userModels; - } - } else { - // no team set, show all available models - tempModelsToPick = userModels; - } - - return unfurlWildcardModelsInList(tempModelsToPick, userModels); -}; - const canCreateOrManageTeams = ( userRole: string | null, userID: string | null, @@ -112,18 +84,6 @@ const getAdminOrganizations = ( return []; }; -const getOrganizationAlias = ( - organizationId: string | null | undefined, - organizations: Organization[] | null | undefined, -): string => { - if (!organizationId || !organizations) { - return organizationId || "N/A"; - } - - const organization = organizations.find((org) => org.organization_id === organizationId); - return organization?.organization_alias || organizationId; -}; - // @deprecated const Teams: React.FC = ({ accessToken, userID, userRole, premiumUser = false }) => { const { data: organizationsData } = useOrganizations(); @@ -135,35 +95,25 @@ const Teams: React.FC = ({ accessToken, userID, userRole, premiumUser const [currentOrgForCreateTeam, setCurrentOrgForCreateTeam] = useState(null); const [form] = Form.useForm(); - const [memberForm] = Form.useForm(); - const [value, setValue] = useState(""); - const [editModalVisible, setEditModalVisible] = useState(false); const [selectedTeam, setSelectedTeam] = useState(null); const [selectedTeamId, setSelectedTeamId] = useQueryState("team", parseAsString.withOptions({ history: "push" })); const [editTeam, setEditTeam] = useState(false); const [isTeamModalVisible, setIsTeamModalVisible] = useState(false); - const [isAddMemberModalVisible, setIsAddMemberModalVisible] = useState(false); - const [isEditMemberModalVisible, setIsEditMemberModalVisible] = useState(false); const [userModels, setUserModels] = useState([]); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [teamToDelete, setTeamToDelete] = useState(null); - const [modelsToPick, setModelsToPick] = useState([]); const [isTeamDeleting, setIsTeamDeleting] = useState(false); // Add this state near the other useState declarations const [guardrailsList, setGuardrailsList] = useState([]); const [policiesList, setPoliciesList] = useState([]); const [loggingSettings, setLoggingSettings] = useState([]); - const [mcpAccessGroups, setMcpAccessGroups] = useState([]); - const [mcpAccessGroupsLoaded, setMcpAccessGroupsLoaded] = useState(false); const [modelAliases, setModelAliases] = useState<{ [key: string]: string }>({}); const [routerSettings, setRouterSettings] = useState(null); const [routerSettingsKey, setRouterSettingsKey] = useState(0); useEffect(() => { - const models = getOrganizationModels(currentOrgForCreateTeam, userModels); - setModelsToPick(models); form.setFieldValue("models", []); }, [currentOrgForCreateTeam, userModels]); @@ -220,22 +170,6 @@ const Teams: React.FC = ({ accessToken, userID, userRole, premiumUser fetchPolicies(); }, [accessToken]); - const fetchMcpAccessGroups = async () => { - try { - if (accessToken == null) { - return; - } - const groups = await fetchMCPAccessGroups(accessToken); - setMcpAccessGroups(groups); - } catch (error) { - console.error("Failed to fetch MCP access groups:", error); - } - }; - - useEffect(() => { - fetchMcpAccessGroups(); - }, [accessToken]); - const handleOk = () => { setIsTeamModalVisible(false); form.resetFields(); @@ -245,12 +179,6 @@ const Teams: React.FC = ({ accessToken, userID, userRole, premiumUser setRouterSettingsKey((prev) => prev + 1); }; - const handleMemberOk = () => { - setIsAddMemberModalVisible(false); - setIsEditMemberModalVisible(false); - memberForm.resetFields(); - }; - const handleCancel = () => { setIsTeamModalVisible(false); form.resetFields(); @@ -260,12 +188,6 @@ const Teams: React.FC = ({ accessToken, userID, userRole, premiumUser setRouterSettingsKey((prev) => prev + 1); }; - const handleMemberCancel = () => { - setIsAddMemberModalVisible(false); - setIsEditMemberModalVisible(false); - memberForm.resetFields(); - }; - const handleDelete = async (team: Team) => { // Set the team to delete and open the confirmation modal setTeamToDelete(team); @@ -749,15 +671,7 @@ const Teams: React.FC = ({ accessToken, userID, userRole, premiumUser /> - { - if (!mcpAccessGroupsLoaded) { - fetchMcpAccessGroups(); - setMcpAccessGroupsLoaded(true); - } - }} - > + Additional Settings diff --git a/ui/litellm-dashboard/src/components/ToolDetail.tsx b/ui/litellm-dashboard/src/components/ToolDetail.tsx index 06f14638141..d90689fc627 100644 --- a/ui/litellm-dashboard/src/components/ToolDetail.tsx +++ b/ui/litellm-dashboard/src/components/ToolDetail.tsx @@ -24,12 +24,9 @@ import { fetchToolPolicyOptions, getToolUsageLogs, keyListCall, - teamListCall, updateToolPolicy, - type ToolPolicyOption, type ToolPolicyOverrideRow, } from "@/components/networking"; -import type { Team } from "@/components/key_team_helpers/key_list"; interface ToolDetailProps { toolName: string; @@ -87,12 +84,6 @@ export function ToolDetail({ toolName, onBack, accessToken }: ToolDetailProps) { staleTime: 60_000, }); - const { data: teamsData } = useQuery({ - queryKey: ["teams-list-tool-detail"], - queryFn: () => teamListCall(accessToken!, null, null), - enabled: !!accessToken, - }); - const { data: keysData } = useQuery({ queryKey: ["keys-list-tool-detail"], queryFn: () => keyListCall(accessToken!, null, null, null, null, null, 1, 100), @@ -122,24 +113,6 @@ export function ToolDetail({ toolName, onBack, accessToken }: ToolDetailProps) { })); }, [logsData?.logs]); - const teams: Team[] = useMemo(() => { - const arr = Array.isArray(teamsData) ? teamsData : teamsData?.data ?? []; - return arr.map((t: { team_id?: string; id?: string; team_alias?: string }) => ({ - team_id: t.team_id ?? t.id ?? "", - team_alias: t.team_alias ?? t.team_id ?? "", - models: [], - max_budget: null, - budget_duration: null, - tpm_limit: null, - rpm_limit: null, - organization_id: "", - created_at: "", - keys: [], - members_with_roles: [], - spend: 0, - })); - }, [teamsData]); - const keys: KeyOption[] = useMemo(() => { const keysRes = keysData?.keys ?? keysData?.data ?? []; return keysRes.map((k: { token?: string; api_key?: string; key_hash?: string; key_alias?: string }) => ({ diff --git a/ui/litellm-dashboard/src/components/add_model/handle_add_model_submit.tsx b/ui/litellm-dashboard/src/components/add_model/handle_add_model_submit.tsx index 71590660765..908a4c498dc 100644 --- a/ui/litellm-dashboard/src/components/add_model/handle_add_model_submit.tsx +++ b/ui/litellm-dashboard/src/components/add_model/handle_add_model_submit.tsx @@ -197,7 +197,7 @@ export const handleAddModelSubmit = async (values: any, accessToken: string, for model_info: modelInfoObj, }; - const response: any = await modelCreateCall(accessToken, new_model); + await modelCreateCall(accessToken, new_model); } callback && callback(); diff --git a/ui/litellm-dashboard/src/components/add_model/model_connection_test.tsx b/ui/litellm-dashboard/src/components/add_model/model_connection_test.tsx index 5b284fd26f5..62bb5975478 100644 --- a/ui/litellm-dashboard/src/components/add_model/model_connection_test.tsx +++ b/ui/litellm-dashboard/src/components/add_model/model_connection_test.tsx @@ -24,7 +24,6 @@ const ModelConnectionTest: React.FC = ({ onTestComplete, }) => { const [error, setError] = React.useState(null); - const [rawRequest, setRawRequest] = React.useState(null); const [rawResponse, setRawResponse] = React.useState(null); const [isLoading, setIsLoading] = React.useState(true); const [isSuccess, setIsSuccess] = React.useState(false); @@ -34,7 +33,6 @@ const ModelConnectionTest: React.FC = ({ setIsLoading(true); setShowDetails(false); setError(null); - setRawRequest(null); setRawResponse(null); setIsSuccess(false); @@ -51,7 +49,7 @@ const ModelConnectionTest: React.FC = ({ return; } - const { litellmParamsObj, modelInfoObj, modelName: returnedModelName } = result[0]; + const { litellmParamsObj, modelInfoObj } = result[0]; const response = await testConnectionRequest(accessToken, litellmParamsObj, modelInfoObj, modelInfoObj?.mode); if (response.status === "success") { @@ -61,7 +59,6 @@ const ModelConnectionTest: React.FC = ({ } else { const errorMessage = response.result?.error || response.message || "Unknown error"; setError(errorMessage); - setRawRequest(litellmParamsObj); setRawResponse(response.result?.raw_request_typed_dict); setIsSuccess(false); } diff --git a/ui/litellm-dashboard/src/components/edit_auto_router/edit_auto_router_modal.tsx b/ui/litellm-dashboard/src/components/edit_auto_router/edit_auto_router_modal.tsx index f9005e099a5..cf1a5727948 100644 --- a/ui/litellm-dashboard/src/components/edit_auto_router/edit_auto_router_modal.tsx +++ b/ui/litellm-dashboard/src/components/edit_auto_router/edit_auto_router_modal.tsx @@ -158,8 +158,6 @@ const EditAutoRouterModal: React.FC = ({ const [loading, setLoading] = useState(false); const [modelAccessGroups, setModelAccessGroups] = useState([]); const [modelInfo, setModelInfo] = useState([]); - const [showCustomDefaultModel, setShowCustomDefaultModel] = useState(false); - const [showCustomEmbeddingModel, setShowCustomEmbeddingModel] = useState(false); const [showValidationErrors, setShowValidationErrors] = useState(false); const [routerConfig, setRouterConfig] = useState(null); const [customTechnicalKeywords, setCustomTechnicalKeywords] = useState([]); @@ -308,11 +306,6 @@ const EditAutoRouterModal: React.FC = ({ auto_router_embedding_model: modelData.litellm_params?.auto_router_embedding_model || "", model_access_group: modelData.model_info?.access_groups || [], }); - - // Check if using custom models - const allModelGroups = new Set(modelInfo.map((model) => model.model_group)); - setShowCustomDefaultModel(!allModelGroups.has(modelData.litellm_params?.auto_router_default_model)); - setShowCustomEmbeddingModel(!allModelGroups.has(modelData.litellm_params?.auto_router_embedding_model)); } catch (error) { console.error("Error parsing auto router config:", error); NotificationsManager.fromBackend("Error loading auto router configuration"); @@ -516,9 +509,6 @@ const EditAutoRouterModal: React.FC = ({ > { - setShowCustomDefaultModel(value === "custom"); - }} options={[...modelOptions, { value: "custom", label: "Enter custom model name" }]} showSearch={true} /> @@ -532,9 +522,6 @@ const EditAutoRouterModal: React.FC = ({ > { - setShowCustomEmbeddingModel(value === "custom"); - }} options={[...modelOptions, { value: "custom", label: "Enter custom model name" }]} showSearch={true} /> diff --git a/ui/litellm-dashboard/src/components/llm_calls/chat_completion.tsx b/ui/litellm-dashboard/src/components/llm_calls/chat_completion.tsx index c20d758fe91..549f309b4ea 100644 --- a/ui/litellm-dashboard/src/components/llm_calls/chat_completion.tsx +++ b/ui/litellm-dashboard/src/components/llm_calls/chat_completion.tsx @@ -73,10 +73,6 @@ export async function makeOpenAIChatCompletionRequest( let firstTokenReceived = false; let timeToFirstToken: number | undefined = undefined; - // For collecting complete response text - let fullResponseContent = ""; - let fullReasoningContent = ""; - // Track MCP metadata cumulatively across chunks let mcpMetadata: { mcp_list_tools?: any[]; @@ -167,7 +163,6 @@ export async function makeOpenAIChatCompletionRequest( if (chunk.choices[0]?.delta?.content) { const content = chunk.choices[0].delta.content; updateUI(content, chunk.model); - fullResponseContent += content; } // Process image generation if present @@ -181,7 +176,6 @@ export async function makeOpenAIChatCompletionRequest( if (onReasoningContent) { onReasoningContent(reasoningContent); } - fullReasoningContent += reasoningContent; } // Check for search results in provider_specific_fields 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 00f36f016b7..b167e44fe04 100644 --- a/ui/litellm-dashboard/src/components/organisms/create_key_button.tsx +++ b/ui/litellm-dashboard/src/components/organisms/create_key_button.tsx @@ -93,26 +93,6 @@ interface UserOption { user: User; } -const getPredefinedTags = (data: any[] | null) => { - let allTags = []; - - if (data) { - for (let key of data) { - if (key["metadata"] && key["metadata"]["tags"]) { - allTags.push(...key["metadata"]["tags"]); - } - } - } - - // Deduplicate using Set - const uniqueTags = Array.from(new Set(allTags)).map((tag) => ({ - value: tag, - label: tag, - })); - - return uniqueTags; -}; - export const fetchTeamModels = async ( userID: string, userRole: string, @@ -178,7 +158,6 @@ const CreateKey: React.FC = ({ team, teams, data, addKey, autoOp const [form] = Form.useForm(); const [isModalVisible, setIsModalVisible] = useState(false); const [apiKey, setApiKey] = useState(null); - const [softBudget, setSoftBudget] = useState(null); const [userModels, setUserModels] = useState([]); const [modelsToPick, setModelsToPick] = useState([]); const [keyOwner, setKeyOwner] = useState("you"); @@ -192,11 +171,9 @@ const CreateKey: React.FC = ({ team, teams, data, addKey, autoOp const [selectedOrganizationId, setSelectedOrganizationId] = useState(null); const [selectedProjectId, setSelectedProjectId] = useState(null); const [isCreateUserModalVisible, setIsCreateUserModalVisible] = useState(false); - const [newlyCreatedUserId, setNewlyCreatedUserId] = useState(null); const [possibleUIRoles, setPossibleUIRoles] = useState>>({}); const [userOptions, setUserOptions] = useState([]); const [userSearchLoading, setUserSearchLoading] = useState(false); - const [mcpAccessGroups, setMcpAccessGroups] = useState([]); const [disabledCallbacks, setDisabledCallbacks] = useState([]); const [keyType, setKeyType] = useState("llm_api"); const [modelAliases, setModelAliases] = useState<{ [key: string]: string }>({}); @@ -578,7 +555,6 @@ const CreateKey: React.FC = ({ team, teams, data, addKey, autoOp queryClient.invalidateQueries({ queryKey: keyKeys.lists() }); setApiKey(response["key"]); - setSoftBudget(response["soft_budget"]); NotificationsManager.success("Virtual Key Created"); form.resetFields(); setBudgetLimits([]); @@ -592,10 +568,6 @@ const CreateKey: React.FC = ({ team, teams, data, addKey, autoOp } }; - const handleCopy = () => { - NotificationsManager.success("Virtual Key copied to clipboard"); - }; - // Fetch available models when team or auth changes. // Note: Model prefill from URL params is handled by the useEffect below, which // watches for pendingPrefillModels + modelsToPick to both be populated. @@ -657,7 +629,6 @@ const CreateKey: React.FC = ({ team, teams, data, addKey, autoOp // Add a callback function to handle user creation const handleUserCreated = (userId: string) => { - setNewlyCreatedUserId(userId); form.setFieldsValue({ user_id: userId }); setIsCreateUserModalVisible(false); }; diff --git a/ui/litellm-dashboard/src/components/organization/organization_view.tsx b/ui/litellm-dashboard/src/components/organization/organization_view.tsx index 10af5bc1a07..a9f79810e1d 100644 --- a/ui/litellm-dashboard/src/components/organization/organization_view.tsx +++ b/ui/litellm-dashboard/src/components/organization/organization_view.tsx @@ -69,7 +69,7 @@ const OrganizationInfoView: React.FC = ({ user_id: values.user_id, role: values.role, }; - const response = await organizationMemberAddCall(accessToken, organizationId, member); + await organizationMemberAddCall(accessToken, organizationId, member); NotificationsManager.success("Organization member added successfully"); setIsAddMemberModalVisible(false); @@ -90,7 +90,7 @@ const OrganizationInfoView: React.FC = ({ role: values.role, }; - const response = await organizationMemberUpdateCall(accessToken, organizationId, member); + await organizationMemberUpdateCall(accessToken, organizationId, member); NotificationsManager.success("Organization member updated successfully"); setIsEditMemberModalVisible(false); queryClient.invalidateQueries({ queryKey: organizationKeys.all }); diff --git a/ui/litellm-dashboard/src/components/per_user_usage.tsx b/ui/litellm-dashboard/src/components/per_user_usage.tsx index 30933700cf3..e542be8df8f 100644 --- a/ui/litellm-dashboard/src/components/per_user_usage.tsx +++ b/ui/litellm-dashboard/src/components/per_user_usage.tsx @@ -55,13 +55,11 @@ const PerUserUsage: React.FC = ({ accessToken, selectedTags, total_pages: 0, }); - const [loading, setLoading] = useState(false); const [currentPage, setCurrentPage] = useState(1); const fetchPerUserData = async () => { if (!accessToken) return; - setLoading(true); try { const response = await perUserAnalyticsCall( accessToken, @@ -72,8 +70,6 @@ const PerUserUsage: React.FC = ({ accessToken, selectedTags, setPerUserData(response); } catch (error) { console.error("Failed to fetch per-user data:", error); - } finally { - setLoading(false); } }; diff --git a/ui/litellm-dashboard/src/components/price_data_reload.tsx b/ui/litellm-dashboard/src/components/price_data_reload.tsx index e0ec0fb794d..f56387d283c 100644 --- a/ui/litellm-dashboard/src/components/price_data_reload.tsx +++ b/ui/litellm-dashboard/src/components/price_data_reload.tsx @@ -60,9 +60,7 @@ const PriceDataReload: React.FC = ({ const [showScheduleModal, setShowScheduleModal] = useState(false); const [hours, setHours] = useState(6); const [reloadStatus, setReloadStatus] = useState(null); - const [loadingStatus, setLoadingStatus] = useState(false); const [sourceInfo, setSourceInfo] = useState(null); - const [loadingSource, setLoadingSource] = useState(false); // Fetch status on component mount and periodically useEffect(() => { @@ -81,7 +79,6 @@ const PriceDataReload: React.FC = ({ const fetchReloadStatus = async () => { if (!accessToken) return; - setLoadingStatus(true); try { const status = await getModelCostMapReloadStatus(accessToken); setReloadStatus(status); @@ -94,22 +91,17 @@ const PriceDataReload: React.FC = ({ last_run: null, next_run: null, }); - } finally { - setLoadingStatus(false); } }; const fetchSourceInfo = async () => { if (!accessToken) return; - setLoadingSource(true); try { const info = await getModelCostMapSource(accessToken); setSourceInfo(info); } catch (error) { console.error("Failed to fetch cost map source info:", error); - } finally { - setLoadingSource(false); } }; diff --git a/ui/litellm-dashboard/src/components/shared/DataTable/columnMeta.ts b/ui/litellm-dashboard/src/components/shared/DataTable/columnMeta.ts index eff4e0cb7db..39a99f1e861 100644 --- a/ui/litellm-dashboard/src/components/shared/DataTable/columnMeta.ts +++ b/ui/litellm-dashboard/src/components/shared/DataTable/columnMeta.ts @@ -4,6 +4,7 @@ import type * as React from "react"; import type { ColumnPinnedSide, DataTableSkeletonShape } from "./types"; declare module "@tanstack/react-table" { + // eslint-disable-next-line @typescript-eslint/no-unused-vars -- declaration merging requires the type parameters to match the upstream ColumnMeta signature exactly (TS2428) interface ColumnMeta { numeric?: boolean; className?: string; diff --git a/ui/litellm-dashboard/src/components/team/LoggingSettings.test.tsx b/ui/litellm-dashboard/src/components/team/LoggingSettings.test.tsx index e724e32d1c4..f998d7d3ecf 100644 --- a/ui/litellm-dashboard/src/components/team/LoggingSettings.test.tsx +++ b/ui/litellm-dashboard/src/components/team/LoggingSettings.test.tsx @@ -1,6 +1,5 @@ import React from "react"; import { describe, it, expect, vi, beforeEach } from "vitest"; -import userEvent from "@testing-library/user-event"; import { renderWithProviders, screen, fireEvent } from "../../../tests/test-utils"; import LoggingSettings from "./LoggingSettings"; @@ -10,7 +9,6 @@ describe("LoggingSettings", () => { }); it("passes a number to updateCallbackVar when user inputs a number in NumericalInput", async () => { - const user = userEvent.setup(); const mockOnChange = vi.fn(); // Create initial config with a callback that has number parameters (LangSmith has langsmith_sampling_rate) diff --git a/ui/litellm-dashboard/src/components/team/TeamInfo.tsx b/ui/litellm-dashboard/src/components/team/TeamInfo.tsx index bbe5dc05a88..b7bbbba3aed 100644 --- a/ui/litellm-dashboard/src/components/team/TeamInfo.tsx +++ b/ui/litellm-dashboard/src/components/team/TeamInfo.tsx @@ -52,7 +52,6 @@ import MCPServerSelector from "../mcp_server_management/MCPServerSelector"; import MCPToolPermissions from "../mcp_server_management/MCPToolPermissions"; import { ModelSelect } from "../ModelSelect/ModelSelect"; import NotificationsManager from "../molecules/notifications_manager"; -import { fetchMCPAccessGroups } from "../networking"; import ObjectPermissionsView from "../object_permissions_view"; import NumericalInput from "../shared/numerical_input"; import VectorStoreSelector from "../vector_store_management/VectorStoreSelector"; @@ -161,29 +160,6 @@ export interface TeamInfoProps { premiumUser?: boolean; } -const getOrganizationModels = (organization: Organization | null, userModels: string[]) => { - let tempModelsToPick = []; - - if (organization) { - // Check if organization has "all-proxy-models" in its models array - if (organization.models.includes("all-proxy-models")) { - // Treat as all-proxy-models (use userModels) - tempModelsToPick = userModels; - } else if (organization.models.length > 0) { - // Organization has specific models - tempModelsToPick = organization.models; - } else { - // Empty array [] is treated as all-proxy-models - tempModelsToPick = userModels; - } - } else { - // No organization, show all available models - tempModelsToPick = userModels; - } - - return unfurlWildcardModelsInList(tempModelsToPick, userModels); -}; - const TeamInfoView: React.FC = ({ teamId, onClose, @@ -203,8 +179,6 @@ const TeamInfoView: React.FC = ({ const [isEditMemberModalVisible, setIsEditMemberModalVisible] = useState(false); const [selectedEditMember, setSelectedEditMember] = useState(null); const [isEditing, setIsEditing] = useState(false); - const [mcpAccessGroups, setMcpAccessGroups] = useState([]); - const [mcpAccessGroupsLoaded, setMcpAccessGroupsLoaded] = useState(false); const [copiedStates, setCopiedStates] = useState>({}); const { data: guardrailsData, isLoading: isGuardrailsLoading } = useGuardrails(); const globalGuardrailNames = guardrailsData?.globalGuardrailNames ?? new Set(); @@ -293,23 +267,6 @@ const TeamInfoView: React.FC = ({ fetchOrganization(); }, [accessToken, teamData?.team_info?.organization_id]); - // Compute modelsToPick based on organization and userModels - const modelsToPick = useMemo(() => { - return getOrganizationModels(organization, userModels); - }, [organization, userModels]); - - 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 fetchPolicies = async () => { try { @@ -653,7 +610,7 @@ const TeamInfoView: React.FC = ({ } } - const response = await teamUpdateCall(accessToken, updateData); + await teamUpdateCall(accessToken, updateData); queryClient.invalidateQueries({ queryKey: organizationKeys.all }); NotificationsManager.success("Team settings updated successfully"); diff --git a/ui/litellm-dashboard/src/components/templates/KeyInfoView.handleKeyUpdate.test.tsx b/ui/litellm-dashboard/src/components/templates/KeyInfoView.handleKeyUpdate.test.tsx index fa8ffcd7366..3b001e39a25 100644 --- a/ui/litellm-dashboard/src/components/templates/KeyInfoView.handleKeyUpdate.test.tsx +++ b/ui/litellm-dashboard/src/components/templates/KeyInfoView.handleKeyUpdate.test.tsx @@ -196,32 +196,28 @@ vi.mock("lucide-react", async () => { }); // Heavy children -> async factories & local React -vi.mock("../organisms/RegenerateKeyModal", async () => { - const React = await import("react"); +vi.mock("../organisms/RegenerateKeyModal", () => { function RegenerateKeyModal() { return null; } (RegenerateKeyModal as any).displayName = "RegenerateKeyModal"; return { RegenerateKeyModal }; }); -vi.mock("../object_permissions_view", async () => { - const React = await import("react"); +vi.mock("../object_permissions_view", () => { function ObjectPermissionsView() { return null; } (ObjectPermissionsView as any).displayName = "ObjectPermissionsView"; return { __esModule: true, default: ObjectPermissionsView }; }); -vi.mock("../logging_settings_view", async () => { - const React = await import("react"); +vi.mock("../logging_settings_view", () => { function LoggingSettingsView() { return null; } (LoggingSettingsView as any).displayName = "LoggingSettingsView"; return { __esModule: true, default: LoggingSettingsView }; }); -vi.mock("../common_components/AutoRotationView", async () => { - const React = await import("react"); +vi.mock("../common_components/AutoRotationView", () => { function AutoRotationView() { return null; } 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 756481487e7..e93b28f4ea3 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 @@ -1007,7 +1007,7 @@ describe("KeyEditView", () => { }); it("should disable the organization dropdown for non-admin users", async () => { - const { container } = renderWithProviders( + renderWithProviders( {}} @@ -1029,7 +1029,7 @@ describe("KeyEditView", () => { }); it("should not disable the organization dropdown for admin users", async () => { - const { container } = renderWithProviders( + renderWithProviders( {}} 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 280abb3dac7..f4803727875 100644 --- a/ui/litellm-dashboard/src/components/templates/key_info_view.tsx +++ b/ui/litellm-dashboard/src/components/templates/key_info_view.tsx @@ -6,7 +6,7 @@ import { formatNumberWithCommas } from "@/utils/dataUtils"; import { mapEmptyStringToNull } from "@/utils/keyUpdateUtils"; import { ArrowLeftIcon } from "@heroicons/react/outline"; import { Badge, Button, Card, Grid, Tab, TabGroup, TabList, TabPanel, TabPanels, Text, Title } from "@tremor/react"; -import { Form, Modal, Tag } from "antd"; +import { Modal, Tag } from "antd"; import { KeyInfoHeader } from "./KeyInfoHeader"; import { useEffect, useState } from "react"; import { isProxyAdminRole, isUserTeamAdminForSingleTeam, rolesWithWriteAccess } from "../../utils/roles"; @@ -74,10 +74,8 @@ export default function KeyInfoView({ const { data: uiSettingsData } = useUISettings(); const enableProjectsUI = Boolean(uiSettingsData?.values?.enable_projects_ui); const [isEditing, setIsEditing] = useState(false); - const [form] = Form.useForm(); const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [deleteLoading, setDeleteLoading] = useState(false); - const [deleteConfirmInput, setDeleteConfirmInput] = useState(""); const [isRegenerateModalOpen, setIsRegenerateModalOpen] = useState(false); const [isResetSpendModalOpen, setIsResetSpendModalOpen] = useState(false); const [isBlockModalOpen, setIsBlockModalOpen] = useState(false); @@ -340,7 +338,6 @@ export default function KeyInfoView({ } finally { setDeleteLoading(false); setIsDeleteModalOpen(false); - setDeleteConfirmInput(""); } }; @@ -526,7 +523,6 @@ export default function KeyInfoView({ ]} onCancel={() => { setIsDeleteModalOpen(false); - setDeleteConfirmInput(""); }} onOk={handleDelete} confirmLoading={deleteLoading} diff --git a/ui/litellm-dashboard/src/components/user_dashboard.tsx b/ui/litellm-dashboard/src/components/user_dashboard.tsx index 1ed4e1d0bba..1de232fadb8 100644 --- a/ui/litellm-dashboard/src/components/user_dashboard.tsx +++ b/ui/litellm-dashboard/src/components/user_dashboard.tsx @@ -6,14 +6,7 @@ import React, { useEffect, useState } from "react"; import { fetchTeams } from "./common_components/fetch_teams"; import { KeyResponse, Team } from "./key_team_helpers/key_list"; import { effectiveSessionRole } from "@/utils/roles"; -import { - getProxyBaseUrl, - getProxyUISettings, - keyInfoCall, - modelAvailableCall, - Organization, - userGetInfoV2, -} from "./networking"; +import { getProxyBaseUrl, keyInfoCall, modelAvailableCall, Organization, userGetInfoV2 } from "./networking"; import CreateKey, { CreateKeyPrefillData } from "./organisms/create_key_button"; import { VirtualKeysTable } from "./VirtualKeysPage/VirtualKeysTable"; @@ -50,12 +43,6 @@ interface UserDashboardProps { prefillData?: CreateKeyPrefillData; } -type TeamInterface = { - models: any[]; - team_id: null; - team_alias: string; -}; - const UserDashboard: React.FC = ({ userID, userRole, @@ -73,15 +60,12 @@ const UserDashboard: React.FC = ({ prefillData, }) => { const [userSpendData, setUserSpendData] = useState(null); - const [currentOrg, setCurrentOrg] = useState(null); + const [currentOrg] = useState(null); const token = getCookie("token"); const [accessToken, setAccessToken] = useState(null); - const [teamSpend, setTeamSpend] = useState(null); - const [userModels, setUserModels] = useState([]); - const [proxySettings, setProxySettings] = useState(null); - const [selectedTeam, setSelectedTeam] = useState(null); + const [selectedTeam] = useState(null); // Clear session storage on page unload so next load fetches fresh data. // Note: MCP auth tokens are persistent and should not be cleared on page refresh @@ -123,14 +107,9 @@ const UserDashboard: React.FC = ({ } if (userID && accessToken && userRole && !userSpendData) { const cachedUserModels = sessionStorage.getItem("userModels" + userID); - if (cachedUserModels) { - setUserModels(JSON.parse(cachedUserModels)); - } else { + if (!cachedUserModels) { const fetchData = async () => { try { - const proxy_settings: ProxySettings = await getProxyUISettings(accessToken); - setProxySettings(proxy_settings); - const response = await userGetInfoV2(accessToken, userID); setUserSpendData(response); @@ -140,7 +119,6 @@ const UserDashboard: React.FC = ({ const model_available = await modelAvailableCall(accessToken, userID, userRole); // loop through model_info["data"] and create an array of element.model_name let available_model_names = model_available["data"].map((element: { id: string }) => element.id); - setUserModels(available_model_names); sessionStorage.setItem("userModels" + userID, JSON.stringify(available_model_names)); } catch (error: any) { @@ -162,7 +140,7 @@ const UserDashboard: React.FC = ({ if (accessToken) { const fetchKeyInfo = async () => { try { - const keyInfo = await keyInfoCall(accessToken, [accessToken]); + await keyInfoCall(accessToken, [accessToken]); } catch (error: any) { if (error.message.includes("Invalid proxy server token passed")) { gotoLogin(); @@ -179,26 +157,6 @@ const UserDashboard: React.FC = ({ } }, [currentOrg]); - useEffect(() => { - // This code will run every time selectedTeam changes - if (keys !== null && selectedTeam !== null && selectedTeam !== undefined && selectedTeam.team_id !== null) { - let sum = 0; - for (const key of keys) { - if (selectedTeam.hasOwnProperty("team_id") && key.team_id !== null && key.team_id === selectedTeam.team_id) { - sum += key.spend; - } - } - setTeamSpend(sum); - } else if (keys !== null) { - // sum the keys which don't have team-id set (default team) - let sum = 0; - for (const key of keys) { - sum += key.spend; - } - setTeamSpend(sum); - } - }, [selectedTeam]); - function gotoLogin() { // Clear token cookies using the utility function clearTokenCookies(); diff --git a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SimpleToolCallBlock.test.tsx b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SimpleToolCallBlock.test.tsx index 107b911e386..0eb61686b73 100644 --- a/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SimpleToolCallBlock.test.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/LogDetailsDrawer/SimpleToolCallBlock.test.tsx @@ -31,7 +31,7 @@ describe("SimpleToolCallBlock", () => { }); it("should not render arguments section when arguments are empty", () => { - const { container } = render(); + render(); // The tool name and "function" badge should be there, but no key: value pairs expect(screen.getByText("get_weather")).toBeInTheDocument(); expect(screen.queryByText(/:$/)).not.toBeInTheDocument(); diff --git a/ui/litellm-dashboard/src/components/view_logs/table.tsx b/ui/litellm-dashboard/src/components/view_logs/table.tsx index c96f34f9b93..d522478e370 100644 --- a/ui/litellm-dashboard/src/components/view_logs/table.tsx +++ b/ui/litellm-dashboard/src/components/view_logs/table.tsx @@ -14,6 +14,7 @@ import { import { Table, TableHeader, TableHead, TableBody, TableRow, TableCell } from "@/components/ui/table"; declare module "@tanstack/react-table" { + // eslint-disable-next-line @typescript-eslint/no-unused-vars -- declaration merging requires the type parameters to match the upstream ColumnMeta signature exactly (TS2428) interface ColumnMeta { numeric?: boolean; }