Skip to content

Commit b0d6a5c

Browse files
committed
feat(workflow): add programmatic node creation utilities
- Add useWorkflowActions hook for programmatic node manipulation - Implement node factory utilities for creating workflow nodes - Export new utilities in library entry point - Update README with new functionality documentation
1 parent 962770e commit b0d6a5c

File tree

5 files changed

+695
-0
lines changed

5 files changed

+695
-0
lines changed

src/lib/README.md

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ A reusable React library for building serverless workflow editors using React Fl
66

77
- **🎯 Pre-built Node Components**: Ready-to-use React Flow nodes for different workflow states (Start, Operation, Switch, Event, Sleep, End)
88
- **🔄 State Management Hooks**: Comprehensive hooks for workflow state, history management, and edge connections
9+
- **🚀 Programmatic Node Creation**: Add, remove, and manipulate workflow nodes programmatically with useWorkflowActions hook
10+
- **🏭 Node Factory Utilities**: Low-level utilities for creating workflow nodes with custom configurations
911
- **📊 Workflow Conversion**: Bidirectional conversion between React Flow data and Serverless Workflow specification
1012
- **🎨 Smart Edge Styling**: Automatic edge styling with animations, colors, and labels based on node types
1113
- **⏮️ Undo/Redo Support**: Built-in history management with undo/redo functionality
@@ -39,6 +41,7 @@ import {
3941
useHistory,
4042
useWorkflowState,
4143
useEdgeConnection,
44+
useWorkflowActions,
4245
createServerlessWorkflow,
4346
convertWorkflowToReactFlow,
4447
} from 'serverless-workflow-builder-lib';
@@ -83,6 +86,12 @@ function WorkflowEditor() {
8386
workflowMetadata
8487
);
8588

