import classNames from 'classnames'; import type { CSSProperties, FormEvent } from 'react'; import { memo, useCallback, useMemo, useState } from 'react'; import { createGlobalState } from 'react-use'; import { useActiveRequest } from '../hooks/useActiveRequest'; import { useIsResponseLoading } from '../hooks/useIsResponseLoading'; import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey'; import { useSendRequest } from '../hooks/useSendRequest'; import { useUpdateHttpRequest } from '../hooks/useUpdateHttpRequest'; import { tryFormatJson } from '../lib/formatters'; import type { HttpHeader, HttpRequest, HttpUrlParameter } from '../lib/models'; import { AUTH_TYPE_BASIC, AUTH_TYPE_BEARER, AUTH_TYPE_NONE, BODY_TYPE_FORM_MULTIPART, BODY_TYPE_FORM_URLENCODED, BODY_TYPE_GRAPHQL, BODY_TYPE_JSON, BODY_TYPE_NONE, BODY_TYPE_XML, } from '../lib/models'; import { BasicAuth } from './BasicAuth'; import { BearerAuth } from './BearerAuth'; import { CountBadge } from './core/CountBadge'; import { Editor } from './core/Editor'; import type { TabItem } from './core/Tabs/Tabs'; import { TabContent, Tabs } from './core/Tabs/Tabs'; import { EmptyStateText } from './EmptyStateText'; import { FormMultipartEditor } from './FormMultipartEditor'; import { FormUrlencodedEditor } from './FormUrlencodedEditor'; import { GraphQLEditor } from './GraphQLEditor'; import { HeadersEditor } from './HeadersEditor'; import { UrlBar } from './UrlBar'; import { UrlParametersEditor } from './UrlParameterEditor'; interface Props { style: CSSProperties; fullHeight: boolean; className?: string; } const useActiveTab = createGlobalState('body'); export const RequestPane = memo(function RequestPane({ style, fullHeight, className }: Props) { const activeRequest = useActiveRequest('http_request'); const activeRequestId = activeRequest?.id ?? null; const updateRequest = useUpdateHttpRequest(activeRequestId); const [activeTab, setActiveTab] = useActiveTab(); const [forceUpdateHeaderEditorKey, setForceUpdateHeaderEditorKey] = useState(0); const { updateKey: forceUpdateKey } = useRequestUpdateKey(activeRequest?.id ?? null); const tabs: TabItem[] = useMemo( () => activeRequest === null ? [] : [ { value: 'body', options: { value: activeRequest.bodyType, items: [ { type: 'separator', label: 'Form Data' }, { label: 'Url Encoded', value: BODY_TYPE_FORM_URLENCODED }, { label: 'Multi-Part', value: BODY_TYPE_FORM_MULTIPART }, { type: 'separator', label: 'Text Content' }, { label: 'JSON', value: BODY_TYPE_JSON }, { label: 'XML', value: BODY_TYPE_XML }, { label: 'GraphQL', value: BODY_TYPE_GRAPHQL }, { type: 'separator', label: 'Other' }, { label: 'No Body', shortLabel: 'Body', value: BODY_TYPE_NONE }, ], onChange: async (bodyType) => { const patch: Partial = { bodyType }; if (bodyType === BODY_TYPE_NONE) { patch.headers = activeRequest?.headers.filter( (h) => h.name.toLowerCase() !== 'content-type', ); } else if ( bodyType === BODY_TYPE_FORM_URLENCODED || bodyType === BODY_TYPE_FORM_MULTIPART || bodyType === BODY_TYPE_JSON || bodyType === BODY_TYPE_XML ) { patch.method = 'POST'; patch.headers = [ ...(activeRequest?.headers.filter( (h) => h.name.toLowerCase() !== 'content-type', ) ?? []), { name: 'Content-Type', value: bodyType, enabled: true, }, ]; } else if (bodyType == BODY_TYPE_GRAPHQL) { patch.method = 'POST'; patch.headers = [ ...(activeRequest?.headers.filter( (h) => h.name.toLowerCase() !== 'content-type', ) ?? []), { name: 'Content-Type', value: 'application/json', enabled: true, }, ]; } // Force update header editor so any changed headers are reflected setTimeout(() => setForceUpdateHeaderEditorKey((u) => u + 1), 100); updateRequest.mutate(patch); }, }, }, { value: 'params', label: (
Params p.name).length} />
), }, { value: 'headers', label: (
Headers h.name).length} />
), }, { value: 'auth', label: 'Auth', options: { value: activeRequest.authenticationType, items: [ { label: 'Basic Auth', shortLabel: 'Basic', value: AUTH_TYPE_BASIC }, { label: 'Bearer Token', shortLabel: 'Bearer', value: AUTH_TYPE_BEARER }, { type: 'separator' }, { label: 'No Authentication', shortLabel: 'Auth', value: AUTH_TYPE_NONE }, ], onChange: async (authenticationType) => { let authentication: HttpRequest['authentication'] = activeRequest?.authentication; if (authenticationType === AUTH_TYPE_BASIC) { authentication = { username: authentication.username ?? '', password: authentication.password ?? '', }; } else if (authenticationType === AUTH_TYPE_BEARER) { authentication = { token: authentication.token ?? '', }; } updateRequest.mutate({ authenticationType, authentication }); }, }, }, ], [activeRequest, updateRequest], ); const handleBodyChange = useCallback( (body: HttpRequest['body']) => updateRequest.mutate({ body }), [updateRequest], ); const handleBodyTextChange = useCallback( (text: string) => updateRequest.mutate({ body: { text } }), [updateRequest], ); const handleHeadersChange = useCallback( (headers: HttpHeader[]) => updateRequest.mutate({ headers }), [updateRequest], ); const handleUrlParametersChange = useCallback( (urlParameters: HttpUrlParameter[]) => updateRequest.mutate({ urlParameters }), [updateRequest], ); const sendRequest = useSendRequest(activeRequest?.id ?? null); const handleSend = useCallback( async (e: FormEvent) => { e.preventDefault(); await sendRequest.mutateAsync(); }, [sendRequest], ); const handleMethodChange = useCallback( (method: string) => updateRequest.mutate({ method }), [updateRequest], ); const handleUrlChange = useCallback( (url: string) => updateRequest.mutate({ url }), [updateRequest], ); const isLoading = useIsResponseLoading(activeRequestId ?? null); const { updateKey } = useRequestUpdateKey(activeRequestId ?? null); return (
{activeRequest && ( <> {activeRequest.authenticationType === AUTH_TYPE_BASIC ? ( ) : activeRequest.authenticationType === AUTH_TYPE_BEARER ? ( ) : ( No Authentication {activeRequest.authenticationType} )} {activeRequest.bodyType === BODY_TYPE_JSON ? ( ) : activeRequest.bodyType === BODY_TYPE_XML ? ( ) : activeRequest.bodyType === BODY_TYPE_GRAPHQL ? ( ) : activeRequest.bodyType === BODY_TYPE_FORM_URLENCODED ? ( ) : activeRequest.bodyType === BODY_TYPE_FORM_MULTIPART ? ( ) : ( No Body )} )}
); });