mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-08-02 02:05:57 +08:00
feat(ui): add quick config toggles to Claude config editor (#1012)
Add 3 quick-toggle checkboxes above the JSON editor in Claude provider settings: - Hide AI Attribution (sets attribution.commit/pr to empty string) - Extended Thinking (sets alwaysThinkingEnabled to true) - Teammates Mode (sets env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS to "1") Uses local state to keep toggles and JsonEditor in sync without triggering ProviderForm re-renders. Includes i18n for zh/en/ja. Co-authored-by: Jason <farion1231@gmail.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState, useCallback, useMemo } from "react";
|
||||||
import { FullScreenPanel } from "@/components/common/FullScreenPanel";
|
import { FullScreenPanel } from "@/components/common/FullScreenPanel";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -53,6 +53,81 @@ export function CommonConfigEditor({
|
|||||||
return () => observer.disconnect();
|
return () => observer.disconnect();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Mirror value prop to local state so checkbox toggles and JsonEditor stay in sync
|
||||||
|
// (parent uses form.getValues which doesn't trigger re-renders)
|
||||||
|
const [localValue, setLocalValue] = useState(value);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLocalValue(value);
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
|
const handleLocalChange = useCallback(
|
||||||
|
(newValue: string) => {
|
||||||
|
setLocalValue(newValue);
|
||||||
|
onChange(newValue);
|
||||||
|
},
|
||||||
|
[onChange],
|
||||||
|
);
|
||||||
|
|
||||||
|
const toggleStates = useMemo(() => {
|
||||||
|
try {
|
||||||
|
const config = JSON.parse(localValue);
|
||||||
|
return {
|
||||||
|
hideAttribution:
|
||||||
|
config?.attribution?.commit === "" && config?.attribution?.pr === "",
|
||||||
|
alwaysThinking: config?.alwaysThinkingEnabled === true,
|
||||||
|
teammates:
|
||||||
|
config?.env?.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === "1" ||
|
||||||
|
config?.env?.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === 1,
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
return {
|
||||||
|
hideAttribution: false,
|
||||||
|
alwaysThinking: false,
|
||||||
|
teammates: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, [localValue]);
|
||||||
|
|
||||||
|
const handleToggle = useCallback(
|
||||||
|
(toggleKey: string, checked: boolean) => {
|
||||||
|
try {
|
||||||
|
const config = JSON.parse(localValue || "{}");
|
||||||
|
|
||||||
|
switch (toggleKey) {
|
||||||
|
case "hideAttribution":
|
||||||
|
if (checked) {
|
||||||
|
config.attribution = { commit: "", pr: "" };
|
||||||
|
} else {
|
||||||
|
delete config.attribution;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "alwaysThinking":
|
||||||
|
if (checked) {
|
||||||
|
config.alwaysThinkingEnabled = true;
|
||||||
|
} else {
|
||||||
|
delete config.alwaysThinkingEnabled;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "teammates":
|
||||||
|
if (!config.env) config.env = {};
|
||||||
|
if (checked) {
|
||||||
|
config.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS = "1";
|
||||||
|
} else {
|
||||||
|
delete config.env.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS;
|
||||||
|
if (Object.keys(config.env).length === 0) delete config.env;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleLocalChange(JSON.stringify(config, null, 2));
|
||||||
|
} catch {
|
||||||
|
// Don't modify if JSON is invalid
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[localValue, handleLocalChange],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
@@ -91,9 +166,40 @@ export function CommonConfigEditor({
|
|||||||
{commonConfigError}
|
{commonConfigError}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
<div className="flex flex-wrap items-center gap-x-4 gap-y-1">
|
||||||
|
<label className="inline-flex items-center gap-2 text-sm text-muted-foreground cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={toggleStates.hideAttribution}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleToggle("hideAttribution", e.target.checked)
|
||||||
|
}
|
||||||
|
className="w-4 h-4 text-blue-500 bg-white dark:bg-gray-800 border-border-default rounded focus:ring-blue-500 dark:focus:ring-blue-400 focus:ring-2"
|
||||||
|
/>
|
||||||
|
<span>{t("claudeConfig.hideAttribution")}</span>
|
||||||
|
</label>
|
||||||
|
<label className="inline-flex items-center gap-2 text-sm text-muted-foreground cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={toggleStates.alwaysThinking}
|
||||||
|
onChange={(e) => handleToggle("alwaysThinking", e.target.checked)}
|
||||||
|
className="w-4 h-4 text-blue-500 bg-white dark:bg-gray-800 border-border-default rounded focus:ring-blue-500 dark:focus:ring-blue-400 focus:ring-2"
|
||||||
|
/>
|
||||||
|
<span>{t("claudeConfig.alwaysThinking")}</span>
|
||||||
|
</label>
|
||||||
|
<label className="inline-flex items-center gap-2 text-sm text-muted-foreground cursor-pointer">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={toggleStates.teammates}
|
||||||
|
onChange={(e) => handleToggle("teammates", e.target.checked)}
|
||||||
|
className="w-4 h-4 text-blue-500 bg-white dark:bg-gray-800 border-border-default rounded focus:ring-blue-500 dark:focus:ring-blue-400 focus:ring-2"
|
||||||
|
/>
|
||||||
|
<span>{t("claudeConfig.enableTeammates")}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
<JsonEditor
|
<JsonEditor
|
||||||
value={value}
|
value={localValue}
|
||||||
onChange={onChange}
|
onChange={handleLocalChange}
|
||||||
placeholder={`{
|
placeholder={`{
|
||||||
"env": {
|
"env": {
|
||||||
"ANTHROPIC_BASE_URL": "https://your-api-endpoint.com",
|
"ANTHROPIC_BASE_URL": "https://your-api-endpoint.com",
|
||||||
|
|||||||
@@ -58,7 +58,10 @@
|
|||||||
"extractFromCurrent": "Extract from Editor",
|
"extractFromCurrent": "Extract from Editor",
|
||||||
"extractNoCommonConfig": "No common config available to extract from editor",
|
"extractNoCommonConfig": "No common config available to extract from editor",
|
||||||
"extractFailed": "Extract failed: {{error}}",
|
"extractFailed": "Extract failed: {{error}}",
|
||||||
"saveFailed": "Save failed: {{error}}"
|
"saveFailed": "Save failed: {{error}}",
|
||||||
|
"hideAttribution": "Hide AI Attribution",
|
||||||
|
"alwaysThinking": "Extended Thinking",
|
||||||
|
"enableTeammates": "Teammates Mode"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"viewOnGithub": "View on GitHub",
|
"viewOnGithub": "View on GitHub",
|
||||||
|
|||||||
@@ -58,7 +58,10 @@
|
|||||||
"extractFromCurrent": "編集内容から抽出",
|
"extractFromCurrent": "編集内容から抽出",
|
||||||
"extractNoCommonConfig": "編集内容から抽出できる共通設定がありません",
|
"extractNoCommonConfig": "編集内容から抽出できる共通設定がありません",
|
||||||
"extractFailed": "抽出に失敗しました: {{error}}",
|
"extractFailed": "抽出に失敗しました: {{error}}",
|
||||||
"saveFailed": "保存に失敗しました: {{error}}"
|
"saveFailed": "保存に失敗しました: {{error}}",
|
||||||
|
"hideAttribution": "AI署名を非表示",
|
||||||
|
"alwaysThinking": "拡張思考",
|
||||||
|
"enableTeammates": "Teammates モード"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"viewOnGithub": "GitHub で見る",
|
"viewOnGithub": "GitHub で見る",
|
||||||
|
|||||||
@@ -58,7 +58,10 @@
|
|||||||
"extractFromCurrent": "从编辑内容提取",
|
"extractFromCurrent": "从编辑内容提取",
|
||||||
"extractNoCommonConfig": "当前编辑内容没有可提取的通用配置",
|
"extractNoCommonConfig": "当前编辑内容没有可提取的通用配置",
|
||||||
"extractFailed": "提取失败: {{error}}",
|
"extractFailed": "提取失败: {{error}}",
|
||||||
"saveFailed": "保存失败: {{error}}"
|
"saveFailed": "保存失败: {{error}}",
|
||||||
|
"hideAttribution": "隐藏 AI 署名",
|
||||||
|
"alwaysThinking": "扩展思考",
|
||||||
|
"enableTeammates": "Teammates 模式"
|
||||||
},
|
},
|
||||||
"header": {
|
"header": {
|
||||||
"viewOnGithub": "在 GitHub 上查看",
|
"viewOnGithub": "在 GitHub 上查看",
|
||||||
|
|||||||
Reference in New Issue
Block a user