Skip to content

Remove blank-tab creation from the side pane - #850

Open
morgmart wants to merge 1 commit into
mainfrom
morganm/remove-blank-tabs
Open

morgmart wants to merge 1 commit into
mainfrom
morganm/remove-blank-tabs

Conversation

@morgmart

Copy link
Copy Markdown
Contributor

What this does

The side pane no longer has a way to create an empty tab. The plus button, the split toggle's "open a blank tab when empty" behavior, and the New tab picker (search for a channel, DM, or tool) are removed in both Messages and Me. Tabs now open only from content: threads, profiles, channel settings, channel menu panels such as Usage, and linked sessions.

This PR only removes. It doesn't add main-pane tabs, placement settings, or dragging; that's separate follow-up work.

Why it matters

Buzz should open things where you need them, from the thing you're looking at. A blank tab that asks you to go find something works against that. You end up searching inside a pane instead of following the content that brought you there. Removing it makes the side pane mean one thing: details and conversations you opened from somewhere.

What people lose: opening an arbitrary channel or DM beside the current one, and opening Todos or Terminal as a tab. Todos and Terminal still open from their own channel launchers. Tabs were only ever kept in memory, so nobody will see a leftover blank tab after updating.

New rule: Side-pane tabs are created only by opening content, never by an empty "new tab" action.

How it works

  • The shared tab host no longer offers an Add tab action. Messages and Me now control the pane only through their existing open/closed state, so neither page can create a blank tab.
  • When the pane has nothing to show, the split toggle is unavailable but still focusable. Closing the last tab still has a stable place to return keyboard focus. When content opens, the toggle works as before.
  • Code that only the picker could reach is deleted along with it: the Me-only variant of conversation tabs, the launcher shortcut that switched to an already-open tool tab, and the picker-only tool icons. Channel menu panels keep their existing icon.
  • Per-channel tab memory, drafts, linked-session tabs, thread tabs inside them, and channel tools are unchanged.

Prior work

This reverses the picker introduced in #413 and refined in #505 (@mahanti) and #675 (@loganj). Draft #570 (@jameskraus) edits the deleted picker file. It will conflict, so we should agree on sequencing.

Verification

All on this branch's head (base 37dcd836f):

  • pnpm typecheck, changed-file Biome, git diff --check, pnpm design:check, and the browser CI discovery test pass.
  • Focused Vitest suites for tab state, conversation tabs, the shared tab host, channel panels, and conversation-tab recovery pass.
  • The pre-push hook passed: types, the full unit suite, design-system checks, and Clippy.
  • On this head, Chromium and WebKit pass the full channel-tabs, me-workspace, todos, channel-usage-geometry, and session-sharing browser files.
  • message-navigation and scrollbar-polish passed in both engines before the final removal of picker-only code. Hosted CI will rerun them on this head.
  • Deliberate mutations prove the restored focus checks are real. With each break in place, the matching test fails in Chromium:
    • Restored side tabs steal focus from the main composer.
    • The last tab closes without returning focus.
    • The last conversation tab closes without returning focus to the toggle.

Browser coverage changes

Removed or changed Why Replacement
Picker component tests (search, ranking, categories, keyboard) Feature removed None needed
channel-tabs: opening tabs via the picker, New tab state, Add tab overflow Feature removed Tabs now open from real linked-session chips. The same journey checks drafts, restoration, send routing, deduplication, unavailable conversations, responsive surface at 1440/800/390 in both themes, restored-focus and last-tab focus. A crowded-strip test uses six real tabs.
channel-tabs: picker-opened DM send Path removed Linked-session send keeps signed destination routing checked
me-workspace: Me side-tab drafts and send via picker Me can no longer open conversation tabs New check: Me's empty toggle is unavailable and creates nothing. Recipient signing and outsider rejection now run through Me's real main reader.
todos: Todos opened as a picker tab Path removed Launcher open/close and saving still covered. Tool-tab survival when opening a thread or profile moved to Channel Usage, the remaining tool tab.
scrollbar-polish: picker list scrollbar Feature removed Remaining panel and Settings scrollbar checks unchanged
message-navigation: focus started from Add tab Button removed Uses the real tab Close button

Not yet checked

  • Hands-on try in the desktop app, plus native/packaged behavior.
  • Disabled-toggle tooltip and appearance by eye at enlarged text sizes. The automated runs only covered themes and widths.
  • Hosted CI on this push.

Tabs now open only from content: threads, profiles, channel settings, channel menu panels and linked sessions. The plus action, the empty-pane toggle's blank tab and the channel/DM/tool picker are removed in Messages and Me. Todos and Terminal keep their channel launchers. The empty split toggle stays focusable but unavailable so closing the last tab keeps a stable focus target.

Signed-off-by: morgmart <98432065+morgmart@users.noreply.github.com>
@morgmart
morgmart marked this pull request as ready for review October 11, 2026 03:54
@morgmart
morgmart requested a review from a team as a code owner October 11, 2026 03:54

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No changes requested from this source review. The removal is consistent across Messages and Me, while the inspected content-opening and tab-close paths retain their existing state and focus handling.

Star Lord automated source review via Wes’s account: head cea3498ea3b55018fa7a89a1a4bb7e5e0be70261, base 37dcd836fbcf1613ddd27cece5a99e04d601bd64. No tests or app execution performed; hosted CI, desktop/native behavior, and enlarged-text/tooltip appearance remain unverified.

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Carl, an automated reviewer, commenting via Wes’s GitHub account.

No demonstrated production blocker. One non-blocking regression-coverage finding inline; recommend restoring those retained checks before merge. The content-only tab creation and focusable-disabled toggle implementation otherwise match the stated scope.

Reviewed head cea3498ea3b55018fa7a89a1a4bb7e5e0be70261 against base 37dcd836fbcf1613ddd27cece5a99e04d601bd64, with an independent keyboard/accessibility and assertion-preservation pass from Princess Donut.

Validation: current hosted CI is green (Windows native validation skipped). A separate local browser-fixture probe passed all four Messages/Me × Chromium/WebKit cases, covering both themes and widths 1440/800/390 at 200% interface size. It checked keyboard reachability, hover tooltip visibility, inert Enter/Space/pointer activation, and draft retention. Selected narrow/wide screenshots showed the disabled control and focus ring visible with its tooltip inside the viewport. This exercised the production frontend with modeled transport, not a native app or live relay; native/assistive-technology and human acceptance remain unverified. No tracked source changes.

Comment on lines +225 to +229
await expect
.poll(() => list.evaluate((el) => el.scrollWidth > el.clientWidth))
.toBe(true);
await expect(list).toHaveCSS("overflow-y", "hidden");
const height = (await list.boundingBox()).height;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking coverage regression: restore the retained tab-strip assertions.

Replacing blank tabs with six linked sessions is the right setup, but the rewritten journey drops checks for behavior that remains part of the navigation-tab contract: active Close visibility, inactive Close reveal on hover/keyboard focus, hover-only scrollbar visibility (including hiding while focus remains in the strip), the 4px track, and tab-row vertical-position stability. The overflow and list-height assertions here do not cover those behaviors. For example, making inactive Close buttons permanently transparent would no longer fail this journey.

These checks existed at base 37dcd836 in this file, lines 304–370. I found no equivalent replacements in browser/design-system specs or source tests. They still correspond to src/shared/design-system/DESIGN.md:1021; AGENTS.md:152–164 requires preserving retained assertions when rewriting browser coverage.

Restore them around the existing six content tabs, using an outside hover target instead of the deleted Add button, and run the affected file in both engines. Keep Add/picker-specific checks removed. This is lost regression protection, not an observed production UI failure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants