feat: integrate Codex common config snippet and template modal features
- Created useCodexCommonConfig hook for managing Codex TOML common config - Persists to localStorage with key 'cc-switch:codex-common-config-snippet' - Added isCodexTemplateModalOpen state to ProviderForm - Connected all CodexConfigEditor props: - Common config snippet management (useCommonConfig, handlers) - Template modal state (isTemplateModalOpen, setIsTemplateModalOpen) - Form field callbacks (onWebsiteUrlChange, onNameChange) - Custom mode detection (isCustomMode) - Hook structure mirrors useCommonConfigSnippet for consistency
This commit is contained in:
@@ -38,6 +38,7 @@ import {
|
|||||||
useKimiModelSelector,
|
useKimiModelSelector,
|
||||||
useTemplateValues,
|
useTemplateValues,
|
||||||
useCommonConfigSnippet,
|
useCommonConfigSnippet,
|
||||||
|
useCodexCommonConfig,
|
||||||
} from "./hooks";
|
} from "./hooks";
|
||||||
|
|
||||||
const CLAUDE_DEFAULT_CONFIG = JSON.stringify({ env: {}, config: {} }, null, 2);
|
const CLAUDE_DEFAULT_CONFIG = JSON.stringify({ env: {}, config: {} }, null, 2);
|
||||||
@@ -166,6 +167,8 @@ export function ProviderForm({
|
|||||||
|
|
||||||
const [isCodexEndpointModalOpen, setIsCodexEndpointModalOpen] =
|
const [isCodexEndpointModalOpen, setIsCodexEndpointModalOpen] =
|
||||||
useState(false);
|
useState(false);
|
||||||
|
const [isCodexTemplateModalOpen, setIsCodexTemplateModalOpen] =
|
||||||
|
useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
form.reset(defaultValues);
|
form.reset(defaultValues);
|
||||||
@@ -247,6 +250,19 @@ export function ProviderForm({
|
|||||||
initialData: appType === "claude" ? initialData : undefined,
|
initialData: appType === "claude" ? initialData : undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 使用 Codex 通用配置片段 hook (仅 Codex 模式)
|
||||||
|
const {
|
||||||
|
useCommonConfig: useCodexCommonConfigFlag,
|
||||||
|
commonConfigSnippet: codexCommonConfigSnippet,
|
||||||
|
commonConfigError: codexCommonConfigError,
|
||||||
|
handleCommonConfigToggle: handleCodexCommonConfigToggle,
|
||||||
|
handleCommonConfigSnippetChange: handleCodexCommonConfigSnippetChange,
|
||||||
|
} = useCodexCommonConfig({
|
||||||
|
codexConfig,
|
||||||
|
onConfigChange: handleCodexConfigChange,
|
||||||
|
initialData: appType === "codex" ? initialData : undefined,
|
||||||
|
});
|
||||||
|
|
||||||
const [isCommonConfigModalOpen, setIsCommonConfigModalOpen] = useState(false);
|
const [isCommonConfigModalOpen, setIsCommonConfigModalOpen] = useState(false);
|
||||||
|
|
||||||
const handleSubmit = (values: ProviderFormData) => {
|
const handleSubmit = (values: ProviderFormData) => {
|
||||||
@@ -803,12 +819,17 @@ export function ProviderForm({
|
|||||||
configValue={codexConfig}
|
configValue={codexConfig}
|
||||||
onAuthChange={setCodexAuth}
|
onAuthChange={setCodexAuth}
|
||||||
onConfigChange={handleCodexConfigChange}
|
onConfigChange={handleCodexConfigChange}
|
||||||
useCommonConfig={false}
|
useCommonConfig={useCodexCommonConfigFlag}
|
||||||
onCommonConfigToggle={() => {}}
|
onCommonConfigToggle={handleCodexCommonConfigToggle}
|
||||||
commonConfigSnippet=""
|
commonConfigSnippet={codexCommonConfigSnippet}
|
||||||
onCommonConfigSnippetChange={() => {}}
|
onCommonConfigSnippetChange={handleCodexCommonConfigSnippetChange}
|
||||||
commonConfigError=""
|
commonConfigError={codexCommonConfigError}
|
||||||
authError={codexAuthError}
|
authError={codexAuthError}
|
||||||
|
isCustomMode={selectedPresetId === "custom"}
|
||||||
|
onWebsiteUrlChange={(url) => form.setValue("websiteUrl", url)}
|
||||||
|
onNameChange={(name) => form.setValue("name", name)}
|
||||||
|
isTemplateModalOpen={isCodexTemplateModalOpen}
|
||||||
|
setIsTemplateModalOpen={setIsCodexTemplateModalOpen}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<CommonConfigEditor
|
<CommonConfigEditor
|
||||||
|
|||||||
@@ -8,3 +8,4 @@ export { useCustomEndpoints } from "./useCustomEndpoints";
|
|||||||
export { useKimiModelSelector } from "./useKimiModelSelector";
|
export { useKimiModelSelector } from "./useKimiModelSelector";
|
||||||
export { useTemplateValues } from "./useTemplateValues";
|
export { useTemplateValues } from "./useTemplateValues";
|
||||||
export { useCommonConfigSnippet } from "./useCommonConfigSnippet";
|
export { useCommonConfigSnippet } from "./useCommonConfigSnippet";
|
||||||
|
export { useCodexCommonConfig } from "./useCodexCommonConfig";
|
||||||
|
|||||||
187
src/components/providers/forms/hooks/useCodexCommonConfig.ts
Normal file
187
src/components/providers/forms/hooks/useCodexCommonConfig.ts
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
import { useState, useEffect, useCallback, useRef } from "react";
|
||||||
|
import {
|
||||||
|
updateTomlCommonConfigSnippet,
|
||||||
|
hasTomlCommonConfigSnippet,
|
||||||
|
} from "@/utils/providerConfigUtils";
|
||||||
|
|
||||||
|
const CODEX_COMMON_CONFIG_STORAGE_KEY = "cc-switch:codex-common-config-snippet";
|
||||||
|
const DEFAULT_CODEX_COMMON_CONFIG_SNIPPET = `# Common Codex config
|
||||||
|
# Add your common TOML configuration here`;
|
||||||
|
|
||||||
|
interface UseCodexCommonConfigProps {
|
||||||
|
codexConfig: string;
|
||||||
|
onConfigChange: (config: string) => void;
|
||||||
|
initialData?: {
|
||||||
|
settingsConfig?: Record<string, unknown>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理 Codex 通用配置片段 (TOML 格式)
|
||||||
|
*/
|
||||||
|
export function useCodexCommonConfig({
|
||||||
|
codexConfig,
|
||||||
|
onConfigChange,
|
||||||
|
initialData,
|
||||||
|
}: UseCodexCommonConfigProps) {
|
||||||
|
const [useCommonConfig, setUseCommonConfig] = useState(false);
|
||||||
|
const [commonConfigSnippet, setCommonConfigSnippetState] = useState<string>(
|
||||||
|
() => {
|
||||||
|
if (typeof window === "undefined") {
|
||||||
|
return DEFAULT_CODEX_COMMON_CONFIG_SNIPPET;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const stored = window.localStorage.getItem(CODEX_COMMON_CONFIG_STORAGE_KEY);
|
||||||
|
if (stored && stored.trim()) {
|
||||||
|
return stored;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// ignore localStorage 读取失败
|
||||||
|
}
|
||||||
|
return DEFAULT_CODEX_COMMON_CONFIG_SNIPPET;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const [commonConfigError, setCommonConfigError] = useState("");
|
||||||
|
|
||||||
|
// 用于跟踪是否正在通过通用配置更新
|
||||||
|
const isUpdatingFromCommonConfig = useRef(false);
|
||||||
|
|
||||||
|
// 初始化时检查通用配置片段(编辑模式)
|
||||||
|
useEffect(() => {
|
||||||
|
if (initialData?.settingsConfig) {
|
||||||
|
const config =
|
||||||
|
typeof initialData.settingsConfig.config === "string"
|
||||||
|
? initialData.settingsConfig.config
|
||||||
|
: "";
|
||||||
|
const hasCommon = hasTomlCommonConfigSnippet(config, commonConfigSnippet);
|
||||||
|
setUseCommonConfig(hasCommon);
|
||||||
|
}
|
||||||
|
}, [initialData, commonConfigSnippet]);
|
||||||
|
|
||||||
|
// 同步本地存储的通用配置片段
|
||||||
|
useEffect(() => {
|
||||||
|
if (typeof window === "undefined") return;
|
||||||
|
try {
|
||||||
|
if (commonConfigSnippet.trim()) {
|
||||||
|
window.localStorage.setItem(
|
||||||
|
CODEX_COMMON_CONFIG_STORAGE_KEY,
|
||||||
|
commonConfigSnippet,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
window.localStorage.removeItem(CODEX_COMMON_CONFIG_STORAGE_KEY);
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}, [commonConfigSnippet]);
|
||||||
|
|
||||||
|
// 处理通用配置开关
|
||||||
|
const handleCommonConfigToggle = useCallback(
|
||||||
|
(checked: boolean) => {
|
||||||
|
const { updatedConfig, error: snippetError } = updateTomlCommonConfigSnippet(
|
||||||
|
codexConfig,
|
||||||
|
commonConfigSnippet,
|
||||||
|
checked,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (snippetError) {
|
||||||
|
setCommonConfigError(snippetError);
|
||||||
|
setUseCommonConfig(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setCommonConfigError("");
|
||||||
|
setUseCommonConfig(checked);
|
||||||
|
// 标记正在通过通用配置更新
|
||||||
|
isUpdatingFromCommonConfig.current = true;
|
||||||
|
onConfigChange(updatedConfig);
|
||||||
|
// 在下一个事件循环中重置标记
|
||||||
|
setTimeout(() => {
|
||||||
|
isUpdatingFromCommonConfig.current = false;
|
||||||
|
}, 0);
|
||||||
|
},
|
||||||
|
[codexConfig, commonConfigSnippet, onConfigChange],
|
||||||
|
);
|
||||||
|
|
||||||
|
// 处理通用配置片段变化
|
||||||
|
const handleCommonConfigSnippetChange = useCallback(
|
||||||
|
(value: string) => {
|
||||||
|
const previousSnippet = commonConfigSnippet;
|
||||||
|
setCommonConfigSnippetState(value);
|
||||||
|
|
||||||
|
if (!value.trim()) {
|
||||||
|
setCommonConfigError("");
|
||||||
|
if (useCommonConfig) {
|
||||||
|
const { updatedConfig } = updateTomlCommonConfigSnippet(
|
||||||
|
codexConfig,
|
||||||
|
previousSnippet,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
onConfigChange(updatedConfig);
|
||||||
|
setUseCommonConfig(false);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TOML 格式校验较为复杂,暂时不做校验,直接清空错误
|
||||||
|
setCommonConfigError("");
|
||||||
|
|
||||||
|
// 若当前启用通用配置,需要替换为最新片段
|
||||||
|
if (useCommonConfig) {
|
||||||
|
const removeResult = updateTomlCommonConfigSnippet(
|
||||||
|
codexConfig,
|
||||||
|
previousSnippet,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
if (removeResult.error) {
|
||||||
|
setCommonConfigError(removeResult.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const addResult = updateTomlCommonConfigSnippet(
|
||||||
|
removeResult.updatedConfig,
|
||||||
|
value,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (addResult.error) {
|
||||||
|
setCommonConfigError(addResult.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 标记正在通过通用配置更新,避免触发状态检查
|
||||||
|
isUpdatingFromCommonConfig.current = true;
|
||||||
|
onConfigChange(addResult.updatedConfig);
|
||||||
|
// 在下一个事件循环中重置标记
|
||||||
|
setTimeout(() => {
|
||||||
|
isUpdatingFromCommonConfig.current = false;
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[
|
||||||
|
commonConfigSnippet,
|
||||||
|
codexConfig,
|
||||||
|
useCommonConfig,
|
||||||
|
onConfigChange,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// 当配置变化时检查是否包含通用配置(但避免在通过通用配置更新时检查)
|
||||||
|
useEffect(() => {
|
||||||
|
if (isUpdatingFromCommonConfig.current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const hasCommon = hasTomlCommonConfigSnippet(
|
||||||
|
codexConfig,
|
||||||
|
commonConfigSnippet,
|
||||||
|
);
|
||||||
|
setUseCommonConfig(hasCommon);
|
||||||
|
}, [codexConfig, commonConfigSnippet]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
useCommonConfig,
|
||||||
|
commonConfigSnippet,
|
||||||
|
commonConfigError,
|
||||||
|
handleCommonConfigToggle,
|
||||||
|
handleCommonConfigSnippetChange,
|
||||||
|
};
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user