Hide large request bodies by default

This commit is contained in:
Gregory Schier
2025-06-29 07:30:07 -07:00
parent 9b0a767ac8
commit d3cda19be2
2 changed files with 145 additions and 66 deletions

View File

@@ -0,0 +1,76 @@
import type { HttpRequest } from '@yaakapp-internal/models';
import { patchModel } from '@yaakapp-internal/models';
import { type ReactNode } from 'react';
import { useToggle } from '../hooks/useToggle';
import { showConfirm } from '../lib/confirm';
import { Banner } from './core/Banner';
import { Button } from './core/Button';
import { InlineCode } from './core/InlineCode';
import { Link } from './core/Link';
import { SizeTag } from './core/SizeTag';
import { HStack } from './core/Stacks';
interface Props {
children: ReactNode;
request: HttpRequest;
}
const LARGE_TEXT_BYTES = 2 * 1000 * 1000;
export function ConfirmLargeRequestBody({ children, request }: Props) {
const [showLargeResponse, toggleShowLargeResponse] = useToggle();
if (request.body?.text == null) {
return children;
}
const contentLength = request.body.text.length ?? 0;
const tooLargeBytes = LARGE_TEXT_BYTES;
const isLarge = contentLength > tooLargeBytes;
if (!showLargeResponse && isLarge) {
return (
<Banner color="primary" className="flex flex-col gap-3">
<p>
Rendering content over{' '}
<InlineCode>
<SizeTag contentLength={tooLargeBytes} />
</InlineCode>{' '}
may impact performance.
</p>
<p>
See{' '}
<Link href="https://feedback.yaak.app/en/help/articles/1198684-working-with-large-values">
Working With Large Values
</Link>{' '}
for tips.
</p>
<HStack wrap space={2}>
<Button color="primary" size="xs" onClick={toggleShowLargeResponse}>
Reveal Body
</Button>
<Button
color="danger"
size="xs"
variant="border"
onClick={async () => {
const confirm = await showConfirm({
id: 'delete-body-' + request.id,
confirmText: 'Delete Body',
title: 'Delete Body Text',
description: 'Are you sure you want to delete the request body text?',
color: 'danger',
});
if (confirm) {
await patchModel(request, { body: { ...request.body, text: '' } });
}
}}
>
Delete Body
</Button>
</HStack>
</Banner>
);
}
return <>{children}</>;
}

View File

