mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-24 12:44:18 +08:00
fix(providers): only block explicit official providers under proxy takeover
The proxy-takeover block previously fell back to the isOfficial heuristic (empty base_url / missing key) when category was absent. That misjudged custom providers whose endpoint lives in meta or whose fields are simply unfilled: their switch button got disabled, making users think the config was broken. That extra UI block was also "virtual" — the executor in useProviderActions only ever honored category === "official", so the front end blocked more than the backend would enforce. Gate the block solely on explicit category === "official", matching the executor and unifying both verdicts on a single source of truth. Also rework the blocked-state UI: - drop the red "blocked" badge for a plain disabled Enable button - move title/cursor onto a wrapper span (disabled buttons set pointer-events:none, so an on-button title/cursor never fired) - replace the account-ban warning tooltip with a lighter hint (provider.blockedByProxyHint), four locales kept in sync
This commit is contained in:
@@ -7,7 +7,6 @@ import {
|
||||
Minus,
|
||||
Play,
|
||||
Plus,
|
||||
ShieldAlert,
|
||||
Terminal,
|
||||
TestTube2,
|
||||
Trash2,
|
||||
@@ -45,6 +44,18 @@ interface ProviderActionsProps {
|
||||
onSetAsDefault?: () => void;
|
||||
}
|
||||
|
||||
// 主按钮的呈现状态。title 用于 disabled 态向用户解释为何不可点击;
|
||||
// 因 Button 基类带 disabled:pointer-events-none,title 必须挂在外层非禁用
|
||||
// 的 wrapper 上才会在 hover 时显示(见下方 <span> 包裹)。
|
||||
interface MainButtonState {
|
||||
disabled: boolean;
|
||||
variant: "default" | "secondary";
|
||||
className: string;
|
||||
icon: JSX.Element;
|
||||
text: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export function ProviderActions({
|
||||
appId,
|
||||
isCurrent,
|
||||
@@ -108,7 +119,7 @@ export function ProviderActions({
|
||||
}
|
||||
};
|
||||
|
||||
const getMainButtonState = () => {
|
||||
const getMainButtonState = (): MainButtonState => {
|
||||
if (isOmo) {
|
||||
if (isCurrent) {
|
||||
return {
|
||||
@@ -174,16 +185,6 @@ export function ProviderActions({
|
||||
};
|
||||
}
|
||||
|
||||
if (isOfficialBlockedByProxy) {
|
||||
return {
|
||||
disabled: true,
|
||||
variant: "secondary" as const,
|
||||
className: "opacity-40 cursor-not-allowed",
|
||||
icon: <ShieldAlert className="h-4 w-4" />,
|
||||
text: t("provider.blockedByProxy", { defaultValue: "已拦截" }),
|
||||
};
|
||||
}
|
||||
|
||||
if (isCurrent) {
|
||||
return {
|
||||
disabled: true,
|
||||
@@ -195,6 +196,17 @@ export function ProviderActions({
|
||||
};
|
||||
}
|
||||
|
||||
if (isOfficialBlockedByProxy) {
|
||||
return {
|
||||
disabled: true,
|
||||
variant: "default" as const,
|
||||
className: "",
|
||||
icon: <Play className="h-4 w-4" />,
|
||||
text: t("provider.enable"),
|
||||
title: t("provider.blockedByProxyHint"),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
disabled: false,
|
||||
variant: "default" as const,
|
||||
@@ -247,16 +259,26 @@ export function ProviderActions({
|
||||
);
|
||||
})()}
|
||||
|
||||
<Button
|
||||
size="sm"
|
||||
variant={buttonState.variant}
|
||||
onClick={handleMainButtonClick}
|
||||
disabled={buttonState.disabled}
|
||||
className={cn("w-[4.5rem] px-2.5", buttonState.className)}
|
||||
{/* wrapper span 承接 hover:disabled 按钮自身 pointer-events:none,
|
||||
原生 title 与 cursor 都必须挂在未禁用的外层元素上才会生效 */}
|
||||
<span
|
||||
title={buttonState.title}
|
||||
className={cn(
|
||||
"inline-flex",
|
||||
buttonState.disabled && "cursor-not-allowed",
|
||||
)}
|
||||
>
|
||||
{buttonState.icon}
|
||||
{buttonState.text}
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant={buttonState.variant}
|
||||
onClick={handleMainButtonClick}
|
||||
disabled={buttonState.disabled}
|
||||
className={cn("w-[4.5rem] px-2.5", buttonState.className)}
|
||||
>
|
||||
{buttonState.icon}
|
||||
{buttonState.text}
|
||||
</Button>
|
||||
</span>
|
||||
|
||||
<div className="flex items-center gap-1">
|
||||
<Button
|
||||
|
||||
@@ -199,8 +199,16 @@ export function ProviderCard({
|
||||
TEMPLATE_TYPES.OFFICIAL_SUBSCRIPTION;
|
||||
const officialSubscriptionEnabled =
|
||||
supportsOfficialSubscription && usageEnabled && isOfficialSubscriptionUsage;
|
||||
// 官方判定只认显式 category === "official"(SSOT),不回退 isOfficial 的空字段启发式。
|
||||
// 理由(此判定曾在「纯 category ↔ category+isOfficial 回退」间反复,结论钉死于此):
|
||||
// 1) 封号保护是高代价决策,不该建立在「base_url/key 缺失」这种脆弱信号上——它无法区分
|
||||
// 「想直连官方」与「自定义但还没填完」,两者都表现为字段为空,必然误伤后者。
|
||||
// 2) 启发式在 UI 多拦的部分,执行层 useProviderActions.ts 也只认 category === "official"、
|
||||
// 并不兑现(绕过 UI 即可切换)→ 属虚保护,却以误伤 category 缺失的自定义供应商为代价。
|
||||
// 3) 预设导入的官方一定带 category="official",category 缺失的「真官方」现实中≈不存在。
|
||||
// 真官方就该有显式 category;手动新建官方应引导标注,而不是靠空字段猜。
|
||||
const isOfficialBlockedByProxy =
|
||||
isProxyTakeover && (provider.category === "official" || isOfficial);
|
||||
isProxyTakeover && provider.category === "official";
|
||||
const isCopilot =
|
||||
provider.meta?.providerType === PROVIDER_TYPES.GITHUB_COPILOT ||
|
||||
provider.meta?.usage_script?.templateType === "github_copilot";
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
"currentlyUsing": "Currently Using",
|
||||
"enable": "Enable",
|
||||
"inUse": "In Use",
|
||||
"blockedByProxy": "Blocked",
|
||||
"blockedByProxyHint": "Can't switch to an official provider while proxy takeover is active",
|
||||
"editProvider": "Edit Provider",
|
||||
"editProviderHint": "Configuration will be applied to the current provider immediately after update.",
|
||||
"deleteProvider": "Delete Provider",
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
"currentlyUsing": "現在使用中",
|
||||
"enable": "有効化",
|
||||
"inUse": "使用中",
|
||||
"blockedByProxy": "ブロック",
|
||||
"blockedByProxyHint": "プロキシ引き継ぎモードでは公式プロバイダーに切り替えできません",
|
||||
"editProvider": "プロバイダーを編集",
|
||||
"editProviderHint": "保存すると現在のプロバイダーにすぐ反映されます。",
|
||||
"deleteProvider": "プロバイダーを削除",
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
"currentlyUsing": "目前使用",
|
||||
"enable": "啟用",
|
||||
"inUse": "使用中",
|
||||
"blockedByProxy": "已攔截",
|
||||
"blockedByProxyHint": "代理接管模式下無法切換至官方供應商",
|
||||
"editProvider": "編輯供應商",
|
||||
"editProviderHint": "更新設定後將立即套用至目前供應商。",
|
||||
"deleteProvider": "刪除供應商",
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
"currentlyUsing": "当前使用",
|
||||
"enable": "启用",
|
||||
"inUse": "使用中",
|
||||
"blockedByProxy": "已拦截",
|
||||
"blockedByProxyHint": "代理接管模式下不可切换到官方供应商",
|
||||
"editProvider": "编辑供应商",
|
||||
"editProviderHint": "更新配置后将立即应用到当前供应商。",
|
||||
"deleteProvider": "删除供应商",
|
||||
|
||||
Reference in New Issue
Block a user