diff --git a/src/components/ProviderForm.tsx b/src/components/ProviderForm.tsx index a4eb9d2..09867a5 100644 --- a/src/components/ProviderForm.tsx +++ b/src/components/ProviderForm.tsx @@ -10,6 +10,7 @@ import { setApiKeyInConfig, } from "../utils/providerConfigUtils"; import { providerPresets } from "../config/providerPresets"; +import { codexProviderPresets } from "../config/codexProviderPresets"; import "./AddProviderModal.css"; interface ProviderFormProps { @@ -45,6 +46,10 @@ const ProviderForm: React.FC = ({ // Codex 特有的状态 const [codexAuth, setCodexAuth] = useState(""); const [codexConfig, setCodexConfig] = useState(""); + const [codexApiKey, setCodexApiKey] = useState(""); + const [selectedCodexPreset, setSelectedCodexPreset] = useState( + null, + ); // 初始化 Codex 配置 useEffect(() => { @@ -53,6 +58,14 @@ const ProviderForm: React.FC = ({ if (typeof config === "object" && config !== null) { setCodexAuth(JSON.stringify(config.auth || {}, null, 2)); setCodexConfig(config.config || ""); + try { + const auth = config.auth || {}; + if (auth && typeof auth.api_key === "string") { + setCodexApiKey(auth.api_key); + } + } catch { + // ignore + } } } }, [isCodex, initialData]); @@ -186,6 +199,33 @@ const ProviderForm: React.FC = ({ setDisableCoAuthored(hasCoAuthoredDisabled); }; + // Codex: 应用预设 + const applyCodexPreset = ( + preset: (typeof codexProviderPresets)[0], + index: number, + ) => { + const authString = JSON.stringify(preset.auth || {}, null, 2); + setCodexAuth(authString); + setCodexConfig(preset.config || ""); + + setFormData({ + name: preset.name, + websiteUrl: preset.websiteUrl, + settingsConfig: formData.settingsConfig, + }); + + setSelectedCodexPreset(index); + + // 同步 API Key 输入框 + try { + const auth = JSON.parse(authString); + const key = typeof auth.api_key === "string" ? auth.api_key : ""; + setCodexApiKey(key); + } catch { + setCodexApiKey(""); + } + }; + // 处理 API Key 输入并自动更新配置 const handleApiKeyChange = (key: string) => { setApiKey(key); @@ -207,6 +247,18 @@ const ProviderForm: React.FC = ({ setDisableCoAuthored(hasCoAuthoredDisabled); }; + // Codex: 处理 API Key 输入并写回 auth.json + const handleCodexApiKeyChange = (key: string) => { + setCodexApiKey(key); + try { + const auth = JSON.parse(codexAuth || "{}"); + auth.api_key = key.trim(); + setCodexAuth(JSON.stringify(auth, null, 2)); + } catch { + // ignore + } + }; + // 根据当前配置决定是否展示 API Key 输入框 const showApiKey = selectedPreset !== null || hasApiKeyField(formData.settingsConfig); @@ -216,6 +268,21 @@ const ProviderForm: React.FC = ({ selectedPreset !== null && providerPresets[selectedPreset]?.isOfficial === true; + // Codex: 控制显示 API Key 与官方标记 + const getCodexAuthApiKey = (authString: string): string => { + try { + const auth = JSON.parse(authString || "{}"); + return typeof auth.api_key === "string" ? auth.api_key : ""; + } catch { + return ""; + } + }; + const showCodexApiKey = + selectedCodexPreset !== null || getCodexAuthApiKey(codexAuth) !== ""; + const isCodexOfficialPreset = + selectedCodexPreset !== null && + codexProviderPresets[selectedCodexPreset]?.isOfficial === true; + // 初始时从配置中同步 API Key(编辑模式) useEffect(() => { if (initialData) { @@ -289,6 +356,26 @@ const ProviderForm: React.FC = ({ )} + {showPresets && isCodex && ( +
+ +
+ {codexProviderPresets.map((preset, index) => ( + + ))} +
+
+ )} +
= ({
)} + {isCodex && ( +
+ + handleCodexApiKeyChange(e.target.value)} + placeholder={ + isCodexOfficialPreset + ? "官方无需填写 API Key,直接保存即可" + : "只需要填这里,上方 auth.json 会自动填充" + } + disabled={isCodexOfficialPreset} + autoComplete="off" + style={ + isCodexOfficialPreset + ? { + backgroundColor: "#f5f5f5", + cursor: "not-allowed", + color: "#999", + } + : {} + } + /> +
+ )} +
= ({