diff --git a/packages/common-components/src/FileInput/FileInput.tsx b/packages/common-components/src/FileInput/FileInput.tsx index 1eff0ed230..458134a5fe 100644 --- a/packages/common-components/src/FileInput/FileInput.tsx +++ b/packages/common-components/src/FileInput/FileInput.tsx @@ -51,6 +51,8 @@ const useStyles = makeStyles(({ constants, palette, overrides }: ITheme) => }, error: { color: palette.error.main, + backgroundColor: palette.additional["gray"][3], + padding: "4px 40px", ...overrides?.FileInput?.error }, item: { diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/CSFFileBrowser.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/CSFFileBrowser.tsx index a5d1c863dc..5e49c928bd 100644 --- a/packages/files-ui/src/Components/Modules/FileBrowsers/CSFFileBrowser.tsx +++ b/packages/files-ui/src/Components/Modules/FileBrowsers/CSFFileBrowser.tsx @@ -27,7 +27,7 @@ import getFilesFromDataTransferItems from "../../../Utils/getFilesFromDataTransf import { Helmet } from "react-helmet-async" const CSFFileBrowser: React.FC = () => { - const { downloadFile, uploadFiles, buckets } = useFiles() + const { downloadFile, uploadFiles, buckets, storageSummary } = useFiles() const { accountRestricted } = useFilesApi() const { filesApiClient } = useFilesApi() const { addToast } = useToasts() @@ -173,12 +173,23 @@ const CSFFileBrowser: React.FC = () => { return } + const availableStorage = storageSummary?.available_storage || 0 + const uploadSize = files?.reduce((total: number, file: File) => total += file.size, 0) || 0 + + if (uploadSize > availableStorage) { + addToast({ + type: "error", + title: t`Upload size exceeds plan capacity`, + subtitle: t`Please select fewer files to upload` + }) + return + } const flattenedFiles = await getFilesFromDataTransferItems(fileItems) const paths = [...new Set(flattenedFiles.map(f => f.filepath))] paths.forEach(p => { uploadFiles(bucket, flattenedFiles.filter(f => f.filepath === p), getPathWithFile(path, p)) }) - }, [uploadFiles, bucket, accountRestricted, addToast]) + }, [bucket, accountRestricted, storageSummary, addToast, uploadFiles]) const viewFolder = useCallback((cid: string) => { const fileSystemItem = pathContents.find(f => f.cid === cid) diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/SharedFileBrowser.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/SharedFileBrowser.tsx index 30197b5173..236e03331c 100644 --- a/packages/files-ui/src/Components/Modules/FileBrowsers/SharedFileBrowser.tsx +++ b/packages/files-ui/src/Components/Modules/FileBrowsers/SharedFileBrowser.tsx @@ -44,7 +44,7 @@ const useStyles = makeStyles(({ constants, palette }: CSFTheme) => })) const SharedFileBrowser = () => { - const { downloadFile, uploadFiles, buckets, getStorageSummary, refreshBuckets } = useFiles() + const { downloadFile, uploadFiles, buckets, getStorageSummary, refreshBuckets, storageSummary } = useFiles() const { filesApiClient, accountRestricted } = useFilesApi() const classes = useStyles() const { addToast } = useToasts() @@ -205,7 +205,7 @@ const SharedFileBrowser = () => { const handleUploadOnDrop = useCallback(async (files: File[], fileItems: DataTransferItemList, path: string) => { if (!bucket) return - if (accountRestricted) { + if (accountRestricted && bucket.permission === "owner") { addToast({ type:"error", title: t`Uploads disabled`, @@ -213,12 +213,23 @@ const SharedFileBrowser = () => { }) return } + const availableStorage = storageSummary?.available_storage || 0 + const uploadSize = files?.reduce((total: number, file: File) => total += file.size, 0) || 0 + + if (bucket.permission === "owner" && uploadSize > availableStorage) { + addToast({ + type: "error", + title: t`Upload size exceeds plan capacity`, + subtitle: t`Please select fewer files to upload` + }) + return + } const flattenedFiles = await getFilesFromDataTransferItems(fileItems) const paths = [...new Set(flattenedFiles.map(f => f.filepath))] paths.forEach(p => { uploadFiles(bucket, flattenedFiles.filter(f => f.filepath === p), getPathWithFile(path, p)) }) - }, [uploadFiles, bucket, accountRestricted, addToast]) + }, [bucket, accountRestricted, storageSummary, addToast, uploadFiles]) const bulkOperations: IBulkOperations = useMemo(() => ({ [CONTENT_TYPES.Directory]: ["download", "move", "delete", "share"], diff --git a/packages/files-ui/src/Components/Modules/FileBrowsers/UploadFileModal.tsx b/packages/files-ui/src/Components/Modules/FileBrowsers/UploadFileModal.tsx index 8c633a88e4..3a13b94088 100644 --- a/packages/files-ui/src/Components/Modules/FileBrowsers/UploadFileModal.tsx +++ b/packages/files-ui/src/Components/Modules/FileBrowsers/UploadFileModal.tsx @@ -1,8 +1,8 @@ import { Button, FileInput } from "@chainsafe/common-components" import { useFiles } from "../../../Contexts/FilesContext" import { createStyles, makeStyles } from "@chainsafe/common-theme" -import React, { useCallback, useState } from "react" -import { Formik, Form } from "formik" +import React, { useCallback, useMemo, useState } from "react" +import { Form, useFormik, FormikProvider } from "formik" import { array, object } from "yup" import CustomModal from "../../Elements/CustomModal" import { Trans, t } from "@lingui/macro" @@ -83,8 +83,21 @@ const UploadFileModule = ({ modalOpen, close }: IUploadFileModuleProps) => { const [isDoneDisabled, setIsDoneDisabled] = useState(true) const { uploadFiles } = useFiles() const { currentPath, refreshContents, bucket } = useFileBrowser() + const { storageSummary } = useFiles() - const UploadSchema = object().shape({ files: array().required(t`Please select a file to upload`) }) + const UploadSchema = useMemo(() => object().shape({ + files: array().required(t`Please select a file to upload`) + .test("Upload Size", + t`Upload size exceeds plan capacity`, + (files) => { + // no validation if the user isn't the owner + if(bucket?.permission !== "owner") return true + + const availableStorage = storageSummary?.available_storage || 0 + const uploadSize = files?.reduce((total: number, file: File) => total += file.size, 0) || 0 + return uploadSize < availableStorage + }) + }), [bucket, storageSummary]) const onFileNumberChange = useCallback((filesNumber: number) => { setIsDoneDisabled(filesNumber === 0) @@ -106,7 +119,13 @@ const UploadFileModule = ({ modalOpen, close }: IUploadFileModuleProps) => { console.error(error) } helpers.setSubmitting(false) - }, [close, currentPath, uploadFiles, refreshContents, bucket]) + }, [bucket, close, refreshContents, uploadFiles, currentPath]) + + const formik = useFormik({ + initialValues: { files: [] }, + validationSchema: UploadSchema, + onSubmit: onSubmit + }) return ( { inner: classes.modalInner }} > - +
{ type="submit" variant="primary" className={clsx(classes.okButton, "wide")} - disabled={isDoneDisabled} + disabled={isDoneDisabled || !formik.isValid} > Start Upload
-
+
) } diff --git a/packages/files-ui/src/locales/de/messages.po b/packages/files-ui/src/locales/de/messages.po index 733566239b..b270d56250 100644 --- a/packages/files-ui/src/locales/de/messages.po +++ b/packages/files-ui/src/locales/de/messages.po @@ -697,6 +697,9 @@ msgstr "Bitte geben Sie ein Passwort an" msgid "Please select a file to upload" msgstr "Bitte wählen Sie eine Datei zum Hochladen" +msgid "Please select fewer files to upload" +msgstr "" + msgid "Preview" msgstr "Vorschau" @@ -1036,6 +1039,9 @@ msgstr "" msgid "Upload" msgstr "" +msgid "Upload size exceeds plan capacity" +msgstr "" + msgid "Uploads cancelled" msgstr "" diff --git a/packages/files-ui/src/locales/en/messages.po b/packages/files-ui/src/locales/en/messages.po index 533384a565..5042749363 100644 --- a/packages/files-ui/src/locales/en/messages.po +++ b/packages/files-ui/src/locales/en/messages.po @@ -700,6 +700,9 @@ msgstr "Please provide a password" msgid "Please select a file to upload" msgstr "Please select a file to upload" +msgid "Please select fewer files to upload" +msgstr "Please select fewer files to upload" + msgid "Preview" msgstr "Preview" @@ -1039,6 +1042,9 @@ msgstr "Update your credit card" msgid "Upload" msgstr "Upload" +msgid "Upload size exceeds plan capacity" +msgstr "Upload size exceeds plan capacity" + msgid "Uploads cancelled" msgstr "Uploads cancelled" diff --git a/packages/files-ui/src/locales/es/messages.po b/packages/files-ui/src/locales/es/messages.po index 95978c7d72..bfcff03fbe 100644 --- a/packages/files-ui/src/locales/es/messages.po +++ b/packages/files-ui/src/locales/es/messages.po @@ -701,6 +701,9 @@ msgstr "Por favor ingrese una contraseña" msgid "Please select a file to upload" msgstr "" +msgid "Please select fewer files to upload" +msgstr "" + msgid "Preview" msgstr "Avance" @@ -1040,6 +1043,9 @@ msgstr "" msgid "Upload" msgstr "" +msgid "Upload size exceeds plan capacity" +msgstr "" + msgid "Uploads cancelled" msgstr "" diff --git a/packages/files-ui/src/locales/fr/messages.po b/packages/files-ui/src/locales/fr/messages.po index 928f934451..4aeff95518 100644 --- a/packages/files-ui/src/locales/fr/messages.po +++ b/packages/files-ui/src/locales/fr/messages.po @@ -701,6 +701,9 @@ msgstr "Merci de donner un mot de passe" msgid "Please select a file to upload" msgstr "Merci de sélectionner un fichier à téléverser" +msgid "Please select fewer files to upload" +msgstr "" + msgid "Preview" msgstr "Aperçu" @@ -1040,6 +1043,9 @@ msgstr "Mettre à jour votre carte de crédit" msgid "Upload" msgstr "Téléverser" +msgid "Upload size exceeds plan capacity" +msgstr "" + msgid "Uploads cancelled" msgstr "Téléversements annulés" diff --git a/packages/files-ui/src/locales/no/messages.po b/packages/files-ui/src/locales/no/messages.po index 25f49680fa..2c27ff8884 100644 --- a/packages/files-ui/src/locales/no/messages.po +++ b/packages/files-ui/src/locales/no/messages.po @@ -697,6 +697,9 @@ msgstr "Angi et passord" msgid "Please select a file to upload" msgstr "Velg en fil å laste opp" +msgid "Please select fewer files to upload" +msgstr "" + msgid "Preview" msgstr "Forhåndsvis" @@ -1036,6 +1039,9 @@ msgstr "" msgid "Upload" msgstr "" +msgid "Upload size exceeds plan capacity" +msgstr "" + msgid "Uploads cancelled" msgstr ""