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)
)}
);
}