mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-04 02:31:27 +00:00
feat(ui): edit_auto_router/edit_auto_router_modal to shadcn
- antd Modal/Button + @tremor Text/TextInput \u2192 shadcn Dialog/Button/ Input. antd Form + AntdSelect preserved (mode='tags' + tokenSepa rators needed for access-group input). - Refactored initializeForm out as useCallback so it's captured in the useEffect deps (React Hooks strict mode). - text-gray-600 \u2192 text-muted-foreground. Gates: TS \u2713 | Build \u2713. Co-authored-by: yuneng-jiang <yuneng-berri@users.noreply.github.com>
This commit is contained in:
parent
b1cb0abfd4
commit
3eaaf5ff1a
1 changed files with 174 additions and 127 deletions
|
|
@ -1,15 +1,28 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { Modal, Form, Button, Select as AntdSelect } from "antd";
|
||||
import { Text, TextInput } from "@tremor/react";
|
||||
import React, { useEffect, useState, useCallback } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Form, Select as AntdSelect } from "antd";
|
||||
import { modelAvailableCall, modelPatchUpdateCall } from "../networking";
|
||||
import { fetchAvailableModels, ModelGroup } from "../playground/llm_calls/fetch_models";
|
||||
import {
|
||||
fetchAvailableModels,
|
||||
ModelGroup,
|
||||
} from "../playground/llm_calls/fetch_models";
|
||||
import RouterConfigBuilder from "../add_model/RouterConfigBuilder";
|
||||
import NotificationsManager from "../molecules/notifications_manager";
|
||||
|
||||
interface EditAutoRouterModalProps {
|
||||
isVisible: boolean;
|
||||
onCancel: () => void;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
onSuccess: (updatedModel: any) => void;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
modelData: any;
|
||||
accessToken: string;
|
||||
userRole: string;
|
||||
|
|
@ -27,22 +40,77 @@ 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 [_showCustomDefaultModel, setShowCustomDefaultModel] =
|
||||
useState<boolean>(false);
|
||||
const [_showCustomEmbeddingModel, setShowCustomEmbeddingModel] =
|
||||
useState<boolean>(false);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const [routerConfig, setRouterConfig] = useState<any>(null);
|
||||
|
||||
const initializeForm = useCallback(() => {
|
||||
try {
|
||||
let parsedConfig = null;
|
||||
if (modelData.litellm_params?.auto_router_config) {
|
||||
if (typeof modelData.litellm_params.auto_router_config === "string") {
|
||||
parsedConfig = JSON.parse(
|
||||
modelData.litellm_params.auto_router_config,
|
||||
);
|
||||
} else {
|
||||
parsedConfig = modelData.litellm_params.auto_router_config;
|
||||
}
|
||||
}
|
||||
|
||||
setRouterConfig(parsedConfig);
|
||||
|
||||
form.setFieldsValue({
|
||||
auto_router_name: modelData.model_name,
|
||||
auto_router_default_model:
|
||||
modelData.litellm_params?.auto_router_default_model || "",
|
||||
auto_router_embedding_model:
|
||||
modelData.litellm_params?.auto_router_embedding_model || "",
|
||||
model_access_group: modelData.model_info?.access_groups || [],
|
||||
});
|
||||
|
||||
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");
|
||||
}
|
||||
}, [form, modelData, modelInfo]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isVisible && modelData) {
|
||||
initializeForm();
|
||||
}
|
||||
}, [isVisible, modelData]);
|
||||
}, [isVisible, modelData, initializeForm]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchModelAccessGroups = async () => {
|
||||
if (!accessToken) return;
|
||||
try {
|
||||
const response = await modelAvailableCall(accessToken, "", "", false, null, true, true);
|
||||
setModelAccessGroups(response["data"].map((model: any) => model["id"]));
|
||||
const response = await modelAvailableCall(
|
||||
accessToken,
|
||||
"",
|
||||
"",
|
||||
false,
|
||||
null,
|
||||
true,
|
||||
true,
|
||||
);
|
||||
setModelAccessGroups(
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
response["data"].map((model: any) => model["id"]),
|
||||
);
|
||||
} catch (error) {
|
||||
console.error("Error fetching model access groups:", error);
|
||||
}
|
||||
|
|
@ -64,38 +132,6 @@ const EditAutoRouterModal: React.FC<EditAutoRouterModalProps> = ({
|
|||
}
|
||||
}, [isVisible, accessToken]);
|
||||
|
||||
const initializeForm = () => {
|
||||
try {
|
||||
// Parse the auto_router_config if it exists and is a string
|
||||
let parsedConfig = null;
|
||||
if (modelData.litellm_params?.auto_router_config) {
|
||||
if (typeof modelData.litellm_params.auto_router_config === "string") {
|
||||
parsedConfig = JSON.parse(modelData.litellm_params.auto_router_config);
|
||||
} else {
|
||||
parsedConfig = modelData.litellm_params.auto_router_config;
|
||||
}
|
||||
}
|
||||
|
||||
setRouterConfig(parsedConfig);
|
||||
|
||||
// Set form values
|
||||
form.setFieldsValue({
|
||||
auto_router_name: modelData.model_name,
|
||||
auto_router_default_model: modelData.litellm_params?.auto_router_default_model || "",
|
||||
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");
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
|
@ -147,101 +183,112 @@ const EditAutoRouterModal: React.FC<EditAutoRouterModalProps> = ({
|
|||
}));
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title="Edit Auto Router Configuration"
|
||||
<Dialog
|
||||
open={isVisible}
|
||||
onCancel={onCancel}
|
||||
footer={[
|
||||
<Button key="cancel" onClick={onCancel}>
|
||||
Cancel
|
||||
</Button>,
|
||||
<Button key="submit" loading={loading} onClick={handleSubmit}>
|
||||
Save Changes
|
||||
</Button>,
|
||||
]}
|
||||
width={1000}
|
||||
destroyOnHidden
|
||||
onOpenChange={(o) => (!o ? onCancel() : undefined)}
|
||||
>
|
||||
<div className="space-y-6">
|
||||
<Text className="text-gray-600">
|
||||
Edit the auto router configuration including routing logic, default models, and access settings.
|
||||
</Text>
|
||||
<DialogContent className="max-w-[1000px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Edit Auto Router Configuration</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="space-y-6">
|
||||
<p className="text-muted-foreground">
|
||||
Edit the auto router configuration including routing logic, default
|
||||
models, and access settings.
|
||||
</p>
|
||||
|
||||
<Form form={form} layout="vertical" className="space-y-4">
|
||||
{/* Auto Router Name */}
|
||||
<Form.Item
|
||||
label="Auto Router Name"
|
||||
name="auto_router_name"
|
||||
rules={[{ required: true, message: "Auto router name is required" }]}
|
||||
>
|
||||
<TextInput placeholder="e.g., auto_router_1, smart_routing" />
|
||||
</Form.Item>
|
||||
|
||||
{/* Router Configuration Builder */}
|
||||
<div className="w-full">
|
||||
<RouterConfigBuilder
|
||||
modelInfo={modelInfo}
|
||||
value={routerConfig}
|
||||
onChange={(config) => {
|
||||
setRouterConfig(config);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Default Model */}
|
||||
<Form.Item
|
||||
label="Default Model"
|
||||
name="auto_router_default_model"
|
||||
rules={[{ required: true, message: "Default model is required" }]}
|
||||
>
|
||||
<AntdSelect
|
||||
placeholder="Select a default model"
|
||||
onChange={(value) => {
|
||||
setShowCustomDefaultModel(value === "custom");
|
||||
}}
|
||||
options={[...modelOptions, { value: "custom", label: "Enter custom model name" }]}
|
||||
showSearch={true}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
{/* Embedding Model */}
|
||||
<Form.Item label="Embedding Model" name="auto_router_embedding_model">
|
||||
<AntdSelect
|
||||
placeholder="Select an embedding model (optional)"
|
||||
onChange={(value) => {
|
||||
setShowCustomEmbeddingModel(value === "custom");
|
||||
}}
|
||||
options={[...modelOptions, { value: "custom", label: "Enter custom model name" }]}
|
||||
showSearch={true}
|
||||
allowClear
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
{/* Model Access Groups - Admin only */}
|
||||
{userRole === "Admin" && (
|
||||
<Form form={form} layout="vertical" className="space-y-4">
|
||||
<Form.Item
|
||||
label="Model Access Groups"
|
||||
name="model_access_group"
|
||||
tooltip="Control who can access this auto router"
|
||||
label="Auto Router Name"
|
||||
name="auto_router_name"
|
||||
rules={[
|
||||
{ required: true, message: "Auto router name is required" },
|
||||
]}
|
||||
>
|
||||
<Input placeholder="e.g., auto_router_1, smart_routing" />
|
||||
</Form.Item>
|
||||
|
||||
<div className="w-full">
|
||||
<RouterConfigBuilder
|
||||
modelInfo={modelInfo}
|
||||
value={routerConfig}
|
||||
onChange={(config) => {
|
||||
setRouterConfig(config);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Form.Item
|
||||
label="Default Model"
|
||||
name="auto_router_default_model"
|
||||
rules={[
|
||||
{ required: true, message: "Default model is required" },
|
||||
]}
|
||||
>
|
||||
<AntdSelect
|
||||
mode="tags"
|
||||
showSearch
|
||||
placeholder="Select existing groups or type to create new ones"
|
||||
optionFilterProp="children"
|
||||
tokenSeparators={[","]}
|
||||
options={modelAccessGroups.map((group) => ({
|
||||
value: group,
|
||||
label: group,
|
||||
}))}
|
||||
maxTagCount="responsive"
|
||||
placeholder="Select a default model"
|
||||
onChange={(value) => {
|
||||
setShowCustomDefaultModel(value === "custom");
|
||||
}}
|
||||
options={[
|
||||
...modelOptions,
|
||||
{ value: "custom", label: "Enter custom model name" },
|
||||
]}
|
||||
showSearch={true}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="Embedding Model"
|
||||
name="auto_router_embedding_model"
|
||||
>
|
||||
<AntdSelect
|
||||
placeholder="Select an embedding model (optional)"
|
||||
onChange={(value) => {
|
||||
setShowCustomEmbeddingModel(value === "custom");
|
||||
}}
|
||||
options={[
|
||||
...modelOptions,
|
||||
{ value: "custom", label: "Enter custom model name" },
|
||||
]}
|
||||
showSearch={true}
|
||||
allowClear
|
||||
/>
|
||||
</Form.Item>
|
||||
)}
|
||||
</Form>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
{userRole === "Admin" && (
|
||||
<Form.Item
|
||||
label="Model Access Groups"
|
||||
name="model_access_group"
|
||||
tooltip="Control who can access this auto router"
|
||||
>
|
||||
<AntdSelect
|
||||
mode="tags"
|
||||
showSearch
|
||||
placeholder="Select existing groups or type to create new ones"
|
||||
optionFilterProp="children"
|
||||
tokenSeparators={[","]}
|
||||
options={modelAccessGroups.map((group) => ({
|
||||
value: group,
|
||||
label: group,
|
||||
}))}
|
||||
maxTagCount="responsive"
|
||||
allowClear
|
||||
/>
|
||||
</Form.Item>
|
||||
)}
|
||||
</Form>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" onClick={onCancel}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button onClick={handleSubmit} disabled={loading}>
|
||||
{loading ? "Saving..." : "Save Changes"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue