diff --git a/package.json b/package.json
index 3aef7fa12..107b0d744 100644
--- a/package.json
+++ b/package.json
@@ -13,10 +13,12 @@
"packages/bruno-testbench",
"packages/bruno-graphql-docs"
],
+ "homepage": "https://usebruno.com",
"devDependencies": {
"@faker-js/faker": "^7.6.0",
"@jest/globals": "^29.2.0",
"@playwright/test": "^1.27.1",
+ "about-window": "^1.15.2",
"husky": "^8.0.3",
"jest": "^29.2.0",
"pretty-quick": "^3.1.3",
diff --git a/packages/bruno-app/package.json b/packages/bruno-app/package.json
index 810f0e6ff..f8ad53c01 100644
--- a/packages/bruno-app/package.json
+++ b/packages/bruno-app/package.json
@@ -47,6 +47,7 @@
"react-dom": "18.2.0",
"react-github-btn": "^1.4.0",
"react-hot-toast": "^2.4.0",
+ "react-inspector": "^6.0.2",
"react-redux": "^7.2.6",
"react-tooltip": "^5.5.2",
"sass": "^1.46.0",
diff --git a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js
index 22872cd46..c0762a441 100644
--- a/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js
+++ b/packages/bruno-app/src/components/Environments/EnvironmentSettings/EnvironmentList/EnvironmentDetails/EnvironmentVariables/StyledWrapper.js
@@ -5,10 +5,20 @@ const Wrapper = styled.div`
width: 100%;
border-collapse: collapse;
font-weight: 600;
+ table-layout: fixed;
thead,
td {
border: 1px solid ${(props) => props.theme.collection.environment.settings.gridBorder};
+ padding: 4px 10px;
+
+ &:nth-child(1) {
+ width: 30%;
+ }
+
+ &:nth-child(3) {
+ width: 70px;
+ }
}
thead {
@@ -16,7 +26,7 @@ const Wrapper = styled.div`
font-size: 0.8125rem;
user-select: none;
}
- td {
+ thead td {
padding: 6px 10px;
}
}
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 4f5aa4dfa..2f1d05f63 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
@@ -2,13 +2,16 @@ import React, { useReducer } from 'react';
import toast from 'react-hot-toast';
import cloneDeep from 'lodash/cloneDeep';
import { IconTrash } from '@tabler/icons';
+import { useTheme } from 'providers/Theme';
import { useDispatch } from 'react-redux';
import { saveEnvironment } from 'providers/ReduxStore/slices/collections/actions';
import reducer from './reducer';
+import SingleLineEditor from 'components/SingleLineEditor';
import StyledWrapper from './StyledWrapper';
const EnvironmentVariables = ({ environment, collection }) => {
const dispatch = useDispatch();
+ const { storedTheme } = useTheme();
const [state, reducerDispatch] = useReducer(reducer, { hasChanges: false, variables: environment.variables || [] });
const { variables, hasChanges } = state;
@@ -100,15 +103,11 @@ const EnvironmentVariables = ({ environment, collection }) => {
/>
- handleVarChange(e, variable, 'value')}
+ handleVarChange({ target: { value: newValue } }, variable, 'value')}
+ collection={collection}
/>
|
diff --git a/packages/bruno-app/src/components/Modal/StyledWrapper.js b/packages/bruno-app/src/components/Modal/StyledWrapper.js
index 583bfe2ec..f0cb79353 100644
--- a/packages/bruno-app/src/components/Modal/StyledWrapper.js
+++ b/packages/bruno-app/src/components/Modal/StyledWrapper.js
@@ -19,7 +19,7 @@ const Wrapper = styled.div`
align-items: flex-start;
justify-content: center;
overflow-y: auto;
- z-index: 1003;
+ z-index: 10;
}
.bruno-modal-card {
@@ -28,7 +28,7 @@ const Wrapper = styled.div`
background: var(--color-background-top);
border-radius: var(--border-radius);
position: relative;
- z-index: 1003;
+ z-index: 10;
max-width: calc(100% - var(--spacing-base-unit));
box-shadow: var(--box-shadow-base);
display: flex;
diff --git a/packages/bruno-app/src/components/RequestTabPanel/index.js b/packages/bruno-app/src/components/RequestTabPanel/index.js
index 371778fbf..511fb5cd4 100644
--- a/packages/bruno-app/src/components/RequestTabPanel/index.js
+++ b/packages/bruno-app/src/components/RequestTabPanel/index.js
@@ -13,6 +13,7 @@ import RequestNotFound from './RequestNotFound';
import QueryUrl from 'components/RequestPane/QueryUrl';
import NetworkError from 'components/ResponsePane/NetworkError';
import RunnerResults from 'components/RunnerResults';
+import VariablesEditor from 'components/VariablesEditor';
import { DocExplorer } from '@usebruno/graphql-docs';
import StyledWrapper from './StyledWrapper';
@@ -123,6 +124,10 @@ const RequestTabPanel = () => {
return ;
}
+ if (focusedTab.type === 'variables') {
+ return ;
+ }
+
const item = findItemInCollection(collection, activeTabUid);
if (!item || !item.uid) {
return ;
diff --git a/packages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.js b/packages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.js
index 1d96df94b..c461e3bb4 100644
--- a/packages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.js
+++ b/packages/bruno-app/src/components/RequestTabs/CollectionToolBar/index.js
@@ -1,7 +1,8 @@
import React from 'react';
-import { IconFiles, IconRun } from '@tabler/icons';
+import { uuid } from 'utils/common';
+import { IconFiles, IconRun, IconEye } from '@tabler/icons';
import EnvironmentSelector from 'components/Environments/EnvironmentSelector';
-import VariablesView from 'components/VariablesView';
+import { addTab } from 'providers/ReduxStore/slices/tabs';
import { useDispatch } from 'react-redux';
import { toggleRunnerView } from 'providers/ReduxStore/slices/collections';
import StyledWrapper from './StyledWrapper';
@@ -17,6 +18,16 @@ const CollectionToolBar = ({ collection }) => {
);
};
+ const viewVariables = () => {
+ dispatch(
+ addTab({
+ uid: uuid(),
+ collectionUid: collection.uid,
+ type: 'variables'
+ })
+ );
+ };
+
return (
@@ -28,7 +39,9 @@ const CollectionToolBar = ({ collection }) => {
-
+
+
+
diff --git a/packages/bruno-app/src/components/RequestTabs/RequestTab/SpecialTab.js b/packages/bruno-app/src/components/RequestTabs/RequestTab/SpecialTab.js
new file mode 100644
index 000000000..d086d5b90
--- /dev/null
+++ b/packages/bruno-app/src/components/RequestTabs/RequestTab/SpecialTab.js
@@ -0,0 +1,23 @@
+import React from 'react';
+import { IconVariable } from '@tabler/icons';
+
+const SpecialTab = ({ handleCloseClick, text }) => {
+ return (
+ <>
+
+
+ {text}
+
+ handleCloseClick(e)}>
+
+
+ >
+ );
+};
+
+export default SpecialTab;
diff --git a/packages/bruno-app/src/components/RequestTabs/RequestTab/index.js b/packages/bruno-app/src/components/RequestTabs/RequestTab/index.js
index a10fd8994..744f85c27 100644
--- a/packages/bruno-app/src/components/RequestTabs/RequestTab/index.js
+++ b/packages/bruno-app/src/components/RequestTabs/RequestTab/index.js
@@ -5,6 +5,7 @@ import { useDispatch } from 'react-redux';
import { findItemInCollection } from 'utils/collections';
import StyledWrapper from './StyledWrapper';
import RequestTabNotFound from './RequestTabNotFound';
+import SpecialTab from './SpecialTab';
const RequestTab = ({ tab, collection }) => {
const dispatch = useDispatch();
@@ -56,6 +57,14 @@ const RequestTab = ({ tab, collection }) => {
return color;
};
+ if (tab.type === 'variables') {
+ return (
+
+
+
+ );
+ }
+
const item = findItemInCollection(collection, tab.uid);
if (!item) {
diff --git a/packages/bruno-app/src/components/RequestTabs/index.js b/packages/bruno-app/src/components/RequestTabs/index.js
index a92c55271..c51da327f 100644
--- a/packages/bruno-app/src/components/RequestTabs/index.js
+++ b/packages/bruno-app/src/components/RequestTabs/index.js
@@ -114,7 +114,7 @@ const RequestTabs = () => {
role="tab"
onClick={() => handleClick(tab)}
>
-
+
);
})
diff --git a/packages/bruno-app/src/components/SingleLineEditor/StyledWrapper.js b/packages/bruno-app/src/components/SingleLineEditor/StyledWrapper.js
index fbd05bb53..c63a0f2a1 100644
--- a/packages/bruno-app/src/components/SingleLineEditor/StyledWrapper.js
+++ b/packages/bruno-app/src/components/SingleLineEditor/StyledWrapper.js
@@ -19,6 +19,7 @@ const StyledWrapper = styled.div`
.CodeMirror-scroll {
overflow: hidden !important;
+ padding-bottom: 50px !important;
}
.CodeMirror-hscrollbar {
diff --git a/packages/bruno-app/src/components/SingleLineEditor/index.js b/packages/bruno-app/src/components/SingleLineEditor/index.js
index 5925b598e..eef157ff9 100644
--- a/packages/bruno-app/src/components/SingleLineEditor/index.js
+++ b/packages/bruno-app/src/components/SingleLineEditor/index.js
@@ -31,6 +31,7 @@ class SingleLineEditor extends Component {
brunoVarInfo: {
variables: getAllVariables(this.props.collection)
},
+ scrollbarStyle: null,
extraKeys: {
Enter: () => {
if (this.props.onRun) {
diff --git a/packages/bruno-app/src/components/VariablesEditor/StyledWrapper.js b/packages/bruno-app/src/components/VariablesEditor/StyledWrapper.js
new file mode 100644
index 000000000..e4d976b0d
--- /dev/null
+++ b/packages/bruno-app/src/components/VariablesEditor/StyledWrapper.js
@@ -0,0 +1,20 @@
+import styled from 'styled-components';
+
+const StyledWrapper = styled.div`
+ table {
+ thead,
+ td {
+ border: 1px solid ${(props) => props.theme.table.border};
+
+ li {
+ background-color: ${(props) => props.theme.bg} !important;
+ }
+ }
+ }
+
+ .muted {
+ color: ${(props) => props.theme.colors.text.muted};
+ }
+`;
+
+export default StyledWrapper;
diff --git a/packages/bruno-app/src/components/VariablesEditor/index.js b/packages/bruno-app/src/components/VariablesEditor/index.js
new file mode 100644
index 000000000..80176065e
--- /dev/null
+++ b/packages/bruno-app/src/components/VariablesEditor/index.js
@@ -0,0 +1,92 @@
+import React from 'react';
+import get from 'lodash/get';
+import filter from 'lodash/filter';
+import { Inspector } from 'react-inspector';
+import { useTheme } from 'providers/Theme';
+import { findEnvironmentInCollection } from 'utils/collections';
+import StyledWrapper from './StyledWrapper';
+
+const KeyValueExplorer = ({ data, theme }) => {
+ data = data || {};
+
+ return (
+
+
+
+ {Object.entries(data).map(([key, value]) => (
+
+ {key} |
+
+
+ |
+
+ ))}
+
+
+
+ );
+};
+
+const EnvVariables = ({ collection, theme }) => {
+ const environment = findEnvironmentInCollection(collection, collection.activeEnvironmentUid);
+
+ if (!environment) {
+ return (
+ <>
+ Environment Variables
+ No environment selected
+ >
+ );
+ }
+
+ const envVars = get(environment, 'variables', []);
+ const enabledEnvVars = filter(envVars, (variable) => variable.enabled);
+ const envVarsObj = enabledEnvVars.reduce((acc, curr) => {
+ acc[curr.name] = curr.value;
+ return acc;
+ }, {});
+
+ return (
+ <>
+
+ Environment Variables
+ ({environment.name})
+
+ {enabledEnvVars.length > 0 ? (
+
+ ) : (
+ No environment variables found
+ )}
+ >
+ );
+};
+
+const CollectionVariables = ({ collection, theme }) => {
+ const collectionVariablesFound = Object.keys(collection.collectionVariables).length > 0;
+
+ return (
+ <>
+ Collection Variables
+ {collectionVariablesFound ? (
+
+ ) : (
+ No collection variables found
+ )}
+ >
+ );
+};
+
+const VariablesEditor = ({ collection }) => {
+ const { storedTheme } = useTheme();
+
+ const reactInspectorTheme = storedTheme === 'light' ? 'chromeLight' : 'chromeDark';
+
+ return (
+
+
+
+
+ );
+};
+
+export default VariablesEditor;
diff --git a/packages/bruno-app/src/components/VariablesView/Popover/StyledWrapper.js b/packages/bruno-app/src/components/VariablesView/Popover/StyledWrapper.js
deleted file mode 100644
index 45fa9b60b..000000000
--- a/packages/bruno-app/src/components/VariablesView/Popover/StyledWrapper.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import styled from 'styled-components';
-
-const Wrapper = styled.div`
- position: absolute;
- min-width: fit-content;
- font-size: 14px;
- top: 36px;
- right: 0;
- white-space: nowrap;
- z-index: 1000;
- background-color: ${(props) => props.theme.variables.bg};
-
- .popover {
- border-radius: 2px;
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
- }
-`;
-
-export default Wrapper;
diff --git a/packages/bruno-app/src/components/VariablesView/Popover/index.js b/packages/bruno-app/src/components/VariablesView/Popover/index.js
deleted file mode 100644
index ab1700f88..000000000
--- a/packages/bruno-app/src/components/VariablesView/Popover/index.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import React, { useRef } from 'react';
-import StyledWrapper from './StyledWrapper';
-import useOnClickOutside from 'hooks/useOnClickOutside';
-
-const PopOver = ({ children, iconRef, handleClose }) => {
- const popOverRef = useRef(null);
-
- useOnClickOutside(popOverRef, (e) => {
- if (iconRef && iconRef.current) {
- if (e.target == iconRef.current || iconRef.current.contains(e.target)) {
- return;
- }
- }
- handleClose();
- });
-
- return (
-
-
-
- );
-};
-
-export default PopOver;
diff --git a/packages/bruno-app/src/components/VariablesView/StyledWrapper.js b/packages/bruno-app/src/components/VariablesView/StyledWrapper.js
deleted file mode 100644
index f280aad41..000000000
--- a/packages/bruno-app/src/components/VariablesView/StyledWrapper.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import styled from 'styled-components';
-
-const StyledWrapper = styled.div`
- position: relative;
- align-self: stretch;
- display: flex;
- align-items: center;
-
- .view-environment {
- width: 1rem;
- font-size: 10px;
- }
-`;
-
-export default StyledWrapper;
diff --git a/packages/bruno-app/src/components/VariablesView/VariablesTable/StyledWrapper.js b/packages/bruno-app/src/components/VariablesView/VariablesTable/StyledWrapper.js
deleted file mode 100644
index a3970cdb1..000000000
--- a/packages/bruno-app/src/components/VariablesView/VariablesTable/StyledWrapper.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import styled from 'styled-components';
-
-const StyledWrapper = styled.div`
- .variable-name {
- color: ${(props) => props.theme.variables.name.color};
- }
-
- .variable-name {
- min-width: 180px;
- }
-
- .variable-value {
- max-width: 600px;
- inline-size: 600px;
- overflow-wrap: break-word;
- }
-`;
-
-export default StyledWrapper;
diff --git a/packages/bruno-app/src/components/VariablesView/VariablesTable/index.js b/packages/bruno-app/src/components/VariablesView/VariablesTable/index.js
deleted file mode 100644
index b56cea098..000000000
--- a/packages/bruno-app/src/components/VariablesView/VariablesTable/index.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import React from 'react';
-import forOwn from 'lodash/forOwn';
-import cloneDeep from 'lodash/cloneDeep';
-import { uuid } from 'utils/common';
-import StyledWrapper from './StyledWrapper';
-
-const VariablesTable = ({ variables, collectionVariables }) => {
- const collectionVars = [];
-
- forOwn(cloneDeep(collectionVariables), (value, key) => {
- collectionVars.push({
- uid: uuid(),
- name: key,
- value: value
- });
- });
-
- return (
-
-
- Environment Variables
- {variables && variables.length ? (
- variables.map((variable) => {
- return (
-
- {variable.name}
- {variable.value}
-
- );
- })
- ) : (
- No env variables found
- )}
-
- Collection Variables
- {collectionVars && collectionVars.length ? (
- collectionVars.map((variable) => {
- return (
-
- {variable.name}
- {variable.value}
-
- );
- })
- ) : (
- No collection variables found
- )}
-
-
- );
-};
-
-export default VariablesTable;
diff --git a/packages/bruno-app/src/components/VariablesView/index.js b/packages/bruno-app/src/components/VariablesView/index.js
deleted file mode 100644
index 8f04fed70..000000000
--- a/packages/bruno-app/src/components/VariablesView/index.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import React, { useState, useRef } from 'react';
-import get from 'lodash/get';
-import filter from 'lodash/filter';
-import { findEnvironmentInCollection } from 'utils/collections';
-import VariablesTable from './VariablesTable';
-import StyledWrapper from './StyledWrapper';
-import PopOver from './Popover';
-import { IconEye } from '@tabler/icons';
-
-const VariablesView = ({ collection }) => {
- const iconRef = useRef(null);
- const [popOverOpen, setPopOverOpen] = useState(false);
-
- const environment = findEnvironmentInCollection(collection, collection.activeEnvironmentUid);
- const variables = get(environment, 'variables', []);
- const enabledVariables = filter(variables, (variable) => variable.enabled);
- const showVariablesTable =
- enabledVariables.length > 0 ||
- (collection.collectionVariables && Object.keys(collection.collectionVariables).length > 0);
-
- return (
-
- setPopOverOpen(true)}
- onMouseEnter={() => setPopOverOpen(true)}
- onMouseLeave={() => setPopOverOpen(false)}
- >
-
-
-
- {popOverOpen && (
- setPopOverOpen(false)}>
-
- {showVariablesTable ? (
-
- ) : (
- 'No variables found'
- )}
-
-
- )}
-
-
- );
-};
-
-export default VariablesView;
diff --git a/packages/bruno-app/src/providers/App/useCollectionTreeSync.js b/packages/bruno-app/src/providers/App/useCollectionTreeSync.js
index 1f3c02c6f..858682e82 100644
--- a/packages/bruno-app/src/providers/App/useCollectionTreeSync.js
+++ b/packages/bruno-app/src/providers/App/useCollectionTreeSync.js
@@ -8,6 +8,7 @@ import {
collectionUnlinkDirectoryEvent,
collectionUnlinkEnvFileEvent,
scriptEnvironmentUpdateEvent,
+ processEnvUpdateEvent,
collectionRenamedEvent,
runRequestEvent,
runFolderEvent
@@ -97,6 +98,10 @@ const useCollectionTreeSync = () => {
dispatch(scriptEnvironmentUpdateEvent(val));
};
+ const _processEnvUpdate = (val) => {
+ dispatch(processEnvUpdateEvent(val));
+ };
+
const _collectionRenamed = (val) => {
dispatch(collectionRenamedEvent(val));
};
@@ -119,7 +124,8 @@ const useCollectionTreeSync = () => {
const removeListener6 = ipcRenderer.on('main:collection-renamed', _collectionRenamed);
const removeListener7 = ipcRenderer.on('main:run-folder-event', _runFolderEvent);
const removeListener8 = ipcRenderer.on('main:run-request-event', _runRequestEvent);
- const removeListener9 = ipcRenderer.on('main:console-log', (val) => {
+ const removeListener9 = ipcRenderer.on('main:process-env-update', _processEnvUpdate);
+ const removeListener10 = ipcRenderer.on('main:console-log', (val) => {
console[val.type](...val.args);
});
@@ -133,6 +139,7 @@ const useCollectionTreeSync = () => {
removeListener7();
removeListener8();
removeListener9();
+ removeListener10();
};
}, [isElectron]);
};
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 c12b81eed..e1137aae7 100644
--- a/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
+++ b/packages/bruno-app/src/providers/ReduxStore/slices/collections/index.js
@@ -177,6 +177,14 @@ export const collectionsSlice = createSlice({
collection.collectionVariables = collectionVariables;
}
},
+ processEnvUpdateEvent: (state, action) => {
+ const { collectionUid, processEnvVariables } = action.payload;
+ const collection = findCollectionByUid(state.collections, collectionUid);
+
+ if (collection) {
+ collection.processEnvVariables = processEnvVariables;
+ }
+ },
requestCancelled: (state, action) => {
const { itemUid, collectionUid } = action.payload;
const collection = findCollectionByUid(state.collections, collectionUid);
@@ -1158,6 +1166,7 @@ export const {
renameItem,
cloneItem,
scriptEnvironmentUpdateEvent,
+ processEnvUpdateEvent,
requestCancelled,
responseReceived,
saveRequest,
diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/tabs.js b/packages/bruno-app/src/providers/ReduxStore/slices/tabs.js
index e1181aac7..4f8778a5e 100644
--- a/packages/bruno-app/src/providers/ReduxStore/slices/tabs.js
+++ b/packages/bruno-app/src/providers/ReduxStore/slices/tabs.js
@@ -19,12 +19,22 @@ export const tabsSlice = createSlice({
if (alreadyExists) {
return;
}
+
+ if (action.payload.type === 'variables') {
+ const tab = find(state.tabs, (t) => t.collectionUid === action.payload.collectionUid && t.type === 'variables');
+ if (tab) {
+ state.activeTabUid = tab.uid;
+ return;
+ }
+ }
+
state.tabs.push({
uid: action.payload.uid,
collectionUid: action.payload.collectionUid,
requestPaneWidth: null,
requestPaneTab: action.payload.requestPaneTab || 'params',
- responsePaneTab: 'response'
+ responsePaneTab: 'response',
+ type: action.payload.type || 'request'
});
state.activeTabUid = action.payload.uid;
},
@@ -55,16 +65,22 @@ export const tabsSlice = createSlice({
closeTabs: (state, action) => {
const activeTab = find(state.tabs, (t) => t.uid === state.activeTabUid);
const tabUids = action.payload.tabUids || [];
+
+ // remove the tabs from the state
state.tabs = filter(state.tabs, (t) => !tabUids.includes(t.uid));
if (activeTab && state.tabs.length) {
const { collectionUid } = activeTab;
const activeTabStillExists = find(state.tabs, (t) => t.uid === state.activeTabUid);
+ // if the active tab no longer exists, set the active tab to the last tab in the list
+ // this implies that the active tab was closed
if (!activeTabStillExists) {
- // attempt to load sibling tabs (based on collections) of the dead tab
+ // load sibling tabs of the current collection
const siblingTabs = filter(state.tabs, (t) => t.collectionUid === collectionUid);
+ // if there are sibling tabs, set the active tab to the last sibling tab
+ // otherwise, set the active tab to the last tab in the list
if (siblingTabs && siblingTabs.length) {
state.activeTabUid = last(siblingTabs).uid;
} else {
diff --git a/packages/bruno-app/src/styles/_buttons.scss b/packages/bruno-app/src/styles/_buttons.scss
index 8b1378917..e69de29bb 100644
--- a/packages/bruno-app/src/styles/_buttons.scss
+++ b/packages/bruno-app/src/styles/_buttons.scss
@@ -1 +0,0 @@
-
diff --git a/packages/bruno-app/src/styles/app.scss b/packages/bruno-app/src/styles/app.scss
index 64423a4bb..46e81fc09 100644
--- a/packages/bruno-app/src/styles/app.scss
+++ b/packages/bruno-app/src/styles/app.scss
@@ -1 +1 @@
-@import "buttons";
+@import 'buttons';
diff --git a/packages/bruno-app/src/styles/globals.css b/packages/bruno-app/src/styles/globals.css
index 69f95ddcb..fb8eb5b5f 100644
--- a/packages/bruno-app/src/styles/globals.css
+++ b/packages/bruno-app/src/styles/globals.css
@@ -1,4 +1,3 @@
-
:root {
--color-brand: #546de5;
--color-text: rgb(52 52 52);
@@ -21,7 +20,8 @@
--color-method-head: rgb(52 52 52);
}
-html, body {
+html,
+body {
margin: 0;
padding: 0;
font-size: 1rem;
@@ -38,15 +38,18 @@ body {
font-size: 0.875rem;
}
-body::-webkit-scrollbar, .CodeMirror-vscrollbar::-webkit-scrollbar {
+body::-webkit-scrollbar,
+.CodeMirror-vscrollbar::-webkit-scrollbar {
width: 0.6rem;
}
-
-body::-webkit-scrollbar-track, .CodeMirror-vscrollbar::-webkit-scrollbar-track {
+
+body::-webkit-scrollbar-track,
+.CodeMirror-vscrollbar::-webkit-scrollbar-track {
background-color: #f1f1f1;
}
-
-body::-webkit-scrollbar-thumb, .CodeMirror-vscrollbar::-webkit-scrollbar-thumb {
+
+body::-webkit-scrollbar-thumb,
+.CodeMirror-vscrollbar::-webkit-scrollbar-thumb {
background-color: #cdcdcd;
border-radius: 5rem;
}
diff --git a/packages/bruno-app/src/utils/codemirror/brunoVarInfo.js b/packages/bruno-app/src/utils/codemirror/brunoVarInfo.js
index 7a1a928b3..50f314dac 100644
--- a/packages/bruno-app/src/utils/codemirror/brunoVarInfo.js
+++ b/packages/bruno-app/src/utils/codemirror/brunoVarInfo.js
@@ -8,6 +8,7 @@
let CodeMirror;
const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true;
+const { get } = require('lodash');
if (!SERVER_RENDERED) {
CodeMirror = require('codemirror');
@@ -20,7 +21,7 @@ if (!SERVER_RENDERED) {
// str is of format {{variableName}}, extract variableName
// we are seeing that from the gql query editor, the token string is of format variableName
const variableName = str.replace('{{', '').replace('}}', '').trim();
- const variableValue = options.variables[variableName];
+ const variableValue = get(options.variables, variableName);
const into = document.createElement('div');
const descriptionDiv = document.createElement('div');
diff --git a/packages/bruno-app/src/utils/collections/index.js b/packages/bruno-app/src/utils/collections/index.js
index 3a0591324..80fe41dd3 100644
--- a/packages/bruno-app/src/utils/collections/index.js
+++ b/packages/bruno-app/src/utils/collections/index.js
@@ -542,6 +542,11 @@ export const getAllVariables = (collection) => {
return {
...environmentVariables,
- ...collection.collectionVariables
+ ...collection.collectionVariables,
+ process: {
+ env: {
+ ...collection.processEnvVariables
+ }
+ }
};
};
diff --git a/packages/bruno-app/src/utils/common/codemirror.js b/packages/bruno-app/src/utils/common/codemirror.js
index a565062e9..59daee837 100644
--- a/packages/bruno-app/src/utils/common/codemirror.js
+++ b/packages/bruno-app/src/utils/common/codemirror.js
@@ -1,3 +1,6 @@
+import get from 'lodash/get';
+import isString from 'lodash/isString';
+
let CodeMirror;
const SERVER_RENDERED = typeof navigator === 'undefined' || global['PREVENT_CODEMIRROR_RENDER'] === true;
@@ -5,6 +8,11 @@ if (!SERVER_RENDERED) {
CodeMirror = require('codemirror');
}
+const pathFoundInVariables = (path, obj) => {
+ const value = get(obj, path);
+ return isString(value);
+};
+
export const defineCodeMirrorBrunoVariablesMode = (variables, mode) => {
CodeMirror.defineMode('brunovariables', function (config, parserConfig) {
let variablesOverlay = {
@@ -15,7 +23,8 @@ export const defineCodeMirrorBrunoVariablesMode = (variables, mode) => {
while ((ch = stream.next()) != null) {
if (ch == '}' && stream.next() == '}') {
stream.eat('}');
- if (word in variables) {
+ let found = pathFoundInVariables(word, variables);
+ if (found) {
return 'variable-valid';
} else {
return 'variable-invalid';
diff --git a/packages/bruno-electron/package.json b/packages/bruno-electron/package.json
index 2cacfda50..1334f3f5d 100644
--- a/packages/bruno-electron/package.json
+++ b/packages/bruno-electron/package.json
@@ -1,7 +1,7 @@
{
"version": "v0.14.1",
"name": "bruno",
- "description": "Opensource API Client",
+ "description": "Opensource API Client for Exploring and Testing APIs",
"homepage": "https://www.usebruno.com",
"private": true,
"main": "src/index.js",
@@ -28,6 +28,7 @@
"form-data": "^4.0.0",
"fs-extra": "^10.1.0",
"graphql": "^16.6.0",
+ "handlebars": "^4.7.8",
"is-valid-path": "^0.1.1",
"lodash": "^4.17.21",
"mustache": "^4.2.0",
diff --git a/packages/bruno-electron/src/app/menu-template.js b/packages/bruno-electron/src/app/menu-template.js
index 2e3beb82b..45125bb97 100644
--- a/packages/bruno-electron/src/app/menu-template.js
+++ b/packages/bruno-electron/src/app/menu-template.js
@@ -1,11 +1,13 @@
const { ipcMain } = require('electron');
+const openAboutWindow = require('about-window').default;
+const { join } = require('path');
const template = [
{
label: 'Collection',
submenu: [
{
- label: 'Open Local Collection',
+ label: 'Open Collection',
click() {
ipcMain.emit('main:open-collection');
}
@@ -21,7 +23,8 @@ const template = [
{ type: 'separator' },
{ role: 'cut' },
{ role: 'copy' },
- { role: 'paste' }
+ { role: 'paste' },
+ { role: 'selectAll' }
]
},
{
@@ -42,7 +45,19 @@ const template = [
},
{
role: 'help',
- submenu: [{ label: 'Learn More' }]
+ submenu: [
+ {
+ label: 'About Bruno',
+ click: () =>
+ openAboutWindow({
+ product_name: 'Bruno',
+ icon_path: join(__dirname, '../../resources/icons/png/256x256.png'),
+ homepage: 'https://www.usebruno.com/',
+ package_json_dir: join(__dirname, '../..')
+ })
+ },
+ { label: 'Documentation', click: () => ipcMain.emit('main:open-docs') }
+ ]
}
];
diff --git a/packages/bruno-electron/src/app/watcher.js b/packages/bruno-electron/src/app/watcher.js
index 84c959cba..3fd2b08a2 100644
--- a/packages/bruno-electron/src/app/watcher.js
+++ b/packages/bruno-electron/src/app/watcher.js
@@ -4,12 +4,14 @@ const path = require('path');
const chokidar = require('chokidar');
const { hasJsonExtension, hasBruExtension, writeFile } = require('../utils/filesystem');
const { bruToEnvJson, envJsonToBru, bruToJson, jsonToBru } = require('../bru');
+const { dotenvToJson } = require('@usebruno/lang');
const { isLegacyEnvFile, migrateLegacyEnvFile, isLegacyBruFile, migrateLegacyBruFile } = require('../bru/migrate');
const { itemSchema } = require('@usebruno/schema');
const { uuid } = require('../utils/common');
const { getRequestUid } = require('../cache/requestUids');
const { decryptString } = require('../utils/encryption');
+const { setDotEnvVars } = require('../store/process-env');
const EnvironmentSecretsStore = require('../store/env-secrets');
const environmentSecretsStore = new EnvironmentSecretsStore();
@@ -21,6 +23,13 @@ const isJsonEnvironmentConfig = (pathname, collectionPath) => {
return dirname === collectionPath && basename === 'environments.json';
};
+const isDotEnvFile = (pathname, collectionPath) => {
+ const dirname = path.dirname(pathname);
+ const basename = path.basename(pathname);
+
+ return dirname === collectionPath && basename === '.env';
+};
+
const isBruEnvironmentConfig = (pathname, collectionPath) => {
const dirname = path.dirname(pathname);
const envDirectory = path.join(collectionPath, 'environments');
@@ -158,6 +167,25 @@ const unlinkEnvironmentFile = async (win, pathname, collectionUid) => {
const add = async (win, pathname, collectionUid, collectionPath) => {
console.log(`watcher add: ${pathname}`);
+ if (isDotEnvFile(pathname, collectionPath)) {
+ try {
+ const content = fs.readFileSync(pathname, 'utf8');
+ const jsonData = dotenvToJson(content);
+
+ setDotEnvVars(collectionUid, jsonData);
+ const payload = {
+ collectionUid,
+ processEnvVariables: {
+ ...process.env,
+ ...jsonData
+ }
+ };
+ win.webContents.send('main:process-env-update', payload);
+ } catch (err) {
+ console.error(err);
+ }
+ }
+
if (isJsonEnvironmentConfig(pathname, collectionPath)) {
try {
const dirname = path.dirname(pathname);
@@ -253,6 +281,25 @@ const addDirectory = (win, pathname, collectionUid, collectionPath) => {
};
const change = async (win, pathname, collectionUid, collectionPath) => {
+ if (isDotEnvFile(pathname, collectionPath)) {
+ try {
+ const content = fs.readFileSync(pathname, 'utf8');
+ const jsonData = dotenvToJson(content);
+
+ setDotEnvVars(collectionUid, jsonData);
+ const payload = {
+ collectionUid,
+ processEnvVariables: {
+ ...process.env,
+ ...jsonData
+ }
+ };
+ win.webContents.send('main:process-env-update', payload);
+ } catch (err) {
+ console.error(err);
+ }
+ }
+
if (isBruEnvironmentConfig(pathname, collectionPath)) {
return changeEnvironmentFile(win, pathname, collectionUid, collectionPath);
}
diff --git a/packages/bruno-electron/src/index.js b/packages/bruno-electron/src/index.js
index 30a98da39..2a62dd969 100644
--- a/packages/bruno-electron/src/index.js
+++ b/packages/bruno-electron/src/index.js
@@ -5,7 +5,7 @@ const { BrowserWindow, app, Menu } = require('electron');
const { setContentSecurityPolicy } = require('electron-util');
const menuTemplate = require('./app/menu-template');
-const LastOpenedCollections = require('./app/last-opened-collections');
+const LastOpenedCollections = require('./store/last-opened-collections');
const registerNetworkIpc = require('./ipc/network');
const registerCollectionsIpc = require('./ipc/collection');
const Watcher = require('./app/watcher');
diff --git a/packages/bruno-electron/src/ipc/collection.js b/packages/bruno-electron/src/ipc/collection.js
index cf87ab1fd..7431d4fed 100644
--- a/packages/bruno-electron/src/ipc/collection.js
+++ b/packages/bruno-electron/src/ipc/collection.js
@@ -1,7 +1,7 @@
const _ = require('lodash');
const fs = require('fs');
const path = require('path');
-const { ipcMain } = require('electron');
+const { ipcMain, shell } = require('electron');
const { envJsonToBru, bruToJson, jsonToBru } = require('../bru');
const {
@@ -17,7 +17,7 @@ const { stringifyJson } = require('../utils/common');
const { openCollectionDialog, openCollection } = require('../app/collections');
const { generateUidBasedOnHash } = require('../utils/common');
const { moveRequestUid, deleteRequestUid } = require('../cache/requestUids');
-const { setPreferences } = require('../app/preferences');
+const { setPreferences } = require('../store/preferences');
const EnvironmentSecretsStore = require('../store/env-secrets');
const environmentSecretsStore = new EnvironmentSecretsStore();
@@ -460,6 +460,11 @@ const registerMainEventHandlers = (mainWindow, watcher, lastOpenedCollections) =
}
});
+ ipcMain.on('main:open-docs', () => {
+ const docsURL = 'https://docs.usebruno.com';
+ shell.openExternal(docsURL);
+ });
+
ipcMain.on('main:collection-opened', (win, pathname, uid) => {
watcher.addWatcher(win, pathname, uid);
lastOpenedCollections.add(pathname);
diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js
index 4858d61d6..bc8deb73e 100644
--- a/packages/bruno-electron/src/ipc/network/index.js
+++ b/packages/bruno-electron/src/ipc/network/index.js
@@ -12,7 +12,8 @@ const { cancelTokens, saveCancelToken, deleteCancelToken } = require('../../util
const { uuid } = require('../../utils/common');
const interpolateVars = require('./interpolate-vars');
const { sortFolder, getAllRequestsInFolderRecursively } = require('./helper');
-const { getPreferences } = require('../../app/preferences');
+const { getPreferences } = require('../../store/preferences');
+const { getProcessEnvVars } = require('../../store/process-env');
// override the default escape function to prevent escaping
Mustache.escape = function (value) {
@@ -129,12 +130,14 @@ const registerNetworkIpc = (mainWindow) => {
collectionPath
);
- mainWindow.webContents.send('main:script-environment-update', {
- envVariables: result.envVariables,
- collectionVariables: result.collectionVariables,
- requestUid,
- collectionUid
- });
+ if (result) {
+ mainWindow.webContents.send('main:script-environment-update', {
+ envVariables: result.envVariables,
+ collectionVariables: result.collectionVariables,
+ requestUid,
+ collectionUid
+ });
+ }
}
// run pre-request script
@@ -158,7 +161,9 @@ const registerNetworkIpc = (mainWindow) => {
});
}
- interpolateVars(request, envVars, collectionVariables);
+ const processEnvVars = getProcessEnvVars(collectionUid);
+
+ interpolateVars(request, envVars, collectionVariables, processEnvVars);
// stringify the request url encoded params
if (request.headers['content-type'] === 'application/x-www-form-urlencoded') {
@@ -222,12 +227,14 @@ const registerNetworkIpc = (mainWindow) => {
collectionPath
);
- mainWindow.webContents.send('main:script-environment-update', {
- envVariables: result.envVariables,
- collectionVariables: result.collectionVariables,
- requestUid,
- collectionUid
- });
+ if (result) {
+ mainWindow.webContents.send('main:script-environment-update', {
+ envVariables: result.envVariables,
+ collectionVariables: result.collectionVariables,
+ requestUid,
+ collectionUid
+ });
+ }
}
// run post-response script
@@ -520,7 +527,21 @@ const registerNetworkIpc = (mainWindow) => {
const preRequestVars = get(request, 'vars.req', []);
if (preRequestVars && preRequestVars.length) {
const varsRuntime = new VarsRuntime();
- varsRuntime.runPreRequestVars(preRequestVars, request, envVars, collectionVariables, collectionPath);
+ const result = varsRuntime.runPreRequestVars(
+ preRequestVars,
+ request,
+ envVars,
+ collectionVariables,
+ collectionPath
+ );
+
+ if (result) {
+ mainWindow.webContents.send('main:script-environment-update', {
+ envVariables: result.envVariables,
+ collectionVariables: result.collectionVariables,
+ collectionUid
+ });
+ }
}
// run pre-request script
@@ -543,8 +564,10 @@ const registerNetworkIpc = (mainWindow) => {
});
}
+ const processEnvVars = getProcessEnvVars(collectionUid);
+
// interpolate variables inside request
- interpolateVars(request, envVars, collectionVariables);
+ interpolateVars(request, envVars, collectionVariables, processEnvVars);
// todo:
// i have no clue why electron can't send the request object
@@ -587,11 +610,13 @@ const registerNetworkIpc = (mainWindow) => {
collectionPath
);
- mainWindow.webContents.send('main:script-environment-update', {
- envVariables: result.envVariables,
- collectionVariables: result.collectionVariables,
- collectionUid
- });
+ if (result) {
+ mainWindow.webContents.send('main:script-environment-update', {
+ envVariables: result.envVariables,
+ collectionVariables: result.collectionVariables,
+ collectionUid
+ });
+ }
}
// run response script
diff --git a/packages/bruno-electron/src/ipc/network/interpolate-vars.js b/packages/bruno-electron/src/ipc/network/interpolate-vars.js
index 8c90e00a5..bfb0601da 100644
--- a/packages/bruno-electron/src/ipc/network/interpolate-vars.js
+++ b/packages/bruno-electron/src/ipc/network/interpolate-vars.js
@@ -1,24 +1,51 @@
-const Mustache = require('mustache');
-const { each, get, forOwn } = require('lodash');
+const Handlebars = require('handlebars');
+const { each, forOwn, cloneDeep } = require('lodash');
-// override the default escape function to prevent escaping
-Mustache.escape = function (value) {
- return value;
+const interpolateEnvVars = (str, processEnvVars) => {
+ if (!str || !str.length || typeof str !== 'string') {
+ return str;
+ }
+
+ const template = Handlebars.compile(str, { noEscape: true });
+
+ return template({
+ process: {
+ env: {
+ ...processEnvVars
+ }
+ }
+ });
};
-const interpolateVars = (request, envVars = {}, collectionVariables = {}) => {
+const interpolateVars = (request, envVars = {}, collectionVariables = {}, processEnvVars = {}) => {
+ // we clone envVars because we don't want to modify the original object
+ envVars = cloneDeep(envVars);
+
+ // envVars can inturn have values as {{process.env.VAR_NAME}}
+ // so we need to interpolate envVars first with processEnvVars
+ forOwn(envVars, (value, key) => {
+ envVars[key] = interpolateEnvVars(value, processEnvVars);
+ });
+
const interpolate = (str) => {
if (!str || !str.length || typeof str !== 'string') {
return str;
}
+ const template = Handlebars.compile(str, { noEscape: true });
+
// collectionVariables take precedence over envVars
const combinedVars = {
...envVars,
- ...collectionVariables
+ ...collectionVariables,
+ process: {
+ env: {
+ ...processEnvVars
+ }
+ }
};
- return Mustache.render(str, combinedVars);
+ return template(combinedVars);
};
request.url = interpolate(request.url);
diff --git a/packages/bruno-electron/src/app/last-opened-collections.js b/packages/bruno-electron/src/store/last-opened-collections.js
similarity index 100%
rename from packages/bruno-electron/src/app/last-opened-collections.js
rename to packages/bruno-electron/src/store/last-opened-collections.js
diff --git a/packages/bruno-electron/src/app/preferences.js b/packages/bruno-electron/src/store/preferences.js
similarity index 100%
rename from packages/bruno-electron/src/app/preferences.js
rename to packages/bruno-electron/src/store/preferences.js
diff --git a/packages/bruno-electron/src/store/process-env.js b/packages/bruno-electron/src/store/process-env.js
new file mode 100644
index 000000000..578d8df71
--- /dev/null
+++ b/packages/bruno-electron/src/store/process-env.js
@@ -0,0 +1,37 @@
+/**
+ * This file stores all the process.env variables under collection scope
+ *
+ * process.env variables are sourced from 2 places:
+ * 1. .env file in the root of the project
+ * 2. process.env variables set in the OS
+ *
+ * Multiple collections can be opened in the same electron app.
+ * Each collection's .env file can have different values for the same process.env variable.
+ */
+
+const dotEnvVars = {};
+
+// collectionUid is a hash based on the collection path)
+const getProcessEnvVars = (collectionUid) => {
+ // if there are no .env vars for this collection, return the process.env
+ if (!dotEnvVars[collectionUid]) {
+ return {
+ ...process.env
+ };
+ }
+
+ // if there are .env vars for this collection, return the process.env merged with the .env vars
+ return {
+ ...process.env,
+ ...dotEnvVars[collectionUid]
+ };
+};
+
+const setDotEnvVars = (collectionUid, envVars) => {
+ dotEnvVars[collectionUid] = envVars;
+};
+
+module.exports = {
+ getProcessEnvVars,
+ setDotEnvVars
+};
diff --git a/packages/bruno-electron/src/utils/common.js b/packages/bruno-electron/src/utils/common.js
index d85d137dd..83d22c7ce 100644
--- a/packages/bruno-electron/src/utils/common.js
+++ b/packages/bruno-electron/src/utils/common.js
@@ -41,10 +41,39 @@ const generateUidBasedOnHash = (str) => {
return `${hash}`.padEnd(21, '0');
};
+const flattenDataForDotNotation = (data) => {
+ var result = {};
+ function recurse(current, prop) {
+ if (Object(current) !== current) {
+ result[prop] = current;
+ } else if (Array.isArray(current)) {
+ for (var i = 0, l = current.length; i < l; i++) {
+ recurse(current[i], prop + '[' + i + ']');
+ }
+ if (l == 0) {
+ result[prop] = [];
+ }
+ } else {
+ var isEmpty = true;
+ for (var p in current) {
+ isEmpty = false;
+ recurse(current[p], prop ? prop + '.' + p : p);
+ }
+ if (isEmpty && prop) {
+ result[prop] = {};
+ }
+ }
+ }
+
+ recurse(data, '');
+ return result;
+};
+
module.exports = {
uuid,
stringifyJson,
parseJson,
simpleHash,
- generateUidBasedOnHash
+ generateUidBasedOnHash,
+ flattenDataForDotNotation
};
diff --git a/packages/bruno-electron/tests/utils/common.spec.js b/packages/bruno-electron/tests/utils/common.spec.js
new file mode 100644
index 000000000..077aac16d
--- /dev/null
+++ b/packages/bruno-electron/tests/utils/common.spec.js
@@ -0,0 +1,85 @@
+const { flattenDataForDotNotation } = require('../../src/utils/common');
+
+describe('utils: flattenDataForDotNotation', () => {
+ test('Flatten a simple object with dot notation', () => {
+ const input = {
+ person: {
+ name: 'John',
+ age: 30,
+ },
+ };
+
+ const expectedOutput = {
+ 'person.name': 'John',
+ 'person.age': 30,
+ };
+
+ expect(flattenDataForDotNotation(input)).toEqual(expectedOutput);
+ });
+
+ test('Flatten an object with nested arrays', () => {
+ const input = {
+ users: [
+ { name: 'Alice', age: 25 },
+ { name: 'Bob', age: 28 },
+ ],
+ };
+
+ const expectedOutput = {
+ 'users[0].name': 'Alice',
+ 'users[0].age': 25,
+ 'users[1].name': 'Bob',
+ 'users[1].age': 28,
+ };
+
+ expect(flattenDataForDotNotation(input)).toEqual(expectedOutput);
+ });
+
+ test('Flatten an empty object', () => {
+ const input = {};
+
+ const expectedOutput = {};
+
+ expect(flattenDataForDotNotation(input)).toEqual(expectedOutput);
+ });
+
+ test('Flatten an object with nested objects', () => {
+ const input = {
+ person: {
+ name: 'Alice',
+ address: {
+ city: 'New York',
+ zipcode: '10001',
+ },
+ },
+ };
+
+ const expectedOutput = {
+ 'person.name': 'Alice',
+ 'person.address.city': 'New York',
+ 'person.address.zipcode': '10001',
+ };
+
+ expect(flattenDataForDotNotation(input)).toEqual(expectedOutput);
+ });
+
+ test('Flatten an object with arrays of objects', () => {
+ const input = {
+ teams: [
+ { name: 'Team A', members: ['Alice', 'Bob'] },
+ { name: 'Team B', members: ['Charlie', 'David'] },
+ ],
+ };
+
+ const expectedOutput = {
+ 'teams[0].name': 'Team A',
+ 'teams[0].members[0]': 'Alice',
+ 'teams[0].members[1]': 'Bob',
+ 'teams[1].name': 'Team B',
+ 'teams[1].members[0]': 'Charlie',
+ 'teams[1].members[1]': 'David',
+ };
+
+ expect(flattenDataForDotNotation(input)).toEqual(expectedOutput);
+ });
+});
\ No newline at end of file
diff --git a/packages/bruno-js/src/runtime/script-runtime.js b/packages/bruno-js/src/runtime/script-runtime.js
index ac9d954a0..9f4871ae6 100644
--- a/packages/bruno-js/src/runtime/script-runtime.js
+++ b/packages/bruno-js/src/runtime/script-runtime.js
@@ -10,6 +10,7 @@ const punycode = require('punycode');
const Bru = require('../bru');
const BrunoRequest = require('../bruno-request');
const BrunoResponse = require('../bruno-response');
+const { cleanJson } = require('../utils');
// Inbuilt Library Support
const atob = require('atob');
@@ -37,7 +38,7 @@ class ScriptRuntime {
if (onConsoleLog && typeof onConsoleLog === 'function') {
const customLogger = (type) => {
return (...args) => {
- onConsoleLog(type, args);
+ onConsoleLog(type, cleanJson(args));
};
};
context.console = {
@@ -81,8 +82,8 @@ class ScriptRuntime {
await asyncVM();
return {
request,
- envVariables,
- collectionVariables
+ envVariables: cleanJson(envVariables),
+ collectionVariables: cleanJson(collectionVariables)
};
}
@@ -100,7 +101,7 @@ class ScriptRuntime {
if (onConsoleLog && typeof onConsoleLog === 'function') {
const customLogger = (type) => {
return (...args) => {
- onConsoleLog(type, args);
+ onConsoleLog(type, cleanJson(args));
};
};
context.console = {
@@ -136,8 +137,8 @@ class ScriptRuntime {
return {
response,
- envVariables,
- collectionVariables
+ envVariables: cleanJson(envVariables),
+ collectionVariables: cleanJson(collectionVariables)
};
}
}
diff --git a/packages/bruno-js/src/runtime/test-runtime.js b/packages/bruno-js/src/runtime/test-runtime.js
index 323a001ab..427506524 100644
--- a/packages/bruno-js/src/runtime/test-runtime.js
+++ b/packages/bruno-js/src/runtime/test-runtime.js
@@ -6,6 +6,7 @@ const BrunoRequest = require('../bruno-request');
const BrunoResponse = require('../bruno-response');
const Test = require('../test');
const TestResults = require('../test-results');
+const { cleanJson } = require('../utils');
// Inbuilt Library Support
const atob = require('atob');
@@ -49,7 +50,7 @@ class TestRuntime {
if (onConsoleLog && typeof onConsoleLog === 'function') {
const customLogger = (type) => {
return (...args) => {
- onConsoleLog(type, args);
+ onConsoleLog(type, cleanJson(args));
};
};
context.console = {
@@ -82,9 +83,9 @@ class TestRuntime {
return {
request,
- envVariables,
- collectionVariables,
- results: __brunoTestResults.getResults()
+ envVariables: cleanJson(envVariables),
+ collectionVariables: cleanJson(collectionVariables),
+ results: cleanJson(__brunoTestResults.getResults())
};
}
}
diff --git a/packages/bruno-js/src/utils.js b/packages/bruno-js/src/utils.js
index a1ba5a7ed..aca101962 100644
--- a/packages/bruno-js/src/utils.js
+++ b/packages/bruno-js/src/utils.js
@@ -118,9 +118,28 @@ const createResponseParser = (response = {}) => {
return res;
};
+/**
+ * Objects that are created inside vm2 execution context result in an serilaization error when sent to the renderer process
+ * Error sending from webFrameMain: Error: Failed to serialize arguments
+ * at s.send (node:electron/js2c/browser_init:169:631)
+ * at g.send (node:electron/js2c/browser_init:165:2156)
+ * How to reproduce
+ * Remove the cleanJson fix and execute the below post response script
+ * bru.setVar("a", {b:3});
+ * Todo: Find a better fix
+ */
+const cleanJson = (data) => {
+ try {
+ return JSON.parse(JSON.stringify(data));
+ } catch (e) {
+ return data;
+ }
+};
+
module.exports = {
evaluateJsExpression,
evaluateJsTemplateLiteral,
createResponseParser,
- internalExpressionCache
+ internalExpressionCache,
+ cleanJson
};
diff --git a/packages/bruno-lang/src/index.js b/packages/bruno-lang/src/index.js
index bb7f35a80..f27179c45 100644
--- a/packages/bruno-lang/src/index.js
+++ b/packages/bruno-lang/src/index.js
@@ -4,6 +4,7 @@ const bruToJsonV2 = require('../v2/src/bruToJson');
const jsonToBruV2 = require('../v2/src/jsonToBru');
const bruToEnvJsonV2 = require('../v2/src/envToJson');
const envJsonToBruV2 = require('../v2/src/jsonToEnv');
+const dotenvToJson = require('../v2/src/dotenvToJson');
module.exports = {
bruToJson,
@@ -14,5 +15,7 @@ module.exports = {
bruToJsonV2,
jsonToBruV2,
bruToEnvJsonV2,
- envJsonToBruV2
+ envJsonToBruV2,
+
+ dotenvToJson
};
|