Skip to content

Commit c142b33

Browse files
authored
Merge pull request #77 from FlowTestAI/set-var-node
Introduce node that helps to set variables during graph run
2 parents 5ce39e4 + 49133f3 commit c142b33

File tree

14 files changed

+548
-15
lines changed

14 files changed

+548
-15
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
const { Node } = require('./Node');
2+
3+
class SetVarNode extends Node {
4+
constructor() {
5+
super('setVarNode');
6+
}
7+
8+
serialize(id, data, metadata) {
9+
return {
10+
id,
11+
type: 'setVarNode',
12+
data,
13+
...metadata,
14+
};
15+
}
16+
17+
deserialize(node) {
18+
const id = node.id;
19+
const data = node.data;
20+
delete node.id;
21+
delete node.data;
22+
const metadata = node;
23+
24+
return {
25+
id,
26+
data,
27+
metadata,
28+
};
29+
}
30+
}
31+
32+
module.exports = {
33+
SetVarNode,
34+
};

packages/flowtest-electron/src/utils/flowparser/parser.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const { AssertNode } = require('./AssertNode');
66
const { OutputNode } = require('./OutputNode');
77
const { RequestNode } = require('./RequestNode');
88
const { StartNode } = require('./StartNode');
9+
const { SetVarNode } = require('./SetVarNode');
910

1011
const VERSION = 1;
1112

@@ -123,6 +124,20 @@ const deserialize = (flowData) => {
123124
...result.metadata,
124125
};
125126
}
127+
128+
if (node.type === 'setVarNode') {
129+
const sNode = new SetVarNode();
130+
const result = sNode.deserialize(node);
131+
textData.graph.data.nodes[result.id] = {
132+
type: 'setVarNode',
133+
...result.data,
134+
};
135+
136+
textData.graph.metadata.nodes[result.id] = {
137+
type: 'setVarNode',
138+
...result.metadata,
139+
};
140+
}
126141
});
127142
}
128143

@@ -211,6 +226,14 @@ const serialize = (textData) => {
211226
const result = cNode.serialize(id, data, metadata);
212227
flowData.nodes.push(result);
213228
}
229+
230+
if (value.type === 'setVarNode') {
231+
const data = value;
232+
const metadata = textDataCopy.graph.metadata.nodes[id];
233+
const cNode = new SetVarNode();
234+
const result = cNode.serialize(id, data, metadata);
235+
flowData.nodes.push(result);
236+
}
214237
});
215238

