feat: migrate workbench to React
This commit is contained in:
32
.trellis/tasks/08-26-react-workbench-migration/design.md
Normal file
32
.trellis/tasks/08-26-react-workbench-migration/design.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Technical Design
|
||||
|
||||
## Frontend Boundary
|
||||
|
||||
Create a Vite app under `workbench/client/` (or a clearly scoped `workbench/frontend/` directory) with React 19 and TypeScript. Keep Node/server code CommonJS and keep `/api/*` payloads unchanged. The production build should emit a deterministic directory consumed by `workbench/server.js`; development mode may use a Vite proxy to the workbench API.
|
||||
|
||||
## OpenLayers Migration Strategy
|
||||
|
||||
- Import OpenLayers modules directly from the installed `ol` package in TypeScript; remove the runtime `/vendor/ol/*.js` import map from the React build.
|
||||
- Keep one `Map` instance per mounted map component. A `useOpenLayersMap` hook creates it once after the container ref is available, registers interactions/listeners, and calls `map.setTarget(undefined)` plus listener cleanup on unmount.
|
||||
- Keep the layer registry in an adapter module/hook (`map/layers.ts`), created once with stable `VectorSource` and `VectorLayer` instances. React state changes update sources, styles, visibility, and selection overlays through explicit adapter methods rather than recreating the map.
|
||||
- Use typed GeoJSON/read helpers at the API boundary; preserve EPSG:4326 to EPSG:3857 conversion and current fit/selection behavior.
|
||||
- OpenLayers event callbacks publish typed selection/pointer events to React state. React panels render from that state and issue API mutations; they do not query or mutate DOM nodes owned by OpenLayers.
|
||||
- Import `ol/ol.css` from the Vite entry and keep map container dimensions in application CSS.
|
||||
|
||||
## UI and State
|
||||
|
||||
- Use shadcn/ui primitives for buttons, inputs, checkboxes, select, tabs/segmented filters, dialogs, sheets, alerts, and toast feedback. Keep the existing dense three-column workbench layout.
|
||||
- Define API/state types in `src/types/` based on the actual `/api/state` and mutation payloads. Use a small typed client in `src/lib/api.ts`.
|
||||
- Use React hooks/context for session and editor state. Keep transient map selection and staged overrides separate from server state; avoid introducing a large state library unless the migration proves one necessary.
|
||||
- Split components by existing workflow boundaries: `ImportScreen`, `WorkbenchShell`, `LayerPanel`, `DiagnosticsPanel`, `MapCanvas`, `RoadInspector`, `SignalEditor`, and shared `ui/` primitives.
|
||||
|
||||
## Static Hosting
|
||||
|
||||
- Update `workbench/server.js` to serve Vite `index.html` and hashed assets in production, with a safe fallback for the SPA route while retaining `/vendor/*` only for compatibility during transition.
|
||||
- Keep `npm run road:workbench` self-contained for production assets. Add Vite dev/proxy scripts without requiring the Node workbench server to become an ESM application.
|
||||
|
||||
## Risks and Compatibility
|
||||
|
||||
- OpenLayers owns imperative objects and must not be recreated on every React render; the hook/adapter boundary is mandatory.
|
||||
- Existing style functions close over selected road state. Convert them to adapter-managed mutable selection refs or call `layer.changed()` after selection updates.
|
||||
- The first migration should preserve behavior and layout; visual redesign is explicitly deferred.
|
||||
Reference in New Issue
Block a user