diff --git a/ui/litellm-dashboard/src/components/playground/chat_ui/ChatUI.tsx b/ui/litellm-dashboard/src/components/playground/chat_ui/ChatUI.tsx index eba9d37669..bc0d52cf58 100644 --- a/ui/litellm-dashboard/src/components/playground/chat_ui/ChatUI.tsx +++ b/ui/litellm-dashboard/src/components/playground/chat_ui/ChatUI.tsx @@ -60,6 +60,7 @@ import CodeInterpreterOutput from "./CodeInterpreterOutput"; import CodeInterpreterTool from "./CodeInterpreterTool"; import { generateCodeSnippet } from "./CodeSnippets"; import EndpointSelector from "./EndpointSelector"; +import FilePreviewCard from "./FilePreviewCard"; import MCPEventsDisplay from "./MCPEventsDisplay"; import type { MCPEvent } from "../../mcp_tools/types"; import { EndpointType, getEndpointType } from "./mode_endpoint_mapping"; @@ -2231,67 +2232,19 @@ const ChatUI: React.FC = ({ {/* Show file previews above input when files are uploaded */} {endpointType === EndpointType.RESPONSES && responsesUploadedImage && ( -
-
-
- {responsesUploadedImage.name.toLowerCase().endsWith(".pdf") ? ( -
- -
- ) : ( - Upload preview - )} -
-
-
{responsesUploadedImage.name}
-
- {responsesUploadedImage.name.toLowerCase().endsWith(".pdf") ? "PDF" : "Image"} -
-
- -
-
+ )} {endpointType === EndpointType.CHAT && chatUploadedImage && ( -
-
-
- {chatUploadedImage.name.toLowerCase().endsWith(".pdf") ? ( -
- -
- ) : ( - Upload preview - )} -
-
-
{chatUploadedImage.name}
-
- {chatUploadedImage.name.toLowerCase().endsWith(".pdf") ? "PDF" : "Image"} -
-
- -
-
+ )} {/* Code Interpreter indicator and sample prompts when enabled */} diff --git a/ui/litellm-dashboard/src/components/playground/chat_ui/FilePreviewCard.test.tsx b/ui/litellm-dashboard/src/components/playground/chat_ui/FilePreviewCard.test.tsx new file mode 100644 index 0000000000..1014df5d16 --- /dev/null +++ b/ui/litellm-dashboard/src/components/playground/chat_ui/FilePreviewCard.test.tsx @@ -0,0 +1,70 @@ +import { render, screen } from "@testing-library/react"; +import userEvent from "@testing-library/user-event"; +import { describe, expect, it, vi } from "vitest"; +import FilePreviewCard from "./FilePreviewCard"; + +function makeFile(name: string): File { + return new File(["dummy"], name, { type: "application/octet-stream" }); +} + +describe("FilePreviewCard", () => { + it("should render", () => { + render( + + ); + expect(screen.getByText("photo.png")).toBeInTheDocument(); + }); + + it("should display the file name", () => { + render( + + ); + expect(screen.getByText("my-screenshot.jpg")).toBeInTheDocument(); + }); + + it("should show 'Image' label for non-PDF files", () => { + render( + + ); + expect(screen.getByText("Image")).toBeInTheDocument(); + }); + + it("should show 'PDF' label for PDF files", () => { + render( + + ); + expect(screen.getByText("PDF")).toBeInTheDocument(); + }); + + it("should render an image preview when the file is not a PDF", () => { + render( + + ); + expect(screen.getByAltText("Upload preview")).toBeInTheDocument(); + }); + + it("should not render an image preview when the file is a PDF", () => { + render( + + ); + expect(screen.queryByAltText("Upload preview")).not.toBeInTheDocument(); + }); + + it("should call onRemove when the remove button is clicked", async () => { + const onRemove = vi.fn(); + const user = userEvent.setup(); + render( + + ); + await user.click(screen.getByRole("button")); + expect(onRemove).toHaveBeenCalledOnce(); + }); + + it("should treat .PDF (uppercase) as a PDF file", () => { + render( + + ); + expect(screen.getByText("PDF")).toBeInTheDocument(); + expect(screen.queryByAltText("Upload preview")).not.toBeInTheDocument(); + }); +}); diff --git a/ui/litellm-dashboard/src/components/playground/chat_ui/FilePreviewCard.tsx b/ui/litellm-dashboard/src/components/playground/chat_ui/FilePreviewCard.tsx new file mode 100644 index 0000000000..26bdf07eda --- /dev/null +++ b/ui/litellm-dashboard/src/components/playground/chat_ui/FilePreviewCard.tsx @@ -0,0 +1,45 @@ +import { DeleteOutlined, FilePdfOutlined } from "@ant-design/icons"; + +interface FilePreviewCardProps { + file: File; + previewUrl: string | null; + onRemove: () => void; +} + +function FilePreviewCard({ file, previewUrl, onRemove }: FilePreviewCardProps) { + const isPdf = file.name.toLowerCase().endsWith(".pdf"); + + return ( +
+
+
+ {isPdf ? ( +
+ +
+ ) : ( + Upload preview + )} +
+
+
{file.name}
+
+ {isPdf ? "PDF" : "Image"} +
+
+ +
+
+ ); +} + +export default FilePreviewCard;