Co-Study4Grid / docs /features /state-reset-and-confirmation-dialogs.md
github-actions[bot]
Deploy 7688ef1
13d4e44
|
Raw
History Blame Contribute Delete
10.4 kB

State Reset & Confirmation Dialogs

Overview

Co-Study4Grid manages complex analysis state across contingency selections, N-1 simulations, manual action simulations, and prioritized action results. To prevent stale data from interfering with new analyses, the application implements two complementary mechanisms:

  1. Confirmation dialogs when switching contingency or reloading a study with existing analysis state
  2. Full state reset when loading a new study or applying new settings

Confirmation Dialogs

When They Trigger

A confirmation dialog appears when the user attempts to:

  • Change contingency (select a different branch in the datalist) while analysis results, manual simulations, or action selections exist
  • Reload study (click "Load Study") while analysis state exists

What They Warn About

The dialog informs the user that all previous analysis results will be cleared:

  • Analysis results and pending results
  • Manual simulation results
  • Action selections (favorited, rejected)
  • Action diagrams and N-1 diagrams
  • Overload selections
  • VL overlay (SLD popups)

User Options

  • Confirm: clears all analysis state and proceeds with the action
  • Cancel: reverts to the previous state (for contingency change, the input reverts to the previous branch)

Implementation Details

React Frontend (App.tsx)

The confirmation logic is implemented at the N-1 fetch useEffect level, not at the input onChange level. This is because:

  • The contingency input is a <input list="..."> (datalist) that fires onChange on every keystroke
  • Intercepting keystrokes would interfere with typing partial branch names
  • The useEffect only fires when selectedBranch matches a valid branch in the branches array

Key state:

  • confirmDialog: { type: 'contingency' | 'loadStudy', pendingBranch?: string } | null
  • committedBranchRef: tracks the last confirmed branch (prevents re-prompting for the same branch)

Flow for contingency change:

  1. User types/selects a new branch name
  2. selectedBranch state updates freely (allows typing)
  3. N-1 useEffect fires when the value matches a valid branch
  4. If selectedBranch !== committedBranchRef.current AND hasAnalysisState() is true:
    • Dialog is shown
    • Input reverts to committedBranchRef.current
  5. On confirm: clearContingencyState() is called, committedBranchRef is updated, branch is committed
  6. On cancel: dialog closes, input stays at committed branch

Standalone Interface

