Repository navigation
Extract N-1 fetch and diagram highlights into custom hooks - #109
Merged
Merged
Conversation
…references The v0.6 snapshot pre-dated the /api/n1-diagram-patch and /api/action-variant-diagram-patch endpoints added in the svg-dom-recycling perf work (PR #108). check_standalone_parity.py (Layer-1) was failing because those paths appeared in frontend/src/api.ts but not in the committed snapshot that CI uses when standalone.html is absent. Rebuilt the snapshot from the current React source via `npm run build:standalone` and committed it as standalone_v0.7.html. Layer-1 parity check now passes against both the auto-generated artifact and the new versioned snapshot. https://claude.ai/code/session_01B6mqrab2Pqjmr5AuLTNQxe
Options 1 + 2 from the App.tsx size-reduction plan. App.tsx shrinks from
1575 lines to ~1150 by relocating pure presentational JSX and two
self-contained effect pipelines. No behavior change.
Extracted components (Option 1):
- components/SidebarSummary.tsx — sticky contingency/N-1 strip
- components/AppSidebar.tsx — sidebar layout shell with
summary + contingency selector
+ children slot
- components/StatusToasts.tsx — error/info floating banners
Extracted hooks (Option 2):
- hooks/useN1Fetch.ts — N-1 diagram fetch effect:
svgPatch fast-path, full
/api/n1-diagram fallback, and
contingency-change confirm
routing
- hooks/useDiagramHighlights.ts — per-tab SVG highlight pipeline
(overload halos, contingency
highlight, action-target halos,
delta visuals) + the per-tab
Flow/Impacts view-mode state
One unavoidable eslint-disable in useDiagramHighlights.ts on the
reattach-prune setState: the pre-extraction code in App.tsx was not
flagged by react-hooks/set-state-in-effect (position-sensitive
heuristic), but the observable behavior must be preserved byte-for-
byte, so the guarded setState stays with a justified suppression.
frontend/CLAUDE.md records what landed, lists deferred options
(Option 3 orchestrator hooks, Option 4 AppContext, the NDJSON parser
extraction), and explains the ESLint exception.
Verified: npm run test (1098 tests pass), npm run lint clean, tsc -b
clean, scripts/check_standalone_parity.py OK,
scripts/check_code_quality.py OK.
https://claude.ai/code/session_01B6mqrab2Pqjmr5AuLTNQxe
…overview
The three UI locations that render an action-type chip row (manual
selection search dropdown, explore-pairs tab in the combined modal,
action overview diagram) previously each owned independent filter
state with different implementations:
- ActionOverviewDiagram used ActionTypeFilterToken via ActionTypeFilterChips (reference)
- ExplorePairsTab had local useState<ActionTypeFilterToken>
- ActionFeed search dropdown had a legacy boolean map (typeFilters) with checkboxes
All three now share overviewFilters.actionType (owned by App.tsx):
- ExplorePairsTab: local state removed; accepts actionTypeFilter + onActionTypeFilterChange props
- CombinedActionsModal: threads the two new props through to ExplorePairsTab
- ActionFeed: typeFilters state removed; filteredActions and scoredActionsList
both use matchesActionTypeFilter(overviewFilters?.actionType ?? 'all');
onOverviewFiltersChange prop added and threaded to ActionSearchDropdown
(chips) and CombinedActionsModal
- ActionSearchDropdown: TypeFilters type removed; checkbox row replaced with
ActionTypeFilterChips; props renamed to actionTypeFilter / onActionTypeFilterChange
- App.tsx: onOverviewFiltersChange={setOverviewFilters} added to <ActionFeed>
Tests updated to match controlled-prop pattern (pass actionTypeFilter/
overviewFilters directly instead of clicking now-gone checkboxes).
https://claude.ai/code/session_01B6mqrab2Pqjmr5AuLTNQxe
…erage Refactor: - utils/actionTypes.ts: add DEFAULT_ACTION_OVERVIEW_FILTERS constant so the initial filter literal is declared once instead of being duplicated across App.tsx, ActionOverviewDiagram, and ActionFeed. - App.tsx: use the shared constant for initial state. - ActionOverviewDiagram.tsx: drop local DEFAULT_FILTERS, reuse the shared constant for the filter-normalisation fallback. - ActionFeed.tsx: extract the actionType-patching callback as useCallback (previously duplicated at two call sites), and fall back to the shared constant instead of an inline object literal. Tests added (17 new, 1100 → 1117): - actionTypes.test.ts: coverage for DEFAULT_ACTION_OVERVIEW_FILTERS (actionType / categories / threshold / showUnsimulated defaults). - ActionFeed.test.tsx: new 'shared action-type filter' describe block covering Selected-card filtering by bucket, undefined overviewFilters fallback, the onOverviewFiltersChange callback from dropdown chips (both default and non-default preserved fields), active chip aria-pressed state, scored-actions-table filtering, and silent no-op when the handler is not wired. - ActionSearchDropdown.test.tsx: active chip aria-pressed state. - ExplorePairsTab.test.tsx: default-to-all when prop omitted, active chip aria-pressed state, silent no-op on chip click when handler not wired. - CombinedActionsModal.test.tsx: initial actionTypeFilter prop respected on first render, onActionTypeFilterChange forwarded to ExplorePairsTab. - ActionFeed.test.tsx mock: expose actionPassesOverviewFilter so tests that exercise the severity-gate code path do not crash. https://claude.ai/code/session_01B6mqrab2Pqjmr5AuLTNQxe
The style prop was being spread directly into the chip row's flex container, changing chip visual appearance relative to the overview version. Move the layout/border styles into a wrapper <div> so all three call sites render ActionTypeFilterChips with no style override, giving identical chip appearance everywhere. https://claude.ai/code/session_01B6mqrab2Pqjmr5AuLTNQxe
The three chip rows (manual-selection dropdown, Explore Pairs modal, action overview diagram) now each manage their own ActionTypeFilterToken state independently — same component, same classification logic, same visual appearance, but no cross-location synchronisation. - ExplorePairsTab: local useState replaces the lifted actionTypeFilter/ onActionTypeFilterChange props (both removed) - CombinedActionsModal: no longer threads those props to ExplorePairsTab - ActionFeed: dropdown + scored list use a new local dropdownTypeFilter state; action cards continue to use overviewFilters.actionType (the overview diagram chip still controls card visibility) - Tests updated to drive filter changes via chip clicks rather than passing overviewFilters.actionType to components that no longer read it https://claude.ai/code/session_01B6mqrab2Pqjmr5AuLTNQxe
marota
pushed a commit
that referenced
this pull request
Apr 22, 2026
… dynamic fix Captures the post-0.6.0 work: svgPatch DOM-recycling (PR #108), Action Overview filters + unsimulated pins (PR #105, #107), code-quality gate + 5 decomposition passes (PR #104, #106), docs reorganisation (PR #103), App.tsx hook extraction (PR #109), and the dynamic reco_ reconnection-action fix on the current branch. https://claude.ai/code/session_01Tzp2fdUas3Y9vNZy6dxxuC
marota
pushed a commit
that referenced
this pull request
Apr 24, 2026
Follow-up to the root/frontend/backend CLAUDE.md + README refresh. Audits the remaining project docs against PRs merged 2026-04-21 → 2026-04-23 and updates the eight that had actually drifted. frontend/README.md (HIGH) Replaced the stock Vite-template boilerplate with a real frontend orientation: npm scripts, source-tree map (hooks, components, utils incl. the utils/svg/* split from PR #104), pointer to the auto-generated standalone bundle, testing + lint commands, and cross-refs to CLAUDE.md / PARITY_AUDIT.md / docs/README.md. expert_backend/tests/CLAUDE.md (MEDIUM) Full rewrite of the test-file inventory: added the PR #104 decomposition suites (test_simulation_helpers.py, test_analysis_helpers.py, test_diagram_helpers.py), the patch- endpoint coverage (test_diagram_patch_helpers.py, test_n1_diagram_fast_path.py) from PR #108, the regression guards (test_resimulate_regression.py, test_second_contingency_reset.py, test_get_n1_variant_clones_from_n_state.py, test_configurable_mw.py) that were added since 2026-04-11, and the dynamic reco_* reconnection path from PR #110. Replaced the frontend inventory with a structural summary matching the current ~60-file Vitest layout, listed the scripts/pypsa_eur pytest coverage, and documented the tests removed by PR #103 / #104 (test_ui_regressions.py, standaloneInterface.test.ts, cssRegression.test.ts). docs/features/combined-actions.md (MEDIUM) Added a "Recent updates (PR #114, release 0.6.5)" section covering LS/curtailment in combined pairs, Simulate Combined moved out of the card + clickable sub-action badges, target_max_rho on the user-selected overload set, and Explore- Pairs re-estimation aligned with the pre-computed betas. Rewrote the "Standalone Interface" section to describe the auto-generated bundle, and dropped the checklist line that required manual standalone_interface.html mirroring. Added a row to the key-files table for the ActionCard sub-action badges and the ComputedPairsTable / ExplorePairsTab split. docs/features/state-reset-and-confirmation-dialogs.md (MEDIUM) Replaced the standalone_interface.html section with a pointer to the auto-generated bundle, and expanded the "What reset() clears" list to match the current RecommenderService.reset() implementation (drain order + fast-path caches + _layout_cache + NAD-prefetch state, with the add-a-new-cache-goes-here guardrail). docs/features/detachable-viz-tabs.md (MEDIUM) Removed the "standalone_interface.html mirror" row and the follow-up caveat that said the single-file interface doesn't support detaching — both are obsolete now that the bundle is auto-generated from the React tree. docs/architecture/app-refactoring-plan.md (MEDIUM) Added a "Status: SHIPPED" banner at the top summarising both refactor waves (Phase 1 via PR #74, Phase 2 hook extraction via PR #109) and pointing readers at the current source of truth (frontend/CLAUDE.md + CHANGELOG.md 0.6.5). Preserved the original plan below the banner for historical value. docs/architecture/phase2-state-management-optimization.md (LOW) Added a "Status: Partially shipped" banner — memoization + React.memo pass shipped under PR #75, superseded in part by PR #109 (useN1Fetch / useDiagramHighlights extractions), orchestrator hooks still deferred. docs/features/frontend-ui-improvements.md (LOW) Scope header now names `frontend/dist-standalone/standalone.html` (auto-generated, PR #101) instead of the decommissioned hand-maintained file. https://claude.ai/code/session_01RsvHjjFbAauF3NvD9BNT5V
marota
pushed a commit
that referenced
this pull request
May 5, 2026
…ctions in README Per request, surface two key 0.7.0 visualization features in the README's Visualization section and add a new "Efficient interactions" sub-section, plus refresh stale doc pointers caught in the sweep. README.md - Visualization: add interactive overflow analysis (layer toggles, hierarchical ↔ geo, SLD drill-down) + action pin overview (selected/rejected/combined/unsimulated semantics, mirrored on the overflow viewer via postMessage). Add VL-names toggle bullet. - New "Efficient interactions" section bundling the operator- velocity affordances: synchronized filter chips across feed + overview + overflow, pin-driven workflow (single-click preview / double-click drill / unsimulated double-click triggers manual simulation), Combined-action explorer, Inspect search, Detachable tabs (relocated from Visualization), tiered notices + diagram legend, progressive-disclosure ActionCard, replay-ready log. Doc staleness fixes - docs/README.md: list the new interactive-overflow-analysis.md feature doc; refresh action-overview-diagram.md description to reflect the overflow-viewer mirror; update architecture entries to point at the post-0.7.0 reality (app-refactoring shipped, phase2 shipped 0.5.0, code-quality §14–15 deltas, dev-cycle through 0.7.0). - docs/architecture/app-refactoring-plan.md: App.tsx is now ~1400 lines (PR #109 dropped it to ~1150; 0.7.0 hooks brought it back up). 0.7.0 entry referenced in CHANGELOG note. - docs/architecture/phase2-state-management-optimization.md: same App.tsx line-count refresh + reason. - docs/features/save-results.md: standalone_interface_legacy.html IS tracked (committed as a frozen snapshot), not "untracked via .gitignore" — corrected. - frontend/CLAUDE.md: App.tsx tree-line + refactor-history table updated to reflect the 0.7.0 ~1400-line state and why (useOverflowIframe, postMessage envelope, design-token glue, action-pin overflow handlers).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Refactored the App.tsx component by extracting two major concerns into dedicated custom hooks:
useN1FetchanduseDiagramHighlights. This reduces App.tsx complexity while improving code organization and testability.Key Changes
New hook:
useN1Fetch— Encapsulates the N-1 diagram fetch logic, including:New hook:
useDiagramHighlights— Owns the per-tab SVG highlighting pipeline:detachedViewModes)applyHighlightsForTab— DOM mutation pass for overload halos, contingency highlights, action-target halos, and delta visualsNew components:
AppSidebar— Left-sidebar layout shell with sticky summary stripSidebarSummary— Compact sticky strip showing selected contingency and N-1 overloadsStatusToasts— Fixed-position status banners for errors and info messagesRefactored ActionFeed:
onOverviewFiltersChangecallback prop for shared filter state updatesActionTypeFilterChipscomponentUpdated utilities:
DEFAULT_ACTION_OVERVIEW_FILTERSconstant toactionTypes.tsgetActionTargetLineslogic in svgUtils for better combined action handlingTest improvements:
overviewFiltersprop instead of internal stateactionPassesOverviewFilterin ActionFeed testsImplementation Details
restoringSessionRefto force full fetches when rehydrating analysis statehttps://claude.ai/code/session_01B6mqrab2Pqjmr5AuLTNQxe