mirror of
https://github.com/usebruno/bruno.git
synced 2024-11-24 08:53:30 +01:00
Merge branch 'usebruno:main' into feature/add-raw-file-request-body-option
This commit is contained in:
commit
fda9b7bd76
3268
package-lock.json
generated
3268
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||
|
@ -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}
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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">
|
||||
<DotIcon width="10"></DotIcon>
|
||||
</sup>
|
||||
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
|
||||
|
@ -50,6 +50,10 @@ const StyledWrapper = styled.div`
|
||||
.cm-variable-invalid {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.CodeMirror-search-hint {
|
||||
display: inline;
|
||||
}
|
||||
`;
|
||||
|
||||
export default StyledWrapper;
|
||||
|
@ -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}
|
||||
|
@ -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>
|
||||
|
@ -60,7 +60,7 @@ const trackStart = () => {
|
||||
event: 'start',
|
||||
properties: {
|
||||
os: platformLib.os.family,
|
||||
version: '1.34.0'
|
||||
version: '1.34.2'
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
@ -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}`);
|
||||
}
|
||||
|
||||
await createDirectory(dirPath);
|
||||
if (!fs.existsSync(dirPath)) {
|
||||
await createDirectory(dirPath);
|
||||
}
|
||||
|
||||
const uid = generateUidBasedOnHash(dirPath);
|
||||
const brunoConfig = {
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
@ -34,6 +35,8 @@ const prepareCollectionRequest = (request, collectionRoot) => {
|
||||
};
|
||||
|
||||
axiosRequest = setAuthHeaders(axiosRequest, request, collectionRoot);
|
||||
|
||||
axiosRequest.globalEnvironmentVariables = collection?.globalEnvironmentVariables;
|
||||
|
||||
if (request.script) {
|
||||
axiosRequest.script = request.script;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user