mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
parent
62531715b3
commit
a0ffb9093c
@ -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",
|
||||
|
@ -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'] } },
|
||||
};
|
||||
|
@ -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 />);
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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"
|
||||
|
24
yarn.lock
24
yarn.lock
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user