From 2bfb44ea2efa4414a33f37eb0da9afb22731d8a5 Mon Sep 17 00:00:00 2001 From: Shakker Date: Tue, 11 Aug 2026 15:38:24 +0200 Subject: [PATCH] fix: satisfy browser tab landing guards --- .../browser-panel-controller-input.test.ts | 2 +- .../browser/browser-panel-controller.ts | 17 ++++------------ .../components/browser/browser-panel-tabs.ts | 20 ++++++++++++++++++- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/ui/src/components/browser/browser-panel-controller-input.test.ts b/ui/src/components/browser/browser-panel-controller-input.test.ts index a7a94c842654..d2c81fc3b416 100644 --- a/ui/src/components/browser/browser-panel-controller-input.test.ts +++ b/ui/src/components/browser/browser-panel-controller-input.test.ts @@ -663,7 +663,7 @@ describe("BrowserPanelController capture and input ownership", () => { const previousUrl = "https://example.test/previous"; const { client, request } = createBrowserClient(async (envelope) => { if (envelope.path === "/act") { - const fn = String(envelope.body?.fn ?? ""); + const fn = typeof envelope.body?.fn === "string" ? envelope.body.fn : ""; return fn.includes("history.go") ? { result: true } : createBrowserPanelTestMetrics(previousUrl, "Previous"); diff --git a/ui/src/components/browser/browser-panel-controller.ts b/ui/src/components/browser/browser-panel-controller.ts index dc7497f96d7b..e4c840035633 100644 --- a/ui/src/components/browser/browser-panel-controller.ts +++ b/ui/src/components/browser/browser-panel-controller.ts @@ -37,6 +37,7 @@ import { paintBrowserPanelOverlay, type BrowserPanelView, } from "./browser-panel-surface.ts"; +import { reconcileCapturedTab } from "./browser-panel-tabs.ts"; import { normalizeBrowserUrlDraft } from "./browser-url.ts"; const INSPECT_THROTTLE_MS = 120; @@ -223,19 +224,9 @@ export class BrowserPanelController implements ReactiveController { shot.url && observedMetrics?.url && shot.url !== observedMetrics.url ? null : observedMetrics; - const tabIndex = this.tabs.findIndex((tab) => tab.id === targetId); - const tab = this.tabs[tabIndex]; - if (tab) { - // Tab snapshots can lag history and in-page navigation. Keep the active - // tab's stable identity aligned with the document this capture owns. - const url = metrics?.url || shot.url || tab.url; - const title = metrics ? metrics.title : tab.title; - if (url !== tab.url || title !== tab.title) { - const tabs = [...this.tabs]; - tabs[tabIndex] = { ...tab, title, url }; - this.setState("tabs", tabs); - } - } + // Tab snapshots can lag history and in-page navigation. Keep the stable + // identity aligned with the document this capture owns. + this.setState("tabs", reconcileCapturedTab(this.tabs, targetId, metrics, shot.url)); this.setState("view", { targetId, dataUrl, image, url: shot.url, metrics }); if (!this.urlDraftEditing && shot.url) { this.setState("urlDraft", shot.url); diff --git a/ui/src/components/browser/browser-panel-tabs.ts b/ui/src/components/browser/browser-panel-tabs.ts index 9be1f252a72a..31ec24219baa 100644 --- a/ui/src/components/browser/browser-panel-tabs.ts +++ b/ui/src/components/browser/browser-panel-tabs.ts @@ -1,6 +1,24 @@ import { t } from "../../i18n/index.ts"; import { renderPanelTabStrip, type PanelTabStripTab } from "../panel-tab-strip.ts"; -import type { BrowserPanelTab } from "./browser-client.ts"; +import type { BrowserPageMetrics, BrowserPanelTab } from "./browser-client.ts"; + +export function reconcileCapturedTab( + tabs: BrowserPanelTab[], + targetId: string, + metrics: BrowserPageMetrics | null, + screenshotUrl: string, +): BrowserPanelTab[] { + const tab = tabs.find((entry) => entry.id === targetId); + if (!tab) { + return tabs; + } + const title = metrics?.title ?? tab.title; + const url = metrics?.url || screenshotUrl || tab.url; + if (title === tab.title && url === tab.url) { + return tabs; + } + return tabs.map((entry) => (entry.id === targetId ? { ...entry, title, url } : entry)); +} function tabLabel(tab: BrowserPanelTab): string { if (tab.title.trim()) {