Repository navigation
Plan frontend UI improvements: buttons, tabs, filters, colors - #71
Merged
Merged
Conversation
Covers 4 changes: relocate analysis button to ActionFeed, always-visible visualization tabs with placeholders, collapsible voltage filter, and revised color scheme (purple-pink for actions, yellow for contingency, orange for overloads). https://claude.ai/code/session_013iLF6N1ofNsjzgQ3VRYYy3
1. Move & rename analysis button: Remove "Run Analysis" from contingency
card; add unified "Analyze & Suggest" / "Analyzing…" / "Display N
prioritized actions" three-state slot in ActionFeed Suggested Actions
section.
2. Always-visible visualization tabs: All 4 tabs (N, N-1, Remedial
Action, Overflow Analysis) always rendered. Unavailable tabs shown
dimmed/italic with placeholder tooltips. Action tab label updates to
"Remedial Action: {actionId}" when an action is selected.
3. Collapsible voltage filter: Collapsed by default to a 24px "kV ▸"
toggle button; expands on click to the full sidebar slider.
4. Revised highlight color scheme:
- Actions: purple-pink #e040fb (was yellow #fffb00)
- Contingency: yellow #f5c542 (was orange #ff9800)
- Overloads: orange #ff8c00 (unchanged) + new glow filter
- Breakers: light purple #ce93d8 (was bold purple #e040fb)
Applied to App.css and standalone_interface.html.
All 339 tests pass.
https://claude.ai/code/session_013iLF6N1ofNsjzgQ3VRYYy3
Mirror the 4 frontend UI changes in standalone_interface.html:
1. Always-visible tabs with placeholder tooltips, dynamic
"Remedial Action: {id}" label
2. Collapsible voltage filter (collapsed by default)
3. "Analyze & Suggest" button moved to suggested actions section
4. Color scheme already updated in previous commit
https://claude.ai/code/session_013iLF6N1ofNsjzgQ3VRYYy3
…laceholder text - Add close button to the Recommender Settings warning in ActionFeed - Fix standalone_interface.html to respect dismissedRecommenderWarning state - Update overflow tab placeholder text to reference "Analyze & Suggest" https://claude.ai/code/session_013iLF6N1ofNsjzgQ3VRYYy3
… approach - Action highlight: #e040fb → #ff4081 (more pink, distinct from voltage level purple) - Contingency highlight: #f5c542 → #ffe033 (more yellow, less orange) - Overload highlights: upgraded from simple CSS class to clone-based halo (same approach as action/contingency) with stroke-width 120px for visibility - Overloads now properly visible in Action tab NAD visualization - Updated tab accent color for Remedial Action tab to match pink theme https://claude.ai/code/session_013iLF6N1ofNsjzgQ3VRYYy3
…ton after use - Action highlight clones now fully opaque (no transparency bleeding through) - Fixed overload highlights in action tab: applyActionTargetHighlights no longer removes all highlight clones (only its own); reordered highlight application so overloads render after action targets - Hide "Analyze & Suggest" button once actions have been displayed (same result, not useful to run again) https://claude.ai/code/session_013iLF6N1ofNsjzgQ3VRYYy3
…verloads filtering Overload highlights in action tab: - Fixed threshold: check rho_after > monitoringFactor instead of > 1.0 (rho values are raw fractions where 1.0 = thermal limit, monitoringFactor is the operational threshold e.g. 0.95) - Filter overloaded lines by selectedOverloads so user-deselected N-1 overloads are not highlighted - Added monitoringFactor and selectedOverloads to highlight effect deps Loading display values (backend): - Removed monitoring_factor multiplication from rho_before, rho_after, and max_rho in simulate_manual_action, _enrich_actions, and compute_superposition - monitoring_factor is an overload detection threshold, not a display scaling factor — displayed loadings now show true physical loading percentages N-1 tab overload highlights: - Filter by selectedOverloads to discard user-deselected overloads https://claude.ai/code/session_013iLF6N1ofNsjzgQ3VRYYy3
…verloads filtering Overload highlights in action tab: - Fixed threshold: check rho_after > monitoringFactor instead of > 1.0 - Use lines_overloaded_after when available, fallback to rho_after check - Filter overloaded lines by selectedOverloads (user-deselected N-1 overloads are excluded from highlights) Loading display values (backend): - Removed monitoring_factor multiplication from rho_before, rho_after, and max_rho in _enrich_actions, simulate_manual_action, and compute_superposition - monitoring_factor is a threshold for overload detection, not a display scaling factor — displayed loadings now show true physical loading % N-1 tab overload highlights: - Filter by selectedOverloads to exclude user-deselected overloads Updated svgUtils tests to match clone-based overload highlight approach. https://claude.ai/code/session_013iLF6N1ofNsjzgQ3VRYYy3
…uggested actions - Restored monitoring_factor multiplication for rho_before/rho_after/max_rho in _enrich_actions, simulate_manual_action, and compute_superposition (monitoring_factor IS needed for operational loading display, not just threshold) - Fixed lines_overloaded_after check: empty array [] is truthy in JS, so suggested actions (which don't have lines_overloaded_after from discovery engine) would skip the rho_after fallback and show no overload highlights. Now checks .length > 0 in both standalone_interface.html and App.tsx. https://claude.ai/code/session_013iLF6N1ofNsjzgQ3VRYYy3
applyContingencyHighlight had two bugs: 1. Did not clear previous contingency clones before adding new ones, causing old highlights to accumulate when switching tabs 2. Used a persistent cached bgCTM (backgroundLayer._cachedScreenCTM) that went stale after panning/zooming, causing position drift Fix: clear all .nad-highlight-clone.nad-contingency-highlight clones at the start of each call, and always compute a fresh bgCTM. https://claude.ai/code/session_013iLF6N1ofNsjzgQ3VRYYy3
…ioning getScreenCTM() includes the screen-space offset which changes with pan/zoom and tab visibility, causing highlight clones to drift away from their target elements when switching between tabs. getCTM() gives the transform relative to the SVG viewport, which is stable regardless of screen position. Applied to all three highlight functions: applyContingencyHighlight, applyActionTargetHighlights, and applyOverloadedHighlights. https://claude.ai/code/session_013iLF6N1ofNsjzgQ3VRYYy3
…nd layer The CTM-based approach (placing clones in a separate background layer with computed transforms) caused highlight drift when switching tabs because the CTM values depend on screen/viewport state that changes. New approach: insert the clone as an immediate previous sibling of the original element. This inherits all parent transforms naturally (no CTM math needed) and SVG paint order ensures the halo renders behind the original element. https://claude.ai/code/session_013iLF6N1ofNsjzgQ3VRYYy3
… solid yellow halo without transparency or dashes
…ellow halo without transparency or dashes
…dering: ensures it stays behind nodes and labels
…ne interface to fix z-ordering
…hts (overloads, actions, contingencies) in React and Standalone interfaces
…hts in standalone interface
…ighlighted elements
…ll opacity on original assets
marota
pushed a commit
that referenced
this pull request
Apr 19, 2026
…tton release
Four user-reported issues from the last screenshot batch:
## 1. Combine-modal Simulate button stuck in running mode
`simulatingActionId` was only reset in the outer try's finally, AFTER
the async action-variant-diagram fetch completed. On big grids
that's ~5-6 seconds of stale "spinner" UI even though the action
CARD (what matters to the sidebar feed) has already landed.
Fix: call setSimulatingActionId(null) + setIsSimulatingCombined(false)
the moment the simulate response arrives and the result has been
merged. The subsequent variant-diagram fetch continues
asynchronously — buttons release immediately, tab flips happen
naturally when the diagram is ready, matching React's perceived
responsiveness. Applied to both handleAddManualAction and
handleSimulateCombined.
## 2. Tab switching / action diagram loading felt sluggish
Two React performance optimisations were missing on the standalone:
### 2a. `/api/network-diagram` served as plain JSON → large JSON.parse
The backend exposes a `format=text` variant that returns
`{header}\n<svg…>` instead of embedding the multi-MB SVG inside a
JSON string. Skips a ~500 ms main-thread JSON.parse on the
PyPSA-EUR France grid (see docs/perf-loading-parallel.md). React
has used this since PR #71.
Ported to the standalone via a new `_fetchNetworkDiagramTextFormat()`
helper that fetches + splits on the first newline, with a graceful
fallback to the JSON endpoint if the text variant 404s (older
backends).
### 2b. Base NAD fetched AFTER branches + VLs + nominal-voltages
Previously the standalone did `Promise.all([branches, VLs, nomV])`
THEN called `fetchBaseDiagram`. Since network-diagram is by far
the slowest XHR, stacking it after the metadata round-trips adds
~1-2 s to the critical path. React parallelises all four since
PR #88 (docs/perf-loading-parallel.md).
Ported: both call sites (applySettingsImmediate + handleLoadConfig
equivalents) now issue a 4-way Promise.all that includes the
network-diagram. The SVG is processed synchronously after the
Promise.all resolves, matching the React flow.
## 3. Pin rendering
Prior implementation was an SVG circle rendered in a viewBox-
scaled layer, so pins shrunk / grew and drifted as the user
zoomed. Label was the rank number, not the loading percentage.
Anchor math was fine but the visual anchoring looked off because
the pin's centroid scaled with the map.
Rewrite:
- Pins rendered as absolutely-positioned `<div>` elements in
SCREEN pixel space. A `projectSvgPoint(x, y)` function maps
each pin's SVG-local coordinates through the current
overviewVb + overlayRect using the same `xMidYMid meet`
projection as the SVG itself, so pins stay exactly on the
line midpoint as the user pans + zooms.
- Teardrop glyph: inline <svg> with a <path> for the classic
Google-Maps pin shape (`d="M18 0 … Z"`), tip at (0, 48) so
`translate(-50%, -100%)` on the wrapper plants the tip on
the asset. Inner white circle for label contrast.
- Label is the loading percentage (rounded), falling back to
the rank when rho isn't set — matches the React ActionOverview
component's pin label.
- Size is 36x48 CSS-px regardless of zoom. A ResizeObserver
keeps overlayRect current when the window or sidebar resizes,
so pin projection stays accurate through responsive layout
changes.
Combined-pair curves (React's Bézier connecting two pins) are
still omitted — it's purely cosmetic and the per-pin events +
metadata round-trip already cover replay parity.
## 4. Deselecting an action jumped to N-1 tab instead of staying on Action
React switched this behaviour in PR #93 — clicking the selected
action card again (or the × chip) now keeps the user on the
Remedial Action tab, which falls through to the
ActionOverviewDiagram pin view. The standalone was still doing
`setActiveTab('n-1')` in the deselect branch of handleActionSelect.
Fix: drop that line. The tab stays on 'action', selectedActionId
becomes null, and the conditional render below picks the Overview
component because it's the only branch where
`result?.actions && !selectedActionId`.
---
Parity-script impact:
- Layer 1 still 51/51, exits 0.
- Layer 2 unchanged (26/30 React, 30/30 standalone).
- Layer 3a 22/22.
- Vitest 972/972.
https://claude.ai/code/session_01LGL7gvedQLrUGGzqVm4wAG
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
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
This PR adds a comprehensive design document outlining four major frontend UI improvements to enhance usability and visual clarity across the network analysis interface.
Key Changes
Move & Rename "Run Analysis" Button: Relocates the analysis trigger from the contingency selector card into the ActionFeed panel header, consolidating it with the processing state and results display into a single unified three-state button slot (Idle → "🔍 Analyze & Suggest", Running → "⚙️ Analyzing…", Pending → "📊 Display N prioritized actions")
Always-Visible Visualization Tabs with Placeholders: Converts the four visualization tabs (Network, Contingency, Action, Overflow Analysis) from conditionally-rendered to always-visible, with placeholder messages guiding users when content is unavailable. Adds dynamic labeling for the Action tab to show the selected action ID.
Collapsible Voltage Filter: Transforms the voltage filter sidebar from always-visible to collapsed-by-default, showing only a small toggle button (
▸ kV) on the right edge that expands to the full filter UI on demand.Revised Color Code for Highlights: Updates the SVG highlight color scheme to improve visual distinction:
#e040fb)#f5c542)#ff8c00)#ce93d8)Implementation Details
App.tsx,ActionFeed.tsx,VisualizationPanel.tsx), CSS updates, test modifications, and the standalone HTML interfaceFiles Affected
frontend/src/App.tsxfrontend/src/components/ActionFeed.tsxfrontend/src/components/VisualizationPanel.tsxfrontend/src/App.cssfrontend/src/utils/svgUtils.ts(optional)frontend/src/utils/cssRegression.test.tsfrontend/src/App.settings.test.tsxfrontend/src/App.session.test.tsxstandalone_interface.htmlhttps://claude.ai/code/session_013iLF6N1ofNsjzgQ3VRYYy3