From 0a172ddce8c874fbeda6daa135bcc6f385857548 Mon Sep 17 00:00:00 2001 From: Anoop M D Date: Sun, 24 Sep 2023 02:07:31 +0530 Subject: [PATCH] feat(#206): Collection and Env variables viewer --- packages/bruno-app/package.json | 1 + .../src/components/RequestTabPanel/index.js | 5 + .../RequestTabs/CollectionToolBar/index.js | 19 +++- .../RequestTabs/RequestTab/SpecialTab.js | 23 +++++ .../RequestTabs/RequestTab/index.js | 9 ++ .../src/components/RequestTabs/index.js | 2 +- .../VariablesEditor/StyledWrapper.js | 20 ++++ .../src/components/VariablesEditor/index.js | 92 +++++++++++++++++++ .../VariablesView/Popover/StyledWrapper.js | 19 ---- .../components/VariablesView/Popover/index.js | 26 ------ .../components/VariablesView/StyledWrapper.js | 15 --- .../VariablesTable/StyledWrapper.js | 19 ---- .../VariablesView/VariablesTable/index.js | 66 ------------- .../src/components/VariablesView/index.js | 48 ---------- .../src/providers/ReduxStore/slices/tabs.js | 20 +++- 15 files changed, 185 insertions(+), 199 deletions(-) create mode 100644 packages/bruno-app/src/components/RequestTabs/RequestTab/SpecialTab.js create mode 100644 packages/bruno-app/src/components/VariablesEditor/StyledWrapper.js create mode 100644 packages/bruno-app/src/components/VariablesEditor/index.js delete mode 100644 packages/bruno-app/src/components/VariablesView/Popover/StyledWrapper.js delete mode 100644 packages/bruno-app/src/components/VariablesView/Popover/index.js delete mode 100644 packages/bruno-app/src/components/VariablesView/StyledWrapper.js delete mode 100644 packages/bruno-app/src/components/VariablesView/VariablesTable/StyledWrapper.js delete mode 100644 packages/bruno-app/src/components/VariablesView/VariablesTable/index.js delete mode 100644 packages/bruno-app/src/components/VariablesView/index.js 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/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/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 ( - -
-
{children}
-
-
- ); -}; - -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 3707359f2..000000000 --- a/packages/bruno-app/src/components/VariablesView/VariablesTable/index.js +++ /dev/null @@ -1,66 +0,0 @@ -import React from 'react'; -import forOwn from 'lodash/forOwn'; -import isObject from 'lodash/isObject'; -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 - }); - }); - - const getValueToDisplay = (value) => { - if (value === undefined) { - return ''; - } - - return isObject(value) ? JSON.stringify(value) : value; - }; - - return ( - -
-
Environment Variables
- {variables && variables.length ? ( - variables.map((variable) => { - return ( -
-
{variable.name}
-
- {getValueToDisplay(variable.value)} -
-
- ); - }) - ) : ( - No env variables found - )} - -
Collection Variables
- {collectionVars && collectionVars.length ? ( - collectionVars.map((variable) => { - return ( -
-
{variable.name}
-
- {getValueToDisplay(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/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 {