mirror of
https://github.com/BerriAI/litellm.git
synced 2026-08-28 05:25:59 +00:00
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
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:
commit
f01a4fc023
32 changed files with 39 additions and 455 deletions
|
|
@ -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": {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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 () => {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ describe("EditSSOSettingsModal", () => {
|
|||
useEditSSOSettings: { mutateAsync: mockMutateAsync, isPending: false },
|
||||
});
|
||||
|
||||
const { mockOnSuccess } = renderComponent();
|
||||
renderComponent();
|
||||
|
||||
fireEvent.click(screen.getByTestId(TEST_IDS.TRIGGER_FORM_SUBMIT));
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 }) => ({
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 });
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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={() => {}}
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue