mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-26 14:35:22 +08:00
a187380d6f
Previously, enabling auto failover kept using the current provider until the first failure, causing inconsistency when the current provider was not in the failover queue. When stopping proxy, the restored config would not match user expectations. New behavior: - Enable auto failover = immediately switch to queue P1 - Subsequent routing follows queue order (P1→P2→...) - Auto-add current provider to queue if queue is empty Changes: - Add switch_proxy_target() for hot-switching during proxy mode - Update provider_router to use queue order when failover enabled - Sync tray menu Auto click with the same logic - Update UI tooltips to reflect new semantics - Add tests for queue-only routing scenario
77 lines
2.1 KiB
TypeScript
77 lines
2.1 KiB
TypeScript
/**
|
|
* 故障转移切换开关组件
|
|
*
|
|
* 放置在主界面头部,用于一键启用/关闭自动故障转移
|
|
*/
|
|
|
|
import { Shuffle, Loader2 } from "lucide-react";
|
|
import { Switch } from "@/components/ui/switch";
|
|
import {
|
|
useAutoFailoverEnabled,
|
|
useSetAutoFailoverEnabled,
|
|
} from "@/lib/query/failover";
|
|
import { cn } from "@/lib/utils";
|
|
import { useTranslation } from "react-i18next";
|
|
import type { AppId } from "@/lib/api";
|
|
|
|
interface FailoverToggleProps {
|
|
className?: string;
|
|
activeApp: AppId;
|
|
}
|
|
|
|
export function FailoverToggle({ className, activeApp }: FailoverToggleProps) {
|
|
const { t } = useTranslation();
|
|
const { data: isEnabled = false, isLoading } =
|
|
useAutoFailoverEnabled(activeApp);
|
|
const setEnabled = useSetAutoFailoverEnabled();
|
|
|
|
const handleToggle = (checked: boolean) => {
|
|
setEnabled.mutate({ appType: activeApp, enabled: checked });
|
|
};
|
|
|
|
const appLabel =
|
|
activeApp === "claude"
|
|
? "Claude"
|
|
: activeApp === "codex"
|
|
? "Codex"
|
|
: "Gemini";
|
|
|
|
const tooltipText = isEnabled
|
|
? t("failover.tooltip.enabled", {
|
|
app: appLabel,
|
|
defaultValue: `${appLabel} 故障转移已启用\n按队列优先级(P1→P2→...)选择供应商`,
|
|
})
|
|
: t("failover.tooltip.disabled", {
|
|
app: appLabel,
|
|
defaultValue: `启用 ${appLabel} 故障转移\n将立即切换到队列 P1,并在失败时自动切换到下一个`,
|
|
});
|
|
|
|
return (
|
|
<div
|
|
className={cn(
|
|
"flex items-center gap-1 px-1.5 h-8 rounded-lg bg-muted/50 transition-all",
|
|
className,
|
|
)}
|
|
title={tooltipText}
|
|
>
|
|
{setEnabled.isPending || isLoading ? (
|
|
<Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
|
|
) : (
|
|
<Shuffle
|
|
className={cn(
|
|
"h-4 w-4 transition-colors",
|
|
isEnabled
|
|
? "text-emerald-500 animate-pulse"
|
|
: "text-muted-foreground",
|
|
)}
|
|
/>
|
|
)}
|
|
<Switch
|
|
checked={isEnabled}
|
|
onCheckedChange={handleToggle}
|
|
disabled={setEnabled.isPending || isLoading}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|