Merge pull request #36026 from BerriAI/litellm_dead_locals_5_8
Some checks are pending
CI Coverage / assert-ci-coverage (push) Waiting to run
CodSpeed Benchmarks / benchmarks (push) Waiting to run
Publish basedpyright base counts / publish (push) Waiting to run
Code Quality Checks / code-quality (push) Waiting to run
UI Unit Tests / ui-unit-tests (push) Waiting to run
Terraform Provider / gofmt, vet, build, test (push) Waiting to run
Terraform Provider / Provider endpoints vs proxy OpenAPI schema (push) Waiting to run
Unit Tests: Core Utilities / core-utils (push) Waiting to run
Unit Tests: Documentation Validation / documentation (push) Waiting to run
Unit Tests: Enterprise, Google GenAI & Routing / enterprise-routing (push) Waiting to run
Unit Tests: Integrations (Callbacks & Logging) / integrations (push) Waiting to run
Unit Tests: LLM Provider Transformations / Vertex AI (push) Waiting to run
Unit Tests: LLM Provider Transformations / All Other Providers (push) Waiting to run
Unit Tests: MCP, Secrets, Containers & Misc / misc (push) Waiting to run
Unit Tests: Proxy Auth & Key Management / proxy-auth (push) Waiting to run
Unit Tests: Proxy DB Operations / assert-shard-coverage (push) Waiting to run
Unit Tests: Proxy DB Operations / auth-checks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / budgets (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / custom-logging (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / db-and-spend (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / endpoints-and-responses (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / guardrails-hooks (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / jwt-and-keys (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / key-generation (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / logging-misc (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-runtime (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-server-core (push) Blocked by required conditions
Unit Tests: Proxy DB Operations / proxy-utils (push) Blocked by required conditions
Unit Tests: Proxy API Endpoints / proxy-endpoints (push) Waiting to run
Unit Tests: Proxy API Endpoints / proxy-server (push) Waiting to run
Unit Tests: Proxy Legacy Tests / auth-and-jwt (push) Waiting to run
Unit Tests: Proxy Legacy Tests / key-generation (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-config (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-response-and-misc (push) Waiting to run
Unit Tests: Proxy Infrastructure / proxy-infra (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-server (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-server-extras (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-token-counter (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-user-auth-and-spend (push) Waiting to run
Unit Tests: Proxy Legacy Tests / proxy-utils (push) Waiting to run
Unit Tests: Responses, Caching & Types / responses-caching-types (push) Waiting to run
GitHub Actions Security Analysis / zizmor (push) Waiting to run

refactor(ui): drop dead locals and unused React state across the dashboard
This commit is contained in:
yuneng-jiang 2026-08-05 18:43:27 -07:00 committed by GitHub
commit f01a4fc023
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 39 additions and 455 deletions

View file

@ -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": {

View file

@ -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<AddAgentFormProps> = ({ visible, onClose, accessTok
const [isSubmitting, setIsSubmitting] = useState(false);
const [agentType, setAgentType] = useState<string>("a2a");
const [agentTypeMetadata, setAgentTypeMetadata] = useState<AgentCreateInfo[]>([]);
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<AddAgentFormProps> = ({ 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();

View file

@ -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 (

View file

@ -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<AddGuardrailFormProps> = ({ visible, onClose, a
const [currentStep, setCurrentStep] = useState(0);
const [providerParams, setProviderParams] = useState<ProviderParamsResponse | null>(null);
// Azure Text Moderation state
const [selectedCategories, setSelectedCategories] = useState<string[]>([]);
const [globalSeverityThreshold, setGlobalSeverityThreshold] = useState<number>(2);
const [categorySpecificThresholds, setCategorySpecificThresholds] = useState<{ [key: string]: number }>({});
// Content Filter state
const [selectedPatterns, setSelectedPatterns] = useState<ContentFilterPattern[]>([]);
const [blockedWords, setBlockedWords] = useState<ContentFilterBlockedWord[]>([]);
@ -297,11 +291,6 @@ const AddGuardrailForm: React.FC<AddGuardrailFormProps> = ({ 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<AddGuardrailFormProps> = ({ 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<AddGuardrailFormProps> = ({ 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<AddGuardrailFormProps> = ({ 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 (
<div className="flex justify-end space-x-2 mt-4">
{currentStep > 0 && <Button onClick={prevStep}>Previous</Button>}
{isCategoriesStep ? (
<>
<Button onClick={nextStep}>Skip</Button>
<Button
type="primary"
onClick={() => handleAddAndContinue(hasCompetitorIntentConfigured)}
disabled={!canContinueFromCategoriesStep}
>
{hasPendingCategory ? "Add & Continue →" : "Continue →"}
</Button>
</>
) : (
<>
{!isLastStep && (
<Button type="primary" onClick={nextStep}>
Next
</Button>
)}
{isLastStep && (
<Button type="primary" onClick={handleSubmit} loading={loading}>
Create Guardrail
</Button>
)}
</>
)}
<Button onClick={handleClose}>Cancel</Button>
</div>
);
};
const renderEndpointSettings = () => {
return (
<div className="space-y-6">

View file

@ -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 () => {

View file

@ -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();

View file

@ -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<AddPolicyFormProps> = ({
const [form] = Form.useForm();
const [isSubmitting, setIsSubmitting] = useState(false);
const [resolvedGuardrails, setResolvedGuardrails] = useState<string[]>([]);
const [isLoadingResolved, setIsLoadingResolved] = useState(false);
const [modelConditionType, setModelConditionType] = useState<"model" | "regex">("model");
const [availableModels, setAvailableModels] = useState<string[]>([]);
const [step, setStep] = useState<"pick_mode" | "simple_form">("pick_mode");
@ -231,14 +229,11 @@ const AddPolicyForm: React.FC<AddPolicyFormProps> = ({
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);
}
};

View file

@ -53,7 +53,6 @@ const PolicyInfoView: React.FC<PolicyInfoViewProps> = ({
const [policy, setPolicy] = useState<Policy | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [resolvedGuardrails, setResolvedGuardrails] = useState<string[]>([]);
const [isLoadingResolved, setIsLoadingResolved] = useState(false);
const fetchPolicy = useCallback(async () => {
if (!accessToken || !policyId) return;
@ -64,14 +63,11 @@ const PolicyInfoView: React.FC<PolicyInfoViewProps> = ({
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);

View file

@ -182,7 +182,7 @@ describe("VersionHistorySidePanel", () => {
render(<VersionHistorySidePanel {...defaultProps} />);
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(<VersionHistorySidePanel {...defaultProps} />);
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();
});

View file

@ -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) => {

View file

@ -23,7 +23,6 @@ const UsefulLinksManagement: React.FC<UsefulLinksManagementProps> = ({ accessTok
const [links, setLinks] = useState<Link[]>([]);
const [newLink, setNewLink] = useState({ url: "", displayName: "" });
const [editingLink, setEditingLink] = useState<Link | null>(null);
const [loading, setLoading] = useState(false);
const [isExpanded, setIsExpanded] = useState(true);
const [isRearranging, setIsRearranging] = useState(false);
const [originalLinksOrder, setOriginalLinksOrder] = useState<Link[]>([]);
@ -32,7 +31,6 @@ const UsefulLinksManagement: React.FC<UsefulLinksManagementProps> = ({ accessTok
if (!accessToken) return;
try {
setLoading(true);
const response = await getPublicModelHubInfo();
if (response && response.useful_links) {
@ -73,8 +71,6 @@ const UsefulLinksManagement: React.FC<UsefulLinksManagementProps> = ({ accessTok
} catch (error) {
console.error("Error fetching useful links:", error);
setLinks([]);
} finally {
setLoading(false);
}
};

View file

@ -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 = {

View file

@ -320,7 +320,7 @@ describe("EditSSOSettingsModal", () => {
useEditSSOSettings: { mutateAsync: mockMutateAsync, isPending: false },
});
const { mockOnSuccess } = renderComponent();
renderComponent();
fireEvent.click(screen.getByTestId(TEST_IDS.TRIGGER_FORM_SUBMIT));

View file

@ -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<TeamProps> = ({ accessToken, userID, userRole, premiumUser = false }) => {
const { data: organizationsData } = useOrganizations();
@ -135,35 +95,25 @@ const Teams: React.FC<TeamProps> = ({ accessToken, userID, userRole, premiumUser
const [currentOrgForCreateTeam, setCurrentOrgForCreateTeam] = useState<Organization | null>(null);
const [form] = Form.useForm();
const [memberForm] = Form.useForm();
const [value, setValue] = useState("");
const [editModalVisible, setEditModalVisible] = useState(false);
const [selectedTeam, setSelectedTeam] = useState<Team | null>(null);
const [selectedTeamId, setSelectedTeamId] = useQueryState("team", parseAsString.withOptions({ history: "push" }));
const [editTeam, setEditTeam] = useState<boolean>(false);
const [isTeamModalVisible, setIsTeamModalVisible] = useState(false);
const [isAddMemberModalVisible, setIsAddMemberModalVisible] = useState(false);
const [isEditMemberModalVisible, setIsEditMemberModalVisible] = useState(false);
const [userModels, setUserModels] = useState<string[]>([]);
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [teamToDelete, setTeamToDelete] = useState<Team | null>(null);
const [modelsToPick, setModelsToPick] = useState<string[]>([]);
const [isTeamDeleting, setIsTeamDeleting] = useState(false);
// Add this state near the other useState declarations
const [guardrailsList, setGuardrailsList] = useState<string[]>([]);
const [policiesList, setPoliciesList] = useState<string[]>([]);
const [loggingSettings, setLoggingSettings] = useState<any[]>([]);
const [mcpAccessGroups, setMcpAccessGroups] = useState<string[]>([]);
const [mcpAccessGroupsLoaded, setMcpAccessGroupsLoaded] = useState(false);
const [modelAliases, setModelAliases] = useState<{ [key: string]: string }>({});
const [routerSettings, setRouterSettings] = useState<RouterSettingsAccordionValue | null>(null);
const [routerSettingsKey, setRouterSettingsKey] = useState<number>(0);
useEffect(() => {
const models = getOrganizationModels(currentOrgForCreateTeam, userModels);
setModelsToPick(models);
form.setFieldValue("models", []);
}, [currentOrgForCreateTeam, userModels]);
@ -220,22 +170,6 @@ const Teams: React.FC<TeamProps> = ({ 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<TeamProps> = ({ 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<TeamProps> = ({ 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<TeamProps> = ({ accessToken, userID, userRole, premiumUser
/>
</Form.Item>
<Accordion
className="mt-20 mb-8"
onClick={() => {
if (!mcpAccessGroupsLoaded) {
fetchMcpAccessGroups();
setMcpAccessGroupsLoaded(true);
}
}}
>
<Accordion className="mt-20 mb-8">
<AccordionHeader>
<b>Additional Settings</b>
</AccordionHeader>

View file

@ -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 }) => ({

View file

@ -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();

View file

@ -24,7 +24,6 @@ const ModelConnectionTest: React.FC<ModelConnectionTestProps> = ({
onTestComplete,
}) => {
const [error, setError] = React.useState<Error | string | null>(null);
const [rawRequest, setRawRequest] = React.useState<any>(null);
const [rawResponse, setRawResponse] = React.useState<any>(null);
const [isLoading, setIsLoading] = React.useState<boolean>(true);
const [isSuccess, setIsSuccess] = React.useState<boolean>(false);
@ -34,7 +33,6 @@ const ModelConnectionTest: React.FC<ModelConnectionTestProps> = ({
setIsLoading(true);
setShowDetails(false);
setError(null);
setRawRequest(null);
setRawResponse(null);
setIsSuccess(false);
@ -51,7 +49,7 @@ const ModelConnectionTest: React.FC<ModelConnectionTestProps> = ({
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<ModelConnectionTestProps> = ({
} else {
const errorMessage = response.result?.error || response.message || "Unknown error";
setError(errorMessage);
setRawRequest(litellmParamsObj);
setRawResponse(response.result?.raw_request_typed_dict);
setIsSuccess(false);
}

View file

@ -158,8 +158,6 @@ const EditAutoRouterModal: React.FC<EditAutoRouterModalProps> = ({
const [loading, setLoading] = useState(false);
const [modelAccessGroups, setModelAccessGroups] = useState<string[]>([]);
const [modelInfo, setModelInfo] = useState<ModelGroup[]>([]);
const [showCustomDefaultModel, setShowCustomDefaultModel] = useState<boolean>(false);
const [showCustomEmbeddingModel, setShowCustomEmbeddingModel] = useState<boolean>(false);
const [showValidationErrors, setShowValidationErrors] = useState<boolean>(false);
const [routerConfig, setRouterConfig] = useState<any>(null);
const [customTechnicalKeywords, setCustomTechnicalKeywords] = useState<string[]>([]);
@ -308,11 +306,6 @@ const EditAutoRouterModal: React.FC<EditAutoRouterModalProps> = ({
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<EditAutoRouterModalProps> = ({
>
<AntdSelect
placeholder="Select a default model"
onChange={(value) => {
setShowCustomDefaultModel(value === "custom");
}}
options={[...modelOptions, { value: "custom", label: "Enter custom model name" }]}
showSearch={true}
/>
@ -532,9 +522,6 @@ const EditAutoRouterModal: React.FC<EditAutoRouterModalProps> = ({
>
<AntdSelect
placeholder="Select an embedding model"
onChange={(value) => {
setShowCustomEmbeddingModel(value === "custom");
}}
options={[...modelOptions, { value: "custom", label: "Enter custom model name" }]}
showSearch={true}
/>

View file

@ -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

View file

@ -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<CreateKeyProps> = ({ 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<string[]>([]);
const [modelsToPick, setModelsToPick] = useState<string[]>([]);
const [keyOwner, setKeyOwner] = useState("you");
@ -192,11 +171,9 @@ const CreateKey: React.FC<CreateKeyProps> = ({ team, teams, data, addKey, autoOp
const [selectedOrganizationId, setSelectedOrganizationId] = useState<string | null>(null);
const [selectedProjectId, setSelectedProjectId] = useState<string | null>(null);
const [isCreateUserModalVisible, setIsCreateUserModalVisible] = useState(false);
const [newlyCreatedUserId, setNewlyCreatedUserId] = useState<string | null>(null);
const [possibleUIRoles, setPossibleUIRoles] = useState<Record<string, Record<string, string>>>({});
const [userOptions, setUserOptions] = useState<UserOption[]>([]);
const [userSearchLoading, setUserSearchLoading] = useState<boolean>(false);
const [mcpAccessGroups, setMcpAccessGroups] = useState<string[]>([]);
const [disabledCallbacks, setDisabledCallbacks] = useState<string[]>([]);
const [keyType, setKeyType] = useState<string>("llm_api");
const [modelAliases, setModelAliases] = useState<{ [key: string]: string }>({});
@ -578,7 +555,6 @@ const CreateKey: React.FC<CreateKeyProps> = ({ 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<CreateKeyProps> = ({ 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<CreateKeyProps> = ({ 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);
};

View file

@ -69,7 +69,7 @@ const OrganizationInfoView: React.FC<OrganizationInfoProps> = ({
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<OrganizationInfoProps> = ({
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 });

View file

@ -55,13 +55,11 @@ const PerUserUsage: React.FC<PerUserUsageProps> = ({ 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<PerUserUsageProps> = ({ accessToken, selectedTags,
setPerUserData(response);
} catch (error) {
console.error("Failed to fetch per-user data:", error);
} finally {
setLoading(false);
}
};

View file

@ -60,9 +60,7 @@ const PriceDataReload: React.FC<PriceDataReloadProps> = ({
const [showScheduleModal, setShowScheduleModal] = useState(false);
const [hours, setHours] = useState<number>(6);
const [reloadStatus, setReloadStatus] = useState<ReloadStatus | null>(null);
const [loadingStatus, setLoadingStatus] = useState(false);
const [sourceInfo, setSourceInfo] = useState<CostMapSourceInfo | null>(null);
const [loadingSource, setLoadingSource] = useState(false);
// Fetch status on component mount and periodically
useEffect(() => {
@ -81,7 +79,6 @@ const PriceDataReload: React.FC<PriceDataReloadProps> = ({
const fetchReloadStatus = async () => {
if (!accessToken) return;
setLoadingStatus(true);
try {
const status = await getModelCostMapReloadStatus(accessToken);
setReloadStatus(status);
@ -94,22 +91,17 @@ const PriceDataReload: React.FC<PriceDataReloadProps> = ({
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);
}
};

View file

@ -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<TData extends RowData, TValue> {
numeric?: boolean;
className?: string;

View file

@ -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)

View file

@ -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<TeamInfoProps> = ({
teamId,
onClose,
@ -203,8 +179,6 @@ const TeamInfoView: React.FC<TeamInfoProps> = ({
const [isEditMemberModalVisible, setIsEditMemberModalVisible] = useState(false);
const [selectedEditMember, setSelectedEditMember] = useState<Member | null>(null);
const [isEditing, setIsEditing] = useState(false);
const [mcpAccessGroups, setMcpAccessGroups] = useState<string[]>([]);
const [mcpAccessGroupsLoaded, setMcpAccessGroupsLoaded] = useState(false);
const [copiedStates, setCopiedStates] = useState<Record<string, boolean>>({});
const { data: guardrailsData, isLoading: isGuardrailsLoading } = useGuardrails();
const globalGuardrailNames = guardrailsData?.globalGuardrailNames ?? new Set<string>();
@ -293,23 +267,6 @@ const TeamInfoView: React.FC<TeamInfoProps> = ({
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<TeamInfoProps> = ({
}
}
const response = await teamUpdateCall(accessToken, updateData);
await teamUpdateCall(accessToken, updateData);
queryClient.invalidateQueries({ queryKey: organizationKeys.all });
NotificationsManager.success("Team settings updated successfully");

View file

@ -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;
}

View file

@ -1007,7 +1007,7 @@ describe("KeyEditView", () => {
});
it("should disable the organization dropdown for non-admin users", async () => {
const { container } = renderWithProviders(
renderWithProviders(
<KeyEditView
keyData={MOCK_KEY_DATA}
onCancel={() => {}}
@ -1029,7 +1029,7 @@ describe("KeyEditView", () => {
});
it("should not disable the organization dropdown for admin users", async () => {
const { container } = renderWithProviders(
renderWithProviders(
<KeyEditView
keyData={MOCK_KEY_DATA}
onCancel={() => {}}

View file

@ -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}

View file

@ -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<UserDashboardProps> = ({
userID,
userRole,
@ -73,15 +60,12 @@ const UserDashboard: React.FC<UserDashboardProps> = ({
prefillData,
}) => {
const [userSpendData, setUserSpendData] = useState<UserInfo | null>(null);
const [currentOrg, setCurrentOrg] = useState<Organization | null>(null);
const [currentOrg] = useState<Organization | null>(null);
const token = getCookie("token");
const [accessToken, setAccessToken] = useState<string | null>(null);
const [teamSpend, setTeamSpend] = useState<number | null>(null);
const [userModels, setUserModels] = useState<string[]>([]);
const [proxySettings, setProxySettings] = useState<ProxySettings | null>(null);
const [selectedTeam, setSelectedTeam] = useState<any | null>(null);
const [selectedTeam] = useState<any | null>(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<UserDashboardProps> = ({
}
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<UserDashboardProps> = ({
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<UserDashboardProps> = ({
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<UserDashboardProps> = ({
}
}, [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();

View file

@ -31,7 +31,7 @@ describe("SimpleToolCallBlock", () => {
});
it("should not render arguments section when arguments are empty", () => {
const { container } = render(<SimpleToolCallBlock tool={{ id: "1", name: "get_weather", arguments: {} }} />);
render(<SimpleToolCallBlock tool={{ id: "1", name: "get_weather", arguments: {} }} />);
// 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();

View file

@ -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<TData extends RowData, TValue> {
numeric?: boolean;
}