diff --git a/package-lock.json b/package-lock.json index ba6e6c5e5..be14d77a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5600,6 +5600,14 @@ "node": ">=4" } }, + "node_modules/chai-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/chai-string/-/chai-string-1.5.0.tgz", + "integrity": "sha512-sydDC3S3pNAQMYwJrs6dQX0oBQ6KfIPuOZ78n7rocW0eJJlsHPh2t3kwW7xfwYA/1Bf6/arGtSUo16rxR2JFlw==", + "peerDependencies": { + "chai": "^4.1.2" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -16691,7 +16699,7 @@ "license": "MIT", "dependencies": { "@usebruno/js": "0.8.0", - "@usebruno/lang": "0.7.0", + "@usebruno/lang": "0.8.0", "axios": "^1.5.1", "chai": "^4.3.7", "chalk": "^3.0.0", @@ -16771,14 +16779,15 @@ }, "packages/bruno-electron": { "name": "bruno", - "version": "v0.22.0", + "version": "v0.22.1", "dependencies": { "@usebruno/js": "0.8.0", - "@usebruno/lang": "0.7.0", + "@usebruno/lang": "0.8.0", "@usebruno/schema": "0.5.0", "about-window": "^1.15.2", "axios": "^1.5.1", "chai": "^4.3.7", + "chai-string": "^1.5.0", "chokidar": "^3.5.3", "decomment": "^0.9.5", "dotenv": "^16.0.3", @@ -17021,7 +17030,7 @@ }, "packages/bruno-lang": { "name": "@usebruno/lang", - "version": "0.7.0", + "version": "0.8.0", "license": "MIT", "dependencies": { "arcsecond": "^5.0.0", @@ -20023,7 +20032,7 @@ "version": "file:packages/bruno-cli", "requires": { "@usebruno/js": "0.8.0", - "@usebruno/lang": "0.7.0", + "@usebruno/lang": "0.8.0", "axios": "^1.5.1", "chai": "^4.3.7", "chalk": "^3.0.0", @@ -21155,11 +21164,12 @@ "version": "file:packages/bruno-electron", "requires": { "@usebruno/js": "0.8.0", - "@usebruno/lang": "0.7.0", + "@usebruno/lang": "0.8.0", "@usebruno/schema": "0.5.0", "about-window": "^1.15.2", "axios": "^1.5.1", "chai": "^4.3.7", + "chai-string": "^1.5.0", "chokidar": "^3.5.3", "decomment": "^0.9.5", "dmg-license": "^1.0.11", @@ -21547,6 +21557,12 @@ "type-detect": "^4.0.5" } }, + "chai-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/chai-string/-/chai-string-1.5.0.tgz", + "integrity": "sha512-sydDC3S3pNAQMYwJrs6dQX0oBQ6KfIPuOZ78n7rocW0eJJlsHPh2t3kwW7xfwYA/1Bf6/arGtSUo16rxR2JFlw==", + "requires": {} + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", diff --git a/packages/bruno-app/src/components/ResponsePane/Placeholder/index.js b/packages/bruno-app/src/components/ResponsePane/Placeholder/index.js index 2e7cd8621..bca9e138a 100644 --- a/packages/bruno-app/src/components/ResponsePane/Placeholder/index.js +++ b/packages/bruno-app/src/components/ResponsePane/Placeholder/index.js @@ -1,8 +1,14 @@ import React from 'react'; import { IconSend } from '@tabler/icons'; import StyledWrapper from './StyledWrapper'; +import { isMacOS } from 'utils/common/platform'; const Placeholder = () => { + const isMac = isMacOS(); + const sendRequestShortcut = isMac ? 'Cmd + Enter' : 'Ctrl + Enter'; + const newRequestShortcut = isMac ? 'Cmd + B' : 'Ctrl + B'; + const editEnvironmentShortcut = isMac ? 'Cmd + E' : 'Ctrl + E'; + return (
@@ -15,9 +21,9 @@ const Placeholder = () => {
Edit Environments
-
Cmd + Enter
-
Cmd + B
-
Cmd + E
+
{sendRequestShortcut}
+
{newRequestShortcut}
+
{editEnvironmentShortcut}
diff --git a/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js b/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js index d77d09951..142c604c9 100644 --- a/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js +++ b/packages/bruno-app/src/components/ResponsePane/QueryResult/index.js @@ -45,6 +45,10 @@ const QueryResult = ({ item, collection, data, width, disableRunEventListener, h return safeStringifyJSON(data); } + if (mode.includes('image')) { + return item.requestSent.url; + } + // final fallback if (typeof data === 'string') { return data; @@ -103,6 +107,8 @@ const QueryResult = ({ item, collection, data, width, disableRunEventListener, h className="h-full bg-white" /> ); + } else if (mode.includes('image')) { + return image; } return ; diff --git a/packages/bruno-app/src/components/Sidebar/index.js b/packages/bruno-app/src/components/Sidebar/index.js index 4cc682a5b..2e233bf0c 100644 --- a/packages/bruno-app/src/components/Sidebar/index.js +++ b/packages/bruno-app/src/components/Sidebar/index.js @@ -105,7 +105,7 @@ const Sidebar = () => { Star -
v0.22.1
+
v0.23.0
diff --git a/packages/bruno-app/src/utils/common/codemirror.js b/packages/bruno-app/src/utils/common/codemirror.js index ce2f8be17..78016de6f 100644 --- a/packages/bruno-app/src/utils/common/codemirror.js +++ b/packages/bruno-app/src/utils/common/codemirror.js @@ -60,6 +60,8 @@ export const getCodeMirrorModeBasedOnContentType = (contentType) => { return 'application/xml'; } else if (contentType.includes('yaml')) { return 'application/yaml'; + } else if (contentType.includes('image')) { + return 'application/image'; } else { return 'application/text'; } diff --git a/packages/bruno-app/src/utils/network/index.js b/packages/bruno-app/src/utils/network/index.js index a498a722c..8952e1986 100644 --- a/packages/bruno-app/src/utils/network/index.js +++ b/packages/bruno-app/src/utils/network/index.js @@ -1,3 +1,5 @@ +import { safeStringifyJSON } from 'utils/common'; + export const sendNetworkRequest = async (item, collection, environment, collectionVariables) => { return new Promise((resolve, reject) => { if (['http-request', 'graphql-request'].includes(item.type)) { @@ -7,7 +9,7 @@ export const sendNetworkRequest = async (item, collection, environment, collecti state: 'success', data: response.data, headers: Object.entries(response.headers), - size: response.headers['content-length'] || 0, + size: getResponseSize(response), status: response.status, statusText: response.statusText, duration: response.duration @@ -29,6 +31,10 @@ const sendHttpRequest = async (item, collection, environment, collectionVariable }); }; +const getResponseSize = (response) => { + return response.headers['content-length'] || Buffer.byteLength(safeStringifyJSON(response.data)) || 0; +}; + export const fetchGqlSchema = async (endpoint, environment, request, collection) => { return new Promise((resolve, reject) => { const { ipcRenderer } = window; diff --git a/packages/bruno-cli/package.json b/packages/bruno-cli/package.json index cdabd32a3..f36459c78 100644 --- a/packages/bruno-cli/package.json +++ b/packages/bruno-cli/package.json @@ -25,7 +25,7 @@ ], "dependencies": { "@usebruno/js": "0.8.0", - "@usebruno/lang": "0.7.0", + "@usebruno/lang": "0.8.0", "axios": "^1.5.1", "chai": "^4.3.7", "chalk": "^3.0.0", diff --git a/packages/bruno-electron/package.json b/packages/bruno-electron/package.json index 340fccee8..95c1086fa 100644 --- a/packages/bruno-electron/package.json +++ b/packages/bruno-electron/package.json @@ -1,5 +1,5 @@ { - "version": "v0.22.1", + "version": "v0.23.0", "name": "bruno", "description": "Opensource API Client for Exploring and Testing APIs", "homepage": "https://www.usebruno.com", @@ -15,11 +15,12 @@ }, "dependencies": { "@usebruno/js": "0.8.0", - "@usebruno/lang": "0.7.0", + "@usebruno/lang": "0.8.0", "@usebruno/schema": "0.5.0", "about-window": "^1.15.2", "axios": "^1.5.1", "chai": "^4.3.7", + "chai-string": "^1.5.0", "chokidar": "^3.5.3", "decomment": "^0.9.5", "dotenv": "^16.0.3", diff --git a/packages/bruno-electron/resources/icons/mac/icon.icns b/packages/bruno-electron/resources/icons/mac/icon.icns index 85d1c1e63..5e01d5bdf 100644 Binary files a/packages/bruno-electron/resources/icons/mac/icon.icns and b/packages/bruno-electron/resources/icons/mac/icon.icns differ diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index f95340229..da7c14e64 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -75,7 +75,7 @@ const getSize = (data) => { } if (typeof data === 'object') { - return Buffer.byteLength(JSON.stringify(data), 'utf8'); + return Buffer.byteLength(safeStringifyJSON(data), 'utf8'); } return 0; @@ -493,7 +493,8 @@ const registerNetworkIpc = (mainWindow) => { ipcMain.handle('fetch-gql-schema', async (event, endpoint, environment, request, collection) => { try { const envVars = getEnvVars(environment); - const preparedRequest = prepareGqlIntrospectionRequest(endpoint, envVars, request); + const collectionRoot = get(collection, 'root', {}); + const preparedRequest = prepareGqlIntrospectionRequest(endpoint, envVars, request, collectionRoot); const preferences = getPreferences(); const sslVerification = get(preferences, 'request.sslVerification', true); @@ -711,14 +712,14 @@ const registerNetworkIpc = (mainWindow) => { if (socksEnabled) { const socksProxyAgent = new SocksProxyAgent(proxyUri); - + request.httpsAgent = socksProxyAgent; request.httpAgent = socksProxyAgent; } else { request.httpsAgent = new HttpsProxyAgent(proxyUri, { rejectUnauthorized: sslVerification }); - + request.httpAgent = new HttpProxyAgent(proxyUri); } } else if (!sslVerification) { diff --git a/packages/bruno-electron/src/ipc/network/prepare-gql-introspection-request.js b/packages/bruno-electron/src/ipc/network/prepare-gql-introspection-request.js index 4a1e41c88..a448d9106 100644 --- a/packages/bruno-electron/src/ipc/network/prepare-gql-introspection-request.js +++ b/packages/bruno-electron/src/ipc/network/prepare-gql-introspection-request.js @@ -1,15 +1,14 @@ const Handlebars = require('handlebars'); const { getIntrospectionQuery } = require('graphql'); -const { get } = require('lodash'); +const { setAuthHeaders } = require('./prepare-request'); -const prepareGqlIntrospectionRequest = (endpoint, envVars, request) => { +const prepareGqlIntrospectionRequest = (endpoint, envVars, request, collectionRoot) => { if (endpoint && endpoint.length) { endpoint = Handlebars.compile(endpoint, { noEscape: true })(envVars); } - const introspectionQuery = getIntrospectionQuery(); const queryParams = { - query: introspectionQuery + query: getIntrospectionQuery() }; let axiosRequest = { @@ -23,20 +22,7 @@ const prepareGqlIntrospectionRequest = (endpoint, envVars, request) => { data: JSON.stringify(queryParams) }; - if (request.auth) { - if (request.auth.mode === 'basic') { - axiosRequest.auth = { - username: get(request, 'auth.basic.username'), - password: get(request, 'auth.basic.password') - }; - } - - if (request.auth.mode === 'bearer') { - axiosRequest.headers.authorization = `Bearer ${get(request, 'auth.bearer.token')}`; - } - } - - return axiosRequest; + return setAuthHeaders(axiosRequest, request, collectionRoot); }; const mapHeaders = (headers) => { diff --git a/packages/bruno-electron/src/ipc/network/prepare-request.js b/packages/bruno-electron/src/ipc/network/prepare-request.js index bff574bb3..44f408ca9 100644 --- a/packages/bruno-electron/src/ipc/network/prepare-request.js +++ b/packages/bruno-electron/src/ipc/network/prepare-request.js @@ -1,6 +1,41 @@ const { get, each, filter } = require('lodash'); const decomment = require('decomment'); +// Authentication +// A request can override the collection auth with another auth +// But it cannot override the collection auth with no auth +// We will provide support for disabling the auth via scripting in the future +const setAuthHeaders = (axiosRequest, request, collectionRoot) => { + const collectionAuth = get(collectionRoot, 'request.auth'); + if (collectionAuth) { + if (collectionAuth.mode === 'basic') { + axiosRequest.auth = { + username: get(collectionAuth, 'basic.username'), + password: get(collectionAuth, 'basic.password') + }; + } + + if (collectionAuth.mode === 'bearer') { + axiosRequest.headers['authorization'] = `Bearer ${get(collectionAuth, 'bearer.token')}`; + } + } + + if (request.auth) { + if (request.auth.mode === 'basic') { + axiosRequest.auth = { + username: get(request, 'auth.basic.username'), + password: get(request, 'auth.basic.password') + }; + } + + if (request.auth.mode === 'bearer') { + axiosRequest.headers['authorization'] = `Bearer ${get(request, 'auth.bearer.token')}`; + } + } + + return axiosRequest; +}; + const prepareRequest = (request, collectionRoot) => { const headers = {}; let contentTypeDefined = false; @@ -30,36 +65,7 @@ const prepareRequest = (request, collectionRoot) => { headers: headers }; - // Authentication - // A request can override the collection auth with another auth - // But it cannot override the collection auth with no auth - // We will provide support for disabling the auth via scripting in the future - const collectionAuth = get(collectionRoot, 'request.auth'); - if (collectionAuth) { - if (collectionAuth.mode === 'basic') { - axiosRequest.auth = { - username: get(collectionAuth, 'basic.username'), - password: get(collectionAuth, 'basic.password') - }; - } - - if (collectionAuth.mode === 'bearer') { - axiosRequest.headers['authorization'] = `Bearer ${get(collectionAuth, 'bearer.token')}`; - } - } - - if (request.auth) { - if (request.auth.mode === 'basic') { - axiosRequest.auth = { - username: get(request, 'auth.basic.username'), - password: get(request, 'auth.basic.password') - }; - } - - if (request.auth.mode === 'bearer') { - axiosRequest.headers['authorization'] = `Bearer ${get(request, 'auth.bearer.token')}`; - } - } + axiosRequest = setAuthHeaders(axiosRequest, request, collectionRoot); if (request.body.mode === 'json') { if (!contentTypeDefined) { @@ -132,3 +138,4 @@ const prepareRequest = (request, collectionRoot) => { }; module.exports = prepareRequest; +module.exports.setAuthHeaders = setAuthHeaders; diff --git a/packages/bruno-js/src/runtime/assert-runtime.js b/packages/bruno-js/src/runtime/assert-runtime.js index a9588263a..06f6adab4 100644 --- a/packages/bruno-js/src/runtime/assert-runtime.js +++ b/packages/bruno-js/src/runtime/assert-runtime.js @@ -6,6 +6,7 @@ const BrunoRequest = require('../bruno-request'); const { evaluateJsTemplateLiteral, evaluateJsExpression, createResponseParser } = require('../utils'); const { expect } = chai; +chai.use(require('chai-string')); chai.use(function (chai, utils) { // Custom assertion for checking if a variable is JSON chai.Assertion.addProperty('json', function () { diff --git a/packages/bruno-lang/package.json b/packages/bruno-lang/package.json index 4081479d0..2e4b3df03 100644 --- a/packages/bruno-lang/package.json +++ b/packages/bruno-lang/package.json @@ -1,6 +1,6 @@ { "name": "@usebruno/lang", - "version": "0.7.0", + "version": "0.8.0", "license": "MIT", "main": "src/index.js", "files": [