From ddd479ed4509ff2fa271a2bb2e0561be822b7fb6 Mon Sep 17 00:00:00 2001 From: Ross Gargett <73141350+Ross-Gargett@users.noreply.github.com> Date: Sun, 15 Oct 2023 19:38:47 -0700 Subject: [PATCH 1/2] fix: prevent non-numerical or negative timeouts --- .../bruno-app/src/components/Preferences/General/index.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/bruno-app/src/components/Preferences/General/index.js b/packages/bruno-app/src/components/Preferences/General/index.js index 2dbcfab76..917b5765d 100644 --- a/packages/bruno-app/src/components/Preferences/General/index.js +++ b/packages/bruno-app/src/components/Preferences/General/index.js @@ -25,8 +25,9 @@ const General = ({ close }) => { }; const handleTimeoutChange = (value) => { - const validTimeout = isNaN(Number(value)) ? timeout : Number(value); - setTimeout(validTimeout); + if (/^[0-9]\d*$/.test(value) || value === '') { + setTimeout(value); + } }; return ( @@ -47,13 +48,14 @@ const General = ({ close }) => { handleTimeoutChange(e.target.value)} defaultValue={timeout === 0 ? '' : timeout} + value={timeout} /> From 67218f5bb496ce7b5713e053d08d5cb8eb56763d Mon Sep 17 00:00:00 2001 From: Ross Gargett <73141350+Ross-Gargett@users.noreply.github.com> Date: Mon, 16 Oct 2023 21:08:22 -0700 Subject: [PATCH 2/2] feedback: use formik and Yup for preferences form --- .../components/Preferences/General/index.js | 121 +++++++++++------- .../src/providers/ReduxStore/slices/app.js | 3 +- 2 files changed, 76 insertions(+), 48 deletions(-) diff --git a/packages/bruno-app/src/components/Preferences/General/index.js b/packages/bruno-app/src/components/Preferences/General/index.js index 917b5765d..b67932eb6 100644 --- a/packages/bruno-app/src/components/Preferences/General/index.js +++ b/packages/bruno-app/src/components/Preferences/General/index.js @@ -1,69 +1,96 @@ -import React, { useState } from 'react'; +import React from 'react'; +import { useFormik } from 'formik'; import { useSelector, useDispatch } from 'react-redux'; import { savePreferences } from 'providers/ReduxStore/slices/app'; import StyledWrapper from './StyledWrapper'; +import * as Yup from 'yup'; +import toast from 'react-hot-toast'; const General = ({ close }) => { const preferences = useSelector((state) => state.app.preferences); const dispatch = useDispatch(); - const [sslVerification, setSslVerification] = useState(preferences.request.sslVerification); - const [timeout, setTimeout] = useState(preferences.request.timeout); + const preferencesSchema = Yup.object().shape({ + sslVerification: Yup.boolean(), + timeout: Yup.number('Request Timeout must be a number') + .positive('Request Timeout must be a positive number') + .typeError('Request Timeout must be a number') + .optional() + }); - const handleSave = () => { + const formik = useFormik({ + initialValues: { + sslVerification: preferences.request.sslVerification, + timeout: preferences.request.timeout + }, + validationSchema: preferencesSchema, + onSubmit: async (values) => { + try { + const newPreferences = await proxySchema.validate(values, { abortEarly: true }); + handleSave(newPreferences); + } catch (error) { + console.error('Preferences validation error:', error.message); + } + } + }); + + const handleSave = (newPreferences) => { dispatch( savePreferences({ ...preferences, request: { - sslVerification, - timeout + sslVerification: newPreferences.sslVerification, + timeout: newPreferences.timeout } }) - ).then(() => { - close(); - }); - }; - - const handleTimeoutChange = (value) => { - if (/^[0-9]\d*$/.test(value) || value === '') { - setTimeout(value); - } + ) + .then(() => { + close(); + }) + .catch((err) => console.log(err) && toast.error('Failed to update preferences')); }; return ( -
- - setSslVerification(!sslVerification)} - className="mousetrap mr-0" - /> -
-
- - handleTimeoutChange(e.target.value)} - defaultValue={timeout === 0 ? '' : timeout} - value={timeout} - /> -
- -
- -
+
+
+ + +
+
+ + +
+ {formik.touched.timeout && formik.errors.timeout ? ( +
{formik.errors.timeout}
+ ) : null} +
+ +
+
); }; diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/app.js b/packages/bruno-app/src/providers/ReduxStore/slices/app.js index c3a3aa5a8..6f5c849f9 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/app.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/app.js @@ -9,7 +9,8 @@ const initialState = { showHomePage: false, preferences: { request: { - sslVerification: true + sslVerification: true, + timeout: 0 }, font: { codeFont: 'default'