Gregory Schier
2025-07-10 13:49:53 -07:00
parent f63da432b9
commit a31f818424
12 changed files with 66 additions and 43 deletions

View File

@@ -3,6 +3,7 @@ import classNames from 'classnames';
import type { CSSProperties, ReactNode } from 'react';
import React, { useCallback, useMemo } from 'react';
import { useLocalStorage } from 'react-use';
import { useCancelHttpResponse } from '../hooks/useCancelHttpResponse';
import { usePinnedHttpResponse } from '../hooks/usePinnedHttpResponse';
import { useResponseViewMode } from '../hooks/useResponseViewMode';
import { getMimeTypeFromContentType } from '../lib/contentType';
@@ -14,7 +15,7 @@ import { HttpResponseDurationTag } from './core/HttpResponseDurationTag';
import { HotKeyList } from './core/HotKeyList';
import { LoadingIcon } from './core/LoadingIcon';
import { SizeTag } from './core/SizeTag';
import { HStack } from './core/Stacks';
import { HStack, VStack } from './core/Stacks';
import { HttpStatusTag } from './core/HttpStatusTag';
import type { TabItem } from './core/Tabs/Tabs';
import { TabContent, Tabs } from './core/Tabs/Tabs';
@@ -31,6 +32,7 @@ import { PdfViewer } from './responseViewers/PdfViewer';
import { SvgViewer } from './responseViewers/SvgViewer';
import { VideoViewer } from './responseViewers/VideoViewer';
import { ErrorBoundary } from './ErrorBoundary';
import { Button } from './core/Button';
interface Props {
style?: CSSProperties;
@@ -90,6 +92,8 @@ export function HttpResponsePane({ style, className, activeRequestId }: Props) {
[activeRequestId, setActiveTabs],
);
const cancel = useCancelHttpResponse(activeResponse?.id ?? null);
return (
<div
style={style}
@@ -160,7 +164,13 @@ export function HttpResponsePane({ style, className, activeRequestId }: Props) {
<ConfirmLargeResponse response={activeResponse}>
{activeResponse.state === 'initialized' ? (
<EmptyStateText>
<LoadingIcon size="xl" className="text-text-subtlest" />
<VStack space={3}>
<HStack space={3} className="text-lg">
<LoadingIcon size="lg" className="text-text-subtlest" />
Sending Request
</HStack>
<Button variant="border" onClick={() => cancel.mutate()}>Cancel</Button>
</VStack>
</EmptyStateText>
) : activeResponse.state === 'closed' && activeResponse.contentLength === 0 ? (
<EmptyStateText>Empty </EmptyStateText>

View File

@@ -27,7 +27,7 @@ const useFilterText = createGlobalState<Record<string, string | null>>({});
export function TextViewer({ language, text, responseId, requestId, pretty, className }: Props) {
const [filterTextMap, setFilterTextMap] = useFilterText();
const filterText = filterTextMap[requestId] ?? null;
const debouncedFilterText = useDebouncedValue(filterText, 200);
const debouncedFilterText = useDebouncedValue(filterText);
const setFilterText = useCallback(
(v: string | null) => {
setFilterTextMap((m) => ({ ...m, [requestId]: v }));
@@ -58,7 +58,7 @@ export function TextViewer({ language, text, responseId, requestId, pretty, clas
<div key="input" className="w-full !opacity-100">
<Input
key={requestId}
validate={!filteredResponse.error}
validate={!(filteredResponse.error || filteredResponse.data?.error)}
hideLabel
autoFocus
containerClassName="bg-surface"
@@ -79,6 +79,7 @@ export function TextViewer({ language, text, responseId, requestId, pretty, clas
<IconButton
key="icon"
size="sm"
isLoading={filteredResponse.isPending}
icon={isSearching ? 'x' : 'filter'}
title={isSearching ? 'Close filter' : 'Filter response'}
onClick={toggleSearch}
@@ -90,7 +91,9 @@ export function TextViewer({ language, text, responseId, requestId, pretty, clas
}, [
canFilter,
filterText,
filteredResponse.data?.error,
filteredResponse.error,
filteredResponse.isPending,
isSearching,
language,
requestId,
@@ -109,7 +112,7 @@ export function TextViewer({ language, text, responseId, requestId, pretty, clas
if (filteredResponse.error) {
body = '';
} else {
body = filteredResponse.data != null ? filteredResponse.data : '';
body = filteredResponse.data?.content != null ? filteredResponse.data.content : '';
}
} else {
body = formattedBody;