From bef2e4fbcea145835af4dc1d79932e864fa03f13 Mon Sep 17 00:00:00 2001 From: Alf Eaton Date: Wed, 21 Feb 2024 11:34:25 +0000 Subject: [PATCH] Allow any single file to be uploaded (#17215) GitOrigin-RevId: 9eecc9e044ec1a489b42ccf697806fecfbe5dfc8 --- .../modes/file-tree-upload-doc.tsx | 14 +++++++++----- .../file-tree/contexts/file-tree-actionable.tsx | 15 ++++++++++++--- .../file-tree/contexts/file-tree-draggable.tsx | 7 ++++++- .../file-tree/util/is-acceptable-file.ts | 16 ++++++++++++++-- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/services/web/frontend/js/features/file-tree/components/file-tree-create/modes/file-tree-upload-doc.tsx b/services/web/frontend/js/features/file-tree/components/file-tree-create/modes/file-tree-upload-doc.tsx index 6015a49e09..ec04578ebe 100644 --- a/services/web/frontend/js/features/file-tree/components/file-tree-create/modes/file-tree-upload-doc.tsx +++ b/services/web/frontend/js/features/file-tree/components/file-tree-create/modes/file-tree-upload-doc.tsx @@ -96,7 +96,7 @@ export default function FileTreeUploadDoc() { const endpoint = buildEndpoint(projectId, parentFolderId) return ( - new Uppy({ + new Uppy<{ relativePath?: string; targetFolderId: string }>({ // logger: Uppy.debugLogger, allowMultipleUploadBatches: false, restrictions: { @@ -104,7 +104,12 @@ export default function FileTreeUploadDoc() { maxFileSize: maxFileSize || null, }, onBeforeFileAdded(file) { - if (!isAcceptableFile(file)) { + if ( + !isAcceptableFile( + file.name, + file.meta.relativePath as string | undefined + ) + ) { return false } }, @@ -180,15 +185,14 @@ export default function FileTreeUploadDoc() { source: 'Local', isRemote: false, meta: { - relativePath: file.relativePath, + relativePath: (file as any).relativePath, targetFolderId: droppedFiles.targetFolderId, }, }) const uppyFile = uppy.getFile(fileId) uppy.setFileState(fileId, { xhrUpload: { - // @ts-ignore - ...uppyFile.xhrUpload, + ...(uppyFile as any).xhrUpload, endpoint: buildEndpoint(projectId, droppedFiles.targetFolderId), }, }) diff --git a/services/web/frontend/js/features/file-tree/contexts/file-tree-actionable.tsx b/services/web/frontend/js/features/file-tree/contexts/file-tree-actionable.tsx index fbd5739eae..17712705c9 100644 --- a/services/web/frontend/js/features/file-tree/contexts/file-tree-actionable.tsx +++ b/services/web/frontend/js/features/file-tree/contexts/file-tree-actionable.tsx @@ -34,6 +34,15 @@ import { } from '../errors' import { Folder } from '../../../../../types/folder' +type DroppedFile = File & { + relativePath?: string +} + +type DroppedFiles = { + files: DroppedFile[] + targetFolderId: string +} + const FileTreeActionableContext = createContext< | { isDeleting: boolean @@ -63,8 +72,8 @@ const FileTreeActionableContext = createContext< finishCreatingDoc: any finishCreatingLinkedFile: any cancel: () => void - droppedFiles: { files: any; targetFolderId: string } | null - setDroppedFiles: (files: any) => void + droppedFiles: { files: File[]; targetFolderId: string } | null + setDroppedFiles: (value: DroppedFiles | null) => void downloadPath?: string } | undefined @@ -222,7 +231,7 @@ export const FileTreeActionableProvider: FC<{ const { fileTreeData, dispatchRename, dispatchMove } = useFileTreeData() const { selectedEntityIds, isRootFolderSelected } = useFileTreeSelectable() - const [droppedFiles, setDroppedFiles] = useState(null) + const [droppedFiles, setDroppedFiles] = useState(null) const startRenaming = useCallback(() => { dispatch({ type: ACTION_TYPES.START_RENAME }) diff --git a/services/web/frontend/js/features/file-tree/contexts/file-tree-draggable.tsx b/services/web/frontend/js/features/file-tree/contexts/file-tree-draggable.tsx index 2b766dd084..959ca0cbfd 100644 --- a/services/web/frontend/js/features/file-tree/contexts/file-tree-draggable.tsx +++ b/services/web/frontend/js/features/file-tree/contexts/file-tree-draggable.tsx @@ -122,7 +122,12 @@ export function useDroppable(targetEntityId: string) { // native file(s) dragged in from outside getDroppedFiles(item as unknown as DataTransfer) - .then(files => files.filter(isAcceptableFile)) + .then(files => + files.filter(file => + // note: getDroppedFiles normalises webkitRelativePath to relativePath + isAcceptableFile(file.name, (file as any).relativePath) + ) + ) .then(files => { setDroppedFiles({ files, targetFolderId: targetEntityId }) startUploadingDocOrFile() diff --git a/services/web/frontend/js/features/file-tree/util/is-acceptable-file.ts b/services/web/frontend/js/features/file-tree/util/is-acceptable-file.ts index 417724be64..fb09435d02 100644 --- a/services/web/frontend/js/features/file-tree/util/is-acceptable-file.ts +++ b/services/web/frontend/js/features/file-tree/util/is-acceptable-file.ts @@ -5,5 +5,17 @@ const fileIgnoreMatcher = new Minimatch( { nocase: true, dot: true } ) -export const isAcceptableFile = (file: { name: string }) => - !fileIgnoreMatcher.match(file.name) +export const isAcceptableFile = (name?: string, relativePath?: string) => { + if (!name) { + // the file must have a name, of course + return false + } + + if (!relativePath) { + // uploading an individual file, so allow anything + return true + } + + // uploading a file in a folder, so exclude unwanted file paths + return !fileIgnoreMatcher.match(relativePath + '/' + name) +}