From e9cb32eb0eba91d6a02e23a6d9c0c289ee0c9e73 Mon Sep 17 00:00:00 2001 From: m3mo Date: Mon, 9 Jun 2025 16:20:03 +0200 Subject: [PATCH] Enhance CustomNode and WorkflowEditor components: Added useCallback for edit and delete handlers, improved button interactions, and ensured node selection state is managed correctly. Updated log file with new server and node registry initialization messages. --- backend/logs/combined.log | 10 +++ .../src/components/workflow/CustomNode.js | 65 ++++++++++++------- frontend/src/pages/WorkflowEditor.js | 51 ++++++++------- 3 files changed, 79 insertions(+), 47 deletions(-) diff --git a/backend/logs/combined.log b/backend/logs/combined.log index 40149e4..f80486b 100644 --- a/backend/logs/combined.log +++ b/backend/logs/combined.log @@ -200,3 +200,13 @@ {"level":"debug","message":"Loaded node type: webhook","service":"flowforge-backend","timestamp":"2025-06-08 13:50:29"} {"level":"info","message":"Node registry initialized with 6 node types","service":"flowforge-backend","timestamp":"2025-06-08 13:50:29"} {"level":"info","message":"Database connection established successfully","service":"flowforge-backend","timestamp":"2025-06-08 13:50:29"} +{"level":"info","message":"Server running on port 4000","service":"flowforge-backend","timestamp":"2025-06-09 13:39:55"} +{"level":"info","message":"Initializing node registry","service":"flowforge-backend","timestamp":"2025-06-09 13:39:55"} +{"level":"debug","message":"Loaded node type: delay","service":"flowforge-backend","timestamp":"2025-06-09 13:39:55"} +{"level":"debug","message":"Loaded node type: email","service":"flowforge-backend","timestamp":"2025-06-09 13:39:55"} +{"level":"debug","message":"Loaded node type: function","service":"flowforge-backend","timestamp":"2025-06-09 13:39:55"} +{"level":"debug","message":"Loaded node type: http-request","service":"flowforge-backend","timestamp":"2025-06-09 13:39:55"} +{"level":"debug","message":"Loaded node type: logger","service":"flowforge-backend","timestamp":"2025-06-09 13:39:55"} +{"level":"debug","message":"Loaded node type: webhook","service":"flowforge-backend","timestamp":"2025-06-09 13:39:55"} +{"level":"info","message":"Node registry initialized with 6 node types","service":"flowforge-backend","timestamp":"2025-06-09 13:39:55"} +{"level":"info","message":"Database connection established successfully","service":"flowforge-backend","timestamp":"2025-06-09 13:39:55"} diff --git a/frontend/src/components/workflow/CustomNode.js b/frontend/src/components/workflow/CustomNode.js index 4566101..723c830 100644 --- a/frontend/src/components/workflow/CustomNode.js +++ b/frontend/src/components/workflow/CustomNode.js @@ -1,4 +1,4 @@ -import React, { memo } from 'react'; +import React, { memo, useCallback } from 'react'; import { Handle, Position } from 'reactflow'; const getNodeColor = (type) => { @@ -71,50 +71,71 @@ const CustomNode = ({ id, data, selected, onEdit, onDelete }) => { const nodeColor = getNodeColor(data.nodeType); const nodeIcon = getNodeIcon(data.nodeType); - const handleEdit = (e) => { - e.stopPropagation(); + const handleEdit = useCallback((e) => { + e?.stopPropagation?.(); + e?.preventDefault?.(); if (onEdit) { onEdit(id); } - }; + }, [id, onEdit]); - const handleDelete = (e) => { - e.stopPropagation(); + const handleDelete = useCallback((e) => { + e?.stopPropagation?.(); + e?.preventDefault?.(); if (onDelete) { onDelete(id); } - }; + }, [id, onDelete]); return (
- {/* Action buttons - show on hover or when selected */} -
+ {/* Action buttons - always visible for debugging */} +
{/* Edit button */} - +
{/* Delete button */} - +
{/* Input handle */} diff --git a/frontend/src/pages/WorkflowEditor.js b/frontend/src/pages/WorkflowEditor.js index 436fe71..acb6615 100644 --- a/frontend/src/pages/WorkflowEditor.js +++ b/frontend/src/pages/WorkflowEditor.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect, useCallback, useRef } from 'react'; +import React, { useState, useEffect, useCallback, useRef, useMemo } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import ReactFlow, { ReactFlowProvider, @@ -51,16 +51,39 @@ const WorkflowEditor = () => { const [viewport, setViewport] = useState({ x: 0, y: 0, zoom: 1 }); const [isFirstLoad, setIsFirstLoad] = useState(true); + // Handle node editing + const handleEditNode = useCallback((nodeId) => { + const node = nodes.find(n => n.id === nodeId); + if (node) { + setSelectedNode(node); + } + }, [nodes, setSelectedNode]); + + // Handle node deletion + const handleDeleteNode = useCallback((nodeId) => { + // Show confirmation dialog + if (window.confirm('Are you sure you want to delete this node?')) { + setNodes((nds) => nds.filter((n) => n.id !== nodeId)); + setEdges((eds) => eds.filter((e) => e.source !== nodeId && e.target !== nodeId)); + + // Clear selection if the deleted node was selected + if (selectedNode && selectedNode.id === nodeId) { + setSelectedNode(null); + } + } + }, [setNodes, setEdges, selectedNode, nodes]); + // Node type definitions for React Flow - const nodeTypeDefinitions = { + const nodeTypeDefinitions = useMemo(() => ({ customNode: (nodeProps) => ( ) - }; + }), [selectedNode, handleEditNode, handleDeleteNode]); // Load workflow if editing existing one useEffect(() => { @@ -306,28 +329,6 @@ const WorkflowEditor = () => { setNodes((nds) => nds.concat(newNode)); }; - // Handle node editing - const handleEditNode = useCallback((nodeId) => { - const node = nodes.find(n => n.id === nodeId); - if (node) { - setSelectedNode(node); - } - }, [nodes]); - - // Handle node deletion - const handleDeleteNode = useCallback((nodeId) => { - // Show confirmation dialog - if (window.confirm('Are you sure you want to delete this node?')) { - setNodes((nds) => nds.filter((n) => n.id !== nodeId)); - setEdges((eds) => eds.filter((e) => e.source !== nodeId && e.target !== nodeId)); - - // Clear selection if the deleted node was selected - if (selectedNode && selectedNode.id === nodeId) { - setSelectedNode(null); - } - } - }, [setNodes, setEdges, selectedNode]); - // Handle workflow execution const handleExecuteWorkflow = (executionId) => { setLatestExecutionId(executionId);