import { type GrpcRequest, type HttpRequestHeader, patchModel } from '@yaakapp-internal/models'; import classNames from 'classnames'; import type { CSSProperties } from 'react'; import { useCallback, useMemo, useRef } from 'react'; import { useAuthTab } from '../hooks/useAuthTab'; import { useContainerSize } from '../hooks/useContainerQuery'; import type { ReflectResponseService } from '../hooks/useGrpc'; import { useHeadersTab } from '../hooks/useHeadersTab'; import { useInheritedHeaders } from '../hooks/useInheritedHeaders'; import { useRequestUpdateKey } from '../hooks/useRequestUpdateKey'; import { resolvedModelName } from '../lib/resolvedModelName'; import { Button } from './core/Button'; import { CountBadge } from './core/CountBadge'; import { Icon } from './core/Icon'; import { IconButton } from './core/IconButton'; import { PlainInput } from './core/PlainInput'; import { RadioDropdown } from './core/RadioDropdown'; import { HStack, VStack } from './core/Stacks'; import type { TabItem } from './core/Tabs/Tabs'; import { TabContent, Tabs } from './core/Tabs/Tabs'; import { GrpcEditor } from './GrpcEditor'; import { HeadersEditor } from './HeadersEditor'; import { HttpAuthenticationEditor } from './HttpAuthenticationEditor'; import { MarkdownEditor } from './MarkdownEditor'; import { UrlBar } from './UrlBar'; interface Props { style?: CSSProperties; className?: string; activeRequest: GrpcRequest; protoFiles: string[]; reflectionError?: string; reflectionLoading?: boolean; methodType: | 'unary' | 'client_streaming' | 'server_streaming' | 'streaming' | 'no-schema' | 'no-method'; isStreaming: boolean; onCommit: () => void; onCancel: () => void; onSend: (v: { message: string }) => void; onGo: () => void; services: ReflectResponseService[] | null; } const TAB_MESSAGE = 'message'; const TAB_METADATA = 'metadata'; const TAB_AUTH = 'auth'; const TAB_DESCRIPTION = 'description'; export function GrpcRequestPane({ style, services, methodType, activeRequest, protoFiles, reflectionError, reflectionLoading, isStreaming, onGo, onCommit, onCancel, onSend, }: Props) { const authTab = useAuthTab(TAB_AUTH, activeRequest); const metadataTab = useHeadersTab(TAB_METADATA, activeRequest, 'Metadata'); const inheritedHeaders = useInheritedHeaders(activeRequest); const forceUpdateKey = useRequestUpdateKey(activeRequest.id ?? null); const urlContainerEl = useRef(null); const { width: paneWidth } = useContainerSize(urlContainerEl); const handleChangeUrl = useCallback( (url: string) => patchModel(activeRequest, { url }), [activeRequest], ); const handleChangeMessage = useCallback( (message: string) => patchModel(activeRequest, { message }), [activeRequest], ); const select = useMemo(() => { const options = services?.flatMap((s) => s.methods.map((m) => ({ label: `${s.name.split('.').pop() ?? s.name}/${m.name}`, value: `${s.name}/${m.name}`, })), ) ?? []; const value = `${activeRequest?.service ?? ''}/${activeRequest?.method ?? ''}`; return { value, options }; }, [activeRequest?.method, activeRequest?.service, services]); const handleChangeService = useCallback( async (v: string) => { const [serviceName, methodName] = v.split('/', 2); if (serviceName == null || methodName == null) throw new Error('Should never happen'); await patchModel(activeRequest, { service: serviceName, method: methodName, }); }, [activeRequest], ); const handleConnect = useCallback(async () => { if (activeRequest == null) return; if (activeRequest.service == null || activeRequest.method == null) { alert({ id: 'grpc-invalid-service-method', title: 'Error', body: 'Service or method not selected', }); } onGo(); }, [activeRequest, onGo]); const handleSend = useCallback(async () => { if (activeRequest == null) return; onSend({ message: activeRequest.message }); }, [activeRequest, onSend]); const tabs: TabItem[] = useMemo( () => [ { value: TAB_MESSAGE, label: 'Message' }, ...metadataTab, ...authTab, { value: TAB_DESCRIPTION, label: 'Info', rightSlot: activeRequest.description && , }, ], [activeRequest.description, authTab, metadataTab], ); const handleMetadataChange = useCallback( (metadata: HttpRequestHeader[]) => patchModel(activeRequest, { metadata }), [activeRequest], ); const handleDescriptionChange = useCallback( (description: string) => patchModel(activeRequest, { description }), [activeRequest], ); return (
0 && paneWidth < 400 && '!grid-cols-1', )} > ({ label: o.label, value: o.value, type: 'default', shortLabel: o.label, }))} itemsAfter={[ { label: 'Refresh', type: 'default', leftSlot: , }, ]} > {methodType === 'client_streaming' || methodType === 'streaming' ? ( <> {isStreaming && ( <> )} ) : ( )}
patchModel(activeRequest, { name })} />
); }