added a type for defaultNodeData, this can house common data that all nodes should have. the other types can build on this defaultData. Also added an endNode and phaseNode to NodeDefinitions.tsx, together with a nodeData type for each new node type. ref: N25B-114
115 lines
2.9 KiB
TypeScript
115 lines
2.9 KiB
TypeScript
import './VisProgUI.css'
|
|
|
|
import {
|
|
useCallback,
|
|
useRef
|
|
} from 'react';
|
|
import {
|
|
Background,
|
|
Controls,
|
|
ReactFlow,
|
|
useNodesState,
|
|
useEdgesState,
|
|
reconnectEdge,
|
|
addEdge,
|
|
MarkerType,
|
|
type Edge,
|
|
type Connection,
|
|
} from '@xyflow/react';
|
|
import '@xyflow/react/dist/style.css';
|
|
import {
|
|
StartNode,
|
|
EndNode,
|
|
PhaseNode
|
|
} from "./components/NodeDefinitions.tsx";
|
|
|
|
const nodeTypes = {
|
|
start: StartNode,
|
|
end: EndNode,
|
|
phase: PhaseNode,
|
|
};
|
|
|
|
const initialNodes = [
|
|
{
|
|
id: 'start',
|
|
type: 'start',
|
|
position: {x: 0, y: 0},
|
|
data: {label: 'start'}
|
|
},
|
|
{
|
|
id: 'genericPhase',
|
|
type: 'phase',
|
|
position: {x: 0, y: 150},
|
|
data: {label: 'Generic Phase', number: 1},
|
|
},
|
|
{
|
|
id: 'end',
|
|
type: 'end',
|
|
position: {x: 0, y: 300},
|
|
data: {label: 'End'}
|
|
}
|
|
];
|
|
const initialEdges = [{id: 'start-end', source: 'start', target: 'end'}];
|
|
|
|
const defaultEdgeOptions = {
|
|
type: 'floating',
|
|
markerEnd: {
|
|
type: MarkerType.ArrowClosed,
|
|
color: '#505050',
|
|
},
|
|
};
|
|
|
|
const VisualProgrammingUI = ()=> {
|
|
const edgeReconnectSuccessful = useRef(true);
|
|
const [nodes, , onNodesChange] = useNodesState(initialNodes);
|
|
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
|
|
|
|
|
|
|
|
const onConnect = useCallback(
|
|
(params: Edge | Connection) => setEdges((els) => addEdge(params, els)),
|
|
[setEdges],
|
|
);
|
|
|
|
const onReconnectStart = useCallback(() => {
|
|
edgeReconnectSuccessful.current = false;
|
|
}, []);
|
|
|
|
const onReconnect = useCallback((oldEdge: Edge, newConnection: Connection) => {
|
|
edgeReconnectSuccessful.current = true;
|
|
setEdges((els) => reconnectEdge(oldEdge, newConnection, els));
|
|
}, [setEdges]);
|
|
|
|
const onReconnectEnd = useCallback((_: unknown, edge: { id: string; }) => {
|
|
if (!edgeReconnectSuccessful.current) {
|
|
setEdges((eds) => eds.filter((e) => e.id !== edge.id));
|
|
}
|
|
|
|
edgeReconnectSuccessful.current = true;
|
|
}, [setEdges]);
|
|
|
|
return (
|
|
<div style={{outlineStyle: 'solid', borderRadius: '10pt' ,marginInline: 'auto',width: '60vw', height: '60vh' }}>
|
|
<ReactFlow
|
|
nodes={nodes}
|
|
edges={edges}
|
|
defaultEdgeOptions={defaultEdgeOptions}
|
|
onNodesChange={onNodesChange}
|
|
onEdgesChange={onEdgesChange}
|
|
nodeTypes={nodeTypes}
|
|
snapToGrid
|
|
onReconnect={onReconnect}
|
|
onReconnectStart={onReconnectStart}
|
|
onReconnectEnd={onReconnectEnd}
|
|
onConnect={onConnect}
|
|
fitView
|
|
proOptions={{hideAttribution: true }}
|
|
>
|
|
<Controls />
|
|
<Background />
|
|
</ReactFlow>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default VisualProgrammingUI |