duplicatedName flag renamed on isUniqName
[arvados-workbench2.git] / src / views-components / dialog-create / dialog-project-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 TextField from '@material-ui/core/TextField';
7 import Dialog from '@material-ui/core/Dialog';
8 import DialogActions from '@material-ui/core/DialogActions';
9 import DialogContent from '@material-ui/core/DialogContent';
10 import DialogTitle from '@material-ui/core/DialogTitle';
11 import { Button, StyleRulesCallback, WithStyles, withStyles, CircularProgress } from '@material-ui/core';
12
13 import Validator from '../../utils/dialog-validator';
14
15 interface ProjectCreateProps {
16   open: boolean;
17   pending: boolean;
18   error: string;
19   handleClose: () => void;
20   onSubmit: (data: { name: string, description: string }) => void;
21 }
22
23 interface DialogState {
24   name: string;
25   description: string;
26   isNameValid: boolean;
27   isDescriptionValid: boolean;
28   isUniqName: boolean;
29 }
30
31 class DialogProjectCreate extends React.Component<ProjectCreateProps & WithStyles<CssRules>> {
32   state: DialogState = {
33     name: '',
34     description: '',
35     isNameValid: false,
36     isDescriptionValid: true,
37     isUniqName: false
38   };
39
40   componentWillReceiveProps(nextProps: ProjectCreateProps) {
41     const { error } = nextProps;
42
43     if (this.props.error !== error) {
44       this.setState({ isUniqName: error });
45     }
46   }
47
48   render() {
49     const { name, description, isNameValid, isDescriptionValid, isUniqName } = this.state;
50     const { classes, open, handleClose, pending } = this.props;
51
52     return (
53       <Dialog
54         open={open}
55         onClose={handleClose}>
56         <div className={classes.dialog}>
57           <DialogTitle id="form-dialog-title" className={classes.dialogTitle}>Create a project</DialogTitle>
58           <DialogContent className={classes.dialogContent}>
59             <Validator
60               value={name}
61               onChange={e => this.isNameValid(e)}
62               isRequired={true}
63               isUniqName={isUniqName}
64               render={hasError =>
65                 <TextField
66                   margin="dense"
67                   className={classes.textField}
68                   id="name"
69                   onChange={e => this.handleProjectName(e)}
70                   label="Project name"
71                   error={hasError || isUniqName}
72                   fullWidth />} />
73             <Validator
74               value={description}
75               onChange={e => this.isDescriptionValid(e)}
76               isRequired={false}
77               render={hasError =>
78                 <TextField
79                   margin="dense"
80                   className={classes.textField}
81                   id="description"
82                   onChange={e => this.handleDescriptionValue(e)}
83                   label="Description - optional"
84                   error={hasError}
85                   fullWidth />} />
86           </DialogContent>
87           <DialogActions>
88             <Button onClick={handleClose} className={classes.button} color="primary" disabled={pending}>CANCEL</Button>
89             <Button onClick={this.handleSubmit}
90               className={classes.lastButton}
91               color="primary"
92               disabled={!isNameValid || (!isDescriptionValid && description.length > 0) || pending}
93               variant="contained">
94               CREATE A PROJECT
95             </Button>
96             {pending && <CircularProgress size={20} className={classes.createProgress} />}
97           </DialogActions>
98         </div>
99       </Dialog>
100     );
101   }
102
103   handleSubmit = () => {
104     this.props.onSubmit({
105       name: this.state.name,
106       description: this.state.description
107     });
108   }
109
110   handleProjectName(e: any) {
111     this.setState({
112       name: e.target.value,
113       isUniqName: ''
114     });
115   }
116
117   handleDescriptionValue(e: any) {
118     this.setState({
119       description: e.target.value,
120     });
121   }
122
123   isNameValid(value: boolean | string) {
124     this.setState({
125       isNameValid: value,
126     });
127   }
128
129   isDescriptionValid(value: boolean | string) {
130     this.setState({
131       isDescriptionValid: value,
132     });
133   }
134 }
135
136 type CssRules = "button" | "lastButton" | "dialogContent" | "textField" | "dialog" | "dialogTitle" | "createProgress";
137
138 const styles: StyleRulesCallback<CssRules> = theme => ({
139   button: {
140     marginLeft: theme.spacing.unit
141   },
142   lastButton: {
143     marginLeft: theme.spacing.unit,
144     marginRight: "20px",
145   },
146   dialogContent: {
147     marginTop: "20px",
148   },
149   dialogTitle: {
150     paddingBottom: "0"
151   },
152   textField: {
153     marginTop: "32px",
154   },
155   dialog: {
156     minWidth: "600px",
157     minHeight: "320px"
158   },
159   createProgress: {
160     position: "absolute",
161     minWidth: "20px",
162     right: "95px"
163   }
164 });
165
166 export default withStyles(styles)(DialogProjectCreate);