Reputation: 11
I am new to Reactflow and trying to make this basic drag-drop workflow builder to work but I m not able to drag-drop my nodes from left to right panel. page renders ok. I am able to drag the nodes but not drop
I do not get any error when I run this just that I am unable to drop the nodes
Here is my code
// Frontend: React (ReactFlow-based Flow Builder)
import React, { useState, useCallback } from 'react';
import ReactFlow, { addEdge, Background, Controls, MiniMap, Handle } from 'react-flow-renderer';
import axios from 'axios';
const initialElements = [
{ id: '1', type: 'input', data: { label: 'Start' }, position: { x: 250, y: 5 } },
];
const nodeTypes = {
textNode: ({ data }) => (
<div style={{ padding: 10, border: '1px solid #777', borderRadius: 5 }}>
<Handle type="target" position="top" />
<div>{data.label}</div>
<Handle type="source" position="bottom" />
</div>
),
conditionNode: ({ data }) => (
<div style={{ padding: 10, border: '1px solid #f39c12', borderRadius: 5, backgroundColor: '#fdf3e7' }}>
<Handle type="target" position="top" />
<div>If: {data.ifCondition}</div>
<div>Then: {data.thenAction}</div>
<div>Else: {data.elseAction}</div>
<Handle type="source" position="bottom" />
</div>
),
switchNode: ({ data }) => (
<div style={{ padding: 10, border: '1px solid #3498db', borderRadius: 5, backgroundColor: '#eaf4fd' }}>
<Handle type="target" position="top" />
<div>Switch: {data.label}</div>
<div>Cases:</div>
{data.cases.map((caseItem, index) => (
<div key={index}>{`Case ${index + 1}: ${caseItem}`}</div>
))}
<Handle type="source" position="bottom" />
</div>
),
apiCallNode: ({ data }) => (
<div style={{ padding: 10, border: '1px solid #27ae60', borderRadius: 5, backgroundColor: '#eafaf1' }}>
<Handle type="target" position="top" />
<div>API Call: {data.url}</div>
<Handle type="source" position="bottom" />
</div>
),
setVariableNode: ({ data }) => (
<div style={{ padding: 10, border: '1px solid #e74c3c', borderRadius: 5, backgroundColor: '#fdecea' }}>
<Handle type="target" position="top" />
<div>Set Variable: {data.variableName} = {data.value}</div>
<Handle type="source" position="bottom" />
</div>
),
};
const DraggableNode = ({ type, label }) => {
const onDragStart = (event) => {
event.dataTransfer.setData('application/reactflow', type);
event.dataTransfer.effectAllowed = 'move';
};
return (
<div
draggable
onDragStart={onDragStart}
style={{ padding: '8px', marginBottom: '8px', backgroundColor: '#eee', cursor: 'grab' }}
>
{label}
</div>
);
};
const ChatBuilder = () => {
const [elements, setElements] = useState(initialElements);
const [reactFlowInstance, setReactFlowInstance] = useState(null);
const onConnect = (params) => setElements((els) => addEdge(params, els));
const onDrop = useCallback(
(event) => {
event.preventDefault();
if (!reactFlowInstance) {
console.error('React Flow instance is not ready');
return;
}
const type = event.dataTransfer.getData('application/reactflow');
if (!type) {
console.error('No node type found in drag data');
return;
}
const reactFlowBounds = document.querySelector('.reactflow-wrapper').getBoundingClientRect();
const position = reactFlowInstance.project({
x: event.clientX - reactFlowBounds.left,
y: event.clientY - reactFlowBounds.top,
});
console.log('Adding node at position:', position); // Debugging log
const id = `node_${+new Date()}`;
const newNode = {
id,
type,
position,
data: { label: `${type} Node` },
};
setElements((es) => es.concat(newNode));
},
[reactFlowInstance]
);
const onDragOver = useCallback((event) => {
event.preventDefault();
event.dataTransfer.dropEffect = 'move';
}, []);
const onLoad = useCallback((rfi) => {
setReactFlowInstance(rfi);
rfi.fitView();
}, []);
const saveFlow = async () => {
try {
const response = await axios.post('http://localhost:5000/api/saveFlow', {
name: 'My First Flow',
flowJson: elements,
});
alert(`Flow saved with ID: ${response.data.id}`);
} catch (error) {
console.error('Error saving flow', error);
alert('Failed to save flow');
}
};
return (
<div style={{ display: 'flex', height: '90vh' }}>
<div style={{ width: '20%', padding: '10px', borderRight: '1px solid #ccc' }}>
<h3>Node Types</h3>
<DraggableNode type="textNode" label="Text Node" />
<DraggableNode type="conditionNode" label="Condition Node" />
<DraggableNode type="switchNode" label="Switch Node" />
<DraggableNode type="apiCallNode" label="API Call Node" />
<DraggableNode type="setVariableNode" label="Set Variable Node" />
<button onClick={saveFlow}>Save Flow</button>
</div>
<div className="reactflow-wrapper" style={{ width: '80%', height: '100%' }}>
<ReactFlow
elements={elements}
onConnect={onConnect}
onElementsRemove={(elementsToRemove) =>
setElements((els) => els.filter((e) => !elementsToRemove.includes(e)))
}
onLoad={onLoad}
onNodeDragStop={(event, node) =>
setElements((els) =>
els.map((el) => (el.id === node.id ? { ...el, position: node.position } : el))
)
}
onDrop={onDrop}
onDragOver={onDragOver}
nodeTypes={nodeTypes}
snapToGrid={true}
>
<Background color="#aaa" gap={16} />
<Controls />
<MiniMap />
</ReactFlow>
</div>
</div>
);
};
export default ChatBuilder;
I should be able to drag and drop the nodes and build my workflow
Upvotes: 0
Views: 77