fix ui: add form validator
This commit is contained in:
@@ -69,7 +69,7 @@ const getUseModel = async (req: any, tokenCount: number, config: any) => {
|
|||||||
(p: any) => p.name.toLowerCase() === provider
|
(p: any) => p.name.toLowerCase() === provider
|
||||||
);
|
);
|
||||||
const finalModel = finalProvider?.models?.find(
|
const finalModel = finalProvider?.models?.find(
|
||||||
(m: any) => m.name.toLowerCase() === model
|
(m: any) => m.toLowerCase() === model
|
||||||
);
|
);
|
||||||
if (finalProvider && finalModel) {
|
if (finalProvider && finalModel) {
|
||||||
return `${finalProvider.name},${finalModel}`;
|
return `${finalProvider.name},${finalModel}`;
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ export function Providers() {
|
|||||||
const [isNewProvider, setIsNewProvider] = useState<boolean>(false);
|
const [isNewProvider, setIsNewProvider] = useState<boolean>(false);
|
||||||
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 comboInputRef = useRef<HTMLInputElement>(null);
|
const comboInputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -93,11 +94,12 @@ export function Providers() {
|
|||||||
setEditingProviderIndex(config.Providers.length);
|
setEditingProviderIndex(config.Providers.length);
|
||||||
setEditingProviderData(newProvider);
|
setEditingProviderData(newProvider);
|
||||||
setIsNewProvider(true);
|
setIsNewProvider(true);
|
||||||
// Reset API key visibility when adding new provider
|
// Reset API key visibility and error when adding new provider
|
||||||
setShowApiKey(prev => ({
|
setShowApiKey(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
[config.Providers.length]: false
|
[config.Providers.length]: false
|
||||||
}));
|
}));
|
||||||
|
setApiKeyError(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEditProvider = (index: number) => {
|
const handleEditProvider = (index: number) => {
|
||||||
@@ -105,14 +107,24 @@ export function Providers() {
|
|||||||
setEditingProviderIndex(index);
|
setEditingProviderIndex(index);
|
||||||
setEditingProviderData(JSON.parse(JSON.stringify(provider))); // 深拷贝
|
setEditingProviderData(JSON.parse(JSON.stringify(provider))); // 深拷贝
|
||||||
setIsNewProvider(false);
|
setIsNewProvider(false);
|
||||||
// Reset API key visibility when opening edit dialog
|
// Reset API key visibility and error when opening edit dialog
|
||||||
setShowApiKey(prev => ({
|
setShowApiKey(prev => ({
|
||||||
...prev,
|
...prev,
|
||||||
[index]: false
|
[index]: false
|
||||||
}));
|
}));
|
||||||
|
setApiKeyError(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveProvider = () => {
|
const handleSaveProvider = () => {
|
||||||
|
// Validate API key
|
||||||
|
if (!editingProviderData || !editingProviderData.api_key || editingProviderData.api_key.trim() === '') {
|
||||||
|
setApiKeyError(t("providers.api_key_required"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear error if validation passes
|
||||||
|
setApiKeyError(null);
|
||||||
|
|
||||||
if (editingProviderIndex !== null && editingProviderData) {
|
if (editingProviderIndex !== null && editingProviderData) {
|
||||||
const newProviders = [...config.Providers];
|
const newProviders = [...config.Providers];
|
||||||
if (isNewProvider) {
|
if (isNewProvider) {
|
||||||
@@ -153,6 +165,7 @@ export function Providers() {
|
|||||||
setEditingProviderIndex(null);
|
setEditingProviderIndex(null);
|
||||||
setEditingProviderData(null);
|
setEditingProviderData(null);
|
||||||
setIsNewProvider(false);
|
setIsNewProvider(false);
|
||||||
|
setApiKeyError(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveProvider = (index: number) => {
|
const handleRemoveProvider = (index: number) => {
|
||||||
@@ -500,6 +513,7 @@ export function Providers() {
|
|||||||
type={showApiKey[editingProviderIndex || 0] ? "text" : "password"}
|
type={showApiKey[editingProviderIndex || 0] ? "text" : "password"}
|
||||||
value={editingProvider.api_key || ''}
|
value={editingProvider.api_key || ''}
|
||||||
onChange={(e) => handleProviderChange(editingProviderIndex, 'api_key', e.target.value)}
|
onChange={(e) => handleProviderChange(editingProviderIndex, 'api_key', e.target.value)}
|
||||||
|
className={apiKeyError ? "border-red-500" : ""}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -521,6 +535,9 @@ export function Providers() {
|
|||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
{apiKeyError && (
|
||||||
|
<p className="text-sm text-red-500">{apiKeyError}</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="models">{t("providers.models")}</Label>
|
<Label htmlFor="models">{t("providers.models")}</Label>
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
"providers": {
|
"providers": {
|
||||||
"title": "Providers",
|
"title": "Providers",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"api_base_url": "API Base URL",
|
"api_base_url": "API Full URL",
|
||||||
"api_key": "API Key",
|
"api_key": "API Key",
|
||||||
"models": "Models",
|
"models": "Models",
|
||||||
"models_placeholder": "Enter model name and press Enter to add",
|
"models_placeholder": "Enter model name and press Enter to add",
|
||||||
@@ -80,7 +80,8 @@
|
|||||||
"selected_transformers": "Selected Transformers",
|
"selected_transformers": "Selected Transformers",
|
||||||
"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"
|
||||||
|
|
||||||
},
|
},
|
||||||
"router": {
|
"router": {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
"providers": {
|
"providers": {
|
||||||
"title": "供应商",
|
"title": "供应商",
|
||||||
"name": "名称",
|
"name": "名称",
|
||||||
"api_base_url": "API 基础地址",
|
"api_base_url": "API 完整地址",
|
||||||
"api_key": "API 密钥",
|
"api_key": "API 密钥",
|
||||||
"models": "模型",
|
"models": "模型",
|
||||||
"models_placeholder": "输入模型名称并按回车键添加",
|
"models_placeholder": "输入模型名称并按回车键添加",
|
||||||
@@ -80,7 +80,8 @@
|
|||||||
"selected_transformers": "已选转换器",
|
"selected_transformers": "已选转换器",
|
||||||
"import_from_template": "从模板导入",
|
"import_from_template": "从模板导入",
|
||||||
"no_templates_found": "未找到模板",
|
"no_templates_found": "未找到模板",
|
||||||
"select_template": "选择一个模板..."
|
"select_template": "选择一个模板...",
|
||||||
|
"api_key_required": "API 密钥为必填项"
|
||||||
|
|
||||||
},
|
},
|
||||||
"router": {
|
"router": {
|
||||||
|
|||||||
Reference in New Issue
Block a user