No separate standalone mirror is required: the single-file distribution is now frontend/dist-standalone/standalone.html, auto-generated from this same React source via npm run build:standalone (PR #101). It therefore renders the exact same ConfirmationDialog component — the legacy hand-maintained standalone_interface.html that used window.confirm() has been decommissioned and frozen as standalone_interface_legacy.html.


Full State Reset

When It Happens

A complete state reset occurs when:

  1. Load Study is clicked (or confirmed via dialog)
  2. Apply Settings is clicked in the Settings modal

What Gets Reset

Frontend State

Category State Variables Reset Value
Diagrams nDiagram, n1Diagram, actionDiagram, originalViewBox null
Analysis result, pendingAnalysisResult, selectedActionId null
Action tracking selectedActionIds, manuallyAddedIds, rejectedActionIds new Set()
Loading flags analysisLoading, n1Loading, actionDiagramLoading false
Analysis flow selectedOverloads, monitorDeselected new Set() / false
Visualization activeTab, actionViewMode, vlOverlay 'n' / 'network' / null
Branch selectedBranch, committedBranchRef, inspectQuery ''
Messages error, infoMessage, showMonitoringWarning '' / false
Refs lastZoomState, actionSyncSourceRef Reset to defaults

What is NOT reset (preserved across reloads)

  • networkPath and actionPath (user inputs)
  • All settings values (minLineReconnections, minCloseCoupling, etc.)
  • linesMonitoringPath
  • monitoringFactor, preExistingOverloadThreshold
  • ignoreReconnections, pypowsyblFastMode

Backend State

The /api/config endpoint now always reloads the network and resets the recommender service caches, even if the network path hasn't changed. This prevents:

  • Stale in-memory network modifications from previous N-1 simulations
  • Cached simulation environments (_simulation_env) from a previous analysis
  • Leftover _base_network, _last_disconnected_element, _dict_action, _analysis_context

The RecommenderService.reset() method clears, in order: 0. _reset_model_settings() — model selection (active model + compute_overflow_graph toggle) back to defaults (ModelSelectionMixin).

  1. Bumps _prefetch_generation (so any in-flight NAD-prefetch worker discards its result under the service lock instead of writing into the next study's cache), then _drain_pending_base_nad_prefetch() — a no-op when the concurrency lock is present (lock ownership already excludes the worker), a join fallback for lock-less test hosts. See docs/architecture/shared-network-concurrency.md.
  2. Per-study analysis state: _last_result, _is_running, _generator, _base_network, _simulation_env, _last_disconnected_element, _dict_action, _analysis_context, _saved_computed_pairs.
  3. Fast-path caches: _cached_obs_n, _cached_obs_n_id, _cached_obs_n1, _cached_obs_n1_id, _cached_obs_n1_elements, _cached_env_context, _initial_pst_taps, _lf_status_by_variant, _last_step1_time.
    • _cached_obs_n1_elements is the exact contingency element list that produced _cached_obs_n1 (defense-in-depth on top of the variant-ID check, used by run_analysis_step1 to decide whether to reuse the pre-warmed obs and skip the contingency LF). See docs/backend/recommender_models.md § Execution-time breakdown.
    • _last_step1_time stashes the wall-clock of the most recent run_analysis_step1 so the step-2 result event can echo it to the React UI for the "Suggestions produced by …" breakdown.
  4. _layout_cache — the cached grid_layout.json DataFrame used as fixed_positions for NAD generation. Must be cleared so a new study loaded from a different grid does not reuse the previous grid's substation coordinates.
  5. NAD-prefetch state: _prefetched_base_nad, _prefetched_base_nad_error, _prefetched_base_nad_event, _prefetched_base_nad_thread.
  6. Overflow-graph toggle state:
    • _overflow_layout_mode — reset to "hierarchical" so a new study's Overflow Analysis tab always opens in the default layout.
    • _overflow_layout_cache — cleared so file paths produced for the previous contingency cannot be served for the new one.
    • _last_step2_context — the preserved enriched Step-2 context used by /api/regenerate-overflow-graph and by the model-swap fast path; stale context must not be reused after a study reload.
    • _last_step2_signature — the input signature (contingency, selected_overloads, all_overloads, monitor_deselected, additional_lines_to_cut) that gates the Step-2 overflow-graph cache reuse. Cleared so a freshly loaded study never reuses the previous study's overflow graph.
  7. Concurrency lifecycle (D3): _contingency_variant_lru — emptied because the contingency variants it tracks die with the Network being dropped. The _network_lock / _study_gate themselves are NOT cleared — they guard the reset itself and persist for the process. See docs/architecture/shared-network-concurrency.md.

Adding a new per-study cache? It MUST be listed in RecommenderService.reset() (see expert_backend/services/recommender_service.py:99) and, if it holds a thread / future / event, drained first via a _drain_pending_* helper — otherwise it WILL leak across studies (regression history: the _layout_cache fix on claude/fix-grid-layout-reset-8TYEV).

Why Force Reload?

Previously, the backend cached the network path and skipped reloading if it hadn't changed (if config.network_path != last_network_path). This caused issues because:

  1. N-1 simulations modify the in-memory network (disconnect elements, run load flow)
  2. The RecommenderService caches simulation environments tied to specific contingencies
  3. Action simulations may leave residual state in the recommender's internal caches

By always reloading and resetting, we guarantee a clean slate for every new study load.


hasAnalysisState() — What Counts as "Analysis State"

The function returns true if ANY of these are non-null/non-empty:

  • result — analysis results from run-analysis
  • pendingAnalysisResult — results waiting to be displayed
  • selectedActionId — an action is being viewed
  • actionDiagram — an action variant diagram is loaded
  • manuallyAddedIds.size > 0 — manual simulations were added
  • selectedActionIds.size > 0 — actions were favorited
  • rejectedActionIds.size > 0 — actions were rejected

Note: the mere presence of an N-1 diagram does NOT count as analysis state. Simply selecting a contingency and viewing the N-1 diagram is considered a lightweight operation that doesn't warrant a confirmation dialog.


Testing

Tests are in frontend/src/App.test.tsx and cover:

Contingency Change Confirmation (5 tests)

  1. No dialog when switching branch without analysis state
  2. Dialog shown when switching branch after running analysis
  3. State cleared and branch switched on confirm
  4. Input reverts to old branch on cancel
  5. No dialog triggered for partial/invalid branch text

Load Study Confirmation (4 tests)

  1. Loads directly when no analysis state exists
  2. Dialog shown when clicking Load Study after analysis
  3. Study reloads on confirm
  4. State preserved on cancel

Run tests with:

cd frontend
npm run test