mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-27 08:14:33 +08:00
a1537807eb
* feat(failover): add auto-failover master switch with proxy integration
- Add persistent auto_failover_enabled setting in database
- Add get/set_auto_failover_enabled commands
- Provider router respects master switch state
- Proxy shutdown automatically disables failover
- Enabling failover auto-starts proxy server
- Optimistic updates for failover queue toggle
* feat(proxy): persist proxy takeover state across app restarts
- Add proxy_takeover_{app_type} settings for per-app state tracking
- Restore proxy takeover state automatically on app startup
- Preserve state on normal exit, clear on manual stop
- Add stop_with_restore_keep_state method for graceful shutdown
* fix(proxy): set takeover state for all apps in start_with_takeover
88 lines
2.6 KiB
TypeScript
88 lines
2.6 KiB
TypeScript
/**
|
|
* 代理模式切换开关组件
|
|
*
|
|
* 放置在主界面头部,用于一键启用/关闭代理模式
|
|
* 启用时自动接管 Live 配置,关闭时恢复原始配置
|
|
*/
|
|
|
|
import { Radio, Loader2 } from "lucide-react";
|
|
import { Switch } from "@/components/ui/switch";
|
|
import { useProxyStatus } from "@/hooks/useProxyStatus";
|
|
import { cn } from "@/lib/utils";
|
|
import { useTranslation } from "react-i18next";
|
|
import type { AppId } from "@/lib/api";
|
|
|
|
interface ProxyToggleProps {
|
|
className?: string;
|
|
activeApp: AppId;
|
|
}
|
|
|
|
export function ProxyToggle({ className, activeApp }: ProxyToggleProps) {
|
|
const { t } = useTranslation();
|
|
const { isRunning, takeoverStatus, setTakeoverForApp, isPending, status } =
|
|
useProxyStatus();
|
|
|
|
const handleToggle = async (checked: boolean) => {
|
|
await setTakeoverForApp({ appType: activeApp, enabled: checked });
|
|
};
|
|
|
|
const takeoverEnabled = takeoverStatus?.[activeApp] || false;
|
|
|
|
const appLabel =
|
|
activeApp === "claude"
|
|
? "Claude"
|
|
: activeApp === "codex"
|
|
? "Codex"
|
|
: "Gemini";
|
|
|
|
const tooltipText = takeoverEnabled
|
|
? isRunning
|
|
? t("proxy.takeover.tooltip.active", {
|
|
defaultValue: `${appLabel} 已接管 - ${status?.address}:${status?.port}\n切换该应用供应商为热切换`,
|
|
})
|
|
: t("proxy.takeover.tooltip.broken", {
|
|
defaultValue: `${appLabel} 已接管,但代理服务未运行`,
|
|
})
|
|
: t("proxy.takeover.tooltip.inactive", {
|
|
defaultValue: `接管 ${appLabel} 的 Live 配置,让该应用请求走本地代理`,
|
|
});
|
|
|
|
return (
|
|
<div
|
|
className={cn("p-1 rounded-xl transition-all", className)}
|
|
title={tooltipText}
|
|
>
|
|
<div className="flex items-center gap-2 px-2 h-8 rounded-md cursor-default">
|
|
{isPending ? (
|
|
<Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
|
|
) : (
|
|
<Radio
|
|
className={cn(
|
|
"h-4 w-4 transition-colors",
|
|
takeoverEnabled
|
|
? "text-emerald-500 animate-pulse"
|
|
: "text-muted-foreground",
|
|
)}
|
|
/>
|
|
)}
|
|
<span
|
|
className={cn(
|
|
"text-sm font-medium transition-colors select-none",
|
|
takeoverEnabled
|
|
? "text-emerald-600 dark:text-emerald-400"
|
|
: "text-muted-foreground",
|
|
)}
|
|
>
|
|
Proxy
|
|
</span>
|
|
<Switch
|
|
checked={takeoverEnabled}
|
|
onCheckedChange={handleToggle}
|
|
disabled={isPending}
|
|
className="ml-1"
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|