feat: added ReactFlow-based node graph #11

Merged
j.gerla merged 68 commits from feat/visual-programming-interface into dev 2025-10-28 11:59:03 +00:00
4 changed files with 22 additions and 22 deletions
Showing only changes of commit e880e00b6d - Show all commits

View File

@@ -38,7 +38,7 @@
filter: drop-shadow(0 0 0.75rem black); filter: drop-shadow(0 0 0.75rem black);
} }
.default-node__norm { .default-node-norm {
padding: 10px 15px; padding: 10px 15px;
background-color: canvas; background-color: canvas;
border-radius: 5pt; border-radius: 5pt;
@@ -46,7 +46,7 @@
filter: drop-shadow(0 0 0.25rem forestgreen); filter: drop-shadow(0 0 0.25rem forestgreen);
} }
.default-node__phase { .default-node-phase {
padding: 10px 15px; padding: 10px 15px;
background-color: canvas; background-color: canvas;
border-radius: 5pt; border-radius: 5pt;
@@ -54,7 +54,7 @@
filter: drop-shadow(0 0 0.25rem dodgerblue); filter: drop-shadow(0 0 0.25rem dodgerblue);
} }
.default-node__start { .default-node-start {
padding: 10px 15px; padding: 10px 15px;
background-color: canvas; background-color: canvas;
border-radius: 5pt; border-radius: 5pt;
@@ -62,7 +62,7 @@
filter: drop-shadow(0 0 0.25rem orange); filter: drop-shadow(0 0 0.25rem orange);
} }
.default-node__end { .default-node-end {
padding: 10px 15px; padding: 10px 15px;
background-color: canvas; background-color: canvas;
border-radius: 5pt; border-radius: 5pt;
@@ -78,7 +78,7 @@
filter: drop-shadow(0 0 0.75rem black); filter: drop-shadow(0 0 0.75rem black);
} }
.draggable-node__norm { .draggable-node-norm {
padding: 3px 10px; padding: 3px 10px;
background-color: canvas; background-color: canvas;
border-radius: 5pt; border-radius: 5pt;
@@ -86,7 +86,7 @@
filter: drop-shadow(0 0 0.25rem forestgreen); filter: drop-shadow(0 0 0.25rem forestgreen);
} }
.draggable-node__phase { .draggable-node-phase {
padding: 3px 10px; padding: 3px 10px;
background-color: canvas; background-color: canvas;
border-radius: 5pt; border-radius: 5pt;
@@ -94,7 +94,7 @@
filter: drop-shadow(0 0 0.25rem dodgerblue); filter: drop-shadow(0 0 0.25rem dodgerblue);
} }
.draggable-node__start { .draggable-node-start {
padding: 3px 10px; padding: 3px 10px;
background-color: canvas; background-color: canvas;
border-radius: 5pt; border-radius: 5pt;
@@ -102,7 +102,7 @@
filter: drop-shadow(0 0 0.25rem orange); filter: drop-shadow(0 0 0.25rem orange);
} }
.draggable-node__end { .draggable-node-end {
padding: 3px 10px; padding: 3px 10px;
background-color: canvas; background-color: canvas;
border-radius: 5pt; border-radius: 5pt;

View File

@@ -18,7 +18,7 @@ import {
import {DndToolbar} from './components/DragDropSidebar.tsx'; import {DndToolbar} from './components/DragDropSidebar.tsx';
import useFlowStore from './VisProgStores.tsx'; import useFlowStore from './VisProgStores.tsx';
import type {FlowState} from './VisProgTypes.tsx'; import type {FlowState} from './VisProgTypes.tsx';
import './VisProgUI.css' import styles from './VisProgUI.module.css'
// --| config starting params for flow |-- // --| config starting params for flow |--
@@ -79,8 +79,8 @@ const VisProgUI = () => {
} = useFlowStore(useShallow(selector)); // instructs the editor to use the corresponding functions from the FlowStore } = useFlowStore(useShallow(selector)); // instructs the editor to use the corresponding functions from the FlowStore
return ( return (
<div className={"outer-editor-container"}> <div className={styles.outerEditorContainer}>
<div className={"inner-editor-container"}> <div className={styles.innerEditorContainer}>
<ReactFlow <ReactFlow
nodes={nodes} nodes={nodes}
edges={edges} edges={edges}
@@ -96,7 +96,7 @@ const VisProgUI = () => {
fitView fitView
proOptions={{hideAttribution: true}} proOptions={{hideAttribution: true}}
> >
<Panel position="top-center" className={"dnd-panel"}> <Panel position="top-center" className={styles.dndPanel}>
<DndToolbar/> {/* contains the drag and drop panel for nodes */} <DndToolbar/> {/* contains the drag and drop panel for nodes */}
</Panel> </Panel>
<Controls/> <Controls/>

View File

@@ -9,6 +9,7 @@ import {
useRef, useRef,
useState useState
} from 'react'; } from 'react';
import styles from "../VisProgUI.module.css"
// Is used to make sure each subsequent node gets a unique id, so the ReactFlow implementation // Is used to make sure each subsequent node gets a unique id, so the ReactFlow implementation
// can distinguish between different nodes. // can distinguish between different nodes.
@@ -40,7 +41,7 @@ function DraggableNode({className, children, nodeType, onDrop}: DraggableNodePro
const draggableRef = useRef<HTMLDivElement>(null); const draggableRef = useRef<HTMLDivElement>(null);
const [position, setPosition] = useState<XYPosition>({x: 0, y: 0}); const [position, setPosition] = useState<XYPosition>({x: 0, y: 0});
// @ts-ignore // @ts-expect-error comes from a package and doesn't appear to play nicely with strict typescript typing
useDraggable(draggableRef, { useDraggable(draggableRef, {
position: position, position: position,
onDrag: ({offsetX, offsetY}) => { onDrag: ({offsetX, offsetY}) => {
@@ -60,8 +61,7 @@ function DraggableNode({className, children, nodeType, onDrop}: DraggableNodePro
}); });
return ( return (
<div className={className === "default" ? "draggable-node" : "draggable-node" + "__" + className} <div className={className} ref={draggableRef}>
ref={draggableRef}>
{children} {children}
</div> </div>
); );
@@ -162,10 +162,10 @@ export function DndToolbar() {
gap: '1rem', gap: '1rem',
justifyContent: 'center' justifyContent: 'center'
}}> }}>
<DraggableNode className="phase" nodeType="phase" onDrop={handleNodeDrop}> <DraggableNode className={styles.draggableNodePhase} nodeType="phase" onDrop={handleNodeDrop}>
phase Node phase Node
</DraggableNode> </DraggableNode>
<DraggableNode className="norm" nodeType="norm" onDrop={handleNodeDrop}> <DraggableNode className={styles.draggableNodeNorm} nodeType="norm" onDrop={handleNodeDrop}>
norm Node norm Node
</DraggableNode> </DraggableNode>
</div> </div>

View File

@@ -1,6 +1,6 @@
import {Handle, NodeToolbar, Position, useReactFlow} from '@xyflow/react'; import {Handle, NodeToolbar, Position, useReactFlow} from '@xyflow/react';
import '@xyflow/react/dist/style.css'; import '@xyflow/react/dist/style.css';
import '../VisProgUI.css'; import styles from '../VisProgUI.module.css';
// Contains the datatypes for the data inside our NodeTypes // Contains the datatypes for the data inside our NodeTypes
// this has to be improved or adapted to suit our implementation for computing the graph // this has to be improved or adapted to suit our implementation for computing the graph
@@ -53,7 +53,7 @@ export const StartNode = ({id, data}: StartNodeProps) => {
return ( return (
<> <>
<Toolbar nodeId={id} allowDelete={false}/> <Toolbar nodeId={id} allowDelete={false}/>
<div className="default-node__start"> <div className={styles.defaultNodeStart}>
<div> data test {data.label} </div> <div> data test {data.label} </div>
<Handle type="source" position={Position.Right} id="start"/> <Handle type="source" position={Position.Right} id="start"/>
</div> </div>
@@ -73,7 +73,7 @@ export const EndNode = ({id, data}: EndNodeProps) => {
return ( return (
<> <>
<Toolbar nodeId={id} allowDelete={false}/> <Toolbar nodeId={id} allowDelete={false}/>
<div className="default-node__end"> <div className={styles.defaultNodeEnd}>
<div> {data.label} </div> <div> {data.label} </div>
<Handle type="target" position={Position.Left} id="end"/> <Handle type="target" position={Position.Left} id="end"/>
</div> </div>
@@ -93,7 +93,7 @@ export const PhaseNode = ({id, data}: PhaseNodeProps) => {
return ( return (
<> <>
<Toolbar nodeId={id} allowDelete={true}/> <Toolbar nodeId={id} allowDelete={true}/>
<div className="default-node__phase"> <div className={styles.defaultNodePhase}>
<div> phase {data.number} {data.label} </div> <div> phase {data.number} {data.label} </div>
<Handle type="target" position={Position.Left} id="target"/> <Handle type="target" position={Position.Left} id="target"/>
<Handle type="target" position={Position.Bottom} id="norms"/> <Handle type="target" position={Position.Bottom} id="norms"/>
@@ -115,7 +115,7 @@ export const NormNode = ({id, data}: NormNodeProps) => {
return ( return (
<> <>
<Toolbar nodeId={id} allowDelete={true}/> <Toolbar nodeId={id} allowDelete={true}/>
<div className="default-node__norm"> <div className={styles.defaultNodeNorm}>
<div> Norm {data.label} </div> <div> Norm {data.label} </div>
<Handle type="source" position={Position.Right} id="NormSource"/> <Handle type="source" position={Position.Right} id="NormSource"/>
</div> </div>