89+
// Initialize workflow actions for programmatic node creation
90+
const workflowActions = useWorkflowActions(
91+
{ nodes, edges, workflowMetadata, updateNodes, updateEdges },
92+
setHistoryState
93+
);
94+
8695
// Convert current workflow to Serverless Workflow JSON
8796
const exportWorkflow = () => {
8897
const workflow = createServerlessWorkflow(nodes, edges, workflowMetadata);
@@ -611,6 +620,210 @@ const stats = getWorkflowStats();
611620
console.log(`Total nodes: ${stats.totalNodes}`);
612621
```
613622

623+
### useWorkflowActions
624+
625+
Provides functions to programmatically add, remove, and manipulate workflow nodes.
626+
627+
```jsx
628+
import { useWorkflowActions } from 'serverless-workflow-builder-lib';
629+
630+
const workflowActions = useWorkflowActions(workflowState, historyCallback);
631+
632+
const {
633+
// Add specific node types
634+
addOperationNode, // Add operation node
635+
addSleepNode, // Add sleep node
636+
addEventNode, // Add event node
637+
addSwitchNode, // Add switch node
638+
addEndNode, // Add end node
639+
addStartNode, // Add start node
640+
641+
// Generic functions
642+
addNode, // Add any node type
643+
removeNode, // Remove node by ID
644+
duplicateNode, // Duplicate existing node
645+
clearAllNodes, // Clear all nodes
646+
647+
// Utility
648+
getDefaultPosition // Get default position for new nodes
649+
} = workflowActions;
650+
```
651+
652+
#### Parameters
653+
- `workflowState`: The workflow state object from useWorkflowState
654+
- `historyCallback`: Optional callback to update history state
655+
656+
#### Example
657+
658+
```jsx
659+
function WorkflowEditor() {
660+
const { nodes, edges, workflowMetadata, updateNodes, updateEdges } = useWorkflowState(
661+
defaultInitialNodes,
662+
defaultInitialEdges,
663+
workflowMetadata
664+
);
665+
666+
const { setState: setHistoryState } = useHistory({
667+
nodes: defaultInitialNodes,
668+
edges: defaultInitialEdges,
669+
workflowMetadata
670+
});
671+
672+
const workflowActions = useWorkflowActions(
673+
{ nodes, edges, workflowMetadata, updateNodes, updateEdges },
674+
setHistoryState
675+
);
676+
677+
return (
678+
<div>
679+
{/* Add state buttons */}
680+
<div style={{ padding: '10px', display: 'flex', gap: '10px' }}>
681+
<button onClick={() => workflowActions.addOperationNode()}>
682+
+ Operation
683+
</button>
684+
<button onClick={() => workflowActions.addSleepNode()}>
685+
+ Sleep
686+
</button>
687+
<button onClick={() => workflowActions.addEventNode()}>
688+
+ Event
689+
</button>
690+
<button onClick={() => workflowActions.addSwitchNode()}>
691+
+ Switch
692+
</button>
693+
<button onClick={() => workflowActions.addEndNode()}>
694+
+ End
695+
</button>
696+
</div>
697+
698+
{/* Custom positioned node */}
699+
<button
700+
onClick={() => workflowActions.addOperationNode({
701+
position: { x: 200, y: 300 },
702+
name: 'Custom Operation',
703+
actions: [{ name: 'customAction', functionRef: 'myFunction' }]
704+
})}
705+
>
706+
Add Custom Operation
707+
</button>
708+
709+
{/* Remove node */}
710+
<button onClick={() => workflowActions.removeNode('node-id')}>
711+
Remove Node
712+
</button>
713+
714+
{/* Duplicate node */}
715+
<button onClick={() => workflowActions.duplicateNode('node-id')}>
716+
Duplicate Node
717+
</button>
718+
719+
{/* React Flow component */}
720+
<ReactFlow
721+
nodes={nodes}
722+
edges={edges}
723+
nodeTypes={nodeTypes}
724+
// ... other props
725+
/>
726+
</div>
727+
);
728+
}
729+
```
730+
731+
#### Node Creation Options
732+
733+
Each add function accepts an optional options object:
734+
735+
```jsx
736+
// Basic usage
737+
workflowActions.addOperationNode();
738+
739+
// With custom options
740+
workflowActions.addOperationNode({
741+
position: { x: 100, y: 200 }, // Custom position
742+
name: 'My Operation', // Custom name
743+
actions: [ // Custom actions
744+
{ name: 'action1', functionRef: 'func1' }
745+
],
746+
metadata: { custom: 'data' } // Custom metadata
747+
});
748+
749+
// Sleep node with duration
750+
workflowActions.addSleepNode({
751+
name: 'Wait 5 seconds',
752+
duration: 'PT5S'
753+
});
754+
755+
// Event node with events
756+
workflowActions.addEventNode({
757+
name: 'Wait for Order',
758+
onEvents: [{
759+
eventRefs: ['order.created']
760+
}]
761+
});
762+
```
763+
764+
## Node Factory Utilities
765+
766+
Low-level utilities for creating workflow nodes programmatically.
767+
768+
```jsx
769+
import {
770+
createOperationNode,
771+
createSleepNode,
772+
createEventNode,
773+
createSwitchNode,
774+
createEndNode,
775+
createStartNode,
776+
createNode,
777+
generateNodeId,
778+
getDefaultPosition
779+
} from 'serverless-workflow-builder-lib';
780+
```
781+
782+
### Individual Node Creators
783+
784+
```jsx
785+
// Create specific node types
786+
const operationNode = createOperationNode({
787+
position: { x: 100, y: 200 },
788+
name: 'Process Order',
789+
actions: [{ name: 'processOrder', functionRef: 'orderProcessor' }]
790+
});
791+
792+
const sleepNode = createSleepNode({
793+
position: { x: 200, y: 300 },
794+
name: 'Wait',
795+
duration: 'PT30S'
796+
});
797+
798+
const eventNode = createEventNode({
799+
position: { x: 300, y: 400 },
800+
name: 'Wait for Event',
801+
onEvents: [{ eventRefs: ['user.action'] }]
802+
});
803+
```
804+
805+
### Generic Node Creator
806+
807+
```jsx
808+
// Create any node type
809+
const node = createNode('operation', {
810+
position: { x: 100, y: 200 },
811+
name: 'My Node',
812+
// ... type-specific options
813+
});
814+
```
815+
816+
### Utility Functions
817+
818+
```jsx
819+
// Generate unique node ID
820+
const nodeId = generateNodeId(); // Returns: 'node-1234567890'
821+
822+
// Get default position for new nodes
823+
const position = getDefaultPosition(existingNodes);
824+
// Returns: { x: number, y: number }
825+
```
826+
614827
## Utilities
615828

616829
### Workflow Conversion

src/lib/src/hooks/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export { useWorkflowState } from './useWorkflowState';
2+
export { useHistory } from './useHistory';
3+
export { useEdgeConnection } from './useEdgeConnection';
4+
export { useWorkflowActions } from './useWorkflowActions';

0 commit comments

Comments
 (0)