Persist response filter per request

This commit is contained in:
Gregory Schier
2026-06-11 09:09:12 -07:00
parent 1b28dfd9d1
commit 3de9a1edd4
2 changed files with 19 additions and 8 deletions
@@ -69,6 +69,7 @@ function HttpTextViewer({ response, text, language, pretty, className }: HttpTex
text={text} text={text}
language={language} language={language}
stateKey={`response.body.${response.id}`} stateKey={`response.body.${response.id}`}
filterStateKey={`response.body.${response.requestId}`}
pretty={pretty} pretty={pretty}
className={className} className={className}
onFilter={filterCallback} onFilter={filterCallback}
@@ -16,6 +16,7 @@ interface Props {
text: string; text: string;
language: EditorProps["language"]; language: EditorProps["language"];
stateKey: string | null; stateKey: string | null;
filterStateKey?: string | null;
pretty?: boolean; pretty?: boolean;
className?: string; className?: string;
onFilter?: (filter: string) => { onFilter?: (filter: string) => {
@@ -27,16 +28,25 @@ interface Props {
const useFilterText = createGlobalState<Record<string, string | null>>({}); const useFilterText = createGlobalState<Record<string, string | null>>({});
export function TextViewer({ language, text, stateKey, pretty, className, onFilter }: Props) { export function TextViewer({
language,
text,
stateKey,
filterStateKey,
pretty,
className,
onFilter,
}: Props) {
const filterKey = filterStateKey ?? stateKey;
const [filterTextMap, setFilterTextMap] = useFilterText(); const [filterTextMap, setFilterTextMap] = useFilterText();
const filterText = stateKey ? (filterTextMap[stateKey] ?? null) : null; const filterText = filterKey ? (filterTextMap[filterKey] ?? null) : null;
const debouncedFilterText = useDebouncedValue(filterText); const debouncedFilterText = useDebouncedValue(filterText);
const setFilterText = useCallback( const setFilterText = useCallback(
(v: string | null) => { (v: string | null) => {
if (!stateKey) return; if (!filterKey) return;
setFilterTextMap((m) => ({ ...m, [stateKey]: v })); setFilterTextMap((m) => ({ ...m, [filterKey]: v }));
}, },
[setFilterTextMap, stateKey], [filterKey, setFilterTextMap],
); );
const isSearching = filterText != null; const isSearching = filterText != null;
@@ -64,7 +74,7 @@ export function TextViewer({ language, text, stateKey, pretty, className, onFilt
nodes.push( nodes.push(
<div key="input" className="w-full !opacity-100"> <div key="input" className="w-full !opacity-100">
<Input <Input
key={stateKey ?? "filter"} key={filterKey ?? "filter"}
validate={!filteredResponse.error} validate={!filteredResponse.error}
hideLabel hideLabel
autoFocus autoFocus
@@ -76,7 +86,7 @@ export function TextViewer({ language, text, stateKey, pretty, className, onFilt
defaultValue={filterText} defaultValue={filterText}
onKeyDown={(e) => e.key === "Escape" && toggleSearch()} onKeyDown={(e) => e.key === "Escape" && toggleSearch()}
onChange={setFilterText} onChange={setFilterText}
stateKey={stateKey ? `filter.${stateKey}` : null} stateKey={filterKey ? `filter.${filterKey}` : null}
/> />
</div>, </div>,
); );
@@ -97,12 +107,12 @@ export function TextViewer({ language, text, stateKey, pretty, className, onFilt
return nodes; return nodes;
}, [ }, [
canFilter, canFilter,
filterKey,
filterText, filterText,
filteredResponse.error, filteredResponse.error,
filteredResponse.isPending, filteredResponse.isPending,
isSearching, isSearching,
language, language,
stateKey,
setFilterText, setFilterText,
toggleSearch, toggleSearch,
]); ]);