switch-node.tsx
Overview
The switch-node.tsx file defines a React functional component SwitchNode that represents a "Switch" node in a graphical flow or workflow editor, likely part of a larger low-code/no-code or workflow automation system. This node allows branching logic based on multiple conditions, visually displaying them in a structured format with handles for connecting to other nodes. It renders a toolbar, a header, multiple conditional blocks with their logical operators, and connection handles to facilitate linking in the flow graph.
The component is built on top of the @xyflow/react node framework and integrates UI components such as cards, handles, and toolbars. It relies on custom hooks and constants for positioning handles and retrieving variable labels.
Detailed Explanation
Types and Interfaces
ISwitchNodeandISwitchConditionare imported interfaces defining the shape of the node data and its conditions, respectively. They represent the data structure for the switch node and its conditions.NodeProps<ISwitchNode>: The prop type for the main component, provided by the node framework, encapsulates the node'sid,data, and selection state.
Utility Function
getConditionKey(idx: number, length: number): string
Purpose: Returns the textual label for a condition block depending on its position in the list of conditions.
Parameters:
idx: Index of the current condition block.length: Total number of condition blocks.
Returns: One of
"If","ElseIf", or"Else"based on position.Usage Example:
getConditionKey(0, 3); // returns 'If' getConditionKey(1, 3); // returns 'ElseIf' getConditionKey(2, 3); // returns 'Else'
React Components
ConditionBlock
interface ConditionBlockProps {
condition: ISwitchCondition;
nodeId: string;
}
Purpose: Displays the details of a single condition block inside the switch node. It shows each item in the condition with the variable label, operator icon, and comparison value.
Props:
condition: An object representing a switch condition, containing multiple items.nodeId: The ID of the node, used to fetch variable labels.
Implementation Details:
Uses
useGetVariableLabelByValuehook to get human-readable labels for variables referenced in the condition.Renders a card with a list of condition items.
For each item, displays:
The variable label (truncated if long).
The logical operator icon (e.g., equals, greater than).
The comparison value.
Return: JSX element rendering the condition block.
Usage Example:
<ConditionBlock condition={someCondition} nodeId="node-123" />
InnerSwitchNode
function InnerSwitchNode(props: NodeProps<ISwitchNode>): JSX.Element
Purpose: The main visual representation of the Switch Node inside the flow editor.
Props:
id: Node unique identifier.data: Node data conforming toISwitchNode.selected: Boolean indicating if the node is currently selected.
Functionality:
Uses
useBuildSwitchHandlePositionshook to calculate the positions and metadata of each condition block and its corresponding output handle.Renders a
ToolBarcomponent, with control options (run button hidden).Wraps content inside a
NodeWrapperwhich visually indicates selection.Adds a single target handle on the left side (
CommonHandleof typetarget) to accept incoming connections.Displays a
NodeHeaderwith the node's name and label.Iterates over the positions returned by the hook to render:
The condition key label ("If", "ElseIf", "Else").
The logical operator text in uppercase.
The associated
ConditionBlock.A source handle on the right side (
CommonHandleof typesource) for outgoing connections.
Return: JSX rendering the complete switch node.
Usage: Wrapped with
React.memoand exported asSwitchNode.Example:
<SwitchNode id="node-1" data={switchNodeData} selected={true} />
Exported Component
export const SwitchNode = memo(InnerSwitchNode);
The component is memoized to prevent unnecessary re-renders when props do not change.
This is the component imported and used elsewhere to render switch nodes in the flow editor.
Important Implementation Details
Handle Positions: The component does not calculate handle positions itself but uses a custom hook
useBuildSwitchHandlePositionsto obtain positions and relevant condition data for rendering handles and condition blocks dynamically.Logical Operators: The logical operators and their icons are referenced from a centralized constant
SwitchOperatorOptions, ensuring consistent representation.Handles: Uses
CommonHandlecomponents for source and target connection points, styled and positioned according to the calculated positions.Label Lookup: Variable labels inside conditions are resolved via
useGetVariableLabelByValuehook, abstracting data fetching or formatting logic.Condition Labeling: The first condition is labeled "If", intermediate conditions "ElseIf", and the last one "Else" to make the switch logic clear to users.
Styling: Uses UI components such as
CardandCardContentfor condition blocks, and applies utility CSS classes for layout and text styling.
Interaction with Other Parts of the System
Node Framework (
@xyflow/react): The component relies on the node framework'sNodePropsandPositionenums to integrate into the flow editor.UI Components: Uses shared UI components (
Card,NodeHeader,ToolBar,CommonHandle, etc.) from the project, promoting consistent look and feel.Constants & Hooks:
Imports constants like
NodeHandleIdandSwitchOperatorOptionsfor identifiers and operator metadata.Uses custom hooks
useGetVariableLabelByValue(for label resolution) anduseBuildSwitchHandlePositions(for layout calculations).
Logical Operator Icons: Uses
LogicalOperatorIconto render operator visuals.Handles Styling: Applies
RightHandleStyleto position the right side handles correctly.Data Model: Expects
ISwitchNodeandISwitchConditioninterfaces that represent the node's data format, presumably shared throughout the flow system.
Visual Diagram
componentDiagram
component SwitchNode {
+id: string
+data: ISwitchNode
+selected: boolean
}
component InnerSwitchNode {
+renders: ToolBar
+renders: NodeWrapper
+renders: NodeHeader
+renders: ConditionBlock[] (multiple)
+renders: CommonHandle (target, left)
+renders: CommonHandle[] (source, right)
}
component ConditionBlock {
+props: condition: ISwitchCondition, nodeId: string
+renders: Card containing condition items
+uses: LogicalOperatorIcon
+uses: useGetVariableLabelByValue
}
component ToolBar
component NodeWrapper
component NodeHeader
component CommonHandle
component LogicalOperatorIcon
component useBuildSwitchHandlePositions
component useGetVariableLabelByValue
SwitchNode <|-- InnerSwitchNode
InnerSwitchNode --> ToolBar
InnerSwitchNode --> NodeWrapper
InnerSwitchNode --> NodeHeader
InnerSwitchNode --> ConditionBlock
InnerSwitchNode --> CommonHandle
ConditionBlock --> LogicalOperatorIcon
ConditionBlock --> useGetVariableLabelByValue
InnerSwitchNode --> useBuildSwitchHandlePositions
Summary
The switch-node.tsx file implements a highly interactive, visually rich "Switch" node component for a flow editor, enabling users to define branching logic with multiple conditional paths. It modularizes rendering into reusable subcomponents, leverages hooks for dynamic positioning and label resolution, and integrates tightly with the node framework and UI libraries of the application. The component ensures clear visualization of conditions and logical operators, while providing connection points for building complex workflows.
Example Usage in JSX
import { SwitchNode } from './switch-node';
const switchNodeData: ISwitchNode = {
name: 'MySwitch',
label: 'Switch Node',
conditions: [
{
items: [
{ cpn_id: 'var1', operator: 'eq', value: '10' },
{ cpn_id: 'var2', operator: 'gt', value: '5' },
],
logical_operator: 'and',
},
{
items: [
{ cpn_id: 'var3', operator: 'lt', value: '20' },
],
logical_operator: 'or',
},
],
};
<SwitchNode id="node-123" data={switchNodeData} selected={true} />
This will render a switch node with two conditional branches, labeled "If" and "Else", each showing their respective condition items with operator icons and connection handles.