From a62a242133a369aed0eeb0d4058eb05312551946 Mon Sep 17 00:00:00 2001 From: Adam Malczewski Date: Wed, 21 Oct 2026 04:21:57 +0900 Subject: fix(review-7.2): show expired placeholders for missing chat images --- src/features/chat/ui/ChatView.svelte | 24 +++++++++++++++++------- src/features/chat/ui/ChatView.test.ts | 17 ++++++++++++++++- 2 files changed, 33 insertions(+), 8 deletions(-) (limited to 'src/features/chat') diff --git a/src/features/chat/ui/ChatView.svelte b/src/features/chat/ui/ChatView.svelte index f34de9a..b473766 100644 --- a/src/features/chat/ui/ChatView.svelte +++ b/src/features/chat/ui/ChatView.svelte @@ -78,6 +78,7 @@ // True while a show-earlier page-in is awaited (disables the button). let loadingEarlier = $state(false); + let failedImages = $state([]); async function showEarlier() { if (!onShowEarlier || loadingEarlier) return; @@ -161,13 +162,22 @@ {#if rendered.chunk.type === "text"}

{rendered.chunk.text}

{:else if rendered.chunk.type === "image"} - {rendered.chunk.mimeType + {#if failedImages.includes(rendered.chunk.url)} + image expired + {:else} + {rendered.chunk.mimeType { + if (rendered.chunk.type === "image" && rendered.chunk.url.startsWith("/images/")) { + failedImages = [...failedImages, rendered.chunk.url]; + } + }} + class="max-h-80 max-w-full rounded" + /> + {/if} {/if} diff --git a/src/features/chat/ui/ChatView.test.ts b/src/features/chat/ui/ChatView.test.ts index 77f832d..ad50784 100644 --- a/src/features/chat/ui/ChatView.test.ts +++ b/src/features/chat/ui/ChatView.test.ts @@ -1,5 +1,5 @@ import type { StepId } from "@dispatch/wire"; -import { render, screen } from "@testing-library/svelte"; +import { fireEvent, render, screen } from "@testing-library/svelte"; import userEvent from "@testing-library/user-event"; import { describe, expect, it } from "vitest"; import type { RenderedChunk } from "../../../core/chunks"; @@ -497,3 +497,18 @@ it("renders a per-tool Phosphor icon in the header", () => { // Different tools → different glyphs. expect(icons[0]?.innerHTML).not.toBe(icons[1]?.innerHTML); }); + +it("replaces failed persisted images with an expired placeholder, without marking inline images expired", async () => { + const chunks: RenderedChunk[] = ["/images/conv/gone.png", "data:image/png;base64,AAAA"].map( + (url, i) => ({ seq: i + 1, role: "user", chunk: { type: "image", url }, provisional: false }), + ); + render(ChatView, { chunks, apiBaseUrl: "https://backend.test" }); + const [stored, inline] = screen.getAllByRole("img"); + if (!stored || !inline) throw new Error("expected both images"); + expect(stored).toHaveAttribute("src", "https://backend.test/images/conv/gone.png"); + await fireEvent.error(inline); + expect(screen.queryByText("image expired")).toBeNull(); + await fireEvent.error(stored); + expect(screen.getByText("image expired")).toBeInTheDocument(); + expect(screen.getAllByRole("img")).toEqual([inline]); +}); -- cgit v1.2.3