diff --git a/README.md b/README.md index d6af7e3..1a55b66 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,101 @@ -# React + TypeScript + Vite +# Pipeline Network Diagram Editor -This template provides a minimal setup to get React working in Vite with HMR and some Oxlint rules. +A desktop editor for designing pipeline networks (water, gas, power, steam …), +built with **Tauri v2 + React + TypeScript + Vite** and the **JointJS** +(`@joint/core`, MPL-2.0) diagramming engine. -Currently, two official plugins are available: +## Features -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs) -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) +**Canvas & modelling** +- Grouped, searchable **node palette** of vector components (source, sink, pump, + valve, tank, junction, filter, meter, heat-exchanger, compressor). Drag onto + the canvas or double-click to add. +- Nodes are defined by an **SVG icon set** plus a **port configuration** + (medium + direction + side). +- Clicking a node **reveals its ports**; drag from a port to draw a connector. + Connections are **validated by relation** — mediums must be compatible + (e.g. water↔water, water↔hot-water) and directions complementary (out→in). +- **Grid (Manhattan) routing** with a configurable **arc-on-intersection** + connector (JointJS `jumpover`), plus orthogonal / straight routers. +- **Edge styles** with source/target markers: arrow, open-arrow, circle, + diamond, bar, and solid/dashed/dotted lines. +- Multiple **color schemes** (default, dark, blueprint, high-contrast) keyed by + medium. -## React Compiler +**Properties** +- Right panel shows **grouped, typed properties** for the selected node/edge: + Identity, Geometry, Presentation, Physics. +- Editors for every type: `string, int, float, enum, color, catalogueItem, + catalogueItems, list`. Values are validated/coerced and written live to the + canvas. **Catalogues** (pipes, pumps, materials) back the catalogue types. -The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation). +**Editing UX** +- Undo/redo, delete, copy/cut/paste, duplicate, select-all. +- Keyboard shortcuts (Del, Ctrl+Z/Y, Ctrl+C/X/V/D/A, Esc, Ctrl+±). +- Zoom (buttons + Ctrl-wheel toward cursor), blank-drag pan, fit-to-content, + reset. Snap-to-grid. +- Save / Open (`.json`) and export **SVG / PNG** — native file dialogs under + Tauri, browser download/upload as a fallback. -## Expanding the Oxlint configuration +**Mock calculation** +- A deterministic **flow-distribution solver** computes per-edge flow from node + supplies/demands, respecting conservation and splitting at junctions by + downstream demand. +- **Run simulation** animates flow along each edge — dash direction follows the + sign, speed and width follow the volume — and the status bar reports total + supply/demand, balance and warnings (under-supplied / unbalanced). -If you are developing a production application, we recommend enabling type-aware lint rules by installing `oxlint-tsgolint` and editing `.oxlintrc.json`: +## Getting started -```json -{ - "$schema": "./node_modules/oxlint/configuration_schema.json", - "plugins": ["react", "typescript", "oxc"], - "options": { - "typeAware": true - }, - "rules": { - "react/rules-of-hooks": "error", - "react/only-export-components": ["warn", { "allowConstantExport": true }] - } -} +```bash +npm install + +# Frontend dev server (browser) — http://localhost:1420 +npm run dev + +# Full desktop app (Tauri) +npm run tauri dev ``` -See the [Oxlint rules documentation](https://oxc.rs/docs/guide/usage/linter/rules) for the full list of rules and categories. +> If port 1420 is already in use, stop the other process or change `server.port` +> in `vite.config.ts` and `build.devUrl` in `src-tauri/tauri.conf.json`. + +## Quality gates + +```bash +npm run test:run # 47 unit + integration + component tests (Vitest) +npm run test:coverage +npm run typecheck # tsc --noEmit +npm run lint # oxlint +npm run build # tsc -b && vite build +``` + +## Architecture + +``` +src/ + model/ pure domain: mediums/relations, color schemes, property schema, + catalogues, node types + SVG icon set, edge styles (tested) + calc/ mock flow-distribution solver (tested) + canvas/ graphOps (paper-independent graph logic, tested) + + CanvasController (paper, selection, tools, undo, animation) + shapes + store/ Zustand editor store (config, selection, catalogues) + ui/ Toolbar, NodePalette, PropertiesPanel, ConfigPanel, StatusBar, + CanvasView, property-type editors + io/ document save/open, SVG/PNG export (Tauri + browser fallback) +src-tauri/ Tauri v2 Rust shell +docs/plan/ implementation plan & milestone checklist +``` + +The core logic is decoupled from the JointJS `Paper` (which needs a real DOM) so +it can be unit-tested in jsdom: `model/`, `calc/` and `canvas/graphOps.ts` are +all covered directly. + +## Why JointJS + +Chosen over React Flow / Rete / GoJS because it uniquely covers every hard +requirement out of the box: framework-agnostic custom **SVG node markup**, a +first-class **port model** with `validateConnection`, built-in **grid routers**, +the **`jumpover` arc connector** for the arc-on-intersection requirement, and +rich **link markers** for arrow/circle/diamond edge ends. See +[`docs/plan/README.md`](docs/plan/README.md) for the full rationale and plan. diff --git a/docs/plan/README.md b/docs/plan/README.md index f06adca..d58e4ab 100644 --- a/docs/plan/README.md +++ b/docs/plan/README.md @@ -44,86 +44,91 @@ src-tauri/ Tauri v2 Rust shell (file dialogs, fs plugin) - [x] Install deps (@joint/core, zustand, vitest, testing-library, tauri plugins) - [x] Configure Vite (port 1420) + Vitest (jsdom, coverage) - [x] Write this plan -- [ ] Base app shell layout (palette | canvas | properties, top toolbar) -- [ ] CI-style scripts: `test`, `test:run`, `lint`, `typecheck` +- [x] Base app shell layout (palette | canvas | properties, top toolbar) +- [x] CI-style scripts: `test`, `test:run`, `lint`, `typecheck` ### M1 — Domain model (pure, tested) -- [ ] Port types & **relation registry** (which port types may connect) -- [ ] Connection validation function (`canConnect(source, target, relations)`) -- [ ] **Color schemes** mapping port/relation types → colors (multiple presets) -- [ ] Property schema types: `string,int,float,enum,catalogueItem,catalogueItems,color,list` -- [ ] Property groups (presentation / identity / physics) -- [ ] Catalogue model (named collections of catalogue items) -- [ ] Node type definitions with SVG markup + port layout (pump, valve, tank, +- [x] Port types & **relation registry** (which port types may connect) +- [x] Connection validation function (`canConnect(source, target, relations)`) +- [x] **Color schemes** mapping port/relation types → colors (multiple presets) +- [x] Property schema types: `string,int,float,enum,catalogueItem,catalogueItems,color,list` +- [x] Property groups (presentation / identity / physics) +- [x] Catalogue model (named collections of catalogue items) +- [x] Node type definitions with SVG markup + port layout (pump, valve, tank, junction, source, sink, …) -- [ ] Edge style definitions (line styles + source/target markers) -- [ ] Default property values & validation/coercion per type +- [x] Edge style definitions (line styles + source/target markers) +- [x] Default property values & validation/coercion per type ### M2 — Canvas engine (JointJS) -- [ ] Paper + graph init, background grid, snap-to-grid -- [ ] Custom `PipelineNode` element (renders node-type SVG + ports) -- [ ] Custom `PipelineLink` with configurable markers & line styles -- [ ] Port rendering; show ports only when node focused/hovered -- [ ] Draw edge from a port; live validation highlight (valid/invalid) -- [ ] Grid routing (`manhattan`) + **config toggle for `jumpover` arc connector** -- [ ] Selection (single, multi, rubber-band) & focus highlighting -- [ ] Element tools: remove, boundary, resize; link tools: vertices, arrowheads, remove +- [x] Paper + graph init, background grid, snap-to-grid +- [x] Custom `PipelineNode` element (renders node-type SVG + ports) +- [x] Custom `PipelineLink` with configurable markers & line styles +- [x] Port rendering; show ports only when node focused/hovered +- [x] Draw edge from a port; live validation highlight (valid/invalid) +- [x] Grid routing (`manhattan`) + **config toggle for `jumpover` arc connector** +- [x] Selection (single + multi via shift-click) & focus highlighting +- [ ] Rubber-band marquee selection (not yet implemented) +- [x] Element tools: remove, boundary; link tools: vertices, segments, arrowheads, remove + (element resize is done via the Geometry properties, not a drag handle) ### M3 — Node palette -- [ ] Grouped, collapsible stencil of node types (vector previews) -- [ ] Search/filter -- [ ] Drag-and-drop node from palette to canvas (drop at cursor, snap) +- [x] Grouped, collapsible stencil of node types (vector previews) +- [x] Search/filter +- [x] Drag-and-drop node from palette to canvas (drop at cursor, snap) ### M4 — Properties panel -- [ ] Reflects current selection (node or edge), empty state otherwise -- [ ] Grouped property editors, one per property type -- [ ] Editors: string, int, float, enum(select), color(picker), +- [x] Reflects current selection (node or edge), empty state otherwise +- [x] Grouped property editors, one per property type +- [x] Editors: string, int, float, enum(select), color(picker), catalogueItem(select), catalogueItems(multi), list(add/remove rows) -- [ ] Two-way binding: edits write back to element & update canvas presentation -- [ ] Geometry props (position/size/rotation) & title reflected live +- [x] Two-way binding: edits write back to element & update canvas presentation +- [x] Geometry props (position/size/rotation) & title reflected live ### M5 — Editing UX (the "typical scenarios" often missed) -- [ ] Undo / redo (command stack) -- [ ] Delete, copy / cut / paste, duplicate -- [ ] Keyboard shortcuts (Del, Ctrl+Z/Y, Ctrl+C/V/X/D, Ctrl+A, Esc) -- [ ] Zoom (buttons + ctrl-wheel), pan (space/mmb drag), fit-to-content, reset -- [ ] Grid + snap toggles, background config -- [ ] Context menu on nodes/edges/canvas -- [ ] Rename via inline / properties title +- [x] Undo / redo (command stack) +- [x] Delete, copy / cut / paste, duplicate +- [x] Keyboard shortcuts (Del, Ctrl+Z/Y, Ctrl+C/V/X/D, Ctrl+A, Esc) +- [x] Zoom (buttons + ctrl-wheel), pan (blank-area drag), fit-to-content, reset +- [x] Grid + snap toggles, background config +- [ ] Context menu on nodes/edges/canvas (not yet implemented — actions available + via toolbar, tools & keyboard shortcuts) +- [x] Rename via properties title (reflected live on canvas) ### M6 — Configuration -- [ ] Config panel: color scheme, arc-on-intersection, grid size/visibility, +- [x] Config panel: color scheme, arc-on-intersection, grid size/visibility, snap, router type, animation speed -- [ ] Persist config; live-apply to paper & links +- [x] Persist config; live-apply to paper & links ### M7 — Persistence & export -- [ ] Serialize document (graph + metadata + config) to JSON -- [ ] Save / Open via Tauri dialog + fs (graceful fallback to download/localStorage in browser) -- [ ] New document -- [ ] Export canvas to SVG and PNG +- [x] Serialize document (graph + metadata + config) to JSON +- [x] Save / Open via Tauri dialog + fs (graceful fallback to browser download / file-picker) +- [x] New document +- [x] Export canvas to SVG and PNG ### M8 — Mock calculation & flow animation -- [ ] Build network graph from nodes/edges (respect port direction) -- [ ] Assign supplies/demands from node physics props -- [ ] **Flow-distribution solver** (conservation at junctions, proportional split) -- [ ] Map per-edge flow → direction (sign) + volume (magnitude) -- [ ] Animate flow along edges (dash animation; speed ∝ volume, dir ∝ sign) -- [ ] Color/width edges by flow volume; run / stop / reset controls -- [ ] Report unbalanced nodes / disconnected components +- [x] Build network graph from nodes/edges (respect port direction) +- [x] Assign supplies/demands from node physics props +- [x] **Flow-distribution solver** (conservation at junctions, proportional split) +- [x] Map per-edge flow → direction (sign) + volume (magnitude) +- [x] Animate flow along edges (dash animation; speed ∝ volume, dir ∝ sign) +- [x] Color/width edges by flow volume; run / stop / reset controls +- [x] Report unbalanced nodes / disconnected components ### M9 — Testing -- [ ] Unit: relation validation & color schemes -- [ ] Unit: property schema coercion/validation & catalogue resolution -- [ ] Unit: flow-distribution solver (linear, split, merge, cycle, unbalanced) -- [ ] Unit: document serialize/deserialize round-trip -- [ ] Component: palette renders groups; properties panel renders & edits -- [ ] Component: store actions (add node, connect, select, undo/redo) -- [ ] `npm run test:run` green; typecheck & lint clean +- [x] Unit: relation validation & color schemes +- [x] Unit: property schema coercion/validation & catalogue resolution +- [x] Unit: flow-distribution solver (linear, split, merge, cycle, unbalanced) +- [x] Unit: document serialize/deserialize round-trip +- [x] Component: palette renders/filters groups; config panel drives store; + properties panel empty-state + grouped/typed fields for a selection +- [x] Integration (graphOps): add node, connect w/ validation, build network, + annotate flow, JSON round-trip (port medium survives) +- [x] `npm run test:run` green (47 tests); typecheck & lint clean ### M10 — Polish & docs -- [ ] Seed demo network on first launch -- [ ] README with run/test instructions & feature list -- [ ] App icon / window sizing +- [x] Seed demo network on first launch +- [x] README with run/test instructions & feature list +- [x] App icon / window sizing ---