From 72b8c547b28f3e6489a2f26dfb964eb9acba285e Mon Sep 17 00:00:00 2001 From: Tim Nikischin <49103409+nikischin@users.noreply.github.com> Date: Mon, 13 Jan 2025 14:06:08 +0100 Subject: [PATCH 01/22] Order Variables alphabetically (#2982) Order variables in Variables Tab alphabetically by name --- packages/bruno-app/src/components/VariablesEditor/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bruno-app/src/components/VariablesEditor/index.js b/packages/bruno-app/src/components/VariablesEditor/index.js index 08f415113a..a06b6a1fff 100644 --- a/packages/bruno-app/src/components/VariablesEditor/index.js +++ b/packages/bruno-app/src/components/VariablesEditor/index.js @@ -15,7 +15,7 @@ const KeyValueExplorer = ({ data = [], theme }) => { setShowSecret(!showSecret)} /> - {data.map((envVar) => ( + {data.toSorted((a, b) => a.name.localeCompare(b.name)).map((envVar) => ( - + <> + - + ); }; diff --git a/packages/bruno-app/src/components/RequestPane/Assertions/StyledWrapper.js b/packages/bruno-app/src/components/RequestPane/Assertions/StyledWrapper.js index 14e21e1c60..efb860893c 100644 --- a/packages/bruno-app/src/components/RequestPane/Assertions/StyledWrapper.js +++ b/packages/bruno-app/src/components/RequestPane/Assertions/StyledWrapper.js @@ -4,6 +4,7 @@ const Wrapper = styled.div` table { width: 100%; border-collapse: collapse; + font-weight: 600; table-layout: fixed; thead, @@ -15,24 +16,15 @@ const Wrapper = styled.div` color: ${(props) => props.theme.table.thead.color}; font-size: 0.8125rem; user-select: none; - font-weight: 600; } td { padding: 6px 10px; - - &:nth-child(2) { - width: 130px; - } - - &:nth-child(4) { - width: 70px; } - select { + select { background-color: transparent; } } - } .btn-add-assertion { font-size: 0.8125rem; @@ -42,7 +34,8 @@ const Wrapper = styled.div` width: 100%; border: solid 1px transparent; outline: none !important; - background-color: inherit; + color: ${(props) => props.theme.table.input.color}; + background: transparent; &:focus { outline: none !important; diff --git a/packages/bruno-app/src/components/RequestPane/Assertions/index.js b/packages/bruno-app/src/components/RequestPane/Assertions/index.js index 1805a632e1..7d173f3c5a 100644 --- a/packages/bruno-app/src/components/RequestPane/Assertions/index.js +++ b/packages/bruno-app/src/components/RequestPane/Assertions/index.js @@ -6,6 +6,9 @@ import { addAssertion, updateAssertion, deleteAssertion } from 'providers/ReduxS import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions'; import AssertionRow from './AssertionRow'; import StyledWrapper from './StyledWrapper'; +import Table from 'components/Table/index'; +import ReorderTable from 'components/ReorderTable/index'; +import { moveAssertion } from 'providers/ReduxStore/slices/collections/index'; const Assertions = ({ item, collection }) => { const dispatch = useDispatch(); @@ -57,21 +60,43 @@ const Assertions = ({ item, collection }) => { ); }; + const handleAssertionDrag = ({ updateReorderedItem }) => { + dispatch( + moveAssertion({ + collectionUid: collection.uid, + itemUid: item.uid, + updateReorderedItem + }) + ); + }; + return ( -
{envVar.name} From 5500070b4956d27e4603ba6a9b4ab704b0ff81fb Mon Sep 17 00:00:00 2001 From: tlaloc911 <29415755+tlaloc911@users.noreply.github.com> Date: Mon, 13 Jan 2025 07:18:26 -0600 Subject: [PATCH 02/22] ntlm auth (#3329) Co-authored-by: Anoop M D --- .../CollectionSettings/Auth/AuthMode/index.js | 9 ++ .../Auth/NTLMAuth/StyledWrapper.js | 17 +++ .../CollectionSettings/Auth/NTLMAuth/index.js | 110 ++++++++++++++++++ .../CollectionSettings/Auth/index.js | 5 + .../RequestPane/Auth/AuthMode/index.js | 9 ++ .../Auth/NTLMAuth/StyledWrapper.js | 17 +++ .../RequestPane/Auth/NTLMAuth/index.js | 110 ++++++++++++++++++ .../src/components/RequestPane/Auth/index.js | 5 + .../ReduxStore/slices/collections/index.js | 7 ++ .../bruno-app/src/utils/collections/index.js | 11 ++ packages/bruno-cli/package.json | 2 + .../bruno-cli/src/runner/interpolate-vars.js | 7 ++ .../bruno-cli/src/runner/prepare-request.js | 8 ++ .../src/runner/run-single-request.js | 11 +- packages/bruno-electron/package.json | 7 +- .../bruno-electron/src/ipc/network/index.js | 11 +- .../src/ipc/network/interpolate-vars.js | 8 ++ .../src/ipc/network/prepare-request.js | 15 +++ packages/bruno-lang/v2/src/bruToJson.js | 23 +++- .../bruno-lang/v2/src/collectionBruToJson.js | 23 +++- packages/bruno-lang/v2/src/jsonToBru.js | 12 ++ .../bruno-lang/v2/src/jsonToCollectionBru.js | 11 ++ .../bruno-schema/src/collections/index.js | 14 ++- 23 files changed, 444 insertions(+), 8 deletions(-) create mode 100644 packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/StyledWrapper.js create mode 100644 packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/index.js create mode 100644 packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/StyledWrapper.js create mode 100644 packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/index.js diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/AuthMode/index.js b/packages/bruno-app/src/components/CollectionSettings/Auth/AuthMode/index.js index 7dabb4c71a..2c541cc289 100644 --- a/packages/bruno-app/src/components/CollectionSettings/Auth/AuthMode/index.js +++ b/packages/bruno-app/src/components/CollectionSettings/Auth/AuthMode/index.js @@ -79,6 +79,15 @@ const AuthMode = ({ collection }) => { > Digest Auth +
{ + dropdownTippyRef.current.hide(); + onModeChange('ntlm'); + }} + > + NTLM Auth +
{ diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/StyledWrapper.js b/packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/StyledWrapper.js new file mode 100644 index 0000000000..316d3a7c5f --- /dev/null +++ b/packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/StyledWrapper.js @@ -0,0 +1,17 @@ +import styled from 'styled-components'; + +const Wrapper = styled.div` + label { + font-size: 0.8125rem; + } + + .single-line-editor-wrapper { + max-width: 400px; + padding: 0.15rem 0.4rem; + border-radius: 3px; + border: solid 1px ${(props) => props.theme.input.border}; + background-color: ${(props) => props.theme.input.bg}; + } +`; + +export default Wrapper; diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/index.js b/packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/index.js new file mode 100644 index 0000000000..341c805dcf --- /dev/null +++ b/packages/bruno-app/src/components/CollectionSettings/Auth/NTLMAuth/index.js @@ -0,0 +1,110 @@ +import React from 'react'; +import get from 'lodash/get'; +import { useTheme } from 'providers/Theme'; +import { useDispatch } from 'react-redux'; +import SingleLineEditor from 'components/SingleLineEditor'; +import { updateCollectionAuth } from 'providers/ReduxStore/slices/collections'; +import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions'; +import StyledWrapper from './StyledWrapper'; + + + + + +const NTLMAuth = ({ collection }) => { + + + const dispatch = useDispatch(); + const { storedTheme } = useTheme(); + + const ntlmAuth = get(collection, 'root.request.auth.ntlm', {}); + + const handleSave = () => dispatch(saveCollectionRoot(collection.uid)); + + + const handleUsernameChange = (username) => { + dispatch( + updateCollectionAuth({ + mode: 'ntlm', + collectionUid: collection.uid, + content: { + username: username, + password: ntlmAuth.password, + domain: ntlmAuth.domain + + } + }) + ); + }; + + const handlePasswordChange = (password) => { + dispatch( + updateCollectionAuth({ + mode: 'ntlm', + collectionUid: collection.uid, + content: { + username: ntlmAuth.username, + password: password, + domain: ntlmAuth.domain + } + }) + ); + }; + + const handleDomainChange = (domain) => { + dispatch( + updateCollectionAuth({ + mode: 'ntlm', + collectionUid: collection.uid, + content: { + username: ntlmAuth.username, + password: ntlmAuth.password, + domain: domain + } + }) + ); + }; + + + + + return ( + + +
+ handleUsernameChange(val)} + collection={collection} + /> +
+ + +
+ handlePasswordChange(val)} + collection={collection} + isSecret={true} + /> +
+ + +
+ handleDomainChange(val)} + collection={collection} + /> +
+
+ ); +}; + +export default NTLMAuth; diff --git a/packages/bruno-app/src/components/CollectionSettings/Auth/index.js b/packages/bruno-app/src/components/CollectionSettings/Auth/index.js index 05efc17b23..c19ae98738 100644 --- a/packages/bruno-app/src/components/CollectionSettings/Auth/index.js +++ b/packages/bruno-app/src/components/CollectionSettings/Auth/index.js @@ -11,6 +11,8 @@ import ApiKeyAuth from './ApiKeyAuth/'; import { saveCollectionRoot } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; import OAuth2 from './OAuth2'; +import NTLMAuth from './NTLMAuth'; + const Auth = ({ collection }) => { const authMode = get(collection, 'root.request.auth.mode'); @@ -32,6 +34,9 @@ const Auth = ({ collection }) => { case 'digest': { return ; } + case 'ntlm': { + return ; + } case 'oauth2': { return ; } diff --git a/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/index.js b/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/index.js index dfbaba7fa0..1e3bedc2f3 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/AuthMode/index.js @@ -70,6 +70,15 @@ const AuthMode = ({ item, collection }) => { > Digest Auth
+
{ + dropdownTippyRef?.current?.hide(); + onModeChange('ntlm'); + }} + > + NTLM Auth +
{ diff --git a/packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/StyledWrapper.js b/packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/StyledWrapper.js new file mode 100644 index 0000000000..316d3a7c5f --- /dev/null +++ b/packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/StyledWrapper.js @@ -0,0 +1,17 @@ +import styled from 'styled-components'; + +const Wrapper = styled.div` + label { + font-size: 0.8125rem; + } + + .single-line-editor-wrapper { + max-width: 400px; + padding: 0.15rem 0.4rem; + border-radius: 3px; + border: solid 1px ${(props) => props.theme.input.border}; + background-color: ${(props) => props.theme.input.bg}; + } +`; + +export default Wrapper; diff --git a/packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/index.js b/packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/index.js new file mode 100644 index 0000000000..65e7560418 --- /dev/null +++ b/packages/bruno-app/src/components/RequestPane/Auth/NTLMAuth/index.js @@ -0,0 +1,110 @@ +import React from 'react'; +import get from 'lodash/get'; +import { useTheme } from 'providers/Theme'; +import { useDispatch } from 'react-redux'; +import SingleLineEditor from 'components/SingleLineEditor'; +import { updateAuth } from 'providers/ReduxStore/slices/collections'; +import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions'; +import StyledWrapper from './StyledWrapper'; + +const NTLMAuth = ({ item, collection }) => { + const dispatch = useDispatch(); + const { storedTheme } = useTheme(); + + const ntlmAuth = item.draft ? get(item, 'draft.request.auth.ntlm', {}) : get(item, 'request.auth.ntlm', {}); + + const handleRun = () => dispatch(sendRequest(item, collection.uid)); + const handleSave = () => dispatch(saveRequest(item.uid, collection.uid)); + + const handleUsernameChange = (username) => { + dispatch( + updateAuth({ + mode: 'ntlm', + collectionUid: collection.uid, + itemUid: item.uid, + content: { + username: username, + password: ntlmAuth.password, + domain: ntlmAuth.domain + + } + }) + ); + }; + + const handlePasswordChange = (password) => { + dispatch( + updateAuth({ + mode: 'ntlm', + collectionUid: collection.uid, + itemUid: item.uid, + content: { + username: ntlmAuth.username, + password: password, + domain: ntlmAuth.domain + } + }) + ); + }; + + const handleDomainChange = (domain) => { + dispatch( + updateAuth({ + mode: 'ntlm', + collectionUid: collection.uid, + itemUid: item.uid, + content: { + username: ntlmAuth.username, + password: ntlmAuth.password, + domain: domain + } + }) + ); + }; + + return ( + + +
+ handleUsernameChange(val)} + onRun={handleRun} + collection={collection} + item={item} + /> +
+ + +
+ handlePasswordChange(val)} + onRun={handleRun} + collection={collection} + item={item} + isSecret={true} + /> +
+ + +
+ handleDomainChange(val)} + onRun={handleRun} + collection={collection} + item={item} + /> +
+
+ ); +}; + +export default NTLMAuth; diff --git a/packages/bruno-app/src/components/RequestPane/Auth/index.js b/packages/bruno-app/src/components/RequestPane/Auth/index.js index 1515e5224f..743d23267e 100644 --- a/packages/bruno-app/src/components/RequestPane/Auth/index.js +++ b/packages/bruno-app/src/components/RequestPane/Auth/index.js @@ -6,6 +6,8 @@ import BearerAuth from './BearerAuth'; import BasicAuth from './BasicAuth'; import DigestAuth from './DigestAuth'; import WsseAuth from './WsseAuth'; +import NTLMAuth from './NTLMAuth'; + import ApiKeyAuth from './ApiKeyAuth'; import StyledWrapper from './StyledWrapper'; import { humanizeRequestAuthMode } from 'utils/collections/index'; @@ -31,6 +33,9 @@ const Auth = ({ item, collection }) => { case 'digest': { return ; } + case 'ntlm': { + return ; + } case 'oauth2': { return ; } diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js index 10f552ec57..d4ad489218 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js @@ -473,6 +473,10 @@ export const collectionsSlice = createSlice({ item.draft.request.auth.mode = 'digest'; item.draft.request.auth.digest = action.payload.content; break; + case 'ntlm': + item.draft.request.auth.mode = 'ntlm'; + item.draft.request.auth.ntlm = action.payload.content; + break; case 'oauth2': item.draft.request.auth.mode = 'oauth2'; item.draft.request.auth.oauth2 = action.payload.content; @@ -1144,6 +1148,9 @@ export const collectionsSlice = createSlice({ case 'digest': set(collection, 'root.request.auth.digest', action.payload.content); break; + case 'ntlm': + set(collection, 'root.request.auth.ntlm', action.payload.content); + break; case 'oauth2': set(collection, 'root.request.auth.oauth2', action.payload.content); break; diff --git a/packages/bruno-app/src/utils/collections/index.js b/packages/bruno-app/src/utils/collections/index.js index d770c60a3c..bc6c731f4d 100644 --- a/packages/bruno-app/src/utils/collections/index.js +++ b/packages/bruno-app/src/utils/collections/index.js @@ -340,6 +340,13 @@ export const transformCollectionToSaveToExportAsFile = (collection, options = {} password: get(si.request, 'auth.digest.password', '') }; break; + case 'ntlm': + di.request.auth.ntlm = { + username: get(si.request, 'auth.ntlm.username', ''), + password: get(si.request, 'auth.ntlm.password', ''), + domain: get(si.request, 'auth.ntlm.domain', '') + }; + break; case 'oauth2': let grantType = get(si.request, 'auth.oauth2.grantType', ''); switch (grantType) { @@ -680,6 +687,10 @@ export const humanizeRequestAuthMode = (mode) => { label = 'Digest Auth'; break; } + case 'ntlm': { + label = 'NTLM'; + break; + } case 'oauth2': { label = 'OAuth 2.0'; break; diff --git a/packages/bruno-cli/package.json b/packages/bruno-cli/package.json index adfc936589..8353e8ba83 100644 --- a/packages/bruno-cli/package.json +++ b/packages/bruno-cli/package.json @@ -50,8 +50,10 @@ "@usebruno/common": "0.1.0", "@usebruno/js": "0.12.0", "@usebruno/lang": "0.12.0", + "@usebruno/vm2": "^3.9.13", "aws4-axios": "^3.3.0", "axios": "1.7.5", + "axios-ntlm": "^1.4.2", "chai": "^4.3.7", "chalk": "^3.0.0", "decomment": "^0.9.5", diff --git a/packages/bruno-cli/src/runner/interpolate-vars.js b/packages/bruno-cli/src/runner/interpolate-vars.js index 8e0ff300c5..88cee00cb5 100644 --- a/packages/bruno-cli/src/runner/interpolate-vars.js +++ b/packages/bruno-cli/src/runner/interpolate-vars.js @@ -165,6 +165,13 @@ const interpolateVars = (request, envVariables = {}, runtimeVariables = {}, proc request.awsv4config.profileName = _interpolate(request.awsv4config.profileName) || ''; } + // interpolate vars for ntlmConfig auth + if (request.ntlmConfig) { + request.ntlmConfig.username = _interpolate(request.ntlmConfig.username) || ''; + request.ntlmConfig.password = _interpolate(request.ntlmConfig.password) || ''; + request.ntlmConfig.domain = _interpolate(request.ntlmConfig.domain) || ''; + } + if (request) return request; }; diff --git a/packages/bruno-cli/src/runner/prepare-request.js b/packages/bruno-cli/src/runner/prepare-request.js index 0ed8667609..f031ff0aa9 100644 --- a/packages/bruno-cli/src/runner/prepare-request.js +++ b/packages/bruno-cli/src/runner/prepare-request.js @@ -68,6 +68,14 @@ const prepareRequest = (item = {}, collection = {}) => { }; } + if (request.auth.mode === 'ntlm') { + axiosRequest.ntlmConfig = { + username: get(request, 'auth.ntlm.username'), + password: get(request, 'auth.ntlm.password'), + domain: get(request, 'auth.ntlm.domain') + }; + } + if (request.auth.mode === 'bearer') { axiosRequest.headers['Authorization'] = `Bearer ${get(request, 'auth.bearer.token')}`; } diff --git a/packages/bruno-cli/src/runner/run-single-request.js b/packages/bruno-cli/src/runner/run-single-request.js index 29ed749b94..67bda80216 100644 --- a/packages/bruno-cli/src/runner/run-single-request.js +++ b/packages/bruno-cli/src/runner/run-single-request.js @@ -23,6 +23,8 @@ const { parseDataFromResponse } = require('../utils/common'); const { getCookieStringForUrl, saveCookies, shouldUseCookies } = require('../utils/cookies'); const { createFormData } = require('../utils/form-data'); const protocolRegex = /^([-+\w]{1,25})(:?\/\/|:)/; +const { NtlmClient } = require('axios-ntlm'); + const onConsoleLog = (type, args) => { console[type](...args); @@ -250,8 +252,13 @@ const runSingleRequest = async function ( let response, responseTime; try { - // run request - const axiosInstance = makeAxiosInstance(); + + let axiosInstance = makeAxiosInstance(); + if (request.ntlmConfig) { + axiosInstance=NtlmClient(request.ntlmConfig,axiosInstance) + delete request.ntlmConfig; + } + if (request.awsv4config) { // todo: make this happen in prepare-request.js diff --git a/packages/bruno-electron/package.json b/packages/bruno-electron/package.json index 7e8e255649..c7a6b369ab 100644 --- a/packages/bruno-electron/package.json +++ b/packages/bruno-electron/package.json @@ -19,7 +19,9 @@ "test": "node --experimental-vm-modules $(npx which jest)" }, "jest": { - "modulePaths": ["node_modules"] + "modulePaths": [ + "node_modules" + ] }, "dependencies": { "@aws-sdk/credential-providers": "3.658.1", @@ -28,9 +30,11 @@ "@usebruno/lang": "0.12.0", "@usebruno/node-machine-id": "^2.0.0", "@usebruno/schema": "0.7.0", + "@usebruno/vm2": "^3.9.13", "about-window": "^1.15.2", "aws4-axios": "^3.3.0", "axios": "1.7.5", + "axios-ntlm": "^1.4.2", "chai": "^4.3.7", "chokidar": "^3.5.3", "content-disposition": "^0.5.4", @@ -55,7 +59,6 @@ "socks-proxy-agent": "^8.0.2", "tough-cookie": "^4.1.3", "uuid": "^9.0.0", - "@usebruno/vm2": "^3.9.13", "yup": "^0.32.11" }, "optionalDependencies": { diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index 782878c59a..1865426e0e 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -40,6 +40,7 @@ const iconv = require('iconv-lite'); const FormData = require('form-data'); const { createFormData } = require('../../utils/form-data'); const { findItemInCollectionByPathname } = require('../../utils/collection'); +const { NtlmClient } = require('axios-ntlm'); const safeStringifyJSON = (data) => { try { @@ -272,7 +273,15 @@ const configureRequest = async ( ...httpsAgentRequestFields }); } - const axiosInstance = makeAxiosInstance(); + + + let axiosInstance = makeAxiosInstance(); + + if (request.ntlmConfig) { + axiosInstance=NtlmClient(request.ntlmConfig,axiosInstance) + delete request.ntlmConfig; + } + if (request.oauth2) { let requestCopy = cloneDeep(request); diff --git a/packages/bruno-electron/src/ipc/network/interpolate-vars.js b/packages/bruno-electron/src/ipc/network/interpolate-vars.js index d9833f59a0..2b46327afb 100644 --- a/packages/bruno-electron/src/ipc/network/interpolate-vars.js +++ b/packages/bruno-electron/src/ipc/network/interpolate-vars.js @@ -231,6 +231,14 @@ const interpolateVars = (request, envVariables = {}, runtimeVariables = {}, proc request.wsse.password = _interpolate(request.wsse.password) || ''; } + + // interpolate vars for ntlmConfig auth + if (request.ntlmConfig) { + request.ntlmConfig.username = _interpolate(request.ntlmConfig.username) || ''; + request.ntlmConfig.password = _interpolate(request.ntlmConfig.password) || ''; + request.ntlmConfig.domain = _interpolate(request.ntlmConfig.domain) || ''; + } + return request; }; diff --git a/packages/bruno-electron/src/ipc/network/prepare-request.js b/packages/bruno-electron/src/ipc/network/prepare-request.js index 69825bc4e1..6c7672e7d6 100644 --- a/packages/bruno-electron/src/ipc/network/prepare-request.js +++ b/packages/bruno-electron/src/ipc/network/prepare-request.js @@ -5,6 +5,7 @@ const { getTreePathFromCollectionToItem, mergeHeaders, mergeScripts, mergeVars } const { buildFormUrlEncodedPayload, createFormData } = require('../../utils/form-data'); const setAuthHeaders = (axiosRequest, request, collectionRoot) => { + const collectionAuth = get(collectionRoot, 'request.auth'); if (collectionAuth && request.auth.mode === 'inherit') { switch (collectionAuth.mode) { @@ -33,6 +34,13 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { password: get(collectionAuth, 'digest.password') }; break; + case 'ntlm': + axiosRequest.ntlmConfig = { + username: get(collectionAuth, 'ntlm.username'), + password: get(collectionAuth, 'ntlm.password'), + domain: get(collectionAuth, 'ntlm.domain') + }; + break; case 'wsse': const username = get(request, 'auth.wsse.username', ''); const password = get(request, 'auth.wsse.password', ''); @@ -89,6 +97,13 @@ const setAuthHeaders = (axiosRequest, request, collectionRoot) => { password: get(request, 'auth.digest.password') }; break; + case 'ntlm': + axiosRequest.ntlmConfig = { + username: get(request, 'auth.ntlm.username'), + password: get(request, 'auth.ntlm.password'), + domain: get(request, 'auth.ntlm.domain') + }; + break; case 'oauth2': const grantType = get(request, 'auth.oauth2.grantType'); switch (grantType) { diff --git a/packages/bruno-lang/v2/src/bruToJson.js b/packages/bruno-lang/v2/src/bruToJson.js index 228691c1b2..2fe5fb472a 100644 --- a/packages/bruno-lang/v2/src/bruToJson.js +++ b/packages/bruno-lang/v2/src/bruToJson.js @@ -23,7 +23,7 @@ const { outdentString } = require('../../v1/src/utils'); */ const grammar = ohm.grammar(`Bru { BruFile = (meta | http | query | params | headers | auths | bodies | varsandassert | script | tests | docs)* - auths = authawsv4 | authbasic | authbearer | authdigest | authOAuth2 | authwsse | authapikey + auths = authawsv4 | authbasic | authbearer | authdigest | authNTLM | authOAuth2 | authwsse | authapikey bodies = bodyjson | bodytext | bodyxml | bodysparql | bodygraphql | bodygraphqlvars | bodyforms | body bodyforms = bodyformurlencoded | bodymultipart params = paramspath | paramsquery @@ -87,6 +87,7 @@ const grammar = ohm.grammar(`Bru { authbasic = "auth:basic" dictionary authbearer = "auth:bearer" dictionary authdigest = "auth:digest" dictionary + authNTLM = "auth:ntlm" dictionary authOAuth2 = "auth:oauth2" dictionary authwsse = "auth:wsse" dictionary authapikey = "auth:apikey" dictionary @@ -450,6 +451,26 @@ const sem = grammar.createSemantics().addAttribute('ast', { } }; }, + authNTLM(_1, dictionary) { + const auth = mapPairListToKeyValPairs(dictionary.ast, false); + const usernameKey = _.find(auth, { name: 'username' }); + const passwordKey = _.find(auth, { name: 'password' }); + const domainKey = _.find(auth, { name: 'domain' }); + + const username = usernameKey ? usernameKey.value : ''; + const password = passwordKey ? passwordKey.value : ''; + const domain = passwordKey ? domainKey.value : ''; + + return { + auth: { + ntlm: { + username, + password, + domain + } + } + }; + }, authOAuth2(_1, dictionary) { const auth = mapPairListToKeyValPairs(dictionary.ast, false); const grantTypeKey = _.find(auth, { name: 'grant_type' }); diff --git a/packages/bruno-lang/v2/src/collectionBruToJson.js b/packages/bruno-lang/v2/src/collectionBruToJson.js index 5180f0193d..61d373d91e 100644 --- a/packages/bruno-lang/v2/src/collectionBruToJson.js +++ b/packages/bruno-lang/v2/src/collectionBruToJson.js @@ -4,7 +4,7 @@ const { outdentString } = require('../../v1/src/utils'); const grammar = ohm.grammar(`Bru { BruFile = (meta | query | headers | auth | auths | vars | script | tests | docs)* - auths = authawsv4 | authbasic | authbearer | authdigest | authOAuth2 | authwsse | authapikey + auths = authawsv4 | authbasic | authbearer | authdigest | authNTLM |authOAuth2 | authwsse | authapikey nl = "\\r"? "\\n" st = " " | "\\t" @@ -42,6 +42,7 @@ const grammar = ohm.grammar(`Bru { authbasic = "auth:basic" dictionary authbearer = "auth:bearer" dictionary authdigest = "auth:digest" dictionary + authNTLM = "auth:ntlm" dictionary authOAuth2 = "auth:oauth2" dictionary authwsse = "auth:wsse" dictionary authapikey = "auth:apikey" dictionary @@ -245,6 +246,26 @@ const sem = grammar.createSemantics().addAttribute('ast', { } }; }, + authNTLM(_1, dictionary) { + const auth = mapPairListToKeyValPairs(dictionary.ast, false); + const usernameKey = _.find(auth, { name: 'username' }); + const passwordKey = _.find(auth, { name: 'password' }); + const domainKey = _.find(auth, { name: 'domain' }); + + const username = usernameKey ? usernameKey.value : ''; + const password = passwordKey ? passwordKey.value : ''; + const domain = domainKey ? domainKey.value : ''; + + return { + auth: { + ntlm: { + username, + password, + domain + } + } + }; + }, authOAuth2(_1, dictionary) { const auth = mapPairListToKeyValPairs(dictionary.ast, false); const grantTypeKey = _.find(auth, { name: 'grant_type' }); diff --git a/packages/bruno-lang/v2/src/jsonToBru.js b/packages/bruno-lang/v2/src/jsonToBru.js index 5c8a573b62..62b31c2f99 100644 --- a/packages/bruno-lang/v2/src/jsonToBru.js +++ b/packages/bruno-lang/v2/src/jsonToBru.js @@ -165,6 +165,18 @@ ${indentString(`password: ${auth?.digest?.password || ''}`)} `; } + + if (auth && auth.ntlm) { + bru += `auth:ntlm { +${indentString(`username: ${auth?.ntlm?.username || ''}`)} +${indentString(`password: ${auth?.ntlm?.password || ''}`)} +${indentString(`domain: ${auth?.ntlm?.domain || ''}`)} + +} + +`; + } + if (auth && auth.oauth2) { switch (auth?.oauth2?.grantType) { case 'password': diff --git a/packages/bruno-lang/v2/src/jsonToCollectionBru.js b/packages/bruno-lang/v2/src/jsonToCollectionBru.js index 8b162b7a6f..c2a843dc6e 100644 --- a/packages/bruno-lang/v2/src/jsonToCollectionBru.js +++ b/packages/bruno-lang/v2/src/jsonToCollectionBru.js @@ -120,6 +120,17 @@ ${indentString(`username: ${auth.digest.username}`)} ${indentString(`password: ${auth.digest.password}`)} } +`; + } + +if (auth && auth.ntlm) { + bru += `auth:ntlm { +${indentString(`username: ${auth.ntlm.username}`)} +${indentString(`password: ${auth.ntlm.password}`)} +${indentString(`domain: ${auth.ntlm.domain}`)} + +} + `; } diff --git a/packages/bruno-schema/src/collections/index.js b/packages/bruno-schema/src/collections/index.js index 3d5959f15d..b6e044ae47 100644 --- a/packages/bruno-schema/src/collections/index.js +++ b/packages/bruno-schema/src/collections/index.js @@ -127,6 +127,17 @@ const authDigestSchema = Yup.object({ .noUnknown(true) .strict(); + + + const authNTLMSchema = Yup.object({ + username: Yup.string().nullable(), + password: Yup.string().nullable(), + domain: Yup.string().nullable() + + }) + .noUnknown(true) + .strict(); + const authApiKeySchema = Yup.object({ key: Yup.string().nullable(), value: Yup.string().nullable(), @@ -195,11 +206,12 @@ const oauth2Schema = Yup.object({ const authSchema = Yup.object({ mode: Yup.string() - .oneOf(['inherit', 'none', 'awsv4', 'basic', 'bearer', 'digest', 'oauth2', 'wsse', 'apikey']) + .oneOf(['inherit', 'none', 'awsv4', 'basic', 'bearer', 'digest', 'ntlm', 'oauth2', 'wsse', 'apikey']) .required('mode is required'), awsv4: authAwsV4Schema.nullable(), basic: authBasicSchema.nullable(), bearer: authBearerSchema.nullable(), + ntlm: authNTLMSchema.nullable(), digest: authDigestSchema.nullable(), oauth2: oauth2Schema.nullable(), wsse: authWsseSchema.nullable(), From d2d7638a54a265bef668271202fe1fb5bcdfb784 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Mon, 13 Jan 2025 18:49:45 +0530 Subject: [PATCH 03/22] chore: updated package-lock --- package-lock.json | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index abf5d7b578..d7ee4064d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8184,6 +8184,29 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/axios-ntlm": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/axios-ntlm/-/axios-ntlm-1.4.3.tgz", + "integrity": "sha512-CS6WE8chZpEDKxv4IFwr5zcG7InMC6Ek0aj2n2tHauBh+8KiYVC4qMn3N2arjR5tnyILQuTGlI0mc83hgWxS4Q==", + "license": "MIT", + "dependencies": { + "axios": "^1.7.9", + "des.js": "^1.1.0", + "dev-null": "^0.1.1", + "js-md4": "^0.3.2" + } + }, + "node_modules/axios-ntlm/node_modules/axios": { + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -10928,7 +10951,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", - "dev": true, "license": "MIT", "dependencies": { "inherits": "^2.0.1", @@ -10979,6 +11001,12 @@ "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", "license": "MIT" }, + "node_modules/dev-null": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/dev-null/-/dev-null-0.1.1.tgz", + "integrity": "sha512-nMNZG0zfMgmdv8S5O0TM5cpwNbGKRGPCxVsr0SmA3NZZy9CYBbuNLL0PD3Acx9e5LIUgwONXtM9kM6RlawPxEQ==", + "license": "MIT" + }, "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", @@ -15466,6 +15494,12 @@ "jiti": "bin/jiti.js" } }, + "node_modules/js-md4": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz", + "integrity": "sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA==", + "license": "MIT" + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -16722,7 +16756,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true, "license": "ISC" }, "node_modules/minimalistic-crypto-utils": { @@ -24115,6 +24148,7 @@ "@usebruno/vm2": "^3.9.13", "aws4-axios": "^3.3.0", "axios": "1.7.5", + "axios-ntlm": "^1.4.2", "chai": "^4.3.7", "chalk": "^3.0.0", "decomment": "^0.9.5", @@ -24177,6 +24211,7 @@ "about-window": "^1.15.2", "aws4-axios": "^3.3.0", "axios": "1.7.5", + "axios-ntlm": "^1.4.2", "chai": "^4.3.7", "chokidar": "^3.5.3", "content-disposition": "^0.5.4", From abb0a7b0db91e902ddf42c3690f9e69bf7cedf9e Mon Sep 17 00:00:00 2001 From: Pragadesh-45 Date: Wed, 15 Jan 2025 13:08:44 +0530 Subject: [PATCH 04/22] chore: version bump --- package-lock.json | 2 +- packages/bruno-app/src/providers/App/useTelemetry.js | 2 +- packages/bruno-electron/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index d7ee4064d3..98b2208634 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24199,7 +24199,7 @@ }, "packages/bruno-electron": { "name": "bruno", - "version": "v1.36.0", + "version": "v1.38.1", "dependencies": { "@aws-sdk/credential-providers": "3.658.1", "@usebruno/common": "0.1.0", diff --git a/packages/bruno-app/src/providers/App/useTelemetry.js b/packages/bruno-app/src/providers/App/useTelemetry.js index f89b1343ee..3692ba7343 100644 --- a/packages/bruno-app/src/providers/App/useTelemetry.js +++ b/packages/bruno-app/src/providers/App/useTelemetry.js @@ -58,7 +58,7 @@ const trackStart = () => { event: 'start', properties: { os: platformLib.os.family, - version: '1.36.0' + version: 'v1.38.1' } }); }; diff --git a/packages/bruno-electron/package.json b/packages/bruno-electron/package.json index c7a6b369ab..16a032b3a8 100644 --- a/packages/bruno-electron/package.json +++ b/packages/bruno-electron/package.json @@ -1,5 +1,5 @@ { - "version": "v1.36.0", + "version": "v1.38.1", "name": "bruno", "description": "Opensource API Client for Exploring and Testing APIs", "homepage": "https://www.usebruno.com", From 27ef28ae9b6c23dbc2828021d4e6551c802027d0 Mon Sep 17 00:00:00 2001 From: Pragadesh-45 Date: Wed, 15 Jan 2025 13:15:21 +0530 Subject: [PATCH 05/22] chore: version bump --- packages/bruno-app/src/providers/App/useTelemetry.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bruno-app/src/providers/App/useTelemetry.js b/packages/bruno-app/src/providers/App/useTelemetry.js index 3692ba7343..6b64e1279e 100644 --- a/packages/bruno-app/src/providers/App/useTelemetry.js +++ b/packages/bruno-app/src/providers/App/useTelemetry.js @@ -58,7 +58,7 @@ const trackStart = () => { event: 'start', properties: { os: platformLib.os.family, - version: 'v1.38.1' + version: '1.38.1' } }); }; From dbf1cad124211945638c264c50a0ca86cdcbe735 Mon Sep 17 00:00:00 2001 From: Pragadesh-45 Date: Wed, 15 Jan 2025 19:57:06 +0530 Subject: [PATCH 06/22] fix: remove `removeQuotes()` --- packages/bruno-js/src/sandbox/quickjs/index.js | 18 ++++++++++-------- packages/bruno-js/src/utils.js | 16 +++++++++------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/packages/bruno-js/src/sandbox/quickjs/index.js b/packages/bruno-js/src/sandbox/quickjs/index.js index d5fe5e8f3b..35a4ee28b5 100644 --- a/packages/bruno-js/src/sandbox/quickjs/index.js +++ b/packages/bruno-js/src/sandbox/quickjs/index.js @@ -22,12 +22,12 @@ const toNumber = (value) => { return Number.isInteger(num) ? parseInt(value, 10) : parseFloat(value); }; -const removeQuotes = (str) => { - if ((str.startsWith('"') && str.endsWith('"')) || (str.startsWith("'") && str.endsWith("'"))) { - return str.slice(1, -1); - } - return str; -}; +// const removeQuotes = (str) => { +// if ((str.startsWith('"') && str.endsWith('"')) || (str.startsWith("'") && str.endsWith("'"))) { +// return str.slice(1, -1); +// } +// return str; +// }; const executeQuickJsVm = ({ script: externalScript, context: externalContext, scriptType = 'template-literal' }) => { if (!externalScript?.length || typeof externalScript !== 'string') { @@ -44,7 +44,8 @@ const executeQuickJsVm = ({ script: externalScript, context: externalContext, sc if (externalScript === 'null') return null; if (externalScript === 'undefined') return undefined; - externalScript = removeQuotes(externalScript); + // This is commented out as part of the fix for #3758 + // externalScript = removeQuotes(externalScript); const vm = QuickJSSyncContext; @@ -94,7 +95,8 @@ const executeQuickJsVmAsync = async ({ script: externalScript, context: external if (externalScript === 'null') return null; if (externalScript === 'undefined') return undefined; - externalScript = removeQuotes(externalScript); + // This is commented out as part of the fix for #3758 + // externalScript = removeQuotes(externalScript); try { const module = await newQuickJSWASMModule(); diff --git a/packages/bruno-js/src/utils.js b/packages/bruno-js/src/utils.js index 55b454d02a..32fa9d9bef 100644 --- a/packages/bruno-js/src/utils.js +++ b/packages/bruno-js/src/utils.js @@ -85,13 +85,15 @@ const evaluateJsTemplateLiteral = (templateLiteral, context) => { return undefined; } - if (templateLiteral.startsWith('"') && templateLiteral.endsWith('"')) { - return templateLiteral.slice(1, -1); - } - - if (templateLiteral.startsWith("'") && templateLiteral.endsWith("'")) { - return templateLiteral.slice(1, -1); - } + // This is commented out as part of the fix for #3758 + // if (templateLiteral.startsWith('"') && templateLiteral.endsWith('"')) { + // return templateLiteral.slice(1, -1); + // } + + // This is commented out as part of the fix for #3758 + // if (templateLiteral.startsWith("'") && templateLiteral.endsWith("'")) { + // return templateLiteral.slice(1, -1); + // } if (!isNaN(templateLiteral)) { const number = Number(templateLiteral); From cf2cb0736ed5d77c1505a04d13c965c0be8aef47 Mon Sep 17 00:00:00 2001 From: Pragadesh-45 Date: Wed, 15 Jan 2025 20:42:02 +0530 Subject: [PATCH 07/22] fix: remove commented-out `removeQuotes()` function --- packages/bruno-js/src/sandbox/quickjs/index.js | 10 ---------- packages/bruno-js/src/utils.js | 10 ---------- 2 files changed, 20 deletions(-) diff --git a/packages/bruno-js/src/sandbox/quickjs/index.js b/packages/bruno-js/src/sandbox/quickjs/index.js index 35a4ee28b5..58ccd885d0 100644 --- a/packages/bruno-js/src/sandbox/quickjs/index.js +++ b/packages/bruno-js/src/sandbox/quickjs/index.js @@ -22,12 +22,6 @@ const toNumber = (value) => { return Number.isInteger(num) ? parseInt(value, 10) : parseFloat(value); }; -// const removeQuotes = (str) => { -// if ((str.startsWith('"') && str.endsWith('"')) || (str.startsWith("'") && str.endsWith("'"))) { -// return str.slice(1, -1); -// } -// return str; -// }; const executeQuickJsVm = ({ script: externalScript, context: externalContext, scriptType = 'template-literal' }) => { if (!externalScript?.length || typeof externalScript !== 'string') { @@ -44,8 +38,6 @@ const executeQuickJsVm = ({ script: externalScript, context: externalContext, sc if (externalScript === 'null') return null; if (externalScript === 'undefined') return undefined; - // This is commented out as part of the fix for #3758 - // externalScript = removeQuotes(externalScript); const vm = QuickJSSyncContext; @@ -95,8 +87,6 @@ const executeQuickJsVmAsync = async ({ script: externalScript, context: external if (externalScript === 'null') return null; if (externalScript === 'undefined') return undefined; - // This is commented out as part of the fix for #3758 - // externalScript = removeQuotes(externalScript); try { const module = await newQuickJSWASMModule(); diff --git a/packages/bruno-js/src/utils.js b/packages/bruno-js/src/utils.js index 32fa9d9bef..6b5ecacb57 100644 --- a/packages/bruno-js/src/utils.js +++ b/packages/bruno-js/src/utils.js @@ -85,16 +85,6 @@ const evaluateJsTemplateLiteral = (templateLiteral, context) => { return undefined; } - // This is commented out as part of the fix for #3758 - // if (templateLiteral.startsWith('"') && templateLiteral.endsWith('"')) { - // return templateLiteral.slice(1, -1); - // } - - // This is commented out as part of the fix for #3758 - // if (templateLiteral.startsWith("'") && templateLiteral.endsWith("'")) { - // return templateLiteral.slice(1, -1); - // } - if (!isNaN(templateLiteral)) { const number = Number(templateLiteral); // Check if the number is too high. Too high number might get altered, see #1000 From a73d2a02cfe420ba054fa7716624ee13952a4393 Mon Sep 17 00:00:00 2001 From: naman-bruno Date: Thu, 16 Jan 2025 19:59:14 +0530 Subject: [PATCH 08/22] fix: Request vars displayed in red color in body even if they are valid (#3812) * fix: Request vars displayed in red color in body * chore: removing index import --------- Co-authored-by: Anoop M D --- packages/bruno-app/src/components/CodeEditor/index.js | 6 +++--- .../src/components/RequestPane/RequestBody/index.js | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/bruno-app/src/components/CodeEditor/index.js b/packages/bruno-app/src/components/CodeEditor/index.js index 168a3b02be..398007a4ab 100644 --- a/packages/bruno-app/src/components/CodeEditor/index.js +++ b/packages/bruno-app/src/components/CodeEditor/index.js @@ -7,12 +7,12 @@ import React from 'react'; import { isEqual, escapeRegExp } from 'lodash'; -import { getEnvironmentVariables } from 'utils/collections'; import { defineCodeMirrorBrunoVariablesMode } from 'utils/common/codemirror'; import StyledWrapper from './StyledWrapper'; import * as jsonlint from '@prantlf/jsonlint'; import { JSHINT } from 'jshint'; import stripJsonComments from 'strip-json-comments'; +import { getAllVariables } from 'utils/collections'; let CodeMirror; const SERVER_RENDERED = typeof window === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true; @@ -293,7 +293,7 @@ export default class CodeEditor extends React.Component { } if (this.editor) { - let variables = getEnvironmentVariables(this.props.collection); + let variables = getAllVariables(this.props.collection, this.props.item); if (!isEqual(variables, this.variables)) { this.addOverlay(); } @@ -333,7 +333,7 @@ export default class CodeEditor extends React.Component { addOverlay = () => { const mode = this.props.mode || 'application/ld+json'; - let variables = getEnvironmentVariables(this.props.collection); + let variables = getAllVariables(this.props.collection, this.props.item); this.variables = variables; defineCodeMirrorBrunoVariablesMode(variables, mode); diff --git a/packages/bruno-app/src/components/RequestPane/RequestBody/index.js b/packages/bruno-app/src/components/RequestPane/RequestBody/index.js index 5fde52ea09..ca60c8662a 100644 --- a/packages/bruno-app/src/components/RequestPane/RequestBody/index.js +++ b/packages/bruno-app/src/components/RequestPane/RequestBody/index.js @@ -48,6 +48,7 @@ const RequestBody = ({ item, collection }) => { Date: Thu, 16 Jan 2025 20:01:48 +0530 Subject: [PATCH 09/22] fix: body formurl value disappearing (#3803) --- .../src/components/MultiLineEditor/StyledWrapper.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/bruno-app/src/components/MultiLineEditor/StyledWrapper.js b/packages/bruno-app/src/components/MultiLineEditor/StyledWrapper.js index 2473463db3..b449ffce6a 100644 --- a/packages/bruno-app/src/components/MultiLineEditor/StyledWrapper.js +++ b/packages/bruno-app/src/components/MultiLineEditor/StyledWrapper.js @@ -19,9 +19,8 @@ const StyledWrapper = styled.div` opacity: 0.5; } - .CodeMirror-scroll { - overflow: hidden !important; - ${'' /* padding-bottom: 50px !important; */} + .CodeMirror-scroll { + overflow: visible !important; position: relative; display: block; margin: 0px; From 5b04e0c189957f0ecc5117d0e1a94a42d1897bf3 Mon Sep 17 00:00:00 2001 From: pooja-bruno Date: Thu, 16 Jan 2025 20:04:34 +0530 Subject: [PATCH 10/22] fix: renaming first collection env (#3735) --- .../EnvironmentSettings/EnvironmentList/index.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js index 079b578917..48f341f26f 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js @@ -9,6 +9,7 @@ import ManageSecrets from '../ManageSecrets'; import StyledWrapper from './StyledWrapper'; import ConfirmSwitchEnv from './ConfirmSwitchEnv'; import ToolHint from 'components/ToolHint'; +import { isEqual } from 'lodash'; const EnvironmentList = ({ selectedEnvironment, setSelectedEnvironment, collection, isModified, setIsModified }) => { const { environments } = collection; @@ -24,6 +25,11 @@ const EnvironmentList = ({ selectedEnvironment, setSelectedEnvironment, collecti useEffect(() => { if (selectedEnvironment) { + const _selectedEnvironment = environments?.find(env => env?.uid === selectedEnvironment?.uid); + const hasSelectedEnvironmentChanged = !isEqual(selectedEnvironment, _selectedEnvironment); + if (hasSelectedEnvironmentChanged) { + setSelectedEnvironment(_selectedEnvironment); + } setOriginalEnvironmentVariables(selectedEnvironment.variables); return; } From 472b5452f73a1ffbc9af8f03cec749a5bfabd6ed Mon Sep 17 00:00:00 2001 From: naman-bruno Date: Thu, 16 Jan 2025 20:06:53 +0530 Subject: [PATCH 11/22] =?UTF-8?q?Allow=20rearrangement=20of=20table=20item?= =?UTF-8?q?s=20in=20params,=20body,=20vars,=20headers,=20etc=E2=80=A6=20(#?= =?UTF-8?q?3801)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Allow rearrangement of table items in params, body, vars, headers, and assert * updated drag function name --- .../Assertions/AssertionRow/index.js | 17 +- .../RequestPane/Assertions/StyledWrapper.js | 15 +- .../RequestPane/Assertions/index.js | 56 ++++-- .../FormUrlEncodedParams/StyledWrapper.js | 8 - .../RequestPane/FormUrlEncodedParams/index.js | 138 +++++++------ .../MultipartFormParams/StyledWrapper.js | 16 -- .../RequestPane/MultipartFormParams/index.js | 188 ++++++++++-------- .../RequestPane/QueryParams/index.js | 4 +- .../RequestHeaders/StyledWrapper.js | 8 - .../RequestPane/RequestHeaders/index.js | 41 ++-- .../Vars/VarsTable/StyledWrapper.js | 11 +- .../RequestPane/Vars/VarsTable/index.js | 64 +++--- .../ReduxStore/slices/collections/index.js | 124 ++++++++++++ 13 files changed, 413 insertions(+), 277 deletions(-) diff --git a/packages/bruno-app/src/components/RequestPane/Assertions/AssertionRow/index.js b/packages/bruno-app/src/components/RequestPane/Assertions/AssertionRow/index.js index ea94847808..e56e3c3986 100644 --- a/packages/bruno-app/src/components/RequestPane/Assertions/AssertionRow/index.js +++ b/packages/bruno-app/src/components/RequestPane/Assertions/AssertionRow/index.js @@ -146,19 +146,8 @@ const AssertionRow = ({ const { operator, value } = parseAssertionOperator(assertion.value); return ( -
- handleAssertionChange(e, assertion, 'name')} - /> -
- - - - - - - - - +
ExprOperatorValue
+ {assertions && assertions.length ? assertions.map((assertion) => { - return ( + return ( + + { onSave={onSave} handleRun={handleRun} /> - ); - }) + + ); + }) : null} - -
+ handleAssertionChange(e, assertion, 'name')} + /> +
+ + diff --git a/packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/StyledWrapper.js b/packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/StyledWrapper.js index f04a30be0f..517415935f 100644 --- a/packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/StyledWrapper.js +++ b/packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/StyledWrapper.js @@ -19,16 +19,8 @@ const Wrapper = styled.div` } td { padding: 6px 10px; - - &:nth-child(1) { - width: 30%; - } - - &:nth-child(3) { - width: 70px; } } - } .btn-add-param { font-size: 0.8125rem; diff --git a/packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/index.js b/packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/index.js index 22de4735ba..c8eeda531f 100644 --- a/packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/index.js +++ b/packages/bruno-app/src/components/RequestPane/FormUrlEncodedParams/index.js @@ -7,11 +7,14 @@ import { useTheme } from 'providers/Theme'; import { addFormUrlEncodedParam, updateFormUrlEncodedParam, - deleteFormUrlEncodedParam + deleteFormUrlEncodedParam, + moveFormUrlEncodedParam } from 'providers/ReduxStore/slices/collections'; import MultiLineEditor from 'components/MultiLineEditor'; import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; +import ReorderTable from 'components/ReorderTable/index'; +import Table from 'components/Table/index'; const FormUrlEncodedParams = ({ item, collection }) => { const dispatch = useDispatch(); @@ -64,75 +67,84 @@ const FormUrlEncodedParams = ({ item, collection }) => { ); }; + const handleParamDrag = ({ updateReorderedItem }) => { + dispatch( + moveFormUrlEncodedParam({ + collectionUid: collection.uid, + itemUid: item.uid, + updateReorderedItem + }) + ); + }; + return ( - - - - - - - - - +
KeyValue
+ {params && params.length ? params.map((param, index) => { - return ( - - + + + - - - - ); - }) + + + + + ); + }) : null} - -
+ return ( +
+ handleParamChange(e, param, 'name')} + /> + + + handleParamChange( + { + target: { + value: newValue + } + }, + param, + 'value' + ) + } + allowNewlines={true} + onRun={handleRun} + collection={collection} + item={item} + /> + +
handleParamChange(e, param, 'name')} - /> -
- - handleParamChange( - { - target: { - value: newValue - } - }, - param, - 'value' - ) - } - allowNewlines={true} - onRun={handleRun} - collection={collection} - item={item} + type="checkbox" + checked={param.enabled} + tabIndex="-1" + className="mr-3 mousetrap" + onChange={(e) => handleParamChange(e, param, 'enabled')} /> - -
- handleParamChange(e, param, 'enabled')} - /> - -
-
+ + diff --git a/packages/bruno-app/src/components/RequestPane/MultipartFormParams/StyledWrapper.js b/packages/bruno-app/src/components/RequestPane/MultipartFormParams/StyledWrapper.js index 49c45f21dc..f7b6e5d132 100644 --- a/packages/bruno-app/src/components/RequestPane/MultipartFormParams/StyledWrapper.js +++ b/packages/bruno-app/src/components/RequestPane/MultipartFormParams/StyledWrapper.js @@ -19,23 +19,7 @@ const Wrapper = styled.div` } td { padding: 6px 10px; - - &:nth-child(1) { - width: 30%; - } - - &:nth-child(2) { - width: 45%; - } - - &:nth-child(3) { - width: 25%; - } - - &:nth-child(4) { - width: 70px; } - } } .btn-add-param { diff --git a/packages/bruno-app/src/components/RequestPane/MultipartFormParams/index.js b/packages/bruno-app/src/components/RequestPane/MultipartFormParams/index.js index af23a645e6..790f7d5fa3 100644 --- a/packages/bruno-app/src/components/RequestPane/MultipartFormParams/index.js +++ b/packages/bruno-app/src/components/RequestPane/MultipartFormParams/index.js @@ -7,12 +7,15 @@ import { useTheme } from 'providers/Theme'; import { addMultipartFormParam, updateMultipartFormParam, - deleteMultipartFormParam + deleteMultipartFormParam, + moveMultipartFormParam } from 'providers/ReduxStore/slices/collections'; import MultiLineEditor from 'components/MultiLineEditor'; import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions'; import StyledWrapper from './StyledWrapper'; import FilePickerEditor from 'components/FilePickerEditor'; +import Table from 'components/Table/index'; +import ReorderTable from 'components/ReorderTable/index'; const MultipartFormParams = ({ item, collection }) => { const dispatch = useDispatch(); @@ -82,80 +85,65 @@ const MultipartFormParams = ({ item, collection }) => { ); }; + const handleParamDrag = ({ updateReorderedItem }) => { + dispatch( + moveMultipartFormParam({ + collectionUid: collection.uid, + itemUid: item.uid, + updateReorderedItem + }) + ); + }; + return ( - - - - - - - - - - +
KeyValueContent-Type
+ {params && params.length ? params.map((param, index) => { - return ( - - + + - - + + - - - ); - }) + + + + + ); + }) : null} - -
- handleParamChange(e, param, 'name')} + return ( +
+ handleParamChange(e, param, 'name')} + /> + + {param.type === 'file' ? ( + + handleParamChange( + { + target: { + value: newValue + } + }, + param, + 'value' + ) + } + collection={collection} /> - - {param.type === 'file' ? ( - - handleParamChange( - { - target: { - value: newValue - } - }, - param, - 'value' - ) - } - collection={collection} - /> - ) : ( - - handleParamChange( - { - target: { - value: newValue - } - }, - param, - 'value' - ) - } - onRun={handleRun} - allowNewlines={true} - collection={collection} - item={item} - /> - )} - + ) : ( handleParamChange( { @@ -164,33 +152,57 @@ const MultipartFormParams = ({ item, collection }) => { } }, param, - 'contentType' + 'value' ) } onRun={handleRun} + allowNewlines={true} collection={collection} + item={item} + /> + )} + + + handleParamChange( + { + target: { + value: newValue + } + }, + param, + 'contentType' + ) + } + onRun={handleRun} + collection={collection} + /> + +
+ handleParamChange(e, param, 'enabled')} /> -
-
- handleParamChange(e, param, 'enabled')} - /> - -
-
+ +
diff --git a/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/StyledWrapper.js b/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/StyledWrapper.js index efacc82885..c8ec78387f 100644 --- a/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/StyledWrapper.js +++ b/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/StyledWrapper.js @@ -19,16 +19,8 @@ const Wrapper = styled.div` } td { padding: 6px 10px; - - &:nth-child(1) { - width: 30%; - } - - &:nth-child(3) { - width: 70px; } } - } .btn-add-var { font-size: 0.8125rem; @@ -38,7 +30,8 @@ const Wrapper = styled.div` width: 100%; border: solid 1px transparent; outline: none !important; - background-color: inherit; + color: ${(props) => props.theme.table.input.color}; + background: transparent; &:focus { outline: none !important; diff --git a/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js b/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js index 0f94f35bba..c073135d36 100644 --- a/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js +++ b/packages/bruno-app/src/components/RequestPane/Vars/VarsTable/index.js @@ -3,13 +3,15 @@ import cloneDeep from 'lodash/cloneDeep'; import { IconTrash } from '@tabler/icons'; import { useDispatch } from 'react-redux'; import { useTheme } from 'providers/Theme'; -import { addVar, updateVar, deleteVar } from 'providers/ReduxStore/slices/collections'; +import { addVar, updateVar, deleteVar, moveVar } from 'providers/ReduxStore/slices/collections'; import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions'; import SingleLineEditor from 'components/SingleLineEditor'; import InfoTip from 'components/InfoTip'; import StyledWrapper from './StyledWrapper'; import toast from 'react-hot-toast'; import { variableNameRegex } from 'utils/common/regex'; +import Table from 'components/Table/index'; +import ReorderTable from 'components/ReorderTable/index'; const VarsTable = ({ item, collection, vars, varType }) => { const dispatch = useDispatch(); @@ -73,35 +75,41 @@ const VarsTable = ({ item, collection, vars, varType }) => { ); }; + const handleVarDrag = ({ updateReorderedItem }) => { + dispatch( + moveVar({ + type: varType, + collectionUid: collection.uid, + itemUid: item.uid, + updateReorderedItem + }) + ); + }; + return ( - - - - - {varType === 'request' ? ( - - ) : ( - - )} - - - - - {vars && vars.length +
Name -
- Value -
-
-
- Expr - -
-
+ Value + + ) : ( +
+ Expr + +
+ ), accessor: 'value', width: '46%' }, + { name: '', accessor: '', width: '14%' } + ]} + > + + {vars && vars.length ? vars.map((_var) => { return ( - - + -
+
{ ); }) : null} -
+ + diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js index d4ad489218..7f40600f62 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js @@ -694,6 +694,28 @@ export const collectionsSlice = createSlice({ } } }, + moveRequestHeader: (state, action) => { + const collection = findCollectionByUid(state.collections, action.payload.collectionUid); + + if (collection) { + const item = findItemInCollection(collection, action.payload.itemUid); + + if (item && isItemARequest(item)) { + // Ensure item.draft is a deep clone of item if not already present + if (!item.draft) { + item.draft = cloneDeep(item); + } + + // Extract payload data + const { updateReorderedItem } = action.payload; + const params = item.draft.request.headers; + + item.draft.request.headers = updateReorderedItem.map((uid) => { + return params.find((param) => param.uid === uid); + }); + } + } + }, addFormUrlEncodedParam: (state, action) => { const collection = findCollectionByUid(state.collections, action.payload.collectionUid); @@ -752,6 +774,28 @@ export const collectionsSlice = createSlice({ } } }, + moveFormUrlEncodedParam: (state, action) => { + const collection = findCollectionByUid(state.collections, action.payload.collectionUid); + + if (collection) { + const item = findItemInCollection(collection, action.payload.itemUid); + + if (item && isItemARequest(item)) { + // Ensure item.draft is a deep clone of item if not already present + if (!item.draft) { + item.draft = cloneDeep(item); + } + + // Extract payload data + const { updateReorderedItem } = action.payload; + const params = item.draft.request.body.formUrlEncoded; + + item.draft.request.body.formUrlEncoded = updateReorderedItem.map((uid) => { + return params.find((param) => param.uid === uid); + }); + } + } + }, addMultipartFormParam: (state, action) => { const collection = findCollectionByUid(state.collections, action.payload.collectionUid); @@ -814,6 +858,28 @@ export const collectionsSlice = createSlice({ } } }, + moveMultipartFormParam: (state, action) => { + const collection = findCollectionByUid(state.collections, action.payload.collectionUid); + + if (collection) { + const item = findItemInCollection(collection, action.payload.itemUid); + + if (item && isItemARequest(item)) { + // Ensure item.draft is a deep clone of item if not already present + if (!item.draft) { + item.draft = cloneDeep(item); + } + + // Extract payload data + const { updateReorderedItem } = action.payload; + const params = item.draft.request.body.multipartForm; + + item.draft.request.body.multipartForm = updateReorderedItem.map((uid) => { + return params.find((param) => param.uid === uid); + }); + } + } + }, updateRequestAuthMode: (state, action) => { const collection = findCollectionByUid(state.collections, action.payload.collectionUid); @@ -1027,6 +1093,28 @@ export const collectionsSlice = createSlice({ } } }, + moveAssertion: (state, action) => { + const collection = findCollectionByUid(state.collections, action.payload.collectionUid); + + if (collection) { + const item = findItemInCollection(collection, action.payload.itemUid); + + if (item && isItemARequest(item)) { + // Ensure item.draft is a deep clone of item if not already present + if (!item.draft) { + item.draft = cloneDeep(item); + } + + // Extract payload data + const { updateReorderedItem } = action.payload; + const params = item.draft.request.assertions; + + item.draft.request.assertions = updateReorderedItem.map((uid) => { + return params.find((param) => param.uid === uid); + }); + } + } + }, addVar: (state, action) => { const collection = findCollectionByUid(state.collections, action.payload.collectionUid); const type = action.payload.type; @@ -1121,6 +1209,37 @@ export const collectionsSlice = createSlice({ } } }, + moveVar: (state, action) => { + const collection = findCollectionByUid(state.collections, action.payload.collectionUid); + const type = action.payload.type; + + if (collection) { + const item = findItemInCollection(collection, action.payload.itemUid); + + if (item && isItemARequest(item)) { + // Ensure item.draft is a deep clone of item if not already present + if (!item.draft) { + item.draft = cloneDeep(item); + } + + // Extract payload data + const { updateReorderedItem } = action.payload; + if(type == "request"){ + const params = item.draft.request.vars.req; + + item.draft.request.vars.req = updateReorderedItem.map((uid) => { + return params.find((param) => param.uid === uid); + }); + } else if (type === 'response') { + const params = item.draft.request.vars.res; + + item.draft.request.vars.res = updateReorderedItem.map((uid) => { + return params.find((param) => param.uid === uid); + }); + } + } + } + }, updateCollectionAuthMode: (state, action) => { const collection = findCollectionByUid(state.collections, action.payload.collectionUid); @@ -1801,12 +1920,15 @@ export const { addRequestHeader, updateRequestHeader, deleteRequestHeader, + moveRequestHeader, addFormUrlEncodedParam, updateFormUrlEncodedParam, deleteFormUrlEncodedParam, + moveFormUrlEncodedParam, addMultipartFormParam, updateMultipartFormParam, deleteMultipartFormParam, + moveMultipartFormParam, updateRequestAuthMode, updateRequestBodyMode, updateRequestBody, @@ -1819,9 +1941,11 @@ export const { addAssertion, updateAssertion, deleteAssertion, + moveAssertion, addVar, updateVar, deleteVar, + moveVar, addFolderHeader, updateFolderHeader, deleteFolderHeader, From 5bfcc9b6e760feaba103afc8befeb2172722247f Mon Sep 17 00:00:00 2001 From: naman-bruno Date: Thu, 16 Jan 2025 20:08:30 +0530 Subject: [PATCH 12/22] Fix: Path table is removed when we rearrange items (#3804) --- .../ReduxStore/slices/collections/index.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js index 7f40600f62..11f12026f7 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js @@ -532,11 +532,16 @@ export const collectionsSlice = createSlice({ const { updateReorderedItem } = action.payload; const params = item.draft.request.params; - item.draft.request.params = updateReorderedItem.map((uid) => { - return params.find((param) => param.uid === uid); + const queryParams = params.filter((param) => param.type === 'query'); + const pathParams = params.filter((param) => param.type === 'path'); + + // Reorder only query params based on updateReorderedItem + const reorderedQueryParams = updateReorderedItem.map((uid) => { + return queryParams.find((param) => param.uid === uid); }); - - // update request url + item.draft.request.params = [...reorderedQueryParams, ...pathParams]; + + // Update request URL const parts = splitOnFirst(item.draft.request.url, '?'); const query = stringifyQueryParams(filter(item.draft.request.params, (p) => p.enabled && p.type === 'query')); if (query && query.length) { From 2bce9b3716a64eb23847859a2df736a21285a2c0 Mon Sep 17 00:00:00 2001 From: pooja-bruno Date: Thu, 16 Jan 2025 20:09:51 +0530 Subject: [PATCH 13/22] add: document save button for folder and collection settings (#3742) --- .../CollectionSettings/Docs/StyledWrapper.js | 3 -- .../CollectionSettings/Docs/index.js | 29 +++++++++++-------- .../FolderSettings/Documentation/index.js | 27 +++++++++-------- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/packages/bruno-app/src/components/CollectionSettings/Docs/StyledWrapper.js b/packages/bruno-app/src/components/CollectionSettings/Docs/StyledWrapper.js index f0ffee808e..262f068e78 100644 --- a/packages/bruno-app/src/components/CollectionSettings/Docs/StyledWrapper.js +++ b/packages/bruno-app/src/components/CollectionSettings/Docs/StyledWrapper.js @@ -2,9 +2,6 @@ import styled from 'styled-components'; const StyledWrapper = styled.div` div.CodeMirror { - /* todo: find a better way */ - height: calc(100vh - 240px); - .CodeMirror-scroll { padding-bottom: 0px; } diff --git a/packages/bruno-app/src/components/CollectionSettings/Docs/index.js b/packages/bruno-app/src/components/CollectionSettings/Docs/index.js index 18a1aca1dc..23dbe9e701 100644 --- a/packages/bruno-app/src/components/CollectionSettings/Docs/index.js +++ b/packages/bruno-app/src/components/CollectionSettings/Docs/index.js @@ -32,22 +32,27 @@ const Docs = ({ collection }) => { const onSave = () => dispatch(saveCollectionRoot(collection.uid)); return ( - -
+ +
{isEditing ? 'Preview' : 'Edit'}
{isEditing ? ( - +
+ + +
) : ( )} diff --git a/packages/bruno-app/src/components/FolderSettings/Documentation/index.js b/packages/bruno-app/src/components/FolderSettings/Documentation/index.js index 81a3ccd014..964afdece6 100644 --- a/packages/bruno-app/src/components/FolderSettings/Documentation/index.js +++ b/packages/bruno-app/src/components/FolderSettings/Documentation/index.js @@ -37,22 +37,25 @@ const Documentation = ({ collection, folder }) => { } return ( - -
+ +
{isEditing ? 'Preview' : 'Edit'}
{isEditing ? ( - +
+ + +
) : ( )} From e5d7cd1be907d717c9c643c0cf06d7a1f152ad58 Mon Sep 17 00:00:00 2001 From: Sanjai Kumar <161328623+sanjaikumar-bruno@users.noreply.github.com> Date: Thu, 16 Jan 2025 20:11:49 +0530 Subject: [PATCH 14/22] feat: add rspack dynamic import configuration to rsbuild (#3819) --- packages/bruno-app/rsbuild.config.mjs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/bruno-app/rsbuild.config.mjs b/packages/bruno-app/rsbuild.config.mjs index 704ea4d090..25f5b7ae7e 100644 --- a/packages/bruno-app/rsbuild.config.mjs +++ b/packages/bruno-app/rsbuild.config.mjs @@ -24,4 +24,16 @@ export default defineConfig({ html: { title: 'Bruno' }, + tools: { + rspack: { + module: { + parser: { + javascript: { + // This loads the JavaScript contents from a library along with the main JavaScript bundle. + dynamicImportMode: "eager", + }, + }, + }, + }, + } }); From 2df7fd6588e642fb4a019a74c61b5e91c75c60f7 Mon Sep 17 00:00:00 2001 From: Hadi <159121162+Exxetler@users.noreply.github.com> Date: Thu, 16 Jan 2025 21:42:33 +0100 Subject: [PATCH 15/22] Added activate button to environment window. (#1531) Co-authored-by: Anoop M D --- .../EnvironmentVariables/index.js | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js index 20ac3ee928..b9fe61eb7d 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js @@ -3,6 +3,7 @@ import cloneDeep from 'lodash/cloneDeep'; import { IconTrash, IconAlertCircle } from '@tabler/icons'; import { useTheme } from 'providers/Theme'; import { useDispatch } from 'react-redux'; +import { selectEnvironment } from 'providers/ReduxStore/slices/collections/actions'; import SingleLineEditor from 'components/SingleLineEditor'; import StyledWrapper from './StyledWrapper'; import { uuid } from 'utils/common'; @@ -84,6 +85,18 @@ const EnvironmentVariables = ({ environment, collection, setIsModified, original formik.setFieldValue(formik.values.length, newVariable, false); }; + const onActivate = () => { + dispatch(selectEnvironment(environment ? environment.uid : null, collection.uid)) + .then(() => { + if (environment) { + toast.success(`Environment changed to ${environment.name}`); + } else { + toast.success(`No Environments are active now`); + } + }) + .catch((err) => console.log(err) && toast.error('An error occurred while selecting the environment')); + }; + const handleRemoveVar = (id) => { formik.setValues(formik.values.filter((variable) => variable.uid !== id)); }; @@ -184,12 +197,19 @@ const EnvironmentVariables = ({ environment, collection, setIsModified, original
- + + + + + +
); From 3c8cb702f51a229fcef700dbc99c748610c01061 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Fri, 17 Jan 2025 02:46:06 +0530 Subject: [PATCH 16/22] feat: added icons to env modal buttons --- .../EnvironmentVariables/index.js | 28 +++++++++---------- .../EnvironmentDetails/index.js | 4 +-- .../EnvironmentList/index.js | 3 +- .../Environments/EnvironmentSettings/index.js | 1 + 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js index b9fe61eb7d..ab2ea7691b 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/index.js @@ -1,6 +1,6 @@ import React, { useRef, useEffect } from 'react'; import cloneDeep from 'lodash/cloneDeep'; -import { IconTrash, IconAlertCircle } from '@tabler/icons'; +import { IconTrash, IconAlertCircle, IconDeviceFloppy, IconRefresh, IconCircleCheck } from '@tabler/icons'; import { useTheme } from 'providers/Theme'; import { useDispatch } from 'react-redux'; import { selectEnvironment } from 'providers/ReduxStore/slices/collections/actions'; @@ -14,7 +14,7 @@ import { saveEnvironment } from 'providers/ReduxStore/slices/collections/actions import toast from 'react-hot-toast'; import { Tooltip } from 'react-tooltip'; -const EnvironmentVariables = ({ environment, collection, setIsModified, originalEnvironmentVariables }) => { +const EnvironmentVariables = ({ environment, collection, setIsModified, originalEnvironmentVariables, onClose }) => { const dispatch = useDispatch(); const { storedTheme } = useTheme(); const addButtonRef = useRef(null); @@ -90,6 +90,7 @@ const EnvironmentVariables = ({ environment, collection, setIsModified, original .then(() => { if (environment) { toast.success(`Environment changed to ${environment.name}`); + onClose(); } else { toast.success(`No Environments are active now`); } @@ -196,20 +197,19 @@ const EnvironmentVariables = ({ environment, collection, setIsModified, original
-
- - - - + - - - +
); diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js index f9fca74ec8..17c0bbcf09 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/index.js @@ -5,7 +5,7 @@ import DeleteEnvironment from '../../DeleteEnvironment'; import RenameEnvironment from '../../RenameEnvironment'; import EnvironmentVariables from './EnvironmentVariables'; -const EnvironmentDetails = ({ environment, collection, setIsModified }) => { +const EnvironmentDetails = ({ environment, collection, setIsModified, onClose }) => { const [openEditModal, setOpenEditModal] = useState(false); const [openDeleteModal, setOpenDeleteModal] = useState(false); const [openCopyModal, setOpenCopyModal] = useState(false); @@ -38,7 +38,7 @@ const EnvironmentDetails = ({ environment, collection, setIsModified }) => {
- +
); diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js index 48f341f26f..278a7f25d3 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/index.js @@ -11,7 +11,7 @@ import ConfirmSwitchEnv from './ConfirmSwitchEnv'; import ToolHint from 'components/ToolHint'; import { isEqual } from 'lodash'; -const EnvironmentList = ({ selectedEnvironment, setSelectedEnvironment, collection, isModified, setIsModified }) => { +const EnvironmentList = ({ selectedEnvironment, setSelectedEnvironment, collection, isModified, setIsModified, onClose }) => { const { environments } = collection; const [openCreateModal, setOpenCreateModal] = useState(false); const [openImportModal, setOpenImportModal] = useState(false); @@ -141,6 +141,7 @@ const EnvironmentList = ({ selectedEnvironment, setSelectedEnvironment, collecti collection={collection} setIsModified={setIsModified} originalEnvironmentVariables={originalEnvironmentVariables} + onClose={onClose} />
diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/index.js index 3a17e2ecd0..81c663caf9 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/index.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/index.js @@ -72,6 +72,7 @@ const EnvironmentSettings = ({ collection, onClose }) => { collection={collection} isModified={isModified} setIsModified={setIsModified} + onClose={onClose} /> ); From dab4bb6a1cb54045bd678d02d8e9b8a20eabbf4d Mon Sep 17 00:00:00 2001 From: naman-bruno Date: Fri, 17 Jan 2025 13:07:39 +0530 Subject: [PATCH 17/22] fix: hide env dropdown on configure (#3826) --- .../src/components/Environments/EnvironmentSelector/index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js b/packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js index c2dfb3bdf2..848048c134 100644 --- a/packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js +++ b/packages/bruno-app/src/components/Environments/EnvironmentSelector/index.js @@ -78,7 +78,10 @@ const EnvironmentSelector = ({ collection }) => { No Environment -
+
{ + handleSettingsIconClick(); + dropdownTippyRef.current.hide(); + }}>
From 3e6204e49bb40a77a91c62ad716483c4eef28080 Mon Sep 17 00:00:00 2001 From: naman-bruno Date: Fri, 17 Jan 2025 13:10:16 +0530 Subject: [PATCH 18/22] Fix: Horizontal Rules missing in markdown docs preview (#3814) --- packages/bruno-app/src/components/MarkDown/StyledWrapper.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/bruno-app/src/components/MarkDown/StyledWrapper.js b/packages/bruno-app/src/components/MarkDown/StyledWrapper.js index 85be8f137e..fa1269e146 100644 --- a/packages/bruno-app/src/components/MarkDown/StyledWrapper.js +++ b/packages/bruno-app/src/components/MarkDown/StyledWrapper.js @@ -55,7 +55,7 @@ const StyledMarkdownBodyWrapper = styled.div` height: 1px; padding: 0; margin: 24px 0; - background-color: var(--color-border-default); + background-color: var(--color-sidebar-collection-item-active-indent-border); border: 0; } From 8a71dfc02296e61c461f456ca45cbb9924a2b748 Mon Sep 17 00:00:00 2001 From: naman-bruno Date: Fri, 17 Jan 2025 13:20:53 +0530 Subject: [PATCH 19/22] enhancement: moved collection click area from name to div (#3813) --- .../src/components/Sidebar/Collections/Collection/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js index 61dd8b6ed7..3b814a7e5e 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js @@ -152,6 +152,8 @@ const Collection = ({ collection, searchText }) => {
{ style={{ width: 16, minWidth: 16, color: 'rgb(160 160 160)' }} onClick={handleClick} /> - From 31b28188219f1356bc65ab1785b164a9720df183 Mon Sep 17 00:00:00 2001 From: sanish chirayath Date: Fri, 17 Jan 2025 14:52:06 +0530 Subject: [PATCH 20/22] fix: modal - provide default handleConfirm function and update dependencies in useEffect (#3830) --- packages/bruno-app/src/components/Modal/index.js | 6 +++--- .../src/components/Sidebar/ImportCollection/index.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/bruno-app/src/components/Modal/index.js b/packages/bruno-app/src/components/Modal/index.js index 3ee08cbb90..0b44b928bd 100644 --- a/packages/bruno-app/src/components/Modal/index.js +++ b/packages/bruno-app/src/components/Modal/index.js @@ -62,7 +62,7 @@ const Modal = ({ confirmText, cancelText, handleCancel, - handleConfirm, + handleConfirm = () => {}, children, confirmDisabled, hideCancel, @@ -92,7 +92,7 @@ const Modal = ({ }; useFocusTrap(modalRef); - + const closeModal = (args) => { setIsClosing(true); setTimeout(() => handleCancel(args), closeModalFadeTimeout); @@ -103,7 +103,7 @@ const Modal = ({ return () => { document.removeEventListener('keydown', handleKeydown); }; - }, [disableEscapeKey, document]); + }, [disableEscapeKey, document, handleConfirm]); let classes = 'bruno-modal'; if (isClosing) { diff --git a/packages/bruno-app/src/components/Sidebar/ImportCollection/index.js b/packages/bruno-app/src/components/Sidebar/ImportCollection/index.js index 6c40317292..47f0f553e1 100644 --- a/packages/bruno-app/src/components/Sidebar/ImportCollection/index.js +++ b/packages/bruno-app/src/components/Sidebar/ImportCollection/index.js @@ -68,7 +68,7 @@ const ImportCollection = ({ onClose, handleSubmit }) => { ); }; return ( - +

Select the type of your existing collection :

From d03de2b62217bc439c38ba8f496a0e9e7a4d66c9 Mon Sep 17 00:00:00 2001 From: Bobby Bonestell Date: Fri, 17 Jan 2025 08:03:53 -0700 Subject: [PATCH 21/22] fix: Inherited apikey auth mapping for bruno-cli (#3512) * Added bruno-cli support for mapping inherited apikey auth from collection Co-authored-by: Anoop M D --- .../bruno-cli/src/runner/prepare-request.js | 22 ++- .../tests/runner/prepare-request.spec.js | 143 +++++++++++++++++- 2 files changed, 161 insertions(+), 4 deletions(-) diff --git a/packages/bruno-cli/src/runner/prepare-request.js b/packages/bruno-cli/src/runner/prepare-request.js index f031ff0aa9..11963bd296 100644 --- a/packages/bruno-cli/src/runner/prepare-request.js +++ b/packages/bruno-cli/src/runner/prepare-request.js @@ -36,7 +36,7 @@ const prepareRequest = (item = {}, collection = {}) => { }; const collectionAuth = get(collection, 'root.request.auth'); - if (collectionAuth && request.auth.mode === 'inherit') { + if (collectionAuth && request.auth?.mode === 'inherit') { if (collectionAuth.mode === 'basic') { axiosRequest.auth = { username: get(collectionAuth, 'basic.username'), @@ -47,9 +47,27 @@ const prepareRequest = (item = {}, collection = {}) => { if (collectionAuth.mode === 'bearer') { axiosRequest.headers['Authorization'] = `Bearer ${get(collectionAuth, 'bearer.token')}`; } + + if (collectionAuth.mode === 'apikey') { + if (collectionAuth.apikey?.placement === 'header') { + axiosRequest.headers[collectionAuth.apikey?.key] = collectionAuth.apikey?.value; + } + + if (collectionAuth.apikey?.placement === 'queryparams') { + if (axiosRequest.url && collectionAuth.apikey?.key) { + try { + const urlObj = new URL(request.url); + urlObj.searchParams.set(collectionAuth.apikey?.key, collectionAuth.apikey?.value); + axiosRequest.url = urlObj.toString(); + } catch (error) { + console.error('Invalid URL:', request.url, error); + } + } + } + } } - if (request.auth) { + if (request.auth && request.auth.mode !== 'inherit') { if (request.auth.mode === 'basic') { axiosRequest.auth = { username: get(request, 'auth.basic.username'), diff --git a/packages/bruno-cli/tests/runner/prepare-request.spec.js b/packages/bruno-cli/tests/runner/prepare-request.spec.js index 37d3e34d30..ffc9986dfd 100644 --- a/packages/bruno-cli/tests/runner/prepare-request.spec.js +++ b/packages/bruno-cli/tests/runner/prepare-request.spec.js @@ -1,5 +1,4 @@ -const { describe, it, expect } = require('@jest/globals'); - +const { describe, it, expect, beforeEach } = require('@jest/globals'); const prepareRequest = require('../../src/runner/prepare-request'); describe('prepare-request: prepareRequest', () => { @@ -22,4 +21,144 @@ describe('prepare-request: prepareRequest', () => { expect(result.data).toEqual(expected); }); }); + + describe('Properly maps inherited auth from collectionRoot', () => { + // Initialize Test Fixtures + let collection, item; + + beforeEach(() => { + collection = { + name: 'Test Collection', + root: { + request: { + auth: {} + } + } + }; + + item = { + name: 'Test Request', + type: 'http-request', + request: { + method: 'GET', + headers: [], + params: [], + url: 'https://usebruno.com', + auth: { + mode: 'inherit' + }, + script: { + req: 'console.log("Pre Request")', + res: 'console.log("Post Response")' + } + } + }; + }); + + describe('API Key Authentication', () => { + it('If collection auth is apikey in header', () => { + collection.root.request.auth = { + mode: "apikey", + apikey: { + key: "x-api-key", + value: "{{apiKey}}", + placement: "header" + } + }; + + const result = prepareRequest(item, collection); + expect(result.headers).toHaveProperty('x-api-key', '{{apiKey}}'); + }); + + it('If collection auth is apikey in header and request has existing headers', () => { + collection.root.request.auth = { + mode: "apikey", + apikey: { + key: "x-api-key", + value: "{{apiKey}}", + placement: "header" + } + }; + + item.request.headers.push({ name: 'Content-Type', value: 'application/json', enabled: true }); + const result = prepareRequest(item, collection); + expect(result.headers).toHaveProperty('Content-Type', 'application/json'); + expect(result.headers).toHaveProperty('x-api-key', '{{apiKey}}'); + }); + + it('If collection auth is apikey in query parameters', () => { + collection.root.request.auth = { + mode: "apikey", + apikey: { + key: "x-api-key", + value: "{{apiKey}}", + placement: "queryparams" + } + }; + + const urlObj = new URL(item.request.url); + urlObj.searchParams.set(collection.root.request.auth.apikey.key, collection.root.request.auth.apikey.value); + + const expected = urlObj.toString(); + const result = prepareRequest(item, collection); + expect(result.url).toEqual(expected); + }); + }); + + describe('Basic Authentication', () => { + it('If collection auth is basic auth', () => { + collection.root.request.auth = { + mode: 'basic', + basic: { + username: 'testUser', + password: 'testPass123' + } + }; + + const result = prepareRequest(item, collection); + const expected = { username: 'testUser', password: 'testPass123' }; + expect(result.auth).toEqual(expected); + }); + }); + + describe('Bearer Token Authentication', () => { + it('If collection auth is bearer token', () => { + collection.root.request.auth = { + mode: 'bearer', + bearer: { + token: 'token' + } + }; + + const result = prepareRequest(item, collection); + expect(result.headers).toHaveProperty('Authorization', 'Bearer token'); + }); + + it('If collection auth is bearer token and request has existing headers', () => { + collection.root.request.auth = { + mode: 'bearer', + bearer: { + token: 'token' + } + }; + + item.request.headers.push({ name: 'Content-Type', value: 'application/json', enabled: true }); + + const result = prepareRequest(item, collection); + expect(result.headers).toHaveProperty('Authorization', 'Bearer token'); + expect(result.headers).toHaveProperty('Content-Type', 'application/json'); + }); + }); + + describe('No Authentication', () => { + it('If request does not have auth configured', () => { + delete item.request.auth; + let result; + expect(() => { + result = prepareRequest(item, collection); + }).not.toThrow(); + expect(result).toBeDefined(); + }); + }); + }); }); From fee631d4963de10a654ccba26385f9bbfebd9c28 Mon Sep 17 00:00:00 2001 From: tlaloc911 <29415755+tlaloc911@users.noreply.github.com> Date: Sat, 18 Jan 2025 10:04:19 -0600 Subject: [PATCH 22/22] passing defaults instead of axiosInstance to NTLMClient (#3841) --- packages/bruno-cli/src/runner/run-single-request.js | 2 +- packages/bruno-electron/src/ipc/network/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/bruno-cli/src/runner/run-single-request.js b/packages/bruno-cli/src/runner/run-single-request.js index 67bda80216..b2bbc3795d 100644 --- a/packages/bruno-cli/src/runner/run-single-request.js +++ b/packages/bruno-cli/src/runner/run-single-request.js @@ -255,7 +255,7 @@ const runSingleRequest = async function ( let axiosInstance = makeAxiosInstance(); if (request.ntlmConfig) { - axiosInstance=NtlmClient(request.ntlmConfig,axiosInstance) + axiosInstance=NtlmClient(request.ntlmConfig,axiosInstance.defaults) delete request.ntlmConfig; } diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index 1865426e0e..218fadf380 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -278,7 +278,7 @@ const configureRequest = async ( let axiosInstance = makeAxiosInstance(); if (request.ntlmConfig) { - axiosInstance=NtlmClient(request.ntlmConfig,axiosInstance) + axiosInstance=NtlmClient(request.ntlmConfig,axiosInstance.defaults) delete request.ntlmConfig; }