Skip to content

Fix main window tab switching when action tab is detached - #90

Merged
marota merged 5 commits into
mainfrom
claude/sync-window-zoom-view-vpF3w
Apr 14, 2026
Merged

marota merged 5 commits into
mainfrom
claude/sync-window-zoom-view-vpF3w

Conversation

@marota

@marota marota commented Apr 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

When the action tab is detached into a popup window, selecting an action card in the popup should not switch the main window's active tab to 'action'. This prevents the main window from blanking out and showing the "Detached" placeholder every time the user clicks a different action card in the popup.

Key Changes

  • Added detachedTabsRef to track the current detached tabs state in a stable ref, allowing callbacks to read the latest detached state without re-binding
  • Modified handleActionSelect to check if the action tab is detached before switching the main window's active tab
    • When detached: skips setActiveTab('action') so the main window stays on its current tab (N or N-1)
    • When not detached: maintains existing behavior of switching to the action tab
  • Modified deselect logic in handleActionSelect to only fall back to 'n-1' when the action tab is inline
    • When detached: skips the fallback so the main window keeps showing whatever tab the user had open
    • When not detached: maintains existing behavior of switching to 'n-1'
  • The popup still receives the updated diagram via the existing render path regardless of detached state

Implementation Details

  • Uses the same ref pattern as activeTabRef to maintain a stable reference to detachedTabs without triggering callback re-binds
  • The action variant diagram fetch still occurs in both cases (detached and inline) to ensure the popup gets the updated diagram
  • Comprehensive test coverage added to verify behavior in both detached and inline scenarios, including selection, deselection, and diagram fetching

https://claude.ai/code/session_01VSVgi5jnBmHLrjb1XZuM9Y

claude added 5 commits April 14, 2026 12:57
When the Remedial Action tab is open in a detached popup, clicking a
different action card used to force the main window to switch to the
action tab — which then rendered only the "view is detached" placeholder
over whatever N or N-1 diagram the user was studying. The detached
popup got the new diagram but the main window lost its context.

`handleActionSelect` now checks whether the action tab is currently
detached (via a ref mirror of the detachedTabs map) and, if so, skips
both the `setActiveTab('action')` call on select and the
`setActiveTab('n-1')` fallback on deselect. The popup still re-renders
with the new diagram because the action PZ / React subtree is unaffected.

Adds 5 regression tests covering select/deselect with and without the
action tab detached.

https://claude.ai/code/session_01VSVgi5jnBmHLrjb1XZuM9Y
The N-1 tab used to source overload halos exclusively from
`result.lines_overloaded`, which is only populated after running
"Analyze & Suggest". As a result, the orange overload highlights stayed
invisible from the moment the user picked a contingency until the
moment they clicked through a remedial-action simulation — even though
the backend already reports the overloaded lines along with the N-1
diagram itself (`n1Diagram.lines_overloaded`).

Add a small `computeN1OverloadHighlights` helper that prefers the
analysis-result overloads when available and falls back to the N-1
diagram's own overload list otherwise, with the user's
selected-overload set further filtering both. Wire `applyHighlightsForTab`
to use it for the N-1 tab. This mirrors what the standalone interface
has been doing.

Tests:
- 8 unit tests for `computeN1OverloadHighlights` covering both sources,
  the override priority, the user-selection filter and the empty
  edge cases.
- 2 integration tests in `App.contingency.test.tsx` verifying that the
  app's overload state is populated immediately after the N-1 fetch
  (no analysis run), including across contingency switches.

https://claude.ai/code/session_01VSVgi5jnBmHLrjb1XZuM9Y
Clicking a different action card while the Remedial Action tab is
detached into a popup used to snap the popup back to the N / N-1
viewBox, losing the zoom the user had on the previous action. The
capture + restore pair in handleActionSelect / the action-diagram
re-sync effect were both gated on `activeTab === 'action'`, which is
FALSE when the tab is detached (the main window is on N or N-1), so
the capture fell through to the N-1 viewBox fallback and the restore
was skipped entirely.

Both paths now treat "action tab shows the action diagram" as either
`activeTab === 'action'` OR `detachedTabsRef.current?.action` being
truthy, matching the inline behaviour for the detached case.

