Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upload notification #2138

Merged
merged 12 commits into from
May 19, 2022
11 changes: 4 additions & 7 deletions packages/common-components/src/FileInput/FileInput.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useCallback, useState, useEffect, ReactNode } from "react"
import { useField } from "formik"
import { useDropzone, DropzoneOptions, FileRejection } from "react-dropzone"
import { useDropzone, DropzoneOptions, FileRejection, FileWithPath } from "react-dropzone"
import clsx from "clsx"
import { ITheme, makeStyles, createStyles } from "@chainsafe/common-theme"
import { Button } from "../Button"
Expand Down Expand Up @@ -101,10 +101,6 @@ const useStyles = makeStyles(({ constants, palette, overrides }: ITheme) =>
})
)

interface FileWithPath extends File {
path?: string
}

interface IFileInputProps extends DropzoneOptions {
className?: string
variant?: "dropzone" | "filepicker"
Expand Down Expand Up @@ -143,14 +139,14 @@ const FileInput = ({
const classes = useStyles()
const [previews, setPreviews] = useState<any[]>([])
const [errors, setErrors] = useState<any[]>([])
const [{ value }, meta, helpers] = useField<Array<FileWithPath>>(name)
const [{ value }, meta, helpers] = useField<FileWithPath[]>(name)

useEffect(() => {
onFileNumberChange && onFileNumberChange(value.length)
}, [onFileNumberChange, value.length])

const onDrop = useCallback(
async (acceptedFiles: Array<FileWithPath>, fileRejections: FileRejection[]) => {
async (acceptedFiles: FileWithPath[], fileRejections: FileRejection[]) => {
const filtered = acceptedFiles.filter((file) =>
maxFileSize ? file.size <= maxFileSize : true
)
Expand All @@ -165,6 +161,7 @@ const FileInput = ({
)
)
}

helpers.setValue([...value, ...filtered])

if (fileRejections.length > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,14 +185,7 @@ const CSFFileBrowser: React.FC<IFileBrowserModuleProps> = () => {
return
}
const flattenedFiles = await getFilesFromDataTransferItems(fileItems)
const paths = [...new Set(flattenedFiles.map(f => f.filepath))]
paths.reduce(async (prev, p) => {
await prev

return await uploadFiles(bucket, flattenedFiles.filter(f => f.filepath === p), getPathWithFile(path, p))
},
Promise.resolve()
)
await uploadFiles(bucket, flattenedFiles, path)
}, [bucket, accountRestricted, storageSummary, addToast, uploadFiles])

const viewFolder = useCallback((cid: string) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,14 +225,7 @@ const SharedFileBrowser = () => {
return
}
const flattenedFiles = await getFilesFromDataTransferItems(fileItems)
const paths = [...new Set(flattenedFiles.map(f => f.filepath))]
paths.reduce(async (prev, p) => {
await prev

return await uploadFiles(bucket, flattenedFiles.filter(f => f.filepath === p), getPathWithFile(path, p))
},
Promise.resolve()
)
await uploadFiles(bucket, flattenedFiles, path)
}, [bucket, accountRestricted, storageSummary, addToast, uploadFiles])

const bulkOperations: IBulkOperations = useMemo(() => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { Trans, t } from "@lingui/macro"
import clsx from "clsx"
import { CSFTheme } from "../../../Themes/types"
import { useFileBrowser } from "../../../Contexts/FileBrowserContext"
import { getPathWithFile } from "../../../Utils/pathUtils"

const useStyles = makeStyles(({ constants, breakpoints }: CSFTheme) =>
createStyles({
Expand Down Expand Up @@ -106,19 +105,9 @@ const UploadFileModule = ({ modalOpen, close }: IUploadFileModuleProps) => {
if (!bucket) return

helpers.setSubmitting(true)

try {
close()
const paths = [...new Set(values.files.map(f => f.path.substring(0, f.path.lastIndexOf("/"))))]
paths.reduce(async (prev, p) => {
await prev

const filesToUpload = values.files.filter((f => f.path.substring(0, f.path.lastIndexOf("/")) === p))
return await uploadFiles(bucket, filesToUpload, getPathWithFile(currentPath, p))
},
Promise.resolve()
)

await uploadFiles(bucket, values.files, currentPath)
refreshContents && refreshContents()
helpers.resetForm()
} catch (error: any) {
Expand Down
47 changes: 29 additions & 18 deletions packages/files-ui/src/Contexts/FilesContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ import { useBeforeunload } from "react-beforeunload"
import { useThresholdKey } from "./ThresholdKeyContext"
import { useFilesApi } from "./FilesApiContext"
import { useUser } from "./UserContext"
import { getPathWithFile, getRelativePath } from "../Utils/pathUtils"
import { getParentPathFromFilePath, getPathWithFile, getRelativePath } from "../Utils/pathUtils"
import { Zippable, zipSync } from "fflate"
import { FileWithPath } from "../Utils/getFilesFromDataTransferItems"

type FilesContextProps = {
children: React.ReactNode | React.ReactNode[]
Expand Down Expand Up @@ -52,7 +53,7 @@ type FilesContext = {
storageSummary: BucketSummaryResponse | undefined
personalEncryptionKey: string | undefined
getStorageSummary: () => Promise<void>
uploadFiles: (bucket: BucketKeyPermission, files: File[], path: string, encryptionKey?: string) => Promise<void>
uploadFiles: (bucket: BucketKeyPermission, files: FileWithPath[], rootUploadPath: string) => Promise<void>
downloadFile: (bucketId: string, itemToDownload: FileSystemItem, path: string) => void
getFileContent: (bucketId: string, params: GetFileContentParams) => Promise<Blob | undefined>
refreshBuckets: (showLoading?: boolean) => Promise<void>
Expand Down Expand Up @@ -319,7 +320,6 @@ const FilesProvider = ({ children }: FilesContextProps) => {
onUploadProgress?: (progressEvent: ProgressEvent<EventTarget>) => void,
cancelToken?: CancelToken
) => {

const key = bucket.encryptionKey

if (!key) {
Expand Down Expand Up @@ -350,7 +350,7 @@ const FilesProvider = ({ children }: FilesContextProps) => {
)
}, [filesApiClient])

const uploadFiles = useCallback(async (bucket: BucketKeyPermission, files: File[], path: string) => {
const uploadFiles = useCallback(async (bucket: BucketKeyPermission, files: FileWithPath[], rootUploadPath: string) => {
const hasOversizedFile = files.some(file => file.size > MAX_FILE_SIZE)
if (hasOversizedFile) {
addToast({
Expand All @@ -377,20 +377,31 @@ const FilesProvider = ({ children }: FilesContextProps) => {
setUploadsInProgress(true)

try {
await encryptAndUploadFiles(
bucket,
files,
path,
(progressEvent: { loaded: number; total: number }) => {
updateToast(toastId, {
...toastParams,
progress: Math.ceil(
(progressEvent.loaded / progressEvent.total) * 100
)
})
},
cancelToken
)
const paths = [...new Set(files.map(f => getParentPathFromFilePath(f.path)))]
const totalUploadSize = files.reduce((sum, f) => sum += f.size, 0)

let uploadedSize = 0
for (const path of paths) {
const filesToUpload = files.filter((f => getParentPathFromFilePath(f.path) === path))
const batchSize = filesToUpload.reduce((sum, f) => sum += f.size, 0)
await encryptAndUploadFiles(
bucket,
filesToUpload,
getPathWithFile(rootUploadPath, path),
(progressEvent: { loaded: number; total: number }) => {
updateToast(toastId, {
...toastParams,
progress: Math.ceil(
((progressEvent.loaded + uploadedSize) / totalUploadSize) * 100
)
})
},
cancelToken
)
uploadedSize += batchSize
}


setUploadsInProgress(false)

await refreshBuckets()
Expand Down
6 changes: 4 additions & 2 deletions packages/files-ui/src/Utils/getFilesFromDataTransferItems.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
//Shamelessly borrowed from https://github.com/anatol-grabowski/datatransfer-files-promise with added Types

type FileWithPath = File & {filepath: string}
export type FileWithPath = File & {
path: string
}

const getFilesFromDataTransferItems = async (dataTransferItems: DataTransferItemList): Promise<Array<FileWithPath>> => {
const readFile = (entry: FileEntry, path = ""): Promise<FileWithPath> => {
return new Promise((resolve, reject) => {
entry.file((file: File) => {
Object.defineProperty(file, "filepath", {
Object.defineProperty(file, "path", {
value: path
})
resolve(file as FileWithPath)
Expand Down
2 changes: 1 addition & 1 deletion packages/files-ui/src/locales/fr/messages.po
Original file line number Diff line number Diff line change
Expand Up @@ -1107,7 +1107,7 @@ msgid "We are performing routine maintenance of the system. Service status updat
msgstr "Nous effectuons une maintenance de routine du système. Les mises à jour de l'état du service seront postées sur le canal <0>Files Support<0> sur Discord"

msgid "We can't encrypt files larger than 2GB. Some items will not be uploaded"
msgstr "Nous ne pouvons pas chiffrer les fichiers de plus de 2 Go. Certains éléments ne pourront pas être téléversés"
msgstr "Nous ne pouvons pas chiffrer les fichiers de plus de 2 Go. Certains éléments ne pourront pas être téléversés"

msgid "Web3: {0}"
msgstr "Web3 : {0}"
Expand Down