mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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
This commit is contained in:
parent
b6db1ed524
commit
6bfd21ef0a
@ -33,6 +33,14 @@ describe('The FileDropzone component', () => {
|
|||||||
expect(screen.getByText('Accepted file type: .json')).toBeInTheDocument();
|
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(<FileDropzone options={{ maxSize: 1 }} />);
|
||||||
|
|
||||||
|
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', () => {
|
it('should show the accepted file type(s) when passed in as a array of strings', () => {
|
||||||
render(<FileDropzone options={{ accept: ['.json', '.txt'] }} />);
|
render(<FileDropzone options={{ accept: ['.json', '.txt'] }} />);
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { css, cx } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
import { isString, uniqueId } from 'lodash';
|
import { isString, uniqueId } from 'lodash';
|
||||||
import React, { ReactNode, useCallback, useState } from 'react';
|
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 { useTheme2 } from '../../themes';
|
||||||
import { Alert } from '../Alert/Alert';
|
import { Alert } from '../Alert/Alert';
|
||||||
@ -68,7 +68,7 @@ export function FileDropzone({
|
|||||||
onFileRemove,
|
onFileRemove,
|
||||||
}: FileDropzoneProps) {
|
}: FileDropzoneProps) {
|
||||||
const [files, setFiles] = useState<DropzoneFile[]>([]);
|
const [files, setFiles] = useState<DropzoneFile[]>([]);
|
||||||
const [errorMessages, setErrorMessages] = useState<string[]>([]);
|
const [fileErrors, setErrorMessages] = useState<FileError[]>([]);
|
||||||
|
|
||||||
const setFileProperty = useCallback(
|
const setFileProperty = useCallback(
|
||||||
(customFile: DropzoneFile, action: (customFileToModify: DropzoneFile) => void) => {
|
(customFile: DropzoneFile, action: (customFileToModify: DropzoneFile) => void) => {
|
||||||
@ -175,11 +175,15 @@ export function FileDropzone({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const setErrors = (rejectedFiles: FileRejection[]) => {
|
const setErrors = (rejectedFiles: FileRejection[]) => {
|
||||||
let errors: string[] = [];
|
let errors: FileError[] = [];
|
||||||
rejectedFiles.map((rejectedFile) => {
|
rejectedFiles.map((rejectedFile) => {
|
||||||
rejectedFile.errors.map((error) => {
|
rejectedFile.errors.map((newError) => {
|
||||||
if (errors.indexOf(error.message) === -1) {
|
if (
|
||||||
errors.push(error.message);
|
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);
|
setErrorMessages(errors);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getErrorMessages = () => {
|
const renderErrorMessages = (errors: FileError[]) => {
|
||||||
return (
|
return (
|
||||||
<div className={styles.errorAlert}>
|
<div className={styles.errorAlert}>
|
||||||
<Alert title="Upload failed" severity="error" onRemove={clearAlert}>
|
<Alert title="Upload failed" severity="error" onRemove={clearAlert}>
|
||||||
{errorMessages.map((error) => {
|
{errors.map((error) => {
|
||||||
return <div key={error}>{error}</div>;
|
switch (error.code) {
|
||||||
|
case ErrorCode.FileTooLarge:
|
||||||
|
const formattedSize = getValueFormat('decbytes')(options?.maxSize!);
|
||||||
|
return (
|
||||||
|
<div key={error.message + error.code}>
|
||||||
|
File is larger than {formattedValueToString(formattedSize)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return <div key={error.message + error.code}>{error.message}</div>;
|
||||||
|
}
|
||||||
})}
|
})}
|
||||||
</Alert>
|
</Alert>
|
||||||
</div>
|
</div>
|
||||||
@ -209,7 +223,7 @@ export function FileDropzone({
|
|||||||
<input {...getInputProps()} />
|
<input {...getInputProps()} />
|
||||||
{children ?? <FileDropzoneDefaultChildren primaryText={primaryTextSupplier(files, options)} />}
|
{children ?? <FileDropzoneDefaultChildren primaryText={primaryTextSupplier(files, options)} />}
|
||||||
</div>
|
</div>
|
||||||
{errorMessages.length > 0 && getErrorMessages()}
|
{fileErrors.length > 0 && renderErrorMessages(fileErrors)}
|
||||||
{options?.accept && (
|
{options?.accept && (
|
||||||
<small className={cx(styles.small, styles.acceptMargin)}>{getAcceptedFileTypeText(options.accept)}</small>
|
<small className={cx(styles.small, styles.acceptMargin)}>{getAcceptedFileTypeText(options.accept)}</small>
|
||||||
)}
|
)}
|
||||||
@ -261,11 +275,12 @@ export function FileDropzoneDefaultChildren({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
function getPrimaryText(files?: DropzoneFile[], options?: BackwardsCompatibleDropzoneOptions) {
|
|
||||||
|
function getPrimaryText(files: DropzoneFile[], options?: BackwardsCompatibleDropzoneOptions) {
|
||||||
if (options?.multiple === undefined || options?.multiple) {
|
if (options?.multiple === undefined || options?.multiple) {
|
||||||
return 'Upload file';
|
return 'Upload file';
|
||||||
}
|
}
|
||||||
return files && files.length ? 'Replace file' : 'Upload file';
|
return files.length ? 'Replace file' : 'Upload file';
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAcceptedFileTypeText(accept: string | string[] | Accept) {
|
function getAcceptedFileTypeText(accept: string | string[] | Accept) {
|
||||||
|
Loading…
Reference in New Issue
Block a user