1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
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';
15 import { COLLECTION_NAME_VALIDATION, COLLECTION_DESCRIPTION_VALIDATION } from '../../validators/create-collection/create-collection-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";
21 type CssRules = "button" | "lastButton" | "formContainer" | "textField" | "createProgress" | "dialogActions";
23 const styles: StyleRulesCallback<CssRules> = theme => ({
25 marginLeft: theme.spacing.unit
28 marginLeft: theme.spacing.unit,
33 flexDirection: "column",
36 marginBottom: theme.spacing.unit * 3
44 marginBottom: theme.spacing.unit * 3
48 interface DialogCollectionCreateProps {
50 handleClose: () => void;
51 onSubmit: (data: { name: string, description: string }, files: UploadFile[]) => void;
59 interface TextFieldProps {
61 floatinglabeltext: string;
67 export const DialogCollectionCreate = compose(
68 connect((state: RootState) => ({
69 files: state.collections.uploader
71 reduxForm({ form: 'collectionCreateDialog' }),
73 class DialogCollectionCreate extends React.Component<DialogCollectionCreateProps & DispatchProp & WithStyles<CssRules>> {
75 const { classes, open, handleClose, handleSubmit, onSubmit, submitting, invalid, pristine, files } = this.props;
76 const busy = submitting || files.reduce(
77 (prev, curr) => prev + (curr.loaded > 0 && curr.loaded < curr.total ? 1 : 0), 0
85 disableBackdropClick={true}
86 disableEscapeKeyDown={true}>
87 <form onSubmit={handleSubmit((data: any) => onSubmit(data, files))}>
88 <DialogTitle id="form-dialog-title">Create a collection</DialogTitle>
89 <DialogContent className={classes.formContainer}>
92 component={this.renderTextField}
93 floatinglabeltext="Collection Name"
94 validate={COLLECTION_NAME_VALIDATION}
95 className={classes.textField}
96 label="Collection Name"/>
97 <Field name="description"
99 component={this.renderTextField}
100 floatinglabeltext="Description - optional"
101 validate={COLLECTION_DESCRIPTION_VALIDATION}
102 className={classes.textField}
103 label="Description - optional"/>
107 onDrop={files => this.props.dispatch(collectionUploaderActions.SET_UPLOAD_FILES(files))}/>
109 <DialogActions className={classes.dialogActions}>
110 <Button onClick={handleClose} className={classes.button} color="primary"
111 disabled={busy}>CANCEL</Button>
112 <Button type="submit"
113 className={classes.lastButton}
115 disabled={invalid || busy || pristine}
119 {busy && <CircularProgress size={20} className={classes.createProgress}/>}
126 renderTextField = ({ input, label, meta: { touched, error }, ...custom }: TextFieldProps) => (
128 helperText={touched && error}
130 className={this.props.classes.textField}
131 error={touched && !!error}