From ad6a4edfeb740bf656563953a0f0347d9566fe35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Bedi?= Date: Tue, 10 Aug 2021 10:23:49 +0200 Subject: [PATCH] UI: FileDropzone component to handle file list overwrite (#37685) * UI: FileDropzone component to handle file list overwrite * FileListItem: use type=button everywhere * Update packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx Co-authored-by: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com> * FileListItem: add aria-hidden and change cancel text * Update packages/grafana-ui/src/components/FileDropzone/FileListItem.test.tsx Co-authored-by: Alex Khomenko Co-authored-by: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com> Co-authored-by: Alex Khomenko --- .../FileDropzone/FileDropzone.story.tsx | 4 ++++ .../components/FileDropzone/FileDropzone.test.tsx | 11 +++++++++++ .../src/components/FileDropzone/FileDropzone.tsx | 14 ++++++++++++-- .../components/FileDropzone/FileListItem.test.tsx | 4 ++-- .../src/components/FileDropzone/FileListItem.tsx | 15 ++++++++++++--- 5 files changed, 41 insertions(+), 7 deletions(-) diff --git a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx index b4f5741c78e..9451ddfa1a8 100644 --- a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx +++ b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx @@ -21,3 +21,7 @@ export default { export const Basic: Story = (args) => { return ; }; + +export const WithCustomFileList: Story = () => { + return
Custom rendered item {file.file.name}
} />; +}; diff --git a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx index 09074c95a15..2d589f69ef6 100644 --- a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx +++ b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx @@ -107,6 +107,17 @@ describe('The FileDropzone component', () => { screen.getByText('Custom dropzone text'); }); + + it('should handle file list overwrite when fileListRenderer is passed', async () => { + render( null} />); + + dispatchEvt(screen.getByTestId('dropzone'), 'drop', mockData([file({})])); + + // need to await this in order to have the drop finished + await screen.findByTestId('dropzone'); + + expect(screen.queryByText('ping.json')).not.toBeInTheDocument(); + }); }); function dispatchEvt(node: HTMLElement, type: string, data: any) { diff --git a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx index 215d67c1642..3c49ffbc176 100644 --- a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx +++ b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx @@ -30,6 +30,11 @@ export interface FileDropzoneProps { * Use the onLoad function to get the result from FileReader. */ onLoad?: (result: string | ArrayBuffer | null) => void; + /** + * The fileListRenderer property can be used to overwrite the list of files. To not to show + * any list return null in the function. + */ + fileListRenderer?: (file: DropzoneFile, removeFile: (file: DropzoneFile) => void) => ReactNode; } export interface DropzoneFile { @@ -41,7 +46,7 @@ export interface DropzoneFile { retryUpload?: () => void; } -export function FileDropzone({ options, children, readAs, onLoad }: FileDropzoneProps) { +export function FileDropzone({ options, children, readAs, onLoad, fileListRenderer }: FileDropzoneProps) { const [files, setFiles] = useState([]); const setFileProperty = useCallback( @@ -133,7 +138,12 @@ export function FileDropzone({ options, children, readAs, onLoad }: FileDropzone const { getRootProps, getInputProps, isDragActive } = useDropzone({ ...options, onDrop }); const theme = useTheme2(); const styles = getStyles(theme, isDragActive); - const fileList = files.map((file) => ); + const fileList = files.map((file) => { + if (fileListRenderer) { + return fileListRenderer(file, removeFile); + } + return ; + }); return (
diff --git a/packages/grafana-ui/src/components/FileDropzone/FileListItem.test.tsx b/packages/grafana-ui/src/components/FileDropzone/FileListItem.test.tsx index 95b5caf5ae2..e1a0e75f2de 100644 --- a/packages/grafana-ui/src/components/FileDropzone/FileListItem.test.tsx +++ b/packages/grafana-ui/src/components/FileDropzone/FileListItem.test.tsx @@ -30,7 +30,7 @@ describe('The FileListItem component', () => { it('should show a progressbar when the progress prop has a value', () => { render(); - expect(screen.queryByText('Cancel')).not.toBeInTheDocument(); + expect(screen.queryByText('Cancel upload')).not.toBeInTheDocument(); expect(screen.getByText('46%')).toBeInTheDocument(); expect(screen.getByRole('progressbar')).toBeInTheDocument(); }); @@ -45,7 +45,7 @@ describe('The FileListItem component', () => { const abortUpload = jest.fn(); render(); - fireEvent.click(screen.getByRole('button', { name: 'Cancel' })); + fireEvent.click(screen.getByRole('button', { name: /cancel/i })); expect(abortUpload).toBeCalledTimes(1); }); diff --git a/packages/grafana-ui/src/components/FileDropzone/FileListItem.tsx b/packages/grafana-ui/src/components/FileDropzone/FileListItem.tsx index 27255b55731..cf039248391 100644 --- a/packages/grafana-ui/src/components/FileDropzone/FileListItem.tsx +++ b/packages/grafana-ui/src/components/FileDropzone/FileListItem.tsx @@ -24,11 +24,19 @@ export function FileListItem({ file: customFile, removeFile }: FileListItemProps <> {error.message} {retryUpload && ( - + )} {removeFile && ( removeFile(customFile)} tooltip={REMOVE_FILE} @@ -46,7 +54,7 @@ export function FileListItem({ file: customFile, removeFile }: FileListItemProps {Math.round((progress / file.size) * 100)}% {abortUpload && ( )} @@ -59,6 +67,7 @@ export function FileListItem({ file: customFile, removeFile }: FileListItemProps onClick={() => removeFile(customFile)} tooltip={REMOVE_FILE} aria-label={REMOVE_FILE} + type="button" tooltipPlacement="top" /> ) @@ -70,7 +79,7 @@ export function FileListItem({ file: customFile, removeFile }: FileListItemProps return (
- + {trimFileName(file.name)} {formattedValueToString(valueFormat)}