Files
browser/web/shared.ts
T
pastilhasandClaude Opus 5 23820ddbaf the preview never had a tab: the URL param is :section, not :tabId
Selecting a tab put its id in the URL and the preview still said "Select a tab to preview".

A plugin gets exactly two routes from the shell — /<route> and /<route>/:section — so :section is the
only param name that ever arrives, whatever the plugin means by it. This read :tabId, which was right
while it was a platform screen with its own /browser/:tabId route and stayed in place through the
extraction. The route matched, the id was in the URL, and useParams().tabId was undefined.

Nothing typechecks this: the param is a string key, and the wrong one is simply absent.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-21 02:27:09 +00:00

44 lines
2.0 KiB
TypeScript

import { useQuery } from '@tanstack/react-query';
import { useParams } from 'react-router';
import { useClient } from 'hooks/useClient';
// Which attached tab is being previewed is `/browser/:tabId`. It used to be a `BROWSER_SELECTED_TAB`
// global read by three components, which meant the address bar said `/browser` no matter what you were
// looking at, and a tab row was a `<button>` with the id in its onClick closure.
export type BrowserTarget = {
id: string;
sessionId: string;
type: string;
title: string;
url: string;
};
export const browserTabPath = (id: string) => `/browser/${encodeURIComponent(id)}`;
/** The previewed tab, or null on the bare `/browser` route — the list with nothing open. */
/**
* Which tab is open, from the URL.
*
* The param is `section`, not `tabId`. A plugin gets exactly two routes from the shell — `/<route>` and
* `/<route>/:section` — so `:section` is the only param name that ever arrives, whatever the plugin
* means by it. This read `tabId` while it was a platform screen with its own `/browser/:tabId` route,
* and kept reading it after becoming a plugin: the id was in the URL, the route matched, and the panel
* saw undefined. The preview said "Select a tab to preview" with a tab plainly selected.
*/
export const useSelectedTabId = (): string | null => useParams<{ section?: string }>().section ?? null;
// Both panels want this list and React Query serves both observers from one key, so the preview being
// able to tell "no tab open" from "that tab is gone" costs no extra request. It needs to: a CDP target
// id dies with the browser session, and now that the id is in the URL a reload can carry a stale one in
// — which the old global, living in memory, could never do.
export const useBrowserTargets = (enabled: boolean) => {
const client = useClient();
return useQuery({
queryKey: ['browser-targets'],
queryFn: () => client.get<BrowserTarget[]>('/browser/targets'),
refetchInterval: 3000,
enabled,
});
};