: null}
+ prefix={getPrefixIcon()}
+ isActive={isActiveTab}
disabled={false}
- className="h-[20px] text-[11px]"
+ className="h-[22px] text-[10px]"
data-testid="format-response-tab"
/>
diff --git a/packages/bruno-app/src/components/ResponsePane/StyledWrapper.js b/packages/bruno-app/src/components/ResponsePane/StyledWrapper.js
index da26a9a78..ed97f6a8b 100644
--- a/packages/bruno-app/src/components/ResponsePane/StyledWrapper.js
+++ b/packages/bruno-app/src/components/ResponsePane/StyledWrapper.js
@@ -80,6 +80,33 @@ const StyledWrapper = styled.div`
border-left: 1px solid ${(props) => props.theme.preferences.sidebar.border};
margin: 0 8px;
}
+
+ .result-view-tabs {
+ display: flex;
+ align-items: center;
+ gap: 2px;
+ padding: 3px;
+ border-radius: 8px;
+
+ .button-dropdown-button {
+ border: 1px solid transparent !important;
+ background-color: transparent;
+ border-radius: 5px;
+ font-size: ${(props) => props.theme.font.size.sm};
+
+ &:hover {
+ border-color: ${(props) => props.theme.app.collection.toolbar.environmentSelector.border} !important;
+ }
+ }
+
+ .tab-active .button-dropdown-button {
+ border-color: ${(props) => props.theme.app.collection.toolbar.environmentSelector.border} !important;
+
+ &:hover {
+ border-color: ${(props) => props.theme.app.collection.toolbar.environmentSelector.hoverBorder} !important;
+ }
+ }
+ }
`;
export default StyledWrapper;
diff --git a/packages/bruno-app/src/components/ResponsePane/index.js b/packages/bruno-app/src/components/ResponsePane/index.js
index 3cb9af16f..725666045 100644
--- a/packages/bruno-app/src/components/ResponsePane/index.js
+++ b/packages/bruno-app/src/components/ResponsePane/index.js
@@ -26,7 +26,7 @@ import WSMessagesList from './WsResponsePane/WSMessagesList';
import ResponsiveTabs from 'ui/ResponsiveTabs';
// Width threshold for expanded right-side action buttons
-const RIGHT_CONTENT_EXPANDED_WIDTH = 375;
+const RIGHT_CONTENT_EXPANDED_WIDTH = 135;
const ResponsePane = ({ item, collection }) => {
const dispatch = useDispatch();
@@ -68,10 +68,9 @@ const ResponsePane = ({ item, collection }) => {
dispatch(updateResponseFormat({ uid: item.uid, responseFormat: newFormat }));
}, [dispatch, item.uid]);
- const handleViewTabToggle = useCallback(() => {
- const newViewTab = selectedViewTab === 'editor' ? 'preview' : 'editor';
+ const handleViewTabChange = useCallback((newViewTab) => {
dispatch(updateResponseViewTab({ uid: item.uid, responseViewTab: newViewTab }));
- }, [dispatch, item.uid, selectedViewTab]);
+ }, [dispatch, item.uid]);
const requestTimeline = ([...(collection.timeline || [])]).filter((obj) => {
if (obj.itemUid === item.uid) return true;
@@ -226,15 +225,24 @@ const ResponsePane = ({ item, collection }) => {
onClick={() => setShowScriptErrorCard(true)}
/>
)}
- {focusedTab?.responsePaneTab === 'response' ? (
+ {focusedTab?.responsePaneTab === 'response' && item?.response ? (
<>
-
+ {/* Result View Tabs (Visualizations + Response Format) */}
+
+
+ {/* Response Format */}
+ {
+ handleViewTabChange('editor');
+ }}
+ />
+
>
) : null}
diff --git a/packages/bruno-app/src/ui/ResponsiveTabs/index.js b/packages/bruno-app/src/ui/ResponsiveTabs/index.js
index b6b98d528..b44c7a0b2 100644
--- a/packages/bruno-app/src/ui/ResponsiveTabs/index.js
+++ b/packages/bruno-app/src/ui/ResponsiveTabs/index.js
@@ -8,6 +8,7 @@ const DROPDOWN_WIDTH = 60;
const CALCULATION_DELAY_DEFAULT = 20;
const CALCULATION_DELAY_EXTENDED = 150;
const GAP_BETWEEN_LEFT_AND_RIGHT_CONTENT = 80;
+const EXPANDABLE_HYSTERESIS = 20; // Buffer to prevent flickering at boundary
// Compare two tab arrays by their keys
const areTabArraysEqual = (a, b) => {
@@ -22,7 +23,8 @@ const ResponsiveTabs = ({
rightContent,
rightContentRef,
delayedTabs = [],
- rightContentExpandedWidth // Optional: width of the right content when expanded(used when right content's elements are collapsible)
+ rightContentExpandedWidth, // Optional: width of the expandable element when expanded
+ expandableElementIndex = -1 // Optional: index of the expandable child element (-1 means last child)
}) => {
const [visibleTabs, setVisibleTabs] = useState([]);
const [overflowTabs, setOverflowTabs] = useState([]);
@@ -82,12 +84,47 @@ const ResponsiveTabs = ({
setOverflowTabs((prev) => (areTabArraysEqual(prev, overflow) ? prev : overflow));
// Only calculate expandibility if rightContentExpandedWidth is provided
- if (rightContentExpandedWidth) {
+ if (rightContentExpandedWidth && rightContentRef?.current) {
const leftContentWidth = currentWidth + (overflow.length ? DROPDOWN_WIDTH : 0);
- const expandable = containerWidth - leftContentWidth - GAP_BETWEEN_LEFT_AND_RIGHT_CONTENT > rightContentExpandedWidth;
- setRightSideExpandable((prev) => (prev === expandable ? prev : expandable));
+
+ // Calculate total expanded width by summing children widths
+ // and replacing the expandable element's current width with its expanded width
+ const children = rightContentRef.current.children;
+ const childrenCount = children.length;
+
+ if (childrenCount > 0) {
+ // Resolve the expandable element index (-1 means last child)
+ const targetIndex = expandableElementIndex < 0 ? childrenCount + expandableElementIndex : expandableElementIndex;
+ const validTargetIndex = Math.max(0, Math.min(targetIndex, childrenCount - 1));
+
+ let totalExpandedWidth = 0;
+ for (let i = 0; i < childrenCount; i++) {
+ if (i === validTargetIndex) {
+ // Use the expanded width for the expandable element
+ totalExpandedWidth += rightContentExpandedWidth;
+ } else {
+ // Use the current width for other elements
+ totalExpandedWidth += children[i].offsetWidth;
+ }
+ }
+
+ const availableSpace = containerWidth - leftContentWidth - GAP_BETWEEN_LEFT_AND_RIGHT_CONTENT;
+
+ // Use hysteresis to prevent flickering at boundary
+ // When expanded: only collapse if significantly less space available
+ // When collapsed: expand when there's enough space
+ setRightSideExpandable((prev) => {
+ if (prev) {
+ // Currently expanded - only collapse if space drops below threshold minus hysteresis
+ return availableSpace > totalExpandedWidth - EXPANDABLE_HYSTERESIS;
+ } else {
+ // Currently collapsed - expand if there's enough space
+ return availableSpace > totalExpandedWidth;
+ }
+ });
+ }
}
- }, [tabs, activeTab, rightContentRef, rightContentExpandedWidth]);
+ }, [tabs, activeTab, rightContentRef, rightContentExpandedWidth, expandableElementIndex]);
// Recalculate on tab/activeTab changes
useEffect(() => {