Skip to content

Commit 2296dd3

Browse files
committed
feat(node): add unique name generation for workflow nodes
Add generateUniqueNodeName utility to create unique names for nodes based on existing ones Update all node factory functions to use this utility when no name is provided Pass existingNodes to node creation functions to ensure name uniqueness
1 parent f216fe8 commit 2296dd3

File tree

2 files changed

+69
-29
lines changed

2 files changed

+69
-29
lines changed

src/lib/src/hooks/useWorkflowActions.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,42 +39,42 @@ export function useWorkflowActions(workflowState, historyCallback) {
3939
// Add operation node
4040
const addOperationNode = useCallback((options = {}) => {
4141
const position = options.position || getDefaultPosition(nodes);
42-
const newNode = createOperationNode({ ...options, position });
42+
const newNode = createOperationNode({ ...options, position, existingNodes: nodes });
4343
return addNodeToWorkflow(newNode);
4444
}, [nodes, addNodeToWorkflow]);
4545

4646
// Add sleep node
4747
const addSleepNode = useCallback((options = {}) => {
4848
const position = options.position || getDefaultPosition(nodes);
49-
const newNode = createSleepNode({ ...options, position });
49+
const newNode = createSleepNode({ ...options, position, existingNodes: nodes });
5050
return addNodeToWorkflow(newNode);
5151
}, [nodes, addNodeToWorkflow]);
5252

5353
// Add event node
5454
const addEventNode = useCallback((options = {}) => {
5555
const position = options.position || getDefaultPosition(nodes);
56-
const newNode = createEventNode({ ...options, position });
56+
const newNode = createEventNode({ ...options, position, existingNodes: nodes });
5757
return addNodeToWorkflow(newNode);
5858
}, [nodes, addNodeToWorkflow]);
5959

6060
// Add switch node
6161
const addSwitchNode = useCallback((options = {}) => {
6262
const position = options.position || getDefaultPosition(nodes);
63-
const newNode = createSwitchNode({ ...options, position });
63+
const newNode = createSwitchNode({ ...options, position, existingNodes: nodes });
6464
return addNodeToWorkflow(newNode);
6565
}, [nodes, addNodeToWorkflow]);
6666

6767
// Add end node
6868
const addEndNode = useCallback((options = {}) => {
6969
const position = options.position || getDefaultPosition(nodes);
70-
const newNode = createEndNode({ ...options, position });
70+
const newNode = createEndNode({ ...options, position, existingNodes: nodes });
7171
return addNodeToWorkflow(newNode);
7272
}, [nodes, addNodeToWorkflow]);
7373

7474
// Add start node
7575
const addStartNode = useCallback((options = {}) => {
7676
const position = options.position || getDefaultPosition(nodes);
77-
const newNode = createStartNode({ ...options, position });
77+
const newNode = createStartNode({ ...options, position, existingNodes: nodes });
7878
return addNodeToWorkflow(newNode);
7979
}, [nodes, addNodeToWorkflow]);
8080

src/lib/src/utils/nodeFactory.js

Lines changed: 63 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,33 @@ export function generateNodeId(nodeType) {
1313
return `${nodeType}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1414
}
1515

16+
/**
17+
* Generate a unique node name based on existing nodes
18+
* @param {string} baseNodeType - The base type of node (e.g., 'Operation', 'Switch')
19+
* @param {Array} existingNodes - Array of existing nodes
20+
* @returns {string} Unique node name
21+
*/
22+
export function generateUniqueNodeName(baseNodeType, existingNodes = []) {
23+
const baseName = baseNodeType;
24+
const existingNames = existingNodes.map(node => node.data?.name || node.data?.label || '').filter(Boolean);
25+
26+
// If base name doesn't exist, use it
27+
if (!existingNames.includes(baseName)) {
28+
return baseName;
29+
}
30+
31+
// Find the next available number
32+
let counter = 1;
33+
let candidateName;
34+
35+
do {
36+
candidateName = `${baseName} ${counter}`;
37+
counter++;
38+
} while (existingNames.includes(candidateName));
39+
40+
return candidateName;
41+
}
42+
1643
/**
1744
* Get default position for a new node
1845
* @param {Array} existingNodes - Array of existing nodes
@@ -59,11 +86,12 @@ export function getDefaultPosition(existingNodes = []) {
5986
* @param {Array} options.actions - Array of actions
6087
* @param {Object} options.position - Position coordinates
6188
* @param {Object} options.metadata - Additional metadata
89+
* @param {Array} options.existingNodes - Array of existing nodes for unique naming
6290
* @returns {Object} Operation node object
6391
*/
6492
export function createOperationNode(options = {}) {
6593
const {
66-
name = 'New Operation',
94+
name,
6795
actions = [{
6896
name: 'defaultAction',
6997
functionRef: {
@@ -72,8 +100,11 @@ export function createOperationNode(options = {}) {
72100
}
73101
}],
74102
position,
75-
metadata = {}
103+
metadata = {},
104+
existingNodes = []
76105
} = options;
106+
107+
const nodeName = name || generateUniqueNodeName('Operation', existingNodes);
77108

78109
const nodeId = generateNodeId('operation');
79110

@@ -82,10 +113,10 @@ export function createOperationNode(options = {}) {
82113
type: 'operation',
83114
position: position || getDefaultPosition(),
84115
data: {
85-
name,
116+
name: nodeName,
86117
actions,
87118
metadata,
88-
label: name
119+
label: nodeName
89120
}
90121
};
91122
}
@@ -101,23 +132,25 @@ export function createOperationNode(options = {}) {
101132
*/
102133
export function createSleepNode(options = {}) {
103134
const {
104-
name = 'New Sleep',
135+
name,
105136
duration = 'PT5S',
106137
position,
107-
metadata = {}
138+
metadata = {},
139+
existingNodes = []
108140
} = options;
109-
141+
142+
const nodeName = name || generateUniqueNodeName('Sleep', existingNodes);
110143
const nodeId = generateNodeId('sleep');
111144

112145
return {
113146
id: nodeId,
114147
type: 'sleep',
115148
position: position || getDefaultPosition(),
116149
data: {
117-
name,
150+
name: nodeName,
118151
duration,
119152
metadata,
120-
label: name
153+
label: nodeName
121154
}
122155
};
123156
}
@@ -134,27 +167,29 @@ export function createSleepNode(options = {}) {
134167
*/
135168
export function createEventNode(options = {}) {
136169
const {
137-
name = 'New Event',
170+
name,
138171
onEvents = [{
139172
eventRefs: ['sample-event']
140173
}],
141174
timeouts = {},
142175
position,
143-
metadata = {}
176+
metadata = {},
177+
existingNodes = []
144178
} = options;
145-
179+
180+
const nodeName = name || generateUniqueNodeName('Event', existingNodes);
146181
const nodeId = generateNodeId('event');
147182

148183
return {
149184
id: nodeId,
150185
type: 'event',
151186
position: position || getDefaultPosition(),
152187
data: {
153-
name,
188+
name: nodeName,
154189
onEvents,
155190
timeouts,
156191
metadata,
157-
label: name
192+
label: nodeName
158193
}
159194
};
160195
}
@@ -172,7 +207,7 @@ export function createEventNode(options = {}) {
172207
*/
173208
export function createSwitchNode(options = {}) {
174209
const {
175-
name = 'New Switch',
210+
name,
176211
dataConditions = [{
177212
condition: '${ .data }',
178213
transition: {
@@ -186,8 +221,11 @@ export function createSwitchNode(options = {}) {
186221
}
187222
},
188223
position,
189-
metadata = {}
224+
metadata = {},
225+
existingNodes = []
190226
} = options;
227+
228+
const nodeName = name || generateUniqueNodeName('Switch', existingNodes);
191229

192230
const nodeId = generateNodeId('switch');
193231

@@ -196,12 +234,12 @@ export function createSwitchNode(options = {}) {
196234
type: 'switch',
197235
position: position || getDefaultPosition(),
198236
data: {
199-
name,
237+
name: nodeName,
200238
dataConditions,
201239
eventConditions,
202240
defaultCondition,
203241
metadata,
204-
label: name
242+
label: nodeName
205243
}
206244
};
207245
}
@@ -217,23 +255,25 @@ export function createSwitchNode(options = {}) {
217255
*/
218256
export function createEndNode(options = {}) {
219257
const {
220-
name = 'New End',
258+
name,
221259
terminate = true,
222260
position,
223-
metadata = {}
261+
metadata = {},
262+
existingNodes = []
224263
} = options;
225-
264+
265+
const nodeName = name || generateUniqueNodeName('End', existingNodes);
226266
const nodeId = generateNodeId('end');
227267

228268
return {
229269
id: nodeId,
230270
type: 'end',
231271
position: position || getDefaultPosition(),
232272
data: {
233-
name,
273+
name: nodeName,
234274
terminate,
235275
metadata,
236-
label: name
276+
label: nodeName
237277
}
238278
};
239279
}

0 commit comments

Comments
 (0)