put the previewed browser tab in the url

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-07 11:56:45 +00:00
co-authored by Claude Opus 5
parent 6c47cbeb74
commit 374140d3a6
7 changed files with 124 additions and 61 deletions
+12 -3
View File
@@ -39,7 +39,8 @@ That fix is the template for the HIGH items below. **Caveat:** the fix only did
was in this list; the Projects feature was removed end to end on 2026-07-30, so the route is gone with it. H3
and navigate-site 22 below still name it — they are the record of work that happened, not of code that exists.)
**Flat screens:** `/` `/files` `/music` `/tasks` `/skills` `/processes` `/activity`
`/system-monitor` `/task-logs` `/plans` `/terminal` `/desktop` `/browser` `/code-editor`.
`/system-monitor` `/task-logs` `/plans` `/terminal` `/desktop` `/code-editor`. (`/browser` is a pair now too —
`/browser/:tabId`.)
The five settings pages are route **pairs** now, not flat screens — `/settings/{profile,ai,system,integrations,user-management}`
plus a `:section` each (M6). There has never been a `/settings/apps`; that entry was wrong when this list
was written.
@@ -101,7 +102,15 @@ is **one design decision** that cascades across many files:
- **Dock / Header active styling** (`Dock.tsx:43,78` · `Header.tsx:53,112`) — destinations are already real
`<Link>`s; only the *active* class is JS-derived from `useLocation`. Switch to react-router `<NavLink>` and drop the hand-rolled `isActive`.
- **Browser tabs** (`Browser/TabList.tsx:93`) — ephemeral CDP targets (polled, come/go every few seconds); a durable `/browser/:targetId` is dubious. Probably leave as selection.
- ~~**Browser tabs**~~ (`Browser/TabList.tsx:93`) — **done, against this file's own advice.** The objection
was that a CDP target id is ephemeral, so a durable `/browser/:tabId` is dubious. True of *bookmarking*,
and irrelevant to everything else the URL buys: the id was in an onClick closure, three components read a
`BROWSER_SELECTED_TAB` global, and the row could not be cmd-clicked. Staleness is handled where it
actually shows up — the preview now distinguishes "no tab open" from "that tab is no longer attached"
by checking the polled target list, which it gets from the same React Query key the list uses, so it
costs no extra request. En route: the row's Focus and Close buttons were nested *inside* the row
`<button>`, which is invalid HTML and only worked because of two `stopPropagation` calls; they are
siblings of the anchor now. And its "Set up in Integrations" was a raw `<a href>` that reloaded the SPA.
- **Jobs step/iteration** (`Jobs/JobDetail.tsx:234,255`) — intra-detail sub-selection; only if we want `/jobs/:id/:stepKey` deep links.
- **Preview slug** (`Preview/PreviewApp.tsx:23`) — Preview usually derives its target from the surrounding dashboard/project `cwd`; the manual picker is a fallback. Probably leave URL-less.
- **FileBrowser widget** (`FileBrowserWidget/.../BrowseTab.tsx:36`) — compact sidebar widget; keeping its browse cursor local is defensible.
@@ -209,7 +218,7 @@ publishers means changing the chat panel, which is another agent's, so it is wri
- [ ] Dock + Header + mobile sheet → react-router `<NavLink>` for active state; drop hand-rolled `isActive` (`Dock.tsx`, `Header.tsx`).
- [ ] "New Chat" → `<Link to="/chat/new">` (`SessionList.tsx:68`) once H4's channel cleanup lands.
- [ ] Jobs back button + any `navigate('/jobs')` → shared `BackButton` (`JobDetail.tsx:709`).
- [ ] Decide/skip: Browser tabs, Jobs step deep-link, Preview slug, FileBrowser widget, Music-favorites/Monitor-scope view toggles.
- [ ] Decide/skip: Jobs step deep-link, Preview slug, FileBrowser widget, Music-favorites view toggle. (Browser tabs: **done** — see the LOW section. Monitor scope: **done** as M10, it was not a view toggle.)
### Cross-cutting for the refactor itself
- [ ] Standardise a URL-as-source-of-truth pattern for panel selection (replace the `usePanelChannel`/`useGlobal`
+12 -1
View File
@@ -667,7 +667,18 @@ All the same bug: an app guessing "am I being closed?" from an unmount, or payin
walk the sweep instead of leaving the mailbox. `EMAIL_FOLDER` stays a global for now: it is read in
one component and is view state rather than selection. Putting it in `?folder=` is a real but
separate item.
Remaining here: Music, Browser. **Chat detail (`chat:selected-session`) is chat-owned —
**Browser is done** — `/browser/:tabId`, `BROWSER_SELECTED_TAB` deleted from its three readers.
The audit had this one filed under "probably leave as selection", on the grounds that a CDP target
id dies with the browser session so a durable URL is dubious. That is an argument about
*bookmarking*, and bookmarking is the least of what the URL was buying: the id lived in an onClick
closure, three components shared a global, and a tab row could not be cmd-clicked. The staleness
the audit worried about is real and is now handled where it shows — the preview tells "no tab open"
from "that tab is no longer attached" by checking the polled target list, which both panels read
from one React Query key, so it costs no extra request. Two defects fell out on the way: the row's
Focus and Close buttons were nested inside the row `<button>` (invalid HTML, held together by two
`stopPropagation` calls — they are siblings of the anchor now), and "Set up in Integrations" was a
raw `<a href>` that reloaded the whole SPA.
Remaining here: Music. **Chat detail (`chat:selected-session`) is chat-owned —
leave it; it is written up in `COMMS/`.**
### 5.9 The context has grown an app-config section — _(found 2026-08-07)_