diff --git a/src/components/admin/review-row.tsx b/src/components/admin/review-row.tsx
index e8a3d8c..b923dbd 100644
--- a/src/components/admin/review-row.tsx
+++ b/src/components/admin/review-row.tsx
@@ -18,6 +18,29 @@ import { Checkbox } from "@/components/ui/checkbox"
import type { SchemaNode } from "@/lib/schema-types"
import { DISPLAY_KEY_FALLBACKS, pickString } from "@/lib/node-display"
import { useUserStore } from "@/stores/user-store"
+
+const IMAGE_FIELD_KEY = "image_url"
+
+function ProposedChangeValue({ fieldKey, value }: { fieldKey: string; value: unknown }) {
+ const [imgError, setImgError] = useState(false)
+ const strValue = String(value)
+
+ if (fieldKey === IMAGE_FIELD_KEY && typeof value === "string" && value.length > 0 && !imgError) {
+ return (
+
+ {/* eslint-disable-next-line @next/next/no-img-element */}
+

setImgError(true)}
+ />
+
+ )
+ }
+
+ return {strValue}
+}
import { useGraphStore } from "@/stores/graph-store"
// ── Status badge ──────────────────────────────────────────────────────────────
@@ -1001,7 +1024,7 @@ export function ReviewRow({
{changedEntries.map(([k, v]) => (
<>
{k}
- {String(v)}
+
>
))}
diff --git a/src/lib/__tests__/reviews.test.tsx b/src/lib/__tests__/reviews.test.tsx
index 83117a1..fcc72b8 100644
--- a/src/lib/__tests__/reviews.test.tsx
+++ b/src/lib/__tests__/reviews.test.tsx
@@ -761,6 +761,87 @@ describe("ReviewRow", () => {
expect(getByText("Node Being Edited")).toBeTruthy()
})
+ // ── edit_node image_url preview ───────────────────────────────────────────
+
+ it("edit_node image_url change renders an img with the proposed URL as src", async () => {
+ const user = userEvent.setup()
+ const imgUrl = "https://example.com/photo.jpg"
+ const { getByText, container } = render(
+
+ )
+ await user.click(getByText("Edit Alice"))
+ const img = container.querySelector("img[alt='image preview']") as HTMLImageElement
+ expect(img).toBeTruthy()
+ expect(img.src).toBe(imgUrl)
+ })
+
+ it("edit_node non-image properties still render as plain text", async () => {
+ const user = userEvent.setup()
+ const { getByText } = render(
+
+ )
+ await user.click(getByText("Edit Bob"))
+ expect(getByText("Bob Updated")).toBeTruthy()
+ })
+
+ it("edit_node image_url falls back to URL string on image load error", async () => {
+ const user = userEvent.setup()
+ const brokenUrl = "https://example.invalid/content-c5-broken.jpg"
+ const { getByText, container } = render(
+
+ )
+ await user.click(getByText("Edit Charlie"))
+ // Trigger the error handler
+ const img = container.querySelector("img[alt='image preview']") as HTMLImageElement
+ expect(img).toBeTruthy()
+ fireEvent.error(img)
+ // After error, the img should be replaced by the raw URL string
+ expect(getByText(brokenUrl)).toBeTruthy()
+ expect(container.querySelector("img[alt='image preview']")).toBeNull()
+ })
+
// ── add_schema_node_type ──────────────────────────────────────────────────
it("renders add_schema_node_type row without crashing with valid payload", () => {