diff --git a/apps/yaak-client/components/HttpResponsePane.tsx b/apps/yaak-client/components/HttpResponsePane.tsx index 645de078..9df20748 100644 --- a/apps/yaak-client/components/HttpResponsePane.tsx +++ b/apps/yaak-client/components/HttpResponsePane.tsx @@ -8,6 +8,7 @@ import { useCopyHttpResponse } from "../hooks/useCopyHttpResponse"; import { useHttpResponseEvents } from "../hooks/useHttpResponseEvents"; import { usePinnedHttpResponse } from "../hooks/usePinnedHttpResponse"; import { useResponseBodyBytes, useResponseBodyText } from "../hooks/useResponseBodyText"; +import { useResponseBodyUrl } from "../hooks/useResponseBodyUrl"; import { useResponseViewMode } from "../hooks/useResponseViewMode"; import { useSaveResponse } from "../hooks/useSaveResponse"; import { useTimelineViewMode } from "../hooks/useTimelineViewMode"; @@ -409,14 +410,13 @@ function EnsureCompleteResponse({ Component, }: { response: HttpResponse; - Component: ComponentType<{ bodyPath: string }>; + Component: ComponentType<{ url: string }>; }) { - if (response.bodyPath === null) { - return
Empty response body
; - } + // Wait until the response has been fully-downloaded before asking for it + const complete = response.state === "closed"; + const bodyUrl = useResponseBodyUrl(complete ? response : null); - // Wait until the response has been fully-downloaded - if (response.state !== "closed") { + if (!complete || bodyUrl.isPending) { return ( @@ -424,7 +424,15 @@ function EnsureCompleteResponse({ ); } - return ; + if (bodyUrl.error) { + return {String(bodyUrl.error)}; + } + + if (bodyUrl.data == null) { + return
Empty response body
; + } + + return ; } function HttpSvgViewer({ response }: { response: HttpResponse }) { diff --git a/apps/yaak-client/components/responseViewers/AudioViewer.tsx b/apps/yaak-client/components/responseViewers/AudioViewer.tsx index 89f102de..880e7649 100644 --- a/apps/yaak-client/components/responseViewers/AudioViewer.tsx +++ b/apps/yaak-client/components/responseViewers/AudioViewer.tsx @@ -1,29 +1,29 @@ import { useEffect, useState } from "react"; -import { platform } from "@yaakapp-internal/platform"; interface Props { - bodyPath?: string; + /** A URL the host resolved, for a body it already stored. */ + url?: string; data?: Uint8Array; mimeType?: string; } -export function AudioViewer({ bodyPath, data, mimeType }: Props) { +export function AudioViewer({ url, data, mimeType }: Props) { const [src, setSrc] = useState(); useEffect(() => { - if (bodyPath) { - setSrc(platform.files.url(bodyPath)); + if (url) { + setSrc(url); } else if (data) { // The type matters here in a way it doesn't for an image: a media element goes by what // the blob declares rather than sniffing it, so an Ogg labelled as MP3 won't play const blob = new Blob([new Uint8Array(data)], { type: mimeType ?? "audio/mpeg" }); - const url = URL.createObjectURL(blob); - setSrc(url); - return () => URL.revokeObjectURL(url); + const objectUrl = URL.createObjectURL(blob); + setSrc(objectUrl); + return () => URL.revokeObjectURL(objectUrl); } else { setSrc(undefined); } - }, [bodyPath, data, mimeType]); + }, [url, data, mimeType]); // oxlint-disable-next-line jsx-a11y/media-has-caption return