Skip to content

Commit e883b25

Browse files
committed
wire in settings modal and allow various stages of publishing flow scans
1 parent 3718c36 commit e883b25

6 files changed

Lines changed: 194 additions & 206 deletions

File tree

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);

src/components/molecules/flow/index.js

Lines changed: 9 additions & 7 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') {
@@ -243,7 +243,7 @@ const Flow = ({ tab, collectionId }) => {
243243
>
244244
<Background variant='dots' gap={12} size={1} />
245245
<Controls
246-
className='flex border-cyan-900 shadow-none'
246+
className='flex shadow-none border-cyan-900'
247247
onFitView={() => setViewport(reactFlowInstance.getViewport())}
248248
></Controls>
249249
<Button
@@ -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/modals/SettingsModal.js

Lines changed: 136 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,49 @@
1-
import React, { Fragment, useState } from 'react';
2-
import { Dialog, Transition } from '@headlessui/react';
1+
import React, { Fragment, useState, useEffect } from 'react';
2+
import { Dialog, Transition, Tab } from '@headlessui/react';
33
import { useForm } from 'react-hook-form';
44
import { z } from 'zod';
55
import { zodResolver } from '@hookform/resolvers/zod';
6+
import { XCircleIcon } from '@heroicons/react/20/solid';
67
import Button from 'components/atoms/common/Button';
78
import { BUTTON_INTENT_TYPES, BUTTON_TYPES } from 'constants/Common';
9+
import { addLogSyncConfig } from 'service/settings';
10+
import useSettingsStore from 'stores/SettingsStore';
811

912
const schema = z.object({
10-
accessId: z.string().min(5),
11-
accessKey: z.string().min(5),
13+
enabled: z.boolean(),
14+
accessId: z.string(),
15+
accessKey: z.string(),
1216
});
13-
//
14-
// type FormFields = z.infer<typeof schema>;
1517

16-
const SettingsModal = ({ closeFn = () => null, open = false }) => {
18+
const SettingsModal = ({ closeFn = () => null, open = false, initialTab = 0 }) => {
1719
const [successFullSubmissionMessage, showSuccessFullSubmissionMessage] = useState(false);
20+
const config = useSettingsStore((state) => state.logSyncConfig);
21+
1822
const {
1923
register,
2024
handleSubmit,
25+
setValue,
2126
setError,
2227
formState: { errors, isSubmitting },
2328
} = useForm({
2429
defaultValues: {
30+
enabled: false,
2531
accessId: '',
32+
accessKey: '',
2633
},
2734
resolver: zodResolver(schema),
2835
});
2936

37+
useEffect(() => {
38+
setValue('enabled', config?.enabled || false);
39+
setValue('accessId', config?.accessId || '');
40+
setValue('accessKey', config?.accessKey || '');
41+
}, [config]);
42+
3043
const onFormSubmit = async (data) => {
31-
console.log(`\n \n onFormSubmit = ${data}\n \n`);
3244
try {
33-
console.log(data);
34-
// send the from data as a request
45+
await addLogSyncConfig(data.enabled, 'http://localhost:3000', data.accessId, data.accessKey);
46+
// send the form data as a request
3547
showSuccessFullSubmissionMessage(true);
3648
closeFn();
3749
} catch (error) {
@@ -63,7 +75,7 @@ const SettingsModal = ({ closeFn = () => null, open = false }) => {
6375
</Transition.Child>
6476

6577
<div className='fixed inset-0 overflow-y-auto'>
66-
<div className='flex min-h-full items-center justify-center p-4 text-center'>
78+
<div className='flex items-center justify-center min-h-full p-4 text-center'>
6779
<Transition.Child
6880
as={Fragment}
6981
enter='ease-out duration-300'
@@ -73,74 +85,122 @@ const SettingsModal = ({ closeFn = () => null, open = false }) => {
7385
leaveFrom='opacity-100 scale-100'
7486
leaveTo='opacity-0 scale-95'
7587
>
76-
<Dialog.Panel className='w-full max-w-5xl transform overflow-hidden rounded bg-white p-6 text-left align-middle shadow-xl transition-all'>
77-
<Dialog.Title as='h1' className='border-b border-gray-300 pb-4 text-center text-3xl font-semibold'>
78-
Settings
88+
<Dialog.Panel className='w-full max-w-5xl p-6 overflow-hidden text-left align-middle transition-all transform bg-white rounded shadow-xl'>
89+
<Dialog.Title as='div' className='flex items-center justify-between pb-4 border-b border-gray-300'>
90+
<h1 className='text-3xl font-semibold'>Settings</h1>
91+
<button onClick={closeFn} className='text-gray-400 hover:text-gray-600'>
92+
<XCircleIcon className='w-6 h-6' />
93+
</button>
7994
</Dialog.Title>
80-
<div className='p-4'>
81-
<form className='flex flex-col items-center gap-4'>
82-
<div className='bg-card min-h-[20vh] w-full rounded-lg border border-gray-300 p-4 shadow-sm'>
83-
<div className='py-2'>
84-
<h2 className='text-2xl font-semibold'>Access Id and Keys</h2>
85-
<p className='mt-2 text-lg'>
86-
To generate your access key pair for CLI Login:{' '}
87-
<a href='' target='_blank' rel='noreferrer' className='link'>
88-
Link
89-
</a>
90-
</p>
91-
</div>
92-
<div className='py-4'>
93-
<div className='py-2'>
94-
<input
95-
{...register('accessId')}
96-
type='text'
97-
placeholder='Access Id'
98-
className='mb-2 block w-full rounded border border-slate-700 bg-background-light p-2.5 text-sm text-slate-900 outline-none'
99-
/>
100-
{errors.accessId && <div className='text-red-500'>{errors.accessId.message}</div>}
95+
<Tab.Group defaultIndex={initialTab}>
96+
<Tab.List className='flex p-1 space-x-1 rounded-xl bg-blue-900/20'>
97+
<Tab
98+
className={({ selected }) =>
99+
`w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-blue-700
100+
${selected ? 'bg-white shadow' : 'text-blue-100 hover:bg-white/[0.12] hover:text-white'}`
101+
}
102+
>
103+
Scans
104+
</Tab>
105+
<Tab
106+
className={({ selected }) =>
107+
`w-full rounded-lg py-2.5 text-sm font-medium leading-5 text-blue-700
108+
${selected ? 'bg-white shadow' : 'text-blue-100 hover:bg-white/[0.12] hover:text-white'}`
109+
}
110+
>
111+
Theme
112+
</Tab>
113+
</Tab.List>
114+
<Tab.Panels className='mt-2'>
115+
<Tab.Panel className='p-4'>
116+
{/* Scans Content */}
117+
<form className='flex flex-col items-start gap-4' onSubmit={handleSubmit(onFormSubmit)}>
118+
<div className='bg-card min-h-[20vh] w-full rounded-lg border border-gray-300 p-4 shadow-sm'>
119+
<div className='py-2'>
120+
<p className='text-lg'>
121+
Scans aim to provide anayltics and observability for your flows. <br />
122+
<a
123+
href='https://flowtest-ai.vercel.app/'
124+
target='_blank'
125+
rel='noreferrer'
126+
className='text-blue-500 hover:underline'
127+
>
128+
Get Access Keys
129+
</a>
130+
</p>
131+
</div>
132+
<div className='py-2'>
133+
<label htmlFor='enabled' className='block text-lg font-medium text-gray-700'>
134+
Enabled
135+
</label>
136+
<input type='checkbox' {...register('enabled')} id='enabled' className='block' />
137+
{errors.enabled && <div className='text-red-500'>{errors.enabled.message}</div>}
138+
</div>
139+
<div className='py-2'>
140+
<label htmlFor='accessId' className='block text-lg font-medium text-gray-700'>
141+
Access Id
142+
</label>
143+
<input
144+
{...register('accessId')}
145+
type='text'
146+
placeholder='Access Id'
147+
className='mb-2 block w-full rounded border border-slate-700 bg-background-light p-2.5 text-sm text-slate-900 outline-none'
148+
/>
149+
{errors.accessId && <div className='text-red-500'>{errors.accessId.message}</div>}
150+
</div>
151+
<div className='py-2'>
152+
<label htmlFor='accessKey' className='block text-lg font-medium text-gray-700'>
153+
Access Key
154+
</label>
155+
<input
156+
{...register('accessKey')}
157+
type='text'
158+
placeholder='Access Key'
159+
className='mb-2 block w-full rounded border border-slate-700 bg-background-light p-2.5 text-sm text-slate-900 outline-none'
160+
/>
161+
{errors.accessKey && <div className='text-red-500'>{errors.accessKey.message}</div>}
162+
</div>
163+
<div>
164+
{errors.root && <div className='text-red-500'>{errors.root.message}</div>}{' '}
165+
{successFullSubmissionMessage && (
166+
<div className='text-green-500'> Successfully saved settings</div>
167+
)}
168+
</div>
101169
</div>
102-
<div className='py-2'>
103-
<input
104-
{...register('accessKey')}
105-
type='text'
106-
placeholder='Access Key'
107-
className='mb-2 block w-full rounded border border-slate-700 bg-background-light p-2.5 text-sm text-slate-900 outline-none'
108-
/>
109-
{errors.accessKey && <div className='text-red-500'>{errors.accessKey.message}</div>}
170+
<div className='flex justify-center w-full mt-6'>
171+
<Button btnType={BUTTON_TYPES.primary} isDisabled={isSubmitting} fullWidth={true}>
172+
{isSubmitting ? 'Loading...' : 'Save'}
173+
</Button>
110174
</div>
111-
</div>
112-
<div>
113-
{errors.root && <div className='text-red-500'>{errors.root.message}</div>}{' '}
114-
{successFullSubmissionMessage && (
115-
<div className='text-green-500'> Successfully submitted the form data</div>
116-
)}
117-
</div>
118-
</div>
119-
120-
<div className='mt-6 flex w-full items-center gap-2'>
121-
<Button
122-
btnType={BUTTON_TYPES.secondary}
123-
intentType={BUTTON_INTENT_TYPES.error}
124-
isDisabled={false}
125-
onClickHandle={(event) => {
126-
event.preventDefault();
127-
closeFn();
128-
}}
129-
fullWidth={true}
130-
>
131-
Cancel
132-
</Button>
133-
<Button
134-
btnType={BUTTON_TYPES.primary}
135-
isDisabled={isSubmitting}
136-
onClickHandle={handleSubmit(onFormSubmit)}
137-
fullWidth={true}
138-
>
139-
{isSubmitting ? 'Loading...' : 'Update'}
140-
</Button>
141-
</div>
142-
</form>
143-
</div>
175+
</form>
176+
</Tab.Panel>
177+
<Tab.Panel className='p-4'>
178+
{/* Theme Content */}
179+
<form className='flex flex-col items-start gap-4'>
180+
<div className='bg-card min-h-[20vh] w-full rounded-lg border border-gray-300 p-4 shadow-sm'>
181+
<div className='flex items-center'>
182+
<input type='radio' id='light' name='theme' value='light' defaultChecked />
183+
<label htmlFor='light' className='ml-2 text-lg'>
184+
Light
185+
</label>
186+
</div>
187+
<div className='flex items-center'>
188+
<input type='radio' id='dark' name='theme' value='dark' />
189+
<label htmlFor='dark' className='ml-2 text-lg'>
190+
Dark
191+
</label>
192+
</div>
193+
<div className='flex items-center'>
194+
<input type='radio' id='system' name='theme' value='system' />
195+
<label htmlFor='system' className='ml-2 text-lg'>
196+
System
197+
</label>
198+
</div>
199+
</div>
200+
</form>
201+
</Tab.Panel>
202+
</Tab.Panels>
203+
</Tab.Group>
144204
</Dialog.Panel>
145205
</Transition.Child>
146206
</div>

0 commit comments

Comments
 (0)