@@ -35,6 +35,7 @@ import { prepareImportQuerystring } from '../lib/prepareImportQuerystring';
import { resolvedModelName } from '../lib/resolvedModelName';
import { showToast } from '../lib/toast';
import { BinaryFileEditor } from './BinaryFileEditor';
import { ConfirmLargeRequestBody } from './ConfirmLargeRequestBody';
import { CountBadge } from './core/CountBadge';
import { Editor } from './core/Editor/Editor';
import type { GenericCompletionConfig } from './core/Editor/genericCompletion';
@@ -373,72 +374,74 @@ export function HttpRequestPane({ style, fullHeight, className, activeRequest }:
/>
</TabContent>
<TabContent value={TAB_BODY}>
{activeRequest.bodyType === BODY_TYPE_JSON ? (
<Editor
forceUpdateKey={forceUpdateKey}
autocompleteFunctions
autocompleteVariables
placeholder="..."
heightMode={fullHeight ? 'full' : 'auto'}
defaultValue={`${activeRequest.body?.text ?? ''}`}
language="json"
onChange={handleBodyTextChange}
stateKey={`json.${activeRequest.id}`}
/>
) : activeRequest.bodyType === BODY_TYPE_XML ? (
<Editor
forceUpdateKey={forceUpdateKey}
autocompleteFunctions
autocompleteVariables
placeholder="..."
heightMode={fullHeight ? 'full' : 'auto'}
defaultValue={`${activeRequest.body?.text ?? ''}`}
language="xml"
onChange={handleBodyTextChange}
stateKey={`xml.${activeRequest.id}`}
/>
) : activeRequest.bodyType === BODY_TYPE_GRAPHQL ? (
<GraphQLEditor
forceUpdateKey={forceUpdateKey}
baseRequest={activeRequest}
request={activeRequest}
onChange={handleBodyChange}
/>
) : activeRequest.bodyType === BODY_TYPE_FORM_URLENCODED ? (
<FormUrlencodedEditor
forceUpdateKey={forceUpdateKey}
request={activeRequest}
onChange={handleBodyChange}
/>
) : activeRequest.bodyType === BODY_TYPE_FORM_MULTIPART ? (
<FormMultipartEditor
forceUpdateKey={forceUpdateKey}
request={activeRequest}
onChange={handleBodyChange}
/>
) : activeRequest.bodyType === BODY_TYPE_BINARY ? (
<BinaryFileEditor
requestId={activeRequest.id}
contentType={contentType}
body={activeRequest.body}
onChange={(body) => patchModel(activeRequest, { body })}
onChangeContentType={handleContentTypeChange}
/>
) : typeof activeRequest.bodyType === 'string' ? (
<Editor
forceUpdateKey={forceUpdateKey}
autocompleteFunctions
autocompleteVariables
language={languageFromContentType(contentType)}
placeholder="..."
heightMode={fullHeight ? 'full' : 'auto'}
defaultValue={`${activeRequest.body?.text ?? ''}`}
onChange={handleBodyTextChange}
stateKey={`other.${activeRequest.id}`}
/>
) : (
<EmptyStateText>No Body</EmptyStateText>
)}
<ConfirmLargeRequestBody request={activeRequest}>
{activeRequest.bodyType === BODY_TYPE_JSON ? (
<Editor
forceUpdateKey={forceUpdateKey}
autocompleteFunctions
autocompleteVariables
placeholder="..."
heightMode={fullHeight ? 'full' : 'auto'}
defaultValue={`${activeRequest.body?.text ?? ''}`}
language="json"
onChange={handleBodyTextChange}
stateKey={`json.${activeRequest.id}`}
/>
) : activeRequest.bodyType === BODY_TYPE_XML ? (
<Editor
forceUpdateKey={forceUpdateKey}
autocompleteFunctions
autocompleteVariables
placeholder="..."
heightMode={fullHeight ? 'full' : 'auto'}
defaultValue={`${activeRequest.body?.text ?? ''}`}
language="xml"
onChange={handleBodyTextChange}
stateKey={`xml.${activeRequest.id}`}
/>
) : activeRequest.bodyType === BODY_TYPE_GRAPHQL ? (
<GraphQLEditor
forceUpdateKey={forceUpdateKey}
baseRequest={activeRequest}
request={activeRequest}
onChange={handleBodyChange}
/>
) : activeRequest.bodyType === BODY_TYPE_FORM_URLENCODED ? (
<FormUrlencodedEditor
forceUpdateKey={forceUpdateKey}
request={activeRequest}
onChange={handleBodyChange}
/>
) : activeRequest.bodyType === BODY_TYPE_FORM_MULTIPART ? (
<FormMultipartEditor
forceUpdateKey={forceUpdateKey}
request={activeRequest}
onChange={handleBodyChange}
/>
) : activeRequest.bodyType === BODY_TYPE_BINARY ? (
<BinaryFileEditor
requestId={activeRequest.id}
contentType={contentType}
body={activeRequest.body}
onChange={(body) => patchModel(activeRequest, { body })}
onChangeContentType={handleContentTypeChange}
/>
) : typeof activeRequest.bodyType === 'string' ? (
<Editor
forceUpdateKey={forceUpdateKey}
autocompleteFunctions
autocompleteVariables
language={languageFromContentType(contentType)}
placeholder="..."
heightMode={fullHeight ? 'full' : 'auto'}
defaultValue={`${activeRequest.body?.text ?? ''}`}
onChange={handleBodyTextChange}
stateKey={`other.${activeRequest.id}`}
/>
) : (
<EmptyStateText>No Body</EmptyStateText>
)}
</ConfirmLargeRequestBody>
</TabContent>
<TabContent value={TAB_DESCRIPTION}>
<div className="grid grid-rows-[auto_minmax(0,1fr)] h-full">