Avoid blank previews for unsupported artifacts (#3644)

This commit is contained in:
vantanco 2026-06-19 23:15:11 +07:00 committed by GitHub
parent df5d90fbb1
commit 90328d5651
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 91 additions and 2 deletions

View File

@ -20,6 +20,7 @@ import {
ArtifactTitle,
} from "@/components/ai-elements/artifact";
import { ClipboardSafeStreamdown } from "@/components/ai-elements/streamdown";
import { Button } from "@/components/ui/button";
import { Select, SelectItem } from "@/components/ui/select";
import {
SelectContent,
@ -43,7 +44,13 @@ import { useI18n } from "@/core/i18n/hooks";
import { findToolCallResult } from "@/core/messages/utils";
import { installSkill } from "@/core/skills/api";
import { streamdownPlugins } from "@/core/streamdown";
import { checkCodeFile, getFileName } from "@/core/utils/files";
import {
canBrowserPreviewFile,
checkCodeFile,
getFileExtensionDisplayName,
getFileIcon,
getFileName,
} from "@/core/utils/files";
import { env } from "@/env";
import { cn } from "@/lib/utils";
@ -92,6 +99,9 @@ export function ArtifactFileDetail({
}
return checkCodeFile(filepath);
}, [filepath, isWriteFile, isSkillFile]);
const canPreviewInBrowser = useMemo(() => {
return canBrowserPreviewFile(filepath);
}, [filepath]);
const isSupportPreview = useMemo(() => {
return language === "html" || language === "markdown";
}, [language]);
@ -303,17 +313,69 @@ export function ArtifactFileDetail({
readonly
/>
)}
{!isCodeFile && (
{!isCodeFile && canPreviewInBrowser && (
<iframe
className="size-full"
src={urlOfArtifact({ filepath, threadId, isMock })}
/>
)}
{!isCodeFile && !canPreviewInBrowser && (
<ArtifactDownloadFallback
filepath={filepath}
threadId={threadId}
isMock={isMock}
/>
)}
</ArtifactContent>
</Artifact>
);
}
function ArtifactDownloadFallback({
filepath,
threadId,
isMock,
}: {
filepath: string;
threadId: string;
isMock?: boolean;
}) {
const filename = getFileName(filepath);
const fileType = getFileExtensionDisplayName(filepath);
return (
<div className="flex size-full items-center justify-center p-6">
<div className="flex max-w-sm flex-col items-center gap-4 text-center">
<div className="text-muted-foreground">
{getFileIcon(filepath, "size-12")}
</div>
<div className="space-y-1">
<div className="font-medium break-all">{filename}</div>
<div className="text-muted-foreground text-sm">{fileType} file</div>
</div>
<p className="text-muted-foreground text-sm">
This file type cannot be previewed in the browser.
</p>
<Button asChild>
<a
href={urlOfArtifact({
filepath,
threadId,
download: true,
isMock,
})}
target="_blank"
rel="noopener noreferrer"
>
<DownloadIcon className="size-4" />
Download
</a>
</Button>
</div>
</div>
);
}
export function ArtifactFilePreview({
content,
language,

View File

@ -143,6 +143,29 @@ const extensionMap: Record<string, string> = {
v: "v",
};
const browserPreviewExtensions = new Set([
"pdf",
"apng",
"avif",
"bmp",
"gif",
"ico",
"jpg",
"jpeg",
"png",
"webp",
"mp3",
"wav",
"ogg",
"aac",
"m4a",
"flac",
"mp4",
"mov",
"m4v",
"webm",
]);
export function getFileName(filepath: string) {
return filepath.split("/").pop()!;
}
@ -170,6 +193,10 @@ export function checkCodeFile(
};
}
export function canBrowserPreviewFile(filepath: string) {
return browserPreviewExtensions.has(getFileExtension(filepath));
}
export function getFileExtensionDisplayName(filepath: string) {
const fileName = getFileName(filepath);
const extension = fileName.split(".").pop()!.toLocaleLowerCase();