import {MouseEvent, useEffect} from 'react'; import queryString from 'query-string'; import ObjectInspector from 'sentry/components/objectInspector'; import {t, tct} from 'sentry/locale'; import {formatBytesBase10} from 'sentry/utils'; import useCrumbHandlers from 'sentry/utils/replays/hooks/useCrumbHandlers'; import { Indent, keyValueTableOrNotFound, SectionItem, SizeTooltip, Warning, } from 'sentry/views/replays/detail/network/details/components'; import {useDismissReqRespBodiesAlert} from 'sentry/views/replays/detail/network/details/onboarding'; import TimestampButton from 'sentry/views/replays/detail/timestampButton'; import type {NetworkSpan} from 'sentry/views/replays/types'; export type SectionProps = { item: NetworkSpan; projectId: string; startTimestampMs: number; }; export function GeneralSection({item, startTimestampMs}: SectionProps) { const {handleClick} = useCrumbHandlers(startTimestampMs); const startMs = item.startTimestamp * 1000; const endMs = item.endTimestamp * 1000; const data = { [t('URL')]: item.description, [t('Type')]: item.op, [t('Method')]: item.data?.method ?? '', [t('Status Code')]: item.data?.statusCode ?? '', [t('Request Body Size')]: ( {formatBytesBase10(item.data?.request?.size ?? 0)} ), [t('Response Body Size')]: ( {formatBytesBase10(item.data?.response?.size ?? 0)} ), [t('Duration')]: `${(endMs - startMs).toFixed(2)}ms`, [t('Timestamp')]: ( { event.stopPropagation(); handleClick(item); }} startTimestampMs={startTimestampMs} timestampMs={startMs} /> ), }; return ( {keyValueTableOrNotFound(data, t('Missing request details'))} ); } export function RequestHeadersSection({item}: SectionProps) { return ( {keyValueTableOrNotFound(item.data?.request?.headers, t('Headers not captured'))} ); } export function ResponseHeadersSection({item}: SectionProps) { return ( {keyValueTableOrNotFound(item.data?.request?.headers, t('Headers not captured'))} ); } export function QueryParamsSection({item}: SectionProps) { const queryParams = queryString.parse(item.description?.split('?')?.[1] ?? ''); return ( ); } export function RequestPayloadSection({item}: SectionProps) { const {dismiss, isDismissed} = useDismissReqRespBodiesAlert(); const hasRequest = 'request' in item.data; useEffect(() => { if (!isDismissed && hasRequest) { dismiss(); } }, [dismiss, hasRequest, isDismissed]); return ( {t('Size:')} {formatBytesBase10(item.data?.request?.size ?? 0)} } > {hasRequest ? ( ) : ( tct('Request body not found.', item.data) )} ); } export function ResponsePayloadSection({item}: SectionProps) { const {dismiss, isDismissed} = useDismissReqRespBodiesAlert(); const hasResponse = 'response' in item.data; useEffect(() => { if (!isDismissed && hasResponse) { dismiss(); } }, [dismiss, hasResponse, isDismissed]); return ( {t('Size:')} {formatBytesBase10(item.data?.response?.size ?? 0)} } > {hasResponse ? ( ) : ( tct('Response body not found.', item.data) )} ); }