Adds 3 regression tests in useDiagrams.test.ts:
- viewBox preserved across action switches when detached;
- viewBox preserved across action switches when inline (guards the
  long-standing attached-case behaviour);
- N-1 viewBox fallback still kicks in when there is no prior
  action-tab viewBox to preserve.

https://claude.ai/code/session_01VSVgi5jnBmHLrjb1XZuM9Y
Clicking an asset badge inside an action card used to force the main
window's activeTab to 'action' via handleAssetClick, even when the
action tab was currently detached into a popup. That blanked whatever
N / N-1 view the operator had open and replaced it with the "view is
detached" placeholder — exactly the regression covered by the earlier
handleActionSelect fix, but from a different entry point. The N and
N-1 branches of handleAssetClick had the same symmetric problem for
overload-badge clicks in the OverloadPanel.

handleAssetClick now:
  - routes the auto-zoom target through setInspectQueryForTab(tab, …)
    so the zoom still lands on the correct (possibly detached) tab
    regardless of the main window's activeTab;
  - skips the setActiveTab call when the click targets a detached tab
    (action, n or n-1). Inline clicks behave exactly as before.

Adds 6 regression tests in useDiagrams.test.ts covering:
  - action-card asset click with action tab detached (stays on n-1);
  - action-card asset click with action tab inline (still switches);
  - n overload badge click with N tab detached (stays on action);
  - n-1 overload badge click with N-1 tab detached (stays on action);
  - n-1 overload badge click with N-1 tab inline (still switches);
  - different-action asset click with action detached still delegates
    to handleActionSelectFn (whose own detached guard is tested
    separately).

https://claude.ai/code/session_01VSVgi5jnBmHLrjb1XZuM9Y
Fills in the doc gap left by the four fixes shipped for detached-tab
interactions:

- New "Main window stays steady on detached-tab interactions" section
  stating the invariant, listing every entry point it covers
  (handleActionSelect select / deselect, handleAssetClick for
  action / n / n-1), explaining why zoom still lands on the right tab
  thanks to setInspectQueryForTab, and showing the ref-mirror
  implementation pattern.
- New "Preserving action-tab zoom across action switches" section
  walking through the capture + restore pattern in useDiagrams and
  why both halves had to learn about the detached case.
- Feature-summary bullets pointing at both new sections.
- Regression-tests section extended with the 14 new useDiagrams
  tests grouped by describe block.

https://claude.ai/code/session_01VSVgi5jnBmHLrjb1XZuM9Y
@marota
marota merged commit 05667b7 into main Apr 14, 2026
2 checks passed
marota pushed a commit that referenced this pull request Apr 30, 2026
Reconciliation of section 2 (0.5.0):
- Drop misattributed PRs that were actually pre-rebrand: save/reload
  (#49/#52), MW Start (#62), interaction-logging (#64), SLD highlights
  (#63), load shedding initial integration (#61). All now properly
  cited in section 1.5–1.6.
- Disambiguate App.tsx refactor history: PR #56 (hooks, 2100 → 800,
  pre-rebrand) vs PR #74 (components, 1000 → 650, 0.5.0) vs PR #75
  (memoization Phase 2, same LoC).
- Add accurate 0.5.0 PRs: #66 (vectorization w/ benchmark table),
  #69/#70/#71 (UI polish), #72 (curtailment), #73 (loads_p/gens_p
  format + configurable MW), #74/#75 (App.tsx decomposition),
  #78 (PST tap re-simulation), #84/#86/#87/#90 (detachable tabs).
- Add a recap table summarizing what's truly new in 0.5.0.

Diagrams added (Mermaid, GitHub-rendered):
- Gantt timeline of all 4 phases (top of doc).
- High-level architecture (frontend / backend / data).
- Two-step analysis sequence diagram (section 1.6).
- App.tsx LoC evolution flow (section 2.4).
- Backend mixin decomposition before/after PR #104/#106 (section 3).
- PyPSA-EUR pipeline flowchart (section 4).

https://claude.ai/code/session_01Pg7fuCUG2edfm5PyHS6SbN
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