2019-05-25 17:41:27 +01:00
|
|
|
import React, { Fragment } from 'react';
|
2019-05-21 23:34:48 +01:00
|
|
|
import PropTypes from 'prop-types';
|
|
|
|
|
2019-05-25 09:45:49 +01:00
|
|
|
import { ValidatorForm } from 'react-material-ui-form-validator';
|
2019-05-21 23:34:48 +01:00
|
|
|
|
|
|
|
import { withStyles } from '@material-ui/core/styles';
|
|
|
|
import Button from '@material-ui/core/Button';
|
|
|
|
import LinearProgress from '@material-ui/core/LinearProgress';
|
|
|
|
import Typography from '@material-ui/core/Typography';
|
|
|
|
import Table from '@material-ui/core/Table';
|
|
|
|
import TableBody from '@material-ui/core/TableBody';
|
|
|
|
import TableCell from '@material-ui/core/TableCell';
|
2019-05-24 12:19:27 +01:00
|
|
|
import TableFooter from '@material-ui/core/TableFooter';
|
2019-05-21 23:34:48 +01:00
|
|
|
import TableHead from '@material-ui/core/TableHead';
|
|
|
|
import TableRow from '@material-ui/core/TableRow';
|
2019-05-25 17:41:27 +01:00
|
|
|
import Box from '@material-ui/core/Box';
|
|
|
|
|
2019-05-21 23:34:48 +01:00
|
|
|
import EditIcon from '@material-ui/icons/Edit';
|
|
|
|
import DeleteIcon from '@material-ui/icons/Delete';
|
2019-05-25 09:45:49 +01:00
|
|
|
import CloseIcon from '@material-ui/icons/Close';
|
|
|
|
import CheckIcon from '@material-ui/icons/Check';
|
2019-05-24 12:19:27 +01:00
|
|
|
import IconButton from '@material-ui/core/IconButton';
|
|
|
|
|
|
|
|
import UserForm from './UserForm';
|
2019-05-25 09:45:49 +01:00
|
|
|
import { withAuthenticationContext } from '../authentication/Context';
|
2019-05-21 23:34:48 +01:00
|
|
|
|
|
|
|
const styles = theme => ({
|
|
|
|
loadingSettings: {
|
2019-06-02 19:01:06 +01:00
|
|
|
margin: theme.spacing(0.5),
|
2019-05-21 23:34:48 +01:00
|
|
|
},
|
|
|
|
loadingSettingsDetails: {
|
2019-06-02 19:01:06 +01:00
|
|
|
margin: theme.spacing(4),
|
2019-05-21 23:34:48 +01:00
|
|
|
textAlign: "center"
|
|
|
|
},
|
|
|
|
button: {
|
2019-06-02 19:01:06 +01:00
|
|
|
marginRight: theme.spacing(2),
|
|
|
|
marginTop: theme.spacing(2),
|
2019-05-21 23:34:48 +01:00
|
|
|
},
|
|
|
|
table: {
|
2019-06-02 19:01:06 +01:00
|
|
|
'& td, & th': { padding: theme.spacing(0.5) }
|
2019-05-24 12:19:27 +01:00
|
|
|
},
|
|
|
|
actions: {
|
2019-05-25 09:45:49 +01:00
|
|
|
whiteSpace: "nowrap"
|
2019-05-24 12:19:27 +01:00
|
|
|
}
|
2019-05-21 23:34:48 +01:00
|
|
|
});
|
|
|
|
|
2019-05-24 12:19:27 +01:00
|
|
|
function compareUsers(a, b) {
|
|
|
|
if (a.username < b.username) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (a.username > b.username) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-05-21 23:34:48 +01:00
|
|
|
class ManageUsersForm extends React.Component {
|
|
|
|
|
2019-05-24 12:19:27 +01:00
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
this.state = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
createUser = () => {
|
|
|
|
this.setState({
|
|
|
|
creating: true,
|
|
|
|
user: {
|
|
|
|
username: "",
|
|
|
|
password: "",
|
2019-05-25 09:45:49 +01:00
|
|
|
admin: true
|
2019-05-24 12:19:27 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
uniqueUsername = username => {
|
|
|
|
return !this.props.userData.users.find(u => u.username === username);
|
|
|
|
}
|
|
|
|
|
2019-05-25 09:45:49 +01:00
|
|
|
noAdminConfigured = () => {
|
|
|
|
return !this.props.userData.users.find(u => u.admin);
|
2019-05-24 12:19:27 +01:00
|
|
|
}
|
|
|
|
|
2019-05-25 17:41:27 +01:00
|
|
|
removeUser = user => {
|
|
|
|
const { userData } = this.props;
|
|
|
|
const users = userData.users.filter(u => u.username !== user.username);
|
|
|
|
this.props.setData({ ...userData, users });
|
|
|
|
}
|
|
|
|
|
2019-05-24 12:19:27 +01:00
|
|
|
startEditingUser = user => {
|
|
|
|
this.setState({
|
|
|
|
creating: false,
|
|
|
|
user
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
cancelEditingUser = () => {
|
|
|
|
this.setState({
|
|
|
|
user: undefined
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
doneEditingUser = () => {
|
|
|
|
const { user } = this.state;
|
|
|
|
const { userData } = this.props;
|
2019-05-25 17:41:27 +01:00
|
|
|
const users = userData.users.filter(u => u.username !== user.username);
|
2019-05-24 12:19:27 +01:00
|
|
|
users.push(user);
|
|
|
|
this.props.setData({ ...userData, users });
|
|
|
|
this.setState({
|
|
|
|
user: undefined
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
handleUserValueChange = name => event => {
|
|
|
|
const { user } = this.state;
|
2019-05-25 09:45:49 +01:00
|
|
|
this.setState({
|
|
|
|
user: {
|
|
|
|
...user, [name]: event.target.value
|
|
|
|
}
|
|
|
|
});
|
2019-05-24 12:19:27 +01:00
|
|
|
};
|
|
|
|
|
2019-05-25 09:45:49 +01:00
|
|
|
handleUserCheckboxChange = name => event => {
|
|
|
|
const { user } = this.state;
|
|
|
|
this.setState({
|
|
|
|
user: {
|
|
|
|
...user, [name]: event.target.checked
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
onSubmit = () => {
|
|
|
|
this.props.onSubmit();
|
2019-05-25 17:41:27 +01:00
|
|
|
this.props.authenticationContext.refresh();
|
2019-05-25 09:45:49 +01:00
|
|
|
}
|
|
|
|
|
2019-05-21 23:34:48 +01:00
|
|
|
render() {
|
2019-05-25 09:45:49 +01:00
|
|
|
const { classes, userData, userDataFetched, errorMessage, onReset } = this.props;
|
2019-05-24 12:19:27 +01:00
|
|
|
const { user, creating } = this.state;
|
2019-05-21 23:34:48 +01:00
|
|
|
return (
|
2019-05-26 19:09:34 +01:00
|
|
|
!userDataFetched ?
|
|
|
|
<div className={classes.loadingSettings}>
|
|
|
|
<LinearProgress className={classes.loadingSettingsDetails} />
|
|
|
|
<Typography variant="h4" className={classes.loadingSettingsDetails}>
|
|
|
|
Loading...
|
|
|
|
</Typography>
|
|
|
|
</div>
|
|
|
|
:
|
|
|
|
userData ?
|
|
|
|
<Fragment>
|
|
|
|
<ValidatorForm onSubmit={this.onSubmit}>
|
|
|
|
<Table className={classes.table}>
|
|
|
|
<TableHead>
|
|
|
|
<TableRow>
|
|
|
|
<TableCell>Username</TableCell>
|
|
|
|
<TableCell align="center">Admin?</TableCell>
|
|
|
|
<TableCell />
|
|
|
|
</TableRow>
|
|
|
|
</TableHead>
|
|
|
|
<TableBody>
|
|
|
|
{userData.users.sort(compareUsers).map(user => (
|
|
|
|
<TableRow key={user.username}>
|
|
|
|
<TableCell component="th" scope="row">
|
|
|
|
{user.username}
|
|
|
|
</TableCell>
|
|
|
|
<TableCell align="center">
|
|
|
|
{
|
|
|
|
user.admin ? <CheckIcon /> : <CloseIcon />
|
|
|
|
}
|
|
|
|
</TableCell>
|
|
|
|
<TableCell align="center">
|
|
|
|
<IconButton aria-label="Delete" onClick={() => this.removeUser(user)}>
|
|
|
|
<DeleteIcon />
|
|
|
|
</IconButton>
|
|
|
|
<IconButton aria-label="Edit" onClick={() => this.startEditingUser(user)}>
|
|
|
|
<EditIcon />
|
|
|
|
</IconButton>
|
|
|
|
</TableCell>
|
|
|
|
</TableRow>
|
|
|
|
))}
|
|
|
|
</TableBody>
|
|
|
|
<TableFooter>
|
|
|
|
<TableRow>
|
|
|
|
<TableCell colSpan={2} />
|
|
|
|
<TableCell align="center">
|
|
|
|
<Button variant="contained" color="secondary" onClick={this.createUser}>
|
|
|
|
Add User
|
|
|
|
</Button>
|
|
|
|
</TableCell>
|
|
|
|
</TableRow>
|
|
|
|
</TableFooter>
|
|
|
|
</Table>
|
|
|
|
{
|
|
|
|
this.noAdminConfigured() &&
|
|
|
|
<Typography component="div" variant="body1">
|
2019-05-27 21:01:00 +01:00
|
|
|
<Box bgcolor="error.main" color="error.contrastText" p={2} mt={2} mb={2}>
|
2019-05-26 19:09:34 +01:00
|
|
|
You must have at least one admin user configured.
|
|
|
|
</Box>
|
2019-05-21 23:34:48 +01:00
|
|
|
</Typography>
|
2019-05-26 19:09:34 +01:00
|
|
|
}
|
|
|
|
<Button variant="contained" color="primary" className={classes.button} type="submit" disabled={this.noAdminConfigured()}>
|
|
|
|
Save
|
|
|
|
</Button>
|
|
|
|
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
|
|
|
|
Reset
|
|
|
|
</Button>
|
|
|
|
</ValidatorForm>
|
|
|
|
{
|
|
|
|
user &&
|
|
|
|
<UserForm
|
|
|
|
user={user}
|
|
|
|
creating={creating}
|
|
|
|
onDoneEditing={this.doneEditingUser}
|
|
|
|
onCancelEditing={this.cancelEditingUser}
|
|
|
|
handleValueChange={this.handleUserValueChange}
|
|
|
|
handleCheckboxChange={this.handleUserCheckboxChange}
|
|
|
|
uniqueUsername={this.uniqueUsername}
|
|
|
|
/>
|
|
|
|
}
|
|
|
|
</Fragment>
|
|
|
|
:
|
|
|
|
<div className={classes.loadingSettings}>
|
|
|
|
<Typography variant="h4" className={classes.loadingSettingsDetails}>
|
|
|
|
{errorMessage}
|
|
|
|
</Typography>
|
|
|
|
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
|
|
|
|
Reset
|
|
|
|
</Button>
|
|
|
|
</div>
|
2019-05-21 23:34:48 +01:00
|
|
|
);
|
|
|
|
}
|
2019-05-24 12:19:27 +01:00
|
|
|
|
2019-05-21 23:34:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ManageUsersForm.propTypes = {
|
|
|
|
classes: PropTypes.object.isRequired,
|
2019-05-24 12:19:27 +01:00
|
|
|
userData: PropTypes.object,
|
|
|
|
userDataFetched: PropTypes.bool.isRequired,
|
2019-05-21 23:34:48 +01:00
|
|
|
errorMessage: PropTypes.string,
|
|
|
|
onSubmit: PropTypes.func.isRequired,
|
|
|
|
onReset: PropTypes.func.isRequired,
|
2019-05-24 12:19:27 +01:00
|
|
|
setData: PropTypes.func.isRequired,
|
2019-05-26 19:09:34 +01:00
|
|
|
handleValueChange: PropTypes.func.isRequired,
|
|
|
|
authenticationContext: PropTypes.object.isRequired,
|
2019-05-21 23:34:48 +01:00
|
|
|
};
|
|
|
|
|
2019-05-25 09:45:49 +01:00
|
|
|
export default withAuthenticationContext(withStyles(styles)(ManageUsersForm));
|