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:
Cursor Agent 2026-04-23 16:39:11 +00:00
parent b1cb0abfd4
commit 3eaaf5ff1a
No known key found for this signature in database

View file

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