Update dependency react-dropzone to v14 (#49243)

* Update dependency react-dropzone to v14

* Changes needed for react-dropzone v13

* feat(FileDropzone): update props to be backward compatible

* refactor(filedropzone): clean up component story

Co-authored-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
Co-authored-by: Jack Westbrook <jack.westbrook@gmail.com>
This commit is contained in:
renovate[bot] 2022-06-21 11:10:00 +02:00 committed by GitHub
parent 62531715b3
commit a0ffb9093c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 81 additions and 32 deletions

View File

@ -73,7 +73,7 @@
"react-colorful": "5.5.1",
"react-custom-scrollbars-2": "4.5.0",
"react-dom": "17.0.2",
"react-dropzone": "12.0.4",
"react-dropzone": "14.2.1",
"react-highlight-words": "0.18.0",
"react-hook-form": "7.5.3",
"react-inlinesvg": "3.0.0",

View File

@ -16,15 +16,18 @@ export default {
page: mdx,
},
},
argTypes: {
onLoad: { action: 'onLoad' },
},
} as Meta;
export const Basic: Story<FileDropzoneProps> = (args) => {
return <FileDropzone {...args} />;
const Template: Story<FileDropzoneProps> = (args) => <FileDropzone {...args} />;
export const Basic = Template.bind({});
export const WithCustomFileList = Template.bind({});
WithCustomFileList.args = {
fileListRenderer: (file) => <div>Custom rendered item {file.file.name}</div>,
};
export const WithCustomFileList: Story<FileDropzoneProps> = () => {
return <FileDropzone fileListRenderer={(file) => <div>Custom rendered item {file.file.name}</div>} />;
export const OnlyAcceptingCertainFiles = Template.bind({});
OnlyAcceptingCertainFiles.args = {
options: { accept: { 'application/json': ['.json'] } },
};

View File

@ -27,18 +27,24 @@ describe('The FileDropzone component', () => {
expect(screen.getByText('Upload file')).toBeInTheDocument();
});
it('should show accepted file type when passed in the options as a string', () => {
it('should show the accepted file type(s) when passed in as a string', () => {
render(<FileDropzone options={{ accept: '.json' }} />);
expect(screen.getByText('Accepted file type: .json')).toBeInTheDocument();
});
it('should show accepted file types when passed in the options as a string array', () => {
it('should show the accepted file type(s) when passed in as a array of strings', () => {
render(<FileDropzone options={{ accept: ['.json', '.txt'] }} />);
expect(screen.getByText('Accepted file types: .json, .txt')).toBeInTheDocument();
});
it('should show the accepted file type(s) when passed in as an `Accept` object', () => {
render(<FileDropzone options={{ accept: { 'text/*': ['.json', '.txt'] } }} />);
expect(screen.getByText('Accepted file types: .json, .txt')).toBeInTheDocument();
});
it('should handle file removal from the list', async () => {
render(<FileDropzone />);

View File

@ -1,7 +1,7 @@
import { css, cx } from '@emotion/css';
import { uniqueId } from 'lodash';
import { uniqueId, isString } from 'lodash';
import React, { ReactNode, useCallback, useState } from 'react';
import { DropEvent, DropzoneOptions, FileRejection, useDropzone } from 'react-dropzone';
import { DropEvent, DropzoneOptions, FileRejection, useDropzone, Accept } from 'react-dropzone';
import { GrafanaTheme2 } from '@grafana/data';
@ -10,6 +10,11 @@ import { Icon } from '../Icon/Icon';
import { FileListItem } from './FileListItem';
type BackwardsCompatibleDropzoneOptions = Omit<DropzoneOptions, 'accept'> & {
// For backward compatibility we are still allowing the old `string | string[]` format for adding accepted file types (format changed in v13.0.0)
accept?: string | string[] | Accept;
};
export interface FileDropzoneProps {
/**
* Use the children property to have custom dropzone view.
@ -25,7 +30,7 @@ export interface FileDropzoneProps {
* maxFiles: 0,
* }
*/
options?: DropzoneOptions;
options?: BackwardsCompatibleDropzoneOptions;
/**
* Use this to change the FileReader's read.
*/
@ -145,6 +150,7 @@ export function FileDropzone({ options, children, readAs, onLoad, fileListRender
...options,
useFsAccessApi: false,
onDrop,
accept: transformAcceptToNewFormat(options?.accept),
});
const theme = useTheme2();
const styles = getStyles(theme, isDragActive);
@ -162,13 +168,41 @@ export function FileDropzone({ options, children, readAs, onLoad, fileListRender
{children ?? <FileDropzoneDefaultChildren primaryText={getPrimaryText(files, options)} />}
</div>
{options?.accept && (
<small className={cx(styles.small, styles.acceptMargin)}>{getAcceptedFileTypeText(options)}</small>
<small className={cx(styles.small, styles.acceptMargin)}>{getAcceptedFileTypeText(options.accept)}</small>
)}
{fileList}
</div>
);
}
export function getMimeTypeByExtension(ext: string) {
if (['txt', 'json', 'csv', 'xls', 'yml'].some((e) => ext.match(e))) {
return 'text/plain';
}
return 'application/octet-stream';
}
export function transformAcceptToNewFormat(accept?: string | string[] | Accept): Accept | undefined {
if (isString(accept)) {
return {
[getMimeTypeByExtension(accept)]: [accept],
};
}
if (Array.isArray(accept)) {
return accept.reduce((prev: Record<string, string[]>, current) => {
const mime = getMimeTypeByExtension(current);
prev[mime] = prev[mime] ? [...prev[mime], current] : [current];
return prev;
}, {});
}
return accept;
}
export function FileDropzoneDefaultChildren({
primaryText = 'Upload file',
secondaryText = 'Drag and drop here or browse',
@ -184,19 +218,25 @@ export function FileDropzoneDefaultChildren({
</div>
);
}
function getPrimaryText(files: DropzoneFile[], options?: DropzoneOptions) {
function getPrimaryText(files: DropzoneFile[], options?: BackwardsCompatibleDropzoneOptions) {
if (options?.multiple === undefined || options?.multiple) {
return 'Upload file';
}
return files.length ? 'Replace file' : 'Upload file';
}
function getAcceptedFileTypeText(options: DropzoneOptions) {
if (Array.isArray(options.accept)) {
return `Accepted file types: ${options.accept.join(', ')}`;
function getAcceptedFileTypeText(accept: string | string[] | Accept) {
if (isString(accept)) {
return `Accepted file type: ${accept}`;
}
return `Accepted file type: ${options.accept}`;
if (Array.isArray(accept)) {
return `Accepted file types: ${accept.join(', ')}`;
}
// react-dropzone has updated the type of the "accept" parameter since v13.0.0:
// https://github.com/react-dropzone/react-dropzone/blob/master/src/index.js#L95
return `Accepted file types: ${Object.values(accept).flat().join(', ')}`;
}
function mapToCustomFile(file: File): DropzoneFile {

View File

@ -49,7 +49,7 @@ export const FileUploader = ({ mediaType, setFormData, setUpload, error }: Props
};
const acceptableFiles =
mediaType === 'icon' ? 'image/svg+xml' : 'image/jpeg,image/png,image/gif,image/png, image/webp';
mediaType === 'icon' ? { 'image/*': ['.svg', '.xml'] } : { 'image/*': ['.jpeg', '.png', '.gif', '.webp'] };
return (
<FileDropzone
readAs="readAsBinaryString"

View File

@ -4797,7 +4797,7 @@ __metadata:
react-custom-scrollbars-2: 4.5.0
react-docgen-typescript-loader: 3.7.2
react-dom: 17.0.2
react-dropzone: 12.0.4
react-dropzone: 14.2.1
react-highlight-words: 0.18.0
react-hook-form: 7.5.3
react-inlinesvg: 3.0.0
@ -19507,12 +19507,12 @@ __metadata:
languageName: node
linkType: hard
"file-selector@npm:^0.4.0":
version: 0.4.0
resolution: "file-selector@npm:0.4.0"
"file-selector@npm:^0.6.0":
version: 0.6.0
resolution: "file-selector@npm:0.6.0"
dependencies:
tslib: ^2.0.3
checksum: 1c9986e94bd033442cb4299d10d73d98fbc0b5f1af5b47d7a27b39f1e6bbd8d677f66c2628167da387166c652ad3c2429875042b453ba62f14945d903adf88d5
tslib: ^2.4.0
checksum: 7d051b6e5d793f3c6e2ab287ba5e7c2c6a0971bccc9d56e044c8047ba483e18f60fc0b5771c951dc707c0d15f4f36ccb4f1f1aaf385d21ec8f7700dadf8325ba
languageName: node
linkType: hard
@ -30691,16 +30691,16 @@ __metadata:
languageName: node
linkType: hard
"react-dropzone@npm:12.0.4":
version: 12.0.4
resolution: "react-dropzone@npm:12.0.4"
"react-dropzone@npm:14.2.1":
version: 14.2.1
resolution: "react-dropzone@npm:14.2.1"
dependencies:
attr-accept: ^2.2.2
file-selector: ^0.4.0
file-selector: ^0.6.0
prop-types: ^15.8.1
peerDependencies:
react: ">= 16.8"
checksum: cc8c2036c72cbe02ddea1e141de45aeee7b399321b5791174d04fb8c1f52eb2ee3ae2d3fb1240fc23008a435c4ceb437e85831f0388a6b34be2bc39417701096
react: ">= 16.8 || 18.0.0"
checksum: 8556d997d66bad79fe165a30d6dc8f917c67d8c7d23069c417eb2a0da6df824ba71b84b532707711e184da105122f6a6e81104341dc5b8c0f96e318267fdda91
languageName: node
linkType: hard