From db822c6e25007d748d729dab806d8b2c669d5f74 Mon Sep 17 00:00:00 2001 From: Pooja Belaramani Date: Wed, 22 Jan 2025 15:46:22 +0530 Subject: [PATCH 1/2] feat(UI): Add collapsible Response Pane --- .../RequestTabPanel/StyledWrapper.js | 64 +++++++++++++++++++ .../src/components/RequestTabPanel/index.js | 62 +++++++++++++++--- .../src/providers/ReduxStore/slices/tabs.js | 9 ++- packages/bruno-app/src/themes/dark.js | 5 ++ packages/bruno-app/src/themes/light.js | 5 ++ 5 files changed, 134 insertions(+), 11 deletions(-) diff --git a/packages/bruno-app/src/components/RequestTabPanel/StyledWrapper.js b/packages/bruno-app/src/components/RequestTabPanel/StyledWrapper.js index ec0a032171..62a49fcfd3 100644 --- a/packages/bruno-app/src/components/RequestTabPanel/StyledWrapper.js +++ b/packages/bruno-app/src/components/RequestTabPanel/StyledWrapper.js @@ -45,6 +45,70 @@ const StyledWrapper = styled.div` display: flex; } } + + .response-toggle { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 48px; + position: absolute; + right: ${props => props.showResponsePane ? 'auto' : '0'}; + top: 50%; + transform: translateY(-50%); + background: ${props => props.theme.requestTabPanel.dragbar.border}; + border-radius: 4px 0 0 4px; + cursor: pointer; + color: ${props => props.theme.requestTabPanel.responseToggle.color}; + z-index: 10; + transition: all 0.2s ease-in-out; + box-shadow: -2px 0 4px rgba(0, 0, 0, 0.1); + + &:hover { + width: 28px; + height: 52px; + background: ${props => props.theme.requestTabPanel.dragbar.activeBorder}; + + svg { + transform: scale(1.2); + } + } + + svg { + transition: transform 0.2s ease-in-out; + } + } + + .response-pane { + animation: slideIn 0.3s ease-in-out; + } + + @keyframes slideIn { + from { + opacity: 0; + transform: translateX(20px); + } + to { + opacity: 1; + transform: translateX(0); + } + } + + .response-pane-exit { + animation: slideOut 0.3s ease-in-out; + } + + @keyframes slideOut { + from { + opacity: 1; + transform: translateX(0); + } + to { + opacity: 0; + transform: translateX(20px); + } + } `; + export default StyledWrapper; diff --git a/packages/bruno-app/src/components/RequestTabPanel/index.js b/packages/bruno-app/src/components/RequestTabPanel/index.js index 4bcfff1c3a..5c6ce7d19e 100644 --- a/packages/bruno-app/src/components/RequestTabPanel/index.js +++ b/packages/bruno-app/src/components/RequestTabPanel/index.js @@ -7,7 +7,7 @@ import HttpRequestPane from 'components/RequestPane/HttpRequestPane'; import ResponsePane from 'components/ResponsePane'; import Welcome from 'components/Welcome'; import { findItemInCollection } from 'utils/collections'; -import { updateRequestPaneTabWidth } from 'providers/ReduxStore/slices/tabs'; +import { updateRequestPaneTabWidth, toggleResponsePane } from 'providers/ReduxStore/slices/tabs'; import { sendRequest } from 'providers/ReduxStore/slices/collections/actions'; import RequestNotFound from './RequestNotFound'; import QueryUrl from 'components/RequestPane/QueryUrl'; @@ -16,6 +16,7 @@ import RunnerResults from 'components/RunnerResults'; import VariablesEditor from 'components/VariablesEditor'; import CollectionSettings from 'components/CollectionSettings'; import { DocExplorer } from '@usebruno/graphql-docs'; +import { IconChevronRight, IconChevronLeft } from '@tabler/icons'; import StyledWrapper from './StyledWrapper'; import SecuritySettings from 'components/SecuritySettings'; @@ -37,6 +38,7 @@ const RequestTabPanel = () => { const focusedTab = find(tabs, (t) => t.uid === activeTabUid); const { globalEnvironments, activeGlobalEnvironmentUid } = useSelector((state) => state.globalEnvironments); const _collections = useSelector((state) => state.collections.collections); + const [showResponsePane, setShowResponsePane] = useState(false); // merge `globalEnvironmentVariables` into the active collection and rebuild `collections` immer proxy object let collections = produce(_collections, (draft) => { @@ -56,6 +58,18 @@ const RequestTabPanel = () => { let collection = find(collections, (c) => c.uid === focusedTab?.collectionUid); + const toggleResponsePane = () => { + const responsePane = document.querySelector('.response-pane'); + if (showResponsePane) { + responsePane?.classList.add('response-pane-exit'); + setTimeout(() => { + setShowResponsePane(false); + }, 280); + } else { + setShowResponsePane(true); + } + }; + const screenWidth = useSelector((state) => state.app.screenWidth); let asideWidth = useSelector((state) => state.app.leftSidebarWidth); const [leftPaneWidth, setLeftPaneWidth] = useState( @@ -168,6 +182,9 @@ const RequestTabPanel = () => { } const handleRun = async () => { + if (!showResponsePane) { + dispatch(toggleResponsePane()); + } dispatch(sendRequest(item, collection.uid)).catch((err) => toast.custom((t) => toast.dismiss(t.id)} />, { duration: 5000 @@ -185,14 +202,16 @@ const RequestTabPanel = () => {
{item.type === 'graphql-request' ? ( { ) : null} {item.type === 'http-request' ? ( - + ) : null}
-
-
+
+ {showResponsePane ? ( + + ) : ( + + )}
-
- -
+ {showResponsePane && ( + <> +
+
+
+ +
+ +
+ + )} {item.type === 'graphql-request' ? ( diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/tabs.js b/packages/bruno-app/src/providers/ReduxStore/slices/tabs.js index 935be60752..761dd4d789 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/tabs.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/tabs.js @@ -7,7 +7,8 @@ import last from 'lodash/last'; const initialState = { tabs: [], - activeTabUid: null + activeTabUid: null, + showResponsePane: false }; const tabTypeAlreadyExists = (tabs, collectionUid, type) => { @@ -89,6 +90,9 @@ export const tabsSlice = createSlice({ tab.responsePaneTab = action.payload.responsePaneTab; } }, + toggleResponsePane: (state) => { + state.showResponsePane = !state.showResponsePane; + }, closeTabs: (state, action) => { const activeTab = find(state.tabs, (t) => t.uid === state.activeTabUid); const tabUids = action.payload.tabUids || []; @@ -136,7 +140,8 @@ export const { updateRequestPaneTab, updateResponsePaneTab, closeTabs, - closeAllCollectionTabs + closeAllCollectionTabs, + toggleResponsePane } = tabsSlice.actions; export default tabsSlice.reducer; diff --git a/packages/bruno-app/src/themes/dark.js b/packages/bruno-app/src/themes/dark.js index 9e8e923aad..83fb1a3801 100644 --- a/packages/bruno-app/src/themes/dark.js +++ b/packages/bruno-app/src/themes/dark.js @@ -99,6 +99,11 @@ const darkTheme = { }, requestTabPanel: { + responseToggle: { + color: '#ffffff', + hoverBg: '#666666', + shadow: '0 2px 4px rgba(0, 0, 0, 0.2)' + }, url: { bg: '#3D3D3D', icon: 'rgb(204, 204, 204)' diff --git a/packages/bruno-app/src/themes/light.js b/packages/bruno-app/src/themes/light.js index a25583136c..eb69955ee4 100644 --- a/packages/bruno-app/src/themes/light.js +++ b/packages/bruno-app/src/themes/light.js @@ -99,6 +99,11 @@ const lightTheme = { }, requestTabPanel: { + responseToggle: { + color: '#333333', + hoverBg: '#e0e0e0', + shadow: '0 2px 4px rgba(0, 0, 0, 0.1)' + }, url: { bg: '#f3f3f3', icon: '#515151' From 94e1504f330036fa155d4843c81903e01638a69e Mon Sep 17 00:00:00 2001 From: Pooja Belaramani Date: Wed, 22 Jan 2025 19:07:12 +0530 Subject: [PATCH 2/2] fixes --- .../bruno-app/src/components/RequestTabPanel/index.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/bruno-app/src/components/RequestTabPanel/index.js b/packages/bruno-app/src/components/RequestTabPanel/index.js index 5c6ce7d19e..0229c624e6 100644 --- a/packages/bruno-app/src/components/RequestTabPanel/index.js +++ b/packages/bruno-app/src/components/RequestTabPanel/index.js @@ -35,10 +35,10 @@ const RequestTabPanel = () => { const dispatch = useDispatch(); const tabs = useSelector((state) => state.tabs.tabs); const activeTabUid = useSelector((state) => state.tabs.activeTabUid); + const showResponsePane = useSelector((state) => state.tabs.showResponsePane); const focusedTab = find(tabs, (t) => t.uid === activeTabUid); const { globalEnvironments, activeGlobalEnvironmentUid } = useSelector((state) => state.globalEnvironments); const _collections = useSelector((state) => state.collections.collections); - const [showResponsePane, setShowResponsePane] = useState(false); // merge `globalEnvironmentVariables` into the active collection and rebuild `collections` immer proxy object let collections = produce(_collections, (draft) => { @@ -58,15 +58,15 @@ const RequestTabPanel = () => { let collection = find(collections, (c) => c.uid === focusedTab?.collectionUid); - const toggleResponsePane = () => { + const handleToggleResponsePane = () => { const responsePane = document.querySelector('.response-pane'); if (showResponsePane) { responsePane?.classList.add('response-pane-exit'); setTimeout(() => { - setShowResponsePane(false); + dispatch(toggleResponsePane()); }, 280); } else { - setShowResponsePane(true); + dispatch(toggleResponsePane()); } }; @@ -230,7 +230,7 @@ const RequestTabPanel = () => {
{showResponsePane ? (