From 0cedf48e688723433e59c5283bd36517357d7066 Mon Sep 17 00:00:00 2001 From: "Siddharth Gelera (reaper)" Date: Wed, 19 Nov 2025 11:30:39 +0530 Subject: [PATCH] feat: encapsulate tab boundaries into a hook for managing pane dimensions (#5878) * feat: implement useTabPaneBoundaries hook for managing pane dimensions * fix: replace hardcoded divisor with constant in useTabPaneBoundaries * chore: un-needed event calls * fix: remove redundant import of sendRequest * update main rediff --- .../src/components/RequestTabPanel/index.js | 57 ++++--------------- .../src/hooks/useTabPaneBoundaries/index.js | 44 ++++++++++++++ .../src/providers/ReduxStore/slices/tabs.js | 8 +++ 3 files changed, 64 insertions(+), 45 deletions(-) create mode 100644 packages/bruno-app/src/hooks/useTabPaneBoundaries/index.js diff --git a/packages/bruno-app/src/components/RequestTabPanel/index.js b/packages/bruno-app/src/components/RequestTabPanel/index.js index f8d3aba83..b50e190d9 100644 --- a/packages/bruno-app/src/components/RequestTabPanel/index.js +++ b/packages/bruno-app/src/components/RequestTabPanel/index.js @@ -9,7 +9,6 @@ import ResponsePane from 'components/ResponsePane'; import GrpcResponsePane from 'components/ResponsePane/GrpcResponsePane'; import Welcome from 'components/Welcome'; import { findItemInCollection } from 'utils/collections'; -import { updateRequestPaneTabWidth } from 'providers/ReduxStore/slices/tabs'; import { cancelRequest, sendRequest } from 'providers/ReduxStore/slices/collections/actions'; import RequestNotFound from './RequestNotFound'; import QueryUrl from 'components/RequestPane/QueryUrl/index'; @@ -33,6 +32,7 @@ import ExampleNotFound from './ExampleNotFound'; import WsQueryUrl from 'components/RequestPane/WsQueryUrl'; import WSRequestPane from 'components/RequestPane/WSRequestPane'; import WSResponsePane from 'components/ResponsePane/WsResponsePane'; +import { useTabPaneBoundaries } from 'hooks/useTabPaneBoundaries/index'; import ResponseExample from 'components/ResponseExample'; const MIN_LEFT_PANE_WIDTH = 300; @@ -70,15 +70,9 @@ const RequestTabPanel = () => { }); let collection = find(collections, (c) => c.uid === focusedTab?.collectionUid); - - const screenWidth = useSelector((state) => state.app.screenWidth); - let asideWidth = useSelector((state) => state.app.leftSidebarWidth); - const [leftPaneWidth, setLeftPaneWidth] = useState( - focusedTab && focusedTab.requestPaneWidth ? focusedTab.requestPaneWidth : (screenWidth - asideWidth) / 2.2 - ); // 2.2 is intentional to make both panes appear to be of equal width - const [topPaneHeight, setTopPaneHeight] = useState(focusedTab?.requestPaneHeight || MIN_TOP_PANE_HEIGHT); const [dragging, setDragging] = useState(false); const dragOffset = useRef({ x: 0, y: 0 }); + const { left: leftPaneWidth, top: topPaneHeight, reset: resetPaneBoundaries, setTop: setTopPaneHeight, setLeft: setLeftPaneWidth } = useTabPaneBoundaries(activeTabUid); // Not a recommended pattern here to have the child component // make a callback to set state, but treating this as an exception @@ -97,22 +91,6 @@ const RequestTabPanel = () => { } }; - useEffect(() => { - // Initialize vertical heights when switching to vertical layout - if (mainSectionRef.current) { - const mainRect = mainSectionRef.current.getBoundingClientRect(); - if (isVerticalLayout) { - const initialHeight = mainRect.height / 2; - setTopPaneHeight(initialHeight); - // In vertical mode, set leftPaneWidth to full container width - setLeftPaneWidth(mainRect.width); - } else { - // In horizontal mode, set to roughly half width - setLeftPaneWidth((screenWidth - asideWidth) / 2.2); - } - } - }, [isVerticalLayout, screenWidth, asideWidth]); - const handleMouseMove = (e) => { if (dragging && mainSectionRef.current) { e.preventDefault(); @@ -130,40 +108,22 @@ const RequestTabPanel = () => { if (newWidth < MIN_LEFT_PANE_WIDTH || newWidth > mainRect.width - MIN_RIGHT_PANE_WIDTH) { return; } + setLeftPaneWidth(newWidth); } } }; const handleMouseUp = (e) => { - if (dragging && mainSectionRef.current) { + if (dragging) { e.preventDefault(); setDragging(false); - if (!isVerticalLayout) { - const mainRect = mainSectionRef.current.getBoundingClientRect(); - dispatch( - updateRequestPaneTabWidth({ - uid: activeTabUid, - requestPaneWidth: e.clientX - mainRect.left - }) - ); - } } }; const handleDragbarMouseDown = (e) => { e.preventDefault(); setDragging(true); - - if (isVerticalLayout) { - const dragBar = e.currentTarget; - const dragBarRect = dragBar.getBoundingClientRect(); - dragOffset.current.y = e.clientY - dragBarRect.top; - } else { - const dragBar = e.currentTarget; - const dragBarRect = dragBar.getBoundingClientRect(); - dragOffset.current.x = e.clientX - dragBarRect.left; - } }; useEffect(() => { @@ -329,7 +289,14 @@ const RequestTabPanel = () => { -
+
{ + e.preventDefault(); + resetPaneBoundaries(); + }} + onMouseDown={handleDragbarMouseDown} + >
diff --git a/packages/bruno-app/src/hooks/useTabPaneBoundaries/index.js b/packages/bruno-app/src/hooks/useTabPaneBoundaries/index.js new file mode 100644 index 000000000..e4036761e --- /dev/null +++ b/packages/bruno-app/src/hooks/useTabPaneBoundaries/index.js @@ -0,0 +1,44 @@ +import find from 'lodash/find'; +import { updateRequestPaneTabHeight, updateRequestPaneTabWidth } from 'providers/ReduxStore/slices/tabs'; +import { useDispatch, useSelector } from 'react-redux'; + +const MIN_TOP_PANE_HEIGHT = 150; + +export function useTabPaneBoundaries(activeTabUid) { + const DEFAULT_PANE_WIDTH_DIVISOR = 2.2; + + const tabs = useSelector((state) => state.tabs.tabs); + const focusedTab = find(tabs, (t) => t.uid === activeTabUid); + const screenWidth = useSelector((state) => state.app.screenWidth); + let asideWidth = useSelector((state) => state.app.leftSidebarWidth); + const left = focusedTab && focusedTab.requestPaneWidth ? focusedTab.requestPaneWidth : (screenWidth - asideWidth) / DEFAULT_PANE_WIDTH_DIVISOR; + const top = focusedTab?.requestPaneHeight; + const dispatch = useDispatch(); + + return { + left, + top, + setLeft(value) { + dispatch(updateRequestPaneTabWidth({ + uid: activeTabUid, + requestPaneWidth: value + })); + }, + setTop(value) { + dispatch(updateRequestPaneTabHeight({ + uid: activeTabUid, + requestPaneHeight: value + })); + }, + reset() { + dispatch(updateRequestPaneTabHeight({ + uid: activeTabUid, + requestPaneHeight: MIN_TOP_PANE_HEIGHT + })); + dispatch(updateRequestPaneTabWidth({ + uid: activeTabUid, + requestPaneWidth: (screenWidth - asideWidth) / DEFAULT_PANE_WIDTH_DIVISOR + })); + } + }; +} diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/tabs.js b/packages/bruno-app/src/providers/ReduxStore/slices/tabs.js index 1692c3eeb..f872cd23b 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/tabs.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/tabs.js @@ -117,6 +117,13 @@ export const tabsSlice = createSlice({ tab.requestPaneWidth = action.payload.requestPaneWidth; } }, + updateRequestPaneTabHeight: (state, action) => { + const tab = find(state.tabs, (t) => t.uid === action.payload.uid); + + if (tab) { + tab.requestPaneHeight = action.payload.requestPaneHeight; + } + }, updateRequestPaneTab: (state, action) => { const tab = find(state.tabs, (t) => t.uid === action.payload.uid); @@ -218,6 +225,7 @@ export const { focusTab, switchTab, updateRequestPaneTabWidth, + updateRequestPaneTabHeight, updateRequestPaneTab, updateResponsePaneTab, updateResponsePaneScrollPosition,