import { IconLoader2 } from "@tabler/icons-react" import { useEffect, useState } from "react" import { useTranslation } from "react-i18next" import { addModel, setDefaultModel } from "@/api/models" import { maskedSecretPlaceholder } from "@/components/secret-placeholder" import { AdvancedSection, Field, KeyInput, SwitchCardField, } from "@/components/shared-form" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Sheet, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, } from "@/components/ui/sheet" interface AddForm { modelName: string model: string apiBase: string apiKey: string proxy: string authMethod: string connectMode: string workspace: string rpm: string maxTokensField: string requestTimeout: string thinkingLevel: string } const EMPTY_ADD_FORM: AddForm = { modelName: "", model: "", apiBase: "", apiKey: "", proxy: "", authMethod: "", connectMode: "", workspace: "", rpm: "", maxTokensField: "", requestTimeout: "", thinkingLevel: "", } interface AddModelSheetProps { open: boolean onClose: () => void onSaved: () => void existingModelNames: string[] } export function AddModelSheet({ open, onClose, onSaved, existingModelNames, }: AddModelSheetProps) { const { t } = useTranslation() const [form, setForm] = useState(EMPTY_ADD_FORM) const [saving, setSaving] = useState(false) const [setAsDefault, setSetAsDefault] = useState(false) const [fieldErrors, setFieldErrors] = useState< Partial> >({}) const [serverError, setServerError] = useState("") const apiKeyPlaceholder = maskedSecretPlaceholder( form.apiKey, t("models.field.apiKeyPlaceholder"), ) useEffect(() => { if (open) { setForm(EMPTY_ADD_FORM) setSetAsDefault(false) setFieldErrors({}) setServerError("") } }, [open]) const validate = (): boolean => { const errors: Partial> = {} const modelName = form.modelName.trim() if (!modelName) { errors.modelName = t("models.add.errorRequired") } else if (existingModelNames.some((name) => name.trim() === modelName)) { errors.modelName = t("models.add.errorDuplicateModelName") } if (!form.model.trim()) errors.model = t("models.add.errorRequired") setFieldErrors(errors) return Object.keys(errors).length === 0 } const setField = (key: keyof AddForm) => (e: React.ChangeEvent) => { setForm((f) => ({ ...f, [key]: e.target.value })) if (fieldErrors[key]) { setFieldErrors((prev) => ({ ...prev, [key]: undefined })) } } const handleSave = async () => { if (!validate()) return setSaving(true) setServerError("") try { const modelName = form.modelName.trim() const modelId = form.model.trim() await addModel({ model_name: modelName, model: modelId, api_base: form.apiBase.trim() || undefined, api_key: form.apiKey.trim() || undefined, proxy: form.proxy.trim() || undefined, auth_method: form.authMethod.trim() || undefined, connect_mode: form.connectMode.trim() || undefined, workspace: form.workspace.trim() || undefined, rpm: form.rpm ? Number(form.rpm) : undefined, max_tokens_field: form.maxTokensField.trim() || undefined, request_timeout: form.requestTimeout ? Number(form.requestTimeout) : undefined, thinking_level: form.thinkingLevel.trim() || undefined, }) if (setAsDefault) { await setDefaultModel(modelName) } onSaved() onClose() } catch (e) { setServerError(e instanceof Error ? e.message : t("models.add.saveError")) } finally { setSaving(false) } } return ( !v && onClose()}> {t("models.add.title")} {t("models.add.description")}
{fieldErrors.modelName && (

{fieldErrors.modelName}

)}
{fieldErrors.model && (

{fieldErrors.model}

)}
setForm((f) => ({ ...f, apiKey: v }))} placeholder={apiKeyPlaceholder} /> {serverError && (

{serverError}

)}
) }