feat: show current env vars

This commit is contained in:
Anoop M D 2023-01-27 03:24:21 +05:30
parent a45628dd85
commit 4a403a253e
15 changed files with 213 additions and 6 deletions

View File

@ -1,6 +1,7 @@
import React from 'react';
import { IconFiles } from '@tabler/icons';
import EnvironmentSelector from 'components/Environments/EnvironmentSelector';
import VariablesView from 'components/VariablesView';
import StyledWrapper from './StyledWrapper';
const CollectionToolBar = ({ collection }) => {
@ -12,6 +13,7 @@ const CollectionToolBar = ({ collection }) => {
<span className="ml-2 mr-4 font-semibold">{collection.name}</span>
</div>
<div className="flex flex-1 items-center justify-end">
<VariablesView collection={collection}/>
<EnvironmentSelector collection={collection} />
</div>
</div>

View File

@ -0,0 +1,19 @@
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;

View File

@ -0,0 +1,30 @@
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 (
<StyledWrapper>
<div className="popover" ref={popOverRef}>
<div className="popover-content">{children}</div>
</div>
</StyledWrapper>
);
};
export default PopOver;

View File

@ -0,0 +1,15 @@
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;

View File

@ -0,0 +1,9 @@
import styled from 'styled-components';
const StyledWrapper = styled.div`
.variable-name {
color: ${(props) => props.theme.variables.name.color};
}
`
export default StyledWrapper;

View File

@ -0,0 +1,21 @@
import React from 'react';
import StyledWrapper from './StyledWrapper';
const VariablesTable = ({ variables }) => {
return (
<StyledWrapper>
<table className="w-full">
<tbody>
{variables.map((variable) => (
<tr key={variable.uid}>
<td className='variable-name text-yellow-600'>{variable.name}</td>
<td className='pl-2'>{variable.value}</td>
</tr>
))}
</tbody>
</table>
</StyledWrapper>
);
};
export default VariablesTable;

View File

@ -0,0 +1,46 @@
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);
return (
<StyledWrapper
className="mr-2 server-syncstatus-icon"
ref={iconRef}
>
<div className="flex p-1 items-center"
onClick={() => setPopOverOpen(true)}
onMouseEnter={() => setPopOverOpen(true)}
onMouseLeave={() => setPopOverOpen(false)}
>
<div className='cursor-pointer view-environment'>
<IconEye size={18} strokeWidth={1.5} />
</div>
{popOverOpen && (
<PopOver
iconRef={iconRef}
handleClose={() => setPopOverOpen(false)}
>
<div className="px-2 py-1">
{(enabledVariables && enabledVariables.length) ? <VariablesTable variables={enabledVariables} /> : 'No variables found'}
</div>
</PopOver>
)}
</div>
</StyledWrapper>
)
};
export default VariablesView;

View File

@ -0,0 +1,34 @@
// See https://usehooks.com/useOnClickOutside/
import { useEffect } from 'react';
const useOnClickOutside = (ref, handler) => {
useEffect(
() => {
const listener = event => {
// Do nothing if clicking ref's element or descendent elements
if (!ref.current || ref.current.contains(event.target)) {
return;
}
handler(event);
};
document.addEventListener('mousedown', listener);
document.addEventListener('touchstart', listener);
return () => {
document.removeEventListener('mousedown', listener);
document.removeEventListener('touchstart', listener);
};
},
// Add ref and handler to effect dependencies
// It's worth noting that because passed in handler is a new ...
// ... function on every render that will cause this effect ...
// ... callback/cleanup to run every render. It's not a big deal ...
// ... but to optimize you can wrap handler in useCallback before ...
// ... passing it into this hook.
[ref, handler]
);
};
export default useOnClickOutside;

View File

@ -16,6 +16,14 @@ const darkTheme = {
}
},
variables: {
bg: 'rgb(48, 48, 49)',
name: {
color: '#569cd6',
}
},
menubar: {
bg: '#333333'
},

View File

@ -20,6 +20,14 @@ const lightTheme = {
bg: 'rgb(44, 44, 44)'
},
variables: {
bg: '#fff',
name: {
color: '#546de5',
}
},
sidebar: {
color: 'rgb(52, 52, 52)',
muted: '#4b5563',

View File

@ -6,6 +6,7 @@ const { ScriptRuntime } = require('@usebruno/js');
const prepareRequest = require('./prepare-request');
const { cancelTokens, saveCancelToken, deleteCancelToken } = require('../../utils/cancel-token');
const { uuid } = require('../../utils/common');
const interpolateVars = require('./interpolate-vars');
const registerNetworkIpc = (mainWindow, watcher, lastOpenedCollections) => {
// handler for sending http request
@ -34,7 +35,7 @@ const registerNetworkIpc = (mainWindow, watcher, lastOpenedCollections) => {
if(request.script && request.script.length) {
request.script = request.script += '\n onRequest(brunoRequest);';
const scriptRuntime = new ScriptRuntime();
scriptRuntime.run(request.script, request);
scriptRuntime.run(request.script, request, environment);
}
mainWindow.webContents.send('main:http-request-sent', {
@ -49,6 +50,8 @@ const registerNetworkIpc = (mainWindow, watcher, lastOpenedCollections) => {
cancelTokenUid
});
interpolateVars(request, environment);
const result = await axios(request);
deleteCancelToken(cancelTokenUid);

View File

@ -1,5 +1,5 @@
const Mustache = require('mustache');
const { each } = require('lodash');
const { each, get } = require('lodash');
// override the default escape function to prevent escaping
Mustache.escape = function (value) {
@ -39,7 +39,8 @@ const interpolateVars = (request, environment) => {
});
// Todo: Make interpolation work with body mode json
switch (request.body.mode) {
const mode = get(request, 'body.mode');
switch (mode) {
case 'text': {
request.body.text = interpolate(request.body.text);
break;

View File

@ -1,9 +1,7 @@
const { get, each, filter } = require('lodash');
const qs = require('qs');
const interpolateVars = require('./interpolate-vars');
const prepareRequest = (request, environment) => {
interpolateVars(request, environment);
const headers = {};
each(request.headers, (h) => {
if (h.enabled) {

View File

@ -0,0 +1,10 @@
class Bru {
constructor(environment) {
this._environment = environment;
}
setVar(key, value) {
}
}
module.exports = Bru;

View File

@ -1,14 +1,17 @@
const { NodeVM } = require('vm2');
const Bru = require('./bru');
const BrunoRequest = require('./bruno-request');
class ScriptRuntime {
constructor() {
}
run(script, request) {
run(script, request, environment) {
const bru = new Bru(environment);
const brunoRequest = new BrunoRequest(request);
const context = {
bru,
brunoRequest
};
const vm = new NodeVM({