Skip to content

Commit a61e7c5

Browse files
committed
Merge branch 'new-ui' into distributable-pacakge
2 parents b7d3abf + 69d8c6f commit a61e7c5

38 files changed

+1334
-592
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"react-router": "^6.15.0",
3030
"react-router-dom": "^6.22.2",
3131
"react-scripts": "5.0.1",
32+
"react-toastify": "^10.0.5",
3233
"react-tooltip": "^5.26.2",
3334
"reactflow": "^11.8.3",
3435
"socket.io-client": "^4.7.4",

packages/flowtest-electron/src/ipc/collection.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,11 @@ const registerRendererEventHandlers = (mainWindow, watcher) => {
185185

186186
ipcMain.handle('renderer:update-environment', async (event, collectionPath, name, variables) => {
187187
try {
188+
const env = Object.entries(variables)
189+
.map(([key, value]) => `${key}: "${value}"`)
190+
.join('\n');
188191
const envDir = path.join(collectionPath, 'environments');
189-
updateFile(path.join(envDir, name), variables);
192+
updateFile(path.join(envDir, name), env);
190193
} catch (error) {
191194
return Promise.reject(error);
192195
}

src/components/atoms/SelectEnvironment.js

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,39 +16,45 @@ const SelectEnvironment = ({ environments }) => {
1616
return (
1717
<Listbox value={selected} onChange={setSelected}>
1818
<div className='relative flex h-full pl-4 border-l border-neutral-300'>
19-
<Listbox.Button className='flex items-center justify-between gap-4 cursor-default sm:text-sm'>
19+
<Listbox.Button
20+
className={`flex items-center justify-between gap-4 sm:text-sm ${environments.length ? 'cursor-default' : 'cursor-not-allowed'}`}
21+
>
2022
<Square3Stack3DIcon className='w-4 h-4' />
2123
<div className='min-w-32'>{selected ? selected : 'Select environment'}</div>
2224
<ChevronUpDownIcon className='w-5 h-5' aria-hidden='true' />
2325
</Listbox.Button>
24-
<Transition as={Fragment} leave='transition ease-in duration-100' leaveFrom='opacity-100' leaveTo='opacity-0'>
25-
<Listbox.Options className='absolute right-0 z-10 w-full py-1 mt-1 overflow-auto text-base bg-white rounded shadow-lg top-12 max-h-60 ring-1 ring-black/5 sm:text-sm'>
26-
{environments.map((environment, environmentIndex) => (
27-
<Listbox.Option
28-
key={environmentIndex}
29-
className={({ active }) =>
30-
`relative cursor-default select-none py-2 pl-10 pr-4 ${
31-
active ? 'bg-amber-100 text-amber-900' : 'text-gray-900'
32-
}`
33-
}
34-
value={environment.name}
35-
>
36-
{({ selected }) => (
37-
<>
38-
<span className={`block truncate ${selected ? 'font-medium' : 'font-normal'}`}>
39-
{environment.name}
40-
</span>
41-
{selected ? (
42-
<span className='absolute inset-y-0 left-0 flex items-center pl-3 text-amber-600'>
43-
<CheckIcon className='w-5 h-5' aria-hidden='true' />
26+
{environments.length ? (
27+
<Transition as={Fragment} leave='transition ease-in duration-100' leaveFrom='opacity-100' leaveTo='opacity-0'>
28+
<Listbox.Options className='absolute right-0 z-10 w-full py-1 mt-1 overflow-auto text-base bg-white rounded shadow-lg top-12 max-h-60 ring-1 ring-black/5 sm:text-sm'>
29+
{environments.map((environment, environmentIndex) => (
30+
<Listbox.Option
31+
key={environmentIndex}
32+
className={({ active }) =>
33+
`relative cursor-default select-none py-2 pl-10 pr-4 ${
34+
active ? 'bg-amber-100 text-amber-900' : 'text-gray-900'
35+
}`
36+
}
37+
value={environment.name}
38+
>
39+
{({ selected }) => (
40+
<>
41+
<span className={`block truncate ${selected ? 'font-medium' : 'font-normal'}`}>
42+
{environment.name}
4443
</span>
45-
) : null}
46-
</>
47-
)}
48-
</Listbox.Option>
49-
))}
50-
</Listbox.Options>
51-
</Transition>
44+
{selected ? (
45+
<span className='absolute inset-y-0 left-0 flex items-center pl-3 text-amber-600'>
46+
<CheckIcon className='w-5 h-5' aria-hidden='true' />
47+
</span>
48+
) : null}
49+
</>
50+
)}
51+
</Listbox.Option>
52+
))}
53+
</Listbox.Options>
54+
</Transition>
55+
) : (
56+
''
57+
)}
5258
</div>
5359
</Listbox>
5460
);

src/components/atoms/Tabs.js

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import React, { useState } from 'react';
22
import { XMarkIcon } from '@heroicons/react/24/outline';
33
import { useTabStore } from 'stores/TabStore';
44
import ConfirmActionModal from 'components/molecules/modals/ConfirmActionModal';
5+
import { isEqual } from 'lodash';
6+
import { OBJ_TYPES } from 'constants/Common';
57

68
const Tabs = () => {
79
const tabs = useTabStore((state) => state.tabs);
@@ -12,32 +14,41 @@ const Tabs = () => {
1214
const closeTab = useTabStore((state) => state.closeTab);
1315
const [closingTabId, setClosingTabId] = useState('');
1416
const [closingCollectionId, setClosingCollectionId] = useState('');
17+
1518
const activeTabStyles =
1619
'before:absolute before:h-[0.25rem] before:w-full before:bg-slate-300 before:content-[""] before:bottom-0 before:left-0';
1720
const tabCommonStyles =
18-
'tab flex items-center gap-x-2 border-r border-neutral-300 bg-transparent pr-0 tracking-[0.15em] transition duration-500 ease-in text-sm';
19-
const messageForConfirmActionModal = 'You have unsaved changes in the flowtest, are you sure you want to close it?';
20-
const handleCloseTab = (event) => {
21+
'tab flex items-center gap-x-2 border-r border-neutral-300 bg-transparent pr-0 tracking-[0.15em] transition duration-500 ease-in text-sm flex-nowrap';
22+
const messageForConfirmActionModal = `You have unsaved changes in the ${focusTab?.type}, are you sure you want to close it?`;
23+
24+
const handleCloseTab = (event, tab) => {
2125
event.stopPropagation();
2226
event.preventDefault();
23-
const tabId = event.currentTarget.dataset.tabId;
24-
const { isDirty, collectionId } = tabs.find((tab) => {
25-
if (tab.id === tabId) return tab;
26-
});
27-
setClosingTabId(tabId);
28-
setClosingCollectionId(collectionId);
2927

30-
if (isDirty) {
31-
console.debug(`Confirm close for tabId: ${tabId} : collectionId: ${collectionId}`);
32-
setConfirmActionModalOpen(true);
33-
return;
28+
setClosingTabId(tab.id);
29+
setClosingCollectionId(tab.collectionId);
30+
31+
if (tab.type === OBJ_TYPES.flowtest) {
32+
if (tab.flowDataDraft && !isEqual(tab.flowData, tab.flowDataDraft)) {
33+
console.debug(`Confirm close for tabId: ${tab.id} : collectionId: ${tab.collectionId}`);
34+
setConfirmActionModalOpen(true);
35+
return;
36+
}
37+
} else if (tab.type === OBJ_TYPES.environment) {
38+
if (tab.variablesDraft && !isEqual(tab.variables, tab.variablesDraft)) {
39+
console.debug(`Confirm close for tabId: ${tab.id} : collectionId: ${tab.collectionId}`);
40+
setConfirmActionModalOpen(true);
41+
return;
42+
}
3443
}
35-
closeTab(tabId, collectionId);
44+
closeTab(tab.id, tab.collectionId);
3645
};
46+
3747
return (
38-
<div role='tablist' className='tabs tabs-lg'>
48+
<div role='tablist' className='overflow-scroll tabs tabs-lg'>
3949
{tabs
4050
// tabs belonging to one collection will be shown at a time
51+
//.reverse()
4152
.filter((t) => t.collectionId === focusTab.collectionId)
4253
.map((tab, index) => {
4354
return (
@@ -52,12 +63,12 @@ const Tabs = () => {
5263
data-id={tab.id}
5364
data-collection-id={tab.collectionId}
5465
>
55-
<a>{tab.name}</a>
66+
<a className='text-nowrap'>{tab.name}</a>
5667
{/* close needs to be a separate clickable component other wise it gets confused with above */}
5768
<div
5869
className='flex items-center h-full px-2 hover:rounded hover:rounded-l-none hover:bg-slate-200'
5970
data-tab-id={tab.id}
60-
onClick={handleCloseTab}
71+
onClick={(e) => handleCloseTab(e, tab)}
6172
>
6273
<XMarkIcon className='w-4 h-4' />
6374
</div>

src/components/atoms/sidebar/collections/OptionsMenu.js

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { Fragment } from 'react';
22
import { PropTypes } from 'prop-types';
33
import { Menu, Transition } from '@headlessui/react';
4-
import { FolderPlusIcon, PencilSquareIcon, TrashIcon } from '@heroicons/react/24/outline';
4+
import { FolderPlusIcon, PencilSquareIcon, TrashIcon, XMarkIcon } from '@heroicons/react/24/outline';
55
import { EllipsisVerticalIcon } from '@heroicons/react/20/solid';
66
import { DirectoryOptionsActions } from 'constants/WorkspaceDirectory';
77
import { OBJ_TYPES } from 'constants/Common';
@@ -84,15 +84,27 @@ const OptionsMenu = ({ collectionId, directory, itemType }) => {
8484
data-item-type={itemType}
8585
data-collection-id={collectionId}
8686
>
87-
<TrashIcon
88-
className='w-4 h-4 mr-2'
89-
aria-hidden='true'
90-
data-click-from='options-menu'
91-
data-item-type={itemType}
92-
/>
93-
{itemType === OBJ_TYPES.collection
94-
? DirectoryOptionsActions.remove.displayValue
95-
: DirectoryOptionsActions.delete.displayValue}
87+
{itemType === OBJ_TYPES.collection ? (
88+
<>
89+
<XMarkIcon
90+
className='w-4 h-4 mr-2'
91+
aria-hidden='true'
92+
data-click-from='options-menu'
93+
data-item-type={itemType}
94+
/>
95+
{DirectoryOptionsActions.remove.displayValue}
96+
</>
97+
) : (
98+
<>
99+
<TrashIcon
100+
className='w-4 h-4 mr-2'
101+
aria-hidden='true'
102+
data-click-from='options-menu'
103+
data-item-type={itemType}
104+
/>
105+
{DirectoryOptionsActions.delete.displayValue}
106+
</>
107+
)}
96108
</button>
97109
</Menu.Item>
98110
</div>
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import React, { useState } from 'react';
2+
import useEnvStore from 'stores/EnvStore';
3+
import 'react-edit-text/dist/index.css';
4+
import { TrashIcon } from '@heroicons/react/24/outline';
5+
import AddEnvVariableModal from '../modals/AddEnvVariableModal';
6+
import ConfirmActionModal from '../modals/ConfirmActionModal';
7+
8+
const Env = () => {
9+
const variables = useEnvStore((state) => state.variables);
10+
const handleAddVariable = useEnvStore((state) => state.handleAddVariable);
11+
const handleDeleteVariable = useEnvStore((state) => state.handleDeleteVariable);
12+
13+
const [addVariableModalOpen, setAddVariableModalOpen] = useState(false);
14+
const [confirmActionModalOpen, setConfirmActionModalOpen] = useState(false);
15+
16+
const [deleteKey, setDeleteKey] = useState('');
17+
18+
return (
19+
<div className='p-4'>
20+
{/* <div>Test Tab panel for environment</div> */}
21+
<div className='overflow-x-auto'>
22+
<table className='table table-zebra'>
23+
{/* head */}
24+
<thead>
25+
<tr>
26+
<th></th>
27+
<th>Key</th>
28+
<th>Value</th>
29+
{/* <th>New Value</th> */}
30+
</tr>
31+
</thead>
32+
<tbody>
33+
{Object.entries(variables).map(([key, value], index) => (
34+
<tr key={index}>
35+
<th>{index}</th>
36+
<td>{key}</td>
37+
<td>{value}</td>
38+
<td>
39+
<div
40+
className='relative inline-block p-2 text-left transition duration-200 ease-out rounded rounded-l-none hover:bg-slate-200'
41+
onClick={() => {
42+
setDeleteKey(key);
43+
setConfirmActionModalOpen(true);
44+
}}
45+
>
46+
<TrashIcon className='w-4 h-4' aria-hidden='true' />
47+
</div>
48+
</td>
49+
</tr>
50+
))}
51+
</tbody>
52+
</table>
53+
<button onClick={() => setAddVariableModalOpen(true)}>+ Add Variable</button>
54+
</div>
55+
<AddEnvVariableModal
56+
closeFn={() => setAddVariableModalOpen(false)}
57+
open={addVariableModalOpen}
58+
handleAddVariable={(key, value) => handleAddVariable(key, value)}
59+
/>
60+
<ConfirmActionModal
61+
closeFn={() => setConfirmActionModalOpen(false)}
62+
open={confirmActionModalOpen}
63+
message='Do you want to delete this variable?'
64+
actionFn={() => {
65+
handleDeleteVariable(deleteKey);
66+
setConfirmActionModalOpen(false);
67+
}}
68+
/>
69+
</div>
70+
);
71+
};
72+
73+
export default Env;

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// assumption is that apis are giving json as output
22

3+
import useCanvasStore from 'stores/CanvasStore';
34
import useCollectionStore from 'stores/CollectionStore';
45
import { useTabStore } from 'stores/TabStore';
56
import { computeAuthNode } from './compute/authnode';
@@ -69,7 +70,7 @@ class Graph {
6970

7071
if (node.type === 'outputNode') {
7172
this.logs.push(`Output: ${JSON.stringify(prevNodeOutputData)}`);
72-
node.data.setOutput(prevNodeOutputData);
73+
useCanvasStore.getState().setOutputNode(node.id, prevNodeOutputData);
7374
result = ['Success', node, prevNodeOutput];
7475
}
7576

@@ -94,7 +95,7 @@ class Graph {
9495
}
9596

9697
if (node.type === 'authNode') {
97-
this.auth = computeAuthNode(node.data.auth, this.env);
98+
this.auth = node.data.type ? computeAuthNode(node.data, this.env) : undefined;
9899
result = ['Success', node, prevNodeOutput];
99100
}
100101

@@ -134,7 +135,7 @@ class Graph {
134135
// reset every output node for a fresh run
135136
this.nodes.forEach((node) => {
136137
if (node.type === 'outputNode') {
137-
node.data.setOutput(undefined);
138+
useCanvasStore.getState().unSetOutputNode(node.id);
138139
}
139140
});
140141
this.graphRunNodeOutput = {};

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ const formulateRequest = (node, finalUrl, variablesDict, auth, logs) => {
3838
data: requestData,
3939
};
4040

41-
if (auth.type === 'basic-auth') {
41+
if (auth && auth.type === 'basic-auth') {
4242
options.auth = {};
4343
options.auth.username = auth.username;
4444
options.auth.password = auth.password;

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,12 @@ const computeNodeVariable = (variable, prevNodeOutputData) => {
4646
};
4747

4848
export const computeNodeVariables = (variables, prevNodeOutputData) => {
49-
let evalVariables = {};
50-
Object.entries(variables).map(([vname, variable]) => {
51-
evalVariables[vname] = computeNodeVariable(variable, prevNodeOutputData);
52-
});
49+
const evalVariables = {};
50+
if (variables) {
51+
Object.entries(variables).map(([vname, variable]) => {
52+
evalVariables[vname] = computeNodeVariable(variable, prevNodeOutputData);
53+
});
54+
}
5355
return evalVariables;
5456
};
5557

0 commit comments

Comments
 (0)