Skip to content

fix(desktop): lone tile header beats persisted headerHidden (unclosable dead zone) - #86191

Open
zmuleyu wants to merge 1 commit into
NousResearch:mainfrom
zmuleyu:fix/desktop-lone-tile-header-close
Open

fix(desktop): lone tile header beats persisted headerHidden (unclosable dead zone)#86191
zmuleyu wants to merge 1 commit into
NousResearch:mainfrom
zmuleyu:fix/desktop-lone-tile-header-close

Conversation

@zmuleyu

@zmuleyu zmuleyu commented Aug 14, 2026

Copy link
Copy Markdown

Problem

A lone preview/session tile in a zone with a persisted headerHidden: true (set by the double-tap-on-strip gesture, or left over from an older build) renders with no tab strip: no tab to grab and no close gesture. Because preview bodies are webview/iframe guests, right-click (zone menu) and keyboard focus never reach the host, so the zone menu's Close and ⌘W are both unreachable. The zone becomes an unclosable dead zone; normalize deliberately preserves the persisted flag across restarts, so the only escape was a full layout reset.

Repro: open a URL preview (it docks as its own lone zone, placement: 'main') → double-click its tab strip to hide the header → restart the app (flag persists) → the preview has no strip and cannot be closed from the visible UI.

Fix

forceLoneHeaderForPanes already encodes the invariant "a closeable surface never becomes an unclosable dead zone", but TreeGroup evaluated node.headerHidden ?? before it, so the persisted flag silently won. This extracts the decision into resolveZoneHeaderHidden() with explicit precedence:

  1. headerVeto (full-page views) still suppresses the strip;
  2. a lone closeable tile (forceLoneHeader) keeps its strip even over a persisted hide — the fix;
  3. every other zone keeps the user's persisted choice exactly as before (stacked chat strips, side chrome, etc. are untouched).

Tests

  • New resolveZoneHeaderHidden cases in lone-header.test.ts: the dead-zone regression (persisted hide + lone tile → strip), veto, preserved choices, defaults.
  • npx vitest run src/components/pane-shell: 20 files / 109 tests pass. tsc --build clean.

…le dead zone)

A lone preview/session tile whose zone had a persisted headerHidden:true
(a double-tap hide, or a leftover from older builds) rendered with no tab
strip: no tab to grab, no close gesture, and the webview/iframe body
swallows right-click and focus, so neither the zone menu nor Ctrl+W could
reach it — a layout reset was the only escape.

resolveZoneHeaderHidden() centralizes the precedence: headerVeto wins; a
lone closeable tile (forceLoneHeader) keeps its strip even over a persisted
hide; every other zone keeps the user's persisted choice as before.
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/desktop Electron desktop app (apps/desktop/*) labels Aug 14, 2026
@Enough1122

Copy link
Copy Markdown
Contributor

AI code review — automated review for reference, author can ignore or act on any point.

fix(desktop): lone tile header beats persisted headerHidden (unclosable dead zone)

The precedence logic is clearly documented and the test matrix covers the important corners. Minor observations:

  1. When resolveZoneHeaderHidden forces the strip visible over a persisted headerHidden: true (lone closeable tile), node.headerHidden itself is never updated — the model still records "hidden" while the render shows the strip. Any later code that reads headerHidden directly (toggle state, layout persistence, tree round-trips) can disagree with what is on screen. Consider normalizing the persisted value when the force path wins, or centralizing all reads through the resolver.

  2. forceLoneHeader is already derived from shown.length === 1 && isCollapsePane(shown[0]) inside forceLoneHeaderForPanes, so the shownCount <= 1 check in the resolver is partially redundant with the flag. Harmless, but the two conditions could drift if the helper's semantics change.

  3. headerVeto returns true unconditionally, even for a lone closeable tile that would otherwise be forced visible. Consistent with the documented precedence, but worth a comment noting a full-page webview pane remains headerless/unclosable by design.

No blocking issues.

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

Labels

comp/desktop Electron desktop app (apps/desktop/*) P3 Low — cosmetic, nice to have type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants