From 6f6dedbb9cee594b7d7b11954b1a54ca0a5ef1d1 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Wed, 1 Feb 2023 17:56:13 +0530 Subject: [PATCH] feat: collection variables --- .../RequestPane/QueryEditor/index.js | 8 ++--- .../src/components/SingleLineEditor/index.js | 8 ++--- .../ReduxStore/slices/collections/actions.js | 6 ++-- .../ReduxStore/slices/collections/index.js | 5 ++- .../bruno-app/src/utils/collections/index.js | 9 ++++++ packages/bruno-app/src/utils/network/index.js | 8 ++--- .../bruno-electron/src/ipc/network/index.js | 31 ++++++++++++++----- .../src/ipc/network/interpolate-vars.js | 10 ++++-- packages/bruno-js/src/scripts/bru.js | 15 ++++++++- .../bruno-js/src/scripts/script-runtime.js | 14 +++++---- packages/bruno-js/src/scripts/test-runtime.js | 5 +-- .../bruno-schema/src/collections/index.js | 3 +- 12 files changed, 86 insertions(+), 36 deletions(-) diff --git a/packages/bruno-app/src/components/RequestPane/QueryEditor/index.js b/packages/bruno-app/src/components/RequestPane/QueryEditor/index.js index 667c61e86..d29df14e3 100644 --- a/packages/bruno-app/src/components/RequestPane/QueryEditor/index.js +++ b/packages/bruno-app/src/components/RequestPane/QueryEditor/index.js @@ -8,7 +8,7 @@ import React from 'react'; import isEqual from 'lodash/isEqual'; import MD from 'markdown-it'; -import { getEnvironmentVariables } from 'utils/collections'; +import { getAllVariables } from 'utils/collections'; import { defineCodeMirrorBrunoVariablesMode } from 'utils/common/codemirror'; import StyledWrapper from './StyledWrapper'; @@ -43,7 +43,7 @@ export default class QueryEditor extends React.Component { mode: 'graphql', // mode: 'brunovariables', brunoVarInfo: { - variables: getEnvironmentVariables(this.props.collection), + variables: getAllVariables(this.props.collection), }, theme: this.props.editorTheme || 'graphiql', theme: this.props.theme === 'dark' ? 'monokai' : 'default', @@ -160,7 +160,7 @@ export default class QueryEditor extends React.Component { if (this.props.theme !== prevProps.theme && this.editor) { this.editor.setOption('theme', this.props.theme === 'dark' ? 'monokai' : 'default'); } - let variables = getEnvironmentVariables(this.props.collection); + let variables = getAllVariables(this.props.collection); if (!isEqual(variables, this.variables)) { this.editor.options.brunoVarInfo.variables = variables; this.addOverlay(); @@ -180,7 +180,7 @@ export default class QueryEditor extends React.Component { // Todo: Overlay is messing up with schema hint // Fix this addOverlay = () => { - // let variables = getEnvironmentVariables(this.props.collection); + // let variables = getAllVariables(this.props.collection); // this.variables = variables; // defineCodeMirrorBrunoVariablesMode(variables, 'graphql'); diff --git a/packages/bruno-app/src/components/SingleLineEditor/index.js b/packages/bruno-app/src/components/SingleLineEditor/index.js index 4c7b6c748..ad60a1687 100644 --- a/packages/bruno-app/src/components/SingleLineEditor/index.js +++ b/packages/bruno-app/src/components/SingleLineEditor/index.js @@ -1,6 +1,6 @@ import React, { Component } from 'react'; import isEqual from 'lodash/isEqual'; -import { getEnvironmentVariables } from 'utils/collections'; +import { getAllVariables } from 'utils/collections'; import { defineCodeMirrorBrunoVariablesMode } from 'utils/common/codemirror'; import StyledWrapper from './StyledWrapper'; @@ -29,7 +29,7 @@ class SingleLineEditor extends Component { theme: this.props.theme === 'dark' ? 'monokai' : 'default', mode: "brunovariables", brunoVarInfo: { - variables: getEnvironmentVariables(this.props.collection), + variables: getAllVariables(this.props.collection), }, extraKeys: { "Enter": () => { @@ -92,7 +92,7 @@ class SingleLineEditor extends Component { // event loop. this.ignoreChangeEvent = true; - let variables = getEnvironmentVariables(this.props.collection); + let variables = getAllVariables(this.props.collection); if (!isEqual(variables, this.variables)) { this.editor.options.brunoVarInfo.variables = variables; this.addOverlay(); @@ -112,7 +112,7 @@ class SingleLineEditor extends Component { } addOverlay = () => { - let variables = getEnvironmentVariables(this.props.collection); + let variables = getAllVariables(this.props.collection); this.variables = variables; defineCodeMirrorBrunoVariablesMode(variables, "text/plain"); 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 126f15c79..594153754 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/actions.js @@ -20,7 +20,6 @@ import { } from 'utils/collections'; import { collectionSchema, itemSchema, environmentSchema, environmentsSchema } from '@usebruno/schema'; import { waitForNextTick } from 'utils/common'; -import { saveCollectionToIdb } from 'utils/idb'; import { sendNetworkRequest, cancelNetworkRequest } from 'utils/network'; import { @@ -100,7 +99,7 @@ export const sendRequest = (item, collectionUid) => (dispatch, getState) => { const environment = findEnvironmentInCollection(collectionCopy, collection.activeEnvironmentUid); - sendNetworkRequest(itemCopy, collection, environment) + sendNetworkRequest(itemCopy, collection, environment, collectionCopy.collectionVariables) .then((response) => { return dispatch( responseReceived({ @@ -716,7 +715,8 @@ export const openCollectionEvent = (uid, pathname, name) => (dispatch, getState) name: name, pathname: pathname, items: [], - showRunner: false + showRunner: false, + collectionVariables: {} }; return new Promise((resolve, reject) => { 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 d5097c864..55542ac95 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js @@ -176,7 +176,7 @@ export const collectionsSlice = createSlice({ } }, scriptEnvironmentUpdateEvent: (state, action) => { - const { collectionUid, environment } = action.payload; + const { collectionUid, environment, collectionVariables } = action.payload; const collection = findCollectionByUid(state.collections, collectionUid); if (collection) { @@ -192,6 +192,9 @@ export const collectionsSlice = createSlice({ } }); } + + collection.collectionVariables = collectionVariables; + } }, requestCancelled: (state, action) => { diff --git a/packages/bruno-app/src/utils/collections/index.js b/packages/bruno-app/src/utils/collections/index.js index 3b42dd59a..5b2e23570 100644 --- a/packages/bruno-app/src/utils/collections/index.js +++ b/packages/bruno-app/src/utils/collections/index.js @@ -517,3 +517,12 @@ export const getEnvironmentVariables = (collection) => { return variables; } + +export const getAllVariables = (collection) => { + const environmentVariables = getEnvironmentVariables(collection); + + return { + ...environmentVariables, + ...collection.collectionVariables + }; +} diff --git a/packages/bruno-app/src/utils/network/index.js b/packages/bruno-app/src/utils/network/index.js index df470b0b6..6bc55a24a 100644 --- a/packages/bruno-app/src/utils/network/index.js +++ b/packages/bruno-app/src/utils/network/index.js @@ -1,8 +1,8 @@ -export const sendNetworkRequest = async (item, collection, environment) => { +export const sendNetworkRequest = async (item, collection, environment, collectionVariables) => { return new Promise((resolve, reject) => { if (['http-request', 'graphql-request'].includes(item.type)) { const timeStart = Date.now(); - sendHttpRequest(item, collection, environment) + sendHttpRequest(item, collection, environment, collectionVariables) .then((response) => { const timeEnd = Date.now(); resolve({ @@ -20,12 +20,12 @@ export const sendNetworkRequest = async (item, collection, environment) => { }); }; -const sendHttpRequest = async (item, collection, environment) => { +const sendHttpRequest = async (item, collection, environment, collectionVariables) => { return new Promise((resolve, reject) => { const { ipcRenderer } = window; ipcRenderer - .invoke('send-http-request', item, collection.uid, collection.pathname, environment) + .invoke('send-http-request', item, collection.uid, collection.pathname, environment, collectionVariables) .then(resolve) .catch(reject); }); diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index 09418c437..92700ab2b 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -69,7 +69,7 @@ const getSize = (data) => { const registerNetworkIpc = (mainWindow, watcher, lastOpenedCollections) => { // handler for sending http request - ipcMain.handle('send-http-request', async (event, item, collectionUid, collectionPath, environment) => { + ipcMain.handle('send-http-request', async (event, item, collectionUid, collectionPath, environment, collectionVariables) => { const cancelTokenUid = uuid(); try { @@ -102,15 +102,16 @@ const registerNetworkIpc = (mainWindow, watcher, lastOpenedCollections) => { if(request.script && request.script.length) { let script = request.script + '\n if (typeof onRequest === "function") {onRequest(__brunoRequest);}'; const scriptRuntime = new ScriptRuntime(); - const result = scriptRuntime.runRequestScript(script, request, envVars, collectionPath); + const result = scriptRuntime.runRequestScript(script, request, envVars, collectionVariables, collectionPath); mainWindow.webContents.send('main:script-environment-update', { environment: result.environment, + collectionVariables: result.collectionVariables, collectionUid }); } - interpolateVars(request, envVars); + interpolateVars(request, envVars, collectionVariables); // todo: // i have no clue why electron can't send the request object @@ -132,10 +133,11 @@ const registerNetworkIpc = (mainWindow, watcher, lastOpenedCollections) => { if(request.script && request.script.length) { let script = request.script + '\n if (typeof onResponse === "function") {onResponse(__brunoResponse);}'; const scriptRuntime = new ScriptRuntime(); - const result = scriptRuntime.runResponseScript(script, response, envVars, collectionPath); + const result = scriptRuntime.runResponseScript(script, response, envVars, collectionVariables, collectionPath); mainWindow.webContents.send('main:script-environment-update', { environment: result.environment, + collectionVariables: result.collectionVariables, collectionUid }); } @@ -143,7 +145,7 @@ const registerNetworkIpc = (mainWindow, watcher, lastOpenedCollections) => { const testFile = get(item, 'request.tests'); if(testFile && testFile.length) { const testRuntime = new TestRuntime(); - const result = testRuntime.runTests(testFile, request, response, envVars, collectionPath); + const result = testRuntime.runTests(testFile, request, response, envVars, collectionVariables, collectionPath); mainWindow.webContents.send('main:test-results', { results: result.results, @@ -275,7 +277,19 @@ const registerNetworkIpc = (mainWindow, watcher, lastOpenedCollections) => { request.data = form; } - interpolateVars(request, envVars); + if(request.script && request.script.length) { + let script = request.script + '\n if (typeof onRequest === "function") {onRequest(__brunoRequest);}'; + const scriptRuntime = new ScriptRuntime(); + const result = scriptRuntime.runRequestScript(script, request, envVars, collectionVariables, collectionPath); + + mainWindow.webContents.send('main:script-environment-update', { + environment: result.environment, + collectionVariables: result.collectionVariables, + collectionUid + }); + } + + interpolateVars(request, envVars, collectionVariables); // todo: // i have no clue why electron can't send the request object @@ -298,10 +312,11 @@ const registerNetworkIpc = (mainWindow, watcher, lastOpenedCollections) => { if(request.script && request.script.length) { let script = request.script + '\n if (typeof onResponse === "function") {onResponse(__brunoResponse);}'; const scriptRuntime = new ScriptRuntime(); - const result = scriptRuntime.runResponseScript(script, response, envVars, collectionPath); + const result = scriptRuntime.runResponseScript(script, response, envVars, collectionVariables, collectionPath); mainWindow.webContents.send('main:script-environment-update', { environment: result.environment, + collectionVariables: result.collectionVariables, collectionUid }); } @@ -309,7 +324,7 @@ const registerNetworkIpc = (mainWindow, watcher, lastOpenedCollections) => { const testFile = get(item, 'request.tests'); if(testFile && testFile.length) { const testRuntime = new TestRuntime(); - const result = testRuntime.runTests(testFile, request, response, envVars, collectionPath); + const result = testRuntime.runTests(testFile, request, response, envVars, collectionVariables, collectionPath); mainWindow.webContents.send('main:run-folder-event', { type: 'test-results', diff --git a/packages/bruno-electron/src/ipc/network/interpolate-vars.js b/packages/bruno-electron/src/ipc/network/interpolate-vars.js index a0db91205..f6f496a47 100644 --- a/packages/bruno-electron/src/ipc/network/interpolate-vars.js +++ b/packages/bruno-electron/src/ipc/network/interpolate-vars.js @@ -6,13 +6,19 @@ Mustache.escape = function (value) { return value; }; -const interpolateVars = (request, envVars = {}) => { +const interpolateVars = (request, envVars = {}, collectionVariables ={}) => { const interpolate = (str) => { if(!str || !str.length || typeof str !== "string") { return str; } - return Mustache.render(str, envVars); + // collectionVariables take precedence over envVars + const combinedVars = { + ...envVars, + ...collectionVariables + }; + + return Mustache.render(str, combinedVars); }; request.url = interpolate(request.url); diff --git a/packages/bruno-js/src/scripts/bru.js b/packages/bruno-js/src/scripts/bru.js index d999f2f7b..c15a40db1 100644 --- a/packages/bruno-js/src/scripts/bru.js +++ b/packages/bruno-js/src/scripts/bru.js @@ -9,8 +9,9 @@ const nanoid = require('nanoid'); const CryptoJS = require('crypto-js'); class Bru { - constructor(environment) { + constructor(environment, collectionVariables) { this._environment = environment; + this._collectionVariables = collectionVariables; } require(module) { @@ -50,6 +51,18 @@ class Bru { this._environment[key] = value; } + + setVar(key, value) { + if(!key) { + throw new Error('Key is required'); + } + + this._collectionVariables[key] = value; + } + + getVar(key) { + return this._collectionVariables[key]; + } } module.exports = Bru; \ No newline at end of file diff --git a/packages/bruno-js/src/scripts/script-runtime.js b/packages/bruno-js/src/scripts/script-runtime.js index 904e2393d..9376b34e9 100644 --- a/packages/bruno-js/src/scripts/script-runtime.js +++ b/packages/bruno-js/src/scripts/script-runtime.js @@ -8,8 +8,8 @@ class ScriptRuntime { constructor() { } - runRequestScript(script, request, environment, collectionPath) { - const bru = new Bru(environment); + runRequestScript(script, request, environment, collectionVariables, collectionPath) { + const bru = new Bru(environment, collectionVariables); const __brunoRequest = new BrunoRequest(request); const context = { @@ -29,12 +29,13 @@ class ScriptRuntime { return { request, - environment + environment, + collectionVariables }; } - runResponseScript(script, response, environment, collectionPath) { - const bru = new Bru(environment); + runResponseScript(script, response, environment, collectionVariables, collectionPath) { + const bru = new Bru(environment, collectionVariables); const __brunoResponse = new BrunoResponse(response); const context = { @@ -54,7 +55,8 @@ class ScriptRuntime { return { response, - environment + environment, + collectionVariables }; } } diff --git a/packages/bruno-js/src/scripts/test-runtime.js b/packages/bruno-js/src/scripts/test-runtime.js index 59c45331b..db1560d2d 100644 --- a/packages/bruno-js/src/scripts/test-runtime.js +++ b/packages/bruno-js/src/scripts/test-runtime.js @@ -11,8 +11,8 @@ class TestRuntime { constructor() { } - runTests(testsFile, request, response, environment, collectionPath) { - const bru = new Bru(environment); + runTests(testsFile, request, response, environment, collectionVariables, collectionPath) { + const bru = new Bru(environment, collectionVariables); const req = new BrunoRequest(request); const res = new BrunoResponse(response); @@ -45,6 +45,7 @@ class TestRuntime { request, response, environment, + collectionVariables, results: __brunoTestResults.getResults() }; } diff --git a/packages/bruno-schema/src/collections/index.js b/packages/bruno-schema/src/collections/index.js index 5563d2783..2659a188f 100644 --- a/packages/bruno-schema/src/collections/index.js +++ b/packages/bruno-schema/src/collections/index.js @@ -89,7 +89,8 @@ const collectionSchema = Yup.object({ showRunner: Yup.boolean(), runnerResult: Yup.object({ items: Yup.array() - }) + }), + collectionVariables: Yup.object() }).noUnknown(true).strict();