216239
Object.entries(textDataCopy.graph.metadata.edges).map(([key, value], index) => {

src/components/molecules/flow/AddNodes.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ const complexNode = {
5757
type: 'complexNode',
5858
};
5959

60+
const setVarNode = {
61+
description: 'Assign a value to a variable',
62+
type: 'setVarNode',
63+
};
64+
6065
const AddNodes = ({ collectionId }) => {
6166
// const [open, setOpen] = useState(false);
6267
// const anchorRef = useRef(null);
@@ -293,6 +298,29 @@ const AddNodes = ({ collectionId }) => {
293298
</>
294299
)}
295300
</Disclosure>
301+
{/* Set Variable */}
302+
<Disclosure as='div'>
303+
{({ open }) => (
304+
<>
305+
<Disclosure.Button className='flex justify-between w-full px-4 py-2 text-lg font-medium text-left border-t border-b bg-gray-50 hover:bg-gray-100 focus:outline-none focus-visible:ring'>
306+
<span>Set Variable</span>
307+
<ChevronUpIcon className={`${open ? 'rotate-180 transform' : ''} h-5 w-5 `} />
308+
</Disclosure.Button>
309+
<Disclosure.Panel className='px-4 pt-4 pb-2 text-sm border-l border-r'>
310+
<div
311+
key='complex'
312+
onDragStart={(event) => onDragStart(event, setVarNode)}
313+
draggable
314+
cursor='move'
315+
className='py-2 border-b'
316+
>
317+
<div className='text-base font-semibold primary-text'>Set Variable</div>
318+
<div className='text-xs secondary-text'>{setVarNode.description}</div>
319+
</div>
320+
</Disclosure.Panel>
321+
</>
322+
)}
323+
</Disclosure>
296324
</div>
297325
</>
298326
</Popover.Panel>

src/components/molecules/flow/constants/operators.js renamed to src/components/molecules/flow/constants/assertOperators.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
const Operators = {
1+
const AssertOperators = {
22
isLessThan: 'isLessThan',
33
isGreaterThan: 'isGreaterThan',
44
isEqualTo: 'isEqualTo',
55
isNotEqualTo: 'isNotEqualTo',
66
};
77

8-
export default Operators;
8+
export default AssertOperators;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const EvaluateOperators = {
2+
Add: 'Add two numbers',
3+
Subtract: 'Subtract two numbers',
4+
};
5+
6+
export default EvaluateOperators;

src/components/molecules/flow/graph/Graph.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import authNode from './compute/authnode';
77
import complexNode from './compute/complexnode';
88
import assertNode from './compute/assertnode';
99
import requestNode from './compute/requestNode';
10+
import setVarNode from './compute/setvarnode';
1011

1112
class Graph {
1213
constructor(nodes, edges, startTime, initialEnvVars, initialLogs) {
@@ -150,6 +151,21 @@ class Graph {
150151
}
151152
}
152153

154+
if (node.type === 'setVarNode') {
155+
const sNode = new setVarNode(node.data, prevNodeOutputData, this.envVariables);
156+
const newVariable = sNode.evaluate();
157+
if (newVariable != undefined) {
158+
this.logs.push(`Evaluate variable: ${newVariable}`);
159+
this.envVariables = {
160+
...this.envVariables,
161+
...newVariable,
162+
};
163+
}
164+
result = {
165+
status: 'Success',
166+
};
167+
}
168+
153169
if (this.#checkTimeout()) {
154170
throw `Timeout of ${this.timeout} ms exceeded, stopping graph run`;
155171
}
@@ -171,8 +187,9 @@ class Graph {
171187
if (connectingEdge != undefined) {
172188
const nextNode = this.nodes.find(
173189
(node) =>
174-
['requestNode', 'outputNode', 'assertNode', 'delayNode', 'authNode', 'complexNode'].includes(node.type) &&
175-
node.id === connectingEdge.target,
190+
['requestNode', 'outputNode', 'assertNode', 'delayNode', 'authNode', 'complexNode', 'setVarNode'].includes(
191+
node.type,
192+
) && node.id === connectingEdge.target,
176193
);
177194
this.graphRunNodeOutput[node.id] = result.data ? result.data : {};
178195
return this.#computeNode(nextNode);

src/components/molecules/flow/graph/compute/assertnode.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Operators from '../../constants/operators';
1+
import AssertOperators from '../../constants/assertOperators';
22
import { computeNodeVariable } from './utils';
33
import Node from './node';
44

@@ -36,13 +36,13 @@ class assertNode extends Node {
3636
this.logs.push(
3737
`Assert var1: ${JSON.stringify(var1)} of type: ${typeof var1}, var2: ${JSON.stringify(var2)} of type: ${typeof var2} with operator: ${operator}`,
3838
);
39-
if (operator == Operators.isEqualTo) {
39+
if (operator == AssertOperators.isEqualTo) {
4040
return var1 === var2;
41-
} else if (operator == Operators.isNotEqualTo) {
41+
} else if (operator == AssertOperators.isNotEqualTo) {
4242
return var1 != var2;
43-
} else if (operator == Operators.isGreaterThan) {
43+
} else if (operator == AssertOperators.isGreaterThan) {
4444
return var1 > var2;
45-
} else if (operator == Operators.isLessThan) {
45+
} else if (operator == AssertOperators.isLessThan) {
4646
return var1 < var2;
4747
}
4848
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { computeNodeVariable } from './utils';
2+
import Node from './node';
3+
import EvaluateOperators from '../../constants/evaluateOperators';
4+
5+
class setVarNode extends Node {
6+
constructor(nodeData, prevNodeOutputData, envVariables) {
7+
super('setVarNode');
8+
this.nodeData = nodeData;
9+
this.prevNodeOutputData = prevNodeOutputData;
10+
this.envVariables = envVariables;
11+
}
12+
13+
getVariableValue(variable) {
14+
if (variable.type.toLowerCase() === 'variable') {
15+
if (Object.prototype.hasOwnProperty.call(this.envVariables, variable.value)) {
16+
return this.envVariables[variable.value];
17+
} else {
18+
throw Error(`Cannot find value of variable ${variable.value}`);
19+
}
20+
} else {
21+
return computeNodeVariable(variable, this.prevNodeOutputData);
22+
}
23+
}
24+
25+
evaluate() {
26+
console.log('Evaluating set variable node');
27+
if (this.nodeData.variable) {
28+
if (this.nodeData.variable.name && this.nodeData.variable.name.trim() != '') {
29+
const vName = this.nodeData.variable.name;
30+
const vType = this.nodeData.variable.type.trim();
31+
if (['String', 'Number', 'Boolean', 'Now', 'Select'].includes(vType)) {
32+
const value = computeNodeVariable(this.nodeData.variable, this.prevNodeOutputData);
33+
return {
34+
[vName]: value,
35+
};
36+
} else if (vType === 'Expression') {
37+
const variables = this.nodeData.variable.value.variables;
38+
if (variables && variables.var1 && variables.var2) {
39+
const var1 = this.getVariableValue(this.nodeData.variable.value.variables.var1);
40+
const var2 = this.getVariableValue(this.nodeData.variable.value.variables.var2);
41+
42+
const operator = this.nodeData.variable.value.operator;
43+
if (operator == undefined) {
44+
throw 'Operator undefined';
45+
}
46+
if (operator == EvaluateOperators.Add) {
47+
if (typeof var1 !== 'number' || typeof var2 !== 'number') {
48+
throw Error(`Cannot perform ${typeof var1} + ${typeof var2}`);
49+
}
50+
return {
51+
[vName]: var1 + var2,
52+
};
53+
} else if (operator == EvaluateOperators.Subtract) {
54+
if (typeof var1 !== 'number' || typeof var2 !== 'number') {
55+
throw Error(`Cannot perform ${typeof var1} + ${typeof var2}`);
56+
}
57+
return {
58+
[vName]: var1 - var2,
59+
};
60+
}
61+
}
62+
}
63+
}
64+
}
65+
}
66+
}
67+
68+
export default setVarNode;

src/components/molecules/flow/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { useTabStore } from 'stores/TabStore';
2424
import Graph from './graph/Graph';
2525
import ComplexNode from './nodes/ComplexNode';
2626
import { initFlowData } from './utils';
27+
import SetVarNode from './nodes/SetVarNode';
2728

2829
const StartNode = () => (
2930
<FlowNode title='Start' handleLeft={false} handleRight={true} handleRightData={{ type: 'source' }}></FlowNode>
@@ -92,6 +93,7 @@ const Flow = ({ collectionId }) => {
9293
delayNode: DelayNode,
9394
authNode: AuthNode,
9495
complexNode: ComplexNode,
96+
setVarNode: SetVarNode,
9597
}),
9698
[],
9799
);

src/components/molecules/flow/nodes/AssertNode.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { useState } from 'react';
22
import { PropTypes } from 'prop-types';
33
import { Handle, Position } from 'reactflow';
4-
import Operators from '../constants/operators';
4+
import AssertOperators from '../constants/assertOperators';
55
import FlowNode from 'components/atoms/flow/FlowNode';
66
import { getInputType } from 'utils/common';
77
import { CHOOSE_OPERATOR_DEFAULT_VALUE_OBJ } from 'constants/Common';
@@ -29,10 +29,10 @@ const operatorMenu = (id, data) => {
2929
<option value={CHOOSE_OPERATOR_DEFAULT_VALUE_OBJ.value}>
3030
{CHOOSE_OPERATOR_DEFAULT_VALUE_OBJ.displayValue}
3131
</option>
32-
<option value={Operators.isLessThan}>{Operators.isLessThan}</option>
33-
<option value={Operators.isGreaterThan}>{Operators.isGreaterThan}</option>
34-
<option value={Operators.isEqualTo}>{Operators.isEqualTo}</option>
35-
<option value={Operators.isNotEqualTo}>{Operators.isNotEqualTo}</option>
32+
<option value={AssertOperators.isLessThan}>{AssertOperators.isLessThan}</option>
33+
<option value={AssertOperators.isGreaterThan}>{AssertOperators.isGreaterThan}</option>
34+
<option value={AssertOperators.isEqualTo}>{AssertOperators.isEqualTo}</option>
35+
<option value={AssertOperators.isNotEqualTo}>{AssertOperators.isNotEqualTo}</option>
3636
</select>
3737
</div>
3838
);

0 commit comments

Comments
 (0)