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