Skip to content

fix(panel): persist panel identity to prevent position/size swap on project switch#3424

Merged
gregpriday merged 4 commits intodevelopfrom
feature/issue-3419-panel-positions-sizes-swap
Mar 16, 2026
Merged

fix(panel): persist panel identity to prevent position/size swap on project switch#3424
gregpriday merged 4 commits intodevelopfrom
feature/issue-3419-panel-positions-sizes-swap

Conversation

@gregpriday
Copy link
Collaborator

Summary

  • Panels in a two-pane split layout were swapping left/right positions and widths when switching back to a project, because twoPaneSplitStore persisted only a scalar ratio with no record of which panel ID occupied the left slot
  • The fix persists the left panel's ID alongside the ratio, so when the layout mounts it can detect if the restored tab group order differs from what was saved and invert the ratio accordingly
  • A backfill path handles legacy persisted state (null panel IDs) gracefully, defaulting to the current order so existing sessions are unaffected

Resolves #3419

Changes

  • twoPaneSplitStore.ts: extended state shape to store leftPanelIdByWorktreeId alongside the ratio; added resolveRatio helper that inverts when the persisted left ID no longer matches the current left panel
  • TwoPaneSplitLayout.tsx: calls resolveRatio on every render so cross-session order changes are corrected before the ratio is applied; existing in-session prevTerminalIdsRef inversion logic is preserved and still fires for live drags
  • fix(panel): backfill legacy null panel IDs and extract ratio resolver commit extracts the resolver into a testable helper and handles null IDs from older persisted state

Testing

Unit tests in src/store/__tests__/twoPaneSplitStore.test.ts cover the swap-detection, inversion, backfill, preferPreview default, and in-session drag paths. Persistence boundary hardening tests in persistenceBoundaryHardening.test.ts were updated to match the new state shape. All tests pass.

- Change ratioByWorktreeId from Record<string, number> to Record<string, WorktreeRatioEntry>
- Store ordered [leftPanelId, rightPanelId] pair with each ratio entry
- Replace useEffect swap detection with synchronous useMemo inversion
- Add Zustand persist migration (v0→v1) for existing scalar ratio values
- Update all tests for new WorktreeRatioEntry shape
- Format twoPaneSplitStore.ts to satisfy prettier checks
- Format twoPaneSplitStore.test.ts to satisfy prettier checks
- Add useEffect to backfill [null, null] panels on first render for migrated entries
- Extract resolveEffectiveRatio as pure testable helper function
- Add comprehensive tests for ratio inversion logic (swap, stale, partial, null)
- Use resolveEffectiveRatio in TwoPaneSplitLayout useMemo
- Auto-format backfill effect and import line
@gregpriday
Copy link
Collaborator Author

Review status: Ready

Cross-PR holistic review — no file overlap or semantic conflicts with other open PRs (#3421, #3422, #3423). All 4 PRs are independent and safe to merge in any order.

@gregpriday gregpriday merged commit 620ac68 into develop Mar 16, 2026
4 checks passed
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.

Panel positions and sizes swap after switching projects

1 participant