Feature #15256
Arvados-DCO-1.1-Signed-off-by: mateuszrojecki <mateusz.rojecki@contractors.roche.com>
uploading: boolean;
onSubmit: () => void;
onChange: (files: File[]) => void;
uploading: boolean;
onSubmit: () => void;
onChange: (files: File[]) => void;
+ onDelete: (files: File[]) => void;
}
export const FilesUploadDialog = (props: FilesUploadDialogProps & WithDialogProps<{}>) =>
}
export const FilesUploadDialog = (props: FilesUploadDialogProps & WithDialogProps<{}>) =>
files={props.files}
disabled={props.uploading}
onDrop={props.onChange}
files={props.files}
disabled={props.uploading}
onDrop={props.onChange}
+ onDelete={props.onDelete}
/>
</DialogContent>
<DialogActions>
/>
</DialogContent>
<DialogActions>
StyleRulesCallback,
Table, TableBody, TableCell, TableHead, TableRow,
Typography,
StyleRulesCallback,
Table, TableBody, TableCell, TableHead, TableRow,
Typography,
+ WithStyles,
+ IconButton
} from '@material-ui/core';
import { withStyles } from '@material-ui/core';
import Dropzone from 'react-dropzone';
} from '@material-ui/core';
import { withStyles } from '@material-ui/core';
import Dropzone from 'react-dropzone';
-import { CloudUploadIcon } from "../icon/icon";
+import { CloudUploadIcon, RemoveIcon } from "../icon/icon";
import { formatFileSize, formatProgress, formatUploadSpeed } from "~/common/formatters";
import { UploadFile } from '~/store/file-uploader/file-uploader-actions';
type CssRules = "root" | "dropzone" | "dropzoneWrapper" | "container" | "uploadIcon"
| "dropzoneBorder" | "dropzoneBorderLeft" | "dropzoneBorderRight" | "dropzoneBorderTop" | "dropzoneBorderBottom"
import { formatFileSize, formatProgress, formatUploadSpeed } from "~/common/formatters";
import { UploadFile } from '~/store/file-uploader/file-uploader-actions';
type CssRules = "root" | "dropzone" | "dropzoneWrapper" | "container" | "uploadIcon"
| "dropzoneBorder" | "dropzoneBorderLeft" | "dropzoneBorderRight" | "dropzoneBorderTop" | "dropzoneBorderBottom"
- | "dropzoneBorderHorzActive" | "dropzoneBorderVertActive";
+ | "dropzoneBorderHorzActive" | "dropzoneBorderVertActive" | "deleteButton" | "deleteButtonDisabled" | "deleteIcon";
const styles: StyleRulesCallback<CssRules> = theme => ({
root: {
const styles: StyleRulesCallback<CssRules> = theme => ({
root: {
},
uploadIcon: {
verticalAlign: "middle"
},
uploadIcon: {
verticalAlign: "middle"
+ },
+ deleteButton: {
+ cursor: "pointer"
+ },
+ deleteButtonDisabled: {
+ cursor: "not-allowed"
+ },
+ deleteIcon: {
+ marginLeft: "-6px"
files: UploadFile[];
disabled: boolean;
onDrop: (files: File[]) => void;
files: UploadFile[];
disabled: boolean;
onDrop: (files: File[]) => void;
+ onDelete: (files: File[]) => void;
}
interface FileUploadState {
}
interface FileUploadState {
+ onDelete = (event: React.MouseEvent<HTMLTableCellElement>, file: any): void => {
+ const { onDelete, disabled } = this.props;
+
+ event.stopPropagation();
+
+ if (!disabled) {
+ onDelete([file]);
+ }
+ }
render() {
const { classes, onDrop, disabled, files } = this.props;
return <div className={"file-upload-dropzone " + classes.dropzoneWrapper}>
render() {
const { classes, onDrop, disabled, files } = this.props;
return <div className={"file-upload-dropzone " + classes.dropzoneWrapper}>
<TableCell>File size</TableCell>
<TableCell>Upload speed</TableCell>
<TableCell>Upload progress</TableCell>
<TableCell>File size</TableCell>
<TableCell>Upload speed</TableCell>
<TableCell>Upload progress</TableCell>
+ <TableCell>Delete</TableCell>
</TableRow>
</TableHead>
<TableBody>
</TableRow>
</TableHead>
<TableBody>
<TableCell>{formatFileSize(f.file.size)}</TableCell>
<TableCell>{formatUploadSpeed(f.prevLoaded, f.loaded, f.prevTime, f.currentTime)}</TableCell>
<TableCell>{formatProgress(f.loaded, f.total)}</TableCell>
<TableCell>{formatFileSize(f.file.size)}</TableCell>
<TableCell>{formatUploadSpeed(f.prevLoaded, f.loaded, f.prevTime, f.currentTime)}</TableCell>
<TableCell>{formatProgress(f.loaded, f.total)}</TableCell>
+ <TableCell>
+ <IconButton
+ aria-label="Remove"
+ onClick={(event: React.MouseEvent<HTMLTableCellElement>) => this.onDelete(event, f)}
+ className={disabled ? classnames(classes.deleteButtonDisabled, classes.deleteIcon) : classnames(classes.deleteButton, classes.deleteIcon)}
+ >
+ <RemoveIcon />
+ </IconButton>
+ </TableCell>
+ </TableRow>
+export interface FileWithId extends File {
+ id: number;
+}
+
export const fileUploaderActions = unionize({
CLEAR_UPLOAD: ofType(),
SET_UPLOAD_FILES: ofType<File[]>(),
UPDATE_UPLOAD_FILES: ofType<File[]>(),
SET_UPLOAD_PROGRESS: ofType<{ fileId: number, loaded: number, total: number, currentTime: number }>(),
START_UPLOAD: ofType(),
export const fileUploaderActions = unionize({
CLEAR_UPLOAD: ofType(),
SET_UPLOAD_FILES: ofType<File[]>(),
UPDATE_UPLOAD_FILES: ofType<File[]>(),
SET_UPLOAD_PROGRESS: ofType<{ fileId: number, loaded: number, total: number, currentTime: number }>(),
START_UPLOAD: ofType(),
+ DELETE_UPLOAD_FILE: ofType<FileWithId[]>(),
});
export type FileUploaderAction = UnionOf<typeof fileUploaderActions>;
});
export type FileUploaderAction = UnionOf<typeof fileUploaderActions>;
return uniqUpdatedState;
},
return uniqUpdatedState;
},
+ DELETE_UPLOAD_FILE: files => {
+ const idToDelete: number = files[0].id;
+ const updatedState = state.filter( file => file.id !== idToDelete);
+
+ return updatedState;
+ },
START_UPLOAD: () => {
const startTime = Date.now();
return state.map(f => ({ ...f, startTime, prevTime: startTime }));
START_UPLOAD: () => {
const startTime = Date.now();
return state.map(f => ({ ...f, startTime, prevTime: startTime }));
import { RootState } from '~/store/store';
import { FileUploadProps } from '../../components/file-upload/file-upload';
import { Dispatch } from 'redux';
import { RootState } from '~/store/store';
import { FileUploadProps } from '../../components/file-upload/file-upload';
import { Dispatch } from 'redux';
-import { fileUploaderActions, getFileUploaderState } from '~/store/file-uploader/file-uploader-actions';
+import { fileUploaderActions, getFileUploaderState, FileWithId } from '~/store/file-uploader/file-uploader-actions';
import { WrappedFieldProps } from 'redux-form';
import { Typography } from '@material-ui/core';
import { WrappedFieldProps } from 'redux-form';
import { Typography } from '@material-ui/core';
files: state.fileUploader,
});
files: state.fileUploader,
});
-const mapDispatchToProps = (dispatch: Dispatch, { onDrop }: FileUploaderProps): Pick<FileUploadProps, 'onDrop'> => ({
+const mapDispatchToProps = (dispatch: Dispatch, { onDrop }: FileUploaderProps): Pick<FileUploadProps, 'onDrop' | 'onDelete'> => ({
onDrop: files => {
const state = dispatch<any>(getFileUploaderState());
if (files.length > 0 && state.length === 0) {
onDrop: files => {
const state = dispatch<any>(getFileUploaderState());
if (files.length > 0 && state.length === 0) {
+ onDelete: files => dispatch(fileUploaderActions.DELETE_UPLOAD_FILE(files as FileWithId[])),
});
export const FileUploader = connect(mapStateToProps, mapDispatchToProps)(FileUpload);
});
export const FileUploader = connect(mapStateToProps, mapDispatchToProps)(FileUpload);