From 227aa0140792fd48dfcff22f8bdfd2da04e31b71 Mon Sep 17 00:00:00 2001 From: Jason Date: Sat, 3 Oct 2026 21:42:09 +0800 Subject: [PATCH] fix(providers): advise picking the official account as the Stack default The Stack dialog now tells subscription users to keep the official account as the default instead of describing what gets dropped. The duplicate warning under "Set as default" in the more menu is removed, along with the now unused menu item detail field. --- .../providers/ProviderCardActions.tsx | 8 +---- src/components/providers/presentation.ts | 11 +------ src/i18n/locales/en.json | 3 +- src/i18n/locales/ja.json | 3 +- src/i18n/locales/zh-TW.json | 3 +- src/i18n/locales/zh.json | 3 +- tests/components/ProviderCardActions.test.tsx | 11 +------ tests/components/providerPresentation.test.ts | 31 ++----------------- 8 files changed, 9 insertions(+), 64 deletions(-) diff --git a/src/components/providers/ProviderCardActions.tsx b/src/components/providers/ProviderCardActions.tsx index 810c9bef5..1f6288f74 100644 --- a/src/components/providers/ProviderCardActions.tsx +++ b/src/components/providers/ProviderCardActions.tsx @@ -178,16 +178,10 @@ export function ProviderCardActions({ className="flex-col items-start gap-0.5" > {item.label} - {item.disabledReason ? ( + {item.disabledReason && ( {item.disabledReason} - ) : ( - item.detail && ( - - {item.detail} - - ) )} ))} diff --git a/src/components/providers/presentation.ts b/src/components/providers/presentation.ts index 4821dfe58..46ff7fb5b 100644 --- a/src/components/providers/presentation.ts +++ b/src/components/providers/presentation.ts @@ -42,8 +42,6 @@ export interface CardMenuOption { export interface CardMenuItem { key: string; label: string; - /** 点了之后的后果,写在名字下面 */ - detail?: string; /** 不能点的原因:照常列出来,原因写在名字下面 */ disabledReason?: string; onSelect: () => void; @@ -447,18 +445,11 @@ function buildSwitchSectionsByView(input: SwitchModeInput): ProviderSection[] { const defaultProvider = providers.find((p) => p.id === defaultId); // 行上的主操作只有名单的添加 / 移除;「设为默认」在「更多」菜单里:进了聚合当场生效, // 在直连时只记下选择(切换时的确认框里还能改)。正在路由时不能点:默认和路由目标是同一个 - // 指针,改了就是当场换路由。官方账号只能做默认、不能做成员(Codex):默认从它换成别家, - // 官方订阅的模型就不在聚合里了,后果写在菜单项上 - const defaultIsOfficial = - defaultProvider !== undefined && official(defaultProvider); + // 指针,改了就是当场换路由 const setDefaultItems = (p: Provider): CardMenuItem[] => [ { key: "setDefault", label: t("providerCard.action.setDefault"), - detail: - defaultIsOfficial && !official(p) - ? t("providerCard.reason.defaultDropsOfficial") - : undefined, disabledReason: active === "route" ? t("providerCard.reason.defaultWhileRouting") diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 0a91604e3..bbe41eaee 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -3969,7 +3969,7 @@ "routeTo": "Route to", "stackDefault": "Default provider", "officialOption": "{{name}} (official)", - "stackOfficialNote": "An official account can only be the default. With another provider as the default, the official subscription's models won't be part of the aggregation.", + "stackOfficialNote": "If you use an official subscription, set the official account as the default provider.", "routeNoteFile": "Rewrites the address and key in {{file}}. The real key stays in CC Switch; other settings are untouched.", "routeNoteSwitch": "Changing providers later on the Routing tab won't rewrite the config file.", "routeNoteKeepRunning": "Keep CC Switch running. Quitting writes the direct config back; it reconnects on the next start.", @@ -4034,7 +4034,6 @@ "noRoute": "Official subscriptions don't go through routing; available again in direct mode.", "noStack": "Official subscriptions can't be used in Aggregation.", "officialStack": "Official accounts can only be the default; they can't join the aggregation.", - "defaultDropsOfficial": "The official subscription's models won't be part of the aggregation.", "defaultWhileRouting": "While routing, the default is the provider you route to. You can pick another one when switching to Aggregation.", "needsRoute": "Needs routing: {{reason}}; can't connect directly.", "defaultCannotRemove": "The default can't be removed. Make another provider the default first.", diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index cc9ddbf02..17186a053 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -3969,7 +3969,7 @@ "routeTo": "転送先", "stackDefault": "既定のプロバイダー", "officialOption": "{{name}}(公式)", - "stackOfficialNote": "公式アカウントは既定にしかできません。別のプロバイダーを既定にすると、公式サブスクリプションのモデルは集約に入りません。", + "stackOfficialNote": "公式サブスクリプションを使っている場合は、公式アカウントを既定のプロバイダーにしてください。", "routeNoteFile": "{{file}} のアドレスとキーを書き換えます。本物のキーは CC Switch に残り、ほかの設定は変わりません。", "routeNoteSwitch": "以後「ルーティング」タブでプロバイダーを変えても設定ファイルは書き換えません。", "routeNoteKeepRunning": "CC Switch を起動したままにしてください。終了時に直接接続へ書き戻し、次回起動時に再接続します。", @@ -4034,7 +4034,6 @@ "noRoute": "公式サブスクリプションはルーティングを通りません。直接接続に戻すと使えます。", "noStack": "公式サブスクリプションは集約では使えません。", "officialStack": "公式アカウントは既定にだけでき、集約には追加できません。", - "defaultDropsOfficial": "公式サブスクリプションのモデルは集約に入りません。", "defaultWhileRouting": "ルーティング中は、転送先のプロバイダーがそのまま既定になります。集約に切り替えるときに別のプロバイダーを選べます。", "needsRoute": "ルーティングが必要:{{reason}}。直接接続はできません。", "defaultCannotRemove": "既定のプロバイダーは削除できません。先にほかを既定にしてください。", diff --git a/src/i18n/locales/zh-TW.json b/src/i18n/locales/zh-TW.json index 44be72744..85aae4cbc 100644 --- a/src/i18n/locales/zh-TW.json +++ b/src/i18n/locales/zh-TW.json @@ -3970,7 +3970,7 @@ "routeTo": "路由到", "stackDefault": "預設供應商", "officialOption": "{{name}}(官方)", - "stackOfficialNote": "官方帳號只能當預設;選別家當預設後,官方訂閱的模型不會出現在聚合裡。", + "stackOfficialNote": "如果你在用官方訂閱,請把官方帳號設為預設供應商。", "routeNoteFile": "會改寫 {{file}} 裡的位址和金鑰;真實金鑰留在 CC Switch 裡,其他設定不動。", "routeNoteSwitch": "之後在「路由」分頁裡換供應商,不再改寫設定檔。", "routeNoteKeepRunning": "CC Switch 需要保持執行;結束時自動寫回直連,下次啟動再接上。", @@ -4035,7 +4035,6 @@ "noRoute": "官方訂閱不經過路由,回到直連後可用。", "noStack": "官方訂閱不能用於聚合模式。", "officialStack": "官方帳號只能當預設,不能加入聚合。", - "defaultDropsOfficial": "官方訂閱的模型不會出現在聚合裡。", "defaultWhileRouting": "正在路由時,預設就是路由到的那家;切換到聚合模式時可以另選。", "needsRoute": "需要路由:{{reason}},不能直連。", "defaultCannotRemove": "預設那家不能移除,先把別家設為預設。", diff --git a/src/i18n/locales/zh.json b/src/i18n/locales/zh.json index 5e186f8e7..9a10a738b 100644 --- a/src/i18n/locales/zh.json +++ b/src/i18n/locales/zh.json @@ -3969,7 +3969,7 @@ "routeTo": "路由到", "stackDefault": "默认供应商", "officialOption": "{{name}}(官方)", - "stackOfficialNote": "官方账号只能做默认;选别家做默认后,官方订阅的模型不会出现在聚合里。", + "stackOfficialNote": "如果你在用官方订阅,请把官方账号设为默认供应商。", "routeNoteFile": "会改写 {{file}} 里的地址和密钥;真实密钥留在 CC Switch 里,其他设置不动。", "routeNoteSwitch": "之后在「路由」页签里换供应商,不再改写配置文件。", "routeNoteKeepRunning": "CC Switch 需要保持运行;退出时自动写回直连,下次启动再接上。", @@ -4034,7 +4034,6 @@ "noRoute": "官方订阅不经过路由,回到直连后可用。", "noStack": "官方订阅不能用于聚合模式。", "officialStack": "官方账号只能做默认,不能加入聚合。", - "defaultDropsOfficial": "官方订阅的模型不会出现在聚合里。", "defaultWhileRouting": "正在路由时,默认就是路由到的那家;切换到聚合模式时可以另选。", "needsRoute": "需要路由:{{reason}},不能直连。", "defaultCannotRemove": "默认那家不能移除,先把别家设为默认。", diff --git a/tests/components/ProviderCardActions.test.tsx b/tests/components/ProviderCardActions.test.tsx index d04ba5f36..afdd65a46 100644 --- a/tests/components/ProviderCardActions.test.tsx +++ b/tests/components/ProviderCardActions.test.tsx @@ -22,7 +22,7 @@ async function openMenu(presentation: CardPresentation) { } describe("ProviderCardActions — mode items in the more menu", () => { - it("lists them first, with the consequence under the name", async () => { + it("lists them first", async () => { const onSelect = vi.fn(); const { user, menu } = await openMenu({ buttons: [], @@ -31,7 +31,6 @@ describe("ProviderCardActions — mode items in the more menu", () => { { key: "setDefault", label: "providerCard.action.setDefault", - detail: "providerCard.reason.defaultDropsOfficial", onSelect, }, ], @@ -39,9 +38,6 @@ describe("ProviderCardActions — mode items in the more menu", () => { const items = within(menu).getAllByRole("menuitem"); expect(items[0]).toHaveTextContent("providerCard.action.setDefault"); - expect(items[0]).toHaveTextContent( - "providerCard.reason.defaultDropsOfficial", - ); expect(items[1]).toHaveTextContent("provider.duplicate"); await user.click(items[0]); @@ -57,7 +53,6 @@ describe("ProviderCardActions — mode items in the more menu", () => { { key: "setDefault", label: "providerCard.action.setDefault", - detail: "providerCard.reason.defaultDropsOfficial", disabledReason: "providerCard.reason.defaultWhileRouting", onSelect, }, @@ -66,11 +61,7 @@ describe("ProviderCardActions — mode items in the more menu", () => { const item = within(menu).getAllByRole("menuitem")[0]; expect(item).toHaveAttribute("aria-disabled", "true"); - // 不能点时只写原因,不再写后果 expect(item).toHaveTextContent("providerCard.reason.defaultWhileRouting"); - expect(item).not.toHaveTextContent( - "providerCard.reason.defaultDropsOfficial", - ); await user.click(item); expect(onSelect).not.toHaveBeenCalled(); }); diff --git a/tests/components/providerPresentation.test.ts b/tests/components/providerPresentation.test.ts index b658abab7..41978973b 100644 --- a/tests/components/providerPresentation.test.ts +++ b/tests/components/providerPresentation.test.ts @@ -345,7 +345,6 @@ describe("buildSwitchSections — stack", () => { expect(input.actions.stackRemove).toHaveBeenCalledWith(backup); expect(setDefaultItem(sections, "backup")).toMatchObject({ label: "providerCard.action.setDefault", - detail: undefined, disabledReason: undefined, }); setDefaultItem(sections, "backup").onSelect(); @@ -433,34 +432,8 @@ describe("buildSwitchSections — stack", () => { expect(button(sections, "account", "add").disabledReason).toBe( "providerCard.reason.officialStack", ); - // 它能做默认;默认本来就不是官方账号时,换默认没有额外后果 - expect(setDefaultItem(sections, "account").detail).toBeUndefined(); - }); - - it("says the official subscription leaves the Stack when the default moves off a Codex official account", () => { - const account = provider("account", { - category: "official", - settingsConfig: { auth: {}, config: "" }, - }); - for (const active of ["direct", "stack"] as AppMode[]) { - const { sections } = build({ - app: "codex", - active, - view: "stack", - providers: [account, relay, backup], - directId: "relay", - routeId: "account", - stackMembers: new Map([["relay", 1]]), - }); - - expect(item(sections, "account").section).toBe("default"); - // 已添加的、还没添加的第三方都一样:官方账号不做默认就不在聚合里了 - for (const id of ["relay", "backup"]) { - expect(setDefaultItem(sections, id).detail).toBe( - "providerCard.reason.defaultDropsOfficial", - ); - } - } + // 它能做默认 + expect(setDefaultItem(sections, "account").disabledReason).toBeUndefined(); }); it("never lets ChatGPT accounts be added in Codex Stack mode, even legacy cards without a category", () => {