-

- {path &&
{path}
}
+ {imageError ? (
+
+ ⚠️ {imageError}
+
+ ) : (
+

+ )}
+ {imagePath && (
+
{formatDisplayPath(imagePath)}
+ )}
{showControls && isHovering && (
setIsDragging(false)}
onMouseLeave={() => setIsDragging(false)}>
- {path && (
+ {imagePath && (
diff --git a/webview-ui/src/components/common/__tests__/ImageViewer.spec.tsx b/webview-ui/src/components/common/__tests__/ImageViewer.spec.tsx
new file mode 100644
index 0000000000..5f85978b74
--- /dev/null
+++ b/webview-ui/src/components/common/__tests__/ImageViewer.spec.tsx
@@ -0,0 +1,116 @@
+// npx vitest run src/components/common/__tests__/ImageViewer.spec.tsx
+
+import { render, fireEvent } from "@testing-library/react"
+import { describe, it, expect, vi } from "vitest"
+import { ImageViewer } from "../ImageViewer"
+
+// Mock vscode API
+vi.mock("@src/utils/vscode", () => ({
+ vscode: {
+ postMessage: vi.fn(),
+ },
+}))
+
+// Import the mocked vscode after the mock is set up
+import { vscode } from "@src/utils/vscode"
+
+describe("ImageViewer", () => {
+ it("should render image with webview URI", () => {
+ const webviewUri = "https://file+.vscode-resource.vscode-cdn.net/path/to/image.png"
+ const { container } = render()
+
+ const img = container.querySelector("img")
+ expect(img).toBeTruthy()
+ expect(img?.src).toBe(webviewUri)
+ expect(img?.alt).toBe("Test image")
+ })
+
+ it("should render image with vscode-resource URI", () => {
+ const vscodeResourceUri = "vscode-resource://file///path/to/image.png"
+ const { container } = render()
+
+ const img = container.querySelector("img")
+ expect(img).toBeTruthy()
+ expect(img?.src).toBe(vscodeResourceUri)
+ })
+
+ it("should handle base64 images", () => {
+ const base64Image =
+ "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=="
+ const { container } = render()
+
+ const img = container.querySelector("img")
+ expect(img).toBeTruthy()
+ expect(img?.src).toBe(base64Image)
+ })
+
+ it("should use imageUri for rendering and imagePath for display", () => {
+ const webviewUri = "https://file+.vscode-resource.vscode-cdn.net/path/to/image.png"
+ const filePath = "/Users/test/project/image.png"
+ const { container } = render()
+
+ const img = container.querySelector("img")
+ expect(img).toBeTruthy()
+ // Should use imageUri for src
+ expect(img?.src).toBe(webviewUri)
+
+ // Should display imagePath below image
+ const pathElement = container.querySelector(".text-xs.text-vscode-descriptionForeground")
+ expect(pathElement).toBeTruthy()
+ expect(pathElement?.textContent).toContain("image.png")
+ })
+
+ it("should handle click to open in editor", () => {
+ const webviewUri = "https://file+.vscode-resource.vscode-cdn.net/path/to/image.png"
+ const filePath = "/Users/test/project/image.png"
+ const { container } = render()
+
+ const img = container.querySelector("img")
+ expect(img).toBeTruthy()
+
+ // Clear previous calls
+ vi.clearAllMocks()
+
+ // Click the image
+ fireEvent.click(img!)
+
+ // Check if vscode.postMessage was called to open the image with the actual path
+ expect(vscode.postMessage).toHaveBeenCalledWith({
+ type: "openImage",
+ text: filePath,
+ })
+ })
+
+ it("should handle error state gracefully", () => {
+ const invalidUri = "invalid://uri"
+ const { container } = render()
+
+ const img = container.querySelector("img")
+ expect(img).toBeTruthy()
+
+ // Trigger error event
+ fireEvent.error(img!)
+
+ // Image should still be rendered but might have error styling
+ expect(img).toBeTruthy()
+ })
+
+ it("should show no image message when imageUri is empty", () => {
+ const { container } = render()
+
+ // Should show no image message
+ expect(container.textContent).toContain("common:image.noData")
+ })
+
+ it("should display path below image when provided", () => {
+ const filePath = "/Users/test/rc1/path/to/image.png"
+ const webviewUri = "https://file+.vscode-resource.vscode-cdn.net/path/to/image.png"
+ const { container } = render()
+
+ // Check if path is displayed as relative path
+ const pathElement = container.querySelector(".text-xs.text-vscode-descriptionForeground")
+ expect(pathElement).toBeTruthy()
+ // Accept filename or relative path depending on environment
+ expect(pathElement?.textContent).toContain("image.png")
+ })
+})
diff --git a/webview-ui/src/i18n/locales/ca/common.json b/webview-ui/src/i18n/locales/ca/common.json
index c056a44328..edf95df4a0 100644
--- a/webview-ui/src/i18n/locales/ca/common.json
+++ b/webview-ui/src/i18n/locales/ca/common.json
@@ -51,7 +51,8 @@
"image": {
"tabs": {
"view": "Imatge"
- }
+ },
+ "noData": "Sense dades d'imatge"
},
"file": {
"errors": {
diff --git a/webview-ui/src/i18n/locales/de/common.json b/webview-ui/src/i18n/locales/de/common.json
index 85137922ff..b332d71413 100644
--- a/webview-ui/src/i18n/locales/de/common.json
+++ b/webview-ui/src/i18n/locales/de/common.json
@@ -51,7 +51,8 @@
"image": {
"tabs": {
"view": "Bild"
- }
+ },
+ "noData": "Keine Bilddaten"
},
"file": {
"errors": {
diff --git a/webview-ui/src/i18n/locales/en/common.json b/webview-ui/src/i18n/locales/en/common.json
index 973cb48297..a1830f1f91 100644
--- a/webview-ui/src/i18n/locales/en/common.json
+++ b/webview-ui/src/i18n/locales/en/common.json
@@ -51,7 +51,8 @@
"image": {
"tabs": {
"view": "Image"
- }
+ },
+ "noData": "No image data"
},
"file": {
"errors": {
diff --git a/webview-ui/src/i18n/locales/es/common.json b/webview-ui/src/i18n/locales/es/common.json
index a293008d8a..9beee73891 100644
--- a/webview-ui/src/i18n/locales/es/common.json
+++ b/webview-ui/src/i18n/locales/es/common.json
@@ -51,7 +51,8 @@
"image": {
"tabs": {
"view": "Imagen"
- }
+ },
+ "noData": "Sin datos de imagen"
},
"file": {
"errors": {
diff --git a/webview-ui/src/i18n/locales/fr/common.json b/webview-ui/src/i18n/locales/fr/common.json
index fd7f53dd97..8bd04a2aef 100644
--- a/webview-ui/src/i18n/locales/fr/common.json
+++ b/webview-ui/src/i18n/locales/fr/common.json
@@ -51,7 +51,8 @@
"image": {
"tabs": {
"view": "Image"
- }
+ },
+ "noData": "Aucune donnée d'image"
},
"file": {
"errors": {
diff --git a/webview-ui/src/i18n/locales/hi/common.json b/webview-ui/src/i18n/locales/hi/common.json
index 15039dc900..55f1b5a717 100644
--- a/webview-ui/src/i18n/locales/hi/common.json
+++ b/webview-ui/src/i18n/locales/hi/common.json
@@ -51,7 +51,8 @@
"image": {
"tabs": {
"view": "चित्र"
- }
+ },
+ "noData": "कोई छवि डेटा नहीं"
},
"file": {
"errors": {
diff --git a/webview-ui/src/i18n/locales/id/common.json b/webview-ui/src/i18n/locales/id/common.json
index 0dac9b2987..80104a87e0 100644
--- a/webview-ui/src/i18n/locales/id/common.json
+++ b/webview-ui/src/i18n/locales/id/common.json
@@ -51,7 +51,8 @@
"image": {
"tabs": {
"view": "Gambar"
- }
+ },
+ "noData": "Tidak ada data gambar"
},
"file": {
"errors": {
diff --git a/webview-ui/src/i18n/locales/it/common.json b/webview-ui/src/i18n/locales/it/common.json
index 9ac9cbadad..a913113708 100644
--- a/webview-ui/src/i18n/locales/it/common.json
+++ b/webview-ui/src/i18n/locales/it/common.json
@@ -51,7 +51,8 @@
"image": {
"tabs": {
"view": "Immagine"
- }
+ },
+ "noData": "Nessun dato immagine"
},
"file": {
"errors": {
diff --git a/webview-ui/src/i18n/locales/ja/common.json b/webview-ui/src/i18n/locales/ja/common.json
index a92a3cd79a..210c828a21 100644
--- a/webview-ui/src/i18n/locales/ja/common.json
+++ b/webview-ui/src/i18n/locales/ja/common.json
@@ -51,7 +51,8 @@
"image": {
"tabs": {
"view": "画像"
- }
+ },
+ "noData": "画像データなし"
},
"file": {
"errors": {
diff --git a/webview-ui/src/i18n/locales/ko/common.json b/webview-ui/src/i18n/locales/ko/common.json
index e8a9b7c64b..8f613c7139 100644
--- a/webview-ui/src/i18n/locales/ko/common.json
+++ b/webview-ui/src/i18n/locales/ko/common.json
@@ -51,7 +51,8 @@
"image": {
"tabs": {
"view": "이미지"
- }
+ },
+ "noData": "이미지 데이터 없음"
},
"file": {
"errors": {
diff --git a/webview-ui/src/i18n/locales/nl/common.json b/webview-ui/src/i18n/locales/nl/common.json
index 12a6c74365..3c4bc49017 100644
--- a/webview-ui/src/i18n/locales/nl/common.json
+++ b/webview-ui/src/i18n/locales/nl/common.json
@@ -51,7 +51,8 @@
"image": {
"tabs": {
"view": "Afbeelding"
- }
+ },
+ "noData": "Geen afbeeldingsgegevens"
},
"file": {
"errors": {
diff --git a/webview-ui/src/i18n/locales/pl/common.json b/webview-ui/src/i18n/locales/pl/common.json
index 410c8dbb9c..8ada6155bf 100644
--- a/webview-ui/src/i18n/locales/pl/common.json
+++ b/webview-ui/src/i18n/locales/pl/common.json
@@ -51,7 +51,8 @@
"image": {
"tabs": {
"view": "Obraz"
- }
+ },
+ "noData": "Brak danych obrazu"
},
"file": {
"errors": {
diff --git a/webview-ui/src/i18n/locales/pt-BR/common.json b/webview-ui/src/i18n/locales/pt-BR/common.json
index 30d9b6dc6c..b4cfdbb112 100644
--- a/webview-ui/src/i18n/locales/pt-BR/common.json
+++ b/webview-ui/src/i18n/locales/pt-BR/common.json
@@ -51,7 +51,8 @@
"image": {
"tabs": {
"view": "Imagem"
- }
+ },
+ "noData": "Nenhum dado de imagem"
},
"file": {
"errors": {
diff --git a/webview-ui/src/i18n/locales/ru/common.json b/webview-ui/src/i18n/locales/ru/common.json
index 8cdb1431eb..9a29b596c5 100644
--- a/webview-ui/src/i18n/locales/ru/common.json
+++ b/webview-ui/src/i18n/locales/ru/common.json
@@ -51,7 +51,8 @@
"image": {
"tabs": {
"view": "Изображение"
- }
+ },
+ "noData": "Нет данных изображения"
},
"file": {
"errors": {
diff --git a/webview-ui/src/i18n/locales/tr/common.json b/webview-ui/src/i18n/locales/tr/common.json
index 15f13fcdd3..d268bf223f 100644
--- a/webview-ui/src/i18n/locales/tr/common.json
+++ b/webview-ui/src/i18n/locales/tr/common.json
@@ -51,7 +51,8 @@
"image": {
"tabs": {
"view": "Resim"
- }
+ },
+ "noData": "Resim verisi yok"
},
"file": {
"errors": {
diff --git a/webview-ui/src/i18n/locales/vi/common.json b/webview-ui/src/i18n/locales/vi/common.json
index a75e1e1f4a..9815c23b6c 100644
--- a/webview-ui/src/i18n/locales/vi/common.json
+++ b/webview-ui/src/i18n/locales/vi/common.json
@@ -51,7 +51,8 @@
"image": {
"tabs": {
"view": "Hình ảnh"
- }
+ },
+ "noData": "Không có dữ liệu hình ảnh"
},
"file": {
"errors": {
diff --git a/webview-ui/src/i18n/locales/zh-CN/common.json b/webview-ui/src/i18n/locales/zh-CN/common.json
index 902bd7f7e0..afdb34794d 100644
--- a/webview-ui/src/i18n/locales/zh-CN/common.json
+++ b/webview-ui/src/i18n/locales/zh-CN/common.json
@@ -51,7 +51,8 @@
"image": {
"tabs": {
"view": "图像"
- }
+ },
+ "noData": "无图片数据"
},
"file": {
"errors": {
diff --git a/webview-ui/src/i18n/locales/zh-TW/common.json b/webview-ui/src/i18n/locales/zh-TW/common.json
index 9497d369a5..b9c9070c8e 100644
--- a/webview-ui/src/i18n/locales/zh-TW/common.json
+++ b/webview-ui/src/i18n/locales/zh-TW/common.json
@@ -51,7 +51,8 @@
"image": {
"tabs": {
"view": "圖像"
- }
+ },
+ "noData": "無圖片資料"
},
"file": {
"errors": {