Merge branch 'usebruno:main' into feature/add-raw-file-request-body-option

This commit is contained in:
zachary-berdell-elliott 2024-11-18 21:25:18 -07:00 committed by GitHub
commit fda9b7bd76
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 1994 additions and 1423 deletions

3268
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,9 @@ const StyledWrapper = styled.div`
.CodeMirror-foldmarker {
text-shadow: none;
color: ${(props) => props.theme.textLink};
background: none;
padding: 0;
margin: 0;
}
.CodeMirror-overlayscroll-horizontal div,
@ -75,6 +78,10 @@ const StyledWrapper = styled.div`
.cm-variable-invalid {
color: red;
}
.CodeMirror-search-hint {
display: inline;
}
`;
export default StyledWrapper;

View File

@ -339,7 +339,7 @@ export default class CodeEditor extends React.Component {
}
return (
<StyledWrapper
className="h-full w-full flex flex-col relative"
className="h-full w-full flex flex-col relative graphiql-container"
aria-label="Code Editor"
font={this.props.font}
fontSize={this.props.fontSize}

View File

@ -17,6 +17,15 @@ import Presets from './Presets';
import Info from './Info';
import StyledWrapper from './StyledWrapper';
import Vars from './Vars/index';
import DotIcon from 'components/Icons/Dot';
const ContentIndicator = () => {
return (
<sup className="ml-[.125rem] opacity-80 font-medium">
<DotIcon width="10"></DotIcon>
</sup>
);
};
const CollectionSettings = ({ collection }) => {
const dispatch = useDispatch();
@ -30,10 +39,23 @@ const CollectionSettings = ({ collection }) => {
);
};
const proxyConfig = get(collection, 'brunoConfig.proxy', {});
const root = collection?.root;
const hasScripts = root?.request?.script?.res || root?.request?.script?.req;
const hasTests = root?.request?.tests;
const hasDocs = root?.docs;
const headers = get(collection, 'root.request.headers', []);
const activeHeadersCount = headers.filter((header) => header.enabled).length;
const requestVars = get(collection, 'root.request.vars.req', []);
const responseVars = get(collection, 'root.request.vars.res', []);
const activeVarsCount = requestVars.filter((v) => v.enabled).length + responseVars.filter((v) => v.enabled).length;
const auth = get(collection, 'root.request.auth', {}).mode;
const proxyConfig = get(collection, 'brunoConfig.proxy', {});
const clientCertConfig = get(collection, 'brunoConfig.clientCertificates.certs', []);
const onProxySettingsUpdate = (config) => {
const brunoConfig = cloneDeep(collection.brunoConfig);
brunoConfig.proxy = config;
@ -126,30 +148,38 @@ const CollectionSettings = ({ collection }) => {
<div className="flex flex-wrap items-center tabs" role="tablist">
<div className={getTabClassname('headers')} role="tab" onClick={() => setTab('headers')}>
Headers
{activeHeadersCount > 0 && <sup className="ml-1 font-medium">{activeHeadersCount}</sup>}
</div>
<div className={getTabClassname('vars')} role="tab" onClick={() => setTab('vars')}>
Vars
{activeVarsCount > 0 && <sup className="ml-1 font-medium">{activeVarsCount}</sup>}
</div>
<div className={getTabClassname('auth')} role="tab" onClick={() => setTab('auth')}>
Auth
{auth !== 'none' && <ContentIndicator />}
</div>
<div className={getTabClassname('script')} role="tab" onClick={() => setTab('script')}>
Script
{hasScripts && <ContentIndicator />}
</div>
<div className={getTabClassname('tests')} role="tab" onClick={() => setTab('tests')}>
Tests
{hasTests && <ContentIndicator />}
</div>
<div className={getTabClassname('presets')} role="tab" onClick={() => setTab('presets')}>
Presets
</div>
<div className={getTabClassname('proxy')} role="tab" onClick={() => setTab('proxy')}>
Proxy
{Object.keys(proxyConfig).length > 0 && <ContentIndicator />}
</div>
<div className={getTabClassname('clientCert')} role="tab" onClick={() => setTab('clientCert')}>
Client Certificates
{clientCertConfig.length > 0 && <ContentIndicator />}
</div>
<div className={getTabClassname('docs')} role="tab" onClick={() => setTab('docs')}>
Docs
{hasDocs && <ContentIndicator />}
</div>
<div className={getTabClassname('info')} role="tab" onClick={() => setTab('info')}>
Info

View File

@ -7,6 +7,15 @@ import Script from './Script';
import Tests from './Tests';
import StyledWrapper from './StyledWrapper';
import Vars from './Vars';
import DotIcon from 'components/Icons/Dot';
const ContentIndicator = () => {
return (
<sup className="ml-[.125rem] opacity-80 font-medium">
<DotIcon width="10"></DotIcon>
</sup>
);
};
const FolderSettings = ({ collection, folder }) => {
const dispatch = useDispatch();
@ -16,6 +25,17 @@ const FolderSettings = ({ collection, folder }) => {
tab = folderLevelSettingsSelectedTab[folder?.uid];
}
const folderRoot = collection?.items.find((item) => item.uid === folder?.uid)?.root;
const hasScripts = folderRoot?.request?.script?.res || folderRoot?.request?.script?.req;
const hasTests = folderRoot?.request?.tests;
const headers = folderRoot?.request?.headers || [];
const activeHeadersCount = headers.filter((header) => header.enabled).length;
const requestVars = folderRoot?.request?.vars?.req || [];
const responseVars = folderRoot?.request?.vars?.res || [];
const activeVarsCount = requestVars.filter((v) => v.enabled).length + responseVars.filter((v) => v.enabled).length;
const setTab = (tab) => {
dispatch(
updatedFolderSettingsSelectedTab({
@ -55,15 +75,19 @@ const FolderSettings = ({ collection, folder }) => {
<div className="flex flex-wrap items-center tabs" role="tablist">
<div className={getTabClassname('headers')} role="tab" onClick={() => setTab('headers')}>
Headers
{activeHeadersCount > 0 && <sup className="ml-1 font-medium">{activeHeadersCount}</sup>}
</div>
<div className={getTabClassname('script')} role="tab" onClick={() => setTab('script')}>
Script
{hasScripts && <ContentIndicator />}
</div>
<div className={getTabClassname('test')} role="tab" onClick={() => setTab('test')}>
Test
{hasTests && <ContentIndicator />}
</div>
<div className={getTabClassname('vars')} role="tab" onClick={() => setTab('vars')}>
Vars
{activeVarsCount > 0 && <sup className="ml-1 font-medium">{activeVarsCount}</sup>}
</div>
</div>
<section className={`flex mt-4 h-full`}>{getTabPanel(tab)}</section>

View File

@ -17,9 +17,11 @@ import { find, get } from 'lodash';
import Documentation from 'components/Documentation/index';
const ContentIndicator = () => {
return <sup className="ml-[.125rem] opacity-80 font-medium">
return (
<sup className="ml-[.125rem] opacity-80 font-medium">
<DotIcon width="10"></DotIcon>
</sup>
);
};
const HttpRequestPane = ({ item, collection, leftPaneWidth }) => {
@ -100,6 +102,7 @@ const HttpRequestPane = ({ item, collection, leftPaneWidth }) => {
const docs = getPropertyFromDraftOrRequest('request.docs');
const requestVars = getPropertyFromDraftOrRequest('request.vars.req');
const responseVars = getPropertyFromDraftOrRequest('request.vars.res');
const auth = getPropertyFromDraftOrRequest('request.auth');
const activeParamsLength = params.filter((param) => param.enabled).length;
const activeHeadersLength = headers.filter((header) => header.enabled).length;
@ -125,6 +128,7 @@ const HttpRequestPane = ({ item, collection, leftPaneWidth }) => {
</div>
<div className={getTabClassname('auth')} role="tab" onClick={() => selectTab('auth')}>
Auth
{auth.mode !== 'none' && <ContentIndicator />}
</div>
<div className={getTabClassname('vars')} role="tab" onClick={() => selectTab('vars')}>
Vars

View File

@ -50,6 +50,10 @@ const StyledWrapper = styled.div`
.cm-variable-invalid {
color: red;
}
.CodeMirror-search-hint {
display: inline;
}
`;
export default StyledWrapper;

View File

@ -209,7 +209,7 @@ export default class QueryEditor extends React.Component {
return (
<>
<StyledWrapper
className="h-full w-full flex flex-col relative"
className="h-full w-full flex flex-col relative graphiql-container"
aria-label="Query Editor"
font={this.props.font}
fontSize={this.props.fontSize}

View File

@ -184,7 +184,7 @@ const Sidebar = () => {
Star
</GitHubButton> */}
</div>
<div className="flex flex-grow items-center justify-end text-xs mr-2">v1.34.0</div>
<div className="flex flex-grow items-center justify-end text-xs mr-2">v1.34.2</div>
</div>
</div>
</div>

View File

@ -60,7 +60,7 @@ const trackStart = () => {
event: 'start',
properties: {
os: platformLib.os.family,
version: '1.34.0'
version: '1.34.2'
}
});
};

View File

@ -201,7 +201,7 @@ export const sendCollectionOauth2Request = (collectionUid, itemUid) => (dispatch
const environment = findEnvironmentInCollection(collectionCopy, collection.activeEnvironmentUid);
_sendCollectionOauth2Request(collection, environment, collectionCopy.runtimeVariables)
_sendCollectionOauth2Request(collectionCopy, environment, collectionCopy.runtimeVariables)
.then((response) => {
if (response?.data?.error) {
toast.error(response?.data?.error);

View File

@ -23,23 +23,26 @@
--color-method-options: rgb(52 52 52);
--color-method-head: rgb(52 52 52);
}
*,.graphiql-container,.CodeMirror-info,.CodeMirror-lint-tooltip,reach-portal {
:root,.graphiql-container,.CodeMirror-info,.CodeMirror-lint-tooltip,reach-portal {
/* Required CSS variables after upgrading GraphiQL from v1.5.9 to v2.4.7 */
--color-primary: 0, 0%, 0% !important;
--color-secondary: 0, 0%, 0% !important;
--color-tertiary: 0, 0%, 0% !important;
--color-info: 0, 0%, 0% !important;
--color-success: 0, 0%, 0% !important;
--color-warning: 0, 0%, 0% !important;
--color-error: 0, 0%, 0% !important;
--color-neutral: 0, 0%, 0% !important;
--color-base: 0, 0%, 100% !important;
--alpha-secondary: .76;
--alpha-tertiary: .5;
--alpha-background-heavy: .15;
--alpha-background-medium: .1;
--alpha-background-light: .07;
/* Colors */
--color-primary: 320, 95%, 43% !important;
--color-secondary: 242, 51%, 61% !important;
--color-tertiary: 188, 100%, 36% !important;
--color-info: 208, 100%, 46% !important;
--color-success: 158, 60%, 42% !important;
--color-warning: 36, 100%, 41% !important;
--color-error: 13, 93%, 58% !important;
--color-neutral: 219, 28%, 32% !important;
--color-base: 219, 28%, 100% !important;
/* Color alpha values */
--alpha-secondary: 0.76 !important;
--alpha-tertiary: 0.5 !important;
--alpha-background-heavy: 0.15 !important;
--alpha-background-medium: 0.1 !important;
--alpha-background-light: 0.07 !important;
--font-size-hint: .75rem;
--font-size-inline-code: .8125rem;
--font-size-body: .9375rem;

View File

@ -246,7 +246,7 @@ const runSingleRequest = async function (
data: null,
responseTime: 0
},
error: err.message,
error: err?.message || err?.errors?.map(e => e?.message)?.at(0) || err?.code || 'Request Failed!',
assertionResults: [],
testResults: [],
nextRequestName: nextRequestName

View File

@ -1,5 +1,5 @@
{
"version": "v1.34.0",
"version": "v1.34.2",
"name": "bruno",
"description": "Opensource API Client for Exploring and Testing APIs",
"homepage": "https://www.usebruno.com",
@ -63,6 +63,6 @@
},
"devDependencies": {
"electron": "31.2.1",
"electron-builder": "23.0.2"
"electron-builder": "25.1.8"
}
}

View File

@ -77,14 +77,20 @@ const registerRendererEventHandlers = (mainWindow, watcher, lastOpenedCollection
try {
const dirPath = path.join(collectionLocation, collectionFolderName);
if (fs.existsSync(dirPath)) {
throw new Error(`collection: ${dirPath} already exists`);
const files = fs.readdirSync(dirPath);
if (files.length > 0) {
throw new Error(`collection: ${dirPath} already exists and is not empty`);
}
}
if (!isValidPathname(dirPath)) {
throw new Error(`collection: invalid pathname - ${dir}`);
}
if (!fs.existsSync(dirPath)) {
await createDirectory(dirPath);
}
const uid = generateUidBasedOnHash(dirPath);
const brunoConfig = {

View File

@ -741,7 +741,7 @@ const registerNetworkIpc = (mainWindow) => {
const collectionRoot = get(collection, 'root', {});
const _request = collectionRoot?.request;
const request = prepareCollectionRequest(_request, collectionRoot, collectionPath);
const request = prepareCollectionRequest(_request, collection, collectionPath);
request.__bruno__executionMode = 'standalone';
const envVars = getEnvVars(environment);
const processEnvVars = getProcessEnvVars(collectionUid);

View File

@ -1,7 +1,8 @@
const { get, each } = require('lodash');
const { setAuthHeaders } = require('./prepare-request');
const prepareCollectionRequest = (request, collectionRoot) => {
const prepareCollectionRequest = (request, collection) => {
const collectionRoot = get(collection, 'root', {});
const headers = {};
let contentTypeDefined = false;
let url = request.url;
@ -35,6 +36,8 @@ const prepareCollectionRequest = (request, collectionRoot) => {
axiosRequest = setAuthHeaders(axiosRequest, request, collectionRoot);
axiosRequest.globalEnvironmentVariables = collection?.globalEnvironmentVariables;
if (request.script) {
axiosRequest.script = request.script;
}

View File

@ -24,7 +24,7 @@ get(data, '..items[?]', { id: 2, amount: 20 })
```
Array mapping [?] with corresponding mapper function
```js
get(data, '..items[?].amount', i => i.amount + 10)
get(data, '..items..amount[?]', amt => amt + 10)
```
### Publish to Npm Registry

View File

@ -5,7 +5,7 @@ meta {
}
get {
url: https://www.usebruno.com/images/landing-2.png
url: https://gloutnikov.com/post/2024/bruno.png
body: none
auth: none
}