import { formatSize } from "@yaakapp-internal/lib/formatSize"; import type { Flow } from "@yaakapp-internal/proxy-lib"; import { DetailsBanner, formatMillis, HeadersTable, KeyValueRow, KeyValueRows, } from "@yaakapp-internal/ui"; import { useMemo } from "react"; import { EmptyState } from "./FlowBodyViewer"; const startedFormat = new Intl.DateTimeFormat("en-US", { month: "short", day: "numeric", year: "numeric", hour: "numeric", minute: "2-digit", second: "2-digit", fractionalSecondDigits: 3, timeZoneName: "short", }); const bytesFormat = new Intl.NumberFormat("en-US"); export function FlowHeaders({ flow }: { flow: Flow }) { const versions = flow.upstreamHttpVersion == null ? `${flow.clientHttpVersion} from the app` : `${flow.clientHttpVersion} from the app, ${flow.upstreamHttpVersion} to the server`; return (
Info}> {startedFormat.format(new Date(`${flow.startedAt}Z`))} {flow.url} {flow.remoteAddr ?? } {versions} {flow.elapsedMs == null ? ( ) : flow.elapsedHeadersMs == null ? ( `${formatMillis(flow.elapsedMs)} in all` ) : ( `${formatMillis(flow.elapsedMs)} in all, headers after ${formatMillis(flow.elapsedHeadersMs)}` )} {formatSize(flow.requestSize)} sent, {formatSize(flow.responseSize)} received{" "} ({bytesFormat.format(flow.responseSize)} B)
); } export function FlowQuery({ flow }: { flow: Flow }) { const params = useMemo(() => queryParams(flow.url), [flow.url]); if (params.length === 0) { return No query parameters; } return (
{params.map(([name, value], i) => ( // oxlint-disable-next-line react/no-array-index-key -- a name can repeat {value} ))}
); } export function queryParams(url: string): [string, string][] { try { return [...new URL(url).searchParams.entries()]; } catch { return []; } } function Missing() { return --; }