Skip to content

Commit b18d6e1

Browse files
committed
Introduce node that helps to set variables during graph run
1 parent 5ce39e4 commit b18d6e1

File tree

10 files changed

+376
-13
lines changed

10 files changed

+376
-13
lines changed

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: '+',
3+
Subtract: '-',
4+
};
5+
6+
export default EvaluateOperators;

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
}

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
);
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
import React from 'react';
2+
import { PropTypes } from 'prop-types';
3+
import FlowNode from 'components/atoms/flow/FlowNode';
4+
import { getInputType } from 'utils/common';
5+
import { variableTypes } from 'components/molecules/modals/flow/AddVariableModal';
6+
import useCanvasStore from 'stores/CanvasStore';
7+
import { CHOOSE_OPERATOR_DEFAULT_VALUE_OBJ } from 'constants/Common';
8+
import EvaluateOperators from '../constants/evaluateOperators';
9+
10+
const SetVarNode = ({ id, data }) => {
11+
const setVariableNodeName = useCanvasStore((state) => state.setVariableNodeName);
12+
const setVariableNodeType = useCanvasStore((state) => state.setVariableNodeType);
13+
14+
const variableNodeChangeVar = useCanvasStore((state) => state.variableNodeChangeVar);
15+
const setVariableNodeExpressionsVariable = useCanvasStore((state) => state.setVariableNodeExpressionsVariable);
16+
const setVariableNodeExpressionOperator = useCanvasStore((state) => state.setVariableNodeExpressionOperator);
17+
18+
const renderVariable = () => {
19+
return (
20+
<div className='flex items-center justify-between pb-2'>
21+
<div className='flex items-center justify-between text-sm border rounded-md border-neutral-500 text-neutral-500 outline-0 focus:ring-0'>
22+
{data.type === 'Boolean' ? (
23+
<select
24+
onChange={(e) => variableNodeChangeVar(id, e.target.value)}
25+
name='boolean-val'
26+
className='nodrag h-9 w-full rounded-br-md rounded-tr-md p-2.5 px-1 '
27+
value={data.value}
28+
>
29+
<option value='true'>True</option>
30+
<option value='false'>False</option>
31+
</select>
32+
) : data.type === 'Now' ? (
33+
<div></div>
34+
) : (
35+
<input
36+
type={getInputType(data.type)}
37+
className='nodrag nowheel block h-9 w-full rounded-bl-md rounded-tl-md p-2.5'
38+
name='variable-value'
39+
data-type={getInputType(data.type)}
40+
onChange={(e) => variableNodeChangeVar(id, e.target.value)}
41+
value={data.value}
42+
/>
43+
)}
44+
</div>
45+
</div>
46+
);
47+
};
48+
49+
const operatorMenu = (id, data) => {
50+
const handleOperatorSelection = (event) => {
51+
const selectedValue = event.target?.value;
52+
// ToDO: verify the behavior when use selects the default item
53+
if (selectedValue !== CHOOSE_OPERATOR_DEFAULT_VALUE_OBJ.value) {
54+
setVariableNodeExpressionOperator(id, selectedValue);
55+
}
56+
};
57+
58+
return (
59+
<div className='mb-4'>
60+
<select
61+
onChange={handleOperatorSelection}
62+
name='operator-type'
63+
value={data.value.operator ? data.value.operator : CHOOSE_OPERATOR_DEFAULT_VALUE_OBJ.value}
64+
className='w-full h-12 px-1 py-2 border rounded-md border-neutral-500 text-neutral-500 outline-0 focus:ring-0'
65+
>
66+
<option value={CHOOSE_OPERATOR_DEFAULT_VALUE_OBJ.value}>
67+
{CHOOSE_OPERATOR_DEFAULT_VALUE_OBJ.displayValue}
68+
</option>
69+
<option value={EvaluateOperators.Add}>{EvaluateOperators.Add}</option>
70+
<option value={EvaluateOperators.Subtract}>{EvaluateOperators.Subtract}</option>
71+
</select>
72+
</div>
73+
);
74+
};
75+
76+
const variableElem = (id, data, varName) => {
77+
const handleInputTypeSelection = (event) => {
78+
const selectedValue = event.target?.value;
79+
switch (selectedValue) {
80+
case 'String':
81+
setVariableNodeExpressionsVariable(id, varName, selectedValue, '');
82+
break;
83+
case 'Select':
84+
setVariableNodeExpressionsVariable(id, varName, selectedValue, '');
85+
break;
86+
case 'Variable':
87+
setVariableNodeExpressionsVariable(id, varName, selectedValue, '');
88+
break;
89+
case 'Number':
90+
setVariableNodeExpressionsVariable(id, varName, selectedValue, 0);
91+
break;
92+
case 'Boolean':
93+
setVariableNodeExpressionsVariable(id, varName, selectedValue, false);
94+
break;
95+
}
96+
};
97+
98+
return (
99+
<div className='flex items-center justify-center mb-4 text-sm border rounded-md border-neutral-500 text-neutral-500 outline-0 focus:ring-0'>
100+
{data.value.variables && data.value.variables[varName] ? (
101+
data.value.variables[varName].type === 'Boolean' ? (
102+
<select
103+
onChange={(event) => setVariableNodeExpressionsVariable(id, varName, 'Boolean', event.target?.value)}
104+
name='boolean-val'
105+
className='nodrag h-12 w-full rounded-br-md rounded-tr-md p-2.5 px-1 '
106+
value={data.value.variables[varName].value}
107+
>
108+
<option value='true'>True</option>
109+
<option value='false'>False</option>
110+
</select>
111+
) : (
112+
<input
113+
id='outlined-adornment-weight'
114+
type={getInputType(data.value.variables[varName].type)}
115+
className='nodrag nowheel block h-12 w-full rounded-bl-md rounded-tl-md p-2.5'
116+
name='variable-value'
117+
placeholder={varName}
118+
value={data.value.variables[varName].value}
119+
onChange={(event) => {
120+
const updatedValue = event.target.value;
121+
switch (data.value.variables[varName].type) {
122+
case 'String':
123+
// data.variables[varName].value = updatedValue.toString();
124+
// setVariableValue(updatedValue.toString());
125+
setVariableNodeExpressionsVariable(id, varName, 'String', updatedValue.toString());
126+
break;
127+
case 'Select':
128+
// data.variables[varName].value = updatedValue.toString();
129+
// setVariableValue(updatedValue.toString());
130+
setVariableNodeExpressionsVariable(id, varName, 'Select', updatedValue.toString());
131+
break;
132+
case 'Variable':
133+
// data.variables[varName].value = updatedValue.toString();
134+
// setVariableValue(updatedValue.toString());
135+
setVariableNodeExpressionsVariable(id, varName, 'Variable', updatedValue.toString());
136+
break;
137+
case 'Number':
138+
// data.variables[varName].value = parseInt(updatedValue);
139+
// setVariableValue(parseInt(updatedValue));
140+
setVariableNodeExpressionsVariable(id, varName, 'Number', parseInt(updatedValue));
141+
break;
142+
}
143+
}}
144+
/>
145+
)
146+
) : (
147+
<input
148+
id='outlined-adornment-weight'
149+
type='text'
150+
className='nodrag nowheel block h-12 w-full rounded-bl-md rounded-tl-md p-2.5'
151+
name='variable-value'
152+
placeholder={varName}
153+
value=''
154+
onChange={(event) => {
155+
// default type is string, as soon as we select another type, it goes to above flow
156+
const updatedValue = event.target.value;
157+
setVariableNodeExpressionsVariable(id, varName, 'String', updatedValue.toString());
158+
}}
159+
/>
160+
)}
161+
162+
<select
163+
onChange={handleInputTypeSelection}
164+
name='var-input-type'
165+
className='w-full h-8 p-0 px-1 border-l nodrag rounded-br-md rounded-tr-md border-l-neutral-500'
166+
value={data.value.variables && data.value.variables[varName] ? data.value.variables[varName].type : 'String'}
167+
>
168+
<option value='Select'>Select</option>
169+
<option value='String'>String</option>
170+
<option value='Variable'>Variable</option>
171+
<option value='Number'>Number</option>
172+
<option value='Boolean'>Boolean</option>
173+
</select>
174+
</div>
175+
);
176+
};
177+
178+
return (
179+
<FlowNode
180+
title={'Set Variable'}
181+
handleLeft={true}
182+
handleLeftData={{ type: 'target' }}
183+
handleRight={true}
184+
handleRightData={{ type: 'source' }}
185+
>
186+
<div>
187+
<div>
188+
<input
189+
type='text'
190+
placeholder={`Enter variable name`}
191+
className='nodrag nowheel mb-2 block w-full rounded-lg border border-gray-300 bg-gray-50 p-2.5 text-sm text-gray-900 outline-blue-300 focus:border-blue-100 focus:ring-blue-100'
192+
name='variable_name'
193+
onChange={(e) => setVariableNodeName(id, e.target.value)}
194+
value={data.name ? data.name : ''}
195+
/>
196+
<select
197+
onChange={(e) => setVariableNodeType(id, e.target.value)}
198+
name='var-input-type'
199+
className='w-full h-8 p-0 px-1 border-l nodrag rounded-br-md rounded-tr-md border-l-neutral-500'
200+
value={data.type ? data.type : ''}
201+
>
202+
<option value=''>None</option>
203+
{variableTypes.map((option) => (
204+
<option key={option.value} value={option.value}>
205+
{option.label}
206+
</option>
207+
))}
208+
<option value='Expression'>Expression</option>
209+
</select>
210+
</div>
211+
{data.type != '' ? (
212+
data.type === 'Expression' ? (
213+
<div>
214+
<div>{variableElem(id, data, 'var1')}</div>
215+
<div>{operatorMenu(id, data)}</div>
216+
<div>{variableElem(id, data, 'var2')}</div>
217+
</div>
218+
) : (
219+
<div>
220+
<div>{renderVariable()}</div>
221+
</div>
222+
)
223+
) : (
224+
<div></div>
225+
)}
226+
</div>
227+
</FlowNode>
228+
);
229+
};
230+
231+
SetVarNode.propTypes = {
232+
data: PropTypes.object.isRequired,
233+
};
234+
235+
export default SetVarNode;

src/components/molecules/flow/utils.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ export const initFlowData = {
9595
{
9696
id: '1',
9797
type: 'authNode',
98+
description: 'Define authentication for the requests',
9899
data: {},
99100
position: {
100101
x: 400,

src/components/molecules/modals/flow/AddVariableModal.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { PropTypes } from 'prop-types';
33
import { Dialog, Transition } from '@headlessui/react';
44
import 'tippy.js/dist/tippy.css';
55

6-
const variableTypes = [
6+
export const variableTypes = [
77
{
88
value: 'String',
99
label: 'String',

0 commit comments

Comments
 (0)