diff --git a/packages/bruno-app/src/components/CodeEditor/StyledWrapper.js b/packages/bruno-app/src/components/CodeEditor/StyledWrapper.js index 09de00ddc..fe0f4cc19 100644 --- a/packages/bruno-app/src/components/CodeEditor/StyledWrapper.js +++ b/packages/bruno-app/src/components/CodeEditor/StyledWrapper.js @@ -4,6 +4,7 @@ const StyledWrapper = styled.div` div.CodeMirror { background: ${(props) => props.theme.codemirror.bg}; border: solid 1px ${(props) => props.theme.codemirror.border}; + font-family: ${(props) => (props.font ? props.font : 'default')}; } .CodeMirror-overlayscroll-horizontal div, diff --git a/packages/bruno-app/src/components/CodeEditor/index.js b/packages/bruno-app/src/components/CodeEditor/index.js index 96d5bb48a..6ad999e6b 100644 --- a/packages/bruno-app/src/components/CodeEditor/index.js +++ b/packages/bruno-app/src/components/CodeEditor/index.js @@ -121,6 +121,7 @@ export default class CodeEditor extends React.Component { { this._node = node; }} diff --git a/packages/bruno-app/src/components/Preferences/Font/StyledWrapper.js b/packages/bruno-app/src/components/Preferences/Font/StyledWrapper.js new file mode 100644 index 000000000..d45eda5b6 --- /dev/null +++ b/packages/bruno-app/src/components/Preferences/Font/StyledWrapper.js @@ -0,0 +1,7 @@ +import styled from 'styled-components'; + +const StyledWrapper = styled.div` + color: ${(props) => props.theme.text}; +`; + +export default StyledWrapper; diff --git a/packages/bruno-app/src/components/Preferences/Font/index.js b/packages/bruno-app/src/components/Preferences/Font/index.js new file mode 100644 index 000000000..bae23e723 --- /dev/null +++ b/packages/bruno-app/src/components/Preferences/Font/index.js @@ -0,0 +1,55 @@ +import React, { useState } from 'react'; +import get from 'lodash/get'; +import { useSelector, useDispatch } from 'react-redux'; +import { savePreferences } from 'providers/ReduxStore/slices/app'; +import StyledWrapper from './StyledWrapper'; + +const Font = ({ close }) => { + const dispatch = useDispatch(); + const preferences = useSelector((state) => state.app.preferences); + + const [codeFont, setCodeFont] = useState(get(preferences, 'font.codeFont', 'default')); + + const handleInputChange = (event) => { + setCodeFont(event.target.value); + }; + + const handleSave = () => { + dispatch( + savePreferences({ + ...preferences, + font: { + codeFont + } + }) + ).then(() => { + close(); + }); + }; + + return ( + + +
+ +
+ +
+ +
+
+ ); +}; + +export default Font; diff --git a/packages/bruno-app/src/components/Preferences/General/index.js b/packages/bruno-app/src/components/Preferences/General/index.js index 20e17593e..b7e5f4f1a 100644 --- a/packages/bruno-app/src/components/Preferences/General/index.js +++ b/packages/bruno-app/src/components/Preferences/General/index.js @@ -1,37 +1,46 @@ import React, { useState } from 'react'; -import { usePreferences } from 'providers/Preferences'; +import { useSelector, useDispatch } from 'react-redux'; +import { savePreferences } from 'providers/ReduxStore/slices/app'; import StyledWrapper from './StyledWrapper'; -import toast from 'react-hot-toast'; -const General = () => { - const { preferences, setPreferences } = usePreferences(); +const General = ({ close }) => { + const preferences = useSelector((state) => state.app.preferences); + const dispatch = useDispatch(); - const [tlsVerification, setTlsVerification] = useState(preferences.request.tlsVerification); + const [sslVerification, setSslVerification] = useState(preferences.request.sslVerification); - const handleCheckboxChange = () => { - const updatedPreferences = { - ...preferences, - request: { - ...preferences.request, - tlsVerification: !tlsVerification - } - }; - - setPreferences(updatedPreferences) - .then(() => { - setTlsVerification(!tlsVerification); - toast.success('Request settings saved successful.'); + const handleSave = () => { + dispatch( + savePreferences({ + ...preferences, + request: { + sslVerification + } }) - .catch((err) => { - console.error(err); - }); + ).then(() => { + close(); + }); }; return (
- - TLS Certificate Verification + setSslVerification(!sslVerification)} + className="mr-3 mousetrap" + /> + +
+ +
+
); diff --git a/packages/bruno-app/src/components/Preferences/index.js b/packages/bruno-app/src/components/Preferences/index.js index 0f552edf0..843fd8228 100644 --- a/packages/bruno-app/src/components/Preferences/index.js +++ b/packages/bruno-app/src/components/Preferences/index.js @@ -3,6 +3,7 @@ import classnames from 'classnames'; import React, { useState } from 'react'; import Support from './Support'; import General from './General'; +import Font from './Font'; import Theme from './Theme'; import Proxy from './ProxySettings'; import StyledWrapper from './StyledWrapper'; @@ -19,20 +20,24 @@ const Preferences = ({ onClose }) => { const getTabPanel = (tab) => { switch (tab) { case 'general': { - return ; + return ; } case 'proxy': { - return ; + return ; } case 'theme': { - return ; + return ; } case 'support': { return ; } + + case 'font': { + return ; + } } }; @@ -46,6 +51,9 @@ const Preferences = ({ onClose }) => {
setTab('theme')}> Theme
+
setTab('font')}> + Font +
setTab('proxy')}> Proxy
diff --git a/packages/bruno-app/src/components/RequestPane/GraphQLVariables/index.js b/packages/bruno-app/src/components/RequestPane/GraphQLVariables/index.js index 59b132044..0d913d97f 100644 --- a/packages/bruno-app/src/components/RequestPane/GraphQLVariables/index.js +++ b/packages/bruno-app/src/components/RequestPane/GraphQLVariables/index.js @@ -1,5 +1,6 @@ import React from 'react'; -import { useDispatch } from 'react-redux'; +import get from 'lodash/get'; +import { useDispatch, useSelector } from 'react-redux'; import CodeEditor from 'components/CodeEditor'; import { updateRequestGraphqlVariables } from 'providers/ReduxStore/slices/collections'; import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions'; @@ -10,6 +11,7 @@ const GraphQLVariables = ({ variables, item, collection }) => { const dispatch = useDispatch(); const { storedTheme } = useTheme(); + const preferences = useSelector((state) => state.app.preferences); const onEdit = (value) => { dispatch( @@ -30,6 +32,7 @@ const GraphQLVariables = ({ variables, item, collection }) => { collection={collection} value={variables || ''} theme={storedTheme} + font={get(preferences, 'font.codeFont', 'default')} onEdit={onEdit} mode="javascript" onRun={onRun} diff --git a/packages/bruno-app/src/components/RequestPane/RequestBody/index.js b/packages/bruno-app/src/components/RequestPane/RequestBody/index.js index c69a6b0ca..9daaf37f1 100644 --- a/packages/bruno-app/src/components/RequestPane/RequestBody/index.js +++ b/packages/bruno-app/src/components/RequestPane/RequestBody/index.js @@ -3,7 +3,7 @@ import get from 'lodash/get'; import CodeEditor from 'components/CodeEditor'; import FormUrlEncodedParams from 'components/RequestPane/FormUrlEncodedParams'; import MultipartFormParams from 'components/RequestPane/MultipartFormParams'; -import { useDispatch } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { useTheme } from 'providers/Theme'; import { updateRequestBody } from 'providers/ReduxStore/slices/collections'; import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions'; @@ -14,6 +14,7 @@ const RequestBody = ({ item, collection }) => { const body = item.draft ? get(item, 'draft.request.body') : get(item, 'request.body'); const bodyMode = item.draft ? get(item, 'draft.request.body.mode') : get(item, 'request.body.mode'); const { storedTheme } = useTheme(); + const preferences = useSelector((state) => state.app.preferences); const onEdit = (value) => { dispatch( @@ -48,6 +49,7 @@ const RequestBody = ({ item, collection }) => { { const responseScript = item.draft ? get(item, 'draft.request.script.res') : get(item, 'request.script.res'); const { storedTheme } = useTheme(); + const preferences = useSelector((state) => state.app.preferences); const onRequestScriptEdit = (value) => { dispatch( @@ -45,6 +46,7 @@ const Script = ({ item, collection }) => { collection={collection} value={requestScript || ''} theme={storedTheme} + font={get(preferences, 'font.codeFont', 'default')} onEdit={onRequestScriptEdit} mode="javascript" onRun={onRun} @@ -57,6 +59,7 @@ const Script = ({ item, collection }) => { collection={collection} value={responseScript || ''} theme={storedTheme} + font={get(preferences, 'font.codeFont', 'default')} onEdit={onResponseScriptEdit} mode="javascript" onRun={onRun} diff --git a/packages/bruno-app/src/components/RequestPane/Tests/index.js b/packages/bruno-app/src/components/RequestPane/Tests/index.js index 351afd3d3..66645509a 100644 --- a/packages/bruno-app/src/components/RequestPane/Tests/index.js +++ b/packages/bruno-app/src/components/RequestPane/Tests/index.js @@ -1,6 +1,6 @@ import React from 'react'; import get from 'lodash/get'; -import { useDispatch } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import CodeEditor from 'components/CodeEditor'; import { updateRequestTests } from 'providers/ReduxStore/slices/collections'; import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions'; @@ -12,6 +12,7 @@ const Tests = ({ item, collection }) => { const tests = item.draft ? get(item, 'draft.request.tests') : get(item, 'request.tests'); const { storedTheme } = useTheme(); + const preferences = useSelector((state) => state.app.preferences); const onEdit = (value) => { dispatch( @@ -32,6 +33,7 @@ const Tests = ({ item, collection }) => { collection={collection} value={tests || ''} theme={storedTheme} + font={get(preferences, 'font.codeFont', 'default')} onEdit={onEdit} mode="javascript" onRun={onRun} diff --git a/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js b/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js index 6a7d37445..bb29abd3a 100644 --- a/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js +++ b/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js @@ -1,7 +1,8 @@ import React from 'react'; +import get from 'lodash/get'; import CodeEditor from 'components/CodeEditor'; import { useTheme } from 'providers/Theme'; -import { useDispatch } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import { sendRequest } from 'providers/ReduxStore/slices/collections/actions'; import classnames from 'classnames'; import { getContentType, safeStringifyJSON, safeParseXML } from 'utils/common'; @@ -13,6 +14,7 @@ import { useMemo } from 'react'; const QueryResult = ({ item, collection, data, width, disableRunEventListener, headers, error }) => { const { storedTheme } = useTheme(); + const preferences = useSelector((state) => state.app.preferences); const [tab, setTab] = useState('preview'); const dispatch = useDispatch(); const contentType = getContentType(headers); @@ -111,7 +113,17 @@ const QueryResult = ({ item, collection, data, width, disableRunEventListener, h return image; } - return ; + return ( + + ); }, [tab, collection, storedTheme, onRun, value, mode]); return ( diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/GenerateCodeItem/CodeView/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/GenerateCodeItem/CodeView/index.js index 79d636daf..64c229ae4 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/GenerateCodeItem/CodeView/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/GenerateCodeItem/CodeView/index.js @@ -1,10 +1,13 @@ import CodeEditor from 'components/CodeEditor/index'; +import get from 'lodash/get'; import { HTTPSnippet } from 'httpsnippet'; import { useTheme } from 'providers/Theme/index'; import { buildHarRequest } from 'utils/codegenerator/har'; +import { useSelector } from 'react-redux'; const CodeView = ({ language, item }) => { const { storedTheme } = useTheme(); + const preferences = useSelector((state) => state.app.preferences); const { target, client, language: lang } = language; let snippet = ''; @@ -15,7 +18,15 @@ const CodeView = ({ language, item }) => { snippet = 'Error generating code snippet'; } - return ; + return ( + + ); }; export default CodeView; diff --git a/packages/bruno-app/src/pageComponents/Index/StyledWrapper.js b/packages/bruno-app/src/pages/Bruno/StyledWrapper.js similarity index 100% rename from packages/bruno-app/src/pageComponents/Index/StyledWrapper.js rename to packages/bruno-app/src/pages/Bruno/StyledWrapper.js diff --git a/packages/bruno-app/src/pageComponents/Index/index.js b/packages/bruno-app/src/pages/Bruno/index.js similarity index 97% rename from packages/bruno-app/src/pageComponents/Index/index.js rename to packages/bruno-app/src/pages/Bruno/index.js index 480ea08f3..9f4de2434 100644 --- a/packages/bruno-app/src/pageComponents/Index/index.js +++ b/packages/bruno-app/src/pages/Bruno/index.js @@ -9,7 +9,6 @@ import StyledWrapper from './StyledWrapper'; import 'codemirror/theme/material.css'; import 'codemirror/theme/monokai.css'; import 'codemirror/addon/scroll/simplescrollbars.css'; -import Documentation from 'components/Documentation'; const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true; if (!SERVER_RENDERED) { diff --git a/packages/bruno-app/src/pages/_app.js b/packages/bruno-app/src/pages/_app.js index 676129049..0b2f9c3a4 100644 --- a/packages/bruno-app/src/pages/_app.js +++ b/packages/bruno-app/src/pages/_app.js @@ -3,7 +3,6 @@ import { Provider } from 'react-redux'; import { AppProvider } from 'providers/App'; import { ToastProvider } from 'providers/Toaster'; import { HotkeysProvider } from 'providers/Hotkeys'; -import { PreferencesProvider } from 'providers/Preferences'; import ReduxStore from 'providers/ReduxStore'; import ThemeProvider from 'providers/Theme/index'; @@ -50,11 +49,9 @@ function MyApp({ Component, pageProps }) { - - - - - + + + diff --git a/packages/bruno-app/src/pages/index.js b/packages/bruno-app/src/pages/index.js index 8c1a8ae5e..1567ef2c4 100644 --- a/packages/bruno-app/src/pages/index.js +++ b/packages/bruno-app/src/pages/index.js @@ -1,5 +1,5 @@ import Head from 'next/head'; -import IndexPage from 'pageComponents/Index'; +import Bruno from './Bruno'; import GlobalStyle from '../globalStyles'; export default function Home() { @@ -13,7 +13,7 @@ export default function Home() {
- +
); diff --git a/packages/bruno-app/src/providers/App/index.js b/packages/bruno-app/src/providers/App/index.js index 041bf6e9d..2fbd17e75 100644 --- a/packages/bruno-app/src/providers/App/index.js +++ b/packages/bruno-app/src/providers/App/index.js @@ -1,6 +1,6 @@ import React, { useEffect } from 'react'; import useTelemetry from './useTelemetry'; -import useCollectionTreeSync from './useCollectionTreeSync'; +import useIpcEvents from './useIpcEvents'; import useCollectionNextAction from './useCollectionNextAction'; import { useDispatch } from 'react-redux'; import { refreshScreenWidth } from 'providers/ReduxStore/slices/app'; @@ -10,7 +10,7 @@ export const AppContext = React.createContext(); export const AppProvider = (props) => { useTelemetry(); - useCollectionTreeSync(); + useIpcEvents(); useCollectionNextAction(); const dispatch = useDispatch(); diff --git a/packages/bruno-app/src/providers/App/useCollectionTreeSync.js b/packages/bruno-app/src/providers/App/useIpcEvents.js similarity index 56% rename from packages/bruno-app/src/providers/App/useCollectionTreeSync.js rename to packages/bruno-app/src/providers/App/useIpcEvents.js index 421702be9..8e87b1cf9 100644 --- a/packages/bruno-app/src/providers/App/useCollectionTreeSync.js +++ b/packages/bruno-app/src/providers/App/useIpcEvents.js @@ -14,11 +14,12 @@ import { runFolderEvent, brunoConfigUpdateEvent } from 'providers/ReduxStore/slices/collections'; +import { updatePreferences } from 'providers/ReduxStore/slices/app'; import toast from 'react-hot-toast'; import { openCollectionEvent, collectionAddEnvFileEvent } from 'providers/ReduxStore/slices/collections/actions'; import { isElectron } from 'utils/common/platform'; -const useCollectionTreeSync = () => { +const useIpcEvents = () => { const dispatch = useDispatch(); useEffect(() => { @@ -28,10 +29,6 @@ const useCollectionTreeSync = () => { const { ipcRenderer } = window; - const _openCollection = (pathname, uid, brunoConfig) => { - dispatch(openCollectionEvent(uid, pathname, brunoConfig)); - }; - const _collectionTreeUpdated = (type, val) => { if (window.__IS_DEV__) { console.log(type); @@ -82,70 +79,73 @@ const useCollectionTreeSync = () => { } }; - const _collectionAlreadyOpened = () => { - toast.success('Collection is already opened'); - }; + ipcRenderer.invoke('renderer:ready'); + const removeCollectionTreeUpdateListener = ipcRenderer.on('main:collection-tree-updated', _collectionTreeUpdated); - const _displayError = (error) => { + const removeOpenCollectionListener = ipcRenderer.on('main:collection-opened', (pathname, uid, brunoConfig) => { + dispatch(openCollectionEvent(uid, pathname, brunoConfig)); + }); + + const removeCollectionAlreadyOpenedListener = ipcRenderer.on('main:collection-already-opened', (pathname) => { + toast.success('Collection is already opened'); + }); + + const removeDisplayErrorListener = ipcRenderer.on('main:display-error', (error) => { if (typeof error === 'string') { return toast.error(error || 'Something went wrong!'); } if (typeof message === 'object') { return toast.error(error.message || 'Something went wrong!'); } - }; + }); - const _scriptEnvironmentUpdate = (val) => { + const removeScriptEnvUpdateListener = ipcRenderer.on('main:script-environment-update', (val) => { dispatch(scriptEnvironmentUpdateEvent(val)); - }; + }); - const _processEnvUpdate = (val) => { - dispatch(processEnvUpdateEvent(val)); - }; - - const _collectionRenamed = (val) => { + const removeCollectionRenamedListener = ipcRenderer.on('main:collection-renamed', (val) => { dispatch(collectionRenamedEvent(val)); - }; + }); - const _runFolderEvent = (val) => { + const removeRunFolderEventListener = ipcRenderer.on('main:run-folder-event', (val) => { dispatch(runFolderEvent(val)); - }; + }); - const _runRequestEvent = (val) => { + const removeRunRequestEventListener = ipcRenderer.on('main:run-request-event', (val) => { dispatch(runRequestEvent(val)); - }; + }); - ipcRenderer.invoke('renderer:ready-application'); - ipcRenderer.invoke('renderer:ready-collection'); + const removeProcessEnvUpdatesListener = ipcRenderer.on('main:process-env-update', (val) => { + dispatch(processEnvUpdateEvent(val)); + }); - const removeListener1 = ipcRenderer.on('main:collection-opened', _openCollection); - const removeListener2 = ipcRenderer.on('main:collection-tree-updated', _collectionTreeUpdated); - const removeListener3 = ipcRenderer.on('main:collection-already-opened', _collectionAlreadyOpened); - const removeListener4 = ipcRenderer.on('main:display-error', _displayError); - const removeListener5 = ipcRenderer.on('main:script-environment-update', _scriptEnvironmentUpdate); - const removeListener6 = ipcRenderer.on('main:collection-renamed', _collectionRenamed); - const removeListener7 = ipcRenderer.on('main:run-folder-event', _runFolderEvent); - const removeListener8 = ipcRenderer.on('main:run-request-event', _runRequestEvent); - const removeListener9 = ipcRenderer.on('main:process-env-update', _processEnvUpdate); - const removeListener10 = ipcRenderer.on('main:console-log', (val) => { + const removeConsoleLogListener = ipcRenderer.on('main:console-log', (val) => { console[val.type](...val.args); }); - const removeListener11 = ipcRenderer.on('main:bruno-config-update', (val) => dispatch(brunoConfigUpdateEvent(val))); + + const removeConfigUpdatesListener = ipcRenderer.on('main:bruno-config-update', (val) => + dispatch(brunoConfigUpdateEvent(val)) + ); + + const removePreferencesUpdatesListener = ipcRenderer.on('main:load-preferences', (val) => { + dispatch(updatePreferences(val)); + }); return () => { - removeListener1(); - removeListener2(); - removeListener3(); - removeListener4(); - removeListener5(); - removeListener6(); - removeListener7(); - removeListener8(); - removeListener9(); - removeListener10(); - removeListener11(); + removeCollectionTreeUpdateListener(); + removeOpenCollectionListener(); + removeCollectionAlreadyOpenedListener(); + removeDisplayErrorListener(); + removeScriptEnvUpdateListener(); + removeCollectionRenamedListener(); + removeRunFolderEventListener(); + removeRunRequestEventListener(); + removeProcessEnvUpdatesListener(); + removeConsoleLogListener(); + removeConfigUpdatesListener(); + removePreferencesUpdatesListener(); }; }, [isElectron]); }; -export default useCollectionTreeSync; +export default useIpcEvents; diff --git a/packages/bruno-app/src/providers/Preferences/index.js b/packages/bruno-app/src/providers/Preferences/index.js deleted file mode 100644 index 7e638def7..000000000 --- a/packages/bruno-app/src/providers/Preferences/index.js +++ /dev/null @@ -1,150 +0,0 @@ -/** - * Preferences Provider - * - * This provider is responsible for managing the user's preferences in the app. - * The preferences are stored in the browser local storage. - * - * On start, an IPC event is published to the main process to set the preferences in the electron process. - */ - -import { useEffect, createContext, useContext, useMemo } from 'react'; -import * as Yup from 'yup'; -import useLocalStorage from 'hooks/useLocalStorage/index'; -import toast from 'react-hot-toast'; - -const requestSchema = Yup.object({ - sslVerification: Yup.boolean(), - caCert: Yup.string().max(1024) -}); -const proxySchema = Yup.object({ - enabled: Yup.boolean(), - protocol: Yup.string().oneOf(['http', 'https', 'socks5']), - hostname: Yup.string() - .when('enabled', { - is: true, - then: (hostname) => hostname.required('Specify the hostname for your proxy.'), - otherwise: (hostname) => hostname.nullable() - }) - .max(1024), - port: Yup.number() - .when('enabled', { - is: true, - then: (port) => port.typeError('Specify port between 1 and 65535'), - otherwise: (port) => port.nullable().transform((_, val) => (val ? Number(val) : null)) - }) - .min(1) - .max(65535), - auth: Yup.object() - .when('enabled', { - is: true, - then: Yup.object({ - enabled: Yup.boolean(), - username: Yup.string() - .when(['enabled'], { - is: true, - then: (username) => username.required('Specify username for proxy authentication.') - }) - .max(1024), - password: Yup.string() - .when('enabled', { - is: true, - then: (password) => password.required('Specify password for proxy authentication.') - }) - .max(1024) - }) - }) - .optional(), - noProxy: Yup.string().optional().max(1024) -}); - -const preferencesSchema = Yup.object({ - request: requestSchema, - proxy: proxySchema -}); - -export const PreferencesContext = createContext(); -export const PreferencesProvider = (props) => { - // TODO: Remove migration later - const [localStorePreferences] = useLocalStorage('bruno.preferences'); - - const preferences = {}; - const { ipcRenderer } = window; - - useEffect(() => { - // TODO: Remove migration later - if (localStorePreferences?.request) { - console.log('migrate prefs from localStorage ' + JSON.stringify(localStorePreferences)); - ipcRenderer - .invoke('renderer:migrate-preferences', localStorePreferences.request.sslVerification) - .then(() => { - localStorage.removeItem('bruno.preferences'); - }) - .catch((err) => { - toast.error(err.message || 'Preferences sync error'); - }); - } - - const removeListener = ipcRenderer.on('main:preferences-read', (currentPreferences) => { - if (currentPreferences.request) { - preferences.request = currentPreferences.request; - } - if (currentPreferences.proxy) { - preferences.proxy = currentPreferences.proxy; - } - }); - - return () => { - removeListener(); - }; - }, [preferences, toast]); - - const validatedSetPreferences = (newPreferences) => { - return new Promise((resolve, reject) => { - preferencesSchema - .validate(newPreferences, { abortEarly: true }) - .then((validatedPreferences) => { - ipcRenderer - .invoke('renderer:set-preferences', validatedPreferences) - .then(() => { - preferences.request = validatedPreferences.request; - preferences.proxy = validatedPreferences.proxy; - }) - .catch((err) => { - toast.error(err.message || 'Preferences sync error'); - }); - resolve(validatedPreferences); - }) - .catch((error) => { - let errMsg = error.message || 'Preferences validation error'; - toast.error(errMsg); - reject(error); - }); - }); - }; - - const value = useMemo( - () => ({ - preferences, - setPreferences: validatedSetPreferences - }), - [preferences, validatedSetPreferences] - ); - - return ( - - <>{props.children} - - ); -}; - -export const usePreferences = () => { - const context = useContext(PreferencesContext); - - if (context === undefined) { - throw new Error(`usePreferences must be used within a PreferencesProvider`); - } - - return context; -}; - -export default PreferencesProvider; diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/app.js b/packages/bruno-app/src/providers/ReduxStore/slices/app.js index f1e9b9117..c3a3aa5a8 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/app.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/app.js @@ -1,11 +1,20 @@ import { createSlice } from '@reduxjs/toolkit'; +import toast from 'react-hot-toast'; const initialState = { isDragging: false, idbConnectionReady: false, leftSidebarWidth: 222, screenWidth: 500, - showHomePage: false + showHomePage: false, + preferences: { + request: { + sslVerification: true + }, + font: { + codeFont: 'default' + } + } }; export const appSlice = createSlice({ @@ -29,6 +38,9 @@ export const appSlice = createSlice({ }, hideHomePage: (state) => { state.showHomePage = false; + }, + updatePreferences: (state, action) => { + state.preferences = action.payload; } } }); @@ -39,7 +51,25 @@ export const { updateLeftSidebarWidth, updateIsDragging, showHomePage, - hideHomePage + hideHomePage, + updatePreferences } = appSlice.actions; +export const savePreferences = (preferences) => (dispatch, getState) => { + return new Promise((resolve, reject) => { + const { ipcRenderer } = window; + + ipcRenderer + .invoke('renderer:save-preferences', preferences) + .then(() => toast.success('Preferences saved successfully')) + .then(() => dispatch(updatePreferences(preferences))) + .then(resolve) + .catch((err) => { + toast.error('An error occurred while saving preferences'); + console.error(err); + reject(err); + }); + }); +}; + export default appSlice.reducer; diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js index c5cb71f83..c60b3e68c 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js @@ -1057,7 +1057,6 @@ export const collectionsSlice = createSlice({ if (collection) { collection.root = file.data; } - console.log('collectionAddFileEvent', file); return; } diff --git a/packages/bruno-electron/src/index.js b/packages/bruno-electron/src/index.js index d2f94ee88..a0b509abc 100644 --- a/packages/bruno-electron/src/index.js +++ b/packages/bruno-electron/src/index.js @@ -8,10 +8,9 @@ const menuTemplate = require('./app/menu-template'); const LastOpenedCollections = require('./store/last-opened-collections'); const registerNetworkIpc = require('./ipc/network'); const registerCollectionsIpc = require('./ipc/collection'); -const registerApplicationIpc = require('./ipc/application'); +const registerPreferencesIpc = require('./ipc/preferences'); const Watcher = require('./app/watcher'); const { loadWindowState, saveWindowState } = require('./utils/window'); -const preferences = require('./store/preferences'); const lastOpenedCollections = new LastOpenedCollections(); @@ -41,8 +40,8 @@ app.on('ready', async () => { y, width, height, - minWidth:1000, - minHeight:640, + minWidth: 1000, + minHeight: 640, webPreferences: { nodeIntegration: true, contextIsolation: true, @@ -78,7 +77,7 @@ app.on('ready', async () => { // register all ipc handlers registerNetworkIpc(mainWindow); registerCollectionsIpc(mainWindow, watcher, lastOpenedCollections); - registerApplicationIpc(mainWindow, preferences); + registerPreferencesIpc(mainWindow, watcher, lastOpenedCollections); }); // Quit the app once all windows are closed diff --git a/packages/bruno-electron/src/ipc/collection.js b/packages/bruno-electron/src/ipc/collection.js index acdb5f8aa..afddb8696 100644 --- a/packages/bruno-electron/src/ipc/collection.js +++ b/packages/bruno-electron/src/ipc/collection.js @@ -15,9 +15,10 @@ const { sanitizeDirectoryName } = require('../utils/filesystem'); const { stringifyJson } = require('../utils/common'); -const { openCollectionDialog, openCollection } = require('../app/collections'); +const { openCollectionDialog } = require('../app/collections'); const { generateUidBasedOnHash } = require('../utils/common'); const { moveRequestUid, deleteRequestUid } = require('../cache/requestUids'); +const { setPreferences } = require('../store/preferences'); const EnvironmentSecretsStore = require('../store/env-secrets'); const environmentSecretsStore = new EnvironmentSecretsStore(); @@ -462,21 +463,6 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection } }); - ipcMain.handle('renderer:ready-collection', async (event) => { - // reload last opened collections - const lastOpened = lastOpenedCollections.getAll(); - - if (lastOpened && lastOpened.length) { - for (let collectionPath of lastOpened) { - if (isDirectory(collectionPath)) { - openCollection(mainWindow, watcher, collectionPath, { - dontSendDisplayErrors: true - }); - } - } - } - }); - ipcMain.handle('renderer:update-bruno-config', async (event, brunoConfig, collectionPath, collectionUid) => { try { const brunoConfigPath = path.join(collectionPath, 'bruno.json'); diff --git a/packages/bruno-electron/src/ipc/preferences.js b/packages/bruno-electron/src/ipc/preferences.js new file mode 100644 index 000000000..f93ec5e6f --- /dev/null +++ b/packages/bruno-electron/src/ipc/preferences.js @@ -0,0 +1,35 @@ +const { ipcMain } = require('electron'); +const { getPreferences, savePreferences } = require('../store/preferences'); +const { isDirectory } = require('../utils/filesystem'); +const { openCollection } = require('../app/collections'); + +const registerPreferencesIpc = (mainWindow, watcher, lastOpenedCollections) => { + ipcMain.handle('renderer:ready', async (event) => { + // load preferences + const preferences = getPreferences(); + mainWindow.webContents.send('main:load-preferences', preferences); + + // reload last opened collections + const lastOpened = lastOpenedCollections.getAll(); + + if (lastOpened && lastOpened.length) { + for (let collectionPath of lastOpened) { + if (isDirectory(collectionPath)) { + openCollection(mainWindow, watcher, collectionPath, { + dontSendDisplayErrors: true + }); + } + } + } + }); + + ipcMain.handle('renderer:save-preferences', async (event, preferences) => { + try { + await savePreferences(preferences); + } catch (error) { + return Promise.reject(error); + } + }); +}; + +module.exports = registerPreferencesIpc; diff --git a/packages/bruno-electron/src/store/preferences.js b/packages/bruno-electron/src/store/preferences.js index fe81988c8..62e17a564 100644 --- a/packages/bruno-electron/src/store/preferences.js +++ b/packages/bruno-electron/src/store/preferences.js @@ -1,3 +1,4 @@ +const Yup = require('yup'); const Store = require('electron-store'); const { get } = require('lodash'); @@ -20,9 +21,12 @@ const { get } = require('lodash'); const defaultPreferences = { request: { - tlsVerification: true, + sslVerification: true, caCert: '' }, + font: { + codeFont: 'default' + }, proxy: { enabled: false, protocol: 'http', @@ -37,6 +41,15 @@ const defaultPreferences = { } }; +const preferencesSchema = Yup.object().shape({ + request: Yup.object().shape({ + sslVerification: Yup.boolean() + }), + font: Yup.object().shape({ + codeFont: Yup.string().nullable() + }) +}); + class PreferencesStore { constructor() { this.store = new Store({ @@ -45,25 +58,36 @@ class PreferencesStore { }); } - get(key) { - return this.store.get(key); + getPreferences() { + return { + defaultPreferences, + ...this.store.get('preferences') + }; } - set(key, value) { - this.store.set(key, value); - } - - getPath() { - return this.store.path; + savePreferences(newPreferences) { + return this.store.set('preferences', newPreferences); } } + const preferencesStore = new PreferencesStore(); const getPreferences = () => { - return { - ...defaultPreferences, - ...(preferencesStore.get('preferences') || {}) - }; + return preferencesStore.getPreferences(); +}; + +const savePreferences = async (newPreferences) => { + return new Promise((resolve, reject) => { + preferencesSchema + .validate(newPreferences, { abortEarly: true }) + .then((validatedPreferences) => { + preferencesStore.savePreferences(validatedPreferences); + resolve(); + }) + .catch((error) => { + reject(error); + }); + }); }; const preferences = { @@ -85,28 +109,11 @@ const preferences = { getProxyConfig: () => { return get(getPreferences(), 'proxy', {}); - }, - - setPreferences: (validatedPreferences) => { - const updatedPreferences = { - ...getPreferences(), - ...validatedPreferences - }; - preferencesStore.set('preferences', updatedPreferences); - }, - - migrateSslVerification: (sslVerification) => { - let preferences = getPreferences(); - if (!preferences.request) { - const updatedPreferences = { - ...preferences, - request: { - tlsVerification: sslVerification - } - }; - preferencesStore.set('preferences', updatedPreferences); - } } }; -module.exports = preferences; +module.exports = { + getPreferences, + savePreferences, + preferences +}; diff --git a/packages/bruno-electron/src/store/window-state.js b/packages/bruno-electron/src/store/window-state.js index bb0a61b64..90bf7b8cb 100644 --- a/packages/bruno-electron/src/store/window-state.js +++ b/packages/bruno-electron/src/store/window-state.js @@ -1,4 +1,3 @@ -const _ = require('lodash'); const Store = require('electron-store'); const DEFAULT_WINDOW_WIDTH = 1280;