Fix correct bytes not being sent, fix showing upload progress and speed
[arvados-workbench2.git] / src / views-components / dialog-create / dialog-collection-create.tsx
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 import * as React from 'react';
6 import { reduxForm, Field } from 'redux-form';
7 import { compose } from 'redux';
8 import TextField from '@material-ui/core/TextField';
9 import Dialog from '@material-ui/core/Dialog';
10 import DialogActions from '@material-ui/core/DialogActions';
11 import DialogContent from '@material-ui/core/DialogContent';
12 import DialogTitle from '@material-ui/core/DialogTitle';
13 import { Button, StyleRulesCallback, WithStyles, withStyles, CircularProgress } from '@material-ui/core';
14
15 import { COLLECTION_NAME_VALIDATION, COLLECTION_DESCRIPTION_VALIDATION } from '../../validators/create-project/create-project-validator';
16 import { FileUpload } from "../../components/file-upload/file-upload";
17 import { connect, DispatchProp } from "react-redux";
18 import { RootState } from "../../store/store";
19 import { collectionUploaderActions, UploadFile } from "../../store/collections/uploader/collection-uploader-actions";
20
21 type CssRules = "button" | "lastButton" | "formContainer" | "textField" | "createProgress" | "dialogActions";
22
23 const styles: StyleRulesCallback<CssRules> = theme => ({
24     button: {
25         marginLeft: theme.spacing.unit
26     },
27     lastButton: {
28         marginLeft: theme.spacing.unit,
29         marginRight: "20px",
30     },
31     formContainer: {
32         display: "flex",
33         flexDirection: "column",
34     },
35     textField: {
36         marginBottom: theme.spacing.unit * 3
37     },
38     createProgress: {
39         position: "absolute",
40         minWidth: "20px",
41         right: "110px"
42     },
43     dialogActions: {
44         marginBottom: theme.spacing.unit * 3
45     }
46 });
47
48 interface DialogCollectionCreateProps {
49     open: boolean;
50     handleClose: () => void;
51     onSubmit: (data: { name: string, description: string }, files: UploadFile[]) => void;
52     handleSubmit: any;
53     submitting: boolean;
54     invalid: boolean;
55     pristine: boolean;
56     files: UploadFile[];
57 }
58
59 interface TextFieldProps {
60     label: string;
61     floatinglabeltext: string;
62     className?: string;
63     input?: string;
64     meta?: any;
65 }
66
67 export const DialogCollectionCreate = compose(
68     connect((state: RootState) => ({
69         files: state.collections.uploader
70     })),
71     reduxForm({ form: 'collectionCreateDialog' }),
72     withStyles(styles))(
73     class DialogCollectionCreate extends React.Component<DialogCollectionCreateProps & DispatchProp & WithStyles<CssRules>> {
74         render() {
75             const { classes, open, handleClose, handleSubmit, onSubmit, submitting, invalid, pristine, files } = this.props;
76
77             return (
78                 <Dialog
79                     open={open}
80                     onClose={handleClose}
81                     fullWidth={true}
82                     maxWidth='sm'
83                     disableBackdropClick={true}
84                     disableEscapeKeyDown={true}>
85                     <form onSubmit={handleSubmit((data: any) => onSubmit(data, files))}>
86                         <DialogTitle id="form-dialog-title">Create a collection</DialogTitle>
87                         <DialogContent className={classes.formContainer}>
88                             <Field name="name"
89                                     disabled={submitting}
90                                     component={this.renderTextField}
91                                     floatinglabeltext="Collection Name"
92                                     validate={COLLECTION_NAME_VALIDATION}
93                                     className={classes.textField}
94                                     label="Collection Name"/>
95                             <Field name="description"
96                                     disabled={submitting}
97                                     component={this.renderTextField}
98                                     floatinglabeltext="Description - optional"
99                                     validate={COLLECTION_DESCRIPTION_VALIDATION}
100                                     className={classes.textField}
101                                     label="Description - optional"/>
102                             <FileUpload
103                                 files={files}
104                                 onDrop={files => this.props.dispatch(collectionUploaderActions.SET_UPLOAD_FILES(files))}/>
105                         </DialogContent>
106                         <DialogActions className={classes.dialogActions}>
107                             <Button onClick={handleClose} className={classes.button} color="primary"
108                                     disabled={submitting}>CANCEL</Button>
109                             <Button type="submit"
110                                     className={classes.lastButton}
111                                     color="primary"
112                                     disabled={invalid || submitting || pristine}
113                                     variant="contained">
114                                 CREATE A COLLECTION
115                             </Button>
116                             {submitting && <CircularProgress size={20} className={classes.createProgress}/>}
117                         </DialogActions>
118                     </form>
119                 </Dialog>
120             );
121         }
122
123         renderTextField = ({ input, label, meta: { touched, error }, ...custom }: TextFieldProps) => (
124             <TextField
125                 helperText={touched && error}
126                 label={label}
127                 className={this.props.classes.textField}
128                 error={touched && !!error}
129                 autoComplete='off'
130                 {...input}
131                 {...custom}
132             />
133         )
134     }
135 );