Fix and simplify side panel splits - #2059
Merged
ymichael merged 6 commits intoAug 20, 2026
Merged
Conversation
ymichael
added a commit
that referenced
this pull request
Aug 20, 2026
## What was wrong [`SidebarSplitDivider`](https://github.com/get-bb/bb/blob/6be45053be92f964895038fc374a45e759087479/apps/app/src/components/secondary-panel/SidebarSplitContainer.tsx#L679-L757), introduced by [#1601](#1601), wrote both `cursor` and `user-select` to `document.body` at drag start and cleared them at drag finish. Both properties are inherited, so each write invalidated styles across the full app tree. That repeats the root cause measured in [#1992](#1992), where inherited body/root mutations cost hundreds of milliseconds per recalculation on a roughly 20k-element long-thread DOM. The divider also had no unmount cleanup for its native pointer listeners or temporary flex values. ## What changed - Keep the active split-divider cursor in local `SidebarSplitContainer` state instead of mutating `document.body` or the document root. - Mount the existing `IframeDragGuardOverlay` after the split content, with `col-resize` or `row-resize` for the active divider. This keeps the drag captured across iframe/browser-backed pane content without inserting a guard before a large sibling subtree. - Continue relying on the divider's existing pointer-down `preventDefault()` to prevent text selection, matching #1992. - Cancel the in-flight resize on divider unmount: remove native pointer listeners, release capture when held, clear drag chrome, and restore uncommitted flex values. - Remove the now-unused global body cursor helpers, while preserving the panel-library takeover used by main.tsx. This is an app-only change with no host-daemon protocol or other wire changes. It reuses the existing drag guard and straightforward component state; it does not introduce another split framework or alter the split layout model. ## How you verified The focused regression coverage failed before the production change and passed after it. Before the fix, the new assertions observed `cursor: col-resize; user-select: none` on `body` during pointer-down and a stuck `data-dragging="true"` state after unmount. - `pnpm exec turbo run test --filter=@bb/app --force -- src/components/secondary-panel/SidebarSplitContainer.test.tsx src/components/layout/AppLayout.sidebar-resize.test.tsx` — 2 files, 20 tests passed. - `pnpm exec turbo run build typecheck lint --filter=@bb/app` — build and typecheck passed; lint passed with 0 errors and 156 existing warnings. - `git diff --check` — passed. Coverage proves that split drag does not change body/document-root inline styles, pointer-down is default-prevented, the guard mounts after split content with both row and column cursors, pointer-up/cancel remove it, and unmount cancels the drag and removes its native listeners. ## Relationship to #1992 and #2059 This applies #1992's measured performance fix to the internal right-panel divider path that #1992 did not cover. Draft [#2059](#2059) fixes the separate mirrored split-tree correctness problem. Its current head (`4aca1e08`) still contains both body mutations, so it does not supersede this fix. The changes overlap only in `SidebarSplitContainer.tsx` and its test because #2059 rewrites that component; if #2059 lands first, the rebase should keep its single-tree rendering while retaining this PR's container-local cursor state, final drag guard, and divider cleanup. > AGENT GENERATED: by GPT-5.6-Sol
ymichael
force-pushed
the
bb/investigate-buggy-side-panel-splits-thr_id6scmvsem
branch
4 times, most recently
from
August 20, 2026 22:40
3cc4ec9 to
f48afb7
Compare
ymichael
force-pushed
the
bb/investigate-buggy-side-panel-splits-thr_id6scmvsem
branch
from
August 20, 2026 22:41
f48afb7 to
4567374
Compare
ymichael
marked this pull request as ready for review
August 20, 2026 22:45
ymichael
deleted the
bb/investigate-buggy-side-panel-splits-thr_id6scmvsem
branch
August 20, 2026 22:59
ymichael
added a commit
that referenced
this pull request
Aug 20, 2026
## What was wrong PR #2088 correctly preserved `PluginFileOpenerSource.experimental_hostId` through the Docs frontend and private RPC, but `resolveOpenerFile` consumed it only for `source.kind === "host"`. Root Compose opens a project-source Markdown file as `{ kind: "workspace", environmentId: null, projectId, experimental_hostId }`, so Docs accepted the source identity and then skipped its only workspace branch, throwing “Docs can open workspace, host, and thread-storage files only.” The same project-backed file already works in the PDF opener through the core project content route. ## What changed Docs now resolves a workspace source with no environment and a project ID through the project's authoritative local-path source. An explicit `experimental_hostId` selects that host; omission resolves through `system.config().primaryHostId`, matching the public opener contract and core project-workspace routing. The resolved source root and host feed the existing confined Files SDK read, preview, and optimistic-write calls. Missing, duplicate, or non-absolute project-source identities fail closed instead of selecting another machine. This is the smallest complete fix: one resolver branch plus one server regression. Environment-backed workspace, absolute host-file, and thread-storage behavior is unchanged. There is no SDK, CLI, guide, configuration, or host-daemon wire change, so `HOST_DAEMON_PROTOCOL_VERSION` is unchanged. ## How you verified The pre-fix focused regression failed both project-backed cases with the reported error (2 failed, 31 passed): - `pnpm exec turbo run test --filter=bb-plugin-simple-notes -- server.test.ts` After the fix and the final rebase onto `deb723091` / merged #2059: - The focused server suite passed 32 tests. The regression proves selected-host read, preview, and optimistic save routing; omitted-host primary routing even when a different project source is marked default; and rejection of an unknown selected host before file I/O. - `pnpm exec turbo run test typecheck build --filter=bb-plugin-simple-notes --force` passed: 66 tests, Docs build and typecheck, 7 successful Turbo tasks. - `git diff --check origin/main...HEAD` passed. Related to #2088, #2083, and #2059. > AGENT GENERATED: by GPT-5.6-Sol
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 free
to 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 was wrong
The split right panel rendered the same layout twice: a shared tab-header tree and a separate pane-body tree. The header copy always laid its children out horizontally, so stacked splits detached each tab strip from its pane, and the paired resize handlers could mutate the mirrored tree on the wrong axis. Tab rendering was also split across parallel
fileTabsandtabModelsrepresentations, while root-compose and plugin fixed tabs used separate adapters, making pane-local selection and content inconsistent.What changed
document.body.fileTabs/tabModelsjoin with one renderable tab descriptor that owns its model, chrome, actions, content renderer, and layout behavior.navPanel.experimental_fixedTabscan mount once per active visible split pane; the updated contract remains covered by the unpublished plugin SDK0.4.10already reserved on main.There are no host-daemon protocol or other wire changes.
How you verified
pnpm exec turbo run typecheck --filter=@bb/app --filter=@get-bb/plugin-sdkpnpm exec turbo run lint --filter=@bb/app --filter=@get-bb/plugin-sdk(0 errors; existing warnings only)node packages/plugin-sdk/scripts/check-npm-version-guard.mjsBefore and after
Thread panel split
Root/new-thread split
Fixes the side-panel split regression introduced by
4e13e3f.