Co-Study4Grid / frontend /README.md
github-actions[bot]
Deploy 7688ef1
13d4e44
|
Raw
History Blame Contribute Delete
8.36 kB
# Co-Study4Grid — Frontend
React 19 + TypeScript 5.9 + Vite 7 single-page app for the
Co-Study4Grid contingency-analysis UI. Talks to the FastAPI backend
at `http://localhost:8000` (hardcoded in `src/api.ts`) and renders
pypowsybl NAD / SLD diagrams with pan / zoom.
This file is a quick orientation. For the full guide — hook split,
data flow, SVG performance levers, detached / tied tabs, interaction
logger contract — see [`CLAUDE.md`](./CLAUDE.md).
## Scripts
```bash
npm install # install dependencies
npm run dev # Vite dev server with HMR (default port 5173)
npm run build # tsc -b && vite build → dist/
npm run build:standalone # tsc -b && vite build --config vite.config.standalone.ts
# → dist-standalone/standalone.html (single-file bundle)
npm run preview # preview the production build
npm run lint # eslint . (flat config, v9+)
npm run test # vitest run (~1000 specs)
npm run test:watch # vitest in watch mode
npm run quality:report # run the backend code-quality reporter on the whole repo
npm run quality:check # gate — exits non-zero on threshold violation
```
The backend must be running on `http://localhost:8000` for the dev
server to serve anything useful. Start it with:
```bash
# from project root
uvicorn expert_backend.main:app --host 0.0.0.0 --port 8000
```
## Source layout
```
src/
├── main.tsx # React entry (StrictMode)
├── App.tsx # State orchestration hub (~1150 lines)
├── App.*.test.tsx # App-level integration tests by domain
├── api.ts # Axios HTTP client
├── types.ts # All TypeScript interfaces
├── hooks/
│ ├── useSettings.ts # Settings state + SettingsState interface
│ ├── useActions.ts # Action selection / favorite / reject
│ ├── useAnalysis.ts # Two-step analysis pipeline (step1 / step2)
│ ├── useDiagrams.ts # NAD fetching + tab management
│ ├── useContingencyFetch.ts # svgPatch fast-path + /api/contingency-diagram fallback
│ ├── useDiagramHighlights.ts # Per-tab SVG highlight pipeline + Flow/Impacts view-mode
│ ├── useSession.ts # Session save / reload
│ ├── useDetachedTabs.ts # Detached visualization windows
│ ├── useTiedTabsSync.ts # Mirror viewBox between detached + main
│ ├── useSldOverlay.ts # SLD overlay state
│ └── usePanZoom.ts # Per-tab viewBox, zoom-to-element
├── components/ # Presentational components (no API calls)
│ ├── Header, ActionFeed, ActionCard, ActionCardPopover,
│ ├── ActionOverviewDiagram, ActionSearchDropdown,
│ ├── ActionTypeFilterChips, # Shared chip row
│ ├── AppSidebar, SidebarSummary, StatusToasts, # Sidebar layout
│ ├── VisualizationPanel, OverloadPanel, CombinedActionsModal,
│ ├── ComputedPairsTable, ExplorePairsTab,
│ ├── DetachableTabHost, MemoizedSvgContainer, SldOverlay,
│ ├── ErrorBoundary
│ └── modals/
│ ├── SettingsModal, ReloadSessionModal, ConfirmationDialog
└── utils/
├── svgUtils.ts # Barrel re-exporting every utils/svg/* module
├── svg/ # PR #104 decomposition of the old svgUtils
│ ├── idMap, metadataIndex, svgBoost, fitRect,
│ ├── deltaVisuals, actionPinData, actionPinRender,
│ └── highlights
├── svgPatch.ts # SVG DOM recycling (PR #108)
├── actionTypes.ts # Action-type classification + filter helpers
├── overloadHighlights.ts # N-1 overload classification
├── sessionUtils.ts # buildSessionResult snapshot
├── interactionLogger.ts # Singleton replay-ready event log
├── mergeAnalysisResult.ts # Step1 + step2 field merge
├── popoverPlacement.ts # Pin-popover positioning
└── fileRegistry.ts # Structure regression guard
```
## Standalone bundle
`npm run build:standalone` produces
`frontend/dist-standalone/standalone.html` — a single-file HTML with
React + CSS inlined via `vite-plugin-singlefile`. This is the
canonical distribution artifact; the legacy hand-maintained
`standalone_interface.html` has been decommissioned and frozen as
`standalone_interface_legacy.html` at the project root. UI changes
should land only in `frontend/src/` — the bundle inherits them on
the next build. See [`CLAUDE.md`](./CLAUDE.md) for the parity story.
## Testing
Tests live next to their source file as `*.test.ts` / `*.test.tsx`.
The suite uses Vitest with `jsdom`, `@testing-library/react`, and
`@testing-library/jest-dom`. Heavy mocking is the norm (`vi.mock`
for `../api` and SVG utilities) so component tests never hit the
backend.
Run a single file:
```bash
npx vitest run src/components/ActionFeed.test.tsx
```
Test patterns and the full inventory are documented in
[`../expert_backend/tests/CLAUDE.md`](../expert_backend/tests/CLAUDE.md).
## ESLint
Flat config (v9+) in `eslint.config.js` with `typescript-eslint`,
`react-hooks`, and `react-refresh`. The code-quality gate
(`python scripts/check_code_quality.py`, CI-enforced) rejects `any`
and `@ts-ignore` in source files — see
[`../CONTRIBUTING.md`](../CONTRIBUTING.md).
## Recent UX iterations (post-0.6.5)
The following PRs reshaped the look-and-feel of the app without
touching the analysis pipeline. The full retrospective lives in
[`../docs/architecture/development-cycle.md`](../docs/architecture/development-cycle.md)
section 5; design rationale comes from
[`../docs/proposals/ui-design-critique.md`](../docs/proposals/ui-design-critique.md).
- **PR #118 — VL-names toggle.** A `🏷 VL` button next to the
Inspect field hides / shows the voltage-level labels on NAD
diagrams. Hidden labels remain reachable via a native `<title>`
tooltip on each bus circle. New `vl_names_toggled { show }`
interaction event.
- **PR #120 — Design tokens (Phases A → C).** Palette / space /
radius / typography moved into `src/styles/tokens.{ts,css}`.
Components consume `colors.brand`, `space[2]`, `text.xs`
Hex literals are forbidden outside the token files; SVG
presentation attributes use the `pinColors` family for
Chrome-safe `setAttribute` calls.
- **PR #121 — Progressive-disclosure ActionCard + halo cap.** Action
cards default to a compact summary and expand on demand. The NAD
highlight halo radius is now capped relative to the viewBox so it
cannot swamp the screen at high zoom.
- **PR #122 — Tier warning system + NoticesPanel + diagram legend.**
Replaces the stack of yellow banners with a single `⚠️ Notices N`
pill in the sidebar header that opens a consolidated list (one
entry, one place to dismiss). A unified diagram legend lands at
the bottom-right of the visualization panel.
`uxConsistency.test.tsx` enforces the recommendations going
forward.
- **`fix-notice-panel-overlap` follow-up.** The Notices popover now
renders via `ReactDOM.createPortal(…, document.body)` with
`position: fixed` so it escapes the sidebar's `overflow: hidden`
clip and any ancestor stacking context — the visualization panel
no longer paints over it on narrow sidebars. Right-aligned to the
pill so it grows leftward into the sidebar rather than bleeding
into the diagram. Regression test in `NoticesPanel.test.tsx`
asserts the popover is NOT a descendant of an `overflow:hidden`
ancestor.
## Further reading
- [`CLAUDE.md`](./CLAUDE.md) — architecture deep dive
- [`../CLAUDE.md`](../CLAUDE.md) — project-wide overview + API table
- [`../docs/README.md`](../docs/README.md) — design, feature and
performance docs index
- [`../docs/architecture/development-cycle.md`](../docs/architecture/development-cycle.md)
— chronological retrospective of all five development phases
- [`PARITY_AUDIT.md`](./PARITY_AUDIT.md) — standalone-bundle parity
audit (Layer 1–4 conformity, regression matrix)