Skip to content

fix(desktop): cancel interrupted pane and session drags - #107330

Open
plcunha wants to merge 2 commits into
NousResearch:mainfrom
plcunha:fix/desktop-cancel-interrupted-tab-drags
Open

plcunha wants to merge 2 commits into
NousResearch:mainfrom
plcunha:fix/desktop-cancel-interrupted-tab-drags

Conversation

@plcunha

@plcunha plcunha commented Sep 10, 2026

Copy link
Copy Markdown

Summary

Cancel abandoned in-app drag sessions when the window loses focus, the initiating handle loses pointer capture, or a subsequent pointer move reports the primary button already released. Restore cursor/selection state, remove listeners, release guards, and clear drag/drop stores without committing a drop or swallowing the next independent click.

The shared primitive covers pane tabs (including Sessions), pane handles, and sidebar session drags. Normal taps, committed drops, and Escape cancellation keep their existing semantics. Pointer events are scoped to the initiating pointer and teardown is idempotent because releasing capture may itself trigger capture-loss notification.

RED proof

Command, from apps/desktop:

npx vitest run src/components/pane-shell/tree/renderer/drag-session.test.ts

Before the production fix, all three interruption cases failed:

cancels on blur without swallowing the next independent click
cancels on lostpointercapture without swallowing the next independent click
cancels on released-move without swallowing the next independent click
AssertionError: expected 'sessions' to be null
Tests 3 failed | 1 passed (4)

After the fix:

Test Files 1 passed (1)
Tests 4 passed (4)

The normal tap/drop control passed before and after. Tests execute startDragSession and dispatch events; they do not assert source spelling. The existing session-drop fixture now supplies the pointer identity and button state of an actual held-pointer gesture.

Code path trace

  1. A pane tab or session row starts startDragSession; movement past the threshold captures the pointer, disables selection, installs a guest-pointer guard and publishes drag state.
  2. Previously, only pointerup, pointercancel, or Escape ended the session. Focus/capture loss was ignored, and a subsequent move with buttons=0 continued an abandoned drag.
  3. Add interruption teardown and a released-button check. Do not reuse the Escape release-click trap for interruption: that trap waits for a future pointer release and can consume the next unrelated click.

Widening audit

Verification

From apps/desktop:

  • npx vitest run src/components/pane-shell/tree src/app/chat/session-drag.test.ts: 32 files, 168 tests passed.
  • npx tsc -p tsconfig.json --noEmit: passed.
  • ESLint on all three changed files: passed.
  • git diff --check: passed.

Scope and native QA limitation

Investigation began with a macOS report of an unresponsive sidebar after interacting with a narrow Sessions titlebar tab. This PR proves and fixes the interrupted-drag lifecycle defect; it does not claim to have reproduced the original macOS compositor/window-move sequence. Validation above is Linux/jsdom, not a native macOS end-to-end test. No changes to Electron drag-region geometry are included.

Native follow-up: start dragging a Sessions tab, switch focus or release outside the renderer, return, and verify the next sidebar click works without Escape. Also verify ordinary tab reorder/docking and window dragging remain functional. If the original simple-click symptom persists, inspect native hit-testing separately rather than treating these unit tests as proof of that symptom's resolution.

@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 Sep 10, 2026

This branch has not been deployed

No deployments
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.

2 participants