Merge pull request 'develop' (#6) from develop into master
Reviewed-on: #6
This commit is contained in:
commit
73dffb2893
23
diagram.json
23
diagram.json
@ -1,4 +1,25 @@
|
||||
{
|
||||
"nodes": [],
|
||||
"nodes": [
|
||||
{
|
||||
"id": "1",
|
||||
"type": "custom",
|
||||
"data": {
|
||||
"label": "Node 1",
|
||||
"icon": "https://s3.dvirlabs.com/lab-icons/dev-tools/argocd.svg"
|
||||
},
|
||||
"position": {
|
||||
"x": 68.5849844537563,
|
||||
"y": 225.18693121594464
|
||||
},
|
||||
"width": 82,
|
||||
"height": 82,
|
||||
"selected": false,
|
||||
"positionAbsolute": {
|
||||
"x": 68.5849844537563,
|
||||
"y": 225.18693121594464
|
||||
},
|
||||
"dragging": false
|
||||
}
|
||||
],
|
||||
"edges": []
|
||||
}
|
||||
21
frontend/package-lock.json
generated
21
frontend/package-lock.json
generated
@ -10,6 +10,7 @@
|
||||
"dependencies": {
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-toastify": "^11.0.5",
|
||||
"reactflow": "^11.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -1589,6 +1590,14 @@
|
||||
"resolved": "https://registry.npmjs.org/classcat/-/classcat-5.0.5.tgz",
|
||||
"integrity": "sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w=="
|
||||
},
|
||||
"node_modules/clsx": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
|
||||
"integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
@ -2434,6 +2443,18 @@
|
||||
"react": "^19.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-toastify": {
|
||||
"version": "11.0.5",
|
||||
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-11.0.5.tgz",
|
||||
"integrity": "sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA==",
|
||||
"dependencies": {
|
||||
"clsx": "^2.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18 || ^19",
|
||||
"react-dom": "^18 || ^19"
|
||||
}
|
||||
},
|
||||
"node_modules/reactflow": {
|
||||
"version": "11.11.4",
|
||||
"resolved": "https://registry.npmjs.org/reactflow/-/reactflow-11.11.4.tgz",
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
"dependencies": {
|
||||
"react": "^19.1.0",
|
||||
"react-dom": "^19.1.0",
|
||||
"react-toastify": "^11.0.5",
|
||||
"reactflow": "^11.11.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@ -1,7 +1,14 @@
|
||||
import Diagram from './components/Diagram';
|
||||
import { ToastContainer } from 'react-toastify';
|
||||
import 'react-toastify/dist/ReactToastify.css';
|
||||
|
||||
function App() {
|
||||
return <Diagram />;
|
||||
return (
|
||||
<>
|
||||
<Diagram />
|
||||
<ToastContainer position="bottom-right" autoClose={3000} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@ -3,31 +3,61 @@ import { Handle, Position } from 'reactflow';
|
||||
function CustomNode({ data }) {
|
||||
const icon = data.icon || 'https://s3.dvirlabs.com/lab-icons/default.svg';
|
||||
|
||||
const handleSize = 5;
|
||||
|
||||
const visibleHandleStyle = {
|
||||
background: '#1976d2',
|
||||
width: handleSize,
|
||||
height: handleSize,
|
||||
borderRadius: '50%',
|
||||
zIndex: 2,
|
||||
};
|
||||
|
||||
const invisibleHandleStyle = {
|
||||
background: 'transparent',
|
||||
width: handleSize,
|
||||
height: handleSize,
|
||||
borderRadius: '50%',
|
||||
zIndex: 1,
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
background: 'transparent',
|
||||
border: '2px solid #1976d2',
|
||||
borderRadius: 6,
|
||||
padding: 10,
|
||||
textAlign: 'center',
|
||||
width: 80,
|
||||
height: 40,
|
||||
height: 80,
|
||||
boxShadow: '0 2px 6px rgba(0,0,0,0.2)',
|
||||
position: 'relative',
|
||||
}}>
|
||||
{/* Handles - חובה */}
|
||||
<Handle type="target" position={Position.Top} />
|
||||
<Handle type="source" position={Position.Bottom} />
|
||||
{/* === TOP === */}
|
||||
<Handle id="source-top" type="source" position={Position.Top} style={{ ...visibleHandleStyle, top: -6 }} />
|
||||
<Handle id="target-top" type="target" position={Position.Top} style={{ ...invisibleHandleStyle, top: -6 }} />
|
||||
|
||||
{/* === BOTTOM === */}
|
||||
<Handle id="source-bottom" type="source" position={Position.Bottom} style={{ ...visibleHandleStyle, bottom: -6 }} />
|
||||
<Handle id="target-bottom" type="target" position={Position.Bottom} style={{ ...invisibleHandleStyle, bottom: -6 }} />
|
||||
|
||||
{/* === LEFT === */}
|
||||
<Handle id="source-left" type="source" position={Position.Left} style={{ ...visibleHandleStyle, left: -6, top: 30 }} />
|
||||
<Handle id="target-left" type="target" position={Position.Left} style={{ ...invisibleHandleStyle, left: -6, top: 30 }} />
|
||||
|
||||
{/* === RIGHT === */}
|
||||
<Handle id="source-right" type="source" position={Position.Right} style={{ ...visibleHandleStyle, right: -6, top: 30 }} />
|
||||
<Handle id="target-right" type="target" position={Position.Right} style={{ ...invisibleHandleStyle, right: -6, top: 30 }} />
|
||||
|
||||
{/* === ICON + LABEL === */}
|
||||
<img
|
||||
src={icon}
|
||||
alt={data.label}
|
||||
onError={(e) => {
|
||||
e.target.src = 'https://s3.dvirlabs.com/lab-icons/default.svg';
|
||||
}}
|
||||
style={{ width: 40, height: 40, marginBottom: 6 }}
|
||||
style={{ width: 40, height: 40, marginTop: 6 }}
|
||||
/>
|
||||
<div style={{ fontWeight: 'bold' }}>{data.label}</div>
|
||||
<div style={{ fontWeight: 'bold', fontSize: 12 }}>{data.label}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
// src/components/Diagram.jsx
|
||||
import { useEffect, useState, useCallback } from 'react';
|
||||
import ReactFlow, {
|
||||
addEdge,
|
||||
@ -11,6 +10,7 @@ import 'reactflow/dist/style.css';
|
||||
import { fetchDiagram, saveDiagram } from '../services/api';
|
||||
import CustomNode from './CustomNode';
|
||||
import IconSelector from './IconSelector';
|
||||
import { toast } from 'react-toastify';
|
||||
|
||||
const nodeTypes = {
|
||||
custom: CustomNode,
|
||||
@ -45,7 +45,7 @@ function Diagram() {
|
||||
animated: !!animated,
|
||||
}));
|
||||
await saveDiagram({ nodes, edges: cleanedEdges });
|
||||
alert('Diagram saved!');
|
||||
toast.success('✅ Diagram saved!');
|
||||
};
|
||||
|
||||
const handleAddNode = () => {
|
||||
@ -65,6 +65,7 @@ function Diagram() {
|
||||
};
|
||||
|
||||
setNodes((nds) => [...nds, newNode]);
|
||||
toast.success(`🟢 Node "${label}" added`);
|
||||
setShowForm(false);
|
||||
setNewLabel('');
|
||||
setSelectedIcon('');
|
||||
@ -72,8 +73,10 @@ function Diagram() {
|
||||
|
||||
const handleDeleteNode = () => {
|
||||
if (!selectedNode) return;
|
||||
|
||||
setNodes((nds) => nds.filter((n) => n.id !== selectedNode.id));
|
||||
setEdges((eds) => eds.filter((e) => e.source !== selectedNode.id && e.target !== selectedNode.id));
|
||||
toast.error(`🗑️ Node "${selectedNode.data.label}" deleted`);
|
||||
setSelectedNode(null);
|
||||
};
|
||||
|
||||
@ -90,6 +93,7 @@ function Diagram() {
|
||||
n.id === node.id ? { ...n, data: { ...n.data, label: newLabel } } : n
|
||||
)
|
||||
);
|
||||
toast.info(`✏️ Node renamed to "${newLabel}"`);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user