From 6bfd21ef0a8bf2f1ee1e9d193c3c375f64a05901 Mon Sep 17 00:00:00 2001 From: Oscar Kilhed Date: Fri, 27 Jan 2023 13:42:47 +0100 Subject: [PATCH] FileDropzone: make a nicer looking error message when file size is exceeded (#62290) * FileDropzone: make a nicer looking error message when file size is exceeded --- .../FileDropzone/FileDropzone.test.tsx | 8 ++++ .../components/FileDropzone/FileDropzone.tsx | 41 +++++++++++++------ 2 files changed, 36 insertions(+), 13 deletions(-) diff --git a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx index 0389d7ffd2a..39dd8a23361 100644 --- a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx +++ b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx @@ -33,6 +33,14 @@ describe('The FileDropzone component', () => { expect(screen.getByText('Accepted file type: .json')).toBeInTheDocument(); }); + it('should show an error message when the file size exceeds the max file size', async () => { + render(); + + dispatchEvt(screen.getByTestId('dropzone'), 'drop', mockData(files)); + + expect(await screen.findByText('File is larger than 1 B')).toBeInTheDocument(); + }); + it('should show the accepted file type(s) when passed in as a array of strings', () => { render(); diff --git a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx index 79ad4c2f92b..08acef7fc28 100644 --- a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx +++ b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx @@ -1,9 +1,9 @@ import { css, cx } from '@emotion/css'; import { isString, uniqueId } from 'lodash'; import React, { ReactNode, useCallback, useState } from 'react'; -import { Accept, DropEvent, DropzoneOptions, FileRejection, useDropzone } from 'react-dropzone'; +import { Accept, DropEvent, DropzoneOptions, FileError, FileRejection, useDropzone, ErrorCode } from 'react-dropzone'; -import { GrafanaTheme2 } from '@grafana/data'; +import { formattedValueToString, getValueFormat, GrafanaTheme2 } from '@grafana/data'; import { useTheme2 } from '../../themes'; import { Alert } from '../Alert/Alert'; @@ -68,7 +68,7 @@ export function FileDropzone({ onFileRemove, }: FileDropzoneProps) { const [files, setFiles] = useState([]); - const [errorMessages, setErrorMessages] = useState([]); + const [fileErrors, setErrorMessages] = useState([]); const setFileProperty = useCallback( (customFile: DropzoneFile, action: (customFileToModify: DropzoneFile) => void) => { @@ -175,11 +175,15 @@ export function FileDropzone({ }); const setErrors = (rejectedFiles: FileRejection[]) => { - let errors: string[] = []; + let errors: FileError[] = []; rejectedFiles.map((rejectedFile) => { - rejectedFile.errors.map((error) => { - if (errors.indexOf(error.message) === -1) { - errors.push(error.message); + rejectedFile.errors.map((newError) => { + if ( + errors.findIndex((presentError) => { + return presentError.code === newError.code && presentError.message === newError.message; + }) === -1 + ) { + errors.push(newError); } }); }); @@ -187,12 +191,22 @@ export function FileDropzone({ setErrorMessages(errors); }; - const getErrorMessages = () => { + const renderErrorMessages = (errors: FileError[]) => { return (
- {errorMessages.map((error) => { - return
{error}
; + {errors.map((error) => { + switch (error.code) { + case ErrorCode.FileTooLarge: + const formattedSize = getValueFormat('decbytes')(options?.maxSize!); + return ( +
+ File is larger than {formattedValueToString(formattedSize)} +
+ ); + default: + return
{error.message}
; + } })}
@@ -209,7 +223,7 @@ export function FileDropzone({ {children ?? } - {errorMessages.length > 0 && getErrorMessages()} + {fileErrors.length > 0 && renderErrorMessages(fileErrors)} {options?.accept && ( {getAcceptedFileTypeText(options.accept)} )} @@ -261,11 +275,12 @@ export function FileDropzoneDefaultChildren({ ); } -function getPrimaryText(files?: DropzoneFile[], options?: BackwardsCompatibleDropzoneOptions) { + +function getPrimaryText(files: DropzoneFile[], options?: BackwardsCompatibleDropzoneOptions) { if (options?.multiple === undefined || options?.multiple) { return 'Upload file'; } - return files && files.length ? 'Replace file' : 'Upload file'; + return files.length ? 'Replace file' : 'Upload file'; } function getAcceptedFileTypeText(accept: string | string[] | Accept) {