feat: add node help system and registry for extensible node types

- Implemented a help system for different node types (config, render, variable, function) with detailed usage instructions.
- Created a node registry to manage node types, including registration, retrieval, and validation of connections between nodes.
- Defined central node and edge types for the application to streamline state management.
- Added Nunjucks autocomplete functionality to enhance user experience in template editing.
- Developed a syntax highlighting parser for PlantUML and Nunjucks within the CodeMirror editor.
- Registered built-in node types at application startup, including their default configurations and help entries.
- Introduced a theme context provider to manage light/dark mode preferences across the application.
- Created utility functions for class name management using clsx and tailwind-merge.
- Set up Tailwind CSS for styling with custom themes and responsive design.
- Configured Vite for development with proxy settings for backend API calls and Kroki diagram service.
This commit is contained in:
2026-03-09 20:04:31 +01:00
parent 11fd9cd54d
commit b3c2c6711f
67 changed files with 1286 additions and 2124 deletions

48
docs/PERFORMANCE.md Normal file
View File

@@ -0,0 +1,48 @@
# Performance notes
## Already in place
- **Throttled node updates during drag** `onNodesChange` merges changes and flushes at most once per animation frame (~60 fps) so dragging doesnt trigger hundreds of re-renders per second.
- **`nodeDragThreshold={1}`** Avoids treating small pointer moves as drags and reduces noisy change events.
- **Memoized React Flow props** `nodeTypes`, `edgeTypes`, `defaultEdgeOptions`, and `flowContextValue` are memoized so their references dont change every render.
- **Custom `nodePropsAreEqual`** Node components use `React.memo(..., nodePropsAreEqual)` so a node only re-renders when its own `id`, `data`, `width`, `height`, or `selected` change (e.g. dragging one node doesnt force others to re-render when the library keeps their props reference stable).
- **ConfigNode derived data** `incomingEdges`, `incomingIds`, and `connected*` are wrapped in `useMemo` so they arent recomputed on every render.
## Further improvements you can try
### 1. Split context (medium effort)
Right now every component that uses `useContext(FlowContext)` re-renders whenever `nodes` or `edges` change. You can split into:
- **FlowDataContext** `nodes`, `edges` (changes often).
- **FlowActionsContext** `setNodes`, `setEdges`, `isValidConnection`, etc. (stable).
Components that only need actions (e.g. menus, buttons) subscribe to `FlowActionsContext` and wont re-render on graph updates.
### 2. Avoid reading full `nodes`/`edges` where possible
React Flows docs recommend not depending on the full `nodes`/`edges` arrays when you only need a small slice (e.g. “selected ids”). If you add features like selection state, keep that in a separate store or state (e.g. `selectedNodeIds`) and have components depend on that instead of filtering `nodes` everywhere.
### 3. Lighter node content
- **CodeMirror** Config and function nodes use CodeMirror; its heavy. Options: lazy-initialize the editor (mount only when the node is focused or visible), or use a plain `<textarea>` for very small/simple flows.
- **Resize** `NodeResizeControl` and `useResizeHeight` add work. If you dont need resize everywhere, make it optional or only on certain node types.
### 4. CSS
- **Containment** `BaseNode` already uses `contain: layout` where dimensions are set. Keeping layout/paint contained per node helps.
- **Simpler styles** For many nodes, avoid heavy shadows, blur, or complex animations on the node container; they can cost a lot during pan/zoom/drag.
### 5. RenderingNode pipeline
The render node runs Nunjucks + Kroki on signatures (config, edges, variables, functions). It already avoids re-running when irrelevant data changes. If you add more inputs, keep them in the signature pattern so the effect only runs when something that affects the result actually changes.
### 6. Large graphs
- **Hide/collapse** For big trees, use the `hidden` property (or similar) so only expanded nodes are rendered.
- **Virtualization** React Flow doesnt virtualize by default. For 100+ nodes, consider only rendering nodes in view (e.g. with `onlyRenderVisibleElements` if/when available in your version) or a custom viewport-based filter.
### 7. Build / runtime
- **Production build** Use `vite build` and test with the production build; React and Vite are much faster without dev mode and source maps.
- **React DevTools Profiler** Record while dragging or editing to see which components re-render and how often; that will guide where to add more memoization or split context.