From 3d23ddb3b5a9ae768a91b9e9e6a2bc85aae5d7dc Mon Sep 17 00:00:00 2001 From: Jason Date: Sat, 3 Oct 2026 12:59:42 +0800 Subject: [PATCH] refactor(ui): drop the direct and last-route chips from the route tab The "used when direct" chip marked the provider the client falls back to after leaving routing. It only helps on the direct tab, where "back to direct" acts at once and doesn't name the provider. On the route tab nothing acts on that provider, and with failover on the chip only showed up when the provider happened to be outside the queue. The "last routed" chip in the route preview said which provider "start routing" would use, but the confirm dialog already preselects and shows it. Keep the direct chip on the direct tab only and remove the other one together with its string. --- src/components/providers/presentation.ts | 30 ++++++++----------- src/i18n/locales/en.json | 1 - src/i18n/locales/ja.json | 1 - src/i18n/locales/zh-TW.json | 1 - src/i18n/locales/zh.json | 1 - tests/components/providerPresentation.test.ts | 22 +++++++++++--- 6 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/components/providers/presentation.ts b/src/components/providers/presentation.ts index 2d8663360..22ee9a7ca 100644 --- a/src/components/providers/presentation.ts +++ b/src/components/providers/presentation.ts @@ -166,10 +166,12 @@ function buildSwitchSectionsByView(input: SwitchModeInput): ProviderSection[] { tone: "outline", title: input.routingReason(p), }), - directWhenDirect: (onSoft = false): CardChip => ({ + // 只在直连页上标:那里的「回到直连」一步生效、不写名字,要靠它看出会落到哪家。 + // 路由页上没有跟直连那家有关的操作,不标 + directWhenDirect: (): CardChip => ({ key: "direct", label: t("providerCard.chip.directWhenDirect"), - tone: onSoft ? "outline" : "direct", + tone: "direct", title: t("provider.directProviderHint"), }), }; @@ -269,9 +271,7 @@ function buildSwitchSectionsByView(input: SwitchModeInput): ProviderSection[] { if (blockedFromRouting(app, p)) return blocked(p, t("providerCard.action.routeHere"), noRoute); const chips = officialOnly(p); - const current = p.id === routeId; - if (p.id === directId) chips.push(chip.directWhenDirect(current)); - if (current) { + if (p.id === routeId) { return { provider: p, presentation: { @@ -363,12 +363,10 @@ function buildSwitchSectionsByView(input: SwitchModeInput): ProviderSection[] { t("providerCard.action.addToQueue"), t("providerCard.reason.noFailover"), ); - const chips = officialOnly(p); - if (p.id === directId) chips.push(chip.directWhenDirect()); return { provider: p, presentation: { - chips, + chips: officialOnly(p), buttons: [ { key: "queueAdd", @@ -399,7 +397,8 @@ function buildSwitchSectionsByView(input: SwitchModeInput): ProviderSection[] { } // 实际在直连 / 聚合,正在查看路由:行上没有主操作,要生效只有通知条的「开始路由」, - // 路由到哪家在确认框里选。不能路由的官方订阅没有按钮可挂原因,原因挂在「官方」徽标上 + // 路由到哪家在确认框里选(预选上次那家,框里看得到,卡上不再标)。不能路由的官方订阅 + // 没有按钮可挂原因,原因挂在「官方」徽标上 return [ { key: "all", @@ -413,17 +412,12 @@ function buildSwitchSectionsByView(input: SwitchModeInput): ProviderSection[] { buttons: [], } satisfies CardPresentation, }; - const chips = officialOnly(p); - if (p.id === routeId) - chips.push({ - key: "lastRoute", - label: t("providerCard.chip.lastRoute"), - tone: "route", - }); - if (p.id === directId) chips.push(chip.directWhenDirect()); return { provider: p, - presentation: { chips, buttons: [] } satisfies CardPresentation, + presentation: { + chips: officialOnly(p), + buttons: [], + } satisfies CardPresentation, }; }), }, diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 644e08453..a19033d6f 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -3909,7 +3909,6 @@ "official": "Official", "needsRoute": "Needs routing", "directWhenDirect": "Used when direct", - "lastRoute": "Last routed", "default": "Default", "models": "{{count}} models", "noModels": "No models", diff --git a/src/i18n/locales/ja.json b/src/i18n/locales/ja.json index 34de1ec05..b5ae3f93f 100644 --- a/src/i18n/locales/ja.json +++ b/src/i18n/locales/ja.json @@ -3909,7 +3909,6 @@ "official": "公式", "needsRoute": "ルーティングが必要", "directWhenDirect": "直接接続時に使用", - "lastRoute": "前回の転送先", "default": "既定", "models": "{{count}} モデル", "noModels": "モデルなし", diff --git a/src/i18n/locales/zh-TW.json b/src/i18n/locales/zh-TW.json index 08b4f3c5c..82c2d99a3 100644 --- a/src/i18n/locales/zh-TW.json +++ b/src/i18n/locales/zh-TW.json @@ -3910,7 +3910,6 @@ "official": "官方", "needsRoute": "需要路由", "directWhenDirect": "直連時使用", - "lastRoute": "上次路由", "default": "預設", "models": "{{count}} 個模型", "noModels": "沒有模型", diff --git a/src/i18n/locales/zh.json b/src/i18n/locales/zh.json index 7629ffa36..93e4c7880 100644 --- a/src/i18n/locales/zh.json +++ b/src/i18n/locales/zh.json @@ -3909,7 +3909,6 @@ "official": "官方", "needsRoute": "需要路由", "directWhenDirect": "直连时使用", - "lastRoute": "上次路由", "default": "默认", "models": "{{count}} 个模型", "noModels": "没有模型", diff --git a/tests/components/providerPresentation.test.ts b/tests/components/providerPresentation.test.ts index 2804c583b..5829fbb85 100644 --- a/tests/components/providerPresentation.test.ts +++ b/tests/components/providerPresentation.test.ts @@ -160,6 +160,8 @@ describe("buildSwitchSections — route", () => { }); button(sections, "relay", "routeHere").onClick(); expect(input.actions.routeTo).toHaveBeenCalledWith(relay); + // 路由页上没有跟直连那家有关的操作,不标「直连时使用」 + expect(item(sections, "relay").chips).toEqual([]); expect(item(sections, "official").dim).toBe(true); expect(button(sections, "official", "blocked").disabledReason).toBe( "providerCard.reason.noRoute", @@ -193,6 +195,19 @@ describe("buildSwitchSections — route", () => { expect(input.actions.queueAdd).toHaveBeenCalledWith(converted); button(sections, "backup", "queueRemove").onClick(); expect(input.actions.queueRemove).toHaveBeenCalledWith(backup); + + // 直连那家不在队列里时也不标「直连时使用」 + const outside = build({ + active: "route", + view: "route", + routeId: "backup", + failoverOn: true, + queue: ["backup"], + }); + expect(item(outside.sections, "relay")).toMatchObject({ + section: "rest", + chips: [], + }); }); it("numbers the queue by its full order and marks the recorded route, not the first visible card", () => { @@ -270,12 +285,11 @@ describe("buildSwitchSections — route", () => { routeId: "backup", }); - expect(item(sections, "backup").chips.map((c) => c.key)).toContain( - "lastRoute", - ); - // 进入路由只有通知条一个入口(目标在确认框里选),行上没有主操作 + // 进入路由只有通知条一个入口(目标在确认框里选、预选上次那家),行上没有主操作, + // 也不标上次路由的那家和直连那家 for (const id of ["relay", "backup", "converted"]) { expect(item(sections, id).buttons).toEqual([]); + expect(item(sections, id).chips).toEqual([]); } // 不能路由的官方订阅没有按钮可挂原因,原因在「官方」徽标上 expect(item(sections, "official")).toMatchObject({