mirror of
https://github.com/tiennm99/litellm.git
synced 2026-07-13 11:07:39 +00:00
fixing build
This commit is contained in:
@@ -2,14 +2,7 @@
|
||||
|
||||
import React, { useCallback, useDeferredValue, useEffect, useState } from "react";
|
||||
import { Select, Switch, Tooltip } from "antd";
|
||||
import {
|
||||
Table,
|
||||
TableHead,
|
||||
TableHeaderCell,
|
||||
TableBody,
|
||||
TableRow,
|
||||
TableCell,
|
||||
} from "@tremor/react";
|
||||
import { Table, TableHead, TableHeaderCell, TableBody, TableRow, TableCell } from "@tremor/react";
|
||||
import { TimeCell } from "./view_logs/time_cell";
|
||||
import { TableHeaderSortDropdown } from "./common_components/TableHeaderSortDropdown/TableHeaderSortDropdown";
|
||||
import type { SortState } from "./common_components/TableHeaderSortDropdown/TableHeaderSortDropdown";
|
||||
@@ -17,14 +10,13 @@ import FilterComponent, { FilterOption } from "./molecules/filter";
|
||||
import { fetchToolsList, updateToolPolicy, ToolRow } from "./networking";
|
||||
|
||||
const POLICY_OPTIONS = [
|
||||
{ value: "trusted", label: "trusted", color: "#065f46", bg: "#d1fae5", border: "#6ee7b7" },
|
||||
{ value: "blocked", label: "blocked", color: "#991b1b", bg: "#fee2e2", border: "#fca5a5" },
|
||||
{ value: "trusted", label: "trusted", color: "#065f46", bg: "#d1fae5", border: "#6ee7b7" },
|
||||
{ value: "blocked", label: "blocked", color: "#991b1b", bg: "#fee2e2", border: "#fca5a5" },
|
||||
] as const;
|
||||
|
||||
type PolicyValue = "trusted" | "blocked";
|
||||
|
||||
const policyStyle = (p: string) =>
|
||||
POLICY_OPTIONS.find((o) => o.value === p) ?? POLICY_OPTIONS[1];
|
||||
const policyStyle = (p: string) => POLICY_OPTIONS.find((o) => o.value === p) ?? POLICY_OPTIONS[1];
|
||||
|
||||
type SortField = "tool_name" | "call_policy" | "team_id" | "key_alias" | "created_at" | "call_count";
|
||||
|
||||
@@ -56,18 +48,6 @@ const PolicySelect: React.FC<{
|
||||
minWidth: 110,
|
||||
fontWeight: 500,
|
||||
}}
|
||||
styles={{
|
||||
selector: {
|
||||
backgroundColor: style.bg,
|
||||
borderColor: style.border,
|
||||
color: style.color,
|
||||
borderRadius: 999,
|
||||
fontSize: 11,
|
||||
fontWeight: 600,
|
||||
paddingLeft: 8,
|
||||
paddingRight: 4,
|
||||
},
|
||||
}}
|
||||
popupMatchSelectWidth={false}
|
||||
options={POLICY_OPTIONS.map((o) => ({
|
||||
value: o.value,
|
||||
@@ -133,7 +113,9 @@ export const ToolPolicies: React.FC<ToolPoliciesProps> = ({ accessToken }) => {
|
||||
}
|
||||
}, [accessToken]);
|
||||
|
||||
useEffect(() => { load(); }, [load]);
|
||||
useEffect(() => {
|
||||
load();
|
||||
}, [load]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLiveTail) return;
|
||||
@@ -146,9 +128,7 @@ export const ToolPolicies: React.FC<ToolPoliciesProps> = ({ accessToken }) => {
|
||||
setSaving(toolName);
|
||||
try {
|
||||
await updateToolPolicy(accessToken, toolName, newPolicy);
|
||||
setTools((prev) =>
|
||||
prev.map((t) => (t.tool_name === toolName ? { ...t, call_policy: newPolicy } : t))
|
||||
);
|
||||
setTools((prev) => prev.map((t) => (t.tool_name === toolName ? { ...t, call_policy: newPolicy } : t)));
|
||||
} catch (e: any) {
|
||||
alert(`Failed to update policy: ${e.message}`);
|
||||
} finally {
|
||||
@@ -178,12 +158,14 @@ export const ToolPolicies: React.FC<ToolPoliciesProps> = ({ accessToken }) => {
|
||||
};
|
||||
|
||||
// Build unique team/key options from loaded data
|
||||
const teamOptions = Array.from(new Set(tools.map((t) => t.team_id).filter(Boolean))).map(
|
||||
(v) => ({ label: v as string, value: v as string })
|
||||
);
|
||||
const keyAliasOptions = Array.from(new Set(tools.map((t) => t.key_alias).filter(Boolean))).map(
|
||||
(v) => ({ label: v as string, value: v as string })
|
||||
);
|
||||
const teamOptions = Array.from(new Set(tools.map((t) => t.team_id).filter(Boolean))).map((v) => ({
|
||||
label: v as string,
|
||||
value: v as string,
|
||||
}));
|
||||
const keyAliasOptions = Array.from(new Set(tools.map((t) => t.key_alias).filter(Boolean))).map((v) => ({
|
||||
label: v as string,
|
||||
value: v as string,
|
||||
}));
|
||||
|
||||
const filterOptions: FilterOption[] = [
|
||||
{
|
||||
@@ -245,7 +227,6 @@ export const ToolPolicies: React.FC<ToolPoliciesProps> = ({ accessToken }) => {
|
||||
<div className="p-6 w-full">
|
||||
<h1 className="text-2xl font-semibold text-gray-900 mb-6">Tool Policies</h1>
|
||||
<div className="bg-white rounded-lg shadow w-full max-w-full box-border">
|
||||
|
||||
{/* Toolbar */}
|
||||
<div className="border-b px-6 py-4 w-full max-w-full box-border">
|
||||
<div className="flex flex-col md:flex-row items-start md:items-center justify-between space-y-4 md:space-y-0 w-full max-w-full box-border">
|
||||
@@ -256,16 +237,29 @@ export const ToolPolicies: React.FC<ToolPoliciesProps> = ({ accessToken }) => {
|
||||
placeholder="Search by Tool Name"
|
||||
className="w-full px-3 py-2 pl-8 border rounded-md text-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
value={searchTerm}
|
||||
onChange={(e) => { setSearchTerm(e.target.value); setCurrentPage(1); }}
|
||||
onChange={(e) => {
|
||||
setSearchTerm(e.target.value);
|
||||
setCurrentPage(1);
|
||||
}}
|
||||
/>
|
||||
<svg className="absolute left-2.5 top-2.5 h-4 w-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
||||
<svg
|
||||
className="absolute left-2.5 top-2.5 h-4 w-4 text-gray-500"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-medium text-gray-900">Live Tail</span>
|
||||
<Switch color="green" checked={isLiveTail} onChange={setIsLiveTail} />
|
||||
<Switch checked={isLiveTail} onChange={setIsLiveTail} />
|
||||
</div>
|
||||
|
||||
<button
|
||||
@@ -273,8 +267,18 @@ export const ToolPolicies: React.FC<ToolPoliciesProps> = ({ accessToken }) => {
|
||||
disabled={isButtonLoading}
|
||||
className="flex items-center gap-1.5 px-3 py-2 text-sm border rounded-md hover:bg-gray-50 disabled:opacity-60"
|
||||
>
|
||||
<svg className={`w-4 h-4 ${isButtonLoading ? "animate-spin" : ""}`} fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
||||
<svg
|
||||
className={`w-4 h-4 ${isButtonLoading ? "animate-spin" : ""}`}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
|
||||
/>
|
||||
</svg>
|
||||
{isButtonLoading ? "Fetching" : "Fetch"}
|
||||
</button>
|
||||
@@ -282,14 +286,27 @@ export const ToolPolicies: React.FC<ToolPoliciesProps> = ({ accessToken }) => {
|
||||
|
||||
<div className="flex items-center gap-4 text-sm text-gray-600 whitespace-nowrap">
|
||||
<span>
|
||||
Showing {filtered.length === 0 ? 0 : (currentPage - 1) * pageSize + 1} - {Math.min(currentPage * pageSize, filtered.length)} of {filtered.length} results
|
||||
Showing {filtered.length === 0 ? 0 : (currentPage - 1) * pageSize + 1} -{" "}
|
||||
{Math.min(currentPage * pageSize, filtered.length)} of {filtered.length} results
|
||||
</span>
|
||||
<span>
|
||||
Page {currentPage} of {totalPages}
|
||||
</span>
|
||||
<span>Page {currentPage} of {totalPages}</span>
|
||||
<div className="flex gap-1">
|
||||
<button onClick={() => setCurrentPage((p) => Math.max(1, p - 1))} disabled={currentPage === 1}
|
||||
className="px-3 py-1.5 border rounded-md text-sm hover:bg-gray-50 disabled:opacity-40">Previous</button>
|
||||
<button onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))} disabled={currentPage === totalPages}
|
||||
className="px-3 py-1.5 border rounded-md text-sm hover:bg-gray-50 disabled:opacity-40">Next</button>
|
||||
<button
|
||||
onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}
|
||||
disabled={currentPage === 1}
|
||||
className="px-3 py-1.5 border rounded-md text-sm hover:bg-gray-50 disabled:opacity-40"
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))}
|
||||
disabled={currentPage === totalPages}
|
||||
className="px-3 py-1.5 border rounded-md text-sm hover:bg-gray-50 disabled:opacity-40"
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -309,7 +326,9 @@ export const ToolPolicies: React.FC<ToolPoliciesProps> = ({ accessToken }) => {
|
||||
{isLiveTail && (
|
||||
<div className="bg-green-50 border-b border-green-100 px-6 py-2 flex items-center justify-between">
|
||||
<span className="text-sm text-green-700">Auto-refreshing every 15 seconds</span>
|
||||
<button onClick={() => setIsLiveTail(false)} className="text-xs text-green-600 underline">Stop</button>
|
||||
<button onClick={() => setIsLiveTail(false)} className="text-xs text-green-600 underline">
|
||||
Stop
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -321,20 +340,34 @@ export const ToolPolicies: React.FC<ToolPoliciesProps> = ({ accessToken }) => {
|
||||
<Table className="[&_td]:py-0.5 [&_th]:py-1 w-full">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableHeaderCell className="py-1 h-8"><SortHeader label="Discovered" field="created_at" /></TableHeaderCell>
|
||||
<TableHeaderCell className="py-1 h-8"><SortHeader label="Tool Name" field="tool_name" /></TableHeaderCell>
|
||||
<TableHeaderCell className="py-1 h-8"><SortHeader label="Policy" field="call_policy" /></TableHeaderCell>
|
||||
<TableHeaderCell className="py-1 h-8"><SortHeader label="# Calls" field="call_count" /></TableHeaderCell>
|
||||
<TableHeaderCell className="py-1 h-8"><SortHeader label="Team Name" field="team_id" /></TableHeaderCell>
|
||||
<TableHeaderCell className="py-1 h-8">
|
||||
<SortHeader label="Discovered" field="created_at" />
|
||||
</TableHeaderCell>
|
||||
<TableHeaderCell className="py-1 h-8">
|
||||
<SortHeader label="Tool Name" field="tool_name" />
|
||||
</TableHeaderCell>
|
||||
<TableHeaderCell className="py-1 h-8">
|
||||
<SortHeader label="Policy" field="call_policy" />
|
||||
</TableHeaderCell>
|
||||
<TableHeaderCell className="py-1 h-8">
|
||||
<SortHeader label="# Calls" field="call_count" />
|
||||
</TableHeaderCell>
|
||||
<TableHeaderCell className="py-1 h-8">
|
||||
<SortHeader label="Team Name" field="team_id" />
|
||||
</TableHeaderCell>
|
||||
<TableHeaderCell className="py-1 h-8">Key Hash</TableHeaderCell>
|
||||
<TableHeaderCell className="py-1 h-8"><SortHeader label="Key Name" field="key_alias" /></TableHeaderCell>
|
||||
<TableHeaderCell className="py-1 h-8">
|
||||
<SortHeader label="Key Name" field="key_alias" />
|
||||
</TableHeaderCell>
|
||||
<TableHeaderCell className="py-1 h-8">Origin</TableHeaderCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{loading ? (
|
||||
<TableRow>
|
||||
<TableCell colSpan={8} className="h-8 text-center text-gray-500">Loading tools…</TableCell>
|
||||
<TableCell colSpan={8} className="h-8 text-center text-gray-500">
|
||||
Loading tools…
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
) : paginated.length === 0 ? (
|
||||
<TableRow>
|
||||
@@ -397,12 +430,25 @@ export const ToolPolicies: React.FC<ToolPoliciesProps> = ({ accessToken }) => {
|
||||
{/* Bottom pagination (only when > 1 page) */}
|
||||
{totalPages > 1 && (
|
||||
<div className="border-t px-6 py-3 flex items-center justify-between text-sm text-gray-600">
|
||||
<span>Showing {(currentPage - 1) * pageSize + 1} - {Math.min(currentPage * pageSize, sorted.length)} of {sorted.length}</span>
|
||||
<span>
|
||||
Showing {(currentPage - 1) * pageSize + 1} - {Math.min(currentPage * pageSize, sorted.length)} of{" "}
|
||||
{sorted.length}
|
||||
</span>
|
||||
<div className="flex gap-1">
|
||||
<button onClick={() => setCurrentPage((p) => Math.max(1, p - 1))} disabled={currentPage === 1}
|
||||
className="px-3 py-1.5 border rounded-md hover:bg-gray-50 disabled:opacity-40">Previous</button>
|
||||
<button onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))} disabled={currentPage === totalPages}
|
||||
className="px-3 py-1.5 border rounded-md hover:bg-gray-50 disabled:opacity-40">Next</button>
|
||||
<button
|
||||
onClick={() => setCurrentPage((p) => Math.max(1, p - 1))}
|
||||
disabled={currentPage === 1}
|
||||
className="px-3 py-1.5 border rounded-md hover:bg-gray-50 disabled:opacity-40"
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))}
|
||||
disabled={currentPage === totalPages}
|
||||
className="px-3 py-1.5 border rounded-md hover:bg-gray-50 disabled:opacity-40"
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -8,10 +8,10 @@ import { Accordion, AccordionBody, AccordionHeader, Button, Col, Grid, Text, Tex
|
||||
import { Button as Button2, Form, Input, Modal, Radio, Select, Switch, Tag, Tooltip } from "antd";
|
||||
import debounce from "lodash/debounce";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import { CopyToClipboard } from "react-copy-to-clipboard";
|
||||
import { rolesWithWriteAccess } from "../../utils/roles";
|
||||
import AgentSelector from "../agent_management/AgentSelector";
|
||||
import { mapDisplayToInternalNames } from "../callback_info_helpers";
|
||||
import AccessGroupSelector from "../common_components/AccessGroupSelector";
|
||||
import BudgetDurationDropdown from "../common_components/budget_duration_dropdown";
|
||||
import SchemaFormFields from "../common_components/check_openapi_schema";
|
||||
import KeyLifecycleSettings from "../common_components/KeyLifecycleSettings";
|
||||
@@ -20,7 +20,6 @@ import PassThroughRoutesSelector from "../common_components/PassThroughRoutesSel
|
||||
import PremiumLoggingSettings from "../common_components/PremiumLoggingSettings";
|
||||
import RateLimitTypeFormItem from "../common_components/RateLimitTypeFormItem";
|
||||
import RouterSettingsAccordion, { RouterSettingsAccordionValue } from "../common_components/RouterSettingsAccordion";
|
||||
import AccessGroupSelector from "../common_components/AccessGroupSelector";
|
||||
import TeamDropdown from "../common_components/team_dropdown";
|
||||
import { CreateUserButton } from "../CreateUserButton";
|
||||
import { getModelDisplayName } from "../key_team_helpers/fetch_available_models_team_key";
|
||||
@@ -40,10 +39,10 @@ import {
|
||||
proxyBaseUrl,
|
||||
userFilterUICall,
|
||||
} from "../networking";
|
||||
import CreatedKeyDisplay from "../shared/CreatedKeyDisplay";
|
||||
import NumericalInput from "../shared/numerical_input";
|
||||
import VectorStoreSelector from "../vector_store_management/VectorStoreSelector";
|
||||
import { simplifyKeyGenerateError } from "./utils";
|
||||
import CreatedKeyDisplay from "../shared/CreatedKeyDisplay";
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
@@ -299,7 +298,7 @@ const CreateKey: React.FC<CreateKeyProps> = ({ team, teams, data, addKey }) => {
|
||||
formValues.user_id = userID;
|
||||
} else if (keyOwner === "agent") {
|
||||
if (!selectedAgentId) {
|
||||
message.error("Please select an agent");
|
||||
NotificationsManager.error("Please select an agent");
|
||||
return;
|
||||
}
|
||||
formValues.agent_id = selectedAgentId;
|
||||
@@ -559,7 +558,9 @@ const CreateKey: React.FC<CreateKeyProps> = ({ team, teams, data, addKey }) => {
|
||||
<Radio value="you">You</Radio>
|
||||
<Radio value="service_account">Service Account</Radio>
|
||||
{userRole === "Admin" && <Radio value="another_user">Another User</Radio>}
|
||||
<Radio value="agent">Agent <Tag color="purple">New</Tag></Radio>
|
||||
<Radio value="agent">
|
||||
Agent <Tag color="purple">New</Tag>
|
||||
</Radio>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
|
||||
@@ -1005,9 +1006,7 @@ const CreateKey: React.FC<CreateKeyProps> = ({ team, teams, data, addKey }) => {
|
||||
style={{ width: "100%" }}
|
||||
disabled={!premiumUser}
|
||||
placeholder={
|
||||
!premiumUser
|
||||
? "Premium feature - Upgrade to set policies by key"
|
||||
: "Select or enter policies"
|
||||
!premiumUser ? "Premium feature - Upgrade to set policies by key" : "Select or enter policies"
|
||||
}
|
||||
options={policiesList.map((name) => ({ value: name, label: name }))}
|
||||
/>
|
||||
@@ -1059,9 +1058,7 @@ const CreateKey: React.FC<CreateKeyProps> = ({ team, teams, data, addKey }) => {
|
||||
className="mt-4"
|
||||
help="Select access groups to assign to this key"
|
||||
>
|
||||
<AccessGroupSelector
|
||||
placeholder="Select access groups (optional)"
|
||||
/>
|
||||
<AccessGroupSelector placeholder="Select access groups (optional)" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={
|
||||
@@ -1297,7 +1294,11 @@ const CreateKey: React.FC<CreateKeyProps> = ({ team, teams, data, addKey }) => {
|
||||
accessToken={accessToken || ""}
|
||||
value={routerSettings || undefined}
|
||||
onChange={setRouterSettings}
|
||||
modelData={userModels.length > 0 ? { data: userModels.map((model) => ({ model_name: model })) } : undefined}
|
||||
modelData={
|
||||
userModels.length > 0
|
||||
? { data: userModels.map((model) => ({ model_name: model })) }
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</AccordionBody>
|
||||
|
||||
Reference in New Issue
Block a user