Revert "fix: improve VS Code config synchronization and code formatting"
This reverts commit 463e430a3d.
This commit is contained in:
@@ -26,8 +26,8 @@ export function AppSwitcher({ activeApp, onSwitch }: AppSwitcherProps) {
|
|||||||
<ClaudeIcon
|
<ClaudeIcon
|
||||||
size={16}
|
size={16}
|
||||||
className={
|
className={
|
||||||
activeApp === "claude"
|
activeApp === "claude"
|
||||||
? "text-[#D97757] dark:text-[#D97757] transition-colors duration-200"
|
? "text-[#D97757] dark:text-[#D97757] transition-colors duration-200"
|
||||||
: "text-gray-500 dark:text-gray-400 group-hover:text-[#D97757] dark:group-hover:text-[#D97757] transition-colors duration-200"
|
: "text-gray-500 dark:text-gray-400 group-hover:text-[#D97757] dark:group-hover:text-[#D97757] transition-colors duration-200"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ const JsonEditor: React.FC<JsonEditorProps> = ({
|
|||||||
|
|
||||||
return diagnostics;
|
return diagnostics;
|
||||||
}),
|
}),
|
||||||
[showValidation],
|
[showValidation]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -128,26 +128,25 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
|
|||||||
const [settingsConfigError, setSettingsConfigError] = useState("");
|
const [settingsConfigError, setSettingsConfigError] = useState("");
|
||||||
// 用于跟踪是否正在通过通用配置更新
|
// 用于跟踪是否正在通过通用配置更新
|
||||||
const isUpdatingFromCommonConfig = useRef(false);
|
const isUpdatingFromCommonConfig = useRef(false);
|
||||||
|
|
||||||
// Codex 通用配置状态
|
// Codex 通用配置状态
|
||||||
const [useCodexCommonConfig, setUseCodexCommonConfig] = useState(false);
|
const [useCodexCommonConfig, setUseCodexCommonConfig] = useState(false);
|
||||||
const [codexCommonConfigSnippet, setCodexCommonConfigSnippetState] =
|
const [codexCommonConfigSnippet, setCodexCommonConfigSnippetState] = useState<string>(() => {
|
||||||
useState<string>(() => {
|
if (typeof window === "undefined") {
|
||||||
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;
|
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 [codexCommonConfigError, setCodexCommonConfigError] = useState("");
|
const [codexCommonConfigError, setCodexCommonConfigError] = useState("");
|
||||||
const isUpdatingFromCodexCommonConfig = useRef(false);
|
const isUpdatingFromCodexCommonConfig = useRef(false);
|
||||||
// -1 表示自定义,null 表示未选择,>= 0 表示预设索引
|
// -1 表示自定义,null 表示未选择,>= 0 表示预设索引
|
||||||
@@ -218,11 +217,7 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (initialData) {
|
if (initialData) {
|
||||||
if (!isCodex) {
|
if (!isCodex) {
|
||||||
const configString = JSON.stringify(
|
const configString = JSON.stringify(initialData.settingsConfig, null, 2);
|
||||||
initialData.settingsConfig,
|
|
||||||
null,
|
|
||||||
2,
|
|
||||||
);
|
|
||||||
const hasCommon = hasCommonConfigSnippet(
|
const hasCommon = hasCommonConfigSnippet(
|
||||||
configString,
|
configString,
|
||||||
commonConfigSnippet,
|
commonConfigSnippet,
|
||||||
@@ -240,9 +235,7 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
|
|||||||
};
|
};
|
||||||
if (config.env) {
|
if (config.env) {
|
||||||
setClaudeModel(config.env.ANTHROPIC_MODEL || "");
|
setClaudeModel(config.env.ANTHROPIC_MODEL || "");
|
||||||
setClaudeSmallFastModel(
|
setClaudeSmallFastModel(config.env.ANTHROPIC_SMALL_FAST_MODEL || "");
|
||||||
config.env.ANTHROPIC_SMALL_FAST_MODEL || "",
|
|
||||||
);
|
|
||||||
setBaseUrl(config.env.ANTHROPIC_BASE_URL || ""); // 初始化基础 URL
|
setBaseUrl(config.env.ANTHROPIC_BASE_URL || ""); // 初始化基础 URL
|
||||||
|
|
||||||
// 初始化 Kimi 模型选择
|
// 初始化 Kimi 模型选择
|
||||||
@@ -261,13 +254,7 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
|
|||||||
setUseCodexCommonConfig(hasCommon);
|
setUseCodexCommonConfig(hasCommon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [
|
}, [initialData, commonConfigSnippet, codexCommonConfigSnippet, isCodex, codexConfig]);
|
||||||
initialData,
|
|
||||||
commonConfigSnippet,
|
|
||||||
codexCommonConfigSnippet,
|
|
||||||
isCodex,
|
|
||||||
codexConfig,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 当选择预设变化时,同步类别
|
// 当选择预设变化时,同步类别
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -510,7 +497,7 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
|
|||||||
isUpdatingFromCommonConfig.current = false;
|
isUpdatingFromCommonConfig.current = false;
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存通用配置到 localStorage
|
// 保存通用配置到 localStorage
|
||||||
if (!validationError && typeof window !== "undefined") {
|
if (!validationError && typeof window !== "undefined") {
|
||||||
try {
|
try {
|
||||||
@@ -542,7 +529,10 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
|
|||||||
setBaseUrl(""); // 清空基础 URL
|
setBaseUrl(""); // 清空基础 URL
|
||||||
|
|
||||||
// 同步通用配置状态
|
// 同步通用配置状态
|
||||||
const hasCommon = hasCommonConfigSnippet(configString, commonConfigSnippet);
|
const hasCommon = hasCommonConfigSnippet(
|
||||||
|
configString,
|
||||||
|
commonConfigSnippet,
|
||||||
|
);
|
||||||
setUseCommonConfig(hasCommon);
|
setUseCommonConfig(hasCommon);
|
||||||
setCommonConfigError("");
|
setCommonConfigError("");
|
||||||
|
|
||||||
@@ -653,7 +643,10 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
|
|||||||
updateSettingsConfigValue(configString);
|
updateSettingsConfigValue(configString);
|
||||||
|
|
||||||
// 同步通用配置开关
|
// 同步通用配置开关
|
||||||
const hasCommon = hasCommonConfigSnippet(configString, commonConfigSnippet);
|
const hasCommon = hasCommonConfigSnippet(
|
||||||
|
configString,
|
||||||
|
commonConfigSnippet,
|
||||||
|
);
|
||||||
setUseCommonConfig(hasCommon);
|
setUseCommonConfig(hasCommon);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -688,12 +681,11 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
|
|||||||
|
|
||||||
// Codex: 处理通用配置开关
|
// Codex: 处理通用配置开关
|
||||||
const handleCodexCommonConfigToggle = (checked: boolean) => {
|
const handleCodexCommonConfigToggle = (checked: boolean) => {
|
||||||
const { updatedConfig, error: snippetError } =
|
const { updatedConfig, error: snippetError } = updateTomlCommonConfigSnippet(
|
||||||
updateTomlCommonConfigSnippet(
|
codexConfig,
|
||||||
codexConfig,
|
codexCommonConfigSnippet,
|
||||||
codexCommonConfigSnippet,
|
checked,
|
||||||
checked,
|
);
|
||||||
);
|
|
||||||
|
|
||||||
if (snippetError) {
|
if (snippetError) {
|
||||||
setCodexCommonConfigError(snippetError);
|
setCodexCommonConfigError(snippetError);
|
||||||
@@ -761,7 +753,10 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
|
|||||||
// 保存 Codex 通用配置到 localStorage
|
// 保存 Codex 通用配置到 localStorage
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined") {
|
||||||
try {
|
try {
|
||||||
window.localStorage.setItem(CODEX_COMMON_CONFIG_STORAGE_KEY, value);
|
window.localStorage.setItem(
|
||||||
|
CODEX_COMMON_CONFIG_STORAGE_KEY,
|
||||||
|
value,
|
||||||
|
);
|
||||||
} catch {
|
} catch {
|
||||||
// ignore localStorage 写入失败
|
// ignore localStorage 写入失败
|
||||||
}
|
}
|
||||||
@@ -1182,9 +1177,7 @@ const ProviderForm: React.FC<ProviderFormProps> = ({
|
|||||||
useCommonConfig={useCodexCommonConfig}
|
useCommonConfig={useCodexCommonConfig}
|
||||||
onCommonConfigToggle={handleCodexCommonConfigToggle}
|
onCommonConfigToggle={handleCodexCommonConfigToggle}
|
||||||
commonConfigSnippet={codexCommonConfigSnippet}
|
commonConfigSnippet={codexCommonConfigSnippet}
|
||||||
onCommonConfigSnippetChange={
|
onCommonConfigSnippetChange={handleCodexCommonConfigSnippetChange}
|
||||||
handleCodexCommonConfigSnippetChange
|
|
||||||
}
|
|
||||||
commonConfigError={codexCommonConfigError}
|
commonConfigError={codexCommonConfigError}
|
||||||
authError={codexAuthError}
|
authError={codexAuthError}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ const ClaudeConfigEditor: React.FC<ClaudeConfigEditorProps> = ({
|
|||||||
// 支持按下 ESC 关闭弹窗
|
// 支持按下 ESC 关闭弹窗
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isCommonConfigModalOpen) return;
|
if (!isCommonConfigModalOpen) return;
|
||||||
|
|
||||||
const onKeyDown = (e: KeyboardEvent) => {
|
const onKeyDown = (e: KeyboardEvent) => {
|
||||||
if (e.key === "Escape") {
|
if (e.key === "Escape") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -120,13 +120,15 @@ const ClaudeConfigEditor: React.FC<ClaudeConfigEditorProps> = ({
|
|||||||
rows={12}
|
rows={12}
|
||||||
/>
|
/>
|
||||||
{configError && (
|
{configError && (
|
||||||
<p className="text-xs text-red-500 dark:text-red-400">{configError}</p>
|
<p className="text-xs text-red-500 dark:text-red-400">
|
||||||
|
{configError}
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
<p className="text-xs text-gray-500 dark:text-gray-400">
|
<p className="text-xs text-gray-500 dark:text-gray-400">
|
||||||
完整的 Claude Code settings.json 配置内容
|
完整的 Claude Code settings.json 配置内容
|
||||||
</p>
|
</p>
|
||||||
{isCommonConfigModalOpen && (
|
{isCommonConfigModalOpen && (
|
||||||
<div
|
<div
|
||||||
className="fixed inset-0 z-50 flex items-center justify-center"
|
className="fixed inset-0 z-50 flex items-center justify-center"
|
||||||
onMouseDown={(e) => {
|
onMouseDown={(e) => {
|
||||||
if (e.target === e.currentTarget) closeModal();
|
if (e.target === e.currentTarget) closeModal();
|
||||||
@@ -134,7 +136,7 @@ const ClaudeConfigEditor: React.FC<ClaudeConfigEditorProps> = ({
|
|||||||
>
|
>
|
||||||
{/* Backdrop - 统一背景样式 */}
|
{/* Backdrop - 统一背景样式 */}
|
||||||
<div className="absolute inset-0 bg-black/50 dark:bg-black/70 backdrop-blur-sm" />
|
<div className="absolute inset-0 bg-black/50 dark:bg-black/70 backdrop-blur-sm" />
|
||||||
|
|
||||||
{/* Modal - 统一窗口样式 */}
|
{/* Modal - 统一窗口样式 */}
|
||||||
<div className="relative bg-white dark:bg-gray-900 rounded-xl shadow-lg max-w-2xl w-full mx-4 max-h-[90vh] overflow-hidden flex flex-col">
|
<div className="relative bg-white dark:bg-gray-900 rounded-xl shadow-lg max-w-2xl w-full mx-4 max-h-[90vh] overflow-hidden flex flex-col">
|
||||||
{/* Header - 统一标题栏样式 */}
|
{/* Header - 统一标题栏样式 */}
|
||||||
@@ -151,7 +153,7 @@ const ClaudeConfigEditor: React.FC<ClaudeConfigEditorProps> = ({
|
|||||||
<X size={18} />
|
<X size={18} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Content - 统一内容区域样式 */}
|
{/* Content - 统一内容区域样式 */}
|
||||||
<div className="flex-1 overflow-auto p-6 space-y-4">
|
<div className="flex-1 overflow-auto p-6 space-y-4">
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||||
@@ -169,7 +171,7 @@ const ClaudeConfigEditor: React.FC<ClaudeConfigEditorProps> = ({
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Footer - 统一底部按钮样式 */}
|
{/* Footer - 统一底部按钮样式 */}
|
||||||
<div className="flex items-center justify-end gap-3 p-6 border-t border-gray-200 dark:border-gray-800 bg-gray-100 dark:bg-gray-800">
|
<div className="flex items-center justify-end gap-3 p-6 border-t border-gray-200 dark:border-gray-800 bg-gray-100 dark:bg-gray-800">
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect, useRef } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { X, Save } from "lucide-react";
|
import { X, Save } from "lucide-react";
|
||||||
import { extractBaseUrlFromToml } from "../../utils/providerConfigUtils";
|
import { extractBaseUrlFromToml } from "../../utils/providerConfigUtils";
|
||||||
|
|
||||||
@@ -34,7 +34,6 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
|
|||||||
const [vscodeError, setVscodeError] = useState("");
|
const [vscodeError, setVscodeError] = useState("");
|
||||||
const [vscodeSuccess, setVscodeSuccess] = useState("");
|
const [vscodeSuccess, setVscodeSuccess] = useState("");
|
||||||
const [isWritingVscode, setIsWritingVscode] = useState(false);
|
const [isWritingVscode, setIsWritingVscode] = useState(false);
|
||||||
const lastAppliedBaseUrlRef = useRef<string | null>(null);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (commonConfigError && !isCommonConfigModalOpen) {
|
if (commonConfigError && !isCommonConfigModalOpen) {
|
||||||
@@ -50,61 +49,6 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
|
|||||||
return () => window.clearTimeout(timer);
|
return () => window.clearTimeout(timer);
|
||||||
}, [vscodeSuccess]);
|
}, [vscodeSuccess]);
|
||||||
|
|
||||||
const ensureVscodeApiAvailable = () => {
|
|
||||||
if (typeof window === "undefined" || !window.api?.writeVscodeSettings) {
|
|
||||||
setVscodeError("当前环境暂不支持写入 VS Code 配置");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
const applyVscodeConfig = async (
|
|
||||||
baseUrl: string,
|
|
||||||
successMessage = "已写入 VS Code 配置",
|
|
||||||
) => {
|
|
||||||
if (!ensureVscodeApiAvailable()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsWritingVscode(true);
|
|
||||||
try {
|
|
||||||
const success = await window.api.writeVscodeSettings(baseUrl);
|
|
||||||
if (success) {
|
|
||||||
setVscodeSuccess(successMessage);
|
|
||||||
lastAppliedBaseUrlRef.current = baseUrl;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
setVscodeError("写入 VS Code 配置失败,请稍后重试");
|
|
||||||
} catch (error) {
|
|
||||||
setVscodeError(`写入 VS Code 配置失败: ${String(error)}`);
|
|
||||||
} finally {
|
|
||||||
setIsWritingVscode(false);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const removeVscodeConfig = async () => {
|
|
||||||
if (!ensureVscodeApiAvailable()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsWritingVscode(true);
|
|
||||||
try {
|
|
||||||
const success = await window.api.writeVscodeSettings();
|
|
||||||
if (success) {
|
|
||||||
setVscodeSuccess("已移除 VS Code 配置");
|
|
||||||
lastAppliedBaseUrlRef.current = null;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
setVscodeError("移除 VS Code 配置失败,请稍后重试");
|
|
||||||
} catch (error) {
|
|
||||||
setVscodeError(`移除 VS Code 配置失败: ${String(error)}`);
|
|
||||||
} finally {
|
|
||||||
setIsWritingVscode(false);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleVscodeConfigToggle = async (checked: boolean) => {
|
const handleVscodeConfigToggle = async (checked: boolean) => {
|
||||||
if (isWritingVscode) return;
|
if (isWritingVscode) return;
|
||||||
|
|
||||||
@@ -112,6 +56,12 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
|
|||||||
setVscodeError("");
|
setVscodeError("");
|
||||||
setVscodeSuccess("");
|
setVscodeSuccess("");
|
||||||
|
|
||||||
|
if (typeof window === "undefined" || !window.api?.writeVscodeSettings) {
|
||||||
|
setVscodeError("当前环境暂不支持写入 VS Code 配置");
|
||||||
|
setWriteVscodeConfig(!checked);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (checked) {
|
if (checked) {
|
||||||
const trimmed = configValue.trim();
|
const trimmed = configValue.trim();
|
||||||
if (!trimmed) {
|
if (!trimmed) {
|
||||||
@@ -127,70 +77,46 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const success = await applyVscodeConfig(baseUrl);
|
|
||||||
if (!success) {
|
|
||||||
setWriteVscodeConfig(false);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const success = await removeVscodeConfig();
|
|
||||||
if (!success) {
|
|
||||||
setWriteVscodeConfig(true);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!writeVscodeConfig || isWritingVscode) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const trimmed = configValue.trim();
|
|
||||||
if (!trimmed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const baseUrl = extractBaseUrlFromToml(trimmed);
|
|
||||||
if (!baseUrl) {
|
|
||||||
setVscodeError("未在 config.toml 中找到 base_url 字段");
|
|
||||||
setWriteVscodeConfig(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastAppliedBaseUrlRef.current === baseUrl) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sync = async () => {
|
|
||||||
// 直接调用 API 而不依赖 applyVscodeConfig 函数,避免闭包问题
|
|
||||||
if (typeof window === "undefined" || !window.api?.writeVscodeSettings) {
|
|
||||||
setVscodeError("当前环境暂不支持写入 VS Code 配置");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsWritingVscode(true);
|
setIsWritingVscode(true);
|
||||||
try {
|
try {
|
||||||
const success = await window.api.writeVscodeSettings(baseUrl);
|
const success = await window.api.writeVscodeSettings(baseUrl);
|
||||||
if (success) {
|
if (success) {
|
||||||
setVscodeSuccess("已更新 VS Code 配置");
|
setVscodeSuccess("已写入 VS Code 配置");
|
||||||
lastAppliedBaseUrlRef.current = baseUrl;
|
|
||||||
} else {
|
} else {
|
||||||
setVscodeError("写入 VS Code 配置失败,请稍后重试");
|
setVscodeError("写入 VS Code 配置失败,请稍后重试");
|
||||||
|
setWriteVscodeConfig(false);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setVscodeError(`写入 VS Code 配置失败: ${String(error)}`);
|
setVscodeError(`写入 VS Code 配置失败: ${String(error)}`);
|
||||||
|
setWriteVscodeConfig(false);
|
||||||
} finally {
|
} finally {
|
||||||
setIsWritingVscode(false);
|
setIsWritingVscode(false);
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
sync();
|
return;
|
||||||
}, [configValue, writeVscodeConfig, isWritingVscode]);
|
}
|
||||||
|
|
||||||
|
setIsWritingVscode(true);
|
||||||
|
try {
|
||||||
|
const success = await window.api.writeVscodeSettings();
|
||||||
|
if (success) {
|
||||||
|
setVscodeSuccess("已移除 VS Code 配置");
|
||||||
|
} else {
|
||||||
|
setVscodeError("移除 VS Code 配置失败,请稍后重试");
|
||||||
|
setWriteVscodeConfig(true);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
setVscodeError(`移除 VS Code 配置失败: ${String(error)}`);
|
||||||
|
setWriteVscodeConfig(true);
|
||||||
|
} finally {
|
||||||
|
setIsWritingVscode(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 支持按下 ESC 关闭弹窗
|
// 支持按下 ESC 关闭弹窗
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isCommonConfigModalOpen) return;
|
if (!isCommonConfigModalOpen) return;
|
||||||
|
|
||||||
const onKeyDown = (e: KeyboardEvent) => {
|
const onKeyDown = (e: KeyboardEvent) => {
|
||||||
if (e.key === "Escape") {
|
if (e.key === "Escape") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -236,7 +162,9 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
|
|||||||
data-enable-grammarly="false"
|
data-enable-grammarly="false"
|
||||||
/>
|
/>
|
||||||
{authError && (
|
{authError && (
|
||||||
<p className="text-xs text-red-500 dark:text-red-400">{authError}</p>
|
<p className="text-xs text-red-500 dark:text-red-400">
|
||||||
|
{authError}
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
<p className="text-xs text-gray-500 dark:text-gray-400">
|
<p className="text-xs text-gray-500 dark:text-gray-400">
|
||||||
Codex auth.json 配置内容
|
Codex auth.json 配置内容
|
||||||
@@ -251,7 +179,7 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
|
|||||||
>
|
>
|
||||||
config.toml (TOML)
|
config.toml (TOML)
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
{/* 右侧对齐的双列布局 - 使用flex而非grid以更好控制宽度 */}
|
{/* 右侧对齐的双列布局 - 使用flex而非grid以更好控制宽度 */}
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
{/* 左列:VS Code 配置 */}
|
{/* 左列:VS Code 配置 */}
|
||||||
@@ -273,16 +201,13 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
{vscodeError && (
|
{vscodeError && (
|
||||||
<p
|
<p className="text-xs text-red-500 dark:text-red-400 text-right truncate" title={vscodeError}>
|
||||||
className="text-xs text-red-500 dark:text-red-400 text-right truncate"
|
|
||||||
title={vscodeError}
|
|
||||||
>
|
|
||||||
{vscodeError}
|
{vscodeError}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 右列:通用配置 - 不设置宽度,让内容自然收缩 */}
|
{/* 右列:通用配置 - 不设置宽度,让内容自然收缩 */}
|
||||||
<div className="flex flex-col items-end space-y-1">
|
<div className="flex flex-col items-end space-y-1">
|
||||||
<label className="inline-flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400 cursor-pointer">
|
<label className="inline-flex items-center gap-2 text-sm text-gray-500 dark:text-gray-400 cursor-pointer">
|
||||||
@@ -302,17 +227,14 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
|
|||||||
编辑通用配置
|
编辑通用配置
|
||||||
</button>
|
</button>
|
||||||
{commonConfigError && !isCommonConfigModalOpen && (
|
{commonConfigError && !isCommonConfigModalOpen && (
|
||||||
<p
|
<p className="text-xs text-red-500 dark:text-red-400 mt-1 max-w-[120px] truncate" title={commonConfigError}>
|
||||||
className="text-xs text-red-500 dark:text-red-400 mt-1 max-w-[120px] truncate"
|
|
||||||
title={commonConfigError}
|
|
||||||
>
|
|
||||||
{commonConfigError}
|
{commonConfigError}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<textarea
|
<textarea
|
||||||
id="codexConfig"
|
id="codexConfig"
|
||||||
value={configValue}
|
value={configValue}
|
||||||
@@ -336,7 +258,7 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isCommonConfigModalOpen && (
|
{isCommonConfigModalOpen && (
|
||||||
<div
|
<div
|
||||||
className="fixed inset-0 z-50 flex items-center justify-center"
|
className="fixed inset-0 z-50 flex items-center justify-center"
|
||||||
onMouseDown={(e) => {
|
onMouseDown={(e) => {
|
||||||
if (e.target === e.currentTarget) closeModal();
|
if (e.target === e.currentTarget) closeModal();
|
||||||
@@ -344,7 +266,7 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
|
|||||||
>
|
>
|
||||||
{/* Backdrop - 统一背景样式 */}
|
{/* Backdrop - 统一背景样式 */}
|
||||||
<div className="absolute inset-0 bg-black/50 dark:bg-black/70 backdrop-blur-sm" />
|
<div className="absolute inset-0 bg-black/50 dark:bg-black/70 backdrop-blur-sm" />
|
||||||
|
|
||||||
{/* Modal - 统一窗口样式 */}
|
{/* Modal - 统一窗口样式 */}
|
||||||
<div className="relative bg-white dark:bg-gray-900 rounded-xl shadow-lg max-w-2xl w-full mx-4 max-h-[90vh] overflow-hidden flex flex-col">
|
<div className="relative bg-white dark:bg-gray-900 rounded-xl shadow-lg max-w-2xl w-full mx-4 max-h-[90vh] overflow-hidden flex flex-col">
|
||||||
{/* Header - 统一标题栏样式 */}
|
{/* Header - 统一标题栏样式 */}
|
||||||
@@ -361,7 +283,7 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
|
|||||||
<X size={18} />
|
<X size={18} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Content - 统一内容区域样式 */}
|
{/* Content - 统一内容区域样式 */}
|
||||||
<div className="flex-1 overflow-auto p-6 space-y-4">
|
<div className="flex-1 overflow-auto p-6 space-y-4">
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||||
@@ -390,7 +312,7 @@ const CodexConfigEditor: React.FC<CodexConfigEditorProps> = ({
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Footer - 统一底部按钮样式 */}
|
{/* Footer - 统一底部按钮样式 */}
|
||||||
<div className="flex items-center justify-end gap-3 p-6 border-t border-gray-200 dark:border-gray-800 bg-gray-100 dark:bg-gray-800">
|
<div className="flex items-center justify-end gap-3 p-6 border-t border-gray-200 dark:border-gray-800 bg-gray-100 dark:bg-gray-800">
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -35,4 +35,4 @@ export const extractErrorMessage = (error: unknown): string => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
};
|
};
|
||||||
@@ -22,10 +22,7 @@ const deepMerge = (
|
|||||||
return target;
|
return target;
|
||||||
};
|
};
|
||||||
|
|
||||||
const deepRemove = (
|
const deepRemove = (target: Record<string, any>, source: Record<string, any>) => {
|
||||||
target: Record<string, any>,
|
|
||||||
source: Record<string, any>,
|
|
||||||
) => {
|
|
||||||
Object.entries(source).forEach(([key, value]) => {
|
Object.entries(source).forEach(([key, value]) => {
|
||||||
if (!(key in target)) return;
|
if (!(key in target)) return;
|
||||||
|
|
||||||
@@ -62,7 +59,7 @@ const isSubset = (target: any, source: any): boolean => {
|
|||||||
const deepClone = <T>(obj: T): T => {
|
const deepClone = <T>(obj: T): T => {
|
||||||
if (obj === null || typeof obj !== "object") return obj;
|
if (obj === null || typeof obj !== "object") return obj;
|
||||||
if (obj instanceof Date) return new Date(obj.getTime()) as T;
|
if (obj instanceof Date) return new Date(obj.getTime()) as T;
|
||||||
if (obj instanceof Array) return obj.map((item) => deepClone(item)) as T;
|
if (obj instanceof Array) return obj.map(item => deepClone(item)) as T;
|
||||||
if (obj instanceof Object) {
|
if (obj instanceof Object) {
|
||||||
const clonedObj = {} as T;
|
const clonedObj = {} as T;
|
||||||
for (const key in obj) {
|
for (const key in obj) {
|
||||||
@@ -81,10 +78,7 @@ export interface UpdateCommonConfigResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 验证JSON配置格式
|
// 验证JSON配置格式
|
||||||
export const validateJsonConfig = (
|
export const validateJsonConfig = (value: string, fieldName: string = "配置"): string => {
|
||||||
value: string,
|
|
||||||
fieldName: string = "配置",
|
|
||||||
): string => {
|
|
||||||
if (!value.trim()) {
|
if (!value.trim()) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@@ -129,7 +123,7 @@ export const updateCommonConfigSnippet = (
|
|||||||
error: snippetError,
|
error: snippetError,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const snippet = JSON.parse(snippetString) as Record<string, any>;
|
const snippet = JSON.parse(snippetString) as Record<string, any>;
|
||||||
|
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
@@ -253,23 +247,23 @@ export const updateTomlCommonConfigSnippet = (
|
|||||||
const removeTomlCommonConfig = (tomlString: string): string => {
|
const removeTomlCommonConfig = (tomlString: string): string => {
|
||||||
const startIdx = tomlString.indexOf(COMMON_CONFIG_MARKER_START);
|
const startIdx = tomlString.indexOf(COMMON_CONFIG_MARKER_START);
|
||||||
const endIdx = tomlString.indexOf(COMMON_CONFIG_MARKER_END);
|
const endIdx = tomlString.indexOf(COMMON_CONFIG_MARKER_END);
|
||||||
|
|
||||||
if (startIdx === -1 || endIdx === -1) {
|
if (startIdx === -1 || endIdx === -1) {
|
||||||
return tomlString;
|
return tomlString;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 找到标记前的换行符(如果有)
|
// 找到标记前的换行符(如果有)
|
||||||
let realStartIdx = startIdx;
|
let realStartIdx = startIdx;
|
||||||
if (startIdx > 0 && tomlString[startIdx - 1] === "\n") {
|
if (startIdx > 0 && tomlString[startIdx - 1] === '\n') {
|
||||||
realStartIdx = startIdx - 1;
|
realStartIdx = startIdx - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 找到标记后的换行符(如果有)
|
// 找到标记后的换行符(如果有)
|
||||||
let realEndIdx = endIdx + COMMON_CONFIG_MARKER_END.length;
|
let realEndIdx = endIdx + COMMON_CONFIG_MARKER_END.length;
|
||||||
if (realEndIdx < tomlString.length && tomlString[realEndIdx] === "\n") {
|
if (realEndIdx < tomlString.length && tomlString[realEndIdx] === '\n') {
|
||||||
realEndIdx = realEndIdx + 1;
|
realEndIdx = realEndIdx + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tomlString.slice(0, realStartIdx) + tomlString.slice(realEndIdx);
|
return tomlString.slice(0, realStartIdx) + tomlString.slice(realEndIdx);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -279,19 +273,19 @@ export const hasTomlCommonConfigSnippet = (
|
|||||||
snippetString: string,
|
snippetString: string,
|
||||||
): boolean => {
|
): boolean => {
|
||||||
if (!snippetString.trim()) return false;
|
if (!snippetString.trim()) return false;
|
||||||
|
|
||||||
const startIdx = tomlString.indexOf(COMMON_CONFIG_MARKER_START);
|
const startIdx = tomlString.indexOf(COMMON_CONFIG_MARKER_START);
|
||||||
const endIdx = tomlString.indexOf(COMMON_CONFIG_MARKER_END);
|
const endIdx = tomlString.indexOf(COMMON_CONFIG_MARKER_END);
|
||||||
|
|
||||||
if (startIdx === -1 || endIdx === -1 || startIdx >= endIdx) {
|
if (startIdx === -1 || endIdx === -1 || startIdx >= endIdx) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 提取标记之间的内容
|
// 提取标记之间的内容
|
||||||
const existingSnippet = tomlString
|
const existingSnippet = tomlString
|
||||||
.slice(startIdx + COMMON_CONFIG_MARKER_START.length, endIdx)
|
.slice(startIdx + COMMON_CONFIG_MARKER_START.length, endIdx)
|
||||||
.trim();
|
.trim();
|
||||||
|
|
||||||
return existingSnippet === snippetString.trim();
|
return existingSnippet === snippetString.trim();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user