feat(settings): add enableLocalProxy toggle to gate main page proxy UI

New users often accidentally trigger ProxyToggle/FailoverToggle on the
main page. Add a settings toggle (default off) so the proxy controls
only appear when explicitly enabled. The proxy service start/stop in
settings remains independent of this visibility flag.
This commit is contained in:
Jason
2026-02-19 23:06:22 +08:00
parent 1b71dc721c
commit 0fa6b33b5e
9 changed files with 46 additions and 20 deletions
+4
View File
@@ -187,6 +187,9 @@ pub struct AppSettings {
/// 静默启动(程序启动时不显示主窗口,仅托盘运行) /// 静默启动(程序启动时不显示主窗口,仅托盘运行)
#[serde(default)] #[serde(default)]
pub silent_startup: bool, pub silent_startup: bool,
/// 是否在主页面启用本地代理功能(默认关闭)
#[serde(default)]
pub enable_local_proxy: bool,
#[serde(default, skip_serializing_if = "Option::is_none")] #[serde(default, skip_serializing_if = "Option::is_none")]
pub language: Option<String>, pub language: Option<String>,
@@ -262,6 +265,7 @@ impl Default for AppSettings {
skip_claude_onboarding: false, skip_claude_onboarding: false,
launch_on_startup: false, launch_on_startup: false,
silent_startup: false, silent_startup: false,
enable_local_proxy: false,
language: None, language: None,
visible_apps: None, visible_apps: None,
claude_config_dir: None, claude_config_dir: None,
+17 -15
View File
@@ -1046,21 +1046,23 @@ function App() {
)} )}
{currentView === "providers" && ( {currentView === "providers" && (
<> <>
{activeApp !== "opencode" && activeApp !== "openclaw" && ( {activeApp !== "opencode" &&
<> activeApp !== "openclaw" &&
<ProxyToggle activeApp={activeApp} /> settingsData?.enableLocalProxy && (
<div <>
className={cn( <ProxyToggle activeApp={activeApp} />
"transition-all duration-300 ease-in-out overflow-hidden", <div
isCurrentAppTakeoverActive className={cn(
? "opacity-100 max-w-[100px] scale-100" "transition-all duration-300 ease-in-out overflow-hidden",
: "opacity-0 max-w-0 scale-75 pointer-events-none", isCurrentAppTakeoverActive
)} ? "opacity-100 max-w-[100px] scale-100"
> : "opacity-0 max-w-0 scale-75 pointer-events-none",
<FailoverToggle activeApp={activeApp} /> )}
</div> >
</> <FailoverToggle activeApp={activeApp} />
)} </div>
</>
)}
<AppSwitcher <AppSwitcher
activeApp={activeApp} activeApp={activeApp}
-3
View File
@@ -408,9 +408,6 @@ export function ProxyPanel() {
</div> </div>
) : ( ) : (
<div className="space-y-6"> <div className="space-y-6">
{/* 空白区域避免冲突 */}
<div className="h-4"></div>
{/* 基础设置 - 监听地址/端口 */} {/* 基础设置 - 监听地址/端口 */}
<div className="rounded-lg border border-border bg-muted/40 p-4 space-y-4"> <div className="rounded-lg border border-border bg-muted/40 p-4 space-y-4">
<div> <div>
+16 -2
View File
@@ -55,6 +55,7 @@ import { useImportExport } from "@/hooks/useImportExport";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import type { SettingsFormState } from "@/hooks/useSettings"; import type { SettingsFormState } from "@/hooks/useSettings";
import { Switch } from "@/components/ui/switch"; import { Switch } from "@/components/ui/switch";
import { ToggleRow } from "@/components/ui/toggle-row";
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { useProxyStatus } from "@/hooks/useProxyStatus"; import { useProxyStatus } from "@/hooks/useProxyStatus";
@@ -356,8 +357,21 @@ export function SettingsPage({
/> />
</div> </div>
</AccordionPrimitive.Header> </AccordionPrimitive.Header>
<AccordionContent className="px-6 pb-6 pt-0 border-t border-border/50"> <AccordionContent className="px-6 pb-6 pt-4 border-t border-border/50">
<ProxyPanel /> <ToggleRow
icon={<Zap className="h-4 w-4 text-green-500" />}
title={t("settings.advanced.proxy.enableFeature")}
description={t(
"settings.advanced.proxy.enableFeatureDescription",
)}
checked={settings?.enableLocalProxy ?? false}
onCheckedChange={(checked) =>
handleAutoSave({ enableLocalProxy: checked })
}
/>
<div className="mt-4">
<ProxyPanel />
</div>
</AccordionContent> </AccordionContent>
</AccordionItem> </AccordionItem>
+2
View File
@@ -192,6 +192,8 @@
"proxy": { "proxy": {
"title": "Local Proxy", "title": "Local Proxy",
"description": "Control proxy service toggle, view status and port info", "description": "Control proxy service toggle, view status and port info",
"enableFeature": "Show Proxy Toggle on Main Page",
"enableFeatureDescription": "When enabled, the proxy and failover toggles will appear at the top of the main page",
"running": "Running", "running": "Running",
"stopped": "Stopped" "stopped": "Stopped"
}, },
+2
View File
@@ -192,6 +192,8 @@
"proxy": { "proxy": {
"title": "ローカルプロキシ", "title": "ローカルプロキシ",
"description": "プロキシサービスの切り替え、ステータスとポート情報を表示", "description": "プロキシサービスの切り替え、ステータスとポート情報を表示",
"enableFeature": "メインページにプロキシ切り替えを表示",
"enableFeatureDescription": "有効にすると、メインページ上部にプロキシとフェイルオーバーの切り替えが表示されます",
"running": "実行中", "running": "実行中",
"stopped": "停止中" "stopped": "停止中"
}, },
+2
View File
@@ -192,6 +192,8 @@
"proxy": { "proxy": {
"title": "本地代理", "title": "本地代理",
"description": "控制代理服务开关、查看状态与端口信息", "description": "控制代理服务开关、查看状态与端口信息",
"enableFeature": "在主页面显示本地代理开关",
"enableFeatureDescription": "开启后,主页面顶部将显示代理和故障转移开关",
"running": "运行中", "running": "运行中",
"stopped": "已停止" "stopped": "已停止"
}, },
+1
View File
@@ -14,6 +14,7 @@ export const settingsSchema = z.object({
enableClaudePluginIntegration: z.boolean().optional(), enableClaudePluginIntegration: z.boolean().optional(),
skipClaudeOnboarding: z.boolean().optional(), skipClaudeOnboarding: z.boolean().optional(),
launchOnStartup: z.boolean().optional(), launchOnStartup: z.boolean().optional(),
enableLocalProxy: z.boolean().optional(),
language: z.enum(["en", "zh", "ja"]).optional(), language: z.enum(["en", "zh", "ja"]).optional(),
// 设备级目录覆盖 // 设备级目录覆盖
+2
View File
@@ -212,6 +212,8 @@ export interface Settings {
launchOnStartup?: boolean; launchOnStartup?: boolean;
// 静默启动(程序启动时不显示主窗口) // 静默启动(程序启动时不显示主窗口)
silentStartup?: boolean; silentStartup?: boolean;
// 是否启用主页面本地代理功能(默认关闭)
enableLocalProxy?: boolean;
// 首选语言(可选,默认中文) // 首选语言(可选,默认中文)
language?: "en" | "zh" | "ja"; language?: "en" | "zh" | "ja";