mirror of
https://github.com/usebruno/bruno.git
synced 2024-11-24 08:53:30 +01:00
feat(#197): prettier formatting on all files in packages/bruno-app
This commit is contained in:
parent
a103f41d85
commit
19a7f397bb
@ -3,5 +3,5 @@
|
|||||||
"tabWidth": 2,
|
"tabWidth": 2,
|
||||||
"semi": true,
|
"semi": true,
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"printWidth": 180
|
"printWidth": 120
|
||||||
}
|
}
|
||||||
|
@ -3,5 +3,5 @@
|
|||||||
"tabWidth": 2,
|
"tabWidth": 2,
|
||||||
"semi": true,
|
"semi": true,
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"printWidth": 180
|
"printWidth": 120
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,11 @@ const Bruno = ({ width }) => {
|
|||||||
stroke="none"
|
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"
|
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>
|
||||||
<g id="hair" />
|
<g id="hair" />
|
||||||
<g id="skin" />
|
<g id="skin" />
|
||||||
@ -84,8 +88,27 @@ const Bruno = ({ width }) => {
|
|||||||
strokeWidth="2"
|
strokeWidth="2"
|
||||||
d="M52.6309,46.4628c0,0-3.0781,6.7216-7.8049,8.2712"
|
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" />
|
<path
|
||||||
<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" />
|
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>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
|
@ -6,7 +6,8 @@ const StyledWrapper = styled.div`
|
|||||||
border: solid 1px ${(props) => props.theme.codemirror.border};
|
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;
|
background: #d2d7db;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,12 +18,14 @@ const StyledWrapper = styled.div`
|
|||||||
// Todo: dark mode temporary fix
|
// Todo: dark mode temporary fix
|
||||||
// Clean this
|
// Clean this
|
||||||
.CodeMirror.cm-s-monokai {
|
.CodeMirror.cm-s-monokai {
|
||||||
.CodeMirror-overlayscroll-horizontal div, .CodeMirror-overlayscroll-vertical div {
|
.CodeMirror-overlayscroll-horizontal div,
|
||||||
|
.CodeMirror-overlayscroll-vertical div {
|
||||||
background: #444444;
|
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;
|
color: #9cdcfe !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,8 +41,12 @@ const StyledWrapper = styled.div`
|
|||||||
color: #569cd6 !important;
|
color: #569cd6 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-variable-valid{color: green}
|
.cm-variable-valid {
|
||||||
.cm-variable-invalid{color: red}
|
color: green;
|
||||||
|
}
|
||||||
|
.cm-variable-invalid {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default StyledWrapper;
|
export default StyledWrapper;
|
||||||
|
@ -43,7 +43,7 @@ export default class CodeEditor extends React.Component {
|
|||||||
foldGutter: true,
|
foldGutter: true,
|
||||||
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
|
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
|
||||||
readOnly: this.props.readOnly,
|
readOnly: this.props.readOnly,
|
||||||
scrollbarStyle: "overlay",
|
scrollbarStyle: 'overlay',
|
||||||
theme: this.props.theme === 'dark' ? 'monokai' : 'default',
|
theme: this.props.theme === 'dark' ? 'monokai' : 'default',
|
||||||
extraKeys: {
|
extraKeys: {
|
||||||
'Cmd-Enter': () => {
|
'Cmd-Enter': () => {
|
||||||
@ -135,7 +135,7 @@ export default class CodeEditor extends React.Component {
|
|||||||
|
|
||||||
defineCodeMirrorBrunoVariablesMode(variables, mode);
|
defineCodeMirrorBrunoVariablesMode(variables, mode);
|
||||||
this.editor.setOption('mode', 'brunovariables');
|
this.editor.setOption('mode', 'brunovariables');
|
||||||
}
|
};
|
||||||
|
|
||||||
_onEdit = () => {
|
_onEdit = () => {
|
||||||
if (!this.ignoreChangeEvent && this.editor) {
|
if (!this.ignoreChangeEvent && this.editor) {
|
||||||
|
@ -5,7 +5,16 @@ import StyledWrapper from './StyledWrapper';
|
|||||||
const Dropdown = ({ icon, children, onCreate, placement }) => {
|
const Dropdown = ({ icon, children, onCreate, placement }) => {
|
||||||
return (
|
return (
|
||||||
<StyledWrapper className="dropdown">
|
<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}
|
{icon}
|
||||||
</Tippy>
|
</Tippy>
|
||||||
</StyledWrapper>
|
</StyledWrapper>
|
||||||
|
@ -16,7 +16,10 @@ const CreateEnvironment = ({ collection, onClose }) => {
|
|||||||
name: ''
|
name: ''
|
||||||
},
|
},
|
||||||
validationSchema: Yup.object({
|
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) => {
|
onSubmit: (values) => {
|
||||||
dispatch(addEnvironment(values.name, collection.uid))
|
dispatch(addEnvironment(values.name, collection.uid))
|
||||||
@ -40,7 +43,13 @@ const CreateEnvironment = ({ collection, onClose }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Portal>
|
<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}>
|
<form className="bruno-form" onSubmit={formik.handleSubmit}>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="name" className="block font-semibold">
|
<label htmlFor="name" className="block font-semibold">
|
||||||
@ -59,7 +68,9 @@ const CreateEnvironment = ({ collection, onClose }) => {
|
|||||||
onChange={formik.handleChange}
|
onChange={formik.handleChange}
|
||||||
value={formik.values.name || ''}
|
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>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@ -20,7 +20,13 @@ const DeleteEnvironment = ({ onClose, environment, collection }) => {
|
|||||||
return (
|
return (
|
||||||
<Portal>
|
<Portal>
|
||||||
<StyledWrapper>
|
<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> ?
|
Are you sure you want to delete <span className="font-semibold">{environment.name}</span> ?
|
||||||
</Modal>
|
</Modal>
|
||||||
</StyledWrapper>
|
</StyledWrapper>
|
||||||
|
@ -12,7 +12,7 @@ const Wrapper = styled.div`
|
|||||||
}
|
}
|
||||||
|
|
||||||
thead {
|
thead {
|
||||||
color: ${(props) => props.theme.table.thead.color};;
|
color: ${(props) => props.theme.table.thead.color};
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,12 @@ const EnvironmentVariables = ({ environment, collection }) => {
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div className="flex items-center">
|
<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)}>
|
<button onClick={() => handleRemoveVars(variable)}>
|
||||||
<IconTrash strokeWidth={1.5} size={20} />
|
<IconTrash strokeWidth={1.5} size={20} />
|
||||||
</button>
|
</button>
|
||||||
@ -119,7 +124,12 @@ const EnvironmentVariables = ({ environment, collection }) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<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
|
Save
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -10,8 +10,16 @@ const EnvironmentDetails = ({ environment, collection }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="px-6 flex-grow flex flex-col pt-6" style={{ maxWidth: '700px' }}>
|
<div className="px-6 flex-grow flex flex-col pt-6" style={{ maxWidth: '700px' }}>
|
||||||
{openEditModal && <RenameEnvironment onClose={() => setOpenEditModal(false)} environment={environment} collection={collection} />}
|
{openEditModal && (
|
||||||
{openDeleteModal && <DeleteEnvironment onClose={() => setOpenDeleteModal(false)} environment={environment} collection={collection} />}
|
<RenameEnvironment onClose={() => setOpenEditModal(false)} environment={environment} collection={collection} />
|
||||||
|
)}
|
||||||
|
{openDeleteModal && (
|
||||||
|
<DeleteEnvironment
|
||||||
|
onClose={() => setOpenDeleteModal(false)}
|
||||||
|
environment={environment}
|
||||||
|
collection={collection}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<div className="flex flex-grow items-center">
|
<div className="flex flex-grow items-center">
|
||||||
<IconDatabase className="cursor-pointer" size={20} strokeWidth={1.5} />
|
<IconDatabase className="cursor-pointer" size={20} strokeWidth={1.5} />
|
||||||
|
@ -16,7 +16,10 @@ const RenameEnvironment = ({ onClose, environment, collection }) => {
|
|||||||
name: environment.name
|
name: environment.name
|
||||||
},
|
},
|
||||||
validationSchema: Yup.object({
|
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) => {
|
onSubmit: (values) => {
|
||||||
dispatch(renameEnvironment(values.name, environment.uid, collection.uid))
|
dispatch(renameEnvironment(values.name, environment.uid, collection.uid))
|
||||||
@ -40,7 +43,13 @@ const RenameEnvironment = ({ onClose, environment, collection }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Portal>
|
<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}>
|
<form className="bruno-form" onSubmit={formik.handleSubmit}>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="name" className="block font-semibold">
|
<label htmlFor="name" className="block font-semibold">
|
||||||
@ -59,7 +68,9 @@ const RenameEnvironment = ({ onClose, environment, collection }) => {
|
|||||||
onChange={formik.handleChange}
|
onChange={formik.handleChange}
|
||||||
value={formik.values.name || ''}
|
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>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@ -11,11 +11,21 @@ const EnvironmentSettings = ({ collection, onClose }) => {
|
|||||||
if (!environments || !environments.length) {
|
if (!environments || !environments.length) {
|
||||||
return (
|
return (
|
||||||
<StyledWrapper>
|
<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)} />}
|
{openCreateModal && <CreateEnvironment collection={collection} onClose={() => setOpenCreateModal(false)} />}
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<p>No environments found!</p>
|
<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>
|
+ <span>Create Environment</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -2,16 +2,11 @@ import React from 'react';
|
|||||||
|
|
||||||
const SendIcon = ({ color, width }) => {
|
const SendIcon = ({ color, width }) => {
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg xmlns="http://www.w3.org/2000/svg" width={width} height={width} viewBox="0 0 48 48">
|
||||||
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 fill={color} d="M4.02 42l41.98-18-41.98-18-.02 14 30 4-30 4z" />
|
||||||
<path d="M0 0h48v48h-48z" fill="none" />
|
<path d="M0 0h48v48h-48z" fill="none" />
|
||||||
</svg>
|
</svg>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default SendIcon;
|
export default SendIcon;
|
||||||
|
@ -100,7 +100,7 @@ const Wrapper = styled.div`
|
|||||||
border-radius: 0px;
|
border-radius: 0px;
|
||||||
outline: none;
|
outline: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
transition: border-color ease-in-out .1s;
|
transition: border-color ease-in-out 0.1s;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
background-color: ${(props) => props.theme.modal.input.bg};
|
background-color: ${(props) => props.theme.modal.input.bg};
|
||||||
border: 1px solid ${(props) => props.theme.modal.input.border};
|
border: 1px solid ${(props) => props.theme.modal.input.border};
|
||||||
|
@ -14,7 +14,15 @@ const ModalHeader = ({ title, handleCancel }) => (
|
|||||||
|
|
||||||
const ModalContent = ({ children }) => <div className="bruno-modal-content px-4 py-6">{children}</div>;
|
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';
|
confirmText = confirmText || 'Save';
|
||||||
cancelText = cancelText || 'Cancel';
|
cancelText = cancelText || 'Cancel';
|
||||||
|
|
||||||
@ -30,7 +38,12 @@ const ModalFooter = ({ confirmText, cancelText, handleSubmit, handleCancel, conf
|
|||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
<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}
|
{confirmText}
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</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 [isClosing, setIsClosing] = useState(false);
|
||||||
const escFunction = (event) => {
|
const escFunction = (event) => {
|
||||||
const escKeyCode = 27;
|
const escKeyCode = 27;
|
||||||
|
@ -3,22 +3,17 @@ import { usePreferences } from 'providers/Preferences';
|
|||||||
import StyledWrapper from './StyledWrapper';
|
import StyledWrapper from './StyledWrapper';
|
||||||
|
|
||||||
const General = () => {
|
const General = () => {
|
||||||
const {
|
const { preferences, setPreferences } = usePreferences();
|
||||||
preferences,
|
|
||||||
setPreferences,
|
|
||||||
} = usePreferences();
|
|
||||||
|
|
||||||
const [sslVerification, setSslVerification] = useState(
|
const [sslVerification, setSslVerification] = useState(preferences.request.sslVerification);
|
||||||
preferences.request.sslVerification
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleCheckboxChange = () => {
|
const handleCheckboxChange = () => {
|
||||||
const updatedPreferences = {
|
const updatedPreferences = {
|
||||||
...preferences,
|
...preferences,
|
||||||
request: {
|
request: {
|
||||||
...preferences.request,
|
...preferences.request,
|
||||||
sslVerification: !sslVerification,
|
sslVerification: !sslVerification
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
setPreferences(updatedPreferences)
|
setPreferences(updatedPreferences)
|
||||||
@ -33,12 +28,7 @@ const General = () => {
|
|||||||
return (
|
return (
|
||||||
<StyledWrapper>
|
<StyledWrapper>
|
||||||
<div className="flex items-center mt-2">
|
<div className="flex items-center mt-2">
|
||||||
<input
|
<input type="checkbox" checked={sslVerification} onChange={handleCheckboxChange} className="mr-3 mousetrap" />
|
||||||
type="checkbox"
|
|
||||||
checked={sslVerification}
|
|
||||||
onChange={handleCheckboxChange}
|
|
||||||
className="mr-3 mousetrap"
|
|
||||||
/>
|
|
||||||
SSL Certificate Verification
|
SSL Certificate Verification
|
||||||
</div>
|
</div>
|
||||||
</StyledWrapper>
|
</StyledWrapper>
|
||||||
|
@ -22,7 +22,7 @@ const Theme = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledWrapper>
|
<StyledWrapper>
|
||||||
<div className='bruno-form'>
|
<div className="bruno-form">
|
||||||
<div className="flex items-center mt-2">
|
<div className="flex items-center mt-2">
|
||||||
<input
|
<input
|
||||||
id="light-theme"
|
id="light-theme"
|
||||||
@ -31,7 +31,7 @@ const Theme = () => {
|
|||||||
name="theme"
|
name="theme"
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
formik.handleChange(e);
|
formik.handleChange(e);
|
||||||
formik.handleSubmit()
|
formik.handleSubmit();
|
||||||
}}
|
}}
|
||||||
value="light"
|
value="light"
|
||||||
checked={formik.values.theme === 'light'}
|
checked={formik.values.theme === 'light'}
|
||||||
@ -47,7 +47,7 @@ const Theme = () => {
|
|||||||
name="theme"
|
name="theme"
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
formik.handleChange(e);
|
formik.handleChange(e);
|
||||||
formik.handleSubmit()
|
formik.handleSubmit();
|
||||||
}}
|
}}
|
||||||
value="dark"
|
value="dark"
|
||||||
checked={formik.values.theme === 'dark'}
|
checked={formik.values.theme === 'dark'}
|
||||||
|
@ -33,10 +33,32 @@ import React from 'react';
|
|||||||
|
|
||||||
const AssertionOperator = ({ operator, onChange }) => {
|
const AssertionOperator = ({ operator, onChange }) => {
|
||||||
const operators = [
|
const operators = [
|
||||||
'eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'in', 'notIn',
|
'eq',
|
||||||
'contains', 'notContains', 'length', 'matches', 'notMatches',
|
'neq',
|
||||||
'startsWith', 'endsWith', 'between', 'isEmpty', 'isNull', 'isUndefined',
|
'gt',
|
||||||
'isDefined', 'isTruthy', 'isFalsy', 'isJson', 'isNumber', 'isString', 'isBoolean'
|
'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) => {
|
const handleChange = (e) => {
|
||||||
|
@ -43,14 +43,45 @@ const parseAssertionOperator = (str = '') => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const operators = [
|
const operators = [
|
||||||
'eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'in', 'notIn',
|
'eq',
|
||||||
'contains', 'notContains', 'length', 'matches', 'notMatches',
|
'neq',
|
||||||
'startsWith', 'endsWith', 'between', 'isEmpty', 'isNull', 'isUndefined',
|
'gt',
|
||||||
'isDefined', 'isTruthy', 'isFalsy', 'isJson', 'isNumber', 'isString', 'isBoolean'
|
'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 = [
|
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 [operator, ...rest] = str.trim().split(' ');
|
||||||
@ -78,22 +109,33 @@ const parseAssertionOperator = (str = '') => {
|
|||||||
|
|
||||||
const isUnaryOperator = (operator) => {
|
const isUnaryOperator = (operator) => {
|
||||||
const unaryOperators = [
|
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);
|
return unaryOperators.includes(operator);
|
||||||
};
|
};
|
||||||
|
|
||||||
const AssertionRow = ({
|
const AssertionRow = ({
|
||||||
item, collection, assertion, handleAssertionChange, handleRemoveAssertion,
|
item,
|
||||||
onSave, handleRun
|
collection,
|
||||||
|
assertion,
|
||||||
|
handleAssertionChange,
|
||||||
|
handleRemoveAssertion,
|
||||||
|
onSave,
|
||||||
|
handleRun
|
||||||
}) => {
|
}) => {
|
||||||
const { storedTheme } = useTheme();
|
const { storedTheme } = useTheme();
|
||||||
|
|
||||||
const {
|
const { operator, value } = parseAssertionOperator(assertion.value);
|
||||||
operator,
|
|
||||||
value
|
|
||||||
} = parseAssertionOperator(assertion.value);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr key={assertion.uid}>
|
<tr key={assertion.uid}>
|
||||||
@ -112,11 +154,17 @@ const AssertionRow = ({
|
|||||||
<td>
|
<td>
|
||||||
<AssertionOperator
|
<AssertionOperator
|
||||||
operator={operator}
|
operator={operator}
|
||||||
onChange={(op) => handleAssertionChange({
|
onChange={(op) =>
|
||||||
|
handleAssertionChange(
|
||||||
|
{
|
||||||
target: {
|
target: {
|
||||||
value: `${op} ${value}`
|
value: `${op} ${value}`
|
||||||
}
|
}
|
||||||
}, assertion, 'value')}
|
},
|
||||||
|
assertion,
|
||||||
|
'value'
|
||||||
|
)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@ -126,20 +174,22 @@ const AssertionRow = ({
|
|||||||
theme={storedTheme}
|
theme={storedTheme}
|
||||||
readOnly={true}
|
readOnly={true}
|
||||||
onSave={onSave}
|
onSave={onSave}
|
||||||
onChange={(newValue) => handleAssertionChange({
|
onChange={(newValue) =>
|
||||||
|
handleAssertionChange(
|
||||||
|
{
|
||||||
target: {
|
target: {
|
||||||
value: newValue
|
value: newValue
|
||||||
}
|
}
|
||||||
}, assertion, 'value')}
|
},
|
||||||
|
assertion,
|
||||||
|
'value'
|
||||||
|
)
|
||||||
|
}
|
||||||
onRun={handleRun}
|
onRun={handleRun}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<input
|
<input type="text" className="cursor-default" disabled />
|
||||||
type="text"
|
|
||||||
className='cursor-default'
|
|
||||||
disabled
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -4,7 +4,11 @@ import cloneDeep from 'lodash/cloneDeep';
|
|||||||
import { IconTrash } from '@tabler/icons';
|
import { IconTrash } from '@tabler/icons';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { useTheme } from 'providers/Theme';
|
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 SingleLineEditor from 'components/SingleLineEditor';
|
||||||
import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
||||||
import StyledWrapper from './StyledWrapper';
|
import StyledWrapper from './StyledWrapper';
|
||||||
@ -92,18 +96,29 @@ const FormUrlEncodedParams = ({ item, collection }) => {
|
|||||||
value={param.value}
|
value={param.value}
|
||||||
theme={storedTheme}
|
theme={storedTheme}
|
||||||
onSave={onSave}
|
onSave={onSave}
|
||||||
onChange={(newValue) => handleParamChange({
|
onChange={(newValue) =>
|
||||||
|
handleParamChange(
|
||||||
|
{
|
||||||
target: {
|
target: {
|
||||||
value: newValue
|
value: newValue
|
||||||
}
|
}
|
||||||
}, param, 'value')}
|
},
|
||||||
|
param,
|
||||||
|
'value'
|
||||||
|
)
|
||||||
|
}
|
||||||
onRun={handleRun}
|
onRun={handleRun}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div className="flex items-center">
|
<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)}>
|
<button onClick={() => handleRemoveParams(param)}>
|
||||||
<IconTrash strokeWidth={1.5} size={20} />
|
<IconTrash strokeWidth={1.5} size={20} />
|
||||||
</button>
|
</button>
|
||||||
|
@ -24,20 +24,15 @@ const GraphQLRequestPane = ({ item, collection, leftPaneWidth, onSchemaLoad, tog
|
|||||||
const tabs = useSelector((state) => state.tabs.tabs);
|
const tabs = useSelector((state) => state.tabs.tabs);
|
||||||
const activeTabUid = useSelector((state) => state.tabs.activeTabUid);
|
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 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 url = item.draft ? get(item, 'draft.request.url') : get(item, 'request.url');
|
||||||
const {
|
const { storedTheme } = useTheme();
|
||||||
storedTheme
|
|
||||||
} = useTheme();
|
|
||||||
|
|
||||||
const environment = findEnvironmentInCollection(collection, collection.activeEnvironmentUid);
|
const environment = findEnvironmentInCollection(collection, collection.activeEnvironmentUid);
|
||||||
|
|
||||||
let {
|
let { schema, loadSchema, isLoading: isSchemaLoading, error: schemaError } = useGraphqlSchema(url, environment);
|
||||||
schema,
|
|
||||||
loadSchema,
|
|
||||||
isLoading: isSchemaLoading,
|
|
||||||
error: schemaError
|
|
||||||
} = useGraphqlSchema(url, environment);
|
|
||||||
|
|
||||||
const loadGqlSchema = () => {
|
const loadGqlSchema = () => {
|
||||||
if (!isSchemaLoading) {
|
if (!isSchemaLoading) {
|
||||||
@ -75,7 +70,8 @@ const GraphQLRequestPane = ({ item, collection, leftPaneWidth, onSchemaLoad, tog
|
|||||||
const getTabPanel = (tab) => {
|
const getTabPanel = (tab) => {
|
||||||
switch (tab) {
|
switch (tab) {
|
||||||
case 'query': {
|
case 'query': {
|
||||||
return <QueryEditor
|
return (
|
||||||
|
<QueryEditor
|
||||||
collection={collection}
|
collection={collection}
|
||||||
theme={storedTheme}
|
theme={storedTheme}
|
||||||
schema={schema}
|
schema={schema}
|
||||||
@ -85,7 +81,8 @@ const GraphQLRequestPane = ({ item, collection, leftPaneWidth, onSchemaLoad, tog
|
|||||||
onRun={onRun}
|
onRun={onRun}
|
||||||
onEdit={onQueryChange}
|
onEdit={onQueryChange}
|
||||||
onClickReference={handleGqlClickReference}
|
onClickReference={handleGqlClickReference}
|
||||||
/>;
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
case 'variables': {
|
case 'variables': {
|
||||||
return <GraphQLVariables item={item} variables={variables} collection={collection} />;
|
return <GraphQLVariables item={item} variables={variables} collection={collection} />;
|
||||||
@ -151,19 +148,15 @@ const GraphQLRequestPane = ({ item, collection, leftPaneWidth, onSchemaLoad, tog
|
|||||||
Tests
|
Tests
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-grow justify-end items-center" style={{ fontSize: 13 }}>
|
<div className="flex flex-grow justify-end items-center" style={{ fontSize: 13 }}>
|
||||||
<div className='flex items-center cursor-pointer hover:underline' onClick={loadGqlSchema}>
|
<div className="flex items-center cursor-pointer hover:underline" onClick={loadGqlSchema}>
|
||||||
{isSchemaLoading ? (
|
{isSchemaLoading ? <IconLoader2 className="animate-spin" size={18} strokeWidth={1.5} /> : null}
|
||||||
<IconLoader2 className="animate-spin" size={18} strokeWidth={1.5}/>
|
|
||||||
) : null}
|
|
||||||
{!isSchemaLoading && !schema ? <IconDownload size={18} strokeWidth={1.5} /> : null}
|
{!isSchemaLoading && !schema ? <IconDownload size={18} strokeWidth={1.5} /> : null}
|
||||||
{!isSchemaLoading && schema ? <IconRefresh size={18} strokeWidth={1.5} /> : null}
|
{!isSchemaLoading && schema ? <IconRefresh size={18} strokeWidth={1.5} /> : null}
|
||||||
<span className='ml-1'>Schema</span>
|
<span className="ml-1">Schema</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className="flex items-center cursor-pointer hover:underline ml-2" onClick={toggleDocs}>
|
||||||
className='flex items-center cursor-pointer hover:underline ml-2'
|
<IconBook size={18} strokeWidth={1.5} />
|
||||||
onClick={toggleDocs}
|
<span className="ml-1">Docs</span>
|
||||||
>
|
|
||||||
<IconBook size={18} strokeWidth={1.5} /><span className='ml-1'>Docs</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,9 +9,7 @@ import StyledWrapper from './StyledWrapper';
|
|||||||
const GraphQLVariables = ({ variables, item, collection }) => {
|
const GraphQLVariables = ({ variables, item, collection }) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const {
|
const { storedTheme } = useTheme();
|
||||||
storedTheme
|
|
||||||
} = useTheme();
|
|
||||||
|
|
||||||
const onEdit = (value) => {
|
const onEdit = (value) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
@ -29,10 +27,11 @@ const GraphQLVariables = ({ variables, item, collection }) => {
|
|||||||
return (
|
return (
|
||||||
<StyledWrapper className="w-full">
|
<StyledWrapper className="w-full">
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
collection={collection} value={variables || ''}
|
collection={collection}
|
||||||
|
value={variables || ''}
|
||||||
theme={storedTheme}
|
theme={storedTheme}
|
||||||
onEdit={onEdit}
|
onEdit={onEdit}
|
||||||
mode='javascript'
|
mode="javascript"
|
||||||
onRun={onRun}
|
onRun={onRun}
|
||||||
onSave={onSave}
|
onSave={onSave}
|
||||||
/>
|
/>
|
||||||
|
@ -103,7 +103,9 @@ const HttpRequestPane = ({ item, collection, leftPaneWidth }) => {
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</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>
|
</StyledWrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -41,7 +41,6 @@ const Wrapper = styled.div`
|
|||||||
color: ${(props) => props.theme.table.input.color};
|
color: ${(props) => props.theme.table.input.color};
|
||||||
background: transparent;
|
background: transparent;
|
||||||
|
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: none !important;
|
outline: none !important;
|
||||||
border: solid 1px transparent;
|
border: solid 1px transparent;
|
||||||
|
@ -4,7 +4,11 @@ import cloneDeep from 'lodash/cloneDeep';
|
|||||||
import { IconTrash } from '@tabler/icons';
|
import { IconTrash } from '@tabler/icons';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
import { useTheme } from 'providers/Theme';
|
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 SingleLineEditor from 'components/SingleLineEditor';
|
||||||
import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
|
||||||
import StyledWrapper from './StyledWrapper';
|
import StyledWrapper from './StyledWrapper';
|
||||||
@ -92,18 +96,29 @@ const MultipartFormParams = ({ item, collection }) => {
|
|||||||
onSave={onSave}
|
onSave={onSave}
|
||||||
theme={storedTheme}
|
theme={storedTheme}
|
||||||
value={param.value}
|
value={param.value}
|
||||||
onChange={(newValue) => handleParamChange({
|
onChange={(newValue) =>
|
||||||
|
handleParamChange(
|
||||||
|
{
|
||||||
target: {
|
target: {
|
||||||
value: newValue
|
value: newValue
|
||||||
}
|
}
|
||||||
}, param, 'value')}
|
},
|
||||||
|
param,
|
||||||
|
'value'
|
||||||
|
)
|
||||||
|
}
|
||||||
onRun={handleRun}
|
onRun={handleRun}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div className="flex items-center">
|
<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)}>
|
<button onClick={() => handleRemoveParams(param)}>
|
||||||
<IconTrash strokeWidth={1.5} size={20} />
|
<IconTrash strokeWidth={1.5} size={20} />
|
||||||
</button>
|
</button>
|
||||||
|
@ -15,16 +15,19 @@ const StyledWrapper = styled.div`
|
|||||||
// Todo: dark mode temporary fix
|
// Todo: dark mode temporary fix
|
||||||
// Clean this
|
// Clean this
|
||||||
.CodeMirror.cm-s-monokai {
|
.CodeMirror.cm-s-monokai {
|
||||||
.CodeMirror-overlayscroll-horizontal div, .CodeMirror-overlayscroll-vertical div {
|
.CodeMirror-overlayscroll-horizontal div,
|
||||||
|
.CodeMirror-overlayscroll-vertical div {
|
||||||
background: #444444;
|
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;
|
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;
|
color: #9cdcfe !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,8 +43,12 @@ const StyledWrapper = styled.div`
|
|||||||
color: #569cd6 !important;
|
color: #569cd6 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cm-variable-valid{color: green}
|
.cm-variable-valid {
|
||||||
.cm-variable-invalid{color: red}
|
color: green;
|
||||||
|
}
|
||||||
|
.cm-variable-invalid {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default StyledWrapper;
|
export default StyledWrapper;
|
||||||
|
@ -43,7 +43,7 @@ export default class QueryEditor extends React.Component {
|
|||||||
mode: 'graphql',
|
mode: 'graphql',
|
||||||
// mode: 'brunovariables',
|
// mode: 'brunovariables',
|
||||||
brunoVarInfo: {
|
brunoVarInfo: {
|
||||||
variables: getAllVariables(this.props.collection),
|
variables: getAllVariables(this.props.collection)
|
||||||
},
|
},
|
||||||
theme: this.props.editorTheme || 'graphiql',
|
theme: this.props.editorTheme || 'graphiql',
|
||||||
theme: this.props.theme === 'dark' ? 'monokai' : 'default',
|
theme: this.props.theme === 'dark' ? 'monokai' : 'default',
|
||||||
@ -51,7 +51,7 @@ export default class QueryEditor extends React.Component {
|
|||||||
autoCloseBrackets: true,
|
autoCloseBrackets: true,
|
||||||
matchBrackets: true,
|
matchBrackets: true,
|
||||||
showCursorWhenSelecting: true,
|
showCursorWhenSelecting: true,
|
||||||
scrollbarStyle: "overlay",
|
scrollbarStyle: 'overlay',
|
||||||
readOnly: this.props.readOnly ? 'nocursor' : false,
|
readOnly: this.props.readOnly ? 'nocursor' : false,
|
||||||
foldGutter: {
|
foldGutter: {
|
||||||
minFoldSize: 4
|
minFoldSize: 4
|
||||||
@ -183,10 +183,9 @@ export default class QueryEditor extends React.Component {
|
|||||||
addOverlay = () => {
|
addOverlay = () => {
|
||||||
// let variables = getAllVariables(this.props.collection);
|
// let variables = getAllVariables(this.props.collection);
|
||||||
// this.variables = variables;
|
// this.variables = variables;
|
||||||
|
|
||||||
// defineCodeMirrorBrunoVariablesMode(variables, 'graphql');
|
// defineCodeMirrorBrunoVariablesMode(variables, 'graphql');
|
||||||
// this.editor.setOption('mode', 'brunovariables');
|
// this.editor.setOption('mode', 'brunovariables');
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
|
@ -59,7 +59,10 @@ export default function onHasCompletion(_cm, data, onHintInformationRender) {
|
|||||||
const description = ctx.description ? md.render(ctx.description) : 'Self descriptive.';
|
const description = ctx.description ? md.render(ctx.description) : 'Self descriptive.';
|
||||||
const type = ctx.type ? '<span className="infoType">' + renderType(ctx.type) + '</span>' : '';
|
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) {
|
if (ctx && deprecation && ctx.deprecationReason) {
|
||||||
const reason = ctx.deprecationReason ? md.render(ctx.deprecationReason) : '';
|
const reason = ctx.deprecationReason ? md.render(ctx.deprecationReason) : '';
|
||||||
|
@ -13,7 +13,7 @@ const Wrapper = styled.div`
|
|||||||
}
|
}
|
||||||
|
|
||||||
thead {
|
thead {
|
||||||
color: ${(props) => props.theme.table.thead.color};;
|
color: ${(props) => props.theme.table.thead.color};
|
||||||
font-size: 0.8125rem;
|
font-size: 0.8125rem;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
@ -95,18 +95,29 @@ const QueryParams = ({ item, collection }) => {
|
|||||||
value={param.value}
|
value={param.value}
|
||||||
theme={storedTheme}
|
theme={storedTheme}
|
||||||
onSave={onSave}
|
onSave={onSave}
|
||||||
onChange={(newValue) => handleParamChange({
|
onChange={(newValue) =>
|
||||||
|
handleParamChange(
|
||||||
|
{
|
||||||
target: {
|
target: {
|
||||||
value: newValue
|
value: newValue
|
||||||
}
|
}
|
||||||
}, param, 'value')}
|
},
|
||||||
|
param,
|
||||||
|
'value'
|
||||||
|
)
|
||||||
|
}
|
||||||
onRun={handleRun}
|
onRun={handleRun}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div className="flex items-center">
|
<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)}>
|
<button onClick={() => handleRemoveParam(param)}>
|
||||||
<IconTrash strokeWidth={1.5} size={20} />
|
<IconTrash strokeWidth={1.5} size={20} />
|
||||||
</button>
|
</button>
|
||||||
|
@ -10,7 +10,9 @@ const HttpMethodSelector = ({ method, onMethodSelect }) => {
|
|||||||
const Icon = forwardRef((props, ref) => {
|
const Icon = forwardRef((props, ref) => {
|
||||||
return (
|
return (
|
||||||
<div ref={ref} className="flex w-full items-center pl-3 py-1 select-none uppercase">
|
<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>
|
<div>
|
||||||
<IconCaretDown className="caret ml-2 mr-2" size={14} strokeWidth={2} />
|
<IconCaretDown className="caret ml-2 mr-2" size={14} strokeWidth={2} />
|
||||||
</div>
|
</div>
|
||||||
|
@ -18,7 +18,7 @@ const QueryUrl = ({ item, collection, handleRun }) => {
|
|||||||
const [methodSelectorWidth, setMethodSelectorWidth] = useState(90);
|
const [methodSelectorWidth, setMethodSelectorWidth] = useState(90);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const el = document.querySelector(".method-selector-container");
|
const el = document.querySelector('.method-selector-container');
|
||||||
setMethodSelectorWidth(el.offsetWidth);
|
setMethodSelectorWidth(el.offsetWidth);
|
||||||
}, [method]);
|
}, [method]);
|
||||||
|
|
||||||
|
@ -13,9 +13,7 @@ const RequestBody = ({ item, collection }) => {
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const body = item.draft ? get(item, 'draft.request.body') : get(item, 'request.body');
|
const body = item.draft ? get(item, 'draft.request.body') : get(item, 'request.body');
|
||||||
const bodyMode = item.draft ? get(item, 'draft.request.body.mode') : get(item, 'request.body.mode');
|
const bodyMode = item.draft ? get(item, 'draft.request.body.mode') : get(item, 'request.body.mode');
|
||||||
const {
|
const { storedTheme } = useTheme();
|
||||||
storedTheme
|
|
||||||
} = useTheme();
|
|
||||||
|
|
||||||
const onEdit = (value) => {
|
const onEdit = (value) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
@ -45,7 +43,15 @@ const RequestBody = ({ item, collection }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledWrapper className="w-full">
|
<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>
|
</StyledWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -92,18 +92,29 @@ const RequestHeaders = ({ item, collection }) => {
|
|||||||
value={header.value}
|
value={header.value}
|
||||||
theme={storedTheme}
|
theme={storedTheme}
|
||||||
onSave={onSave}
|
onSave={onSave}
|
||||||
onChange={(newValue) => handleHeaderValueChange({
|
onChange={(newValue) =>
|
||||||
|
handleHeaderValueChange(
|
||||||
|
{
|
||||||
target: {
|
target: {
|
||||||
value: newValue
|
value: newValue
|
||||||
}
|
}
|
||||||
}, header, 'value')}
|
},
|
||||||
|
header,
|
||||||
|
'value'
|
||||||
|
)
|
||||||
|
}
|
||||||
onRun={handleRun}
|
onRun={handleRun}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div className="flex items-center">
|
<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)}>
|
<button onClick={() => handleRemoveHeader(header)}>
|
||||||
<IconTrash strokeWidth={1.5} size={20} />
|
<IconTrash strokeWidth={1.5} size={20} />
|
||||||
</button>
|
</button>
|
||||||
|
@ -28,7 +28,14 @@ const SaveRequest = ({ items, onClose }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledWrapper>
|
<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>
|
<p className="mb-2">Select a folder to save request:</p>
|
||||||
<div className="folder-list">
|
<div className="folder-list">
|
||||||
{showFolders && showFolders.length
|
{showFolders && showFolders.length
|
||||||
|
@ -12,9 +12,7 @@ const Script = ({ item, collection }) => {
|
|||||||
const requestScript = item.draft ? get(item, 'draft.request.script.req') : get(item, 'request.script.req');
|
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 responseScript = item.draft ? get(item, 'draft.request.script.res') : get(item, 'request.script.res');
|
||||||
|
|
||||||
const {
|
const { storedTheme } = useTheme();
|
||||||
storedTheme
|
|
||||||
} = useTheme();
|
|
||||||
|
|
||||||
const onRequestScriptEdit = (value) => {
|
const onRequestScriptEdit = (value) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
@ -41,24 +39,26 @@ const Script = ({ item, collection }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledWrapper className="w-full flex flex-col">
|
<StyledWrapper className="w-full flex flex-col">
|
||||||
<div className='flex-1 mt-2'>
|
<div className="flex-1 mt-2">
|
||||||
<div className='mb-1 title text-xs'>Pre Request</div>
|
<div className="mb-1 title text-xs">Pre Request</div>
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
collection={collection} value={requestScript || ''}
|
collection={collection}
|
||||||
|
value={requestScript || ''}
|
||||||
theme={storedTheme}
|
theme={storedTheme}
|
||||||
onEdit={onRequestScriptEdit}
|
onEdit={onRequestScriptEdit}
|
||||||
mode='javascript'
|
mode="javascript"
|
||||||
onRun={onRun}
|
onRun={onRun}
|
||||||
onSave={onSave}
|
onSave={onSave}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className='flex-1 mt-6'>
|
<div className="flex-1 mt-6">
|
||||||
<div className='mt-1 mb-1 title text-xs'>Post Response</div>
|
<div className="mt-1 mb-1 title text-xs">Post Response</div>
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
collection={collection} value={responseScript || ''}
|
collection={collection}
|
||||||
|
value={responseScript || ''}
|
||||||
theme={storedTheme}
|
theme={storedTheme}
|
||||||
onEdit={onResponseScriptEdit}
|
onEdit={onResponseScriptEdit}
|
||||||
mode='javascript'
|
mode="javascript"
|
||||||
onRun={onRun}
|
onRun={onRun}
|
||||||
onSave={onSave}
|
onSave={onSave}
|
||||||
/>
|
/>
|
||||||
|
@ -11,9 +11,7 @@ const Tests = ({ item, collection }) => {
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const tests = item.draft ? get(item, 'draft.request.tests') : get(item, 'request.tests');
|
const tests = item.draft ? get(item, 'draft.request.tests') : get(item, 'request.tests');
|
||||||
|
|
||||||
const {
|
const { storedTheme } = useTheme();
|
||||||
storedTheme
|
|
||||||
} = useTheme();
|
|
||||||
|
|
||||||
const onEdit = (value) => {
|
const onEdit = (value) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
@ -31,10 +29,11 @@ const Tests = ({ item, collection }) => {
|
|||||||
return (
|
return (
|
||||||
<StyledWrapper className="w-full">
|
<StyledWrapper className="w-full">
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
collection={collection} value={tests || ''}
|
collection={collection}
|
||||||
|
value={tests || ''}
|
||||||
theme={storedTheme}
|
theme={storedTheme}
|
||||||
onEdit={onEdit}
|
onEdit={onEdit}
|
||||||
mode='javascript'
|
mode="javascript"
|
||||||
onRun={onRun}
|
onRun={onRun}
|
||||||
onSave={onSave}
|
onSave={onSave}
|
||||||
/>
|
/>
|
||||||
|
@ -70,14 +70,14 @@ const VarsTable = ({ item, collection, vars, varType }) => {
|
|||||||
<td>Name</td>
|
<td>Name</td>
|
||||||
{varType === 'request' ? (
|
{varType === 'request' ? (
|
||||||
<td>
|
<td>
|
||||||
<div className='flex items-center'>
|
<div className="flex items-center">
|
||||||
<span>Value</span>
|
<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>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
) : (
|
) : (
|
||||||
<td>
|
<td>
|
||||||
<div className='flex items-center'>
|
<div className="flex items-center">
|
||||||
<span>Expr</span>
|
<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>
|
</div>
|
||||||
@ -108,11 +108,17 @@ const VarsTable = ({ item, collection, vars, varType }) => {
|
|||||||
value={_var.value}
|
value={_var.value}
|
||||||
theme={storedTheme}
|
theme={storedTheme}
|
||||||
onSave={onSave}
|
onSave={onSave}
|
||||||
onChange={(newValue) => handleVarChange({
|
onChange={(newValue) =>
|
||||||
|
handleVarChange(
|
||||||
|
{
|
||||||
target: {
|
target: {
|
||||||
value: newValue
|
value: newValue
|
||||||
}
|
}
|
||||||
}, _var, 'value')}
|
},
|
||||||
|
_var,
|
||||||
|
'value'
|
||||||
|
)
|
||||||
|
}
|
||||||
onRun={handleRun}
|
onRun={handleRun}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
/>
|
/>
|
||||||
|
@ -12,9 +12,7 @@ const Vars = ({ item, collection }) => {
|
|||||||
const requestVars = item.draft ? get(item, 'draft.request.vars.req') : get(item, 'request.vars.req');
|
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 responseVars = item.draft ? get(item, 'draft.request.vars.res') : get(item, 'request.vars.res');
|
||||||
|
|
||||||
const {
|
const { storedTheme } = useTheme();
|
||||||
storedTheme
|
|
||||||
} = useTheme();
|
|
||||||
|
|
||||||
const onRequestScriptEdit = (value) => {
|
const onRequestScriptEdit = (value) => {
|
||||||
dispatch(
|
dispatch(
|
||||||
@ -41,13 +39,13 @@ const Vars = ({ item, collection }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledWrapper className="w-full flex flex-col">
|
<StyledWrapper className="w-full flex flex-col">
|
||||||
<div className='flex-1 mt-2'>
|
<div className="flex-1 mt-2">
|
||||||
<div className='mb-1 title text-xs'>Pre Request</div>
|
<div className="mb-1 title text-xs">Pre Request</div>
|
||||||
<VarsTable item={item} collection={collection} vars={requestVars} varType='request'/>
|
<VarsTable item={item} collection={collection} vars={requestVars} varType="request" />
|
||||||
</div>
|
</div>
|
||||||
<div className='flex-1'>
|
<div className="flex-1">
|
||||||
<div className='mt-1 mb-1 title text-xs'>Post Response</div>
|
<div className="mt-1 mb-1 title text-xs">Post Response</div>
|
||||||
<VarsTable item={item} collection={collection} vars={responseVars} varType='response'/>
|
<VarsTable item={item} collection={collection} vars={responseVars} varType="response" />
|
||||||
</div>
|
</div>
|
||||||
</StyledWrapper>
|
</StyledWrapper>
|
||||||
);
|
);
|
||||||
|
@ -32,7 +32,9 @@ const RequestNotFound = ({ itemUid }) => {
|
|||||||
<div className="mt-6 px-6">
|
<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 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>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>
|
</div>
|
||||||
<button className="btn btn-md btn-secondary mt-6" onClick={closeTab}>
|
<button className="btn btn-md btn-secondary mt-6" onClick={closeTab}>
|
||||||
Close Tab
|
Close Tab
|
||||||
|
@ -33,7 +33,9 @@ const RequestTabPanel = () => {
|
|||||||
|
|
||||||
let asideWidth = useSelector((state) => state.app.leftSidebarWidth);
|
let asideWidth = useSelector((state) => state.app.leftSidebarWidth);
|
||||||
const focusedTab = find(tabs, (t) => t.uid === activeTabUid);
|
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 [rightPaneWidth, setRightPaneWidth] = useState(screenWidth - asideWidth - leftPaneWidth - DEFAULT_PADDING);
|
||||||
const [dragging, setDragging] = useState(false);
|
const [dragging, setDragging] = useState(false);
|
||||||
|
|
||||||
@ -66,7 +68,10 @@ const RequestTabPanel = () => {
|
|||||||
if (dragging) {
|
if (dragging) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
let leftPaneXPosition = e.clientX + 2;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
setLeftPaneWidth(leftPaneXPosition - asideWidth);
|
setLeftPaneWidth(leftPaneXPosition - asideWidth);
|
||||||
@ -138,7 +143,13 @@ const RequestTabPanel = () => {
|
|||||||
</div>
|
</div>
|
||||||
<section className="main flex flex-grow pb-4 relative">
|
<section className="main flex flex-grow pb-4 relative">
|
||||||
<section className="request-pane">
|
<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' ? (
|
{item.type === 'graphql-request' ? (
|
||||||
<GraphQLRequestPane
|
<GraphQLRequestPane
|
||||||
item={item}
|
item={item}
|
||||||
@ -150,7 +161,9 @@ const RequestTabPanel = () => {
|
|||||||
/>
|
/>
|
||||||
) : null}
|
) : 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>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@ -165,12 +178,8 @@ const RequestTabPanel = () => {
|
|||||||
|
|
||||||
{item.type === 'graphql-request' ? (
|
{item.type === 'graphql-request' ? (
|
||||||
<div className={`graphql-docs-explorer-container ${showGqlDocs ? '' : 'hidden'}`}>
|
<div className={`graphql-docs-explorer-container ${showGqlDocs ? '' : 'hidden'}`}>
|
||||||
<DocExplorer schema={schema} ref={(r) => docExplorerRef.current = r}>
|
<DocExplorer schema={schema} ref={(r) => (docExplorerRef.current = r)}>
|
||||||
<button
|
<button className="mr-2" onClick={toggleDocs} aria-label="Close Documentation Explorer">
|
||||||
className='mr-2'
|
|
||||||
onClick={toggleDocs}
|
|
||||||
aria-label="Close Documentation Explorer"
|
|
||||||
>
|
|
||||||
{'\u2715'}
|
{'\u2715'}
|
||||||
</button>
|
</button>
|
||||||
</DocExplorer>
|
</DocExplorer>
|
||||||
|
@ -10,9 +10,11 @@ const CollectionToolBar = ({ collection }) => {
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const handleRun = () => {
|
const handleRun = () => {
|
||||||
dispatch(toggleRunnerView({
|
dispatch(
|
||||||
|
toggleRunnerView({
|
||||||
collectionUid: collection.uid
|
collectionUid: collection.uid
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -87,7 +87,15 @@ const RequestTab = ({ tab, collection }) => {
|
|||||||
></path>
|
></path>
|
||||||
</svg>
|
</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" />
|
<circle cx="4" cy="4" r="3" />
|
||||||
</svg>
|
</svg>
|
||||||
)}
|
)}
|
||||||
|
@ -81,7 +81,9 @@ const RequestTabs = () => {
|
|||||||
// Todo: Must support ephermal requests
|
// Todo: Must support ephermal requests
|
||||||
return (
|
return (
|
||||||
<StyledWrapper className={getRootClassname()}>
|
<StyledWrapper className={getRootClassname()}>
|
||||||
{newRequestModalOpen && <NewRequest collection={activeCollection} onClose={() => setNewRequestModalOpen(false)} />}
|
{newRequestModalOpen && (
|
||||||
|
<NewRequest collection={activeCollection} onClose={() => setNewRequestModalOpen(false)} />
|
||||||
|
)}
|
||||||
{collectionRequestTabs && collectionRequestTabs.length ? (
|
{collectionRequestTabs && collectionRequestTabs.length ? (
|
||||||
<>
|
<>
|
||||||
<CollectionToolBar collection={activeCollection} />
|
<CollectionToolBar collection={activeCollection} />
|
||||||
@ -106,7 +108,12 @@ const RequestTabs = () => {
|
|||||||
{collectionRequestTabs && collectionRequestTabs.length
|
{collectionRequestTabs && collectionRequestTabs.length
|
||||||
? collectionRequestTabs.map((tab, index) => {
|
? collectionRequestTabs.map((tab, index) => {
|
||||||
return (
|
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} />
|
<RequestTab key={tab.uid} tab={tab} collection={activeCollection} activeTab={activeTab} />
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
@ -124,7 +131,13 @@ const RequestTabs = () => {
|
|||||||
) : null}
|
) : null}
|
||||||
<li className="select-none short-tab" id="create-new-tab" onClick={createNewTab}>
|
<li className="select-none short-tab" id="create-new-tab" onClick={createNewTab}>
|
||||||
<div className="flex items-center">
|
<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" />
|
<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>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
@ -20,7 +20,14 @@ const QueryResult = ({ item, collection, value, width, disableRunEventListener,
|
|||||||
return (
|
return (
|
||||||
<StyledWrapper className="px-3 w-full" style={{ maxWidth: width }}>
|
<StyledWrapper className="px-3 w-full" style={{ maxWidth: width }}>
|
||||||
<div className="h-full">
|
<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>
|
</div>
|
||||||
</StyledWrapper>
|
</StyledWrapper>
|
||||||
);
|
);
|
||||||
|
@ -5,11 +5,7 @@ const TestResults = ({ results, assertionResults }) => {
|
|||||||
results = results || [];
|
results = results || [];
|
||||||
assertionResults = assertionResults || [];
|
assertionResults = assertionResults || [];
|
||||||
if (!results.length && !assertionResults.length) {
|
if (!results.length && !assertionResults.length) {
|
||||||
return (
|
return <div className="px-3">No tests found</div>;
|
||||||
<div className="px-3">
|
|
||||||
No tests found
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const passedTests = results.filter((result) => result.status === 'pass');
|
const passedTests = results.filter((result) => result.status === 'pass');
|
||||||
@ -19,7 +15,7 @@ const TestResults = ({ results, assertionResults }) => {
|
|||||||
const failedAssertions = assertionResults.filter((result) => result.status === 'fail');
|
const failedAssertions = assertionResults.filter((result) => result.status === 'fail');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledWrapper className='flex flex-col px-3'>
|
<StyledWrapper className="flex flex-col px-3">
|
||||||
<div className="py-2 font-medium test-summary">
|
<div className="py-2 font-medium test-summary">
|
||||||
Tests ({results.length}/{results.length}), Passed: {passedTests.length}, Failed: {failedTests.length}
|
Tests ({results.length}/{results.length}), Passed: {passedTests.length}, Failed: {failedTests.length}
|
||||||
</div>
|
</div>
|
||||||
@ -27,18 +23,12 @@ const TestResults = ({ results, assertionResults }) => {
|
|||||||
{results.map((result) => (
|
{results.map((result) => (
|
||||||
<li key={result.uid} className="py-1">
|
<li key={result.uid} className="py-1">
|
||||||
{result.status === 'pass' ? (
|
{result.status === 'pass' ? (
|
||||||
<span className="test-success">
|
<span className="test-success">✔ {result.description}</span>
|
||||||
✔ {result.description}
|
|
||||||
</span>
|
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
<span className="test-failure">
|
<span className="test-failure">✘ {result.description}</span>
|
||||||
✘ {result.description}
|
|
||||||
</span>
|
|
||||||
<br />
|
<br />
|
||||||
<span className="error-message pl-8">
|
<span className="error-message pl-8">{result.error}</span>
|
||||||
{result.error}
|
|
||||||
</span>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</li>
|
</li>
|
||||||
@ -46,7 +36,8 @@ const TestResults = ({ results, assertionResults }) => {
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div className="py-2 font-medium test-summary">
|
<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>
|
</div>
|
||||||
<ul className="">
|
<ul className="">
|
||||||
{assertionResults.map((result) => (
|
{assertionResults.map((result) => (
|
||||||
@ -61,9 +52,7 @@ const TestResults = ({ results, assertionResults }) => {
|
|||||||
✘ {result.lhsExpr}: {result.rhsExpr}
|
✘ {result.lhsExpr}: {result.rhsExpr}
|
||||||
</span>
|
</span>
|
||||||
<br />
|
<br />
|
||||||
<span className="error-message pl-8">
|
<span className="error-message pl-8">{result.error}</span>
|
||||||
{result.error}
|
|
||||||
</span>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</li>
|
</li>
|
||||||
|
@ -8,25 +8,21 @@ const TestResultsLabel = ({ results, assertionResults }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const numberOfTests = results.length;
|
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 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 totalNumberOfTests = numberOfTests + numberOfAssertions;
|
||||||
const totalNumberOfFailedTests = numberOfFailedTests + numberOfFailedAssertions;
|
const totalNumberOfFailedTests = numberOfFailedTests + numberOfFailedAssertions;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex items-center'>
|
<div className="flex items-center">
|
||||||
<div>Tests</div>
|
<div>Tests</div>
|
||||||
{totalNumberOfFailedTests ? (
|
{totalNumberOfFailedTests ? (
|
||||||
<sup className='sups some-tests-failed ml-1 font-medium'>
|
<sup className="sups some-tests-failed ml-1 font-medium">{totalNumberOfFailedTests}</sup>
|
||||||
{totalNumberOfFailedTests}
|
|
||||||
</sup>
|
|
||||||
) : (
|
) : (
|
||||||
<sup className='sups all-tests-passed ml-1 font-medium'>
|
<sup className="sups all-tests-passed ml-1 font-medium">{totalNumberOfTests}</sup>
|
||||||
{totalNumberOfTests}
|
|
||||||
</sup>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -22,32 +22,32 @@ const Timeline = ({ request, response}) => {
|
|||||||
return (
|
return (
|
||||||
<StyledWrapper className="px-3 pb-4 w-full">
|
<StyledWrapper className="px-3 pb-4 w-full">
|
||||||
<div>
|
<div>
|
||||||
<pre className='line request font-bold'>
|
<pre className="line request font-bold">
|
||||||
<span className="arrow">{'>'}</span> {request.method} {request.url}
|
<span className="arrow">{'>'}</span> {request.method} {request.url}
|
||||||
</pre>
|
</pre>
|
||||||
{requestHeaders.map((h) => {
|
{requestHeaders.map((h) => {
|
||||||
return (
|
return (
|
||||||
<pre className='line request' key={h.name}>
|
<pre className="line request" key={h.name}>
|
||||||
<span className="arrow">{'>'}</span> {h.name}: {h.value}
|
<span className="arrow">{'>'}</span> {h.name}: {h.value}
|
||||||
</pre>
|
</pre>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
{requestData ? (
|
{requestData ? (
|
||||||
<pre className='line request'>
|
<pre className="line request">
|
||||||
<span className="arrow">{'>'}</span> data {requestData}
|
<span className="arrow">{'>'}</span> data {requestData}
|
||||||
</pre>
|
</pre>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='mt-4'>
|
<div className="mt-4">
|
||||||
<pre className='line response font-bold'>
|
<pre className="line response font-bold">
|
||||||
<span className="arrow">{'<'}</span> {response.status} {response.statusText}
|
<span className="arrow">{'<'}</span> {response.status} {response.statusText}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
{responseHeaders.map((h) => {
|
{responseHeaders.map((h) => {
|
||||||
return (
|
return (
|
||||||
<pre className='line response' key={h[0]}>
|
<pre className="line response" key={h[0]}>
|
||||||
<span className="arrow">{'<'}</span> {h[0]}: {h[1]}
|
<span className="arrow">{'<'}</span> {h[0]}: {h[1]}
|
||||||
</pre>
|
</pre>
|
||||||
);
|
);
|
||||||
|
@ -41,7 +41,9 @@ const ResponsePane = ({ rightPaneWidth, item, collection }) => {
|
|||||||
item={item}
|
item={item}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
width={rightPaneWidth}
|
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)}
|
mode={getContentType(response.headers)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -15,11 +15,7 @@ import StyledWrapper from './StyledWrapper';
|
|||||||
const ResponsePane = ({ rightPaneWidth, item, collection }) => {
|
const ResponsePane = ({ rightPaneWidth, item, collection }) => {
|
||||||
const [selectedTab, setSelectedTab] = useState('response');
|
const [selectedTab, setSelectedTab] = useState('response');
|
||||||
|
|
||||||
const {
|
const { requestSent, responseReceived, testResults } = item;
|
||||||
requestSent,
|
|
||||||
responseReceived,
|
|
||||||
testResults
|
|
||||||
} = item;
|
|
||||||
|
|
||||||
const headers = get(item, 'responseReceived.headers', {});
|
const headers = get(item, 'responseReceived.headers', {});
|
||||||
const status = get(item, 'responseReceived.status', 0);
|
const status = get(item, 'responseReceived.status', 0);
|
||||||
@ -31,13 +27,15 @@ const ResponsePane = ({ rightPaneWidth, item, collection }) => {
|
|||||||
const getTabPanel = (tab) => {
|
const getTabPanel = (tab) => {
|
||||||
switch (tab) {
|
switch (tab) {
|
||||||
case 'response': {
|
case 'response': {
|
||||||
return <QueryResult
|
return (
|
||||||
|
<QueryResult
|
||||||
item={item}
|
item={item}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
width={rightPaneWidth}
|
width={rightPaneWidth}
|
||||||
disableRunEventListener={true}
|
disableRunEventListener={true}
|
||||||
value={(responseReceived && responseReceived.data) ? safeStringifyJSON(responseReceived.data, true) : ''}
|
value={responseReceived && responseReceived.data ? safeStringifyJSON(responseReceived.data, true) : ''}
|
||||||
/>;
|
/>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
case 'headers': {
|
case 'headers': {
|
||||||
return <ResponseHeaders headers={headers} />;
|
return <ResponseHeaders headers={headers} />;
|
||||||
|
@ -18,7 +18,7 @@ const getRelativePath = (fullPath, pathname) => {
|
|||||||
let relativePath = path.relative(fullPath, pathname);
|
let relativePath = path.relative(fullPath, pathname);
|
||||||
const { dir, name } = path.parse(relativePath);
|
const { dir, name } = path.parse(relativePath);
|
||||||
return path.join(dir, name);
|
return path.join(dir, name);
|
||||||
}
|
};
|
||||||
|
|
||||||
export default function RunnerResults({ collection }) {
|
export default function RunnerResults({ collection }) {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
@ -42,7 +42,7 @@ export default function RunnerResults({collection}) {
|
|||||||
item.pathname = info.pathname;
|
item.pathname = info.pathname;
|
||||||
item.relativePath = getRelativePath(collection.pathname, info.pathname);
|
item.relativePath = getRelativePath(collection.pathname, info.pathname);
|
||||||
|
|
||||||
if(item.status !== "error") {
|
if (item.status !== 'error') {
|
||||||
if (item.testResults) {
|
if (item.testResults) {
|
||||||
const failed = item.testResults.filter((result) => result.status === 'fail');
|
const failed = item.testResults.filter((result) => result.status === 'fail');
|
||||||
|
|
||||||
@ -70,29 +70,31 @@ export default function RunnerResults({collection}) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const closeRunner = () => {
|
const closeRunner = () => {
|
||||||
dispatch(closeCollectionRunner({
|
dispatch(
|
||||||
collectionUid: collection.uid,
|
closeCollectionRunner({
|
||||||
}));
|
collectionUid: collection.uid
|
||||||
|
})
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const totalRequestsInCollection = getTotalRequestCountInCollection(collectionCopy);
|
const totalRequestsInCollection = getTotalRequestCountInCollection(collectionCopy);
|
||||||
const passedRequests = items.filter((item) => {
|
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) => {
|
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 (
|
return (
|
||||||
<StyledWrapper className='px-4'>
|
<StyledWrapper className="px-4">
|
||||||
<div className='font-medium mt-6 title flex items-center'>
|
<div className="font-medium mt-6 title flex items-center">
|
||||||
Runner
|
Runner
|
||||||
<IconRun size={20} strokeWidth={1.5} className='ml-2'/>
|
<IconRun size={20} strokeWidth={1.5} className="ml-2" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='mt-6'>
|
<div className="mt-6">
|
||||||
You have <span className='font-medium'>{totalRequestsInCollection}</span> requests in this collection.
|
You have <span className="font-medium">{totalRequestsInCollection}</span> requests in this collection.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="submit" className="submit btn btn-sm btn-secondary mt-6" onClick={runCollection}>
|
<button type="submit" className="submit btn btn-sm btn-secondary mt-6" onClick={runCollection}>
|
||||||
@ -107,13 +109,13 @@ export default function RunnerResults({collection}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledWrapper className='px-4'>
|
<StyledWrapper className="px-4">
|
||||||
<div className='font-medium mt-6 mb-4 title flex items-center'>
|
<div className="font-medium mt-6 mb-4 title flex items-center">
|
||||||
Runner
|
Runner
|
||||||
<IconRun size={20} strokeWidth={1.5} className='ml-2'/>
|
<IconRun size={20} strokeWidth={1.5} className="ml-2" />
|
||||||
</div>
|
</div>
|
||||||
<div className='flex'>
|
<div className="flex">
|
||||||
<div className='flex flex-col flex-1'>
|
<div className="flex flex-col flex-1">
|
||||||
<div className="py-2 font-medium test-summary">
|
<div className="py-2 font-medium test-summary">
|
||||||
Total Requests: {items.length}, Passed: {passedRequests.length}, Failed: {failedRequests.length}
|
Total Requests: {items.length}, Passed: {passedRequests.length}, Failed: {failedRequests.length}
|
||||||
</div>
|
</div>
|
||||||
@ -123,34 +125,31 @@ export default function RunnerResults({collection}) {
|
|||||||
<div className="item-path mt-2">
|
<div className="item-path mt-2">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<span>
|
<span>
|
||||||
{item.status !== "error" && item.testStatus === 'pass' ? (
|
{item.status !== 'error' && item.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>
|
</span>
|
||||||
<span className={`mr-1 ml-2 ${(item.status == "error" || item.testStatus == 'fail') ? 'danger' : ''}`}>{item.relativePath}</span>
|
<span
|
||||||
{(item.status !== "error" && item.status !== "completed") ? (
|
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} />
|
<IconRefresh className="animate-spin ml-1" size={18} strokeWidth={1.5} />
|
||||||
) : (
|
) : (
|
||||||
<span className='text-xs link cursor-pointer' onClick={() => setSelectedItem(item)}>
|
<span className="text-xs link cursor-pointer" onClick={() => setSelectedItem(item)}>
|
||||||
(<span className='mr-1'>
|
(<span className="mr-1">{get(item.responseReceived, 'status')}</span>
|
||||||
{get(item.responseReceived, 'status')}
|
<span>{get(item.responseReceived, 'statusText')}</span>)
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
{get(item.responseReceived, 'statusText')}
|
|
||||||
</span>)
|
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{item.status == "error" ? (
|
{item.status == 'error' ? <div className="error-message pl-8 pt-2 text-xs">{item.error}</div> : null}
|
||||||
<div className="error-message pl-8 pt-2 text-xs">
|
|
||||||
{item.error}
|
|
||||||
</div>
|
|
||||||
) : null }
|
|
||||||
|
|
||||||
<ul className="pl-8">
|
<ul className="pl-8">
|
||||||
{item.testResults ? item.testResults.map((result) => (
|
{item.testResults
|
||||||
|
? item.testResults.map((result) => (
|
||||||
<li key={result.uid}>
|
<li key={result.uid}>
|
||||||
{result.status === 'pass' ? (
|
{result.status === 'pass' ? (
|
||||||
<span className="test-success flex items-center">
|
<span className="test-success flex items-center">
|
||||||
@ -163,14 +162,14 @@ export default function RunnerResults({collection}) {
|
|||||||
<IconX size={18} strokeWidth={2} className="mr-2" />
|
<IconX size={18} strokeWidth={2} className="mr-2" />
|
||||||
{result.description}
|
{result.description}
|
||||||
</span>
|
</span>
|
||||||
<span className="error-message pl-8 text-xs">
|
<span className="error-message pl-8 text-xs">{result.error}</span>
|
||||||
{result.error}
|
|
||||||
</span>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</li>
|
</li>
|
||||||
)): null}
|
))
|
||||||
{item.assertionResults ? item.assertionResults.map((result) => (
|
: null}
|
||||||
|
{item.assertionResults
|
||||||
|
? item.assertionResults.map((result) => (
|
||||||
<li key={result.uid}>
|
<li key={result.uid}>
|
||||||
{result.status === 'pass' ? (
|
{result.status === 'pass' ? (
|
||||||
<span className="test-success flex items-center">
|
<span className="test-success flex items-center">
|
||||||
@ -183,13 +182,12 @@ export default function RunnerResults({collection}) {
|
|||||||
<IconX size={18} strokeWidth={2} className="mr-2" />
|
<IconX size={18} strokeWidth={2} className="mr-2" />
|
||||||
{result.lhsExpr}: {result.rhsExpr}
|
{result.lhsExpr}: {result.rhsExpr}
|
||||||
</span>
|
</span>
|
||||||
<span className="error-message pl-8 text-xs">
|
<span className="error-message pl-8 text-xs">{result.error}</span>
|
||||||
{result.error}
|
|
||||||
</span>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</li>
|
</li>
|
||||||
)): null}
|
))
|
||||||
|
: null}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -210,11 +208,11 @@ export default function RunnerResults({collection}) {
|
|||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<div className='flex flex-1' style={{width: '50%'}}>
|
<div className="flex flex-1" style={{ width: '50%' }}>
|
||||||
{selectedItem ? (
|
{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">
|
<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>
|
<span>
|
||||||
{selectedItem.testStatus === 'pass' ? (
|
{selectedItem.testStatus === 'pass' ? (
|
||||||
<IconCircleCheck className="test-success" size={20} strokeWidth={1.5} />
|
<IconCircleCheck className="test-success" size={20} strokeWidth={1.5} />
|
||||||
@ -231,4 +229,4 @@ export default function RunnerResults({collection}) {
|
|||||||
</div>
|
</div>
|
||||||
</StyledWrapper>
|
</StyledWrapper>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
@ -17,7 +17,10 @@ const CloneCollectionItem = ({ collection, item, onClose }) => {
|
|||||||
name: item.name
|
name: item.name
|
||||||
},
|
},
|
||||||
validationSchema: Yup.object({
|
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) => {
|
onSubmit: (values) => {
|
||||||
dispatch(cloneItem(values.name, item.uid, collection.uid))
|
dispatch(cloneItem(values.name, item.uid, collection.uid))
|
||||||
@ -25,7 +28,7 @@ const CloneCollectionItem = ({ collection, item, onClose }) => {
|
|||||||
onClose();
|
onClose();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.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();
|
const onSubmit = () => formik.handleSubmit();
|
||||||
|
|
||||||
return (
|
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}>
|
<form className="bruno-form" onSubmit={formik.handleSubmit}>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="name" className="block font-semibold">
|
<label htmlFor="name" className="block font-semibold">
|
||||||
|
@ -31,7 +31,13 @@ const DeleteCollectionItem = ({ onClose, item, collection }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledWrapper>
|
<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> ?
|
Are you sure you want to delete <span className="font-semibold">{item.name}</span> ?
|
||||||
</Modal>
|
</Modal>
|
||||||
</StyledWrapper>
|
</StyledWrapper>
|
||||||
|
@ -16,7 +16,10 @@ const RenameCollectionItem = ({ collection, item, onClose }) => {
|
|||||||
name: item.name
|
name: item.name
|
||||||
},
|
},
|
||||||
validationSchema: Yup.object({
|
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) => {
|
onSubmit: (values) => {
|
||||||
dispatch(renameItem(values.name, item.uid, collection.uid));
|
dispatch(renameItem(values.name, item.uid, collection.uid));
|
||||||
@ -33,7 +36,13 @@ const RenameCollectionItem = ({ collection, item, onClose }) => {
|
|||||||
const onSubmit = () => formik.handleSubmit();
|
const onSubmit = () => formik.handleSubmit();
|
||||||
|
|
||||||
return (
|
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}>
|
<form className="bruno-form" onSubmit={formik.handleSubmit}>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="name" className="block font-semibold">
|
<label htmlFor="name" className="block font-semibold">
|
||||||
|
@ -11,9 +11,11 @@ const RunCollectionItem = ({ collection, item, onClose }) => {
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
const onSubmit = (recursive) => {
|
const onSubmit = (recursive) => {
|
||||||
dispatch(showRunnerView({
|
dispatch(
|
||||||
collectionUid: collection.uid,
|
showRunnerView({
|
||||||
}));
|
collectionUid: collection.uid
|
||||||
|
})
|
||||||
|
);
|
||||||
dispatch(runCollectionFolder(collection.uid, item ? item.uid : null, recursive));
|
dispatch(runCollectionFolder(collection.uid, item ? item.uid : null, recursive));
|
||||||
onClose();
|
onClose();
|
||||||
};
|
};
|
||||||
@ -25,25 +27,21 @@ const RunCollectionItem = ({ collection, item, onClose }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledWrapper>
|
<StyledWrapper>
|
||||||
<Modal size="md" title='Collection Runner' hideFooter={true} handleCancel={onClose}>
|
<Modal size="md" title="Collection Runner" hideFooter={true} handleCancel={onClose}>
|
||||||
<div className='mb-1'>
|
<div className="mb-1">
|
||||||
<span className='font-medium'>Run</span>
|
<span className="font-medium">Run</span>
|
||||||
<span className='ml-1 text-xs'>({runLength} requests)</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>
|
||||||
|
<div className="mb-8">This will only run the requests in this folder.</div>
|
||||||
|
|
||||||
<div className='mb-1'>
|
<div className="mb-1">
|
||||||
<span className='font-medium'>Recursive Run</span>
|
<span className="font-medium">Recursive Run</span>
|
||||||
<span className='ml-1 text-xs'>({recursiveRunLength} requests)</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>
|
||||||
|
<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">
|
<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">
|
<button type="button" onClick={onClose} className="btn btn-md btn-close">
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
|
@ -86,9 +86,11 @@ const CollectionItem = ({ item, collection, searchText }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const handleClick = (event) => {
|
const handleClick = (event) => {
|
||||||
dispatch(hideRunnerView({
|
dispatch(
|
||||||
|
hideRunnerView({
|
||||||
collectionUid: collection.uid
|
collectionUid: collection.uid
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
if (isItemARequest(item)) {
|
if (isItemARequest(item)) {
|
||||||
if (itemIsOpenedInTabs(item, tabs)) {
|
if (itemIsOpenedInTabs(item, tabs)) {
|
||||||
dispatch(
|
dispatch(
|
||||||
@ -151,12 +153,24 @@ const CollectionItem = ({ item, collection, searchText }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledWrapper className={className}>
|
<StyledWrapper className={className}>
|
||||||
{renameItemModalOpen && <RenameCollectionItem item={item} collection={collection} onClose={() => setRenameItemModalOpen(false)} />}
|
{renameItemModalOpen && (
|
||||||
{cloneItemModalOpen && <CloneCollectionItem item={item} collection={collection} onClose={() => setCloneItemModalOpen(false)} />}
|
<RenameCollectionItem item={item} collection={collection} onClose={() => setRenameItemModalOpen(false)} />
|
||||||
{deleteItemModalOpen && <DeleteCollectionItem item={item} collection={collection} onClose={() => setDeleteItemModalOpen(false)} />}
|
)}
|
||||||
{newRequestModalOpen && <NewRequest item={item} collection={collection} onClose={() => setNewRequestModalOpen(false)} />}
|
{cloneItemModalOpen && (
|
||||||
{newFolderModalOpen && <NewFolder item={item} collection={collection} onClose={() => setNewFolderModalOpen(false)} />}
|
<CloneCollectionItem item={item} collection={collection} onClose={() => setCloneItemModalOpen(false)} />
|
||||||
{runCollectionModalOpen && <RunCollectionItem collection={collection} item={item} onClose={() => setRunCollectionModalOpen(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={itemRowClassName} ref={(node) => drag(drop(node))}>
|
||||||
<div className="flex items-center h-full w-full">
|
<div className="flex items-center h-full w-full">
|
||||||
{indents && indents.length
|
{indents && indents.length
|
||||||
@ -185,7 +199,14 @@ const CollectionItem = ({ item, collection, searchText }) => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ width: 16, minWidth: 16 }}>
|
<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>
|
||||||
|
|
||||||
<div className="ml-1 flex items-center overflow-hidden">
|
<div className="ml-1 flex items-center overflow-hidden">
|
||||||
|
@ -15,7 +15,10 @@ const RenameCollection = ({ collection, onClose }) => {
|
|||||||
name: collection.name
|
name: collection.name
|
||||||
},
|
},
|
||||||
validationSchema: Yup.object({
|
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) => {
|
onSubmit: (values) => {
|
||||||
dispatch(renameCollection(values.name, collection.uid));
|
dispatch(renameCollection(values.name, collection.uid));
|
||||||
|
@ -97,13 +97,26 @@ const Collection = ({ collection, searchText }) => {
|
|||||||
<StyledWrapper className="flex flex-col">
|
<StyledWrapper className="flex flex-col">
|
||||||
{showNewRequestModal && <NewRequest collection={collection} onClose={() => setShowNewRequestModal(false)} />}
|
{showNewRequestModal && <NewRequest collection={collection} onClose={() => setShowNewRequestModal(false)} />}
|
||||||
{showNewFolderModal && <NewFolder collection={collection} onClose={() => setShowNewFolderModal(false)} />}
|
{showNewFolderModal && <NewFolder collection={collection} onClose={() => setShowNewFolderModal(false)} />}
|
||||||
{showRenameCollectionModal && <RenameCollection collection={collection} onClose={() => setShowRenameCollectionModal(false)} />}
|
{showRenameCollectionModal && (
|
||||||
{showRemoveCollectionModal && <RemoveCollection collection={collection} onClose={() => setShowRemoveCollectionModal(false)} />}
|
<RenameCollection collection={collection} onClose={() => setShowRenameCollectionModal(false)} />
|
||||||
{showRunCollectionModal && <RunCollectionItem collection={collection} onClose={() => setShowRunCollectionModal(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 py-1 collection-name items-center" ref={drop}>
|
||||||
<div className="flex flex-grow items-center overflow-hidden" onClick={handleClick}>
|
<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)' }} />
|
<IconChevronRight
|
||||||
<div className="ml-1" id="sidebar-collection-name">{collection.name}</div>
|
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>
|
||||||
<div className="collection-actions">
|
<div className="collection-actions">
|
||||||
<Dropdown onCreate={onMenuDropdownCreate} icon={<MenuIcon />} placement="bottom-start">
|
<Dropdown onCreate={onMenuDropdownCreate} icon={<MenuIcon />} placement="bottom-start">
|
||||||
|
@ -18,10 +18,16 @@ const CreateOrOpenCollection = () => {
|
|||||||
const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false);
|
const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false);
|
||||||
|
|
||||||
const handleOpenCollection = () => {
|
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 = () => (
|
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
|
Create
|
||||||
</LinkStyle>
|
</LinkStyle>
|
||||||
);
|
);
|
||||||
|
@ -10,7 +10,7 @@ const StyledWrapper = styled.div`
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: ${(props) => props.theme.plainGrid.hoverBg};;
|
background-color: ${(props) => props.theme.plainGrid.hoverBg};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -20,8 +20,14 @@ const CreateCollection = ({ onClose }) => {
|
|||||||
collectionLocation: ''
|
collectionLocation: ''
|
||||||
},
|
},
|
||||||
validationSchema: Yup.object({
|
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'),
|
collectionName: Yup.string()
|
||||||
collectionFolderName: Yup.string().min(1, 'must be atleast 1 characters').max(50, 'must be 50 characters or less').required('folder name is required'),
|
.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')
|
collectionLocation: Yup.string().required('location is required')
|
||||||
}),
|
}),
|
||||||
onSubmit: (values) => {
|
onSubmit: (values) => {
|
||||||
@ -58,7 +64,7 @@ const CreateCollection = ({ onClose }) => {
|
|||||||
<form className="bruno-form" onSubmit={formik.handleSubmit}>
|
<form className="bruno-form" onSubmit={formik.handleSubmit}>
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="collectionName" className="flex items-center">
|
<label htmlFor="collectionName" className="flex items-center">
|
||||||
<span className='font-semibold'>Name</span>
|
<span className="font-semibold">Name</span>
|
||||||
<Tooltip text="Name of the collection" tooltipId="collection-name" />
|
<Tooltip text="Name of the collection" tooltipId="collection-name" />
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@ -74,10 +80,12 @@ const CreateCollection = ({ onClose }) => {
|
|||||||
spellCheck="false"
|
spellCheck="false"
|
||||||
value={formik.values.collectionName || ''}
|
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">
|
<label htmlFor="collectionFolderName" className="flex items-center mt-3">
|
||||||
<span className='font-semibold'>Folder Name</span>
|
<span className="font-semibold">Folder Name</span>
|
||||||
<Tooltip text="Name of the folder where your collection is stored" tooltipId="collection-folder-name" />
|
<Tooltip text="Name of the folder where your collection is stored" tooltipId="collection-folder-name" />
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@ -92,7 +100,9 @@ const CreateCollection = ({ onClose }) => {
|
|||||||
spellCheck="false"
|
spellCheck="false"
|
||||||
value={formik.values.collectionFolderName || ''}
|
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">
|
<label htmlFor="collectionLocation" className="block font-semibold mt-3">
|
||||||
|
@ -33,22 +33,13 @@ const ImportCollection = ({ onClose, handleSubmit }) => {
|
|||||||
return (
|
return (
|
||||||
<Modal size="sm" title="Import Collection" hideFooter={true} handleConfirm={onClose} handleCancel={onClose}>
|
<Modal size="sm" title="Import Collection" hideFooter={true} handleConfirm={onClose} handleCancel={onClose}>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div className="text-link hover:underline cursor-pointer" onClick={handleImportBrunoCollection}>
|
||||||
className='text-link hover:underline cursor-pointer'
|
|
||||||
onClick={handleImportBrunoCollection}
|
|
||||||
>
|
|
||||||
Bruno Collection
|
Bruno Collection
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className="text-link hover:underline cursor-pointer mt-2" onClick={handleImportPostmanCollection}>
|
||||||
className='text-link hover:underline cursor-pointer mt-2'
|
|
||||||
onClick={handleImportPostmanCollection}
|
|
||||||
>
|
|
||||||
Postman Collection
|
Postman Collection
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className="text-link hover:underline cursor-pointer mt-2" onClick={handleImportInsomniaCollection}>
|
||||||
className='text-link hover:underline cursor-pointer mt-2'
|
|
||||||
onClick={handleImportInsomniaCollection}
|
|
||||||
>
|
|
||||||
Insomnia Collection
|
Insomnia Collection
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -15,7 +15,10 @@ const ImportCollectionLocation = ({ onClose, handleSubmit, collectionName }) =>
|
|||||||
collectionLocation: ''
|
collectionLocation: ''
|
||||||
},
|
},
|
||||||
validationSchema: Yup.object({
|
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) => {
|
onSubmit: (values) => {
|
||||||
console.log('here');
|
console.log('here');
|
||||||
@ -49,7 +52,7 @@ const ImportCollectionLocation = ({ onClose, handleSubmit, collectionName }) =>
|
|||||||
<label htmlFor="collectionName" className="block font-semibold">
|
<label htmlFor="collectionName" className="block font-semibold">
|
||||||
Name
|
Name
|
||||||
</label>
|
</label>
|
||||||
<div className='mt-2'>{collectionName}</div>
|
<div className="mt-2">{collectionName}</div>
|
||||||
|
|
||||||
<>
|
<>
|
||||||
<label htmlFor="collectionLocation" className="block font-semibold mt-3">
|
<label htmlFor="collectionLocation" className="block font-semibold mt-3">
|
||||||
|
@ -25,7 +25,7 @@ const NewFolder = ({ collection, item, onClose }) => {
|
|||||||
if (item && item.uid) {
|
if (item && item.uid) {
|
||||||
return true;
|
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}
|
onChange={formik.handleChange}
|
||||||
value={formik.values.folderName || ''}
|
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>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@ -30,7 +30,7 @@ const NewRequest = ({ collection, item, isEphermal, onClose }) => {
|
|||||||
.test({
|
.test({
|
||||||
name: 'requestName',
|
name: 'requestName',
|
||||||
message: 'The request name "index" is reserved in bruno',
|
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) => {
|
onSubmit: (values) => {
|
||||||
@ -140,7 +140,9 @@ const NewRequest = ({ collection, item, isEphermal, onClose }) => {
|
|||||||
onChange={formik.handleChange}
|
onChange={formik.handleChange}
|
||||||
value={formik.values.requestName || ''}
|
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>
|
||||||
|
|
||||||
<div className="mt-4">
|
<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 mt-2 ">
|
||||||
<div className="flex items-center h-full method-selector-container">
|
<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>
|
||||||
<div className="flex items-center flex-grow input-container h-full">
|
<div className="flex items-center flex-grow input-container h-full">
|
||||||
<input
|
<input
|
||||||
@ -167,7 +172,9 @@ const NewRequest = ({ collection, item, isEphermal, onClose }) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@ -45,13 +45,17 @@ const TitleBar = () => {
|
|||||||
const handleTitleClick = () => dispatch(showHomePage());
|
const handleTitleClick = () => dispatch(showHomePage());
|
||||||
|
|
||||||
const handleOpenCollection = () => {
|
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 (
|
return (
|
||||||
<StyledWrapper className="px-2 py-2">
|
<StyledWrapper className="px-2 py-2">
|
||||||
{createCollectionModalOpen ? <CreateCollection onClose={() => setCreateCollectionModalOpen(false)} /> : null}
|
{createCollectionModalOpen ? <CreateCollection onClose={() => setCreateCollectionModalOpen(false)} /> : null}
|
||||||
{importCollectionModalOpen ? <ImportCollection onClose={() => setImportCollectionModalOpen(false)} handleSubmit={handleImportCollection} /> : null}
|
{importCollectionModalOpen ? (
|
||||||
|
<ImportCollection onClose={() => setImportCollectionModalOpen(false)} handleSubmit={handleImportCollection} />
|
||||||
|
) : null}
|
||||||
{importCollectionLocationModalOpen ? (
|
{importCollectionLocationModalOpen ? (
|
||||||
<ImportCollectionLocation
|
<ImportCollectionLocation
|
||||||
collectionName={importedCollection.name}
|
collectionName={importedCollection.name}
|
||||||
|
@ -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="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 ">
|
<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>
|
||||||
<div className="pl-1" style={{ position: 'relative', top: '3px' }}>
|
<div className="pl-1" style={{ position: 'relative', top: '3px' }}>
|
||||||
{storedTheme === 'dark' ? (
|
{storedTheme === 'dark' ? (
|
||||||
|
@ -49,7 +49,6 @@ const StyledWrapper = styled.div`
|
|||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default StyledWrapper;
|
export default StyledWrapper;
|
||||||
|
@ -27,32 +27,32 @@ class SingleLineEditor extends Component {
|
|||||||
lineWrapping: false,
|
lineWrapping: false,
|
||||||
lineNumbers: false,
|
lineNumbers: false,
|
||||||
theme: this.props.theme === 'dark' ? 'monokai' : 'default',
|
theme: this.props.theme === 'dark' ? 'monokai' : 'default',
|
||||||
mode: "brunovariables",
|
mode: 'brunovariables',
|
||||||
brunoVarInfo: {
|
brunoVarInfo: {
|
||||||
variables: getAllVariables(this.props.collection),
|
variables: getAllVariables(this.props.collection)
|
||||||
},
|
},
|
||||||
extraKeys: {
|
extraKeys: {
|
||||||
"Enter": () => {
|
Enter: () => {
|
||||||
if (this.props.onRun) {
|
if (this.props.onRun) {
|
||||||
this.props.onRun();
|
this.props.onRun();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Ctrl-Enter": () => {
|
'Ctrl-Enter': () => {
|
||||||
if (this.props.onRun) {
|
if (this.props.onRun) {
|
||||||
this.props.onRun();
|
this.props.onRun();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Cmd-Enter": () => {
|
'Cmd-Enter': () => {
|
||||||
if (this.props.onRun) {
|
if (this.props.onRun) {
|
||||||
this.props.onRun();
|
this.props.onRun();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Alt-Enter": () => {
|
'Alt-Enter': () => {
|
||||||
if (this.props.onRun) {
|
if (this.props.onRun) {
|
||||||
this.props.onRun();
|
this.props.onRun();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Shift-Enter": () => {
|
'Shift-Enter': () => {
|
||||||
if (this.props.onRun) {
|
if (this.props.onRun) {
|
||||||
this.props.onRun();
|
this.props.onRun();
|
||||||
}
|
}
|
||||||
@ -69,8 +69,8 @@ class SingleLineEditor extends Component {
|
|||||||
},
|
},
|
||||||
'Cmd-F': () => {},
|
'Cmd-F': () => {},
|
||||||
'Ctrl-F': () => {},
|
'Ctrl-F': () => {},
|
||||||
'Tab': () => {}
|
Tab: () => {}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
this.editor.setValue(this.props.value || '');
|
this.editor.setValue(this.props.value || '');
|
||||||
this.editor.on('change', this._onEdit);
|
this.editor.on('change', this._onEdit);
|
||||||
@ -115,14 +115,12 @@ class SingleLineEditor extends Component {
|
|||||||
let variables = getAllVariables(this.props.collection);
|
let variables = getAllVariables(this.props.collection);
|
||||||
this.variables = variables;
|
this.variables = variables;
|
||||||
|
|
||||||
defineCodeMirrorBrunoVariablesMode(variables, "text/plain");
|
defineCodeMirrorBrunoVariablesMode(variables, 'text/plain');
|
||||||
this.editor.setOption('mode', 'brunovariables');
|
this.editor.setOption('mode', 'brunovariables');
|
||||||
}
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return <StyledWrapper ref={this.editorRef} className="single-line-editor"></StyledWrapper>;
|
||||||
<StyledWrapper ref={this.editorRef} className="single-line-editor"></StyledWrapper>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export default SingleLineEditor;
|
export default SingleLineEditor;
|
||||||
|
@ -4,7 +4,17 @@ import { Tooltip as ReactTooltip } from 'react-tooltip';
|
|||||||
const Tooltip = ({ text, tooltipId }) => {
|
const Tooltip = ({ text, tooltipId }) => {
|
||||||
return (
|
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}}>
|
<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="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" />
|
<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>
|
</svg>
|
||||||
|
@ -2,11 +2,7 @@ import React, {useRef} from 'react';
|
|||||||
import StyledWrapper from './StyledWrapper';
|
import StyledWrapper from './StyledWrapper';
|
||||||
import useOnClickOutside from 'hooks/useOnClickOutside';
|
import useOnClickOutside from 'hooks/useOnClickOutside';
|
||||||
|
|
||||||
const PopOver = ({
|
const PopOver = ({ children, iconRef, handleClose }) => {
|
||||||
children,
|
|
||||||
iconRef,
|
|
||||||
handleClose
|
|
||||||
}) => {
|
|
||||||
const popOverRef = useRef(null);
|
const popOverRef = useRef(null);
|
||||||
|
|
||||||
useOnClickOutside(popOverRef, (e) => {
|
useOnClickOutside(popOverRef, (e) => {
|
||||||
|
@ -10,6 +10,6 @@ const StyledWrapper = styled.div`
|
|||||||
width: 1rem;
|
width: 1rem;
|
||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
}
|
}
|
||||||
`
|
`;
|
||||||
|
|
||||||
export default StyledWrapper;
|
export default StyledWrapper;
|
@ -14,6 +14,6 @@ const StyledWrapper = styled.div`
|
|||||||
inline-size: 600px;
|
inline-size: 600px;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
}
|
}
|
||||||
`
|
`;
|
||||||
|
|
||||||
export default StyledWrapper;
|
export default StyledWrapper;
|
@ -18,25 +18,33 @@ const VariablesTable = ({ variables, collectionVariables }) => {
|
|||||||
return (
|
return (
|
||||||
<StyledWrapper>
|
<StyledWrapper>
|
||||||
<div className="flex flex-col w-full">
|
<div className="flex flex-col w-full">
|
||||||
<div className='mb-2 font-medium'>Environment Variables</div>
|
<div className="mb-2 font-medium">Environment Variables</div>
|
||||||
{(variables && variables.length) ? variables.map((variable) => {
|
{variables && variables.length ? (
|
||||||
|
variables.map((variable) => {
|
||||||
return (
|
return (
|
||||||
<div key={variable.uid} className="flex">
|
<div key={variable.uid} className="flex">
|
||||||
<div className='variable-name text-yellow-600 text-right pr-2'>{variable.name}</div>
|
<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 className="variable-value pl-2 whitespace-normal text-left flex-grow">{variable.value}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}) : <small>No env variables found</small>}
|
})
|
||||||
|
) : (
|
||||||
|
<small>No env variables found</small>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className='mt-2 font-medium'>Collection Variables</div>
|
<div className="mt-2 font-medium">Collection Variables</div>
|
||||||
{(collectionVars && collectionVars.length) ? collectionVars.map((variable) => {
|
{collectionVars && collectionVars.length ? (
|
||||||
|
collectionVars.map((variable) => {
|
||||||
return (
|
return (
|
||||||
<div key={variable.uid} className="flex">
|
<div key={variable.uid} className="flex">
|
||||||
<div className='variable-name text-yellow-600 text-right pr-2'>{variable.name}</div>
|
<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 className="variable-value pl-2 whitespace-normal text-left flex-grow">{variable.value}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}) : <small>No collection variables found</small>}
|
})
|
||||||
|
) : (
|
||||||
|
<small>No collection variables found</small>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</StyledWrapper>
|
</StyledWrapper>
|
||||||
);
|
);
|
||||||
|
@ -14,39 +14,35 @@ const VariablesView = ({collection}) => {
|
|||||||
const environment = findEnvironmentInCollection(collection, collection.activeEnvironmentUid);
|
const environment = findEnvironmentInCollection(collection, collection.activeEnvironmentUid);
|
||||||
const variables = get(environment, 'variables', []);
|
const variables = get(environment, 'variables', []);
|
||||||
const enabledVariables = filter(variables, (variable) => variable.enabled);
|
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 (
|
return (
|
||||||
<StyledWrapper
|
<StyledWrapper className="mr-2 server-syncstatus-icon" ref={iconRef}>
|
||||||
className="mr-2 server-syncstatus-icon"
|
<div
|
||||||
ref={iconRef}
|
className="flex p-1 items-center"
|
||||||
>
|
|
||||||
<div className="flex p-1 items-center"
|
|
||||||
onClick={() => setPopOverOpen(true)}
|
onClick={() => setPopOverOpen(true)}
|
||||||
onMouseEnter={() => setPopOverOpen(true)}
|
onMouseEnter={() => setPopOverOpen(true)}
|
||||||
onMouseLeave={() => setPopOverOpen(false)}
|
onMouseLeave={() => setPopOverOpen(false)}
|
||||||
>
|
>
|
||||||
<div className='cursor-pointer view-environment'>
|
<div className="cursor-pointer view-environment">
|
||||||
<IconEye size={18} strokeWidth={1.5} />
|
<IconEye size={18} strokeWidth={1.5} />
|
||||||
</div>
|
</div>
|
||||||
{popOverOpen && (
|
{popOverOpen && (
|
||||||
<PopOver
|
<PopOver iconRef={iconRef} handleClose={() => setPopOverOpen(false)}>
|
||||||
iconRef={iconRef}
|
|
||||||
handleClose={() => setPopOverOpen(false)}
|
|
||||||
>
|
|
||||||
<div className="px-2 py-1">
|
<div className="px-2 py-1">
|
||||||
{showVariablesTable ? (
|
{showVariablesTable ? (
|
||||||
<VariablesTable
|
<VariablesTable variables={enabledVariables} collectionVariables={collection.collectionVariables} />
|
||||||
variables={enabledVariables}
|
) : (
|
||||||
collectionVariables={collection.collectionVariables}
|
'No variables found'
|
||||||
/>
|
)}
|
||||||
) : 'No variables found'}
|
|
||||||
</div>
|
</div>
|
||||||
</PopOver>
|
</PopOver>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</StyledWrapper>
|
</StyledWrapper>
|
||||||
)
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default VariablesView;
|
export default VariablesView;
|
@ -18,7 +18,9 @@ const Welcome = () => {
|
|||||||
const [importCollectionLocationModalOpen, setImportCollectionLocationModalOpen] = useState(false);
|
const [importCollectionLocationModalOpen, setImportCollectionLocationModalOpen] = useState(false);
|
||||||
|
|
||||||
const handleOpenCollection = () => {
|
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) => {
|
const handleImportCollection = (collection) => {
|
||||||
@ -37,7 +39,9 @@ const Welcome = () => {
|
|||||||
return (
|
return (
|
||||||
<StyledWrapper className="pb-4 px-6 mt-6">
|
<StyledWrapper className="pb-4 px-6 mt-6">
|
||||||
{createCollectionModalOpen ? <CreateCollection onClose={() => setCreateCollectionModalOpen(false)} /> : null}
|
{createCollectionModalOpen ? <CreateCollection onClose={() => setCreateCollectionModalOpen(false)} /> : null}
|
||||||
{importCollectionModalOpen ? <ImportCollection onClose={() => setImportCollectionModalOpen(false)} handleSubmit={handleImportCollection} /> : null}
|
{importCollectionModalOpen ? (
|
||||||
|
<ImportCollection onClose={() => setImportCollectionModalOpen(false)} handleSubmit={handleImportCollection} />
|
||||||
|
) : null}
|
||||||
{importCollectionLocationModalOpen ? (
|
{importCollectionLocationModalOpen ? (
|
||||||
<ImportCollectionLocation
|
<ImportCollectionLocation
|
||||||
collectionName={importedCollection.name}
|
collectionName={importedCollection.name}
|
||||||
@ -62,13 +66,13 @@ const Welcome = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex items-center ml-6" onClick={handleOpenCollection}>
|
<div className="flex items-center ml-6" onClick={handleOpenCollection}>
|
||||||
<IconFolders size={18} strokeWidth={2} />
|
<IconFolders size={18} strokeWidth={2} />
|
||||||
<span className="label ml-2">
|
<span className="label ml-2">Open Collection</span>
|
||||||
Open Collection
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center ml-6" onClick={() => setImportCollectionModalOpen(true)}>
|
<div className="flex items-center ml-6" onClick={() => setImportCollectionModalOpen(true)}>
|
||||||
<IconUpload size={18} strokeWidth={2} />
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import { useEffect } from 'react';
|
|||||||
const useOnClickOutside = (ref, handler) => {
|
const useOnClickOutside = (ref, handler) => {
|
||||||
useEffect(
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
const listener = event => {
|
const listener = (event) => {
|
||||||
// Do nothing if clicking ref's element or descendent elements
|
// Do nothing if clicking ref's element or descendent elements
|
||||||
if (!ref.current || ref.current.contains(event.target)) {
|
if (!ref.current || ref.current.contains(event.target)) {
|
||||||
return;
|
return;
|
||||||
|
@ -31,7 +31,10 @@ export default class MyDocument extends Document {
|
|||||||
return (
|
return (
|
||||||
<Html>
|
<Html>
|
||||||
<Head>
|
<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>
|
</Head>
|
||||||
<body id="bruno-app-body">
|
<body id="bruno-app-body">
|
||||||
<Main />
|
<Main />
|
||||||
|
@ -29,9 +29,7 @@ export const AppProvider = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<AppContext.Provider {...props} value="appProvider">
|
<AppContext.Provider {...props} value="appProvider">
|
||||||
<StyledWrapper>
|
<StyledWrapper>{props.children}</StyledWrapper>
|
||||||
{props.children}
|
|
||||||
</StyledWrapper>
|
|
||||||
</AppContext.Provider>
|
</AppContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -85,10 +85,10 @@ const useCollectionTreeSync = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const _displayError = (error) => {
|
const _displayError = (error) => {
|
||||||
if(typeof error === "string") {
|
if (typeof error === 'string') {
|
||||||
return toast.error(error || 'Something went wrong!');
|
return toast.error(error || 'Something went wrong!');
|
||||||
}
|
}
|
||||||
if(typeof message === "object") {
|
if (typeof message === 'object') {
|
||||||
return toast.error(error.message || 'Something went wrong!');
|
return toast.error(error.message || 'Something went wrong!');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -165,9 +165,15 @@ export const HotkeysProvider = (props) => {
|
|||||||
return (
|
return (
|
||||||
<HotkeysContext.Provider {...props} value="hotkey">
|
<HotkeysContext.Provider {...props} value="hotkey">
|
||||||
{showBrunoSupportModal && <BrunoSupport onClose={() => setShowBrunoSupportModal(false)} />}
|
{showBrunoSupportModal && <BrunoSupport onClose={() => setShowBrunoSupportModal(false)} />}
|
||||||
{showSaveRequestModal && <SaveRequest items={getCurrentCollectionItems()} onClose={() => setShowSaveRequestModal(false)} />}
|
{showSaveRequestModal && (
|
||||||
{showEnvSettingsModal && <EnvironmentSettings collection={getCurrentCollection()} onClose={() => setShowEnvSettingsModal(false)} />}
|
<SaveRequest items={getCurrentCollectionItems()} onClose={() => setShowSaveRequestModal(false)} />
|
||||||
{showNewRequestModal && <NewRequest collection={getCurrentCollection()} onClose={() => setShowNewRequestModal(false)} />}
|
)}
|
||||||
|
{showEnvSettingsModal && (
|
||||||
|
<EnvironmentSettings collection={getCurrentCollection()} onClose={() => setShowEnvSettingsModal(false)} />
|
||||||
|
)}
|
||||||
|
{showNewRequestModal && (
|
||||||
|
<NewRequest collection={getCurrentCollection()} onClose={() => setShowNewRequestModal(false)} />
|
||||||
|
)}
|
||||||
<div>{props.children}</div>
|
<div>{props.children}</div>
|
||||||
</HotkeysContext.Provider>
|
</HotkeysContext.Provider>
|
||||||
);
|
);
|
||||||
|
@ -30,21 +30,20 @@ export const PreferencesProvider = (props) => {
|
|||||||
const { ipcRenderer } = window;
|
const { ipcRenderer } = window;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
ipcRenderer
|
ipcRenderer.invoke('renderer:set-preferences', preferences).catch((err) => {
|
||||||
.invoke('renderer:set-preferences', preferences)
|
|
||||||
.catch(err => {
|
|
||||||
toast.error(err.message || 'Preferences sync error');
|
toast.error(err.message || 'Preferences sync error');
|
||||||
});
|
});
|
||||||
}, [preferences, toast]);
|
}, [preferences, toast]);
|
||||||
|
|
||||||
const validatedSetPreferences = (newPreferences) => {
|
const validatedSetPreferences = (newPreferences) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
preferencesSchema.validate(newPreferences, { abortEarly: true })
|
preferencesSchema
|
||||||
.then(validatedPreferences => {
|
.validate(newPreferences, { abortEarly: true })
|
||||||
|
.then((validatedPreferences) => {
|
||||||
setPreferences(validatedPreferences);
|
setPreferences(validatedPreferences);
|
||||||
resolve(validatedPreferences);
|
resolve(validatedPreferences);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch((error) => {
|
||||||
let errMsg = error.message || 'Preferences validation error';
|
let errMsg = error.message || 'Preferences validation error';
|
||||||
toast.error(errMsg);
|
toast.error(errMsg);
|
||||||
reject(error);
|
reject(error);
|
||||||
@ -60,9 +59,7 @@ export const PreferencesProvider = (props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<PreferencesContext.Provider value={value}>
|
<PreferencesContext.Provider value={value}>
|
||||||
<>
|
<>{props.children}</>
|
||||||
{props.children}
|
|
||||||
</>
|
|
||||||
</PreferencesContext.Provider>
|
</PreferencesContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -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;
|
export default appSlice.reducer;
|
||||||
|
@ -56,10 +56,7 @@ export const renameCollection = (newName, collectionUid) => (dispatch, getState)
|
|||||||
return reject(new Error('Collection not found'));
|
return reject(new Error('Collection not found'));
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcRenderer
|
ipcRenderer.invoke('renderer:rename-collection', newName, collection.pathname).then(resolve).catch(reject);
|
||||||
.invoke('renderer:rename-collection', newName, collection.pathname)
|
|
||||||
.then(resolve)
|
|
||||||
.catch(reject);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -166,12 +163,21 @@ export const runCollectionFolder = (collectionUid, folderUid, recursive) => (dis
|
|||||||
|
|
||||||
const environment = findEnvironmentInCollection(collectionCopy, collection.activeEnvironmentUid);
|
const environment = findEnvironmentInCollection(collectionCopy, collection.activeEnvironmentUid);
|
||||||
|
|
||||||
dispatch(resetRunResults({
|
dispatch(
|
||||||
|
resetRunResults({
|
||||||
collectionUid: collection.uid
|
collectionUid: collection.uid
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
|
|
||||||
ipcRenderer
|
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)
|
.then(resolve)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
toast.error(get(err, 'error.message') || 'Something went wrong!');
|
toast.error(get(err, 'error.message') || 'Something went wrong!');
|
||||||
@ -190,7 +196,10 @@ export const newFolder = (folderName, collectionUid, itemUid) => (dispatch, getS
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!itemUid) {
|
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) {
|
if (!folderWithSameNameExists) {
|
||||||
const fullName = `${collection.pathname}${PATH_SEPARATOR}${folderName}`;
|
const fullName = `${collection.pathname}${PATH_SEPARATOR}${folderName}`;
|
||||||
const { ipcRenderer } = window;
|
const { ipcRenderer } = window;
|
||||||
@ -205,7 +214,10 @@ export const newFolder = (folderName, collectionUid, itemUid) => (dispatch, getS
|
|||||||
} else {
|
} else {
|
||||||
const currentItem = findItemInCollection(collection, itemUid);
|
const currentItem = findItemInCollection(collection, itemUid);
|
||||||
if (currentItem) {
|
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) {
|
if (!folderWithSameNameExists) {
|
||||||
const fullName = `${currentItem.pathname}${PATH_SEPARATOR}${folderName}`;
|
const fullName = `${currentItem.pathname}${PATH_SEPARATOR}${folderName}`;
|
||||||
const { ipcRenderer } = window;
|
const { ipcRenderer } = window;
|
||||||
@ -250,10 +262,7 @@ export const renameItem = (newName, itemUid, collectionUid) => (dispatch, getSta
|
|||||||
}
|
}
|
||||||
const { ipcRenderer } = window;
|
const { ipcRenderer } = window;
|
||||||
|
|
||||||
ipcRenderer
|
ipcRenderer.invoke('renderer:rename-item', item.pathname, newPathname, newName).then(resolve).catch(reject);
|
||||||
.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));
|
const itemToSave = refreshUidsInItem(transformRequestToSaveToFilesystem(item));
|
||||||
itemToSave.name = trim(newName);
|
itemToSave.name = trim(newName);
|
||||||
if (!parentItem) {
|
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) {
|
if (!reqWithSameNameExists) {
|
||||||
const fullName = `${collection.pathname}${PATH_SEPARATOR}${filename}`;
|
const fullName = `${collection.pathname}${PATH_SEPARATOR}${filename}`;
|
||||||
const { ipcRenderer } = window;
|
const { ipcRenderer } = window;
|
||||||
const requestItems = filter(collection.items, (i) => i.type !== 'folder');
|
const requestItems = filter(collection.items, (i) => i.type !== 'folder');
|
||||||
itemToSave.seq = requestItems ? (requestItems.length + 1) : 1;
|
itemToSave.seq = requestItems ? requestItems.length + 1 : 1;
|
||||||
|
|
||||||
itemSchema
|
itemSchema
|
||||||
.validate(itemToSave)
|
.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'));
|
return reject(new Error('Duplicate request names are not allowed under the same folder'));
|
||||||
}
|
}
|
||||||
} else {
|
} 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) {
|
if (!reqWithSameNameExists) {
|
||||||
const dirname = getDirectoryName(item.pathname);
|
const dirname = getDirectoryName(item.pathname);
|
||||||
const fullName = path.join(dirname, filename);
|
const fullName = path.join(dirname, filename);
|
||||||
const { ipcRenderer } = window;
|
const { ipcRenderer } = window;
|
||||||
const requestItems = filter(parentItem.items, (i) => i.type !== 'folder');
|
const requestItems = filter(parentItem.items, (i) => i.type !== 'folder');
|
||||||
itemToSave.seq = requestItems ? (requestItems.length + 1) : 1;
|
itemToSave.seq = requestItems ? requestItems.length + 1 : 1;
|
||||||
|
|
||||||
itemSchema
|
itemSchema
|
||||||
.validate(itemToSave)
|
.validate(itemToSave)
|
||||||
@ -542,7 +557,10 @@ export const newHttpRequest = (params) => (dispatch, getState) => {
|
|||||||
// itemUid is null when we are creating a new request at the root level
|
// itemUid is null when we are creating a new request at the root level
|
||||||
const filename = resolveRequestFilename(requestName);
|
const filename = resolveRequestFilename(requestName);
|
||||||
if (!itemUid) {
|
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');
|
const requestItems = filter(collection.items, (i) => i.type !== 'folder');
|
||||||
item.seq = requestItems.length + 1;
|
item.seq = requestItems.length + 1;
|
||||||
|
|
||||||
@ -557,7 +575,10 @@ export const newHttpRequest = (params) => (dispatch, getState) => {
|
|||||||
} else {
|
} else {
|
||||||
const currentItem = findItemInCollection(collection, itemUid);
|
const currentItem = findItemInCollection(collection, itemUid);
|
||||||
if (currentItem) {
|
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');
|
const requestItems = filter(currentItem.items, (i) => i.type !== 'folder');
|
||||||
item.seq = requestItems.length + 1;
|
item.seq = requestItems.length + 1;
|
||||||
if (!reqWithSameNameExists) {
|
if (!reqWithSameNameExists) {
|
||||||
@ -583,13 +604,17 @@ export const addEnvironment = (name, collectionUid) => (dispatch, getState) => {
|
|||||||
|
|
||||||
ipcRenderer
|
ipcRenderer
|
||||||
.invoke('renderer:create-environment', collection.pathname, name)
|
.invoke('renderer:create-environment', collection.pathname, name)
|
||||||
.then(dispatch(updateLastAction({
|
.then(
|
||||||
|
dispatch(
|
||||||
|
updateLastAction({
|
||||||
collectionUid,
|
collectionUid,
|
||||||
lastAction: {
|
lastAction: {
|
||||||
type: 'ADD_ENVIRONMENT',
|
type: 'ADD_ENVIRONMENT',
|
||||||
payload: name
|
payload: name
|
||||||
}
|
}
|
||||||
})))
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
.then(resolve)
|
.then(resolve)
|
||||||
.catch(reject);
|
.catch(reject);
|
||||||
});
|
});
|
||||||
@ -793,9 +818,6 @@ export const importCollection = (collection, collectionLocation) => (dispatch, g
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const { ipcRenderer } = window;
|
const { ipcRenderer } = window;
|
||||||
|
|
||||||
ipcRenderer
|
ipcRenderer.invoke('renderer:import-collection', collection, collectionLocation).then(resolve).catch(reject);
|
||||||
.invoke('renderer:import-collection', collection, collectionLocation)
|
|
||||||
.then(resolve)
|
|
||||||
.catch(reject);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -482,7 +482,10 @@ export const collectionsSlice = createSlice({
|
|||||||
if (!item.draft) {
|
if (!item.draft) {
|
||||||
item.draft = cloneDeep(item);
|
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) {
|
if (!item.draft) {
|
||||||
item.draft = cloneDeep(item);
|
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) {
|
if (!item.draft) {
|
||||||
item.draft = cloneDeep(item);
|
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
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1088,7 +1096,6 @@ export const collectionsSlice = createSlice({
|
|||||||
info.status = 'ended';
|
info.status = 'ended';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (type === 'request-queued') {
|
if (type === 'request-queued') {
|
||||||
collection.runnerResult.items.push({
|
collection.runnerResult.items.push({
|
||||||
uid: request.uid,
|
uid: request.uid,
|
||||||
@ -1122,7 +1129,7 @@ export const collectionsSlice = createSlice({
|
|||||||
const item = collection.runnerResult.items.find((i) => i.uid === request.uid);
|
const item = collection.runnerResult.items.find((i) => i.uid === request.uid);
|
||||||
item.error = action.payload.error;
|
item.error = action.payload.error;
|
||||||
item.responseReceived = action.payload.responseReceived;
|
item.responseReceived = action.payload.responseReceived;
|
||||||
item.status = "error";
|
item.status = 'error';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -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;
|
export default tabsSlice.reducer;
|
||||||
|
@ -6,7 +6,7 @@ import { ThemeProvider as SCThemeProvider } from 'styled-components';
|
|||||||
|
|
||||||
export const ThemeContext = createContext();
|
export const ThemeContext = createContext();
|
||||||
export const ThemeProvider = (props) => {
|
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 [storedTheme, setStoredTheme] = useLocalStorage('bruno.theme', isBrowserThemeLight ? 'light' : 'dark');
|
||||||
|
|
||||||
const theme = themes[storedTheme];
|
const theme = themes[storedTheme];
|
||||||
|
@ -5,9 +5,7 @@ import { useTheme } from 'providers/Theme';
|
|||||||
export const ToastContext = React.createContext();
|
export const ToastContext = React.createContext();
|
||||||
|
|
||||||
export const ToastProvider = (props) => {
|
export const ToastProvider = (props) => {
|
||||||
const {
|
const { storedTheme } = useTheme();
|
||||||
storedTheme
|
|
||||||
} = useTheme();
|
|
||||||
|
|
||||||
const toastOptions = { duration: 2000 };
|
const toastOptions = { duration: 2000 };
|
||||||
if (storedTheme === 'dark') {
|
if (storedTheme === 'dark') {
|
||||||
@ -21,9 +19,7 @@ export const ToastProvider = (props) => {
|
|||||||
return (
|
return (
|
||||||
<ToastContext.Provider {...props} value="toastProvider">
|
<ToastContext.Provider {...props} value="toastProvider">
|
||||||
<Toaster toastOptions={toastOptions} />
|
<Toaster toastOptions={toastOptions} />
|
||||||
<div>
|
<div>{props.children}</div>
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
</ToastContext.Provider>
|
</ToastContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -20,7 +20,7 @@ const darkTheme = {
|
|||||||
bg: 'rgb(48, 48, 49)',
|
bg: 'rgb(48, 48, 49)',
|
||||||
|
|
||||||
name: {
|
name: {
|
||||||
color: '#569cd6',
|
color: '#569cd6'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ const lightTheme = {
|
|||||||
green: '#047857',
|
green: '#047857',
|
||||||
danger: 'rgb(185, 28, 28)',
|
danger: 'rgb(185, 28, 28)',
|
||||||
muted: '#4b5563',
|
muted: '#4b5563',
|
||||||
purple: '#8e44ad',
|
purple: '#8e44ad'
|
||||||
},
|
},
|
||||||
bg: {
|
bg: {
|
||||||
danger: '#dc3545'
|
danger: '#dc3545'
|
||||||
@ -24,7 +24,7 @@ const lightTheme = {
|
|||||||
bg: '#fff',
|
bg: '#fff',
|
||||||
|
|
||||||
name: {
|
name: {
|
||||||
color: '#546de5',
|
color: '#546de5'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -33,7 +33,6 @@ if (!SERVER_RENDERED) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
CodeMirror.defineOption('brunoVarInfo', false, function (cm, options, old) {
|
CodeMirror.defineOption('brunoVarInfo', false, function (cm, options, old) {
|
||||||
|
|
||||||
if (old && old !== CodeMirror.Init) {
|
if (old && old !== CodeMirror.Init) {
|
||||||
const oldOnMouseOver = cm.state.brunoVarInfo.onMouseOver;
|
const oldOnMouseOver = cm.state.brunoVarInfo.onMouseOver;
|
||||||
CodeMirror.off(cm.getWrapperElement(), 'mouseover', oldOnMouseOver);
|
CodeMirror.off(cm.getWrapperElement(), 'mouseover', oldOnMouseOver);
|
||||||
@ -50,10 +49,7 @@ if (!SERVER_RENDERED) {
|
|||||||
|
|
||||||
function createState(options) {
|
function createState(options) {
|
||||||
return {
|
return {
|
||||||
options:
|
options: options instanceof Function ? { render: options } : options === true ? {} : options
|
||||||
options instanceof Function
|
|
||||||
? {render: options}
|
|
||||||
: options === true ? {} : options,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,7 +101,7 @@ if (!SERVER_RENDERED) {
|
|||||||
function onMouseHover(cm, box) {
|
function onMouseHover(cm, box) {
|
||||||
const pos = cm.coordsChar({
|
const pos = cm.coordsChar({
|
||||||
left: (box.left + box.right) / 2,
|
left: (box.left + box.right) / 2,
|
||||||
top: (box.top + box.bottom) / 2,
|
top: (box.top + box.bottom) / 2
|
||||||
});
|
});
|
||||||
|
|
||||||
const state = cm.state.brunoVarInfo;
|
const state = cm.state.brunoVarInfo;
|
||||||
@ -128,21 +124,12 @@ if (!SERVER_RENDERED) {
|
|||||||
const popupBox = popup.getBoundingClientRect();
|
const popupBox = popup.getBoundingClientRect();
|
||||||
const popupStyle = popup.currentStyle || window.getComputedStyle(popup);
|
const popupStyle = popup.currentStyle || window.getComputedStyle(popup);
|
||||||
const popupWidth =
|
const popupWidth =
|
||||||
popupBox.right -
|
popupBox.right - popupBox.left + parseFloat(popupStyle.marginLeft) + parseFloat(popupStyle.marginRight);
|
||||||
popupBox.left +
|
|
||||||
parseFloat(popupStyle.marginLeft) +
|
|
||||||
parseFloat(popupStyle.marginRight);
|
|
||||||
const popupHeight =
|
const popupHeight =
|
||||||
popupBox.bottom -
|
popupBox.bottom - popupBox.top + parseFloat(popupStyle.marginTop) + parseFloat(popupStyle.marginBottom);
|
||||||
popupBox.top +
|
|
||||||
parseFloat(popupStyle.marginTop) +
|
|
||||||
parseFloat(popupStyle.marginBottom);
|
|
||||||
|
|
||||||
let topPos = box.bottom;
|
let topPos = box.bottom;
|
||||||
if (
|
if (popupHeight > window.innerHeight - box.bottom - 15 && box.top > window.innerHeight - box.bottom) {
|
||||||
popupHeight > window.innerHeight - box.bottom - 15 &&
|
|
||||||
box.top > window.innerHeight - box.bottom
|
|
||||||
) {
|
|
||||||
topPos = box.top - popupHeight;
|
topPos = box.top - popupHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,6 @@ const exportCollection = (collection) => {
|
|||||||
deleteUidsInEnvs(collection.environments);
|
deleteUidsInEnvs(collection.environments);
|
||||||
transformItem(collection.items);
|
transformItem(collection.items);
|
||||||
|
|
||||||
|
|
||||||
const fileName = `${collection.name}.json`;
|
const fileName = `${collection.name}.json`;
|
||||||
const fileBlob = new Blob([JSON.stringify(collection, null, 2)], { type: 'application/json' });
|
const fileBlob = new Blob([JSON.stringify(collection, null, 2)], { type: 'application/json' });
|
||||||
|
|
||||||
|
@ -522,7 +522,7 @@ export const getEnvironmentVariables = (collection) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return variables;
|
return variables;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const getTotalRequestCountInCollection = (collection) => {
|
export const getTotalRequestCountInCollection = (collection) => {
|
||||||
let count = 0;
|
let count = 0;
|
||||||
@ -544,4 +544,4 @@ export const getAllVariables = (collection) => {
|
|||||||
...environmentVariables,
|
...environmentVariables,
|
||||||
...collection.collectionVariables
|
...collection.collectionVariables
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
let CodeMirror;
|
let CodeMirror;
|
||||||
const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true;
|
const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true;
|
||||||
|
|
||||||
@ -7,25 +6,25 @@ if (!SERVER_RENDERED) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const defineCodeMirrorBrunoVariablesMode = (variables, mode) => {
|
export const defineCodeMirrorBrunoVariablesMode = (variables, mode) => {
|
||||||
CodeMirror.defineMode("brunovariables", function(config, parserConfig) {
|
CodeMirror.defineMode('brunovariables', function (config, parserConfig) {
|
||||||
let variablesOverlay = {
|
let variablesOverlay = {
|
||||||
token: function (stream, state) {
|
token: function (stream, state) {
|
||||||
if (stream.match("{{", true)) {
|
if (stream.match('{{', true)) {
|
||||||
let ch;
|
let ch;
|
||||||
let word = "";
|
let word = '';
|
||||||
while ((ch = stream.next()) != null) {
|
while ((ch = stream.next()) != null) {
|
||||||
if (ch == "}" && stream.next() == "}") {
|
if (ch == '}' && stream.next() == '}') {
|
||||||
stream.eat("}");
|
stream.eat('}');
|
||||||
if (word in variables) {
|
if (word in variables) {
|
||||||
return "variable-valid";
|
return 'variable-valid';
|
||||||
} else {
|
} else {
|
||||||
return "variable-invalid";
|
return 'variable-invalid';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
word += ch;
|
word += ch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (stream.next() != null && !stream.match("{{", false)) {}
|
while (stream.next() != null && !stream.match('{{', false)) {}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -48,7 +48,7 @@ export const safeStringifyJSON = (obj, indent=false) => {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// Remove any characters that are not alphanumeric, spaces, hyphens, or underscores
|
// Remove any characters that are not alphanumeric, spaces, hyphens, or underscores
|
||||||
export const normalizeFileName = (name) => {
|
export const normalizeFileName = (name) => {
|
||||||
@ -60,4 +60,4 @@ export const normalizeFileName = (name) => {
|
|||||||
const formattedName = name.replace(validChars, '-');
|
const formattedName = name.replace(validChars, '-');
|
||||||
|
|
||||||
return formattedName;
|
return formattedName;
|
||||||
}
|
};
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
const { describe, it, expect } = require("@jest/globals");
|
const { describe, it, expect } = require('@jest/globals');
|
||||||
|
|
||||||
import { normalizeFileName } from './index';
|
import { normalizeFileName } from './index';
|
||||||
|
|
||||||
describe("common utils", () => {
|
describe('common utils', () => {
|
||||||
describe("normalizeFileName", () => {
|
describe('normalizeFileName', () => {
|
||||||
it("should remove special characters", () => {
|
it('should remove special characters', () => {
|
||||||
expect(normalizeFileName("hello world")).toBe("hello world");
|
expect(normalizeFileName('hello world')).toBe('hello world');
|
||||||
expect(normalizeFileName("hello-world")).toBe("hello-world");
|
expect(normalizeFileName('hello-world')).toBe('hello-world');
|
||||||
expect(normalizeFileName("hello_world")).toBe("hello_world");
|
expect(normalizeFileName('hello_world')).toBe('hello_world');
|
||||||
expect(normalizeFileName("hello_world-")).toBe("hello_world-");
|
expect(normalizeFileName('hello_world-')).toBe('hello_world-');
|
||||||
expect(normalizeFileName("hello_world-123")).toBe("hello_world-123");
|
expect(normalizeFileName('hello_world-123')).toBe('hello_world-123');
|
||||||
expect(normalizeFileName("hello_world-123!@#$%^&*()")).toBe("hello_world-123----------");
|
expect(normalizeFileName('hello_world-123!@#$%^&*()')).toBe('hello_world-123----------');
|
||||||
expect(normalizeFileName("hello_world?")).toBe("hello_world-");
|
expect(normalizeFileName('hello_world?')).toBe('hello_world-');
|
||||||
expect(normalizeFileName("foo/bar/")).toBe("foo-bar-");
|
expect(normalizeFileName('foo/bar/')).toBe('foo-bar-');
|
||||||
expect(normalizeFileName("foo\\bar\\")).toBe("foo-bar-");
|
expect(normalizeFileName('foo\\bar\\')).toBe('foo-bar-');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
@ -32,4 +32,4 @@ export const getDirectoryName = (pathname) => {
|
|||||||
pathname = slash(pathname);
|
pathname = slash(pathname);
|
||||||
|
|
||||||
return path.dirname(pathname);
|
return path.dirname(pathname);
|
||||||
}
|
};
|
||||||
|
@ -15,6 +15,6 @@ const slash = (path) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return path.replace(/\\/g, '/');
|
return path.replace(/\\/g, '/');
|
||||||
}
|
};
|
||||||
|
|
||||||
export default slash;
|
export default slash;
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
import each from 'lodash/each';
|
import each from 'lodash/each';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
|
|
||||||
@ -101,4 +100,4 @@ export const hydrateSeqInCollection = (collection) => {
|
|||||||
hydrateSeq(collection.items);
|
hydrateSeq(collection.items);
|
||||||
|
|
||||||
return collection;
|
return collection;
|
||||||
}
|
};
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user