diff --git a/ui/src/components/Providers.tsx b/ui/src/components/Providers.tsx index 6a43bd7..a91762c 100644 --- a/ui/src/components/Providers.tsx +++ b/ui/src/components/Providers.tsx @@ -37,6 +37,7 @@ export function Providers() { const [providerTemplates, setProviderTemplates] = useState([]); const [showApiKey, setShowApiKey] = useState>({}); const [apiKeyError, setApiKeyError] = useState(null); + const [nameError, setNameError] = useState(null); const comboInputRef = useRef(null); useEffect(() => { @@ -100,6 +101,7 @@ export function Providers() { [config.Providers.length]: false })); setApiKeyError(null); + setNameError(null); }; const handleEditProvider = (index: number) => { @@ -113,17 +115,42 @@ export function Providers() { [index]: false })); setApiKeyError(null); + setNameError(null); }; const handleSaveProvider = () => { + if (!editingProviderData) return; + + // Validate name + if (!editingProviderData.name || editingProviderData.name.trim() === '') { + setNameError(t("providers.name_required")); + return; + } + + // Check for duplicate names (case-insensitive) + const trimmedName = editingProviderData.name.trim(); + const isDuplicate = config.Providers.some((provider, index) => { + // For edit mode, skip checking the current provider being edited + if (!isNewProvider && index === editingProviderIndex) { + return false; + } + return provider.name.toLowerCase() === trimmedName.toLowerCase(); + }); + + if (isDuplicate) { + setNameError(t("providers.name_duplicate")); + return; + } + // Validate API key - if (!editingProviderData || !editingProviderData.api_key || editingProviderData.api_key.trim() === '') { + if (!editingProviderData.api_key || editingProviderData.api_key.trim() === '') { setApiKeyError(t("providers.api_key_required")); return; } - // Clear error if validation passes + // Clear errors if validation passes setApiKeyError(null); + setNameError(null); if (editingProviderIndex !== null && editingProviderData) { const newProviders = [...config.Providers]; @@ -166,6 +193,7 @@ export function Providers() { setEditingProviderData(null); setIsNewProvider(false); setApiKeyError(null); + setNameError(null); }; const handleRemoveProvider = (index: number) => { @@ -499,7 +527,21 @@ export function Providers() { )}
- handleProviderChange(editingProviderIndex, 'name', e.target.value)} /> + { + handleProviderChange(editingProviderIndex, 'name', e.target.value); + // Clear name error when user starts typing + if (nameError) { + setNameError(null); + } + }} + className={nameError ? "border-red-500" : ""} + /> + {nameError && ( +

{nameError}

+ )}
diff --git a/ui/src/locales/en.json b/ui/src/locales/en.json index 2287218..c79459d 100644 --- a/ui/src/locales/en.json +++ b/ui/src/locales/en.json @@ -81,7 +81,9 @@ "import_from_template": "Import from template", "no_templates_found": "No templates found", "select_template": "Select a template...", - "api_key_required": "API Key is required" + "api_key_required": "API Key is required", + "name_required": "Name is required", + "name_duplicate": "A provider with this name already exists" }, "router": { diff --git a/ui/src/locales/zh.json b/ui/src/locales/zh.json index 6965a4d..fff7ce3 100644 --- a/ui/src/locales/zh.json +++ b/ui/src/locales/zh.json @@ -81,7 +81,9 @@ "import_from_template": "从模板导入", "no_templates_found": "未找到模板", "select_template": "选择一个模板...", - "api_key_required": "API 密钥为必填项" + "api_key_required": "API 密钥为必填项", + "name_required": "名称为必填项", + "name_duplicate": "已存在同名供应商" }, "router": {