feat: add real-time TOML validation for Codex config

- Add smol-toml dependency for client-side TOML parsing
- Create useCodexTomlValidation hook with 500ms debounce
- Display validation errors below config.toml textarea
- Trigger validation on onChange for immediate user feedback
- Backend validation remains as fallback for data integrity
This commit is contained in:
Jason
2025-10-16 23:56:30 +08:00
parent 51c68ef192
commit 54b0b3b139
4 changed files with 102 additions and 7 deletions

View File

@@ -1,4 +1,4 @@
import { useEffect, useMemo, useState } from "react";
import { useEffect, useMemo, useState, useCallback } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { useTranslation } from "react-i18next";
@@ -32,6 +32,7 @@ import {
useCommonConfigSnippet,
useCodexCommonConfig,
useSpeedTestEndpoints,
useCodexTomlValidation,
} from "./hooks";
const CLAUDE_DEFAULT_CONFIG = JSON.stringify({ env: {}, config: {} }, null, 2);
@@ -149,10 +150,19 @@ export function ProviderForm({
setCodexAuth,
handleCodexApiKeyChange,
handleCodexBaseUrlChange,
handleCodexConfigChange,
handleCodexConfigChange: originalHandleCodexConfigChange,
resetCodexConfig,
} = useCodexConfigState({ initialData });
// 使用 Codex TOML 校验 hook (仅 Codex 模式)
const { configError: codexConfigError, debouncedValidate } = useCodexTomlValidation();
// 包装 handleCodexConfigChange添加实时校验
const handleCodexConfigChange = useCallback((value: string) => {
originalHandleCodexConfigChange(value);
debouncedValidate(value);
}, [originalHandleCodexConfigChange, debouncedValidate]);
const [isCodexEndpointModalOpen, setIsCodexEndpointModalOpen] =
useState(false);
const [isCodexTemplateModalOpen, setIsCodexTemplateModalOpen] =
@@ -511,6 +521,7 @@ export function ProviderForm({
onCommonConfigSnippetChange={handleCodexCommonConfigSnippetChange}
commonConfigError={codexCommonConfigError}
authError={codexAuthError}
configError={codexConfigError}
isCustomMode={selectedPresetId === "custom"}
onWebsiteUrlChange={(url) => form.setValue("websiteUrl", url)}
onNameChange={(name) => form.setValue("name", name)}