diff --git a/Data/WebUI/src/App.js b/Data/WebUI/src/App.jsx
similarity index 74%
rename from Data/WebUI/src/App.js
rename to Data/WebUI/src/App.jsx
index 84733de..7f5f7db 100644
--- a/Data/WebUI/src/App.js
+++ b/Data/WebUI/src/App.jsx
@@ -77,7 +77,6 @@ const CustomNode = ({ data }) => {
);
};
-// FlowEditor with drag-and-drop and updated behavior
function FlowEditor({ nodes, edges, setNodes, setEdges }) {
const reactFlowWrapper = useRef(null);
const { project } = useReactFlow();
@@ -202,10 +201,10 @@ export default function App() {
const [nodes, setNodes] = useState([]);
const [edges, setEdges] = useState([]);
const [confirmCloseOpen, setConfirmCloseOpen] = useState(false);
+ const fileInputRef = useRef(null);
const handleAboutMenuOpen = (event) => setAboutAnchorEl(event.currentTarget);
const handleAboutMenuClose = () => setAboutAnchorEl(null);
-
const handleOpenCloseDialog = () => setConfirmCloseOpen(true);
const handleCloseDialog = () => setConfirmCloseOpen(false);
const handleConfirmCloseWorkflow = () => {
@@ -214,21 +213,59 @@ export default function App() {
setConfirmCloseOpen(false);
};
- const handleAddTestNode = () => {
- const id = `test-node-${Date.now()}`;
- const newNode = {
- id,
- type: "custom",
- data: {
- label: "Custom Node",
- content: "Placeholder"
- },
- position: {
- x: 250 + Math.random() * 300,
- y: 150 + Math.random() * 200
+ const handleSaveWorkflow = async () => {
+ const data = JSON.stringify({ nodes, edges }, null, 2);
+ const blob = new Blob([data], { type: "application/json" });
+
+ if (window.showSaveFilePicker) {
+ try {
+ const fileHandle = await window.showSaveFilePicker({
+ suggestedName: "workflow.json",
+ types: [{
+ description: "Workflow JSON File",
+ accept: { "application/json": [".json"] }
+ }]
+ });
+ const writable = await fileHandle.createWritable();
+ await writable.write(blob);
+ await writable.close();
+ } catch (error) {
+ console.error("Save cancelled or failed:", error);
}
- };
- setNodes((nds) => [...nds, newNode]);
+ } else {
+ const a = document.createElement("a");
+ a.href = URL.createObjectURL(blob);
+ a.download = "workflow.json";
+ a.style.display = "none";
+ document.body.appendChild(a);
+ a.click();
+ URL.revokeObjectURL(a.href);
+ document.body.removeChild(a);
+ }
+ };
+
+ const handleOpenWorkflow = async () => {
+ if (window.showOpenFilePicker) {
+ try {
+ const [fileHandle] = await window.showOpenFilePicker({
+ types: [{
+ description: "Workflow JSON File",
+ accept: { "application/json": [".json"] }
+ }]
+ });
+ const file = await fileHandle.getFile();
+ const text = await file.text();
+ const { nodes: loadedNodes, edges: loadedEdges } = JSON.parse(text);
+ const confirm = window.confirm("Opening a workflow will overwrite your current one. Continue?");
+ if (!confirm) return;
+ setNodes(loadedNodes);
+ setEdges(loadedEdges);
+ } catch (error) {
+ console.error("Open cancelled or failed:", error);
+ }
+ } else {
+ fileInputRef.current?.click();
+ }
};
return (
@@ -272,15 +309,9 @@ export default function App() {
Workflows
-
-
-
+
+
+
@@ -316,23 +347,12 @@ export default function App() {
-
+
Nodes: 0 | Update Rate: 500ms
- {/* Confirmation Dialog */}
-