diff --git a/packages/bruno-app/src/components/RequestTabPanel/index.js b/packages/bruno-app/src/components/RequestTabPanel/index.js index 51d3194be..346a64aff 100644 --- a/packages/bruno-app/src/components/RequestTabPanel/index.js +++ b/packages/bruno-app/src/components/RequestTabPanel/index.js @@ -20,6 +20,8 @@ import { DocExplorer } from '@usebruno/graphql-docs'; import StyledWrapper from './StyledWrapper'; import SecuritySettings from 'components/SecuritySettings'; import FolderSettings from 'components/FolderSettings'; +import { getGlobalEnvironmentVariables } from 'utils/collections/index'; +import { cloneDeep } from 'lodash'; const MIN_LEFT_PANE_WIDTH = 300; const MIN_RIGHT_PANE_WIDTH = 350; @@ -34,6 +36,7 @@ const RequestTabPanel = () => { const activeTabUid = useSelector((state) => state.tabs.activeTabUid); const collections = useSelector((state) => state.collections.collections); const screenWidth = useSelector((state) => state.app.screenWidth); + const { globalEnvironments, activeGlobalEnvironmentUid } = useSelector((state) => state.globalEnvironments); let asideWidth = useSelector((state) => state.app.leftSidebarWidth); const focusedTab = find(tabs, (t) => t.uid === activeTabUid); @@ -117,7 +120,14 @@ const RequestTabPanel = () => { return
An error occurred!
; } - let collection = find(collections, (c) => c.uid === focusedTab.collectionUid); + let _collection = find(collections, (c) => c.uid === focusedTab.collectionUid); + let collection = cloneDeep(_collection); + + // add selected global env variables to the collection object + const globalEnvironmentVariables = getGlobalEnvironmentVariables({ globalEnvironments, activeGlobalEnvironmentUid }); + collection.globalEnvironmentVariables = globalEnvironmentVariables; + + if (!collection || !collection.uid) { return
Collection not found!
; } diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/GenerateCodeItem/CodeView/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/GenerateCodeItem/CodeView/index.js index 9d5648907..28f68a5a7 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/GenerateCodeItem/CodeView/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/GenerateCodeItem/CodeView/index.js @@ -8,19 +8,24 @@ import { useSelector } from 'react-redux'; import { CopyToClipboard } from 'react-copy-to-clipboard'; import toast from 'react-hot-toast'; import { IconCopy } from '@tabler/icons'; -import { findCollectionByItemUid } from '../../../../../../../utils/collections/index'; +import { findCollectionByItemUid, getGlobalEnvironmentVariables } from '../../../../../../../utils/collections/index'; import { getAuthHeaders } from '../../../../../../../utils/codegenerator/auth'; const CodeView = ({ language, item }) => { const { displayedTheme } = useTheme(); const preferences = useSelector((state) => state.app.preferences); + const { globalEnvironments, activeGlobalEnvironmentUid } = useSelector((state) => state.globalEnvironments); const { target, client, language: lang } = language; const requestHeaders = item.draft ? get(item, 'draft.request.headers') : get(item, 'request.headers'); - const collection = findCollectionByItemUid( + let collection = findCollectionByItemUid( useSelector((state) => state.collections.collections), item.uid ); + // add selected global env variables to the collection object + const globalEnvironmentVariables = getGlobalEnvironmentVariables({ globalEnvironments, activeGlobalEnvironmentUid }); + collection.globalEnvironmentVariables = globalEnvironmentVariables; + const collectionRootAuth = collection?.root?.request?.auth; const requestAuth = item.draft ? get(item, 'draft.request.auth') : get(item, 'request.auth'); diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js index 777a194ab..4e83b89df 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js @@ -44,6 +44,7 @@ import { parsePathParams, parseQueryParams, splitOnFirst } from 'utils/url/index import { sendCollectionOauth2Request as _sendCollectionOauth2Request } from 'utils/network/index'; import { name } from 'file-loader'; import slash from 'utils/common/slash'; +import { getGlobalEnvironmentVariables } from 'utils/collections/index'; export const renameCollection = (newName, collectionUid) => (dispatch, getState) => { const state = getState(); @@ -183,6 +184,7 @@ export const saveFolderRoot = (collectionUid, folderUid) => (dispatch, getState) export const sendCollectionOauth2Request = (collectionUid, itemUid) => (dispatch, getState) => { const state = getState(); + const { globalEnvironments, activeGlobalEnvironmentUid } = state.globalEnvironments; const collection = findCollectionByUid(state.collections.collections, collectionUid); return new Promise((resolve, reject) => { @@ -190,7 +192,11 @@ export const sendCollectionOauth2Request = (collectionUid, itemUid) => (dispatch return reject(new Error('Collection not found')); } - const collectionCopy = cloneDeep(collection); + let collectionCopy = cloneDeep(collection); + + // add selected global env variables to the collection object + const globalEnvironmentVariables = getGlobalEnvironmentVariables({ globalEnvironments, activeGlobalEnvironmentUid }); + collectionCopy.globalEnvironmentVariables = globalEnvironmentVariables; const environment = findEnvironmentInCollection(collectionCopy, collection.activeEnvironmentUid); @@ -212,6 +218,7 @@ export const sendCollectionOauth2Request = (collectionUid, itemUid) => (dispatch export const sendRequest = (item, collectionUid) => (dispatch, getState) => { const state = getState(); + const { globalEnvironments, activeGlobalEnvironmentUid } = state.globalEnvironments; const collection = findCollectionByUid(state.collections.collections, collectionUid); return new Promise((resolve, reject) => { @@ -220,7 +227,11 @@ export const sendRequest = (item, collectionUid) => (dispatch, getState) => { } const itemCopy = cloneDeep(item || {}); - const collectionCopy = cloneDeep(collection); + let collectionCopy = cloneDeep(collection); + + // add selected global env variables to the collection object + const globalEnvironmentVariables = getGlobalEnvironmentVariables({ globalEnvironments, activeGlobalEnvironmentUid }); + collectionCopy.globalEnvironmentVariables = globalEnvironmentVariables; const environment = findEnvironmentInCollection(collectionCopy, collectionCopy.activeEnvironmentUid); sendNetworkRequest(itemCopy, collectionCopy, environment, collectionCopy.runtimeVariables) @@ -285,6 +296,7 @@ export const cancelRunnerExecution = (cancelTokenUid) => (dispatch) => { export const runCollectionFolder = (collectionUid, folderUid, recursive, delay) => (dispatch, getState) => { const state = getState(); + const { globalEnvironments, activeGlobalEnvironmentUid } = state.globalEnvironments; const collection = findCollectionByUid(state.collections.collections, collectionUid); return new Promise((resolve, reject) => { @@ -292,7 +304,12 @@ export const runCollectionFolder = (collectionUid, folderUid, recursive, delay) return reject(new Error('Collection not found')); } - const collectionCopy = cloneDeep(collection); + let collectionCopy = cloneDeep(collection); + + // add selected global env variables to the collection object + const globalEnvironmentVariables = getGlobalEnvironmentVariables({ globalEnvironments, activeGlobalEnvironmentUid }); + collectionCopy.globalEnvironmentVariables = globalEnvironmentVariables; + const folder = findItemInCollection(collectionCopy, folderUid); if (folderUid && !folder) { diff --git a/packages/bruno-app/src/utils/collections/index.js b/packages/bruno-app/src/utils/collections/index.js index 2b2c7d13b..c39a097fb 100644 --- a/packages/bruno-app/src/utils/collections/index.js +++ b/packages/bruno-app/src/utils/collections/index.js @@ -782,6 +782,19 @@ export const getDefaultRequestPaneTab = (item) => { } }; +export const getGlobalEnvironmentVariables = ({ globalEnvironments, activeGlobalEnvironmentUid }) => { + let variables = {}; + const environment = globalEnvironments?.find(env => env?.uid === activeGlobalEnvironmentUid); + if (environment) { + each(environment.variables, (variable) => { + if (variable.name && variable.value && variable.enabled) { + variables[variable.name] = variable.value; + } + }); + } + return variables; +}; + export const getEnvironmentVariables = (collection) => { let variables = {}; if (collection) { @@ -798,6 +811,7 @@ export const getEnvironmentVariables = (collection) => { return variables; }; + const getPathParams = (item) => { let pathParams = {}; if (item && item.request && item.request.params) { @@ -829,10 +843,12 @@ export const getAllVariables = (collection, item) => { const requestTreePath = getTreePathFromCollectionToItem(collection, item); let { collectionVariables, folderVariables, requestVariables } = mergeVars(collection, requestTreePath); const pathParams = getPathParams(item); + const { globalEnvironmentVariables = {} } = collection; const { processEnvVariables = {}, runtimeVariables = {} } = collection; return { + ...globalEnvironmentVariables, ...collectionVariables, ...envVariables, ...folderVariables, diff --git a/packages/bruno-electron/src/ipc/network/interpolate-vars.js b/packages/bruno-electron/src/ipc/network/interpolate-vars.js index 5ea2bf7f4..70150130a 100644 --- a/packages/bruno-electron/src/ipc/network/interpolate-vars.js +++ b/packages/bruno-electron/src/ipc/network/interpolate-vars.js @@ -14,6 +14,7 @@ const getContentType = (headers = {}) => { }; const interpolateVars = (request, envVariables = {}, runtimeVariables = {}, processEnvVars = {}) => { + const globalEnvironmentVariables = request?.globalEnvironmentVariables || {}; const collectionVariables = request?.collectionVariables || {}; const folderVariables = request?.folderVariables || {}; const requestVariables = request?.requestVariables || {}; @@ -39,6 +40,7 @@ const interpolateVars = (request, envVariables = {}, runtimeVariables = {}, proc // runtimeVariables take precedence over envVars const combinedVars = { + ...globalEnvironmentVariables, ...collectionVariables, ...envVariables, ...folderVariables, diff --git a/packages/bruno-electron/src/ipc/network/prepare-request.js b/packages/bruno-electron/src/ipc/network/prepare-request.js index 0bac42af9..1ba52895a 100644 --- a/packages/bruno-electron/src/ipc/network/prepare-request.js +++ b/packages/bruno-electron/src/ipc/network/prepare-request.js @@ -370,6 +370,7 @@ const prepareRequest = (item, collection) => { mergeFolderLevelHeaders(request, requestTreePath); mergeFolderLevelScripts(request, requestTreePath, scriptFlow); mergeVars(collection, request, requestTreePath); + request.globalEnvironmentVariables = collection?.globalEnvironmentVariables; } // Request level headers @@ -461,6 +462,7 @@ const prepareRequest = (item, collection) => { axiosRequest.collectionVariables = request.collectionVariables; axiosRequest.folderVariables = request.folderVariables; axiosRequest.requestVariables = request.requestVariables; + axiosRequest.globalEnvironmentVariables = request.globalEnvironmentVariables; axiosRequest.assertions = request.assertions; return axiosRequest; diff --git a/packages/bruno-js/src/bru.js b/packages/bruno-js/src/bru.js index 7f24cea14..46c6231ba 100644 --- a/packages/bruno-js/src/bru.js +++ b/packages/bruno-js/src/bru.js @@ -4,13 +4,14 @@ const { interpolate } = require('@usebruno/common'); const variableNameRegex = /^[\w-.]*$/; class Bru { - constructor(envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables) { + constructor(envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables) { this.envVariables = envVariables || {}; this.runtimeVariables = runtimeVariables || {}; this.processEnvVars = cloneDeep(processEnvVars || {}); this.collectionVariables = collectionVariables || {}; this.folderVariables = folderVariables || {}; this.requestVariables = requestVariables || {}; + this.globalEnvironmentVariables = globalEnvironmentVariables || {}; this.collectionPath = collectionPath; } @@ -20,6 +21,7 @@ class Bru { } const combinedVars = { + ...this.globalEnvironmentVariables, ...this.collectionVariables, ...this.envVariables, ...this.folderVariables, @@ -63,6 +65,18 @@ class Bru { this.envVariables[key] = value; } + getGlobalEnvVar(key) { + return this._interpolate(this.globalEnvironmentVariables[key]); + } + + setGlobalEnvVar(key, value) { + if (!key) { + throw new Error('Creating a env variable without specifying a name is not allowed.'); + } + + this.globalEnvironmentVariables[key] = value; + } + hasVar(key) { return Object.hasOwn(this.runtimeVariables, key); } diff --git a/packages/bruno-js/src/interpolate-string.js b/packages/bruno-js/src/interpolate-string.js index 2692641c2..f75daf57c 100644 --- a/packages/bruno-js/src/interpolate-string.js +++ b/packages/bruno-js/src/interpolate-string.js @@ -2,13 +2,14 @@ const { interpolate } = require('@usebruno/common'); const interpolateString = ( str, - { envVariables = {}, runtimeVariables = {}, processEnvVars = {}, collectionVariables = {}, folderVariables = {}, requestVariables = {} } + { envVariables = {}, runtimeVariables = {}, processEnvVars = {}, collectionVariables = {}, folderVariables = {}, requestVariables = {}, globalEnvironmentVariables = {} } ) => { if (!str || !str.length || typeof str !== 'string') { return str; } const combinedVars = { + ...globalEnvironmentVariables, ...collectionVariables, ...envVariables, ...folderVariables, diff --git a/packages/bruno-js/src/runtime/assert-runtime.js b/packages/bruno-js/src/runtime/assert-runtime.js index aafacfe8a..b338730cc 100644 --- a/packages/bruno-js/src/runtime/assert-runtime.js +++ b/packages/bruno-js/src/runtime/assert-runtime.js @@ -192,6 +192,7 @@ const evaluateRhsOperand = (rhsOperand, operator, context, runtime) => { } const interpolationContext = { + globalEnvironmentVariables: context.bru.globalEnvironmentVariables, collectionVariables: context.bru.collectionVariables, folderVariables: context.bru.folderVariables, requestVariables: context.bru.requestVariables, @@ -240,6 +241,7 @@ class AssertRuntime { } runAssertions(assertions, request, response, envVariables, runtimeVariables, processEnvVars) { + const globalEnvironmentVariables = request?.globalEnvironmentVariables || {}; const collectionVariables = request?.collectionVariables || {}; const folderVariables = request?.folderVariables || {}; const requestVariables = request?.requestVariables || {}; @@ -255,7 +257,8 @@ class AssertRuntime { undefined, collectionVariables, folderVariables, - requestVariables + requestVariables, + globalEnvironmentVariables ); const req = new BrunoRequest(request); const res = createResponseParser(response); @@ -267,6 +270,7 @@ class AssertRuntime { }; const context = { + ...globalEnvironmentVariables, ...collectionVariables, ...envVariables, ...folderVariables, diff --git a/packages/bruno-js/src/runtime/script-runtime.js b/packages/bruno-js/src/runtime/script-runtime.js index 9dc47a29d..cdccfc4a7 100644 --- a/packages/bruno-js/src/runtime/script-runtime.js +++ b/packages/bruno-js/src/runtime/script-runtime.js @@ -47,10 +47,11 @@ class ScriptRuntime { processEnvVars, scriptingConfig ) { + const globalEnvironmentVariables = request?.globalEnvironmentVariables || {}; const collectionVariables = request?.collectionVariables || {}; const folderVariables = request?.folderVariables || {}; const requestVariables = request?.requestVariables || {}; - const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables); + const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables); const req = new BrunoRequest(request); const allowScriptFilesystemAccess = get(scriptingConfig, 'filesystemAccess.allow', false); const moduleWhitelist = get(scriptingConfig, 'moduleWhitelist', []); @@ -164,10 +165,11 @@ class ScriptRuntime { processEnvVars, scriptingConfig ) { + const globalEnvironmentVariables = request?.globalEnvironmentVariables || {}; const collectionVariables = request?.collectionVariables || {}; const folderVariables = request?.folderVariables || {}; const requestVariables = request?.requestVariables || {}; - const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables); + const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables); const req = new BrunoRequest(request); const res = new BrunoResponse(response); const allowScriptFilesystemAccess = get(scriptingConfig, 'filesystemAccess.allow', false); diff --git a/packages/bruno-js/src/runtime/test-runtime.js b/packages/bruno-js/src/runtime/test-runtime.js index 53fab05eb..8cd118df2 100644 --- a/packages/bruno-js/src/runtime/test-runtime.js +++ b/packages/bruno-js/src/runtime/test-runtime.js @@ -48,10 +48,11 @@ class TestRuntime { processEnvVars, scriptingConfig ) { + const globalEnvironmentVariables = request?.globalEnvironmentVariables || {}; const collectionVariables = request?.collectionVariables || {}; const folderVariables = request?.folderVariables || {}; const requestVariables = request?.requestVariables || {}; - const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables); + const bru = new Bru(envVariables, runtimeVariables, processEnvVars, collectionPath, collectionVariables, folderVariables, requestVariables, globalEnvironmentVariables); const req = new BrunoRequest(request); const res = new BrunoResponse(response); const allowScriptFilesystemAccess = get(scriptingConfig, 'filesystemAccess.allow', false);