From a0ffb9093cd7c684dd96edee17c577afa8771d84 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Jun 2022 11:10:00 +0200 Subject: [PATCH] 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 Co-authored-by: Ashley Harrison Co-authored-by: Levente Balogh Co-authored-by: Jack Westbrook --- packages/grafana-ui/package.json | 2 +- .../FileDropzone/FileDropzone.story.tsx | 17 +++--- .../FileDropzone/FileDropzone.test.tsx | 10 +++- .../components/FileDropzone/FileDropzone.tsx | 58 ++++++++++++++++--- .../dimensions/editors/FileUploader.tsx | 2 +- yarn.lock | 24 ++++---- 6 files changed, 81 insertions(+), 32 deletions(-) diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index 8643d0b0eb9..655102a2ea9 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -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", diff --git a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx index 32466894539..d335d69bd00 100644 --- a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx +++ b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx @@ -16,15 +16,18 @@ export default { page: mdx, }, }, - argTypes: { - onLoad: { action: 'onLoad' }, - }, } as Meta; -export const Basic: Story = (args) => { - return ; +const Template: Story = (args) => ; + +export const Basic = Template.bind({}); + +export const WithCustomFileList = Template.bind({}); +WithCustomFileList.args = { + fileListRenderer: (file) =>
Custom rendered item {file.file.name}
, }; -export const WithCustomFileList: Story = () => { - return
Custom rendered item {file.file.name}
} />; +export const OnlyAcceptingCertainFiles = Template.bind({}); +OnlyAcceptingCertainFiles.args = { + options: { accept: { 'application/json': ['.json'] } }, }; diff --git a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx index 3f970c5cd88..b10c9160d08 100644 --- a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx +++ b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx @@ -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(); 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(); 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(); + + expect(screen.getByText('Accepted file types: .json, .txt')).toBeInTheDocument(); + }); + it('should handle file removal from the list', async () => { render(); diff --git a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx index 89f81427c19..1c8f24dec6e 100644 --- a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx +++ b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx @@ -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 & { + // 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 ?? } {options?.accept && ( - {getAcceptedFileTypeText(options)} + {getAcceptedFileTypeText(options.accept)} )} {fileList} ); } +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, 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({ ); } -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 { diff --git a/public/app/features/dimensions/editors/FileUploader.tsx b/public/app/features/dimensions/editors/FileUploader.tsx index 0a2c9d61546..7ea6c151039 100644 --- a/public/app/features/dimensions/editors/FileUploader.tsx +++ b/public/app/features/dimensions/editors/FileUploader.tsx @@ -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 ( = 16.8" - checksum: cc8c2036c72cbe02ddea1e141de45aeee7b399321b5791174d04fb8c1f52eb2ee3ae2d3fb1240fc23008a435c4ceb437e85831f0388a6b34be2bc39417701096 + react: ">= 16.8 || 18.0.0" + checksum: 8556d997d66bad79fe165a30d6dc8f917c67d8c7d23069c417eb2a0da6df824ba71b84b532707711e184da105122f6a6e81104341dc5b8c0f96e318267fdda91 languageName: node linkType: hard