From ed35fc3777f1ba0d14953aa30ab2f41b2e790138 Mon Sep 17 00:00:00 2001 From: Silow <99187811+Silow9@users.noreply.github.com> Date: Thu, 24 Apr 2025 13:39:16 +0800 Subject: [PATCH] Update index.tsx Delete extra button and support drag folder to upload --- .../datasets/create/file-uploader/index.tsx | 132 ++++++++++-------- 1 file changed, 71 insertions(+), 61 deletions(-) diff --git a/web/app/components/datasets/create/file-uploader/index.tsx b/web/app/components/datasets/create/file-uploader/index.tsx index 092f2f0ab5..3703840c7d 100644 --- a/web/app/components/datasets/create/file-uploader/index.tsx +++ b/web/app/components/datasets/create/file-uploader/index.tsx @@ -47,10 +47,6 @@ const FileUploader = ({ const dropRef = useRef(null) const dragRef = useRef(null) const fileUploader = useRef(null) - - // For upload folder - const dirUploader = useRef(null) - const hideUpload = notSupportBatchUpload && fileList.length > 0 const { data: fileUploadConfigResponse } = useSWR({ url: '/files/upload' }, fetchFileUploadConfig) @@ -200,30 +196,73 @@ const FileUploader = ({ e.stopPropagation() e.target === dragRef.current && setDragging(false) } + type FileWithPath = { + relativePath?: string + } & File + const traverseFileEntry = useCallback( + (entry: any, prefix = ''): Promise => { + return new Promise((resolve) => { + if (entry.isFile) { + entry.file((file: FileWithPath) => { + file.relativePath = `${prefix}${file.name}` // 保留相对路径 + resolve([file]) + }) + } + else if (entry.isDirectory) { + const reader = entry.createReader() + const entries: any[] = [] + const read = () => { + reader.readEntries(async (results: FileSystemEntry[]) => { + if (!results.length) { + const files = await Promise.all( + entries.map(ent => + traverseFileEntry(ent, `${prefix}${entry.name}/`), + ), + ) + resolve(files.flat()) + } + else { + entries.push(...results) + read() + } + }) + } + read() + } + else { + resolve([]) + } + }) + }, + [], // ← 依赖为空,引用稳定 + ) - const handleDrop = useCallback((e: DragEvent) => { - e.preventDefault() - e.stopPropagation() - setDragging(false) - if (!e.dataTransfer) - return - - const files = [...e.dataTransfer.files] as File[] - const validFiles = files.filter(isValid) - initialUpload(validFiles) - }, [initialUpload, isValid]) - + const handleDrop = useCallback( + async (e: DragEvent) => { + e.preventDefault() + e.stopPropagation() + setDragging(false) + if (!e.dataTransfer) return + const nested = await Promise.all( + Array.from(e.dataTransfer.items).map((it) => { + const entry = (it as any).webkitGetAsEntry?.() + if (entry) return traverseFileEntry(entry) + const f = it.getAsFile?.() + return f ? Promise.resolve([f]) : Promise.resolve([]) + }), + ) + let files = nested.flat() + if (notSupportBatchUpload) files = files.slice(0, 1) + const valid = files.filter(isValid) + initialUpload(valid) + }, + [initialUpload, isValid, notSupportBatchUpload, traverseFileEntry], + ) const selectHandle = () => { if (fileUploader.current) fileUploader.current.click() } - // click on button, use folder upload - const selectFolderHandle = () => { - if (dirUploader.current) - dirUploader.current.click() - } - const removeFile = (fileID: string) => { if (fileUploader.current) fileUploader.current.value = '' @@ -233,15 +272,7 @@ const FileUploader = ({ } const fileChangeHandle = useCallback((e: React.ChangeEvent) => { const files = [...(e.target.files ?? [])] as File[] - const validFiles = files.filter(isValid) - initialUpload(validFiles) - }, [isValid, initialUpload]) - - // Callback for folder upload - const folderChangeHandle = useCallback((e: React.ChangeEvent) => { - const files = [...(e.target.files ?? [])] as File[] - const validFiles = files.filter(isValid) - initialUpload(validFiles) + initialUpload(files.filter(isValid)) }, [isValid, initialUpload]) const { theme } = useTheme() @@ -263,36 +294,15 @@ const FileUploader = ({ return (
{!hideUpload && ( - <> - - {/* folder uploader */} - - - )} - - {/* give user a “Upload Folder” button */} - {!hideUpload && ( - + )}
{t('datasetCreation.stepOne.uploader.title')}