diff --git a/packages/react-core/src/components/FileUpload/FileUpload.tsx b/packages/react-core/src/components/FileUpload/FileUpload.tsx index ce4c8e04f33..4aa06c62332 100644 --- a/packages/react-core/src/components/FileUpload/FileUpload.tsx +++ b/packages/react-core/src/components/FileUpload/FileUpload.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { DropzoneInputProps, DropzoneOptions, FileRejection, useDropzone } from 'react-dropzone'; +import { DropzoneInputProps, DropzoneOptions, FileRejection, useDropzone, ErrorCode } from 'react-dropzone'; import { FileUploadField, FileUploadFieldProps } from './FileUploadField'; import { readFile, fileReaderType } from '../../helpers/fileUtils'; import { DropEvent } from '../../helpers/typeUtils'; @@ -84,6 +84,8 @@ export interface FileUploadProps onTextChange?: (event: React.ChangeEvent, text: string) => void; } +export { ErrorCode as DropzoneErrorCode }; // FileInvalidType, FileTooLarge, FileTooSmall, TooManyFiles + export const FileUpload: React.FunctionComponent = ({ id, type, diff --git a/packages/react-core/src/components/FileUpload/examples/FileUpload.md b/packages/react-core/src/components/FileUpload/examples/FileUpload.md index b6f8efbd109..4280d6a22c3 100644 --- a/packages/react-core/src/components/FileUpload/examples/FileUpload.md +++ b/packages/react-core/src/components/FileUpload/examples/FileUpload.md @@ -40,7 +40,7 @@ Typing/pasting text in the box will call `onTextChange` with a string, and a str ### Restricting file size and type -Any [props accepted by `react-dropzone`'s `Dropzone` component](https://react-dropzone.js.org/#!/Dropzone) can be passed as a `dropzoneProps` object in order to customize the behavior of the Dropzone, such as restricting the size and type of files allowed. The following example will only accept CSV files smaller than 1 KB. Note that file type determination is not reliable across platforms (see the note on react-dropzone's docs about the `accept` prop), so be sure to test the behavior of your file upload restriction on all browsers and operating systems targeted by your application. +Any [props accepted by `react-dropzone`'s `Dropzone` component](https://react-dropzone.js.org/#!/Dropzone) can be passed as a `dropzoneProps` object in order to customize the behavior of the Dropzone, such as restricting the size and type of files allowed. You can also capture and act upon native `react-dropzone` errors using the exposed `DropzoneErrorCode` enum. The following example will only accept CSV files smaller than 1 KB. Note that file type determination is not reliable across platforms (see the note on react-dropzone's docs about the `accept` prop), so be sure to test the behavior of your file upload restriction on all browsers and operating systems targeted by your application. #### IMPORTANT: A note about security diff --git a/packages/react-core/src/components/FileUpload/examples/FileUploadTextWithRestrictions.tsx b/packages/react-core/src/components/FileUpload/examples/FileUploadTextWithRestrictions.tsx index 15858108488..a942654f600 100644 --- a/packages/react-core/src/components/FileUpload/examples/FileUploadTextWithRestrictions.tsx +++ b/packages/react-core/src/components/FileUpload/examples/FileUploadTextWithRestrictions.tsx @@ -1,6 +1,7 @@ import React from 'react'; import { FileUpload, + DropzoneErrorCode, FileUploadHelperText, Form, FormGroup, @@ -9,13 +10,13 @@ import { DropEvent, Icon } from '@patternfly/react-core'; -import ExclamationCircleIcon from '@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon'; export const TextFileUploadWithRestrictions: React.FunctionComponent = () => { const [value, setValue] = React.useState(''); const [filename, setFilename] = React.useState(''); const [isLoading, setIsLoading] = React.useState(false); const [isRejected, setIsRejected] = React.useState(false); + const [message, setMessage] = React.useState('Must be a CSV file no larger than 1 KB'); const handleFileInputChange = (_, file: File) => { setFilename(file.name); @@ -29,16 +30,25 @@ export const TextFileUploadWithRestrictions: React.FunctionComponent = () => { setValue(value); }; - const handleClear = (_event: React.MouseEvent) => { + const reset = () => { setFilename(''); setValue(''); + }; + + const handleClear = (_event: React.MouseEvent) => { + reset(); setIsRejected(false); }; const handleFileRejected = () => { + reset(); setIsRejected(true); }; + const handleFileAccepted = () => { + setIsRejected(false); + }; + const handleFileReadStarted = (_event: DropEvent, _fileHandle: File) => { setIsLoading(true); }; @@ -66,7 +76,16 @@ export const TextFileUploadWithRestrictions: React.FunctionComponent = () => { dropzoneProps={{ accept: { 'text/csv': ['.csv'] }, maxSize: 1024, - onDropRejected: handleFileRejected + onDropRejected: (rejections) => { + const error = rejections[0].errors[0]; + if (error.code === DropzoneErrorCode.FileTooLarge) { + setMessage('File is too big'); + } else if (error.code === DropzoneErrorCode.FileInvalidType) { + setMessage('File is not a CSV file'); + } + handleFileRejected(); + }, + onDropAccepted: handleFileAccepted }} validated={isRejected ? 'error' : 'default'} browseButtonText="Upload" @@ -77,10 +96,8 @@ export const TextFileUploadWithRestrictions: React.FunctionComponent = () => { {isRejected ? ( <> - - - - Must be a CSV file no larger than 1 KB + + {message} ) : ( 'Upload a CSV file'