From 1680e6527af2b76a3a1bc7f67a66edd40a82f977 Mon Sep 17 00:00:00 2001 From: Silow <99187811+Silow9@users.noreply.github.com> Date: Fri, 28 Mar 2025 14:50:45 +0800 Subject: [PATCH 1/8] Update index.tsx Made modification to make the system support uploading a folder so that the system recursively retrieves all files within the folder and sequentially adds them to the upload list. Add a button to upload the folder. By the way, remember to modify the Knowledge Configuration and NGINX_CLIENT_MAX_BODY_SIZE in the file named .env.example in main menu to ensure the uploading is allowed for size limitation. --- .../datasets/create/file-uploader/index.tsx | 59 +++++++++++++++---- 1 file changed, 49 insertions(+), 10 deletions(-) diff --git a/web/app/components/datasets/create/file-uploader/index.tsx b/web/app/components/datasets/create/file-uploader/index.tsx index 63bd554215..092f2f0ab5 100644 --- a/web/app/components/datasets/create/file-uploader/index.tsx +++ b/web/app/components/datasets/create/file-uploader/index.tsx @@ -47,6 +47,10 @@ 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) @@ -214,6 +218,12 @@ const FileUploader = ({ 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 = '' @@ -223,7 +233,15 @@ const FileUploader = ({ } const fileChangeHandle = useCallback((e: React.ChangeEvent) => { const files = [...(e.target.files ?? [])] as File[] - initialUpload(files.filter(isValid)) + 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) }, [isValid, initialUpload]) const { theme } = useTheme() @@ -245,15 +263,36 @@ const FileUploader = ({ return (
{!hideUpload && ( - + <> + + {/* folder uploader */} + + + )} + + {/* give user a “Upload Folder” button */} + {!hideUpload && ( + )}
{t('datasetCreation.stepOne.uploader.title')}
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 2/8] 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')}
From 18e0b0a45ab4969e49884bb3ae088c273c50eeea Mon Sep 17 00:00:00 2001 From: Silow <99187811+Silow9@users.noreply.github.com> Date: Thu, 24 Apr 2025 13:41:03 +0800 Subject: [PATCH 3/8] Update index.tsx delete extra comment --- web/app/components/datasets/create/file-uploader/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/app/components/datasets/create/file-uploader/index.tsx b/web/app/components/datasets/create/file-uploader/index.tsx index 3703840c7d..b03532df0b 100644 --- a/web/app/components/datasets/create/file-uploader/index.tsx +++ b/web/app/components/datasets/create/file-uploader/index.tsx @@ -204,7 +204,7 @@ const FileUploader = ({ return new Promise((resolve) => { if (entry.isFile) { entry.file((file: FileWithPath) => { - file.relativePath = `${prefix}${file.name}` // 保留相对路径 + file.relativePath = `${prefix}${file.name}` resolve([file]) }) } @@ -234,7 +234,7 @@ const FileUploader = ({ } }) }, - [], // ← 依赖为空,引用稳定 + [], ) const handleDrop = useCallback( From f6b372426858bacc1df606555abec5d4500315eb Mon Sep 17 00:00:00 2001 From: -LAN- Date: Thu, 24 Apr 2025 15:08:37 +0900 Subject: [PATCH 4/8] chore(docker): bump dify-plugin-daemon to 0.0.9 (#18672) Signed-off-by: -LAN- --- docker/docker-compose-template.yaml | 2 +- docker/docker-compose.middleware.yaml | 2 +- docker/docker-compose.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker/docker-compose-template.yaml b/docker/docker-compose-template.yaml index 8c57a7c4c2..9da06df2b0 100644 --- a/docker/docker-compose-template.yaml +++ b/docker/docker-compose-template.yaml @@ -142,7 +142,7 @@ services: # plugin daemon plugin_daemon: - image: langgenius/dify-plugin-daemon:0.0.8-local + image: langgenius/dify-plugin-daemon:0.0.9-local restart: always environment: # Use the shared environment variables. diff --git a/docker/docker-compose.middleware.yaml b/docker/docker-compose.middleware.yaml index fc08edd264..01c7573a95 100644 --- a/docker/docker-compose.middleware.yaml +++ b/docker/docker-compose.middleware.yaml @@ -71,7 +71,7 @@ services: # plugin daemon plugin_daemon: - image: langgenius/dify-plugin-daemon:0.0.8-local + image: langgenius/dify-plugin-daemon:0.0.9-local restart: always env_file: - ./middleware.env diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 3d3e3a901f..ea9332bf2e 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -619,7 +619,7 @@ services: # plugin daemon plugin_daemon: - image: langgenius/dify-plugin-daemon:0.0.8-local + image: langgenius/dify-plugin-daemon:0.0.9-local restart: always environment: # Use the shared environment variables. From 7b00f35a0d96e344a9a1ffbddf1bd3843765e740 Mon Sep 17 00:00:00 2001 From: "Junjie.M" <118170653@qq.com> Date: Thu, 24 Apr 2025 14:50:12 +0800 Subject: [PATCH 5/8] fix: link address error in the embedding in websites first example (#18677) --- web/app/components/app/overview/embedded/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/app/components/app/overview/embedded/index.tsx b/web/app/components/app/overview/embedded/index.tsx index 6ebd0fce69..691b727b8e 100644 --- a/web/app/components/app/overview/embedded/index.tsx +++ b/web/app/components/app/overview/embedded/index.tsx @@ -29,7 +29,7 @@ const OPTION_MAP = { iframe: { getContent: (url: string, token: string) => `