feat(#197): prettier formatting on all files in packages/bruno-app

This commit is contained in:
Anoop M D 2023-09-18 13:37:00 +05:30
parent a103f41d85
commit 19a7f397bb
117 changed files with 1249 additions and 854 deletions

View File

@ -3,5 +3,5 @@
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"printWidth": 180
"printWidth": 120
}

View File

@ -3,5 +3,5 @@
"tabWidth": 2,
"semi": true,
"singleQuote": true,
"printWidth": 180
"printWidth": 120
}

View File

@ -14,7 +14,11 @@ const Bruno = ({ width }) => {
stroke="none"
points="36,47.2521 32.9167,49.6688 30.4167,49.6688 30.3333,53.5021 31.0833,57.0021 32.1667,58.9188 35,60.4188 39.5833,59.8355 41.1667,58.0855 42.1667,53.8355 41.9167,49.8355 39.9167,50.0855"
/>
<polygon fill="#3F3F3F" stroke="none" points="32.5,36.9188 30.9167,40.6688 33.0833,41.9188 34.3333,42.4188 38.6667,42.5855 41.5833,40.3355 39.8333,37.0855" />
<polygon
fill="#3F3F3F"
stroke="none"
points="32.5,36.9188 30.9167,40.6688 33.0833,41.9188 34.3333,42.4188 38.6667,42.5855 41.5833,40.3355 39.8333,37.0855"
/>
</g>
<g id="hair" />
<g id="skin" />
@ -84,8 +88,27 @@ const Bruno = ({ width }) => {
strokeWidth="2"
d="M52.6309,46.4628c0,0-3.0781,6.7216-7.8049,8.2712"
/>
<path fill="none" stroke="#000000" strokeLinecap="round" strokeLinejoin="round" strokeMiterlimit="10" strokeWidth="2" d="M19.437,46.969c0,0,3.0781,6.0823,7.8049,7.632" />
<line x1="36.2078" x2="36.2078" y1="47.3393" y2="44.3093" fill="none" stroke="#000000" strokeLinecap="round" strokeLinejoin="round" strokeMiterlimit="10" strokeWidth="2" />
<path
fill="none"
stroke="#000000"
strokeLinecap="round"
strokeLinejoin="round"
strokeMiterlimit="10"
strokeWidth="2"
d="M19.437,46.969c0,0,3.0781,6.0823,7.8049,7.632"
/>
<line
x1="36.2078"
x2="36.2078"
y1="47.3393"
y2="44.3093"
fill="none"
stroke="#000000"
strokeLinecap="round"
strokeLinejoin="round"
strokeMiterlimit="10"
strokeWidth="2"
/>
</g>
</svg>
);

View File

@ -6,7 +6,8 @@ const StyledWrapper = styled.div`
border: solid 1px ${(props) => props.theme.codemirror.border};
}
.CodeMirror-overlayscroll-horizontal div, .CodeMirror-overlayscroll-vertical div {
.CodeMirror-overlayscroll-horizontal div,
.CodeMirror-overlayscroll-vertical div {
background: #d2d7db;
}
@ -17,12 +18,14 @@ const StyledWrapper = styled.div`
// Todo: dark mode temporary fix
// Clean this
.CodeMirror.cm-s-monokai {
.CodeMirror-overlayscroll-horizontal div, .CodeMirror-overlayscroll-vertical div {
.CodeMirror-overlayscroll-horizontal div,
.CodeMirror-overlayscroll-vertical div {
background: #444444;
}
}
.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute {
.cm-s-monokai span.cm-property,
.cm-s-monokai span.cm-attribute {
color: #9cdcfe !important;
}
@ -30,16 +33,20 @@ const StyledWrapper = styled.div`
color: #ce9178 !important;
}
.cm-s-monokai span.cm-number{
.cm-s-monokai span.cm-number {
color: #b5cea8 !important;
}
.cm-s-monokai span.cm-atom{
.cm-s-monokai span.cm-atom {
color: #569cd6 !important;
}
.cm-variable-valid{color: green}
.cm-variable-invalid{color: red}
.cm-variable-valid {
color: green;
}
.cm-variable-invalid {
color: red;
}
`;
export default StyledWrapper;

View File

@ -43,7 +43,7 @@ export default class CodeEditor extends React.Component {
foldGutter: true,
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
readOnly: this.props.readOnly,
scrollbarStyle: "overlay",
scrollbarStyle: 'overlay',
theme: this.props.theme === 'dark' ? 'monokai' : 'default',
extraKeys: {
'Cmd-Enter': () => {
@ -96,7 +96,7 @@ export default class CodeEditor extends React.Component {
this.editor.setValue(this.props.value);
}
if(this.editor) {
if (this.editor) {
let variables = getEnvironmentVariables(this.props.collection);
if (!isEqual(variables, this.variables)) {
this.addOverlay();
@ -135,7 +135,7 @@ export default class CodeEditor extends React.Component {
defineCodeMirrorBrunoVariablesMode(variables, mode);
this.editor.setOption('mode', 'brunovariables');
}
};
_onEdit = () => {
if (!this.ignoreChangeEvent && this.editor) {

View File

@ -5,7 +5,16 @@ import StyledWrapper from './StyledWrapper';
const Dropdown = ({ icon, children, onCreate, placement }) => {
return (
<StyledWrapper className="dropdown">
<Tippy content={children} placement={placement || 'bottom-end'} animation={false} arrow={false} onCreate={onCreate} interactive={true} trigger="click" appendTo="parent">
<Tippy
content={children}
placement={placement || 'bottom-end'}
animation={false}
arrow={false}
onCreate={onCreate}
interactive={true}
trigger="click"
appendTo="parent"
>
{icon}
</Tippy>
</StyledWrapper>

View File

@ -2,7 +2,7 @@ import styled from 'styled-components';
const Wrapper = styled.div`
.current-enviroment {
background-color: ${(props) => props.theme.sidebar.badge.bg};
background-color: ${(props) => props.theme.sidebar.badge.bg};
border-radius: 15px;
.caret {

View File

@ -16,7 +16,10 @@ const CreateEnvironment = ({ collection, onClose }) => {
name: ''
},
validationSchema: Yup.object({
name: Yup.string().min(1, 'must be atleast 1 characters').max(50, 'must be 50 characters or less').required('name is required')
name: Yup.string()
.min(1, 'must be atleast 1 characters')
.max(50, 'must be 50 characters or less')
.required('name is required')
}),
onSubmit: (values) => {
dispatch(addEnvironment(values.name, collection.uid))
@ -40,7 +43,13 @@ const CreateEnvironment = ({ collection, onClose }) => {
return (
<Portal>
<Modal size="sm" title={'Create Environment'} confirmText="Create" handleConfirm={onSubmit} handleCancel={onClose}>
<Modal
size="sm"
title={'Create Environment'}
confirmText="Create"
handleConfirm={onSubmit}
handleCancel={onClose}
>
<form className="bruno-form" onSubmit={formik.handleSubmit}>
<div>
<label htmlFor="name" className="block font-semibold">
@ -59,7 +68,9 @@ const CreateEnvironment = ({ collection, onClose }) => {
onChange={formik.handleChange}
value={formik.values.name || ''}
/>
{formik.touched.name && formik.errors.name ? <div className="text-red-500">{formik.errors.name}</div> : null}
{formik.touched.name && formik.errors.name ? (
<div className="text-red-500">{formik.errors.name}</div>
) : null}
</div>
</form>
</Modal>

View File

@ -20,7 +20,13 @@ const DeleteEnvironment = ({ onClose, environment, collection }) => {
return (
<Portal>
<StyledWrapper>
<Modal size="sm" title={'Delete Environment'} confirmText="Delete" handleConfirm={onConfirm} handleCancel={onClose}>
<Modal
size="sm"
title={'Delete Environment'}
confirmText="Delete"
handleConfirm={onConfirm}
handleCancel={onClose}
>
Are you sure you want to delete <span className="font-semibold">{environment.name}</span> ?
</Modal>
</StyledWrapper>

View File

@ -12,7 +12,7 @@ const Wrapper = styled.div`
}
thead {
color: ${(props) => props.theme.table.thead.color};;
color: ${(props) => props.theme.table.thead.color};
font-size: 0.8125rem;
user-select: none;
}

View File

@ -99,7 +99,12 @@ const EnvironmentVariables = ({ environment, collection }) => {
</td>
<td>
<div className="flex items-center">
<input type="checkbox" checked={variable.enabled} className="mr-3 mousetrap" onChange={(e) => handleVarChange(e, variable, 'enabled')} />
<input
type="checkbox"
checked={variable.enabled}
className="mr-3 mousetrap"
onChange={(e) => handleVarChange(e, variable, 'enabled')}
/>
<button onClick={() => handleRemoveVars(variable)}>
<IconTrash strokeWidth={1.5} size={20} />
</button>
@ -119,7 +124,12 @@ const EnvironmentVariables = ({ environment, collection }) => {
</div>
<div>
<button type="submit" className="submit btn btn-md btn-secondary mt-2" disabled={!hasChanges} onClick={saveChanges}>
<button
type="submit"
className="submit btn btn-md btn-secondary mt-2"
disabled={!hasChanges}
onClick={saveChanges}
>
Save
</button>
</div>

View File

@ -10,8 +10,16 @@ const EnvironmentDetails = ({ environment, collection }) => {
return (
<div className="px-6 flex-grow flex flex-col pt-6" style={{ maxWidth: '700px' }}>
{openEditModal && <RenameEnvironment onClose={() => setOpenEditModal(false)} environment={environment} collection={collection} />}
{openDeleteModal && <DeleteEnvironment onClose={() => setOpenDeleteModal(false)} environment={environment} collection={collection} />}
{openEditModal && (
<RenameEnvironment onClose={() => setOpenEditModal(false)} environment={environment} collection={collection} />
)}
{openDeleteModal && (
<DeleteEnvironment
onClose={() => setOpenDeleteModal(false)}
environment={environment}
collection={collection}
/>
)}
<div className="flex">
<div className="flex flex-grow items-center">
<IconDatabase className="cursor-pointer" size={20} strokeWidth={1.5} />

View File

@ -14,12 +14,12 @@ const EnvironmentList = ({ collection }) => {
const prevEnvUids = usePrevious(envUids);
useEffect(() => {
if(selectedEnvironment) {
if (selectedEnvironment) {
return;
}
const environment = findEnvironmentInCollection(collection, collection.activeEnvironmentUid);
if(environment) {
if (environment) {
setSelectedEnvironment(environment);
} else {
setSelectedEnvironment(environments && environments.length ? environments[0] : null);
@ -28,9 +28,9 @@ const EnvironmentList = ({ collection }) => {
useEffect(() => {
// check env add
if (prevEnvUids && prevEnvUids.length && envUids.length > prevEnvUids.length) {
if (prevEnvUids && prevEnvUids.length && envUids.length > prevEnvUids.length) {
const newEnv = environments.find((env) => !prevEnvUids.includes(env.uid));
if(newEnv){
if (newEnv) {
setSelectedEnvironment(newEnv);
}
}
@ -38,7 +38,7 @@ const EnvironmentList = ({ collection }) => {
// check env delete
if (prevEnvUids && prevEnvUids.length && envUids.length < prevEnvUids.length) {
setSelectedEnvironment(environments && environments.length ? environments[0] : null);
}
}
}, [envUids, environments, prevEnvUids]);
if (!selectedEnvironment) {

View File

@ -16,7 +16,10 @@ const RenameEnvironment = ({ onClose, environment, collection }) => {
name: environment.name
},
validationSchema: Yup.object({
name: Yup.string().min(1, 'must be atleast 1 characters').max(50, 'must be 50 characters or less').required('name is required')
name: Yup.string()
.min(1, 'must be atleast 1 characters')
.max(50, 'must be 50 characters or less')
.required('name is required')
}),
onSubmit: (values) => {
dispatch(renameEnvironment(values.name, environment.uid, collection.uid))
@ -40,7 +43,13 @@ const RenameEnvironment = ({ onClose, environment, collection }) => {
return (
<Portal>
<Modal size="sm" title={'Rename Environment'} confirmText="Rename" handleConfirm={onSubmit} handleCancel={onClose}>
<Modal
size="sm"
title={'Rename Environment'}
confirmText="Rename"
handleConfirm={onSubmit}
handleCancel={onClose}
>
<form className="bruno-form" onSubmit={formik.handleSubmit}>
<div>
<label htmlFor="name" className="block font-semibold">
@ -59,7 +68,9 @@ const RenameEnvironment = ({ onClose, environment, collection }) => {
onChange={formik.handleChange}
value={formik.values.name || ''}
/>
{formik.touched.name && formik.errors.name ? <div className="text-red-500">{formik.errors.name}</div> : null}
{formik.touched.name && formik.errors.name ? (
<div className="text-red-500">{formik.errors.name}</div>
) : null}
</div>
</form>
</Modal>

View File

@ -11,11 +11,21 @@ const EnvironmentSettings = ({ collection, onClose }) => {
if (!environments || !environments.length) {
return (
<StyledWrapper>
<Modal size="md" title="Environments" confirmText={'Close'} handleConfirm={onClose} handleCancel={onClose} hideCancel={true}>
<Modal
size="md"
title="Environments"
confirmText={'Close'}
handleConfirm={onClose}
handleCancel={onClose}
hideCancel={true}
>
{openCreateModal && <CreateEnvironment collection={collection} onClose={() => setOpenCreateModal(false)} />}
<div className="text-center">
<p>No environments found!</p>
<button className="btn-create-environment text-link pr-2 py-3 mt-2 select-none" onClick={() => setOpenCreateModal(true)}>
<button
className="btn-create-environment text-link pr-2 py-3 mt-2 select-none"
onClick={() => setOpenCreateModal(true)}
>
+ <span>Create Environment</span>
</button>
</div>

View File

@ -1,17 +1,12 @@
import React from 'react';
const SendIcon = ({color, width}) => {
const SendIcon = ({ color, width }) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={width}
height={width}
viewBox="0 0 48 48"
>
<path fill={color} d="M4.02 42l41.98-18-41.98-18-.02 14 30 4-30 4z"/>
<path d="M0 0h48v48h-48z" fill="none"/>
<svg xmlns="http://www.w3.org/2000/svg" width={width} height={width} viewBox="0 0 48 48">
<path fill={color} d="M4.02 42l41.98-18-41.98-18-.02 14 30 4-30 4z" />
<path d="M0 0h48v48h-48z" fill="none" />
</svg>
);
}
};
export default SendIcon;

View File

@ -100,7 +100,7 @@ const Wrapper = styled.div`
border-radius: 0px;
outline: none;
box-shadow: none;
transition: border-color ease-in-out .1s;
transition: border-color ease-in-out 0.1s;
border-radius: 3px;
background-color: ${(props) => props.theme.modal.input.bg};
border: 1px solid ${(props) => props.theme.modal.input.border};

View File

@ -14,7 +14,15 @@ const ModalHeader = ({ title, handleCancel }) => (
const ModalContent = ({ children }) => <div className="bruno-modal-content px-4 py-6">{children}</div>;
const ModalFooter = ({ confirmText, cancelText, handleSubmit, handleCancel, confirmDisabled, hideCancel, hideFooter }) => {
const ModalFooter = ({
confirmText,
cancelText,
handleSubmit,
handleCancel,
confirmDisabled,
hideCancel,
hideFooter
}) => {
confirmText = confirmText || 'Save';
cancelText = cancelText || 'Cancel';
@ -30,7 +38,12 @@ const ModalFooter = ({ confirmText, cancelText, handleSubmit, handleCancel, conf
</button>
</span>
<span>
<button type="submit" className="submit btn btn-md btn-secondary" disabled={confirmDisabled} onClick={handleSubmit}>
<button
type="submit"
className="submit btn btn-md btn-secondary"
disabled={confirmDisabled}
onClick={handleSubmit}
>
{confirmText}
</button>
</span>
@ -38,7 +51,18 @@ const ModalFooter = ({ confirmText, cancelText, handleSubmit, handleCancel, conf
);
};
const Modal = ({ size, title, confirmText, cancelText, handleCancel, handleConfirm, children, confirmDisabled, hideCancel, hideFooter }) => {
const Modal = ({
size,
title,
confirmText,
cancelText,
handleCancel,
handleConfirm,
children,
confirmDisabled,
hideCancel,
hideFooter
}) => {
const [isClosing, setIsClosing] = useState(false);
const escFunction = (event) => {
const escKeyCode = 27;
@ -64,7 +88,7 @@ const Modal = ({ size, title, confirmText, cancelText, handleCancel, handleConfi
if (isClosing) {
classes += ' modal--animate-out';
}
if(hideFooter) {
if (hideFooter) {
classes += ' modal-footer-none';
}
return (

View File

@ -3,22 +3,17 @@ import { usePreferences } from 'providers/Preferences';
import StyledWrapper from './StyledWrapper';
const General = () => {
const {
preferences,
setPreferences,
} = usePreferences();
const { preferences, setPreferences } = usePreferences();
const [sslVerification, setSslVerification] = useState(
preferences.request.sslVerification
);
const [sslVerification, setSslVerification] = useState(preferences.request.sslVerification);
const handleCheckboxChange = () => {
const updatedPreferences = {
...preferences,
request: {
...preferences.request,
sslVerification: !sslVerification,
},
sslVerification: !sslVerification
}
};
setPreferences(updatedPreferences)
@ -33,12 +28,7 @@ const General = () => {
return (
<StyledWrapper>
<div className="flex items-center mt-2">
<input
type="checkbox"
checked={sslVerification}
onChange={handleCheckboxChange}
className="mr-3 mousetrap"
/>
<input type="checkbox" checked={sslVerification} onChange={handleCheckboxChange} className="mr-3 mousetrap" />
SSL Certificate Verification
</div>
</StyledWrapper>

View File

@ -22,7 +22,7 @@ const Theme = () => {
return (
<StyledWrapper>
<div className='bruno-form'>
<div className="bruno-form">
<div className="flex items-center mt-2">
<input
id="light-theme"
@ -31,7 +31,7 @@ const Theme = () => {
name="theme"
onChange={(e) => {
formik.handleChange(e);
formik.handleSubmit()
formik.handleSubmit();
}}
value="light"
checked={formik.values.theme === 'light'}
@ -47,7 +47,7 @@ const Theme = () => {
name="theme"
onChange={(e) => {
formik.handleChange(e);
formik.handleSubmit()
formik.handleSubmit();
}}
value="dark"
checked={formik.values.theme === 'dark'}

View File

@ -2,7 +2,7 @@ import React from 'react';
/**
* Assertion operators
*
*
* eq : equal to
* neq : not equal to
* gt : greater than
@ -33,10 +33,32 @@ import React from 'react';
const AssertionOperator = ({ operator, onChange }) => {
const operators = [
'eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'in', 'notIn',
'contains', 'notContains', 'length', 'matches', 'notMatches',
'startsWith', 'endsWith', 'between', 'isEmpty', 'isNull', 'isUndefined',
'isDefined', 'isTruthy', 'isFalsy', 'isJson', 'isNumber', 'isString', 'isBoolean'
'eq',
'neq',
'gt',
'gte',
'lt',
'lte',
'in',
'notIn',
'contains',
'notContains',
'length',
'matches',
'notMatches',
'startsWith',
'endsWith',
'between',
'isEmpty',
'isNull',
'isUndefined',
'isDefined',
'isTruthy',
'isFalsy',
'isJson',
'isNumber',
'isString',
'isBoolean'
];
const handleChange = (e) => {
@ -44,7 +66,7 @@ const AssertionOperator = ({ operator, onChange }) => {
};
const getLabel = (operator) => {
switch(operator) {
switch (operator) {
case 'eq':
return 'equals';
case 'neq':

View File

@ -6,7 +6,7 @@ import { useTheme } from 'providers/Theme';
/**
* Assertion operators
*
*
* eq : equal to
* neq : not equal to
* gt : greater than
@ -35,7 +35,7 @@ import { useTheme } from 'providers/Theme';
* isBoolean : is boolean
*/
const parseAssertionOperator = (str = '') => {
if(!str || typeof str !== 'string' || !str.length) {
if (!str || typeof str !== 'string' || !str.length) {
return {
operator: 'eq',
value: str
@ -43,27 +43,58 @@ const parseAssertionOperator = (str = '') => {
}
const operators = [
'eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'in', 'notIn',
'contains', 'notContains', 'length', 'matches', 'notMatches',
'startsWith', 'endsWith', 'between', 'isEmpty', 'isNull', 'isUndefined',
'isDefined', 'isTruthy', 'isFalsy', 'isJson', 'isNumber', 'isString', 'isBoolean'
'eq',
'neq',
'gt',
'gte',
'lt',
'lte',
'in',
'notIn',
'contains',
'notContains',
'length',
'matches',
'notMatches',
'startsWith',
'endsWith',
'between',
'isEmpty',
'isNull',
'isUndefined',
'isDefined',
'isTruthy',
'isFalsy',
'isJson',
'isNumber',
'isString',
'isBoolean'
];
const unaryOperators = [
'isEmpty', 'isNull', 'isUndefined', 'isDefined', 'isTruthy', 'isFalsy', 'isJson', 'isNumber', 'isString', 'isBoolean'
'isEmpty',
'isNull',
'isUndefined',
'isDefined',
'isTruthy',
'isFalsy',
'isJson',
'isNumber',
'isString',
'isBoolean'
];
const [operator, ...rest] = str.trim().split(' ');
const value = rest.join(' ');
if(unaryOperators.includes(operator)) {
if (unaryOperators.includes(operator)) {
return {
operator,
value: ''
};
}
if(operators.includes(operator)) {
if (operators.includes(operator)) {
return {
operator,
value
@ -78,22 +109,33 @@ const parseAssertionOperator = (str = '') => {
const isUnaryOperator = (operator) => {
const unaryOperators = [
'isEmpty', 'isNull', 'isUndefined', 'isDefined', 'isTruthy', 'isFalsy', 'isJson', 'isNumber', 'isString', 'isBoolean'
'isEmpty',
'isNull',
'isUndefined',
'isDefined',
'isTruthy',
'isFalsy',
'isJson',
'isNumber',
'isString',
'isBoolean'
];
return unaryOperators.includes(operator);
};
const AssertionRow = ({
item, collection, assertion, handleAssertionChange, handleRemoveAssertion,
onSave, handleRun
item,
collection,
assertion,
handleAssertionChange,
handleRemoveAssertion,
onSave,
handleRun
}) => {
const { storedTheme } = useTheme();
const {
operator,
value
} = parseAssertionOperator(assertion.value);
const { operator, value } = parseAssertionOperator(assertion.value);
return (
<tr key={assertion.uid}>
@ -112,11 +154,17 @@ const AssertionRow = ({
<td>
<AssertionOperator
operator={operator}
onChange={(op) => handleAssertionChange({
target: {
value: `${op} ${value}`
}
}, assertion, 'value')}
onChange={(op) =>
handleAssertionChange(
{
target: {
value: `${op} ${value}`
}
},
assertion,
'value'
)
}
/>
</td>
<td>
@ -126,20 +174,22 @@ const AssertionRow = ({
theme={storedTheme}
readOnly={true}
onSave={onSave}
onChange={(newValue) => handleAssertionChange({
target: {
value: newValue
}
}, assertion, 'value')}
onChange={(newValue) =>
handleAssertionChange(
{
target: {
value: newValue
}
},
assertion,
'value'
)
}
onRun={handleRun}
collection={collection}
/>
) : (
<input
type="text"
className='cursor-default'
disabled
/>
<input type="text" className="cursor-default" disabled />
)}
</td>
<td>

View File

@ -4,7 +4,11 @@ import cloneDeep from 'lodash/cloneDeep';
import { IconTrash } from '@tabler/icons';
import { useDispatch } from 'react-redux';
import { useTheme } from 'providers/Theme';
import { addFormUrlEncodedParam, updateFormUrlEncodedParam, deleteFormUrlEncodedParam } from 'providers/ReduxStore/slices/collections';
import {
addFormUrlEncodedParam,
updateFormUrlEncodedParam,
deleteFormUrlEncodedParam
} from 'providers/ReduxStore/slices/collections';
import SingleLineEditor from 'components/SingleLineEditor';
import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
import StyledWrapper from './StyledWrapper';
@ -88,22 +92,33 @@ const FormUrlEncodedParams = ({ item, collection }) => {
/>
</td>
<td>
<SingleLineEditor
<SingleLineEditor
value={param.value}
theme={storedTheme}
onSave={onSave}
onChange={(newValue) => handleParamChange({
target: {
value: newValue
}
}, param, 'value')}
onChange={(newValue) =>
handleParamChange(
{
target: {
value: newValue
}
},
param,
'value'
)
}
onRun={handleRun}
collection={collection}
/>
</td>
<td>
<div className="flex items-center">
<input type="checkbox" checked={param.enabled} className="mr-3 mousetrap" onChange={(e) => handleParamChange(e, param, 'enabled')} />
<input
type="checkbox"
checked={param.enabled}
className="mr-3 mousetrap"
onChange={(e) => handleParamChange(e, param, 'enabled')}
/>
<button onClick={() => handleRemoveParams(param)}>
<IconTrash strokeWidth={1.5} size={20} />
</button>

View File

@ -24,29 +24,24 @@ const GraphQLRequestPane = ({ item, collection, leftPaneWidth, onSchemaLoad, tog
const tabs = useSelector((state) => state.tabs.tabs);
const activeTabUid = useSelector((state) => state.tabs.activeTabUid);
const query = item.draft ? get(item, 'draft.request.body.graphql.query') : get(item, 'request.body.graphql.query');
const variables = item.draft ? get(item, 'draft.request.body.graphql.variables') : get(item, 'request.body.graphql.variables');
const variables = item.draft
? get(item, 'draft.request.body.graphql.variables')
: get(item, 'request.body.graphql.variables');
const url = item.draft ? get(item, 'draft.request.url') : get(item, 'request.url');
const {
storedTheme
} = useTheme();
const { storedTheme } = useTheme();
const environment = findEnvironmentInCollection(collection, collection.activeEnvironmentUid);
let {
schema,
loadSchema,
isLoading: isSchemaLoading,
error: schemaError
} = useGraphqlSchema(url, environment);
let { schema, loadSchema, isLoading: isSchemaLoading, error: schemaError } = useGraphqlSchema(url, environment);
const loadGqlSchema = () => {
if(!isSchemaLoading) {
if (!isSchemaLoading) {
loadSchema();
}
};
useEffect(() => {
if(onSchemaLoad) {
if (onSchemaLoad) {
onSchemaLoad(schema);
}
}, [schema]);
@ -75,17 +70,19 @@ const GraphQLRequestPane = ({ item, collection, leftPaneWidth, onSchemaLoad, tog
const getTabPanel = (tab) => {
switch (tab) {
case 'query': {
return <QueryEditor
collection={collection}
theme={storedTheme}
schema={schema}
width={leftPaneWidth}
onSave={onSave}
value={query}
onRun={onRun}
onEdit={onQueryChange}
onClickReference={handleGqlClickReference}
/>;
return (
<QueryEditor
collection={collection}
theme={storedTheme}
schema={schema}
width={leftPaneWidth}
onSave={onSave}
value={query}
onRun={onRun}
onEdit={onQueryChange}
onClickReference={handleGqlClickReference}
/>
);
}
case 'variables': {
return <GraphQLVariables item={item} variables={variables} collection={collection} />;
@ -150,20 +147,16 @@ const GraphQLRequestPane = ({ item, collection, leftPaneWidth, onSchemaLoad, tog
<div className={getTabClassname('tests')} role="tab" onClick={() => selectTab('tests')}>
Tests
</div>
<div className="flex flex-grow justify-end items-center" style={{fontSize: 13}}>
<div className='flex items-center cursor-pointer hover:underline' onClick={loadGqlSchema}>
{isSchemaLoading ? (
<IconLoader2 className="animate-spin" size={18} strokeWidth={1.5}/>
) : null}
{!isSchemaLoading && !schema ? <IconDownload size={18} strokeWidth={1.5}/> : null }
{!isSchemaLoading && schema ? <IconRefresh size={18} strokeWidth={1.5}/> : null }
<span className='ml-1'>Schema</span>
<div className="flex flex-grow justify-end items-center" style={{ fontSize: 13 }}>
<div className="flex items-center cursor-pointer hover:underline" onClick={loadGqlSchema}>
{isSchemaLoading ? <IconLoader2 className="animate-spin" size={18} strokeWidth={1.5} /> : null}
{!isSchemaLoading && !schema ? <IconDownload size={18} strokeWidth={1.5} /> : null}
{!isSchemaLoading && schema ? <IconRefresh size={18} strokeWidth={1.5} /> : null}
<span className="ml-1">Schema</span>
</div>
<div
className='flex items-center cursor-pointer hover:underline ml-2'
onClick={toggleDocs}
>
<IconBook size={18} strokeWidth={1.5} /><span className='ml-1'>Docs</span>
<div className="flex items-center cursor-pointer hover:underline ml-2" onClick={toggleDocs}>
<IconBook size={18} strokeWidth={1.5} />
<span className="ml-1">Docs</span>
</div>
</div>
</div>

View File

@ -13,7 +13,7 @@ const useGraphqlSchema = (endpoint, environment) => {
const [schema, setSchema] = useState(() => {
try {
const saved = localStorage.getItem(localStorageKey);
if(!saved) {
if (!saved) {
return null;
}
return buildClientSchema(JSON.parse(saved));

View File

@ -9,9 +9,7 @@ import StyledWrapper from './StyledWrapper';
const GraphQLVariables = ({ variables, item, collection }) => {
const dispatch = useDispatch();
const {
storedTheme
} = useTheme();
const { storedTheme } = useTheme();
const onEdit = (value) => {
dispatch(
@ -29,10 +27,11 @@ const GraphQLVariables = ({ variables, item, collection }) => {
return (
<StyledWrapper className="w-full">
<CodeEditor
collection={collection} value={variables || ''}
collection={collection}
value={variables || ''}
theme={storedTheme}
onEdit={onEdit}
mode='javascript'
mode="javascript"
onRun={onRun}
onSave={onSave}
/>

View File

@ -103,7 +103,9 @@ const HttpRequestPane = ({ item, collection, leftPaneWidth }) => {
</div>
) : null}
</div>
<section className={`flex w-full ${['script', 'vars'].includes(focusedTab.requestPaneTab) ? '' : 'mt-5'}`}>{getTabPanel(focusedTab.requestPaneTab)}</section>
<section className={`flex w-full ${['script', 'vars'].includes(focusedTab.requestPaneTab) ? '' : 'mt-5'}`}>
{getTabPanel(focusedTab.requestPaneTab)}
</section>
</StyledWrapper>
);
};

View File

@ -41,7 +41,6 @@ const Wrapper = styled.div`
color: ${(props) => props.theme.table.input.color};
background: transparent;
&:focus {
outline: none !important;
border: solid 1px transparent;

View File

@ -4,7 +4,11 @@ import cloneDeep from 'lodash/cloneDeep';
import { IconTrash } from '@tabler/icons';
import { useDispatch } from 'react-redux';
import { useTheme } from 'providers/Theme';
import { addMultipartFormParam, updateMultipartFormParam, deleteMultipartFormParam } from 'providers/ReduxStore/slices/collections';
import {
addMultipartFormParam,
updateMultipartFormParam,
deleteMultipartFormParam
} from 'providers/ReduxStore/slices/collections';
import SingleLineEditor from 'components/SingleLineEditor';
import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
import StyledWrapper from './StyledWrapper';
@ -88,22 +92,33 @@ const MultipartFormParams = ({ item, collection }) => {
/>
</td>
<td>
<SingleLineEditor
<SingleLineEditor
onSave={onSave}
theme={storedTheme}
value={param.value}
onChange={(newValue) => handleParamChange({
target: {
value: newValue
}
}, param, 'value')}
value={param.value}
onChange={(newValue) =>
handleParamChange(
{
target: {
value: newValue
}
},
param,
'value'
)
}
onRun={handleRun}
collection={collection}
/>
</td>
<td>
<div className="flex items-center">
<input type="checkbox" checked={param.enabled} className="mr-3 mousetrap" onChange={(e) => handleParamChange(e, param, 'enabled')} />
<input
type="checkbox"
checked={param.enabled}
className="mr-3 mousetrap"
onChange={(e) => handleParamChange(e, param, 'enabled')}
/>
<button onClick={() => handleRemoveParams(param)}>
<IconTrash strokeWidth={1.5} size={20} />
</button>

View File

@ -15,16 +15,19 @@ const StyledWrapper = styled.div`
// Todo: dark mode temporary fix
// Clean this
.CodeMirror.cm-s-monokai {
.CodeMirror-overlayscroll-horizontal div, .CodeMirror-overlayscroll-vertical div {
.CodeMirror-overlayscroll-horizontal div,
.CodeMirror-overlayscroll-vertical div {
background: #444444;
}
}
.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute {
.cm-s-monokai span.cm-property,
.cm-s-monokai span.cm-attribute {
color: #9cdcfe !important;
}
.cm-s-monokai span.cm-property, .cm-s-monokai span.cm-attribute {
.cm-s-monokai span.cm-property,
.cm-s-monokai span.cm-attribute {
color: #9cdcfe !important;
}
@ -32,16 +35,20 @@ const StyledWrapper = styled.div`
color: #ce9178 !important;
}
.cm-s-monokai span.cm-number{
.cm-s-monokai span.cm-number {
color: #b5cea8 !important;
}
.cm-s-monokai span.cm-atom{
.cm-s-monokai span.cm-atom {
color: #569cd6 !important;
}
.cm-variable-valid{color: green}
.cm-variable-invalid{color: red}
.cm-variable-valid {
color: green;
}
.cm-variable-invalid {
color: red;
}
`;
export default StyledWrapper;

View File

@ -43,7 +43,7 @@ export default class QueryEditor extends React.Component {
mode: 'graphql',
// mode: 'brunovariables',
brunoVarInfo: {
variables: getAllVariables(this.props.collection),
variables: getAllVariables(this.props.collection)
},
theme: this.props.editorTheme || 'graphiql',
theme: this.props.theme === 'dark' ? 'monokai' : 'default',
@ -51,7 +51,7 @@ export default class QueryEditor extends React.Component {
autoCloseBrackets: true,
matchBrackets: true,
showCursorWhenSelecting: true,
scrollbarStyle: "overlay",
scrollbarStyle: 'overlay',
readOnly: this.props.readOnly ? 'nocursor' : false,
foldGutter: {
minFoldSize: 4
@ -179,14 +179,13 @@ export default class QueryEditor extends React.Component {
}
// Todo: Overlay is messing up with schema hint
// Fix this
// Fix this
addOverlay = () => {
// let variables = getAllVariables(this.props.collection);
// this.variables = variables;
// defineCodeMirrorBrunoVariablesMode(variables, 'graphql');
// this.editor.setOption('mode', 'brunovariables');
}
};
render() {
return (

View File

@ -59,7 +59,10 @@ export default function onHasCompletion(_cm, data, onHintInformationRender) {
const description = ctx.description ? md.render(ctx.description) : 'Self descriptive.';
const type = ctx.type ? '<span className="infoType">' + renderType(ctx.type) + '</span>' : '';
information.innerHTML = '<div className="content">' + (description.slice(0, 3) === '<p>' ? '<p>' + type + description.slice(3) : type + description) + '</div>';
information.innerHTML =
'<div className="content">' +
(description.slice(0, 3) === '<p>' ? '<p>' + type + description.slice(3) : type + description) +
'</div>';
if (ctx && deprecation && ctx.deprecationReason) {
const reason = ctx.deprecationReason ? md.render(ctx.deprecationReason) : '';

View File

@ -13,7 +13,7 @@ const Wrapper = styled.div`
}
thead {
color: ${(props) => props.theme.table.thead.color};;
color: ${(props) => props.theme.table.thead.color};
font-size: 0.8125rem;
user-select: none;
}

View File

@ -91,22 +91,33 @@ const QueryParams = ({ item, collection }) => {
/>
</td>
<td>
<SingleLineEditor
<SingleLineEditor
value={param.value}
theme={storedTheme}
onSave={onSave}
onChange={(newValue) => handleParamChange({
target: {
value: newValue
}
}, param, 'value')}
onChange={(newValue) =>
handleParamChange(
{
target: {
value: newValue
}
},
param,
'value'
)
}
onRun={handleRun}
collection={collection}
/>
</td>
<td>
<div className="flex items-center">
<input type="checkbox" checked={param.enabled} className="mr-3 mousetrap" onChange={(e) => handleParamChange(e, param, 'enabled')} />
<input
type="checkbox"
checked={param.enabled}
className="mr-3 mousetrap"
onChange={(e) => handleParamChange(e, param, 'enabled')}
/>
<button onClick={() => handleRemoveParam(param)}>
<IconTrash strokeWidth={1.5} size={20} />
</button>

View File

@ -10,7 +10,9 @@ const HttpMethodSelector = ({ method, onMethodSelect }) => {
const Icon = forwardRef((props, ref) => {
return (
<div ref={ref} className="flex w-full items-center pl-3 py-1 select-none uppercase">
<div className="flex-grow font-medium" id="create-new-request-method">{method}</div>
<div className="flex-grow font-medium" id="create-new-request-method">
{method}
</div>
<div>
<IconCaretDown className="caret ml-2 mr-2" size={14} strokeWidth={2} />
</div>

View File

@ -1,4 +1,4 @@
import React, { useState, useEffect} from 'react';
import React, { useState, useEffect } from 'react';
import get from 'lodash/get';
import { useDispatch } from 'react-redux';
import { requestUrlChanged, updateRequestMethod } from 'providers/ReduxStore/slices/collections';
@ -18,7 +18,7 @@ const QueryUrl = ({ item, collection, handleRun }) => {
const [methodSelectorWidth, setMethodSelectorWidth] = useState(90);
useEffect(() => {
const el = document.querySelector(".method-selector-container");
const el = document.querySelector('.method-selector-container');
setMethodSelectorWidth(el.offsetWidth);
}, [method]);
@ -56,8 +56,8 @@ const QueryUrl = ({ item, collection, handleRun }) => {
maxWidth: `calc(100% - ${methodSelectorWidth}px)`
}}
>
<SingleLineEditor
value={url}
<SingleLineEditor
value={url}
onSave={onSave}
theme={storedTheme}
onChange={(newValue) => onUrlChange(newValue)}
@ -65,7 +65,7 @@ const QueryUrl = ({ item, collection, handleRun }) => {
collection={collection}
/>
<div className="flex items-center h-full mr-2 cursor-pointer" id="send-request" onClick={handleRun}>
<SendIcon color={theme.requestTabPanel.url.icon} width={22}/>
<SendIcon color={theme.requestTabPanel.url.icon} width={22} />
</div>
</div>
</StyledWrapper>

View File

@ -13,9 +13,7 @@ const RequestBody = ({ item, collection }) => {
const dispatch = useDispatch();
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 { storedTheme } = useTheme();
const onEdit = (value) => {
dispatch(
@ -45,7 +43,15 @@ const RequestBody = ({ item, collection }) => {
return (
<StyledWrapper className="w-full">
<CodeEditor collection={collection} theme={storedTheme} value={bodyContent[bodyMode] || ''} onEdit={onEdit} onRun={onRun} onSave={onSave} mode={codeMirrorMode[bodyMode]} />
<CodeEditor
collection={collection}
theme={storedTheme}
value={bodyContent[bodyMode] || ''}
onEdit={onEdit}
onRun={onRun}
onSave={onSave}
mode={codeMirrorMode[bodyMode]}
/>
</StyledWrapper>
);
}

View File

@ -92,18 +92,29 @@ const RequestHeaders = ({ item, collection }) => {
value={header.value}
theme={storedTheme}
onSave={onSave}
onChange={(newValue) => handleHeaderValueChange({
target: {
value: newValue
}
}, header, 'value')}
onChange={(newValue) =>
handleHeaderValueChange(
{
target: {
value: newValue
}
},
header,
'value'
)
}
onRun={handleRun}
collection={collection}
/>
</td>
<td>
<div className="flex items-center">
<input type="checkbox" checked={header.enabled} className="mr-3 mousetrap" onChange={(e) => handleHeaderValueChange(e, header, 'enabled')} />
<input
type="checkbox"
checked={header.enabled}
className="mr-3 mousetrap"
onChange={(e) => handleHeaderValueChange(e, header, 'enabled')}
/>
<button onClick={() => handleRemoveHeader(header)}>
<IconTrash strokeWidth={1.5} size={20} />
</button>

View File

@ -28,7 +28,14 @@ const SaveRequest = ({ items, onClose }) => {
return (
<StyledWrapper>
<Modal size="md" title="Save Request" confirmText="Save" cancelText="Cancel" handleCancel={onClose} handleConfirm={onClose}>
<Modal
size="md"
title="Save Request"
confirmText="Save"
cancelText="Cancel"
handleCancel={onClose}
handleConfirm={onClose}
>
<p className="mb-2">Select a folder to save request:</p>
<div className="folder-list">
{showFolders && showFolders.length

View File

@ -12,9 +12,7 @@ const Script = ({ item, collection }) => {
const requestScript = item.draft ? get(item, 'draft.request.script.req') : get(item, 'request.script.req');
const responseScript = item.draft ? get(item, 'draft.request.script.res') : get(item, 'request.script.res');
const {
storedTheme
} = useTheme();
const { storedTheme } = useTheme();
const onRequestScriptEdit = (value) => {
dispatch(
@ -29,36 +27,38 @@ const Script = ({ item, collection }) => {
const onResponseScriptEdit = (value) => {
dispatch(
updateResponseScript({
script: value,
itemUid: item.uid,
collectionUid: collection.uid
})
);
};
script: value,
itemUid: item.uid,
collectionUid: collection.uid
})
);
};
const onRun = () => dispatch(sendRequest(item, collection.uid));
const onSave = () => dispatch(saveRequest(item.uid, collection.uid));
return (
<StyledWrapper className="w-full flex flex-col">
<div className='flex-1 mt-2'>
<div className='mb-1 title text-xs'>Pre Request</div>
<div className="flex-1 mt-2">
<div className="mb-1 title text-xs">Pre Request</div>
<CodeEditor
collection={collection} value={requestScript || ''}
collection={collection}
value={requestScript || ''}
theme={storedTheme}
onEdit={onRequestScriptEdit}
mode='javascript'
mode="javascript"
onRun={onRun}
onSave={onSave}
/>
</div>
<div className='flex-1 mt-6'>
<div className='mt-1 mb-1 title text-xs'>Post Response</div>
<div className="flex-1 mt-6">
<div className="mt-1 mb-1 title text-xs">Post Response</div>
<CodeEditor
collection={collection} value={responseScript || ''}
collection={collection}
value={responseScript || ''}
theme={storedTheme}
onEdit={onResponseScriptEdit}
mode='javascript'
mode="javascript"
onRun={onRun}
onSave={onSave}
/>

View File

@ -11,9 +11,7 @@ const Tests = ({ item, collection }) => {
const dispatch = useDispatch();
const tests = item.draft ? get(item, 'draft.request.tests') : get(item, 'request.tests');
const {
storedTheme
} = useTheme();
const { storedTheme } = useTheme();
const onEdit = (value) => {
dispatch(
@ -31,10 +29,11 @@ const Tests = ({ item, collection }) => {
return (
<StyledWrapper className="w-full">
<CodeEditor
collection={collection} value={tests || ''}
collection={collection}
value={tests || ''}
theme={storedTheme}
onEdit={onEdit}
mode='javascript'
mode="javascript"
onRun={onRun}
onSave={onSave}
/>

View File

@ -68,18 +68,18 @@ const VarsTable = ({ item, collection, vars, varType }) => {
<thead>
<tr>
<td>Name</td>
{ varType === 'request' ? (
{varType === 'request' ? (
<td>
<div className='flex items-center'>
<div className="flex items-center">
<span>Value</span>
<Tooltip text="You can write any valid JS Template Literal here" tooltipId="request-var"/>
<Tooltip text="You can write any valid JS Template Literal here" tooltipId="request-var" />
</div>
</td>
) : (
) : (
<td>
<div className='flex items-center'>
<div className="flex items-center">
<span>Expr</span>
<Tooltip text="You can write any valid JS expression here" tooltipId="response-var"/>
<Tooltip text="You can write any valid JS expression here" tooltipId="response-var" />
</div>
</td>
)}
@ -108,11 +108,17 @@ const VarsTable = ({ item, collection, vars, varType }) => {
value={_var.value}
theme={storedTheme}
onSave={onSave}
onChange={(newValue) => handleVarChange({
target: {
value: newValue
}
}, _var, 'value')}
onChange={(newValue) =>
handleVarChange(
{
target: {
value: newValue
}
},
_var,
'value'
)
}
onRun={handleRun}
collection={collection}
/>

View File

@ -12,9 +12,7 @@ const Vars = ({ item, collection }) => {
const requestVars = item.draft ? get(item, 'draft.request.vars.req') : get(item, 'request.vars.req');
const responseVars = item.draft ? get(item, 'draft.request.vars.res') : get(item, 'request.vars.res');
const {
storedTheme
} = useTheme();
const { storedTheme } = useTheme();
const onRequestScriptEdit = (value) => {
dispatch(
@ -29,25 +27,25 @@ const Vars = ({ item, collection }) => {
const onResponseScriptEdit = (value) => {
dispatch(
updateResponseScript({
script: value,
itemUid: item.uid,
collectionUid: collection.uid
})
);
};
script: value,
itemUid: item.uid,
collectionUid: collection.uid
})
);
};
const onRun = () => dispatch(sendRequest(item, collection.uid));
const onSave = () => dispatch(saveRequest(item.uid, collection.uid));
return (
<StyledWrapper className="w-full flex flex-col">
<div className='flex-1 mt-2'>
<div className='mb-1 title text-xs'>Pre Request</div>
<VarsTable item={item} collection={collection} vars={requestVars} varType='request'/>
<div className="flex-1 mt-2">
<div className="mb-1 title text-xs">Pre Request</div>
<VarsTable item={item} collection={collection} vars={requestVars} varType="request" />
</div>
<div className='flex-1'>
<div className='mt-1 mb-1 title text-xs'>Post Response</div>
<VarsTable item={item} collection={collection} vars={responseVars} varType='response'/>
<div className="flex-1">
<div className="mt-1 mb-1 title text-xs">Post Response</div>
<VarsTable item={item} collection={collection} vars={responseVars} varType="response" />
</div>
</StyledWrapper>
);

View File

@ -24,7 +24,7 @@ const RequestNotFound = ({ itemUid }) => {
// and then shows the error message after a delay
// this will prevent the error message from flashing on the screen
if(!showErrorMessage) {
if (!showErrorMessage) {
return null;
}
@ -32,7 +32,9 @@ const RequestNotFound = ({ itemUid }) => {
<div className="mt-6 px-6">
<div className="p-4 bg-orange-100 border-l-4 border-yellow-500 text-yellow-700 bg-yellow-100 p-4">
<div>Request no longer exists.</div>
<div className="mt-2">This can happen when the .bru file associated with this request was deleted on your filesystem.</div>
<div className="mt-2">
This can happen when the .bru file associated with this request was deleted on your filesystem.
</div>
</div>
<button className="btn btn-md btn-secondary mt-6" onClick={closeTab}>
Close Tab

View File

@ -33,7 +33,9 @@ const RequestTabPanel = () => {
let asideWidth = useSelector((state) => state.app.leftSidebarWidth);
const focusedTab = find(tabs, (t) => t.uid === activeTabUid);
const [leftPaneWidth, setLeftPaneWidth] = useState(focusedTab && focusedTab.requestPaneWidth ? focusedTab.requestPaneWidth : (screenWidth - asideWidth) / 2.2); // 2.2 so that request pane is relatively smaller
const [leftPaneWidth, setLeftPaneWidth] = useState(
focusedTab && focusedTab.requestPaneWidth ? focusedTab.requestPaneWidth : (screenWidth - asideWidth) / 2.2
); // 2.2 so that request pane is relatively smaller
const [rightPaneWidth, setRightPaneWidth] = useState(screenWidth - asideWidth - leftPaneWidth - DEFAULT_PADDING);
const [dragging, setDragging] = useState(false);
@ -45,10 +47,10 @@ const RequestTabPanel = () => {
const onSchemaLoad = (schema) => setSchema(schema);
const toggleDocs = () => setShowGqlDocs((showGqlDocs) => !showGqlDocs);
const handleGqlClickReference = (reference) => {
if(docExplorerRef.current) {
if (docExplorerRef.current) {
docExplorerRef.current.showDocForReference(reference);
}
if(!showGqlDocs) {
if (!showGqlDocs) {
setShowGqlDocs(true);
}
};
@ -66,10 +68,13 @@ const RequestTabPanel = () => {
if (dragging) {
e.preventDefault();
let leftPaneXPosition = e.clientX + 2;
if (leftPaneXPosition < (asideWidth+ DEFAULT_PADDING + MIN_LEFT_PANE_WIDTH) || leftPaneXPosition > (screenWidth - MIN_RIGHT_PANE_WIDTH )) {
if (
leftPaneXPosition < asideWidth + DEFAULT_PADDING + MIN_LEFT_PANE_WIDTH ||
leftPaneXPosition > screenWidth - MIN_RIGHT_PANE_WIDTH
) {
return;
}
setLeftPaneWidth(leftPaneXPosition- asideWidth);
setLeftPaneWidth(leftPaneXPosition - asideWidth);
setRightPaneWidth(screenWidth - e.clientX - DEFAULT_PADDING);
}
};
@ -114,8 +119,8 @@ const RequestTabPanel = () => {
}
const showRunner = collection.showRunner;
if(showRunner) {
return <RunnerResults collection={collection}/>;
if (showRunner) {
return <RunnerResults collection={collection} />;
}
const item = findItemInCollection(collection, activeTabUid);
@ -138,7 +143,13 @@ const RequestTabPanel = () => {
</div>
<section className="main flex flex-grow pb-4 relative">
<section className="request-pane">
<div className="px-4" style={{ width: `${Math.max(leftPaneWidth, MIN_LEFT_PANE_WIDTH)}px`, height: `calc(100% - ${DEFAULT_PADDING}px)` }}>
<div
className="px-4"
style={{
width: `${Math.max(leftPaneWidth, MIN_LEFT_PANE_WIDTH)}px`,
height: `calc(100% - ${DEFAULT_PADDING}px)`
}}
>
{item.type === 'graphql-request' ? (
<GraphQLRequestPane
item={item}
@ -150,7 +161,9 @@ const RequestTabPanel = () => {
/>
) : null}
{item.type === 'http-request' ? <HttpRequestPane item={item} collection={collection} leftPaneWidth={leftPaneWidth} /> : null}
{item.type === 'http-request' ? (
<HttpRequestPane item={item} collection={collection} leftPaneWidth={leftPaneWidth} />
) : null}
</div>
</section>
@ -165,19 +178,15 @@ const RequestTabPanel = () => {
{item.type === 'graphql-request' ? (
<div className={`graphql-docs-explorer-container ${showGqlDocs ? '' : 'hidden'}`}>
<DocExplorer schema={schema} ref={(r) => docExplorerRef.current = r}>
<button
className='mr-2'
onClick={toggleDocs}
aria-label="Close Documentation Explorer"
>
<DocExplorer schema={schema} ref={(r) => (docExplorerRef.current = r)}>
<button className="mr-2" onClick={toggleDocs} aria-label="Close Documentation Explorer">
{'\u2715'}
</button>
</DocExplorer>
</div>
): null}
) : null}
</StyledWrapper>
);
};
export default RequestTabPanel;
export default RequestTabPanel;

View File

@ -10,9 +10,11 @@ const CollectionToolBar = ({ collection }) => {
const dispatch = useDispatch();
const handleRun = () => {
dispatch(toggleRunnerView({
collectionUid: collection.uid
}));
dispatch(
toggleRunnerView({
collectionUid: collection.uid
})
);
};
return (
@ -26,7 +28,7 @@ const CollectionToolBar = ({ collection }) => {
<span className="mr-2">
<IconRun className="cursor-pointer" size={20} strokeWidth={1.5} onClick={handleRun} />
</span>
<VariablesView collection={collection}/>
<VariablesView collection={collection} />
<EnvironmentSelector collection={collection} />
</div>
</div>

View File

@ -1,7 +1,7 @@
import React, { useState, useEffect } from 'react';
import { IconAlertTriangle } from '@tabler/icons';
const RequestTabNotFound = ({handleCloseClick}) => {
const RequestTabNotFound = ({ handleCloseClick }) => {
const [showErrorMessage, setShowErrorMessage] = useState(false);
// add a delay component in react that shows a loading spinner
@ -13,7 +13,7 @@ const RequestTabNotFound = ({handleCloseClick}) => {
}, 300);
}, []);
if(!showErrorMessage) {
if (!showErrorMessage) {
return null;
}

View File

@ -87,7 +87,15 @@ const RequestTab = ({ tab, collection }) => {
></path>
</svg>
) : (
<svg focusable="false" xmlns="http://www.w3.org/2000/svg" width="8" height="16" fill="#cc7b1b" className="has-changes-icon" viewBox="0 0 8 8">
<svg
focusable="false"
xmlns="http://www.w3.org/2000/svg"
width="8"
height="16"
fill="#cc7b1b"
className="has-changes-icon"
viewBox="0 0 8 8"
>
<circle cx="4" cy="4" r="3" />
</svg>
)}

View File

@ -81,7 +81,9 @@ const RequestTabs = () => {
// Todo: Must support ephermal requests
return (
<StyledWrapper className={getRootClassname()}>
{newRequestModalOpen && <NewRequest collection={activeCollection} onClose={() => setNewRequestModalOpen(false)} />}
{newRequestModalOpen && (
<NewRequest collection={activeCollection} onClose={() => setNewRequestModalOpen(false)} />
)}
{collectionRequestTabs && collectionRequestTabs.length ? (
<>
<CollectionToolBar collection={activeCollection} />
@ -106,7 +108,12 @@ const RequestTabs = () => {
{collectionRequestTabs && collectionRequestTabs.length
? collectionRequestTabs.map((tab, index) => {
return (
<li key={tab.uid} className={getTabClassname(tab, index)} role="tab" onClick={() => handleClick(tab)}>
<li
key={tab.uid}
className={getTabClassname(tab, index)}
role="tab"
onClick={() => handleClick(tab)}
>
<RequestTab key={tab.uid} tab={tab} collection={activeCollection} activeTab={activeTab} />
</li>
);
@ -124,7 +131,13 @@ const RequestTabs = () => {
) : null}
<li className="select-none short-tab" id="create-new-tab" onClick={createNewTab}>
<div className="flex items-center">
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" viewBox="0 0 16 16">
<svg
xmlns="http://www.w3.org/2000/svg"
width="22"
height="22"
fill="currentColor"
viewBox="0 0 16 16"
>
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z" />
</svg>
</div>

View File

@ -20,7 +20,14 @@ const QueryResult = ({ item, collection, value, width, disableRunEventListener,
return (
<StyledWrapper className="px-3 w-full" style={{ maxWidth: width }}>
<div className="h-full">
<CodeEditor collection={collection} theme={storedTheme} onRun={onRun} value={value || ''} mode={mode} readOnly />
<CodeEditor
collection={collection}
theme={storedTheme}
onRun={onRun}
value={value || ''}
mode={mode}
readOnly
/>
</div>
</StyledWrapper>
);

View File

@ -3,11 +3,11 @@ import styled from 'styled-components';
const Wrapper = styled.div`
font-size: 0.75rem;
font-weight: 600;
&.text-ok {
color: ${(props) => props.theme.requestTabPanel.responseOk};
}
&.text-error {
color: ${(props) => props.theme.requestTabPanel.responseError};
}

View File

@ -5,11 +5,7 @@ const TestResults = ({ results, assertionResults }) => {
results = results || [];
assertionResults = assertionResults || [];
if (!results.length && !assertionResults.length) {
return (
<div className="px-3">
No tests found
</div>
);
return <div className="px-3">No tests found</div>;
}
const passedTests = results.filter((result) => result.status === 'pass');
@ -19,7 +15,7 @@ const TestResults = ({ results, assertionResults }) => {
const failedAssertions = assertionResults.filter((result) => result.status === 'fail');
return (
<StyledWrapper className='flex flex-col px-3'>
<StyledWrapper className="flex flex-col px-3">
<div className="py-2 font-medium test-summary">
Tests ({results.length}/{results.length}), Passed: {passedTests.length}, Failed: {failedTests.length}
</div>
@ -27,18 +23,12 @@ const TestResults = ({ results, assertionResults }) => {
{results.map((result) => (
<li key={result.uid} className="py-1">
{result.status === 'pass' ? (
<span className="test-success">
&#x2714;&nbsp; {result.description}
</span>
<span className="test-success">&#x2714;&nbsp; {result.description}</span>
) : (
<>
<span className="test-failure">
&#x2718;&nbsp; {result.description}
</span>
<span className="test-failure">&#x2718;&nbsp; {result.description}</span>
<br />
<span className="error-message pl-8">
{result.error}
</span>
<span className="error-message pl-8">{result.error}</span>
</>
)}
</li>
@ -46,7 +36,8 @@ const TestResults = ({ results, assertionResults }) => {
</ul>
<div className="py-2 font-medium test-summary">
Assertions ({assertionResults.length}/{assertionResults.length}), Passed: {passedAssertions.length}, Failed: {failedAssertions.length}
Assertions ({assertionResults.length}/{assertionResults.length}), Passed: {passedAssertions.length}, Failed:{' '}
{failedAssertions.length}
</div>
<ul className="">
{assertionResults.map((result) => (
@ -61,9 +52,7 @@ const TestResults = ({ results, assertionResults }) => {
&#x2718;&nbsp; {result.lhsExpr}: {result.rhsExpr}
</span>
<br />
<span className="error-message pl-8">
{result.error}
</span>
<span className="error-message pl-8">{result.error}</span>
</>
)}
</li>

View File

@ -3,32 +3,28 @@ import React from 'react';
const TestResultsLabel = ({ results, assertionResults }) => {
results = results || [];
assertionResults = assertionResults || [];
if(!results.length && !assertionResults.length) {
if (!results.length && !assertionResults.length) {
return 'Tests';
}
const numberOfTests = results.length;
const numberOfFailedTests = results.filter(result => result.status === 'fail').length;
const numberOfFailedTests = results.filter((result) => result.status === 'fail').length;
const numberOfAssertions = assertionResults.length;
const numberOfFailedAssertions = assertionResults.filter(result => result.status === 'fail').length;
const numberOfFailedAssertions = assertionResults.filter((result) => result.status === 'fail').length;
const totalNumberOfTests = numberOfTests + numberOfAssertions;
const totalNumberOfFailedTests = numberOfFailedTests + numberOfFailedAssertions;
return (
<div className='flex items-center'>
<div className="flex items-center">
<div>Tests</div>
{totalNumberOfFailedTests ? (
<sup className='sups some-tests-failed ml-1 font-medium'>
{totalNumberOfFailedTests}
</sup>
<sup className="sups some-tests-failed ml-1 font-medium">{totalNumberOfFailedTests}</sup>
) : (
<sup className='sups all-tests-passed ml-1 font-medium'>
{totalNumberOfTests}
</sup>
<sup className="sups all-tests-passed ml-1 font-medium">{totalNumberOfTests}</sup>
)}
</div>
</div>
);
};

View File

@ -3,7 +3,7 @@ import forOwn from 'lodash/forOwn';
import { safeStringifyJSON } from 'utils/common';
import StyledWrapper from './StyledWrapper';
const Timeline = ({ request, response}) => {
const Timeline = ({ request, response }) => {
const requestHeaders = [];
const responseHeaders = response.headers || [];
@ -22,32 +22,32 @@ const Timeline = ({ request, response}) => {
return (
<StyledWrapper className="px-3 pb-4 w-full">
<div>
<pre className='line request font-bold'>
<pre className="line request font-bold">
<span className="arrow">{'>'}</span> {request.method} {request.url}
</pre>
{requestHeaders.map((h) => {
return (
<pre className='line request' key={h.name}>
<pre className="line request" key={h.name}>
<span className="arrow">{'>'}</span> {h.name}: {h.value}
</pre>
);
})}
{requestData ? (
<pre className='line request'>
<pre className="line request">
<span className="arrow">{'>'}</span> data {requestData}
</pre>
) : null}
</div>
<div className='mt-4'>
<pre className='line response font-bold'>
<div className="mt-4">
<pre className="line response font-bold">
<span className="arrow">{'<'}</span> {response.status} {response.statusText}
</pre>
{responseHeaders.map((h) => {
return (
<pre className='line response' key={h[0]}>
<pre className="line response" key={h[0]}>
<span className="arrow">{'<'}</span> {h[0]}: {h[1]}
</pre>
);

View File

@ -41,7 +41,9 @@ const ResponsePane = ({ rightPaneWidth, item, collection }) => {
item={item}
collection={collection}
width={rightPaneWidth}
value={response.data ? (isJson(response.headers) ? safeStringifyJSON(response.data, true) : response.data) : ''}
value={
response.data ? (isJson(response.headers) ? safeStringifyJSON(response.data, true) : response.data) : ''
}
mode={getContentType(response.headers)}
/>
);

View File

@ -15,11 +15,7 @@ import StyledWrapper from './StyledWrapper';
const ResponsePane = ({ rightPaneWidth, item, collection }) => {
const [selectedTab, setSelectedTab] = useState('response');
const {
requestSent,
responseReceived,
testResults
} = item;
const { requestSent, responseReceived, testResults } = item;
const headers = get(item, 'responseReceived.headers', {});
const status = get(item, 'responseReceived.status', 0);
@ -31,13 +27,15 @@ const ResponsePane = ({ rightPaneWidth, item, collection }) => {
const getTabPanel = (tab) => {
switch (tab) {
case 'response': {
return <QueryResult
item={item}
collection={collection}
width={rightPaneWidth}
disableRunEventListener={true}
value={(responseReceived && responseReceived.data) ? safeStringifyJSON(responseReceived.data, true) : ''}
/>;
return (
<QueryResult
item={item}
collection={collection}
width={rightPaneWidth}
disableRunEventListener={true}
value={responseReceived && responseReceived.data ? safeStringifyJSON(responseReceived.data, true) : ''}
/>
);
}
case 'headers': {
return <ResponseHeaders headers={headers} />;

View File

@ -18,14 +18,14 @@ const getRelativePath = (fullPath, pathname) => {
let relativePath = path.relative(fullPath, pathname);
const { dir, name } = path.parse(relativePath);
return path.join(dir, name);
}
};
export default function RunnerResults({collection}) {
export default function RunnerResults({ collection }) {
const dispatch = useDispatch();
const [selectedItem, setSelectedItem] = useState(null);
useEffect(() => {
if(!collection.runnerResult) {
if (!collection.runnerResult) {
setSelectedItem(null);
}
}, [collection, setSelectedItem]);
@ -42,8 +42,8 @@ export default function RunnerResults({collection}) {
item.pathname = info.pathname;
item.relativePath = getRelativePath(collection.pathname, info.pathname);
if(item.status !== "error") {
if(item.testResults) {
if (item.status !== 'error') {
if (item.testResults) {
const failed = item.testResults.filter((result) => result.status === 'fail');
item.testStatus = failed.length ? 'fail' : 'pass';
@ -51,7 +51,7 @@ export default function RunnerResults({collection}) {
item.testStatus = 'pass';
}
if(item.assertionResults) {
if (item.assertionResults) {
const failed = item.assertionResults.filter((result) => result.status === 'fail');
item.assertionStatus = failed.length ? 'fail' : 'pass';
@ -70,29 +70,31 @@ export default function RunnerResults({collection}) {
};
const closeRunner = () => {
dispatch(closeCollectionRunner({
collectionUid: collection.uid,
}));
dispatch(
closeCollectionRunner({
collectionUid: collection.uid
})
);
};
const totalRequestsInCollection = getTotalRequestCountInCollection(collectionCopy);
const passedRequests = items.filter((item) => {
return item.status !== "error" && item.testStatus === 'pass' && item.assertionStatus === 'pass';
return item.status !== 'error' && item.testStatus === 'pass' && item.assertionStatus === 'pass';
});
const failedRequests = items.filter((item) => {
return item.status !== "error" && item.testStatus === 'fail' || item.assertionStatus === 'fail';
return (item.status !== 'error' && item.testStatus === 'fail') || item.assertionStatus === 'fail';
});
if(!items || !items.length) {
if (!items || !items.length) {
return (
<StyledWrapper className='px-4'>
<div className='font-medium mt-6 title flex items-center'>
<StyledWrapper className="px-4">
<div className="font-medium mt-6 title flex items-center">
Runner
<IconRun size={20} strokeWidth={1.5} className='ml-2'/>
<IconRun size={20} strokeWidth={1.5} className="ml-2" />
</div>
<div className='mt-6'>
You have <span className='font-medium'>{totalRequestsInCollection}</span> requests in this collection.
<div className="mt-6">
You have <span className="font-medium">{totalRequestsInCollection}</span> requests in this collection.
</div>
<button type="submit" className="submit btn btn-sm btn-secondary mt-6" onClick={runCollection}>
@ -107,13 +109,13 @@ export default function RunnerResults({collection}) {
}
return (
<StyledWrapper className='px-4'>
<div className='font-medium mt-6 mb-4 title flex items-center'>
<StyledWrapper className="px-4">
<div className="font-medium mt-6 mb-4 title flex items-center">
Runner
<IconRun size={20} strokeWidth={1.5} className='ml-2'/>
<IconRun size={20} strokeWidth={1.5} className="ml-2" />
</div>
<div className='flex'>
<div className='flex flex-col flex-1'>
<div className="flex">
<div className="flex flex-col flex-1">
<div className="py-2 font-medium test-summary">
Total Requests: {items.length}, Passed: {passedRequests.length}, Failed: {failedRequests.length}
</div>
@ -123,73 +125,69 @@ export default function RunnerResults({collection}) {
<div className="item-path mt-2">
<div className="flex items-center">
<span>
{item.status !== "error" && item.testStatus === 'pass' ? (
<IconCircleCheck className="test-success" size={20} strokeWidth={1.5}/>
) : (
<IconCircleX className="test-failure" size={20} strokeWidth={1.5}/>
)}
{item.status !== 'error' && item.testStatus === 'pass' ? (
<IconCircleCheck className="test-success" size={20} strokeWidth={1.5} />
) : (
<IconCircleX className="test-failure" size={20} strokeWidth={1.5} />
)}
</span>
<span className={`mr-1 ml-2 ${(item.status == "error" || item.testStatus == 'fail') ? 'danger' : ''}`}>{item.relativePath}</span>
{(item.status !== "error" && item.status !== "completed") ? (
<IconRefresh className="animate-spin ml-1" size={18} strokeWidth={1.5}/>
<span
className={`mr-1 ml-2 ${item.status == 'error' || item.testStatus == 'fail' ? 'danger' : ''}`}
>
{item.relativePath}
</span>
{item.status !== 'error' && item.status !== 'completed' ? (
<IconRefresh className="animate-spin ml-1" size={18} strokeWidth={1.5} />
) : (
<span className='text-xs link cursor-pointer' onClick={() => setSelectedItem(item)}>
(<span className='mr-1'>
{get(item.responseReceived, 'status')}
</span>
<span>
{get(item.responseReceived, 'statusText')}
</span>)
<span className="text-xs link cursor-pointer" onClick={() => setSelectedItem(item)}>
(<span className="mr-1">{get(item.responseReceived, 'status')}</span>
<span>{get(item.responseReceived, 'statusText')}</span>)
</span>
)}
</div>
{item.status == "error" ? (
<div className="error-message pl-8 pt-2 text-xs">
{item.error}
</div>
) : null }
{item.status == 'error' ? <div className="error-message pl-8 pt-2 text-xs">{item.error}</div> : null}
<ul className="pl-8">
{item.testResults ? item.testResults.map((result) => (
<li key={result.uid}>
{result.status === 'pass' ? (
<span className="test-success flex items-center">
<IconCheck size={18} strokeWidth={2} className="mr-2"/>
{result.description}
</span>
) : (
<>
<span className="test-failure flex items-center">
<IconX size={18} strokeWidth={2} className="mr-2"/>
{result.description}
</span>
<span className="error-message pl-8 text-xs">
{result.error}
</span>
</>
)}
</li>
)): null}
{item.assertionResults ? item.assertionResults.map((result) => (
<li key={result.uid}>
{result.status === 'pass' ? (
<span className="test-success flex items-center">
<IconCheck size={18} strokeWidth={2} className="mr-2"/>
{result.lhsExpr}: {result.rhsExpr}
</span>
) : (
<>
<span className="test-failure flex items-center">
<IconX size={18} strokeWidth={2} className="mr-2"/>
{result.lhsExpr}: {result.rhsExpr}
</span>
<span className="error-message pl-8 text-xs">
{result.error}
</span>
</>
)}
</li>
)): null}
{item.testResults
? item.testResults.map((result) => (
<li key={result.uid}>
{result.status === 'pass' ? (
<span className="test-success flex items-center">
<IconCheck size={18} strokeWidth={2} className="mr-2" />
{result.description}
</span>
) : (
<>
<span className="test-failure flex items-center">
<IconX size={18} strokeWidth={2} className="mr-2" />
{result.description}
</span>
<span className="error-message pl-8 text-xs">{result.error}</span>
</>
)}
</li>
))
: null}
{item.assertionResults
? item.assertionResults.map((result) => (
<li key={result.uid}>
{result.status === 'pass' ? (
<span className="test-success flex items-center">
<IconCheck size={18} strokeWidth={2} className="mr-2" />
{result.lhsExpr}: {result.rhsExpr}
</span>
) : (
<>
<span className="test-failure flex items-center">
<IconX size={18} strokeWidth={2} className="mr-2" />
{result.lhsExpr}: {result.rhsExpr}
</span>
<span className="error-message pl-8 text-xs">{result.error}</span>
</>
)}
</li>
))
: null}
</ul>
</div>
</div>
@ -210,25 +208,25 @@ export default function RunnerResults({collection}) {
</div>
) : null}
</div>
<div className='flex flex-1' style={{width: '50%'}}>
<div className="flex flex-1" style={{ width: '50%' }}>
{selectedItem ? (
<div className='flex flex-col w-full overflow-auto'>
<div className="flex flex-col w-full overflow-auto">
<div className="flex items-center px-3 mb-4 font-medium">
<span className='mr-2'>{selectedItem.relativePath}</span>
<span className="mr-2">{selectedItem.relativePath}</span>
<span>
{selectedItem.testStatus === 'pass' ? (
<IconCircleCheck className="test-success" size={20} strokeWidth={1.5}/>
<IconCircleCheck className="test-success" size={20} strokeWidth={1.5} />
) : (
<IconCircleX className="test-failure" size={20} strokeWidth={1.5}/>
<IconCircleX className="test-failure" size={20} strokeWidth={1.5} />
)}
</span>
</div>
{/* <div className='px-3 mb-4 font-medium'>{selectedItem.relativePath}</div> */}
<ResponsePane item={selectedItem} collection={collection}/>
<ResponsePane item={selectedItem} collection={collection} />
</div>
) : null}
</div>
</div>
</StyledWrapper>
);
};
}

View File

@ -17,7 +17,10 @@ const CloneCollectionItem = ({ collection, item, onClose }) => {
name: item.name
},
validationSchema: Yup.object({
name: Yup.string().min(1, 'must be atleast 1 characters').max(50, 'must be 50 characters or less').required('name is required')
name: Yup.string()
.min(1, 'must be atleast 1 characters')
.max(50, 'must be 50 characters or less')
.required('name is required')
}),
onSubmit: (values) => {
dispatch(cloneItem(values.name, item.uid, collection.uid))
@ -25,7 +28,7 @@ const CloneCollectionItem = ({ collection, item, onClose }) => {
onClose();
})
.catch((err) => {
toast.error(err ? err.message : 'An error occured while cloning the request')
toast.error(err ? err.message : 'An error occured while cloning the request');
});
}
});
@ -39,7 +42,13 @@ const CloneCollectionItem = ({ collection, item, onClose }) => {
const onSubmit = () => formik.handleSubmit();
return (
<Modal size="sm" title={`Clone ${isFolder ? 'Folder' : 'Request'}`} confirmText="Clone" handleConfirm={onSubmit} handleCancel={onClose}>
<Modal
size="sm"
title={`Clone ${isFolder ? 'Folder' : 'Request'}`}
confirmText="Clone"
handleConfirm={onSubmit}
handleCancel={onClose}
>
<form className="bruno-form" onSubmit={formik.handleSubmit}>
<div>
<label htmlFor="name" className="block font-semibold">

View File

@ -31,7 +31,13 @@ const DeleteCollectionItem = ({ onClose, item, collection }) => {
return (
<StyledWrapper>
<Modal size="sm" title={`Delete ${isFolder ? 'Folder' : 'Request'}`} confirmText="Delete" handleConfirm={onConfirm} handleCancel={onClose}>
<Modal
size="sm"
title={`Delete ${isFolder ? 'Folder' : 'Request'}`}
confirmText="Delete"
handleConfirm={onConfirm}
handleCancel={onClose}
>
Are you sure you want to delete <span className="font-semibold">{item.name}</span> ?
</Modal>
</StyledWrapper>

View File

@ -16,7 +16,10 @@ const RenameCollectionItem = ({ collection, item, onClose }) => {
name: item.name
},
validationSchema: Yup.object({
name: Yup.string().min(1, 'must be atleast 1 characters').max(50, 'must be 50 characters or less').required('name is required')
name: Yup.string()
.min(1, 'must be atleast 1 characters')
.max(50, 'must be 50 characters or less')
.required('name is required')
}),
onSubmit: (values) => {
dispatch(renameItem(values.name, item.uid, collection.uid));
@ -33,7 +36,13 @@ const RenameCollectionItem = ({ collection, item, onClose }) => {
const onSubmit = () => formik.handleSubmit();
return (
<Modal size="sm" title={`Rename ${isFolder ? 'Folder' : 'Request'}`} confirmText="Rename" handleConfirm={onSubmit} handleCancel={onClose}>
<Modal
size="sm"
title={`Rename ${isFolder ? 'Folder' : 'Request'}`}
confirmText="Rename"
handleConfirm={onSubmit}
handleCancel={onClose}
>
<form className="bruno-form" onSubmit={formik.handleSubmit}>
<div>
<label htmlFor="name" className="block font-semibold">

View File

@ -1,7 +1,7 @@
import styled from 'styled-components';
const Wrapper = styled.div`
.bruno-modal-content {
.bruno-modal-content {
padding-bottom: 1rem;
}
`;

View File

@ -11,9 +11,11 @@ const RunCollectionItem = ({ collection, item, onClose }) => {
const dispatch = useDispatch();
const onSubmit = (recursive) => {
dispatch(showRunnerView({
collectionUid: collection.uid,
}));
dispatch(
showRunnerView({
collectionUid: collection.uid
})
);
dispatch(runCollectionFolder(collection.uid, item ? item.uid : null, recursive));
onClose();
};
@ -25,25 +27,21 @@ const RunCollectionItem = ({ collection, item, onClose }) => {
return (
<StyledWrapper>
<Modal size="md" title='Collection Runner' hideFooter={true} handleCancel={onClose}>
<div className='mb-1'>
<span className='font-medium'>Run</span>
<span className='ml-1 text-xs'>({runLength} requests)</span>
</div>
<div className='mb-8'>
This will only run the requests in this folder.
<Modal size="md" title="Collection Runner" hideFooter={true} handleCancel={onClose}>
<div className="mb-1">
<span className="font-medium">Run</span>
<span className="ml-1 text-xs">({runLength} requests)</span>
</div>
<div className="mb-8">This will only run the requests in this folder.</div>
<div className='mb-1'>
<span className='font-medium'>Recursive Run</span>
<span className='ml-1 text-xs'>({recursiveRunLength} requests)</span>
</div>
<div className='mb-8'>
This will run all the requests in this folder and all its subfolders.
<div className="mb-1">
<span className="font-medium">Recursive Run</span>
<span className="ml-1 text-xs">({recursiveRunLength} requests)</span>
</div>
<div className="mb-8">This will run all the requests in this folder and all its subfolders.</div>
<div className="flex justify-end bruno-modal-footer">
<span className='mr-3'>
<span className="mr-3">
<button type="button" onClick={onClose} className="btn btn-md btn-close">
Cancel
</button>

View File

@ -86,9 +86,11 @@ const CollectionItem = ({ item, collection, searchText }) => {
});
const handleClick = (event) => {
dispatch(hideRunnerView({
collectionUid: collection.uid
}));
dispatch(
hideRunnerView({
collectionUid: collection.uid
})
);
if (isItemARequest(item)) {
if (itemIsOpenedInTabs(item, tabs)) {
dispatch(
@ -151,12 +153,24 @@ const CollectionItem = ({ item, collection, searchText }) => {
return (
<StyledWrapper className={className}>
{renameItemModalOpen && <RenameCollectionItem item={item} collection={collection} onClose={() => setRenameItemModalOpen(false)} />}
{cloneItemModalOpen && <CloneCollectionItem item={item} collection={collection} onClose={() => setCloneItemModalOpen(false)} />}
{deleteItemModalOpen && <DeleteCollectionItem item={item} collection={collection} onClose={() => setDeleteItemModalOpen(false)} />}
{newRequestModalOpen && <NewRequest item={item} collection={collection} onClose={() => setNewRequestModalOpen(false)} />}
{newFolderModalOpen && <NewFolder item={item} collection={collection} onClose={() => setNewFolderModalOpen(false)} />}
{runCollectionModalOpen && <RunCollectionItem collection={collection} item={item} onClose={() => setRunCollectionModalOpen(false)} />}
{renameItemModalOpen && (
<RenameCollectionItem item={item} collection={collection} onClose={() => setRenameItemModalOpen(false)} />
)}
{cloneItemModalOpen && (
<CloneCollectionItem item={item} collection={collection} onClose={() => setCloneItemModalOpen(false)} />
)}
{deleteItemModalOpen && (
<DeleteCollectionItem item={item} collection={collection} onClose={() => setDeleteItemModalOpen(false)} />
)}
{newRequestModalOpen && (
<NewRequest item={item} collection={collection} onClose={() => setNewRequestModalOpen(false)} />
)}
{newFolderModalOpen && (
<NewFolder item={item} collection={collection} onClose={() => setNewFolderModalOpen(false)} />
)}
{runCollectionModalOpen && (
<RunCollectionItem collection={collection} item={item} onClose={() => setRunCollectionModalOpen(false)} />
)}
<div className={itemRowClassName} ref={(node) => drag(drop(node))}>
<div className="flex items-center h-full w-full">
{indents && indents.length
@ -185,7 +199,14 @@ const CollectionItem = ({ item, collection, searchText }) => {
}}
>
<div style={{ width: 16, minWidth: 16 }}>
{isFolder ? <IconChevronRight size={16} strokeWidth={2} className={iconClassName} style={{ color: 'rgb(160 160 160)' }} /> : null}
{isFolder ? (
<IconChevronRight
size={16}
strokeWidth={2}
className={iconClassName}
style={{ color: 'rgb(160 160 160)' }}
/>
) : null}
</div>
<div className="ml-1 flex items-center overflow-hidden">

View File

@ -15,7 +15,10 @@ const RenameCollection = ({ collection, onClose }) => {
name: collection.name
},
validationSchema: Yup.object({
name: Yup.string().min(1, 'must be atleast 1 characters').max(50, 'must be 50 characters or less').required('name is required')
name: Yup.string()
.min(1, 'must be atleast 1 characters')
.max(50, 'must be 50 characters or less')
.required('name is required')
}),
onSubmit: (values) => {
dispatch(renameCollection(values.name, collection.uid));

View File

@ -97,13 +97,26 @@ const Collection = ({ collection, searchText }) => {
<StyledWrapper className="flex flex-col">
{showNewRequestModal && <NewRequest collection={collection} onClose={() => setShowNewRequestModal(false)} />}
{showNewFolderModal && <NewFolder collection={collection} onClose={() => setShowNewFolderModal(false)} />}
{showRenameCollectionModal && <RenameCollection collection={collection} onClose={() => setShowRenameCollectionModal(false)} />}
{showRemoveCollectionModal && <RemoveCollection collection={collection} onClose={() => setShowRemoveCollectionModal(false)} />}
{showRunCollectionModal && <RunCollectionItem collection={collection} onClose={() => setShowRunCollectionModal(false)} />}
{showRenameCollectionModal && (
<RenameCollection collection={collection} onClose={() => setShowRenameCollectionModal(false)} />
)}
{showRemoveCollectionModal && (
<RemoveCollection collection={collection} onClose={() => setShowRemoveCollectionModal(false)} />
)}
{showRunCollectionModal && (
<RunCollectionItem collection={collection} onClose={() => setShowRunCollectionModal(false)} />
)}
<div className="flex py-1 collection-name items-center" ref={drop}>
<div className="flex flex-grow items-center overflow-hidden" onClick={handleClick}>
<IconChevronRight size={16} strokeWidth={2} className={iconClassName} style={{ width: 16, minWidth:16, color: 'rgb(160 160 160)' }} />
<div className="ml-1" id="sidebar-collection-name">{collection.name}</div>
<IconChevronRight
size={16}
strokeWidth={2}
className={iconClassName}
style={{ width: 16, minWidth: 16, color: 'rgb(160 160 160)' }}
/>
<div className="ml-1" id="sidebar-collection-name">
{collection.name}
</div>
</div>
<div className="collection-actions">
<Dropdown onCreate={onMenuDropdownCreate} icon={<MenuIcon />} placement="bottom-start">

View File

@ -18,10 +18,16 @@ const CreateOrOpenCollection = () => {
const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false);
const handleOpenCollection = () => {
dispatch(openCollection()).catch((err) => console.log(err) && toast.error('An error occured while opening the collection'));
dispatch(openCollection()).catch(
(err) => console.log(err) && toast.error('An error occured while opening the collection')
);
};
const CreateLink = () => (
<LinkStyle className="underline text-link cursor-pointer" theme={theme} onClick={() => setCreateCollectionModalOpen(true)}>
<LinkStyle
className="underline text-link cursor-pointer"
theme={theme}
onClick={() => setCreateCollectionModalOpen(true)}
>
Create
</LinkStyle>
);

View File

@ -10,7 +10,7 @@ const StyledWrapper = styled.div`
cursor: pointer;
&:hover {
background-color: ${(props) => props.theme.plainGrid.hoverBg};;
background-color: ${(props) => props.theme.plainGrid.hoverBg};
}
}
`;

View File

@ -20,8 +20,14 @@ const CreateCollection = ({ onClose }) => {
collectionLocation: ''
},
validationSchema: Yup.object({
collectionName: Yup.string().min(1, 'must be atleast 1 characters').max(50, 'must be 50 characters or less').required('collection name is required'),
collectionFolderName: Yup.string().min(1, 'must be atleast 1 characters').max(50, 'must be 50 characters or less').required('folder name is required'),
collectionName: Yup.string()
.min(1, 'must be atleast 1 characters')
.max(50, 'must be 50 characters or less')
.required('collection name is required'),
collectionFolderName: Yup.string()
.min(1, 'must be atleast 1 characters')
.max(50, 'must be 50 characters or less')
.required('folder name is required'),
collectionLocation: Yup.string().required('location is required')
}),
onSubmit: (values) => {
@ -58,8 +64,8 @@ const CreateCollection = ({ onClose }) => {
<form className="bruno-form" onSubmit={formik.handleSubmit}>
<div>
<label htmlFor="collectionName" className="flex items-center">
<span className='font-semibold'>Name</span>
<Tooltip text="Name of the collection" tooltipId="collection-name"/>
<span className="font-semibold">Name</span>
<Tooltip text="Name of the collection" tooltipId="collection-name" />
</label>
<input
id="collection-name"
@ -74,11 +80,13 @@ const CreateCollection = ({ onClose }) => {
spellCheck="false"
value={formik.values.collectionName || ''}
/>
{formik.touched.collectionName && formik.errors.collectionName ? <div className="text-red-500">{formik.errors.collectionName}</div> : null}
{formik.touched.collectionName && formik.errors.collectionName ? (
<div className="text-red-500">{formik.errors.collectionName}</div>
) : null}
<label htmlFor="collectionFolderName" className="flex items-center mt-3">
<span className='font-semibold'>Folder Name</span>
<Tooltip text="Name of the folder where your collection is stored" tooltipId="collection-folder-name"/>
<span className="font-semibold">Folder Name</span>
<Tooltip text="Name of the folder where your collection is stored" tooltipId="collection-folder-name" />
</label>
<input
id="collection-folder-name"
@ -92,7 +100,9 @@ const CreateCollection = ({ onClose }) => {
spellCheck="false"
value={formik.values.collectionFolderName || ''}
/>
{formik.touched.collectionFolderName && formik.errors.collectionFolderName ? <div className="text-red-500">{formik.errors.collectionFolderName}</div> : null}
{formik.touched.collectionFolderName && formik.errors.collectionFolderName ? (
<div className="text-red-500">{formik.errors.collectionFolderName}</div>
) : null}
<>
<label htmlFor="collectionLocation" className="block font-semibold mt-3">

View File

@ -33,22 +33,13 @@ const ImportCollection = ({ onClose, handleSubmit }) => {
return (
<Modal size="sm" title="Import Collection" hideFooter={true} handleConfirm={onClose} handleCancel={onClose}>
<div>
<div
className='text-link hover:underline cursor-pointer'
onClick={handleImportBrunoCollection}
>
<div className="text-link hover:underline cursor-pointer" onClick={handleImportBrunoCollection}>
Bruno Collection
</div>
<div
className='text-link hover:underline cursor-pointer mt-2'
onClick={handleImportPostmanCollection}
>
<div className="text-link hover:underline cursor-pointer mt-2" onClick={handleImportPostmanCollection}>
Postman Collection
</div>
<div
className='text-link hover:underline cursor-pointer mt-2'
onClick={handleImportInsomniaCollection}
>
<div className="text-link hover:underline cursor-pointer mt-2" onClick={handleImportInsomniaCollection}>
Insomnia Collection
</div>
</div>

View File

@ -15,7 +15,10 @@ const ImportCollectionLocation = ({ onClose, handleSubmit, collectionName }) =>
collectionLocation: ''
},
validationSchema: Yup.object({
collectionLocation: Yup.string().min(1, 'must be atleast 1 characters').max(500, 'must be 500 characters or less').required('name is required')
collectionLocation: Yup.string()
.min(1, 'must be atleast 1 characters')
.max(500, 'must be 500 characters or less')
.required('name is required')
}),
onSubmit: (values) => {
console.log('here');
@ -49,7 +52,7 @@ const ImportCollectionLocation = ({ onClose, handleSubmit, collectionName }) =>
<label htmlFor="collectionName" className="block font-semibold">
Name
</label>
<div className='mt-2'>{collectionName}</div>
<div className="mt-2">{collectionName}</div>
<>
<label htmlFor="collectionLocation" className="block font-semibold mt-3">

View File

@ -21,11 +21,11 @@ const NewFolder = ({ collection, item, onClose }) => {
.test({
name: 'folderName',
message: 'The folder name "environments" at the root of the collection is reserved in bruno',
test:(value) => {
if(item && item.uid) {
test: (value) => {
if (item && item.uid) {
return true;
}
return value && !(value.trim().toLowerCase().includes('environments'))
return value && !value.trim().toLowerCase().includes('environments');
}
})
}),
@ -64,7 +64,9 @@ const NewFolder = ({ collection, item, onClose }) => {
onChange={formik.handleChange}
value={formik.values.folderName || ''}
/>
{formik.touched.folderName && formik.errors.folderName ? <div className="text-red-500">{formik.errors.folderName}</div> : null}
{formik.touched.folderName && formik.errors.folderName ? (
<div className="text-red-500">{formik.errors.folderName}</div>
) : null}
</div>
</form>
</Modal>

View File

@ -30,7 +30,7 @@ const NewRequest = ({ collection, item, isEphermal, onClose }) => {
.test({
name: 'requestName',
message: 'The request name "index" is reserved in bruno',
test: value => value && !(value.trim().toLowerCase().includes('index')),
test: (value) => value && !value.trim().toLowerCase().includes('index')
})
}),
onSubmit: (values) => {
@ -51,7 +51,7 @@ const NewRequest = ({ collection, item, isEphermal, onClose }) => {
addTab({
uid: uid,
collectionUid: collection.uid,
requestPaneTab: getDefaultRequestPaneTab({type: values.requestType})
requestPaneTab: getDefaultRequestPaneTab({ type: values.requestType })
})
);
onClose();
@ -140,7 +140,9 @@ const NewRequest = ({ collection, item, isEphermal, onClose }) => {
onChange={formik.handleChange}
value={formik.values.requestName || ''}
/>
{formik.touched.requestName && formik.errors.requestName ? <div className="text-red-500">{formik.errors.requestName}</div> : null}
{formik.touched.requestName && formik.errors.requestName ? (
<div className="text-red-500">{formik.errors.requestName}</div>
) : null}
</div>
<div className="mt-4">
@ -150,7 +152,10 @@ const NewRequest = ({ collection, item, isEphermal, onClose }) => {
<div className="flex items-center mt-2 ">
<div className="flex items-center h-full method-selector-container">
<HttpMethodSelector method={formik.values.requestMethod} onMethodSelect={(val) => formik.setFieldValue('requestMethod', val)} />
<HttpMethodSelector
method={formik.values.requestMethod}
onMethodSelect={(val) => formik.setFieldValue('requestMethod', val)}
/>
</div>
<div className="flex items-center flex-grow input-container h-full">
<input
@ -167,7 +172,9 @@ const NewRequest = ({ collection, item, isEphermal, onClose }) => {
/>
</div>
</div>
{formik.touched.requestUrl && formik.errors.requestUrl ? <div className="text-red-500">{formik.errors.requestUrl}</div> : null}
{formik.touched.requestUrl && formik.errors.requestUrl ? (
<div className="text-red-500">{formik.errors.requestUrl}</div>
) : null}
</div>
</form>
</Modal>

View File

@ -32,7 +32,7 @@ const Wrapper = styled.div`
input {
border: ${(props) => props.theme.sidebar.search.border};
border-radius: 2px;
background-color: ${(props) => props.theme.sidebar.search.bg};
background-color: ${(props) => props.theme.sidebar.search.bg};
&:focus {
outline: none;

View File

@ -45,20 +45,24 @@ const TitleBar = () => {
const handleTitleClick = () => dispatch(showHomePage());
const handleOpenCollection = () => {
dispatch(openCollection()).catch((err) => console.log(err) && toast.error('An error occured while opening the collection'));
dispatch(openCollection()).catch(
(err) => console.log(err) && toast.error('An error occured while opening the collection')
);
};
return (
<StyledWrapper className="px-2 py-2">
{createCollectionModalOpen ? <CreateCollection onClose={() => setCreateCollectionModalOpen(false)} /> : null}
{importCollectionModalOpen ? <ImportCollection onClose={() => setImportCollectionModalOpen(false)} handleSubmit={handleImportCollection} /> : null}
{importCollectionModalOpen ? (
<ImportCollection onClose={() => setImportCollectionModalOpen(false)} handleSubmit={handleImportCollection} />
) : null}
{importCollectionLocationModalOpen ? (
<ImportCollectionLocation
collectionName={importedCollection.name}
onClose={() => setImportCollectionLocationModalOpen(false)}
handleSubmit={handleImportCollectionLocation}
/>
): null}
) : null}
<div className="flex items-center">
<div className="flex items-center cursor-pointer" onClick={handleTitleClick}>

View File

@ -88,7 +88,12 @@ const Sidebar = () => {
<div className="footer flex px-1 py-2 absolute bottom-0 left-0 right-0 items-center cursor-pointer select-none">
<div className="flex items-center ml-1 text-xs ">
<IconSettings size={18} strokeWidth={1.5} className="mr-2 hover:text-gray-700" onClick={() => setPreferencesOpen(true)} />
<IconSettings
size={18}
strokeWidth={1.5}
className="mr-2 hover:text-gray-700"
onClick={() => setPreferencesOpen(true)}
/>
</div>
<div className="pl-1" style={{ position: 'relative', top: '3px' }}>
{storedTheme === 'dark' ? (

View File

@ -49,7 +49,6 @@ const StyledWrapper = styled.div`
padding-right: 0;
}
}
`;
export default StyledWrapper;

View File

@ -27,32 +27,32 @@ class SingleLineEditor extends Component {
lineWrapping: false,
lineNumbers: false,
theme: this.props.theme === 'dark' ? 'monokai' : 'default',
mode: "brunovariables",
mode: 'brunovariables',
brunoVarInfo: {
variables: getAllVariables(this.props.collection),
variables: getAllVariables(this.props.collection)
},
extraKeys: {
"Enter": () => {
Enter: () => {
if (this.props.onRun) {
this.props.onRun();
}
},
"Ctrl-Enter": () => {
'Ctrl-Enter': () => {
if (this.props.onRun) {
this.props.onRun();
}
},
"Cmd-Enter": () => {
'Cmd-Enter': () => {
if (this.props.onRun) {
this.props.onRun();
}
},
"Alt-Enter": () => {
'Alt-Enter': () => {
if (this.props.onRun) {
this.props.onRun();
}
},
"Shift-Enter": () => {
'Shift-Enter': () => {
if (this.props.onRun) {
this.props.onRun();
}
@ -69,8 +69,8 @@ class SingleLineEditor extends Component {
},
'Cmd-F': () => {},
'Ctrl-F': () => {},
'Tab': () => {}
},
Tab: () => {}
}
});
this.editor.setValue(this.props.value || '');
this.editor.on('change', this._onEdit);
@ -115,14 +115,12 @@ class SingleLineEditor extends Component {
let variables = getAllVariables(this.props.collection);
this.variables = variables;
defineCodeMirrorBrunoVariablesMode(variables, "text/plain");
defineCodeMirrorBrunoVariablesMode(variables, 'text/plain');
this.editor.setOption('mode', 'brunovariables');
}
};
render() {
return (
<StyledWrapper ref={this.editorRef} className="single-line-editor"></StyledWrapper>
);
return <StyledWrapper ref={this.editorRef} className="single-line-editor"></StyledWrapper>;
}
}
export default SingleLineEditor;

View File

@ -4,9 +4,19 @@ import { Tooltip as ReactTooltip } from 'react-tooltip';
const Tooltip = ({ text, tooltipId }) => {
return (
<>
<svg tabIndex="-1" id={tooltipId} xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" className="inline-block ml-2 cursor-pointer" viewBox="0 0 16 16" style={{marginTop: 1}}>
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
<path d="M5.255 5.786a.237.237 0 0 0 .241.247h.825c.138 0 .248-.113.266-.25.09-.656.54-1.134 1.342-1.134.686 0 1.314.343 1.314 1.168 0 .635-.374.927-.965 1.371-.673.489-1.206 1.06-1.168 1.987l.003.217a.25.25 0 0 0 .25.246h.811a.25.25 0 0 0 .25-.25v-.105c0-.718.273-.927 1.01-1.486.609-.463 1.244-.977 1.244-2.056 0-1.511-1.276-2.241-2.673-2.241-1.267 0-2.655.59-2.75 2.286zm1.557 5.763c0 .533.425.927 1.01.927.609 0 1.028-.394 1.028-.927 0-.552-.42-.94-1.029-.94-.584 0-1.009.388-1.009.94z"/>
<svg
tabIndex="-1"
id={tooltipId}
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
fill="currentColor"
className="inline-block ml-2 cursor-pointer"
viewBox="0 0 16 16"
style={{ marginTop: 1 }}
>
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
<path d="M5.255 5.786a.237.237 0 0 0 .241.247h.825c.138 0 .248-.113.266-.25.09-.656.54-1.134 1.342-1.134.686 0 1.314.343 1.314 1.168 0 .635-.374.927-.965 1.371-.673.489-1.206 1.06-1.168 1.987l.003.217a.25.25 0 0 0 .25.246h.811a.25.25 0 0 0 .25-.25v-.105c0-.718.273-.927 1.01-1.486.609-.463 1.244-.977 1.244-2.056 0-1.511-1.276-2.241-2.673-2.241-1.267 0-2.655.59-2.75 2.286zm1.557 5.763c0 .533.425.927 1.01.927.609 0 1.028-.394 1.028-.927 0-.552-.42-.94-1.029-.94-.584 0-1.009.388-1.009.94z" />
</svg>
<ReactTooltip anchorId={tooltipId} content={text} />
</>

View File

@ -16,4 +16,4 @@ const Wrapper = styled.div`
}
`;
export default Wrapper;
export default Wrapper;

View File

@ -1,16 +1,12 @@
import React, {useRef} from 'react';
import React, { useRef } from 'react';
import StyledWrapper from './StyledWrapper';
import useOnClickOutside from 'hooks/useOnClickOutside';
const PopOver = ({
children,
iconRef,
handleClose
}) => {
const PopOver = ({ children, iconRef, handleClose }) => {
const popOverRef = useRef(null);
useOnClickOutside(popOverRef, (e) => {
if(iconRef && iconRef.current) {
if (iconRef && iconRef.current) {
if (e.target == iconRef.current || iconRef.current.contains(e.target)) {
return;
}
@ -27,4 +23,4 @@ const PopOver = ({
);
};
export default PopOver;
export default PopOver;

View File

@ -10,6 +10,6 @@ const StyledWrapper = styled.div`
width: 1rem;
font-size: 10px;
}
`
`;
export default StyledWrapper;
export default StyledWrapper;

View File

@ -5,8 +5,8 @@ const StyledWrapper = styled.div`
color: ${(props) => props.theme.variables.name.color};
}
.variable-name{
min-width:180px;
.variable-name {
min-width: 180px;
}
.variable-value {
@ -14,6 +14,6 @@ const StyledWrapper = styled.div`
inline-size: 600px;
overflow-wrap: break-word;
}
`
`;
export default StyledWrapper;
export default StyledWrapper;

View File

@ -18,25 +18,33 @@ const VariablesTable = ({ variables, collectionVariables }) => {
return (
<StyledWrapper>
<div className="flex flex-col w-full">
<div className='mb-2 font-medium'>Environment Variables</div>
{(variables && variables.length) ? variables.map((variable) => {
return (
<div key={variable.uid} className="flex">
<div className='variable-name text-yellow-600 text-right pr-2'>{variable.name}</div>
<div className='variable-value pl-2 whitespace-normal text-left flex-grow'>{variable.value}</div>
</div>
);
}) : <small>No env variables found</small>}
<div className="mb-2 font-medium">Environment Variables</div>
{variables && variables.length ? (
variables.map((variable) => {
return (
<div key={variable.uid} className="flex">
<div className="variable-name text-yellow-600 text-right pr-2">{variable.name}</div>
<div className="variable-value pl-2 whitespace-normal text-left flex-grow">{variable.value}</div>
</div>
);
})
) : (
<small>No env variables found</small>
)}
<div className='mt-2 font-medium'>Collection Variables</div>
{(collectionVars && collectionVars.length) ? collectionVars.map((variable) => {
return (
<div key={variable.uid} className="flex">
<div className='variable-name text-yellow-600 text-right pr-2'>{variable.name}</div>
<div className='variable-value pl-2 whitespace-normal text-left flex-grow'>{variable.value}</div>
</div>
);
}) : <small>No collection variables found</small>}
<div className="mt-2 font-medium">Collection Variables</div>
{collectionVars && collectionVars.length ? (
collectionVars.map((variable) => {
return (
<div key={variable.uid} className="flex">
<div className="variable-name text-yellow-600 text-right pr-2">{variable.name}</div>
<div className="variable-value pl-2 whitespace-normal text-left flex-grow">{variable.value}</div>
</div>
);
})
) : (
<small>No collection variables found</small>
)}
</div>
</StyledWrapper>
);

View File

@ -7,46 +7,42 @@ import StyledWrapper from './StyledWrapper';
import PopOver from './Popover';
import { IconEye } from '@tabler/icons';
const VariablesView = ({collection}) => {
const VariablesView = ({ collection }) => {
const iconRef = useRef(null);
const [popOverOpen, setPopOverOpen] = useState(false);
const environment = findEnvironmentInCollection(collection, collection.activeEnvironmentUid);
const variables = get(environment, 'variables', []);
const enabledVariables = filter(variables, (variable) => variable.enabled);
const showVariablesTable = enabledVariables.length > 0 || (collection.collectionVariables && Object.keys(collection.collectionVariables).length > 0);
const showVariablesTable =
enabledVariables.length > 0 ||
(collection.collectionVariables && Object.keys(collection.collectionVariables).length > 0);
return (
<StyledWrapper
className="mr-2 server-syncstatus-icon"
ref={iconRef}
>
<div className="flex p-1 items-center"
<StyledWrapper className="mr-2 server-syncstatus-icon" ref={iconRef}>
<div
className="flex p-1 items-center"
onClick={() => setPopOverOpen(true)}
onMouseEnter={() => setPopOverOpen(true)}
onMouseLeave={() => setPopOverOpen(false)}
>
<div className='cursor-pointer view-environment'>
<div className="cursor-pointer view-environment">
<IconEye size={18} strokeWidth={1.5} />
</div>
{popOverOpen && (
<PopOver
iconRef={iconRef}
handleClose={() => setPopOverOpen(false)}
>
<PopOver iconRef={iconRef} handleClose={() => setPopOverOpen(false)}>
<div className="px-2 py-1">
{showVariablesTable ? (
<VariablesTable
variables={enabledVariables}
collectionVariables={collection.collectionVariables}
/>
) : 'No variables found'}
<VariablesTable variables={enabledVariables} collectionVariables={collection.collectionVariables} />
) : (
'No variables found'
)}
</div>
</PopOver>
)}
</div>
</StyledWrapper>
)
);
};
export default VariablesView;
export default VariablesView;

View File

@ -18,7 +18,9 @@ const Welcome = () => {
const [importCollectionLocationModalOpen, setImportCollectionLocationModalOpen] = useState(false);
const handleOpenCollection = () => {
dispatch(openCollection()).catch((err) => console.log(err) && toast.error('An error occured while opening the collection'));
dispatch(openCollection()).catch(
(err) => console.log(err) && toast.error('An error occured while opening the collection')
);
};
const handleImportCollection = (collection) => {
@ -37,14 +39,16 @@ const Welcome = () => {
return (
<StyledWrapper className="pb-4 px-6 mt-6">
{createCollectionModalOpen ? <CreateCollection onClose={() => setCreateCollectionModalOpen(false)} /> : null}
{importCollectionModalOpen ? <ImportCollection onClose={() => setImportCollectionModalOpen(false)} handleSubmit={handleImportCollection} /> : null}
{importCollectionModalOpen ? (
<ImportCollection onClose={() => setImportCollectionModalOpen(false)} handleSubmit={handleImportCollection} />
) : null}
{importCollectionLocationModalOpen ? (
<ImportCollectionLocation
collectionName={importedCollection.name}
onClose={() => setImportCollectionLocationModalOpen(false)}
handleSubmit={handleImportCollectionLocation}
/>
): null}
) : null}
<div className="">
<Bruno width={50} />
@ -61,14 +65,14 @@ const Welcome = () => {
</span>
</div>
<div className="flex items-center ml-6" onClick={handleOpenCollection}>
<IconFolders size={18} strokeWidth={2} />
<span className="label ml-2">
Open Collection
</span>
</div>
<IconFolders size={18} strokeWidth={2} />
<span className="label ml-2">Open Collection</span>
</div>
<div className="flex items-center ml-6" onClick={() => setImportCollectionModalOpen(true)}>
<IconUpload size={18} strokeWidth={2} />
<span className="label ml-2" id="import-collection">Import Collection</span>
<span className="label ml-2" id="import-collection">
Import Collection
</span>
</div>
</div>

View File

@ -4,7 +4,7 @@ import { useEffect } from 'react';
const useOnClickOutside = (ref, handler) => {
useEffect(
() => {
const listener = event => {
const listener = (event) => {
// Do nothing if clicking ref's element or descendent elements
if (!ref.current || ref.current.contains(event.target)) {
return;
@ -31,4 +31,4 @@ const useOnClickOutside = (ref, handler) => {
);
};
export default useOnClickOutside;
export default useOnClickOutside;

View File

@ -5,9 +5,9 @@ function usePrevious(value) {
useEffect(() => {
ref.current = value; //assign the value of ref to the argument
},[value]); //this code will run when the value of 'value' changes
}, [value]); //this code will run when the value of 'value' changes
return ref.current; //in the end, return the current ref value.
}
export default usePrevious;
export default usePrevious;

View File

@ -36,7 +36,7 @@ function MyApp({ Component, pageProps }) {
setDomLoaded(true);
}, []);
if(!domLoaded) {
if (!domLoaded) {
return null;
}

View File

@ -31,7 +31,10 @@ export default class MyDocument extends Document {
return (
<Html>
<Head>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
</Head>
<body id="bruno-app-body">
<Main />

View File

@ -1,7 +1,7 @@
import styled from 'styled-components';
const StyledWrapper = styled.div`
color: ${(props) => props.theme.text};
color: ${(props) => props.theme.text};
background-color: ${(props) => props.theme.bg};
`;

View File

@ -29,9 +29,7 @@ export const AppProvider = (props) => {
return (
<AppContext.Provider {...props} value="appProvider">
<StyledWrapper>
{props.children}
</StyledWrapper>
<StyledWrapper>{props.children}</StyledWrapper>
</AppContext.Provider>
);
};

View File

@ -31,7 +31,7 @@ const useCollectionTreeSync = () => {
};
const _collectionTreeUpdated = (type, val) => {
if(window.__IS_DEV__) {
if (window.__IS_DEV__) {
console.log(type);
console.log(val);
}
@ -85,10 +85,10 @@ const useCollectionTreeSync = () => {
};
const _displayError = (error) => {
if(typeof error === "string") {
if (typeof error === 'string') {
return toast.error(error || 'Something went wrong!');
}
if(typeof message === "object") {
if (typeof message === 'object') {
return toast.error(error.message || 'Something went wrong!');
}
};

View File

@ -23,7 +23,7 @@ const getPlatform = () => {
};
const getPosthogClient = () => {
if(posthogClient) {
if (posthogClient) {
return posthogClient;
}
@ -34,7 +34,7 @@ const getPosthogClient = () => {
const getAnonymousTrackingId = () => {
let id = localStorage.getItem('bruno.anonymousTrackingId');
if(!id || !id.length || id.length !== 21) {
if (!id || !id.length || id.length !== 21) {
id = uuid();
localStorage.setItem('bruno.anonymousTrackingId', id);
}
@ -43,11 +43,11 @@ const getAnonymousTrackingId = () => {
};
const trackStart = () => {
if(isPlaywrightTestRunning()) {
if (isPlaywrightTestRunning()) {
return;
}
if(isDevEnv()) {
if (isDevEnv()) {
return;
}
@ -67,7 +67,7 @@ const trackStart = () => {
const useTelemetry = () => {
useEffect(() => {
trackStart();
setInterval(trackStart , 24 * 60 * 60 * 1000);
setInterval(trackStart, 24 * 60 * 60 * 1000);
}, []);
};

View File

@ -165,9 +165,15 @@ export const HotkeysProvider = (props) => {
return (
<HotkeysContext.Provider {...props} value="hotkey">
{showBrunoSupportModal && <BrunoSupport onClose={() => setShowBrunoSupportModal(false)} />}
{showSaveRequestModal && <SaveRequest items={getCurrentCollectionItems()} onClose={() => setShowSaveRequestModal(false)} />}
{showEnvSettingsModal && <EnvironmentSettings collection={getCurrentCollection()} onClose={() => setShowEnvSettingsModal(false)} />}
{showNewRequestModal && <NewRequest collection={getCurrentCollection()} onClose={() => setShowNewRequestModal(false)} />}
{showSaveRequestModal && (
<SaveRequest items={getCurrentCollectionItems()} onClose={() => setShowSaveRequestModal(false)} />
)}
{showEnvSettingsModal && (
<EnvironmentSettings collection={getCurrentCollection()} onClose={() => setShowEnvSettingsModal(false)} />
)}
{showNewRequestModal && (
<NewRequest collection={getCurrentCollection()} onClose={() => setShowNewRequestModal(false)} />
)}
<div>{props.children}</div>
</HotkeysContext.Provider>
);

View File

@ -1,9 +1,9 @@
/**
* 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.
*/
@ -30,21 +30,20 @@ export const PreferencesProvider = (props) => {
const { ipcRenderer } = window;
useEffect(() => {
ipcRenderer
.invoke('renderer:set-preferences', preferences)
.catch(err => {
toast.error(err.message || 'Preferences sync error');
});
ipcRenderer.invoke('renderer:set-preferences', preferences).catch((err) => {
toast.error(err.message || 'Preferences sync error');
});
}, [preferences, toast]);
const validatedSetPreferences = (newPreferences) => {
return new Promise((resolve, reject) => {
preferencesSchema.validate(newPreferences, { abortEarly: true })
.then(validatedPreferences => {
preferencesSchema
.validate(newPreferences, { abortEarly: true })
.then((validatedPreferences) => {
setPreferences(validatedPreferences);
resolve(validatedPreferences);
})
.catch(error => {
.catch((error) => {
let errMsg = error.message || 'Preferences validation error';
toast.error(errMsg);
reject(error);
@ -60,9 +59,7 @@ export const PreferencesProvider = (props) => {
return (
<PreferencesContext.Provider value={value}>
<>
{props.children}
</>
<>{props.children}</>
</PreferencesContext.Provider>
);
};

View File

@ -33,6 +33,13 @@ export const appSlice = createSlice({
}
});
export const { idbConnectionReady, refreshScreenWidth, updateLeftSidebarWidth, updateIsDragging, showHomePage, hideHomePage } = appSlice.actions;
export const {
idbConnectionReady,
refreshScreenWidth,
updateLeftSidebarWidth,
updateIsDragging,
showHomePage,
hideHomePage
} = appSlice.actions;
export default appSlice.reducer;

View File

@ -56,10 +56,7 @@ export const renameCollection = (newName, collectionUid) => (dispatch, getState)
return reject(new Error('Collection not found'));
}
ipcRenderer
.invoke('renderer:rename-collection', newName, collection.pathname)
.then(resolve)
.catch(reject);
ipcRenderer.invoke('renderer:rename-collection', newName, collection.pathname).then(resolve).catch(reject);
});
};
@ -123,7 +120,7 @@ export const sendRequest = (item, collectionUid) => (dispatch, getState) => {
})
);
if(err && err.message === "Error invoking remote method 'send-http-request': Error: Request cancelled") {
if (err && err.message === "Error invoking remote method 'send-http-request': Error: Request cancelled") {
console.log('>> request cancelled');
return;
}
@ -166,12 +163,21 @@ export const runCollectionFolder = (collectionUid, folderUid, recursive) => (dis
const environment = findEnvironmentInCollection(collectionCopy, collection.activeEnvironmentUid);
dispatch(resetRunResults({
collectionUid: collection.uid
}));
dispatch(
resetRunResults({
collectionUid: collection.uid
})
);
ipcRenderer
.invoke('renderer:run-collection-folder', folder, collectionCopy, environment, collectionCopy.collectionVariables, recursive)
.invoke(
'renderer:run-collection-folder',
folder,
collectionCopy,
environment,
collectionCopy.collectionVariables,
recursive
)
.then(resolve)
.catch((err) => {
toast.error(get(err, 'error.message') || 'Something went wrong!');
@ -190,7 +196,10 @@ export const newFolder = (folderName, collectionUid, itemUid) => (dispatch, getS
}
if (!itemUid) {
const folderWithSameNameExists = find(collection.items, (i) => i.type === 'folder' && trim(i.name) === trim(folderName));
const folderWithSameNameExists = find(
collection.items,
(i) => i.type === 'folder' && trim(i.name) === trim(folderName)
);
if (!folderWithSameNameExists) {
const fullName = `${collection.pathname}${PATH_SEPARATOR}${folderName}`;
const { ipcRenderer } = window;
@ -205,7 +214,10 @@ export const newFolder = (folderName, collectionUid, itemUid) => (dispatch, getS
} else {
const currentItem = findItemInCollection(collection, itemUid);
if (currentItem) {
const folderWithSameNameExists = find(currentItem.items, (i) => i.type === 'folder' && trim(i.name) === trim(folderName));
const folderWithSameNameExists = find(
currentItem.items,
(i) => i.type === 'folder' && trim(i.name) === trim(folderName)
);
if (!folderWithSameNameExists) {
const fullName = `${currentItem.pathname}${PATH_SEPARATOR}${folderName}`;
const { ipcRenderer } = window;
@ -250,10 +262,7 @@ export const renameItem = (newName, itemUid, collectionUid) => (dispatch, getSta
}
const { ipcRenderer } = window;
ipcRenderer
.invoke('renderer:rename-item', item.pathname, newPathname, newName)
.then(resolve)
.catch(reject);
ipcRenderer.invoke('renderer:rename-item', item.pathname, newPathname, newName).then(resolve).catch(reject);
});
};
@ -280,12 +289,15 @@ export const cloneItem = (newName, itemUid, collectionUid) => (dispatch, getStat
const itemToSave = refreshUidsInItem(transformRequestToSaveToFilesystem(item));
itemToSave.name = trim(newName);
if (!parentItem) {
const reqWithSameNameExists = find(collection.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename));
const reqWithSameNameExists = find(
collection.items,
(i) => i.type !== 'folder' && trim(i.filename) === trim(filename)
);
if (!reqWithSameNameExists) {
const fullName = `${collection.pathname}${PATH_SEPARATOR}${filename}`;
const { ipcRenderer } = window;
const requestItems = filter(collection.items, (i) => i.type !== 'folder');
itemToSave.seq = requestItems ? (requestItems.length + 1) : 1;
itemToSave.seq = requestItems ? requestItems.length + 1 : 1;
itemSchema
.validate(itemToSave)
@ -296,13 +308,16 @@ export const cloneItem = (newName, itemUid, collectionUid) => (dispatch, getStat
return reject(new Error('Duplicate request names are not allowed under the same folder'));
}
} else {
const reqWithSameNameExists = find(parentItem.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename));
const reqWithSameNameExists = find(
parentItem.items,
(i) => i.type !== 'folder' && trim(i.filename) === trim(filename)
);
if (!reqWithSameNameExists) {
const dirname = getDirectoryName(item.pathname);
const fullName = path.join(dirname, filename);
const { ipcRenderer } = window;
const requestItems = filter(parentItem.items, (i) => i.type !== 'folder');
itemToSave.seq = requestItems ? (requestItems.length + 1) : 1;
itemToSave.seq = requestItems ? requestItems.length + 1 : 1;
itemSchema
.validate(itemToSave)
@ -490,7 +505,7 @@ export const moveItemToRootOfCollection = (collectionUid, draggedItemUid) => (di
const draggedItemPathname = draggedItem.pathname;
moveCollectionItemToRootOfCollection(collectionCopy, draggedItem);
if(isItemAFolder(draggedItem)) {
if (isItemAFolder(draggedItem)) {
return ipcRenderer
.invoke('renderer:move-folder-item', draggedItemPathname, collectionCopy.pathname)
.then(resolve)
@ -542,7 +557,10 @@ export const newHttpRequest = (params) => (dispatch, getState) => {
// itemUid is null when we are creating a new request at the root level
const filename = resolveRequestFilename(requestName);
if (!itemUid) {
const reqWithSameNameExists = find(collection.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename));
const reqWithSameNameExists = find(
collection.items,
(i) => i.type !== 'folder' && trim(i.filename) === trim(filename)
);
const requestItems = filter(collection.items, (i) => i.type !== 'folder');
item.seq = requestItems.length + 1;
@ -557,7 +575,10 @@ export const newHttpRequest = (params) => (dispatch, getState) => {
} else {
const currentItem = findItemInCollection(collection, itemUid);
if (currentItem) {
const reqWithSameNameExists = find(currentItem.items, (i) => i.type !== 'folder' && trim(i.filename) === trim(filename));
const reqWithSameNameExists = find(
currentItem.items,
(i) => i.type !== 'folder' && trim(i.filename) === trim(filename)
);
const requestItems = filter(currentItem.items, (i) => i.type !== 'folder');
item.seq = requestItems.length + 1;
if (!reqWithSameNameExists) {
@ -583,13 +604,17 @@ export const addEnvironment = (name, collectionUid) => (dispatch, getState) => {
ipcRenderer
.invoke('renderer:create-environment', collection.pathname, name)
.then(dispatch(updateLastAction({
collectionUid,
lastAction: {
type: 'ADD_ENVIRONMENT',
payload: name
}
})))
.then(
dispatch(
updateLastAction({
collectionUid,
lastAction: {
type: 'ADD_ENVIRONMENT',
payload: name
}
})
)
)
.then(resolve)
.catch(reject);
});
@ -793,9 +818,6 @@ export const importCollection = (collection, collectionLocation) => (dispatch, g
return new Promise((resolve, reject) => {
const { ipcRenderer } = window;
ipcRenderer
.invoke('renderer:import-collection', collection, collectionLocation)
.then(resolve)
.catch(reject);
ipcRenderer.invoke('renderer:import-collection', collection, collectionLocation).then(resolve).catch(reject);
});
};

View File

@ -482,7 +482,10 @@ export const collectionsSlice = createSlice({
if (!item.draft) {
item.draft = cloneDeep(item);
}
item.draft.request.body.formUrlEncoded = filter(item.draft.request.body.formUrlEncoded, (p) => p.uid !== action.payload.paramUid);
item.draft.request.body.formUrlEncoded = filter(
item.draft.request.body.formUrlEncoded,
(p) => p.uid !== action.payload.paramUid
);
}
}
},
@ -537,7 +540,10 @@ export const collectionsSlice = createSlice({
if (!item.draft) {
item.draft = cloneDeep(item);
}
item.draft.request.body.multipartForm = filter(item.draft.request.body.multipartForm, (p) => p.uid !== action.payload.paramUid);
item.draft.request.body.multipartForm = filter(
item.draft.request.body.multipartForm,
(p) => p.uid !== action.payload.paramUid
);
}
}
},
@ -729,7 +735,9 @@ export const collectionsSlice = createSlice({
if (!item.draft) {
item.draft = cloneDeep(item);
}
item.draft.request.assertions = item.draft.request.assertions.filter((a) => a.uid !== action.payload.assertUid);
item.draft.request.assertions = item.draft.request.assertions.filter(
(a) => a.uid !== action.payload.assertUid
);
}
}
},
@ -744,7 +752,7 @@ export const collectionsSlice = createSlice({
if (!item.draft) {
item.draft = cloneDeep(item);
}
if(type === 'request') {
if (type === 'request') {
item.draft.request.vars = item.draft.request.vars || {};
item.draft.request.vars.req = item.draft.request.vars.req || [];
item.draft.request.vars.req.push({
@ -754,7 +762,7 @@ export const collectionsSlice = createSlice({
local: false,
enabled: true
});
} else if(type === 'response') {
} else if (type === 'response') {
item.draft.request.vars = item.draft.request.vars || {};
item.draft.request.vars.res = item.draft.request.vars.res || [];
item.draft.request.vars.res.push({
@ -779,7 +787,7 @@ export const collectionsSlice = createSlice({
if (!item.draft) {
item.draft = cloneDeep(item);
}
if(type === 'request') {
if (type === 'request') {
item.draft.request.vars = item.draft.request.vars || {};
item.draft.request.vars.req = item.draft.request.vars.req || [];
@ -790,7 +798,7 @@ export const collectionsSlice = createSlice({
reqVar.description = action.payload.var.description;
reqVar.enabled = action.payload.var.enabled;
}
} else if(type === 'response') {
} else if (type === 'response') {
item.draft.request.vars = item.draft.request.vars || {};
item.draft.request.vars.res = item.draft.request.vars.res || [];
const resVar = find(item.draft.request.vars.res, (v) => v.uid === action.payload.var.uid);
@ -815,11 +823,11 @@ export const collectionsSlice = createSlice({
if (!item.draft) {
item.draft = cloneDeep(item);
}
if(type === 'request') {
if (type === 'request') {
item.draft.request.vars = item.draft.request.vars || {};
item.draft.request.vars.req = item.draft.request.vars.req || [];
item.draft.request.vars.req = item.draft.request.vars.req.filter((v) => v.uid !== action.payload.varUid);
} else if(type === 'response') {
} else if (type === 'response') {
item.draft.request.vars = item.draft.request.vars || {};
item.draft.request.vars.res = item.draft.request.vars.res || [];
item.draft.request.vars.res = item.draft.request.vars.res.filter((v) => v.uid !== action.payload.varUid);
@ -922,7 +930,7 @@ export const collectionsSlice = createSlice({
// whenever a user attempts to sort a req within the same folder
// the seq is updated, but everything else remains the same
// we don't want to lose the draft in this case
if(areItemsTheSameExceptSeqUpdate(item, file.data)) {
if (areItemsTheSameExceptSeqUpdate(item, file.data)) {
item.seq = file.data.seq;
} else {
item.name = file.data.name;
@ -968,16 +976,16 @@ export const collectionsSlice = createSlice({
collection.environments = collection.environments || [];
const existingEnv = collection.environments.find((e) => e.uid === environment.uid);
if (existingEnv) {
existingEnv.variables = environment.variables;
} else {
collection.environments.push(environment);
const lastAction = collection.lastAction;
if(lastAction && lastAction.type === 'ADD_ENVIRONMENT') {
if (lastAction && lastAction.type === 'ADD_ENVIRONMENT') {
collection.lastAction = null;
if(lastAction.payload === environment.name) {
if (lastAction.payload === environment.name) {
collection.activeEnvironmentUid = environment.uid;
}
}
@ -1031,7 +1039,7 @@ export const collectionsSlice = createSlice({
if (collection) {
const item = findItemInCollection(collection, itemUid);
if (item) {
if(type === 'request-queued') {
if (type === 'request-queued') {
const { cancelTokenUid } = action.payload;
item.requestUid = requestUid;
item.requestState = 'queued';
@ -1039,24 +1047,24 @@ export const collectionsSlice = createSlice({
item.cancelTokenUid = cancelTokenUid;
}
if(type === 'request-sent') {
if (type === 'request-sent') {
const { cancelTokenUid, requestSent } = action.payload;
item.requestSent = requestSent;
// sometimes the response is received before the request-sent event arrives
if(item.requestUid === requestUid && item.requestState === 'queued') {
if (item.requestUid === requestUid && item.requestState === 'queued') {
item.requestUid = requestUid;
item.requestState = 'sending';
item.cancelTokenUid = cancelTokenUid;
}
}
if(type === 'assertion-results') {
if (type === 'assertion-results') {
const { results } = action.payload;
item.assertionResults = results;
}
if(type === 'test-results') {
if (type === 'test-results') {
const { results } = action.payload;
item.testResults = results;
}
@ -1071,11 +1079,11 @@ export const collectionsSlice = createSlice({
const folder = findItemInCollection(collection, folderUid);
const request = findItemInCollection(collection, itemUid);
collection.runnerResult = collection.runnerResult || {info: {}, items: []};
collection.runnerResult = collection.runnerResult || { info: {}, items: [] };
// todo
// get startedAt and endedAt from the runner and display it in the UI
if(type === 'testrun-started') {
if (type === 'testrun-started') {
const info = collection.runnerResult.info;
info.collectionUid = collectionUid;
info.folderUid = folderUid;
@ -1083,46 +1091,45 @@ export const collectionsSlice = createSlice({
info.status = 'started';
}
if(type === 'testrun-ended') {
if (type === 'testrun-ended') {
const info = collection.runnerResult.info;
info.status = 'ended';
}
if(type === 'request-queued') {
if (type === 'request-queued') {
collection.runnerResult.items.push({
uid: request.uid,
status: 'queued'
});
}
if(type === 'request-sent') {
if (type === 'request-sent') {
const item = collection.runnerResult.items.find((i) => i.uid === request.uid);
item.status = 'running';
item.requestSent = action.payload.requestSent;
}
if(type === 'response-received') {
if (type === 'response-received') {
const item = collection.runnerResult.items.find((i) => i.uid === request.uid);
item.status = 'completed';
item.responseReceived = action.payload.responseReceived;
}
if(type === 'test-results') {
if (type === 'test-results') {
const item = collection.runnerResult.items.find((i) => i.uid === request.uid);
item.testResults = action.payload.testResults;
}
if(type === 'assertion-results') {
if (type === 'assertion-results') {
const item = collection.runnerResult.items.find((i) => i.uid === request.uid);
item.assertionResults = action.payload.assertionResults;
}
if(type === 'error') {
if (type === 'error') {
const item = collection.runnerResult.items.find((i) => i.uid === request.uid);
item.error = action.payload.error;
item.responseReceived = action.payload.responseReceived;
item.status = "error";
item.status = 'error';
}
}
},

View File

@ -80,6 +80,7 @@ export const tabsSlice = createSlice({
}
});
export const { addTab, focusTab, updateRequestPaneTabWidth, updateRequestPaneTab, updateResponsePaneTab, closeTabs } = tabsSlice.actions;
export const { addTab, focusTab, updateRequestPaneTabWidth, updateRequestPaneTab, updateResponsePaneTab, closeTabs } =
tabsSlice.actions;
export default tabsSlice.reducer;

View File

@ -6,7 +6,7 @@ import { ThemeProvider as SCThemeProvider } from 'styled-components';
export const ThemeContext = createContext();
export const ThemeProvider = (props) => {
const isBrowserThemeLight = window.matchMedia("(prefers-color-scheme: light)").matches;
const isBrowserThemeLight = window.matchMedia('(prefers-color-scheme: light)').matches;
const [storedTheme, setStoredTheme] = useLocalStorage('bruno.theme', isBrowserThemeLight ? 'light' : 'dark');
const theme = themes[storedTheme];

Some files were not shown because too many files have changed in this diff Show More