From 5d2c9416f765235693b75f047f953a08b8d41f72 Mon Sep 17 00:00:00 2001 From: Kshitiz Agrawal Date: Tue, 10 Jun 2025 00:00:40 +0530 Subject: [PATCH] (WIP): Enhance node detail visibility in WorkflowEditor components - Updated WorkflowEditor.js to include zoom functionality for node types, allowing detailed views based on zoom level. - Modified EventNode, OperationNode, and SwitchNode to display additional information when hovered and zoomed in, improving user interaction and clarity. - Added new CSS styles in NodeStyles.css for detailed views, enhancing the visual presentation of node information. --- src/components/WorkflowEditor.js | 21 +++++---- src/components/nodes/EventNode.js | 22 ++++++++- src/components/nodes/NodeStyles.css | 66 +++++++++++++++++++++++++++ src/components/nodes/OperationNode.js | 52 ++++++++++++++++++++- src/components/nodes/SwitchNode.js | 20 +++++++- 5 files changed, 166 insertions(+), 15 deletions(-) diff --git a/src/components/WorkflowEditor.js b/src/components/WorkflowEditor.js index a130c55..117aed3 100644 --- a/src/components/WorkflowEditor.js +++ b/src/components/WorkflowEditor.js @@ -9,6 +9,7 @@ import ReactFlow, { ReactFlowProvider, SelectionMode, useReactFlow, + useViewport, } from 'reactflow'; import 'reactflow/dist/style.css'; @@ -24,15 +25,6 @@ import JsonImporter from './JsonImporter'; import { useHistory } from '../hooks/useHistory'; import './WorkflowEditor.css'; -const nodeTypes = { - operation: OperationNode, - switch: SwitchNode, - start: StartNode, - end: EndNode, - event: EventNode, - sleep: SleepNode, -}; - const STORAGE_KEY = 'serverless-workflow-editor-state'; const defaultInitialNodes = [ @@ -82,6 +74,17 @@ function WorkflowEditor() { const reactFlowWrapper = useRef(null); const [reactFlowBounds, setReactFlowBounds] = useState(null); const [isDragOver, setIsDragOver] = useState(false); + const { zoom } = useViewport(); + + // Node types with zoom prop + const nodeTypes = useMemo(() => ({ + operation: (props) => , + switch: (props) => , + start: (props) => , + end: (props) => , + event: (props) => , + sleep: (props) => , + }), [zoom]); // History management for undo/redo const { diff --git a/src/components/nodes/EventNode.js b/src/components/nodes/EventNode.js index 469277e..0150f3e 100644 --- a/src/components/nodes/EventNode.js +++ b/src/components/nodes/EventNode.js @@ -3,9 +3,15 @@ import { Handle, Position } from 'reactflow'; import { Zap } from 'lucide-react'; import './NodeStyles.css'; -const EventNode = ({ data, selected }) => { +const EventNode = ({ data, selected, zoom = 1 }) => { + const [isHovered, setIsHovered] = React.useState(false); + const shouldShowDetails = zoom > 1.5 && isHovered; return ( -
+
setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + >
@@ -27,6 +33,18 @@ const EventNode = ({ data, selected }) => { Timeout: Yes
)} + + {/* Show detailed event info when highly zoomed AND hovered */} + {shouldShowDetails && data.events && data.events.map((event, index) => ( +
+
• Event {index + 1}
+ {event.eventRefs && ( +
+ {JSON.stringify(event.eventRefs)} +
+ )} +
+ ))}
diff --git a/src/components/nodes/NodeStyles.css b/src/components/nodes/NodeStyles.css index 80ddc45..933ada5 100644 --- a/src/components/nodes/NodeStyles.css +++ b/src/components/nodes/NodeStyles.css @@ -161,3 +161,69 @@ .sleep-node .node-header { color: #0891b2; } + +/* Detailed view styles for high zoom levels */ +.detailed-action { + margin-top: 8px; + padding: 6px; + background: rgba(255, 255, 255, 0.5); + border: 1px solid var(--border-color); + border-radius: 4px; + font-size: 10px; +} + +.action-name { + font-weight: 600; + color: var(--text-color); + margin-bottom: 2px; +} + +.action-function { + color: var(--text-secondary); + font-style: italic; + margin-bottom: 4px; +} + +.action-args { + margin: 4px 0; +} + +.action-args code { + font-size: 9px; + background: var(--bg-secondary); + padding: 2px 4px; + border-radius: 2px; + color: var(--text-color); + display: block; + white-space: pre-wrap; + word-break: break-word; + max-width: 200px; + overflow: hidden; + text-overflow: ellipsis; +} + +.action-retry { + font-size: 9px; + color: var(--success-color); + font-weight: 500; +} + +/* Condition detail styles for switch nodes */ +.condition-detail { + margin-top: 4px; + font-size: 9px; + color: var(--text-secondary); +} + +.condition-detail code { + font-size: 8px; + background: var(--bg-secondary); + padding: 1px 3px; + border-radius: 2px; + color: var(--text-color); + white-space: nowrap; + max-width: 150px; + overflow: hidden; + text-overflow: ellipsis; + display: inline-block; +} diff --git a/src/components/nodes/OperationNode.js b/src/components/nodes/OperationNode.js index 966fca5..abbebd7 100644 --- a/src/components/nodes/OperationNode.js +++ b/src/components/nodes/OperationNode.js @@ -3,9 +3,41 @@ import { Handle, Position, useReactFlow } from 'reactflow'; import { Play } from 'lucide-react'; import './NodeStyles.css'; -const OperationNode = ({ data, selected }) => { +const OperationNode = ({ data, selected, zoom = 1 }) => { + const [isHovered, setIsHovered] = React.useState(false); + const shouldShowDetails = zoom > 1.5 && isHovered; // Show details only when zoomed AND hovered + + // Use React Flow's useReactFlow hook to manipulate node z-index + const { setNodes } = useReactFlow(); + + React.useEffect(() => { + if (shouldShowDetails) { + setNodes((nds) => + nds.map((node) => { + if (node.data === data) { + return { ...node, style: { ...node.style, zIndex: 9999 } }; + } + return node; + }) + ); + } else { + setNodes((nds) => + nds.map((node) => { + if (node.data === data) { + return { ...node, style: { ...node.style, zIndex: 1 } }; + } + return node; + }) + ); + } + }, [shouldShowDetails, setNodes, data]); + return ( -
+
setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + >
@@ -22,6 +54,22 @@ const OperationNode = ({ data, selected }) => { Actions: {data.actions.length}
)} + + {/* Show detailed action info when highly zoomed AND hovered */} + {shouldShowDetails && data.actions && data.actions.map((action, index) => ( +
+
• {action.name}
+
{action.functionRef?.refName || 'No function'}
+ {action.functionRef?.arguments && Object.keys(action.functionRef.arguments).length > 0 && ( +
+ {JSON.stringify(action.functionRef.arguments)} +
+ )} + {action.retryRef && ( +
🔄 Retry enabled
+ )} +
+ ))}
diff --git a/src/components/nodes/SwitchNode.js b/src/components/nodes/SwitchNode.js index a7460d0..f82d238 100644 --- a/src/components/nodes/SwitchNode.js +++ b/src/components/nodes/SwitchNode.js @@ -3,7 +3,9 @@ import { Handle, Position } from 'reactflow'; import { GitBranch } from 'lucide-react'; import './NodeStyles.css'; -const SwitchNode = ({ data, selected }) => { +const SwitchNode = ({ data, selected, zoom = 1 }) => { + const [isHovered, setIsHovered] = React.useState(false); + const shouldShowDetails = zoom > 1.5 && isHovered; // Show details only when zoomed AND hovered const dataConditions = data.dataConditions || []; const eventConditions = data.eventConditions || []; const conditions = dataConditions.length > 0 ? dataConditions : eventConditions; @@ -12,7 +14,11 @@ const SwitchNode = ({ data, selected }) => { const totalHandles = conditions.length + (hasDefault ? 1 : 0); return ( -
+
setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + >
@@ -41,6 +47,16 @@ const SwitchNode = ({ data, selected }) => { {conditions.map((condition, index) => (
{condition.name || condition.eventRef || condition.condition || `condition${index + 1}`} + {shouldShowDetails && conditionType === 'data' && condition.condition && ( +
+ {condition.condition} +
+ )} + {shouldShowDetails && conditionType === 'event' && condition.eventRef && ( +
+ Event: {condition.eventRef} +
+ )}