From 74315fde64f9dfb312274304366712ea1a4368d1 Mon Sep 17 00:00:00 2001 From: dvirlabs Date: Tue, 24 Mar 2026 08:37:03 +0200 Subject: [PATCH] Build and push app --- backend/Dockerfile | 1 + backend/__pycache__/main.cpython-313.pyc | Bin 5390 -> 5390 bytes frontend/package-lock.json | 73 +++++++++++++ frontend/package.json | 1 + frontend/src/components/Diagram.jsx | 127 +++++++++++++++++++++-- 5 files changed, 196 insertions(+), 6 deletions(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index 8236346..294f689 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -10,3 +10,4 @@ COPY . . CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] EXPOSE 8000 + diff --git a/backend/__pycache__/main.cpython-313.pyc b/backend/__pycache__/main.cpython-313.pyc index c8f154aed03f2a903e8e981b7d62c6370ade46ce..b68de2f07b5b5385f5ce92e49ae09e931beb594a 100644 GIT binary patch delta 20 acmeCv>eJ%>%*)Hg00dKx6>sEb76kw~!v!<| delta 20 acmeCv>eJ%>%*)Hg00bdNi#BpIivj>Q_yqC* diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a00bf2d..3e81629 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -12,6 +12,7 @@ "react": "^19.1.0", "react-confirm-alert": "^3.0.6", "react-dom": "^19.1.0", + "react-quill-new": "^3.4.6", "react-toastify": "^11.0.5", "reactflow": "^11.11.4" }, @@ -1988,12 +1989,22 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==" + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -2247,6 +2258,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, + "node_modules/lodash.isequal": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", + "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==", + "deprecated": "This package is deprecated. Use require('node:util').isDeepStrictEqual instead." + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -2361,6 +2388,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parchment": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/parchment/-/parchment-3.0.0.tgz", + "integrity": "sha512-HUrJFQ/StvgmXRcQ1ftY6VEZUq3jA2t9ncFN4F84J/vN0/FPpQF+8FKXb3l6fLces6q0uOHj6NJn+2xvZnxO6A==" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -2465,6 +2497,33 @@ "node": ">=6" } }, + "node_modules/quill": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/quill/-/quill-2.0.3.tgz", + "integrity": "sha512-xEYQBqfYx/sfb33VJiKnSJp8ehloavImQ2A6564GAbqG55PGw1dAWUn1MUbQB62t0azawUS2CZZhWCjO8gRvTw==", + "dependencies": { + "eventemitter3": "^5.0.1", + "lodash-es": "^4.17.21", + "parchment": "^3.0.0", + "quill-delta": "^5.1.0" + }, + "engines": { + "npm": ">=8.2.3" + } + }, + "node_modules/quill-delta": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-5.1.0.tgz", + "integrity": "sha512-X74oCeRI4/p0ucjb5Ma8adTXd9Scumz367kkMK5V/IatcX6A0vlgLgKbzXWy5nZmCGeNJm2oQX0d2Eqj+ZIlCA==", + "dependencies": { + "fast-diff": "^1.3.0", + "lodash.clonedeep": "^4.5.0", + "lodash.isequal": "^4.5.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/react": { "version": "19.1.0", "resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz", @@ -2498,6 +2557,20 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "node_modules/react-quill-new": { + "version": "3.4.6", + "resolved": "https://registry.npmjs.org/react-quill-new/-/react-quill-new-3.4.6.tgz", + "integrity": "sha512-S2kEAwoKRo+xUIAEpb94fwiPe2QU3FmwIfQ+7Lkchf+izPa2nRu1mr4i4QxyVYg8TjHDryDUiOEYZuFEV45QFA==", + "dependencies": { + "lodash-es": "^4.17.21", + "quill": "~2.0.2" + }, + "peerDependencies": { + "quill-delta": "^5.1.0", + "react": "^16 || ^17 || ^18 || ^19", + "react-dom": "^16 || ^17 || ^18 || ^19" + } + }, "node_modules/react-toastify": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-11.0.5.tgz", diff --git a/frontend/package.json b/frontend/package.json index f6c6816..f72054b 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -14,6 +14,7 @@ "react": "^19.1.0", "react-confirm-alert": "^3.0.6", "react-dom": "^19.1.0", + "react-quill-new": "^3.4.6", "react-toastify": "^11.0.5", "reactflow": "^11.11.4" }, diff --git a/frontend/src/components/Diagram.jsx b/frontend/src/components/Diagram.jsx index 2e28434..425d0bc 100644 --- a/frontend/src/components/Diagram.jsx +++ b/frontend/src/components/Diagram.jsx @@ -16,14 +16,18 @@ import { listDiagrams, deleteDiagramByName, } from '../services/api'; +import ReactQuill from 'react-quill-new'; +import 'react-quill-new/dist/quill.snow.css'; import CustomNode from './CustomNode'; +import RouterNode from './RouterNode'; +import TextNode from './TextNode'; import IconSelector from './IconSelector'; import { toast } from 'react-toastify'; -import RouterNode from './RouterNode'; const nodeTypes = { custom: CustomNode, router: RouterNode, + text: TextNode, }; function Diagram() { @@ -37,6 +41,8 @@ function Diagram() { const [selectedIcon, setSelectedIcon] = useState(''); const [diagramName, setDiagramName] = useState(null); const [diagramList, setDiagramList] = useState([]); + const [editingTextNode, setEditingTextNode] = useState(null); + const [tempHtml, setTempHtml] = useState(''); const isIframe = window.self !== window.top; useEffect(() => { @@ -68,7 +74,45 @@ function Diagram() { } try { const data = await fetchDiagramByName(diagramName); - setNodes(data.nodes || []); + const enhancedNodes = (data.nodes || []).map((n) => { + if (n.type === 'text') { + return { + ...n, + draggable: true, // ✅ ADD THIS HERE + data: { + ...(n.data || {}), + editing: false, + onChange: (val) => + setNodes((nds) => + nds.map((node) => + node.id === n.id ? { ...node, data: { ...node.data, value: val } } : node + ) + ), + onSave: () => + setNodes((nds) => + nds.map((node) => + node.id === n.id + ? { + ...node, + draggable: true, // ✅ RE-ENABLE ON SAVE + data: { ...node.data, editing: false }, + } + : node + ) + ), + }, + }; + } + + return { + ...n, + draggable: true // ✅ optionally apply for all node types too + }; + }); + + + setNodes(enhancedNodes); + const sanitizedEdges = (data.edges || []).map(({ id, source, target, animated }) => ({ id, source, target, animated: !!animated })); @@ -142,17 +186,55 @@ function Diagram() { const onNodeClick = (_, node) => setSelectedNode(node); const handleNodeDoubleClick = (_, node) => { - const newLabel = prompt('Enter new name:', node.data.label); - if (newLabel !== null) { + if (node.type === 'text') { setNodes((nds) => nds.map((n) => - n.id === node.id ? { ...n, data: { ...n.data, label: newLabel } } : n + n.id === node.id + ? { + ...n, + draggable: false, // <-- disable dragging + data: { + ...n.data, + editing: true, + onChange: (val) => + setNodes((prev) => + prev.map((x) => + x.id === n.id ? { ...x, data: { ...x.data, value: val } } : x + ) + ), + onSave: () => + setNodes((prev) => + prev.map((x) => + x.id === n.id + ? { + ...x, + draggable: true, // <-- re-enable dragging on save + data: { ...x.data, editing: false }, + } + : x + ) + ), + }, + } + : n ) ); - toast.info(`✏️ Node renamed to "${newLabel}"`); + } else { + const newLabel = prompt('Enter new name:', node.data.label); + if (newLabel !== null) { + setNodes((nds) => + nds.map((n) => + n.id === node.id ? { ...n, data: { ...n.data, label: newLabel } } : n + ) + ); + toast.info(`✏️ Node renamed to "${newLabel}"`); + } } }; + + + const handleDeleteDiagram = async () => { if (!diagramName || diagramName === 'default') { toast.warn("❌ Cannot delete 'default' diagram or nothing selected."); @@ -258,6 +340,39 @@ function Diagram() { )} + +