Merge pull request #465 from HynoR/main
fix: check provider name to prevent duplicate name with different config param
This commit is contained in:
@@ -37,6 +37,7 @@ export function Providers() {
|
|||||||
const [providerTemplates, setProviderTemplates] = useState<ProviderType[]>([]);
|
const [providerTemplates, setProviderTemplates] = useState<ProviderType[]>([]);
|
||||||
const [showApiKey, setShowApiKey] = useState<Record<number, boolean>>({});
|
const [showApiKey, setShowApiKey] = useState<Record<number, boolean>>({});
|
||||||
const [apiKeyError, setApiKeyError] = useState<string | null>(null);
|
const [apiKeyError, setApiKeyError] = useState<string | null>(null);
|
||||||
|
const [nameError, setNameError] = useState<string | null>(null);
|
||||||
const comboInputRef = useRef<HTMLInputElement>(null);
|
const comboInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -100,6 +101,7 @@ export function Providers() {
|
|||||||
[config.Providers.length]: false
|
[config.Providers.length]: false
|
||||||
}));
|
}));
|
||||||
setApiKeyError(null);
|
setApiKeyError(null);
|
||||||
|
setNameError(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEditProvider = (index: number) => {
|
const handleEditProvider = (index: number) => {
|
||||||
@@ -113,17 +115,42 @@ export function Providers() {
|
|||||||
[index]: false
|
[index]: false
|
||||||
}));
|
}));
|
||||||
setApiKeyError(null);
|
setApiKeyError(null);
|
||||||
|
setNameError(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveProvider = () => {
|
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
|
// 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"));
|
setApiKeyError(t("providers.api_key_required"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear error if validation passes
|
// Clear errors if validation passes
|
||||||
setApiKeyError(null);
|
setApiKeyError(null);
|
||||||
|
setNameError(null);
|
||||||
|
|
||||||
if (editingProviderIndex !== null && editingProviderData) {
|
if (editingProviderIndex !== null && editingProviderData) {
|
||||||
const newProviders = [...config.Providers];
|
const newProviders = [...config.Providers];
|
||||||
@@ -166,6 +193,7 @@ export function Providers() {
|
|||||||
setEditingProviderData(null);
|
setEditingProviderData(null);
|
||||||
setIsNewProvider(false);
|
setIsNewProvider(false);
|
||||||
setApiKeyError(null);
|
setApiKeyError(null);
|
||||||
|
setNameError(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveProvider = (index: number) => {
|
const handleRemoveProvider = (index: number) => {
|
||||||
@@ -499,7 +527,21 @@ export function Providers() {
|
|||||||
)}
|
)}
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="name">{t("providers.name")}</Label>
|
<Label htmlFor="name">{t("providers.name")}</Label>
|
||||||
<Input id="name" value={editingProvider.name || ''} onChange={(e) => handleProviderChange(editingProviderIndex, 'name', e.target.value)} />
|
<Input
|
||||||
|
id="name"
|
||||||
|
value={editingProvider.name || ''}
|
||||||
|
onChange={(e) => {
|
||||||
|
handleProviderChange(editingProviderIndex, 'name', e.target.value);
|
||||||
|
// Clear name error when user starts typing
|
||||||
|
if (nameError) {
|
||||||
|
setNameError(null);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
className={nameError ? "border-red-500" : ""}
|
||||||
|
/>
|
||||||
|
{nameError && (
|
||||||
|
<p className="text-sm text-red-500">{nameError}</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="api_base_url">{t("providers.api_base_url")}</Label>
|
<Label htmlFor="api_base_url">{t("providers.api_base_url")}</Label>
|
||||||
|
|||||||
@@ -81,7 +81,9 @@
|
|||||||
"import_from_template": "Import from template",
|
"import_from_template": "Import from template",
|
||||||
"no_templates_found": "No templates found",
|
"no_templates_found": "No templates found",
|
||||||
"select_template": "Select a template...",
|
"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": {
|
"router": {
|
||||||
|
|||||||
@@ -81,7 +81,9 @@
|
|||||||
"import_from_template": "从模板导入",
|
"import_from_template": "从模板导入",
|
||||||
"no_templates_found": "未找到模板",
|
"no_templates_found": "未找到模板",
|
||||||
"select_template": "选择一个模板...",
|
"select_template": "选择一个模板...",
|
||||||
"api_key_required": "API 密钥为必填项"
|
"api_key_required": "API 密钥为必填项",
|
||||||
|
"name_required": "名称为必填项",
|
||||||
|
"name_duplicate": "已存在同名供应商"
|
||||||
|
|
||||||
},
|
},
|
||||||
"router": {
|
"router": {
|
||||||
|
|||||||
Reference in New Issue
Block a user