Split brains-pane.tsx into sidebar, detail pane, and collection view - #925
Merged
Conversation
brains-pane.tsx held seven components in one 704-line file. Split along the existing component boundaries — every component moved wholesale, so no state or effect changed owner and the rendered output is identical. - brains-pane.tsx (123): BrainsListContent, the sidebar project list - brains-detail-pane.tsx (276): BrainsDetailPane, BrainsOverview, BrainProjectDetail, CollectionPill - brains-collection-view.tsx (300): BrainCollectionView, DeleteBrainDialog, plus a shared DeleteTarget type that was previously spelled out twice - brains-utils.ts (3): repoBasename, used by the sidebar and the detail header automations-pane.tsx is the sole consumer; its import block now pulls BrainsDetailPane from the new file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
selfcontained added a commit
that referenced
this pull request
Aug 14, 2026
* Cover the Brain Explorer panes and fix two routing bugs Closes the last two zero-coverage surfaces from the #925 brains split, and fixes two real bugs the coverage work surfaced in brains-detail-pane.tsx. A malformed base64url repo root recovered by calling navigate() during render. React Router v7 refuses imperative navigation during render — it warns and no-ops — so the undecodable root stayed in the address bar and came straight back on reload or from a shared link. It is now a declarative <Navigate replace />. The collection path segment was decoded a second time on the way to the collection view, but react-router has already decoded it. A collection named "50%off" threw URIError and took the pane down; one named "%41" silently selected a collection that does not exist. Both names are reachable — the sidebar links to whatever collection an agent created. brains-detail-pane.test.tsx (20 tests) mounts the pane on the same three routes the real router declares and pins the repo-root decode and its malformed fallback, the collection round trip, the pill counts and active marker, the search wiring, and the destructive "Clear project" flow including its wire contract, summed toast, failure path and pending gating. 16/17 mutants killed; the survivor is the collections loading guard, which is unobservable because the query's data already defaults to []. brains-pane.test.tsx (14 tests) pins the encode half of the same URL contract plus the sidebar's list states, per-type count gating, keyboard activation and selection highlight. 18/18 mutants killed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Address review: assert the replace semantics, drop two hollow tests The first battery never mutated the { replace: true } flags, so nothing guarded the half of the malformed-root fix that matters most: pushing instead of replacing leaves the undecodable URL one Back press away, and going Back redirects forward again — a trap. A navigation-type probe now pins REPLACE on all three redirects and PUSH on ordinary pill navigation. Deleted the loading-pills test. It could not fail: useBrainCollections already defaults data to [], so both collectionsLoading guards are unobservable, and the assertion filtered for a collection no fixture declared. The dead guards are recorded for a future run rather than covered by a test that certifies nothing. Renamed the post-delete test to the navigation it actually protects — leaving the project unmounts the dialog either way, so that test cannot be what proves the dialog closes. Also: dropped a sidebar test that duplicated the routing case, split the Enter/Space test so neither reuses a node captured before its own route change, tightened the pill count assertions to exact text, relaxed the skeleton count to presence, and stubbed Toaster alongside toast. Batteries after the changes: 20/21 on brains-detail-pane.tsx (the survivor is the proven-unobservable loading guard) and 19/19 on brains-pane.tsx. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
apps/web/src/components/app/brains-pane.tsxwas a 704-line file holding seven components. This splits it along the boundaries that were already there — every component moved wholesale.brains-pane.tsxBrainsListContent— the sidebar project listbrains-detail-pane.tsxBrainsDetailPane,BrainsOverview,BrainProjectDetail,CollectionPillbrains-collection-view.tsxBrainCollectionView,DeleteBrainDialog, sharedDeleteTargettypebrains-utils.tsrepoBasename— used by both the sidebar and the detail headerautomations-pane.tsxis the sole consumer; its import block now pullsBrainsDetailPanefrom the new file. No barrel re-export was added, matching the convention from #855, #883, and #913.Why it was a candidate
704 lines, three logically independent UI regions (sidebar / project detail chrome / collection contents), and a compound-component shape that had grown over time. It was the queued
next_focusfrom the previous run (recorded there as 482 lines — that count was actuallybrain-cards.tsx).Behavior
Purely structural. No hook changed owner, so neither the state-lifetime hazard from #803 nor the effect-registration-order hazard from #870 applies here. The one non-mechanical change is that the 4-variant delete-target union — previously written out twice, once in
BrainCollectionView'suseStateand once inDeleteBrainDialog's props — is now a singleDeleteTargettype in the file that owns both.Validation
pnpm run finalize:web— type check + production build greenpnpm run test:e2e— 178 passed, 12 skipped (terminal-live, pre-existing)DeleteBrainDialogand clear-project) open and cancel correctly. 0 console errors.Next run
path-input.tsx(531 lines, 14 hooks) — flagged higher-risk for focus/keyboard timing.