feat: enhance ResponsePane with persisted response format and view tab state management (#6475)

- Added Redux state management for response format and view tab in ResponsePane.
- Implemented useCallback hooks for handling format changes and view tab toggling.
- Updated component to utilize persisted values from Redux, improving user experience by maintaining state across sessions.
This commit is contained in:
Abhishek S Lal
2025-12-22 13:51:19 +05:30
committed by GitHub
parent 3552801ca5
commit 9967d863f5
2 changed files with 54 additions and 18 deletions

View File

@@ -1,8 +1,7 @@
import React, { useState, useEffect, useMemo, useRef } from 'react';
import React, { useState, useEffect, useMemo, useRef, useCallback } from 'react';
import find from 'lodash/find';
import classnames from 'classnames';
import { useDispatch, useSelector } from 'react-redux';
import { updateResponsePaneTab } from 'providers/ReduxStore/slices/tabs';
import { updateResponsePaneTab, updateResponseFormat, updateResponseViewTab } from 'providers/ReduxStore/slices/tabs';
import QueryResult from './QueryResult';
import Overlay from './Overlay';
import Placeholder from './Placeholder';
@@ -35,22 +34,44 @@ const ResponsePane = ({ item, collection }) => {
const activeTabUid = useSelector((state) => state.tabs.activeTabUid);
const isLoading = ['queued', 'sending'].includes(item.requestState);
const [showScriptErrorCard, setShowScriptErrorCard] = useState(false);
const [selectedFormat, setSelectedFormat] = useState('raw');
const [selectedTab, setSelectedTab] = useState('editor');
const rightContentRef = useRef(null);
const response = item.response || {};
// Get the focused tab for reading persisted format/view state
const focusedTab = find(tabs, (t) => t.uid === activeTabUid);
// Initialize format and tab only once when data loads.
const { initialFormat, initialTab } = useInitialResponseFormat(response?.dataBuffer, response?.headers);
const previewFormatOptions = useResponsePreviewFormatOptions(response?.dataBuffer, response?.headers);
const persistedFormat = focusedTab?.responseFormat;
const persistedViewTab = focusedTab?.responseViewTab;
// Use persisted values from Redux, falling back to initial values or defaults
const selectedFormat = persistedFormat ?? initialFormat ?? 'raw';
const selectedViewTab = persistedViewTab ?? initialTab ?? 'editor';
useEffect(() => {
if (initialFormat !== null && initialTab !== null) {
setSelectedFormat(initialFormat);
setSelectedTab(initialTab);
if (!focusedTab || initialFormat === null || initialTab === null) {
return;
}
}, [initialFormat, initialTab]);
if (persistedFormat === null) {
dispatch(updateResponseFormat({ uid: item.uid, responseFormat: initialFormat }));
}
if (persistedViewTab === null) {
dispatch(updateResponseViewTab({ uid: item.uid, responseViewTab: initialTab }));
}
}, [initialFormat, initialTab, persistedFormat, persistedViewTab, focusedTab, item.uid, dispatch]);
const handleFormatChange = useCallback((newFormat) => {
dispatch(updateResponseFormat({ uid: item.uid, responseFormat: newFormat }));
}, [dispatch, item.uid]);
const handleViewTabToggle = useCallback(() => {
const newViewTab = selectedViewTab === 'editor' ? 'preview' : 'editor';
dispatch(updateResponseViewTab({ uid: item.uid, responseViewTab: newViewTab }));
}, [dispatch, item.uid, selectedViewTab]);
const requestTimeline = ([...(collection.timeline || [])]).filter((obj) => {
if (obj.itemUid === item.uid) return true;
@@ -138,7 +159,7 @@ const ResponsePane = ({ item, collection }) => {
error={response.error}
key={item.filename}
selectedFormat={selectedFormat}
selectedTab={selectedTab}
selectedTab={selectedViewTab}
/>
);
}
@@ -193,7 +214,6 @@ const ResponsePane = ({ item, collection }) => {
return <div>Something went wrong</div>;
}
const focusedTab = find(tabs, (t) => t.uid === activeTabUid);
if (!focusedTab || !focusedTab.uid || !focusedTab.responsePaneTab) {
return <div className="pb-4 px-4">An error occurred!</div>;
}
@@ -211,13 +231,9 @@ const ResponsePane = ({ item, collection }) => {
<QueryResultTypeSelector
formatOptions={previewFormatOptions}
formatValue={selectedFormat}
onFormatChange={(newFormat) => {
setSelectedFormat(newFormat);
}}
onPreviewTabSelect={() => {
setSelectedTab((prev) => prev === 'editor' ? 'preview' : 'editor');
}}
selectedTab={selectedTab}
onFormatChange={handleFormatChange}
onPreviewTabSelect={handleViewTabToggle}
selectedTab={selectedViewTab}
/>
</>
) : null}

View File

@@ -59,6 +59,8 @@ export const tabsSlice = createSlice({
requestPaneWidth: null,
requestPaneTab: requestPaneTab || defaultRequestPaneTab,
responsePaneTab: 'response',
responseFormat: null,
responseViewTab: null,
type: type || 'request',
preview: preview !== undefined
? preview
@@ -79,6 +81,8 @@ export const tabsSlice = createSlice({
requestPaneTab: requestPaneTab || defaultRequestPaneTab,
responsePaneTab: 'response',
responsePaneScrollPosition: null,
responseFormat: null,
responseViewTab: null,
type: type || 'request',
...(uid ? { folderUid: uid } : {}),
preview: preview !== undefined
@@ -147,6 +151,20 @@ export const tabsSlice = createSlice({
tab.responsePaneScrollPosition = action.payload.scrollY;
}
},
updateResponseFormat: (state, action) => {
const tab = find(state.tabs, (t) => t.uid === action.payload.uid);
if (tab) {
tab.responseFormat = action.payload.responseFormat;
}
},
updateResponseViewTab: (state, action) => {
const tab = find(state.tabs, (t) => t.uid === action.payload.uid);
if (tab) {
tab.responseViewTab = action.payload.responseViewTab;
}
},
closeTabs: (state, action) => {
const activeTab = find(state.tabs, (t) => t.uid === state.activeTabUid);
const tabUids = action.payload.tabUids || [];
@@ -231,6 +249,8 @@ export const {
updateRequestPaneTab,
updateResponsePaneTab,
updateResponsePaneScrollPosition,
updateResponseFormat,
updateResponseViewTab,
closeTabs,
closeAllCollectionTabs,
makeTabPermanent,