From e63f15d872865c8958905fc9c66fee2061198496 Mon Sep 17 00:00:00 2001 From: cpadm <57954026+cpAdm@users.noreply.github.com> Date: Fri, 17 Oct 2025 22:11:33 +0200 Subject: [PATCH] fix(trace): Allow zip files of other mime types on paste --- .../trace-viewer/src/ui/workbenchLoader.tsx | 32 ++++++++----------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/packages/trace-viewer/src/ui/workbenchLoader.tsx b/packages/trace-viewer/src/ui/workbenchLoader.tsx index 165f4d6c70c7b..1a41560d980e7 100644 --- a/packages/trace-viewer/src/ui/workbenchLoader.tsx +++ b/packages/trace-viewer/src/ui/workbenchLoader.tsx @@ -23,12 +23,12 @@ import { DialogToolbarButton } from '@web/components/dialogToolbarButton'; import { Dialog } from '@web/shared/dialog'; import { DefaultSettingsView } from './defaultSettingsView'; import { TraceModelContext } from './traceModelContext'; +import { getMimeTypeForPath } from '@isomorphic/mimeType'; export const WorkbenchLoader: React.FunctionComponent<{ }> = () => { const [isServer, setIsServer] = React.useState(false); const [traceURL, setTraceURL] = React.useState(); - const [uploadedTraceName, setUploadedTraceName] = React.useState(); const [model, setModel] = React.useState(emptyModel); const [progress, setProgress] = React.useState<{ done: number, total: number }>({ done: 0, total: 0 }); const [dragOver, setDragOver] = React.useState(false); @@ -36,37 +36,35 @@ export const WorkbenchLoader: React.FunctionComponent<{ const [fileForLocalModeError, setFileForLocalModeError] = React.useState(null); const [showProgressDialog, setShowProgressDialog] = React.useState(false); - const processTraceFiles = React.useCallback((files: FileList) => { - const url = new URL(window.location.href); - if (!files.length) + const processTraceFiles = React.useCallback((files?: FileList | null) => { + if (!files?.length) return; - const file = files.item(0)!; + + // Do best effort to select the first valid trace valid, if not, rely on error reporting of sw + // Zip files may have different mime types on different operating systems, so rely on filename instead + const file = Array.from(files).find(file => getMimeTypeForPath(file.name) === 'application/zip') ?? files[0]; const blobTraceURL = URL.createObjectURL(file); + + const url = new URL(window.location.href); url.searchParams.append('trace', blobTraceURL); const href = url.toString(); // Snapshot loaders will inherit the trace url from the query parameters, // so set it here. window.history.pushState({}, '', href); setTraceURL(blobTraceURL); - setUploadedTraceName(file.name); setDragOver(false); setProcessingErrorMessage(null); }, []); React.useEffect(() => { const listener = async (e: ClipboardEvent) => { - if (!e.clipboardData?.files.length) - return; - for (const file of e.clipboardData.files) { - if (file.type !== 'application/zip') - return; - } e.preventDefault(); - processTraceFiles(e.clipboardData.files); + processTraceFiles(e.clipboardData?.files); }; document.addEventListener('paste', listener); return () => document.removeEventListener('paste', listener); }); + React.useEffect(() => { const listener = (e: MessageEvent) => { const { method, params } = e.data; @@ -90,11 +88,9 @@ export const WorkbenchLoader: React.FunctionComponent<{ processTraceFiles(event.dataTransfer.files); }, [processTraceFiles]); - const handleFileInputChange = React.useCallback((event: any) => { + const handleFileInputChange = React.useCallback((event: Event) => { event.preventDefault(); - if (!event.target.files) - return; - processTraceFiles(event.target.files); + processTraceFiles((event.target as HTMLInputElement).files); }, [processTraceFiles]); React.useEffect(() => { @@ -157,7 +153,7 @@ export const WorkbenchLoader: React.FunctionComponent<{ navigator.serviceWorker.removeEventListener('message', swListener); } })(); - }, [isServer, traceURL, uploadedTraceName]); + }, [isServer, traceURL]); const showLoading = progress.done !== progress.total && progress.total !== 0 && !processingErrorMessage;