mirror of
https://github.com/usebruno/bruno.git
synced 2025-02-17 02:00:49 +01:00
Merge branch 'main' into feature/proxy-global-and-collection
# Conflicts: # packages/bruno-app/src/components/Preferences/General/index.js # packages/bruno-app/src/components/Preferences/index.js # packages/bruno-app/src/providers/App/useIpcEvents.js # packages/bruno-app/src/providers/Preferences/index.js # packages/bruno-electron/src/index.js # packages/bruno-electron/src/ipc/collection.js # packages/bruno-electron/src/store/preferences.js
This commit is contained in:
commit
f2bdf2eaf6
@ -4,6 +4,7 @@ const StyledWrapper = styled.div`
|
|||||||
div.CodeMirror {
|
div.CodeMirror {
|
||||||
background: ${(props) => props.theme.codemirror.bg};
|
background: ${(props) => props.theme.codemirror.bg};
|
||||||
border: solid 1px ${(props) => props.theme.codemirror.border};
|
border: solid 1px ${(props) => props.theme.codemirror.border};
|
||||||
|
font-family: ${(props) => (props.font ? props.font : 'default')};
|
||||||
}
|
}
|
||||||
|
|
||||||
.CodeMirror-overlayscroll-horizontal div,
|
.CodeMirror-overlayscroll-horizontal div,
|
||||||
|
@ -121,6 +121,7 @@ export default class CodeEditor extends React.Component {
|
|||||||
<StyledWrapper
|
<StyledWrapper
|
||||||
className="h-full w-full"
|
className="h-full w-full"
|
||||||
aria-label="Code Editor"
|
aria-label="Code Editor"
|
||||||
|
font={this.props.font}
|
||||||
ref={(node) => {
|
ref={(node) => {
|
||||||
this._node = node;
|
this._node = node;
|
||||||
}}
|
}}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
const StyledWrapper = styled.div`
|
||||||
|
color: ${(props) => props.theme.text};
|
||||||
|
`;
|
||||||
|
|
||||||
|
export default StyledWrapper;
|
55
packages/bruno-app/src/components/Preferences/Font/index.js
Normal file
55
packages/bruno-app/src/components/Preferences/Font/index.js
Normal file
@ -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 (
|
||||||
|
<StyledWrapper>
|
||||||
|
<label className="block font-medium">Code Editor Font</label>
|
||||||
|
<div className="input-container">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="block textbox mt-2 w-full"
|
||||||
|
autoComplete="off"
|
||||||
|
autoCorrect="off"
|
||||||
|
autoCapitalize="off"
|
||||||
|
spellCheck="false"
|
||||||
|
onChange={handleInputChange}
|
||||||
|
defaultValue={codeFont}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-10">
|
||||||
|
<button type="submit" className="submit btn btn-sm btn-secondary" onClick={handleSave}>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</StyledWrapper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Font;
|
@ -1,37 +1,46 @@
|
|||||||
import React, { useState } from 'react';
|
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 StyledWrapper from './StyledWrapper';
|
||||||
import toast from 'react-hot-toast';
|
|
||||||
|
|
||||||
const General = () => {
|
const General = ({ close }) => {
|
||||||
const { preferences, setPreferences } = usePreferences();
|
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 handleSave = () => {
|
||||||
const updatedPreferences = {
|
dispatch(
|
||||||
...preferences,
|
savePreferences({
|
||||||
request: {
|
...preferences,
|
||||||
...preferences.request,
|
request: {
|
||||||
tlsVerification: !tlsVerification
|
sslVerification
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
setPreferences(updatedPreferences)
|
|
||||||
.then(() => {
|
|
||||||
setTlsVerification(!tlsVerification);
|
|
||||||
toast.success('Request settings saved successful.');
|
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
).then(() => {
|
||||||
console.error(err);
|
close();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledWrapper>
|
<StyledWrapper>
|
||||||
<div className="flex items-center mt-2">
|
<div className="flex items-center mt-2">
|
||||||
<input type="checkbox" checked={tlsVerification} onChange={handleCheckboxChange} className="mr-3 mousetrap" />
|
<input
|
||||||
TLS Certificate Verification
|
id="ssl-verification"
|
||||||
|
type="checkbox"
|
||||||
|
checked={sslVerification}
|
||||||
|
onChange={() => setSslVerification(!sslVerification)}
|
||||||
|
className="mr-3 mousetrap"
|
||||||
|
/>
|
||||||
|
<label htmlFor="ssl-verification" className="select-none">
|
||||||
|
TLS Certificate Verification
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-10">
|
||||||
|
<button type="submit" className="submit btn btn-sm btn-secondary" onClick={handleSave}>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</StyledWrapper>
|
</StyledWrapper>
|
||||||
);
|
);
|
||||||
|
@ -3,6 +3,7 @@ import classnames from 'classnames';
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import Support from './Support';
|
import Support from './Support';
|
||||||
import General from './General';
|
import General from './General';
|
||||||
|
import Font from './Font';
|
||||||
import Theme from './Theme';
|
import Theme from './Theme';
|
||||||
import Proxy from './ProxySettings';
|
import Proxy from './ProxySettings';
|
||||||
import StyledWrapper from './StyledWrapper';
|
import StyledWrapper from './StyledWrapper';
|
||||||
@ -19,20 +20,24 @@ const Preferences = ({ onClose }) => {
|
|||||||
const getTabPanel = (tab) => {
|
const getTabPanel = (tab) => {
|
||||||
switch (tab) {
|
switch (tab) {
|
||||||
case 'general': {
|
case 'general': {
|
||||||
return <General />;
|
return <General close={onClose} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'proxy': {
|
case 'proxy': {
|
||||||
return <Proxy />;
|
return <Proxy close={onClose} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'theme': {
|
case 'theme': {
|
||||||
return <Theme />;
|
return <Theme close={onClose} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'support': {
|
case 'support': {
|
||||||
return <Support />;
|
return <Support />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'font': {
|
||||||
|
return <Font close={onClose} />;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -46,6 +51,9 @@ const Preferences = ({ onClose }) => {
|
|||||||
<div className={getTabClassname('theme')} role="tab" onClick={() => setTab('theme')}>
|
<div className={getTabClassname('theme')} role="tab" onClick={() => setTab('theme')}>
|
||||||
Theme
|
Theme
|
||||||
</div>
|
</div>
|
||||||
|
<div className={getTabClassname('font')} role="tab" onClick={() => setTab('font')}>
|
||||||
|
Font
|
||||||
|
</div>
|
||||||
<div className={getTabClassname('proxy')} role="tab" onClick={() => setTab('proxy')}>
|
<div className={getTabClassname('proxy')} role="tab" onClick={() => setTab('proxy')}>
|
||||||
Proxy
|
Proxy
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import React from 'react';
|
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 CodeEditor from 'components/CodeEditor';
|
||||||
import { updateRequestGraphqlVariables } from 'providers/ReduxStore/slices/collections';
|
import { updateRequestGraphqlVariables } from 'providers/ReduxStore/slices/collections';
|
||||||
import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
||||||
@ -10,6 +11,7 @@ const GraphQLVariables = ({ variables, item, collection }) => {
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const { storedTheme } = useTheme();
|
const { storedTheme } = useTheme();
|
||||||
|
const preferences = useSelector((state) => state.app.preferences);
|
||||||
|
|
||||||
const onEdit = (value) => {
|
const onEdit = (value) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
@ -30,6 +32,7 @@ const GraphQLVariables = ({ variables, item, collection }) => {
|
|||||||
collection={collection}
|
collection={collection}
|
||||||
value={variables || ''}
|
value={variables || ''}
|
||||||
theme={storedTheme}
|
theme={storedTheme}
|
||||||
|
font={get(preferences, 'font.codeFont', 'default')}
|
||||||
onEdit={onEdit}
|
onEdit={onEdit}
|
||||||
mode="javascript"
|
mode="javascript"
|
||||||
onRun={onRun}
|
onRun={onRun}
|
||||||
|
@ -3,7 +3,7 @@ import get from 'lodash/get';
|
|||||||
import CodeEditor from 'components/CodeEditor';
|
import CodeEditor from 'components/CodeEditor';
|
||||||
import FormUrlEncodedParams from 'components/RequestPane/FormUrlEncodedParams';
|
import FormUrlEncodedParams from 'components/RequestPane/FormUrlEncodedParams';
|
||||||
import MultipartFormParams from 'components/RequestPane/MultipartFormParams';
|
import MultipartFormParams from 'components/RequestPane/MultipartFormParams';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { useTheme } from 'providers/Theme';
|
import { useTheme } from 'providers/Theme';
|
||||||
import { updateRequestBody } from 'providers/ReduxStore/slices/collections';
|
import { updateRequestBody } from 'providers/ReduxStore/slices/collections';
|
||||||
import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
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 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 bodyMode = item.draft ? get(item, 'draft.request.body.mode') : get(item, 'request.body.mode');
|
||||||
const { storedTheme } = useTheme();
|
const { storedTheme } = useTheme();
|
||||||
|
const preferences = useSelector((state) => state.app.preferences);
|
||||||
|
|
||||||
const onEdit = (value) => {
|
const onEdit = (value) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
@ -48,6 +49,7 @@ const RequestBody = ({ item, collection }) => {
|
|||||||
<CodeEditor
|
<CodeEditor
|
||||||
collection={collection}
|
collection={collection}
|
||||||
theme={storedTheme}
|
theme={storedTheme}
|
||||||
|
font={get(preferences, 'font.codeFont', 'default')}
|
||||||
value={bodyContent[bodyMode] || ''}
|
value={bodyContent[bodyMode] || ''}
|
||||||
onEdit={onEdit}
|
onEdit={onEdit}
|
||||||
onRun={onRun}
|
onRun={onRun}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import CodeEditor from 'components/CodeEditor';
|
import CodeEditor from 'components/CodeEditor';
|
||||||
import { updateRequestScript, updateResponseScript } from 'providers/ReduxStore/slices/collections';
|
import { updateRequestScript, updateResponseScript } from 'providers/ReduxStore/slices/collections';
|
||||||
import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
||||||
@ -13,6 +13,7 @@ const Script = ({ item, collection }) => {
|
|||||||
const responseScript = item.draft ? get(item, 'draft.request.script.res') : get(item, 'request.script.res');
|
const responseScript = item.draft ? get(item, 'draft.request.script.res') : get(item, 'request.script.res');
|
||||||
|
|
||||||
const { storedTheme } = useTheme();
|
const { storedTheme } = useTheme();
|
||||||
|
const preferences = useSelector((state) => state.app.preferences);
|
||||||
|
|
||||||
const onRequestScriptEdit = (value) => {
|
const onRequestScriptEdit = (value) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
@ -45,6 +46,7 @@ const Script = ({ item, collection }) => {
|
|||||||
collection={collection}
|
collection={collection}
|
||||||
value={requestScript || ''}
|
value={requestScript || ''}
|
||||||
theme={storedTheme}
|
theme={storedTheme}
|
||||||
|
font={get(preferences, 'font.codeFont', 'default')}
|
||||||
onEdit={onRequestScriptEdit}
|
onEdit={onRequestScriptEdit}
|
||||||
mode="javascript"
|
mode="javascript"
|
||||||
onRun={onRun}
|
onRun={onRun}
|
||||||
@ -57,6 +59,7 @@ const Script = ({ item, collection }) => {
|
|||||||
collection={collection}
|
collection={collection}
|
||||||
value={responseScript || ''}
|
value={responseScript || ''}
|
||||||
theme={storedTheme}
|
theme={storedTheme}
|
||||||
|
font={get(preferences, 'font.codeFont', 'default')}
|
||||||
onEdit={onResponseScriptEdit}
|
onEdit={onResponseScriptEdit}
|
||||||
mode="javascript"
|
mode="javascript"
|
||||||
onRun={onRun}
|
onRun={onRun}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import CodeEditor from 'components/CodeEditor';
|
import CodeEditor from 'components/CodeEditor';
|
||||||
import { updateRequestTests } from 'providers/ReduxStore/slices/collections';
|
import { updateRequestTests } from 'providers/ReduxStore/slices/collections';
|
||||||
import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
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 tests = item.draft ? get(item, 'draft.request.tests') : get(item, 'request.tests');
|
||||||
|
|
||||||
const { storedTheme } = useTheme();
|
const { storedTheme } = useTheme();
|
||||||
|
const preferences = useSelector((state) => state.app.preferences);
|
||||||
|
|
||||||
const onEdit = (value) => {
|
const onEdit = (value) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
@ -32,6 +33,7 @@ const Tests = ({ item, collection }) => {
|
|||||||
collection={collection}
|
collection={collection}
|
||||||
value={tests || ''}
|
value={tests || ''}
|
||||||
theme={storedTheme}
|
theme={storedTheme}
|
||||||
|
font={get(preferences, 'font.codeFont', 'default')}
|
||||||
onEdit={onEdit}
|
onEdit={onEdit}
|
||||||
mode="javascript"
|
mode="javascript"
|
||||||
onRun={onRun}
|
onRun={onRun}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import get from 'lodash/get';
|
||||||
import CodeEditor from 'components/CodeEditor';
|
import CodeEditor from 'components/CodeEditor';
|
||||||
import { useTheme } from 'providers/Theme';
|
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 { sendRequest } from 'providers/ReduxStore/slices/collections/actions';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { getContentType, safeStringifyJSON, safeParseXML } from 'utils/common';
|
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 QueryResult = ({ item, collection, data, width, disableRunEventListener, headers, error }) => {
|
||||||
const { storedTheme } = useTheme();
|
const { storedTheme } = useTheme();
|
||||||
|
const preferences = useSelector((state) => state.app.preferences);
|
||||||
const [tab, setTab] = useState('preview');
|
const [tab, setTab] = useState('preview');
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const contentType = getContentType(headers);
|
const contentType = getContentType(headers);
|
||||||
@ -111,7 +113,17 @@ const QueryResult = ({ item, collection, data, width, disableRunEventListener, h
|
|||||||
return <img src={item.requestSent.url} alt="image" />;
|
return <img src={item.requestSent.url} alt="image" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <CodeEditor collection={collection} theme={storedTheme} onRun={onRun} value={value} mode={mode} readOnly />;
|
return (
|
||||||
|
<CodeEditor
|
||||||
|
collection={collection}
|
||||||
|
font={get(preferences, 'font.codeFont', 'default')}
|
||||||
|
theme={storedTheme}
|
||||||
|
onRun={onRun}
|
||||||
|
value={value}
|
||||||
|
mode={mode}
|
||||||
|
readOnly
|
||||||
|
/>
|
||||||
|
);
|
||||||
}, [tab, collection, storedTheme, onRun, value, mode]);
|
}, [tab, collection, storedTheme, onRun, value, mode]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
import CodeEditor from 'components/CodeEditor/index';
|
import CodeEditor from 'components/CodeEditor/index';
|
||||||
|
import get from 'lodash/get';
|
||||||
import { HTTPSnippet } from 'httpsnippet';
|
import { HTTPSnippet } from 'httpsnippet';
|
||||||
import { useTheme } from 'providers/Theme/index';
|
import { useTheme } from 'providers/Theme/index';
|
||||||
import { buildHarRequest } from 'utils/codegenerator/har';
|
import { buildHarRequest } from 'utils/codegenerator/har';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
const CodeView = ({ language, item }) => {
|
const CodeView = ({ language, item }) => {
|
||||||
const { storedTheme } = useTheme();
|
const { storedTheme } = useTheme();
|
||||||
|
const preferences = useSelector((state) => state.app.preferences);
|
||||||
const { target, client, language: lang } = language;
|
const { target, client, language: lang } = language;
|
||||||
let snippet = '';
|
let snippet = '';
|
||||||
|
|
||||||
@ -15,7 +18,15 @@ const CodeView = ({ language, item }) => {
|
|||||||
snippet = 'Error generating code snippet';
|
snippet = 'Error generating code snippet';
|
||||||
}
|
}
|
||||||
|
|
||||||
return <CodeEditor readOnly value={snippet} theme={storedTheme} mode={lang} />;
|
return (
|
||||||
|
<CodeEditor
|
||||||
|
readOnly
|
||||||
|
value={snippet}
|
||||||
|
font={get(preferences, 'font.codeFont', 'default')}
|
||||||
|
theme={storedTheme}
|
||||||
|
mode={lang}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CodeView;
|
export default CodeView;
|
||||||
|
@ -9,7 +9,6 @@ import StyledWrapper from './StyledWrapper';
|
|||||||
import 'codemirror/theme/material.css';
|
import 'codemirror/theme/material.css';
|
||||||
import 'codemirror/theme/monokai.css';
|
import 'codemirror/theme/monokai.css';
|
||||||
import 'codemirror/addon/scroll/simplescrollbars.css';
|
import 'codemirror/addon/scroll/simplescrollbars.css';
|
||||||
import Documentation from 'components/Documentation';
|
|
||||||
|
|
||||||
const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true;
|
const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true;
|
||||||
if (!SERVER_RENDERED) {
|
if (!SERVER_RENDERED) {
|
@ -3,7 +3,6 @@ import { Provider } from 'react-redux';
|
|||||||
import { AppProvider } from 'providers/App';
|
import { AppProvider } from 'providers/App';
|
||||||
import { ToastProvider } from 'providers/Toaster';
|
import { ToastProvider } from 'providers/Toaster';
|
||||||
import { HotkeysProvider } from 'providers/Hotkeys';
|
import { HotkeysProvider } from 'providers/Hotkeys';
|
||||||
import { PreferencesProvider } from 'providers/Preferences';
|
|
||||||
|
|
||||||
import ReduxStore from 'providers/ReduxStore';
|
import ReduxStore from 'providers/ReduxStore';
|
||||||
import ThemeProvider from 'providers/Theme/index';
|
import ThemeProvider from 'providers/Theme/index';
|
||||||
@ -50,11 +49,9 @@ function MyApp({ Component, pageProps }) {
|
|||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
<ToastProvider>
|
<ToastProvider>
|
||||||
<AppProvider>
|
<AppProvider>
|
||||||
<PreferencesProvider>
|
<HotkeysProvider>
|
||||||
<HotkeysProvider>
|
<Component {...pageProps} />
|
||||||
<Component {...pageProps} />
|
</HotkeysProvider>
|
||||||
</HotkeysProvider>
|
|
||||||
</PreferencesProvider>
|
|
||||||
</AppProvider>
|
</AppProvider>
|
||||||
</ToastProvider>
|
</ToastProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import Head from 'next/head';
|
import Head from 'next/head';
|
||||||
import IndexPage from 'pageComponents/Index';
|
import Bruno from './Bruno';
|
||||||
import GlobalStyle from '../globalStyles';
|
import GlobalStyle from '../globalStyles';
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
@ -13,7 +13,7 @@ export default function Home() {
|
|||||||
<GlobalStyle />
|
<GlobalStyle />
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<IndexPage />
|
<Bruno />
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import useTelemetry from './useTelemetry';
|
import useTelemetry from './useTelemetry';
|
||||||
import useCollectionTreeSync from './useCollectionTreeSync';
|
import useIpcEvents from './useIpcEvents';
|
||||||
import useCollectionNextAction from './useCollectionNextAction';
|
import useCollectionNextAction from './useCollectionNextAction';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { refreshScreenWidth } from 'providers/ReduxStore/slices/app';
|
import { refreshScreenWidth } from 'providers/ReduxStore/slices/app';
|
||||||
@ -10,7 +10,7 @@ export const AppContext = React.createContext();
|
|||||||
|
|
||||||
export const AppProvider = (props) => {
|
export const AppProvider = (props) => {
|
||||||
useTelemetry();
|
useTelemetry();
|
||||||
useCollectionTreeSync();
|
useIpcEvents();
|
||||||
useCollectionNextAction();
|
useCollectionNextAction();
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
@ -14,11 +14,12 @@ import {
|
|||||||
runFolderEvent,
|
runFolderEvent,
|
||||||
brunoConfigUpdateEvent
|
brunoConfigUpdateEvent
|
||||||
} from 'providers/ReduxStore/slices/collections';
|
} from 'providers/ReduxStore/slices/collections';
|
||||||
|
import { updatePreferences } from 'providers/ReduxStore/slices/app';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
import { openCollectionEvent, collectionAddEnvFileEvent } from 'providers/ReduxStore/slices/collections/actions';
|
import { openCollectionEvent, collectionAddEnvFileEvent } from 'providers/ReduxStore/slices/collections/actions';
|
||||||
import { isElectron } from 'utils/common/platform';
|
import { isElectron } from 'utils/common/platform';
|
||||||
|
|
||||||
const useCollectionTreeSync = () => {
|
const useIpcEvents = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -28,10 +29,6 @@ const useCollectionTreeSync = () => {
|
|||||||
|
|
||||||
const { ipcRenderer } = window;
|
const { ipcRenderer } = window;
|
||||||
|
|
||||||
const _openCollection = (pathname, uid, brunoConfig) => {
|
|
||||||
dispatch(openCollectionEvent(uid, pathname, brunoConfig));
|
|
||||||
};
|
|
||||||
|
|
||||||
const _collectionTreeUpdated = (type, val) => {
|
const _collectionTreeUpdated = (type, val) => {
|
||||||
if (window.__IS_DEV__) {
|
if (window.__IS_DEV__) {
|
||||||
console.log(type);
|
console.log(type);
|
||||||
@ -82,70 +79,73 @@ const useCollectionTreeSync = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const _collectionAlreadyOpened = () => {
|
ipcRenderer.invoke('renderer:ready');
|
||||||
toast.success('Collection is already opened');
|
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') {
|
if (typeof error === 'string') {
|
||||||
return toast.error(error || 'Something went wrong!');
|
return toast.error(error || 'Something went wrong!');
|
||||||
}
|
}
|
||||||
if (typeof message === 'object') {
|
if (typeof message === 'object') {
|
||||||
return toast.error(error.message || 'Something went wrong!');
|
return toast.error(error.message || 'Something went wrong!');
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
||||||
const _scriptEnvironmentUpdate = (val) => {
|
const removeScriptEnvUpdateListener = ipcRenderer.on('main:script-environment-update', (val) => {
|
||||||
dispatch(scriptEnvironmentUpdateEvent(val));
|
dispatch(scriptEnvironmentUpdateEvent(val));
|
||||||
};
|
});
|
||||||
|
|
||||||
const _processEnvUpdate = (val) => {
|
const removeCollectionRenamedListener = ipcRenderer.on('main:collection-renamed', (val) => {
|
||||||
dispatch(processEnvUpdateEvent(val));
|
|
||||||
};
|
|
||||||
|
|
||||||
const _collectionRenamed = (val) => {
|
|
||||||
dispatch(collectionRenamedEvent(val));
|
dispatch(collectionRenamedEvent(val));
|
||||||
};
|
});
|
||||||
|
|
||||||
const _runFolderEvent = (val) => {
|
const removeRunFolderEventListener = ipcRenderer.on('main:run-folder-event', (val) => {
|
||||||
dispatch(runFolderEvent(val));
|
dispatch(runFolderEvent(val));
|
||||||
};
|
});
|
||||||
|
|
||||||
const _runRequestEvent = (val) => {
|
const removeRunRequestEventListener = ipcRenderer.on('main:run-request-event', (val) => {
|
||||||
dispatch(runRequestEvent(val));
|
dispatch(runRequestEvent(val));
|
||||||
};
|
});
|
||||||
|
|
||||||
ipcRenderer.invoke('renderer:ready-application');
|
const removeProcessEnvUpdatesListener = ipcRenderer.on('main:process-env-update', (val) => {
|
||||||
ipcRenderer.invoke('renderer:ready-collection');
|
dispatch(processEnvUpdateEvent(val));
|
||||||
|
});
|
||||||
|
|
||||||
const removeListener1 = ipcRenderer.on('main:collection-opened', _openCollection);
|
const removeConsoleLogListener = ipcRenderer.on('main:console-log', (val) => {
|
||||||
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) => {
|
|
||||||
console[val.type](...val.args);
|
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 () => {
|
return () => {
|
||||||
removeListener1();
|
removeCollectionTreeUpdateListener();
|
||||||
removeListener2();
|
removeOpenCollectionListener();
|
||||||
removeListener3();
|
removeCollectionAlreadyOpenedListener();
|
||||||
removeListener4();
|
removeDisplayErrorListener();
|
||||||
removeListener5();
|
removeScriptEnvUpdateListener();
|
||||||
removeListener6();
|
removeCollectionRenamedListener();
|
||||||
removeListener7();
|
removeRunFolderEventListener();
|
||||||
removeListener8();
|
removeRunRequestEventListener();
|
||||||
removeListener9();
|
removeProcessEnvUpdatesListener();
|
||||||
removeListener10();
|
removeConsoleLogListener();
|
||||||
removeListener11();
|
removeConfigUpdatesListener();
|
||||||
|
removePreferencesUpdatesListener();
|
||||||
};
|
};
|
||||||
}, [isElectron]);
|
}, [isElectron]);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useCollectionTreeSync;
|
export default useIpcEvents;
|
@ -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 (
|
|
||||||
<PreferencesContext.Provider value={value}>
|
|
||||||
<>{props.children}</>
|
|
||||||
</PreferencesContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
@ -1,11 +1,20 @@
|
|||||||
import { createSlice } from '@reduxjs/toolkit';
|
import { createSlice } from '@reduxjs/toolkit';
|
||||||
|
import toast from 'react-hot-toast';
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
isDragging: false,
|
isDragging: false,
|
||||||
idbConnectionReady: false,
|
idbConnectionReady: false,
|
||||||
leftSidebarWidth: 222,
|
leftSidebarWidth: 222,
|
||||||
screenWidth: 500,
|
screenWidth: 500,
|
||||||
showHomePage: false
|
showHomePage: false,
|
||||||
|
preferences: {
|
||||||
|
request: {
|
||||||
|
sslVerification: true
|
||||||
|
},
|
||||||
|
font: {
|
||||||
|
codeFont: 'default'
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const appSlice = createSlice({
|
export const appSlice = createSlice({
|
||||||
@ -29,6 +38,9 @@ export const appSlice = createSlice({
|
|||||||
},
|
},
|
||||||
hideHomePage: (state) => {
|
hideHomePage: (state) => {
|
||||||
state.showHomePage = false;
|
state.showHomePage = false;
|
||||||
|
},
|
||||||
|
updatePreferences: (state, action) => {
|
||||||
|
state.preferences = action.payload;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -39,7 +51,25 @@ export const {
|
|||||||
updateLeftSidebarWidth,
|
updateLeftSidebarWidth,
|
||||||
updateIsDragging,
|
updateIsDragging,
|
||||||
showHomePage,
|
showHomePage,
|
||||||
hideHomePage
|
hideHomePage,
|
||||||
|
updatePreferences
|
||||||
} = appSlice.actions;
|
} = 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;
|
export default appSlice.reducer;
|
||||||
|
@ -1057,7 +1057,6 @@ export const collectionsSlice = createSlice({
|
|||||||
if (collection) {
|
if (collection) {
|
||||||
collection.root = file.data;
|
collection.root = file.data;
|
||||||
}
|
}
|
||||||
console.log('collectionAddFileEvent', file);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,10 +8,9 @@ const menuTemplate = require('./app/menu-template');
|
|||||||
const LastOpenedCollections = require('./store/last-opened-collections');
|
const LastOpenedCollections = require('./store/last-opened-collections');
|
||||||
const registerNetworkIpc = require('./ipc/network');
|
const registerNetworkIpc = require('./ipc/network');
|
||||||
const registerCollectionsIpc = require('./ipc/collection');
|
const registerCollectionsIpc = require('./ipc/collection');
|
||||||
const registerApplicationIpc = require('./ipc/application');
|
const registerPreferencesIpc = require('./ipc/preferences');
|
||||||
const Watcher = require('./app/watcher');
|
const Watcher = require('./app/watcher');
|
||||||
const { loadWindowState, saveWindowState } = require('./utils/window');
|
const { loadWindowState, saveWindowState } = require('./utils/window');
|
||||||
const preferences = require('./store/preferences');
|
|
||||||
|
|
||||||
const lastOpenedCollections = new LastOpenedCollections();
|
const lastOpenedCollections = new LastOpenedCollections();
|
||||||
|
|
||||||
@ -41,8 +40,8 @@ app.on('ready', async () => {
|
|||||||
y,
|
y,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
minWidth:1000,
|
minWidth: 1000,
|
||||||
minHeight:640,
|
minHeight: 640,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
nodeIntegration: true,
|
nodeIntegration: true,
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
@ -78,7 +77,7 @@ app.on('ready', async () => {
|
|||||||
// register all ipc handlers
|
// register all ipc handlers
|
||||||
registerNetworkIpc(mainWindow);
|
registerNetworkIpc(mainWindow);
|
||||||
registerCollectionsIpc(mainWindow, watcher, lastOpenedCollections);
|
registerCollectionsIpc(mainWindow, watcher, lastOpenedCollections);
|
||||||
registerApplicationIpc(mainWindow, preferences);
|
registerPreferencesIpc(mainWindow, watcher, lastOpenedCollections);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Quit the app once all windows are closed
|
// Quit the app once all windows are closed
|
||||||
|
@ -15,9 +15,10 @@ const {
|
|||||||
sanitizeDirectoryName
|
sanitizeDirectoryName
|
||||||
} = require('../utils/filesystem');
|
} = require('../utils/filesystem');
|
||||||
const { stringifyJson } = require('../utils/common');
|
const { stringifyJson } = require('../utils/common');
|
||||||
const { openCollectionDialog, openCollection } = require('../app/collections');
|
const { openCollectionDialog } = require('../app/collections');
|
||||||
const { generateUidBasedOnHash } = require('../utils/common');
|
const { generateUidBasedOnHash } = require('../utils/common');
|
||||||
const { moveRequestUid, deleteRequestUid } = require('../cache/requestUids');
|
const { moveRequestUid, deleteRequestUid } = require('../cache/requestUids');
|
||||||
|
const { setPreferences } = require('../store/preferences');
|
||||||
const EnvironmentSecretsStore = require('../store/env-secrets');
|
const EnvironmentSecretsStore = require('../store/env-secrets');
|
||||||
|
|
||||||
const environmentSecretsStore = new EnvironmentSecretsStore();
|
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) => {
|
ipcMain.handle('renderer:update-bruno-config', async (event, brunoConfig, collectionPath, collectionUid) => {
|
||||||
try {
|
try {
|
||||||
const brunoConfigPath = path.join(collectionPath, 'bruno.json');
|
const brunoConfigPath = path.join(collectionPath, 'bruno.json');
|
||||||
|
35
packages/bruno-electron/src/ipc/preferences.js
Normal file
35
packages/bruno-electron/src/ipc/preferences.js
Normal file
@ -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;
|
@ -1,3 +1,4 @@
|
|||||||
|
const Yup = require('yup');
|
||||||
const Store = require('electron-store');
|
const Store = require('electron-store');
|
||||||
const { get } = require('lodash');
|
const { get } = require('lodash');
|
||||||
|
|
||||||
@ -20,9 +21,12 @@ const { get } = require('lodash');
|
|||||||
|
|
||||||
const defaultPreferences = {
|
const defaultPreferences = {
|
||||||
request: {
|
request: {
|
||||||
tlsVerification: true,
|
sslVerification: true,
|
||||||
caCert: ''
|
caCert: ''
|
||||||
},
|
},
|
||||||
|
font: {
|
||||||
|
codeFont: 'default'
|
||||||
|
},
|
||||||
proxy: {
|
proxy: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
protocol: 'http',
|
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 {
|
class PreferencesStore {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.store = new Store({
|
this.store = new Store({
|
||||||
@ -45,25 +58,36 @@ class PreferencesStore {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
get(key) {
|
getPreferences() {
|
||||||
return this.store.get(key);
|
return {
|
||||||
|
defaultPreferences,
|
||||||
|
...this.store.get('preferences')
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
set(key, value) {
|
savePreferences(newPreferences) {
|
||||||
this.store.set(key, value);
|
return this.store.set('preferences', newPreferences);
|
||||||
}
|
|
||||||
|
|
||||||
getPath() {
|
|
||||||
return this.store.path;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const preferencesStore = new PreferencesStore();
|
const preferencesStore = new PreferencesStore();
|
||||||
|
|
||||||
const getPreferences = () => {
|
const getPreferences = () => {
|
||||||
return {
|
return preferencesStore.getPreferences();
|
||||||
...defaultPreferences,
|
};
|
||||||
...(preferencesStore.get('preferences') || {})
|
|
||||||
};
|
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 = {
|
const preferences = {
|
||||||
@ -85,28 +109,11 @@ const preferences = {
|
|||||||
|
|
||||||
getProxyConfig: () => {
|
getProxyConfig: () => {
|
||||||
return get(getPreferences(), 'proxy', {});
|
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
|
||||||
|
};
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
const _ = require('lodash');
|
|
||||||
const Store = require('electron-store');
|
const Store = require('electron-store');
|
||||||
|
|
||||||
const DEFAULT_WINDOW_WIDTH = 1280;
|
const DEFAULT_WINDOW_WIDTH = 1280;
|
||||||
|
Loading…
Reference in New Issue
Block a user