Skip to content

Commit 08398ef

Browse files
authored
Merge pull request #123 from FlowTestAI/ui-improvements
feat: Adding new settings modal, beautify logs side sheet and ability to upload flow scans
2 parents d44dc17 + e968f1e commit 08398ef

21 files changed

Lines changed: 587 additions & 180 deletions

File tree

.changeset/honest-pandas-appear.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'flowtestai': minor
3+
---
4+
5+
beautify logs sidesheet and ability to upload flow scans

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
"@emotion/styled": "^11.11.0",
4646
"@headlessui/react": "^1.7.18",
4747
"@heroicons/react": "^2.1.1",
48+
"@hookform/resolvers": "^3.7.0",
4849
"@testing-library/jest-dom": "^5.17.0",
4950
"@testing-library/react": "^13.4.0",
5051
"@testing-library/user-event": "^13.5.0",
@@ -53,6 +54,7 @@
5354
"autoprefixer": "^10.4.18",
5455
"axios": "^1.5.1",
5556
"codemirror": "^6.0.1",
57+
"date-fns": "^3.6.0",
5658
"eslint-import-resolver-alias": "^1.1.2",
5759
"eslint-plugin-import": "^2.29.1",
5860
"immer": "^10.0.4",
@@ -65,6 +67,7 @@
6567
"react-custom-scrollbars": "^4.2.1",
6668
"react-dom": "^18.2.0",
6769
"react-edit-text": "^5.1.1",
70+
"react-hook-form": "^7.52.0",
6871
"react-icons": "^5.0.1",
6972
"react-json-view-lite": "^1.4.0",
7073
"react-perfect-scrollbar": "^1.5.8",
@@ -79,10 +82,12 @@
7982
"tailwindcss": "^3.4.1",
8083
"typescript": "4",
8184
"web-vitals": "^2.1.4",
85+
"zod": "^3.23.8",
8286
"zustand": "^4.5.2"
8387
},
8488
"devDependencies": {
8589
"@changesets/cli": "^2.27.1",
90+
"@tailwindcss/forms": "^0.5.7",
8691
"@tailwindcss/typography": "^0.5.10",
8792
"@types/node": "20.11.5",
8893
"daisyui": "^4.7.2",

packages/flowtest-cli/graph/compute/requestnode.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ class requestNode extends Node {
4848

4949
const res = await this.runHttpRequest(options);
5050

51+
if (this.nodeData.requestBody.type === 'form-data') {
52+
// we don't want to send full file value
53+
options.data.value = '<BASE64_ENCODED_FILE_DATA>';
54+
}
55+
5156
if (res.error) {
5257
console.log(chalk.red(` ✕ `) + chalk.dim(`Request failed: ${JSON.stringify(res.error)}`));
5358
this.logger.add(LogLevel.ERROR, 'HTTP request failed', {

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -340,23 +340,24 @@ const registerRendererEventHandlers = (mainWindow, watcher) => {
340340
}
341341
});
342342

343-
ipcMain.handle('renderer:upload-logs', async (event, name, config, logs) => {
343+
ipcMain.handle('renderer:upload-logs', async (event, name, config, status, time, logs) => {
344344
function bytesToBase64(bytes) {
345345
const binString = Array.from(bytes, (byte) => String.fromCodePoint(byte)).join('');
346346
return btoa(binString);
347347
}
348348

349349
try {
350350
const data = {
351-
version: 1,
352-
name,
353-
scan: logs,
351+
scan_metadata: {
352+
version: 1,
353+
name,
354+
status,
355+
time,
356+
},
357+
scan: bytesToBase64(new TextEncoder().encode(JSON.stringify(logs))),
354358
};
355359
try {
356-
const response = await axiosClient(config.hostUrl, config.accessId, config.accessKey).post(
357-
'/upload',
358-
bytesToBase64(new TextEncoder().encode(JSON.stringify(data))),
359-
);
360+
const response = await axiosClient(config.hostUrl, config.accessId, config.accessKey).post('/upload', data);
360361
return {
361362
upload: 'success',
362363
url: `${config.hostUrl}/scan/${response.data.data[0].id}`,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const registerSettingsEventHandlers = (mainWindow) => {
1212

1313
ipcMain.handle('renderer:add-logsyncconfig', async (event, config) => {
1414
try {
15-
settingsStore.addLogSyncConfig(...config);
15+
settingsStore.addLogSyncConfig(config.enabled, config.hostUrl, config.accessId, config.accessKey);
1616
const savedSettings = settingsStore.getAll();
1717

1818
mainWindow.webContents.send('main:saved-settings', savedSettings);

pnpm-lock.yaml

Lines changed: 59 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ class requestNode extends Node {
3232

3333
const res = await this.runHttpRequest(options);
3434

35+
if (this.nodeData.requestBody.type === 'form-data') {
36+
options.data.value = '<BASE64_ENCODED_FILE_DATA>';
37+
}
38+
3539
if (res.error) {
3640
this.logger.add(LogLevel.ERROR, 'HTTP request failed', {
3741
type: 'requestNode',

src/components/molecules/flow/index.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,8 @@ const Flow = ({ tab, collectionId }) => {
194194
return true;
195195
};
196196

197-
const onGraphComplete = async (status, logs) => {
198-
const response = await uploadGraphRunLogs(tab.name, logs);
197+
const onGraphComplete = async (status, time, logs) => {
198+
const response = await uploadGraphRunLogs(tab.name, status, time, logs);
199199
console.log(response);
200200
setLogs(tab.id, logs, response);
201201
if (status == 'Success') {
@@ -275,11 +275,13 @@ const Flow = ({ tab, collectionId }) => {
275275
'main',
276276
);
277277
const result = await g.run();
278-
logger.add(LogLevel.INFO, `Total time: ${Date.now() - startTime} ms`);
279-
await onGraphComplete(result.status, logger.get());
278+
const time = Date.now() - startTime;
279+
logger.add(LogLevel.INFO, `Total time: ${time} ms`);
280+
await onGraphComplete(result.status, time, logger.get());
280281
} catch (error) {
281-
logger.add(LogLevel.INFO, `Total time: ${Date.now() - startTime} ms`);
282-
await onGraphComplete('Failed', logger.get());
282+
const time = Date.now() - startTime;
283+
logger.add(LogLevel.INFO, `Total time: ${time} ms`);
284+
await onGraphComplete('Failed', time, logger.get());
283285
toast.error(`Internal error running graph`);
284286
runnableEdges(false);
285287
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ const AuthNode = ({ id, data }) => {
6262
leaveFrom='opacity-100'
6363
leaveTo='opacity-0'
6464
>
65-
<Listbox.Options className='absolute w-full py-1 mt-1 overflow-auto text-base bg-white max-h-60 focus:outline-none'>
65+
<Listbox.Options className='absolute z-10 w-full py-1 mt-1 overflow-auto text-base bg-white max-h-60 focus:outline-none'>
6666
<Listbox.Option
6767
className={({ active }) =>
6868
`relative cursor-default select-none py-2 pl-10 pr-4 hover:font-semibold ${
@@ -118,7 +118,7 @@ const AuthNode = ({ id, data }) => {
118118
<TextEditor
119119
placeHolder={`Password`}
120120
onChangeHandler={(value) => handleChange(value, 'password')}
121-
name={'username'}
121+
name={'password'}
122122
value={data.password ? data.password : ''}
123123
completionOptions={getActiveVariables()}
124124
styles={'w-full'}

src/components/molecules/footers/MainFooter.js

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,45 @@
1-
import React from 'react';
2-
import { ArrowLeftEndOnRectangleIcon, ArrowRightStartOnRectangleIcon } from '@heroicons/react/24/outline';
1+
import React, { useState } from 'react';
2+
import {
3+
ArrowLeftEndOnRectangleIcon,
4+
ArrowRightStartOnRectangleIcon,
5+
Cog8ToothIcon,
6+
} from '@heroicons/react/24/outline';
7+
38
import Tippy from '@tippyjs/react';
49
import useNavigationStore from 'stores/AppNavBarStore';
510
import useCollectionStore from 'stores/CollectionStore';
11+
import SettingsModal from '../modals/SettingsModal';
612

713
const MainFooter = () => {
814
const collections = useCollectionStore((state) => state.collections);
915
const isNavBarCollapsed = useNavigationStore((state) => state.collapseNavBar);
1016
const updateNavCollapseState = useNavigationStore((state) => state.setNavCollapseState);
17+
const [openSettingsModal, setOpenSettingsModal] = useState(false);
1118
return (
1219
<footer className='flex items-center justify-between px-4 py-3 text-xs'>
13-
<label className='swap swap-rotate cursor-pointer py-1'>
14-
<input
15-
type='checkbox'
16-
onClick={(event) => {
17-
if (collections.length) {
18-
// since default is false for isNavBarCollapsed
19-
updateNavCollapseState(!isNavBarCollapsed);
20-
} else {
21-
event.preventDefault();
22-
event.stopPropagation();
23-
}
24-
}}
25-
/>
26-
<ArrowRightStartOnRectangleIcon className='swap-on h-6 w-6' />
27-
<ArrowLeftEndOnRectangleIcon className='swap-off h-6 w-6' />
28-
</label>
20+
<div className='flex items-center justify-between gap-2'>
21+
<button onClick={() => setOpenSettingsModal(true)}>
22+
<Cog8ToothIcon className='w-6 h-6' />
23+
</button>
24+
<label className='py-1 cursor-pointer swap swap-rotate'>
25+
<input
26+
// Overriding styles as Daisy UI input and React Hook form's input were conflicting
27+
className='!focus:outline-none !focus:ring-0 !appearance-none !border-0 !bg-transparent !bg-none !outline-none'
28+
type='checkbox'
29+
onClick={(event) => {
30+
if (collections.length) {
31+
// since default is false for isNavBarCollapsed
32+
updateNavCollapseState(!isNavBarCollapsed);
33+
} else {
34+
event.preventDefault();
35+
event.stopPropagation();
36+
}
37+
}}
38+
/>
39+
<ArrowRightStartOnRectangleIcon className='w-6 h-6 swap-on' />
40+
<ArrowLeftEndOnRectangleIcon className='w-6 h-6 swap-off' />
41+
</label>
42+
</div>
2943
<div className='flex items-center justify-between gap-4 font-semibold'>
3044
<Tippy content='External Link' placement='top'>
3145
<a href='https://github.com/FlowTestAI/FlowTest' target='_blank' rel='noreferrer' className='link'>
@@ -62,6 +76,7 @@ const MainFooter = () => {
6276
</a>
6377
</Tippy>
6478
</div>
79+
<SettingsModal closeFn={() => setOpenSettingsModal(false)} open={openSettingsModal} />
6580
</footer>
6681
);
6782
};

0 commit comments

Comments
 (0)