1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
5 import React from 'react';
6 import classnames from 'classnames';
10 Table, TableBody, TableCell, TableHead, TableRow,
14 } from '@material-ui/core';
15 import { withStyles } from '@material-ui/core';
16 import Dropzone from 'react-dropzone';
17 import { CloudUploadIcon, RemoveIcon } from "../icon/icon";
18 import { formatFileSize, formatProgress, formatUploadSpeed } from "common/formatters";
19 import { UploadFile } from 'store/file-uploader/file-uploader-actions';
21 type CssRules = "root" | "dropzone" | "dropzoneWrapper" | "container" | "uploadIcon"
22 | "dropzoneBorder" | "dropzoneBorderLeft" | "dropzoneBorderRight" | "dropzoneBorderTop" | "dropzoneBorderBottom"
23 | "dropzoneBorderHorzActive" | "dropzoneBorderVertActive" | "deleteButton" | "deleteButtonDisabled" | "deleteIcon";
25 const styles: StyleRulesCallback<CssRules> = theme => ({
37 border: "1px solid rgba(0, 0, 0, 0.42)",
38 boxSizing: 'border-box',
43 transition: "transform 200ms cubic-bezier(0.0, 0, 0.2, 1) 0ms",
44 pointerEvents: "none",
45 backgroundColor: "#6a1b9a"
52 transform: "scaleY(0)",
54 dropzoneBorderRight: {
59 transform: "scaleY(0)",
66 transform: "scaleX(0)",
68 dropzoneBorderBottom: {
73 transform: "scaleX(0)",
75 dropzoneBorderHorzActive: {
76 transform: "scaleY(1)"
78 dropzoneBorderVertActive: {
79 transform: "scaleX(1)"
85 verticalAlign: "middle"
90 deleteButtonDisabled: {
98 interface FileUploadPropsData {
101 onDrop: (files: File[]) => void;
102 onDelete: (file: UploadFile) => void;
105 interface FileUploadState {
109 export type FileUploadProps = FileUploadPropsData & WithStyles<CssRules>;
111 export const FileUpload = withStyles(styles)(
112 class extends React.Component<FileUploadProps, FileUploadState> {
113 constructor(props: FileUploadProps) {
119 onDelete = (event: React.MouseEvent<HTMLTableCellElement>, file: UploadFile): void => {
120 const { onDelete, disabled } = this.props;
122 event.stopPropagation();
128 let interval = setInterval(() => {
129 const key = Object.keys((window as any).cancelTokens).find(key => key.indexOf(file.file.name) > -1);
132 clearInterval(interval);
133 (window as any).cancelTokens[key]();
134 delete (window as any).cancelTokens[key];
140 const { classes, onDrop, disabled, files } = this.props;
141 return <div className={"file-upload-dropzone " + classes.dropzoneWrapper}>
142 <div className={classnames(classes.dropzoneBorder, classes.dropzoneBorderLeft, { [classes.dropzoneBorderHorzActive]: this.state.focused })} />
143 <div className={classnames(classes.dropzoneBorder, classes.dropzoneBorderRight, { [classes.dropzoneBorderHorzActive]: this.state.focused })} />
144 <div className={classnames(classes.dropzoneBorder, classes.dropzoneBorderTop, { [classes.dropzoneBorderVertActive]: this.state.focused })} />
145 <div className={classnames(classes.dropzoneBorder, classes.dropzoneBorderBottom, { [classes.dropzoneBorderVertActive]: this.state.focused })} />
146 <Dropzone className={classes.dropzone}
147 onDrop={files => onDrop(files)}
149 const el = document.getElementsByClassName("file-upload-dropzone")[0];
150 const inputs = el.getElementsByTagName("input");
151 if (inputs.length > 0) {
155 data-cy="drag-and-drop"
169 {files.length === 0 &&
170 <Grid container justify="center" alignItems="center" className={classes.container}>
171 <Grid item component={"span"}>
172 <Typography variant='subtitle1'>
173 <CloudUploadIcon className={classes.uploadIcon} /> Drag and drop data or click to browse
178 <Table style={{ width: "100%" }}>
181 <TableCell>File name</TableCell>
182 <TableCell>File size</TableCell>
183 <TableCell>Upload speed</TableCell>
184 <TableCell>Upload progress</TableCell>
185 <TableCell>Delete</TableCell>
190 <TableRow key={f.id}>
191 <TableCell>{f.file.name}</TableCell>
192 <TableCell>{formatFileSize(f.file.size)}</TableCell>
193 <TableCell>{formatUploadSpeed(f.prevLoaded, f.loaded, f.prevTime, f.currentTime)}</TableCell>
194 <TableCell>{formatProgress(f.loaded, f.total)}</TableCell>
198 onClick={(event: React.MouseEvent<HTMLTableCellElement>) => this.onDelete(event, f)}
199 className={disabled ? classnames(classes.deleteButtonDisabled, classes.deleteIcon) : classnames(classes.deleteButton, classes.deleteIcon)}