mirror of
https://github.com/Unleash/unleash.git
synced 2025-03-27 00:19:39 +01:00
Feat: admin users (#266)
* fix: make it work * fix: cleanup add/update users a bit * fix: fix * fix: fine tune
This commit is contained in:
parent
45bce4576d
commit
5166198f07
@ -3,10 +3,20 @@ import { Dialog, DialogTitle, DialogActions, DialogContent, Button } from '@mate
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ConditionallyRender from '../ConditionallyRender/ConditionallyRender';
|
import ConditionallyRender from '../ConditionallyRender/ConditionallyRender';
|
||||||
|
|
||||||
const ConfirmDialogue = ({ children, open, onClick, onClose, title, primaryButtonText, secondaryButtonText }) => (
|
const ConfirmDialogue = ({
|
||||||
|
children,
|
||||||
|
open,
|
||||||
|
onClick,
|
||||||
|
onClose,
|
||||||
|
title,
|
||||||
|
primaryButtonText,
|
||||||
|
secondaryButtonText,
|
||||||
|
fullWidth = false,
|
||||||
|
}) => (
|
||||||
<Dialog
|
<Dialog
|
||||||
open={open}
|
open={open}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
|
fullWidth={fullWidth}
|
||||||
aria-labelledby={'simple-modal-title'}
|
aria-labelledby={'simple-modal-title'}
|
||||||
aria-describedby={'simple-modal-description'}
|
aria-describedby={'simple-modal-description'}
|
||||||
>
|
>
|
||||||
@ -32,6 +42,7 @@ ConfirmDialogue.propTypes = {
|
|||||||
ariaLabel: PropTypes.string,
|
ariaLabel: PropTypes.string,
|
||||||
ariaDescription: PropTypes.string,
|
ariaDescription: PropTypes.string,
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
|
fullWidth: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ConfirmDialogue;
|
export default ConfirmDialogue;
|
||||||
|
@ -7,10 +7,10 @@ import AddUser from '../add-user-component';
|
|||||||
import ChangePassword from '../change-password-component';
|
import ChangePassword from '../change-password-component';
|
||||||
import UpdateUser from '../update-user-component';
|
import UpdateUser from '../update-user-component';
|
||||||
import DelUser from '../del-user-component';
|
import DelUser from '../del-user-component';
|
||||||
import { showPermissions } from '../util';
|
|
||||||
import ConditionallyRender from '../../../../component/common/ConditionallyRender/ConditionallyRender';
|
import ConditionallyRender from '../../../../component/common/ConditionallyRender/ConditionallyRender';
|
||||||
|
|
||||||
function UsersList({
|
function UsersList({
|
||||||
|
roles,
|
||||||
fetchUsers,
|
fetchUsers,
|
||||||
removeUser,
|
removeUser,
|
||||||
addUser,
|
addUser,
|
||||||
@ -68,6 +68,11 @@ function UsersList({
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const renderRole = roleId => {
|
||||||
|
const role = roles.find(r => r.id === roleId);
|
||||||
|
return role ? role.name : '';
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Table>
|
<Table>
|
||||||
@ -77,7 +82,7 @@ function UsersList({
|
|||||||
<TableCell>Created</TableCell>
|
<TableCell>Created</TableCell>
|
||||||
<TableCell>Username</TableCell>
|
<TableCell>Username</TableCell>
|
||||||
<TableCell>Name</TableCell>
|
<TableCell>Name</TableCell>
|
||||||
<TableCell>Access</TableCell>
|
<TableCell>Role</TableCell>
|
||||||
<TableCell>{hasPermission('ADMIN') ? 'Action' : ''}</TableCell>
|
<TableCell>{hasPermission('ADMIN') ? 'Action' : ''}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
@ -88,7 +93,7 @@ function UsersList({
|
|||||||
<TableCell>{formatFullDateTimeWithLocale(item.createdAt, location.locale)}</TableCell>
|
<TableCell>{formatFullDateTimeWithLocale(item.createdAt, location.locale)}</TableCell>
|
||||||
<TableCell style={{ textAlign: 'left' }}>{item.username || item.email}</TableCell>
|
<TableCell style={{ textAlign: 'left' }}>{item.username || item.email}</TableCell>
|
||||||
<TableCell style={{ textAlign: 'left' }}>{item.name}</TableCell>
|
<TableCell style={{ textAlign: 'left' }}>{item.name}</TableCell>
|
||||||
<TableCell>{showPermissions(item.permissions)}</TableCell>
|
<TableCell>{renderRole(item.rootRole)}</TableCell>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={hasPermission('ADMIN')}
|
condition={hasPermission('ADMIN')}
|
||||||
show={
|
show={
|
||||||
@ -104,34 +109,37 @@ function UsersList({
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
}
|
}
|
||||||
elseShow={
|
elseShow={<TableCell />}
|
||||||
<TableCell>
|
|
||||||
<IconButton aria-label="Change password" title="Change password" onClick={openPwDialog(item)}>
|
|
||||||
<Icon>lock</Icon>
|
|
||||||
</IconButton>
|
|
||||||
</TableCell>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
<br />
|
<br />
|
||||||
<Button variant="contained" color="primary" onClick={openDialog}>
|
<ConditionallyRender
|
||||||
Add new user
|
condition={hasPermission('ADMIN')}
|
||||||
</Button>
|
show={
|
||||||
|
<Button variant="contained" color="primary" onClick={openDialog}>
|
||||||
|
Add new user
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
elseShow={<small>PS! Only admins can add/remove users.</small>}
|
||||||
|
/>
|
||||||
|
|
||||||
<AddUser
|
<AddUser
|
||||||
showDialog={showDialog}
|
showDialog={showDialog}
|
||||||
closeDialog={closeDialog}
|
closeDialog={closeDialog}
|
||||||
addUser={addUser}
|
addUser={addUser}
|
||||||
validatePassword={validatePassword}
|
validatePassword={validatePassword}
|
||||||
|
roles={roles}
|
||||||
/>
|
/>
|
||||||
<UpdateUser
|
{updateDialog.open && <UpdateUser
|
||||||
showDialog={updateDialog.open}
|
showDialog={updateDialog.open}
|
||||||
closeDialog={closeUpdateDialog}
|
closeDialog={closeUpdateDialog}
|
||||||
updateUser={updateUser}
|
updateUser={updateUser}
|
||||||
user={updateDialog.user}
|
user={updateDialog.user}
|
||||||
/>
|
roles={roles}
|
||||||
|
/>}
|
||||||
<ChangePassword
|
<ChangePassword
|
||||||
showDialog={pwDialog.open}
|
showDialog={pwDialog.open}
|
||||||
closeDialog={closePwDialog}
|
closeDialog={closePwDialog}
|
||||||
@ -155,6 +163,7 @@ function UsersList({
|
|||||||
}
|
}
|
||||||
|
|
||||||
UsersList.propTypes = {
|
UsersList.propTypes = {
|
||||||
|
roles: PropTypes.array.isRequired,
|
||||||
users: PropTypes.array.isRequired,
|
users: PropTypes.array.isRequired,
|
||||||
fetchUsers: PropTypes.func.isRequired,
|
fetchUsers: PropTypes.func.isRequired,
|
||||||
removeUser: PropTypes.func.isRequired,
|
removeUser: PropTypes.func.isRequired,
|
||||||
|
@ -12,6 +12,7 @@ import { hasPermission } from '../../../../permissions';
|
|||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
users: state.userAdmin.toJS(),
|
users: state.userAdmin.toJS(),
|
||||||
|
roles: state.roles.get('root').toJS() || [],
|
||||||
location: state.settings.toJS().location || {},
|
location: state.settings.toJS().location || {},
|
||||||
hasPermission: permission => hasPermission(state.user.get('profile'), permission),
|
hasPermission: permission => hasPermission(state.user.get('profile'), permission),
|
||||||
});
|
});
|
||||||
|
@ -1,49 +1,28 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Dialogue from '../../../component/common/Dialogue';
|
import Dialogue from '../../../component/common/Dialogue';
|
||||||
import {
|
import UserForm from './user-form';
|
||||||
TextField,
|
|
||||||
DialogTitle,
|
|
||||||
DialogContent,
|
|
||||||
RadioGroup,
|
|
||||||
Radio,
|
|
||||||
FormControl,
|
|
||||||
FormControlLabel,
|
|
||||||
FormLabel,
|
|
||||||
} from '@material-ui/core';
|
|
||||||
import { trim } from '../../../component/common/util';
|
|
||||||
import commonStyles from '../../../component/common/common.module.scss';
|
|
||||||
|
|
||||||
const EMPTY = { userType: 'regular' };
|
function AddUser({ showDialog, closeDialog, addUser, roles }) {
|
||||||
|
const [data, setData] = useState({});
|
||||||
function AddUser({ showDialog, closeDialog, addUser, validatePassword }) {
|
|
||||||
const [data, setData] = useState(EMPTY);
|
|
||||||
const [error, setError] = useState({});
|
const [error, setError] = useState({});
|
||||||
|
|
||||||
const updateField = e => {
|
|
||||||
setData({
|
|
||||||
...data,
|
|
||||||
[e.target.name]: e.target.value,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateFieldWithTrim = e => {
|
|
||||||
setData({
|
|
||||||
...data,
|
|
||||||
[e.target.name]: trim(e.target.value),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const submit = async e => {
|
const submit = async e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!data.email) {
|
if (!data.email) {
|
||||||
setError({ general: 'You must specify the email adress' });
|
setError({ general: 'You must specify the email address' });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data.rootRole) {
|
||||||
|
setError({ general: 'You must specify a role for the user' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await addUser(data);
|
await addUser(data);
|
||||||
setData(EMPTY);
|
setData({});
|
||||||
|
setError({});
|
||||||
closeDialog();
|
closeDialog();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
const msg = error.message || 'Could not create user';
|
const msg = error.message || 'Could not create user';
|
||||||
@ -51,22 +30,10 @@ function AddUser({ showDialog, closeDialog, addUser, validatePassword }) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onPasswordBlur = async e => {
|
|
||||||
e.preventDefault();
|
|
||||||
setError({ password: '' });
|
|
||||||
if (data.password) {
|
|
||||||
try {
|
|
||||||
await validatePassword(data.password);
|
|
||||||
} catch (error) {
|
|
||||||
const msg = error.message || '';
|
|
||||||
setError({ password: msg });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const onCancel = e => {
|
const onCancel = e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setData(EMPTY);
|
setData({});
|
||||||
|
setError({});
|
||||||
closeDialog();
|
closeDialog();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -79,61 +46,9 @@ function AddUser({ showDialog, closeDialog, addUser, validatePassword }) {
|
|||||||
onClose={onCancel}
|
onClose={onCancel}
|
||||||
primaryButtonText="Add user"
|
primaryButtonText="Add user"
|
||||||
secondaryButtonText="Cancel"
|
secondaryButtonText="Cancel"
|
||||||
|
fullWidth
|
||||||
>
|
>
|
||||||
<form onSubmit={submit}>
|
<UserForm title="Add new user" data={data} setData={setData} roles={roles} submit={submit} error={error} />
|
||||||
<DialogTitle>Add new user</DialogTitle>
|
|
||||||
|
|
||||||
<DialogContent
|
|
||||||
className={commonStyles.contentSpacing}
|
|
||||||
style={{ display: 'flex', flexDirection: 'column' }}
|
|
||||||
>
|
|
||||||
<p style={{ color: 'red' }}>{error.general}</p>
|
|
||||||
<TextField
|
|
||||||
label="Full name"
|
|
||||||
name="name"
|
|
||||||
value={data.name}
|
|
||||||
error={error.name !== undefined}
|
|
||||||
helperText={error.name}
|
|
||||||
type="name"
|
|
||||||
variant="outlined"
|
|
||||||
size="small"
|
|
||||||
onChange={updateField}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
label="Email"
|
|
||||||
name="email"
|
|
||||||
value={data.email}
|
|
||||||
error={error.email !== undefined}
|
|
||||||
helperText={error.email}
|
|
||||||
type="email"
|
|
||||||
variant="outlined"
|
|
||||||
size="small"
|
|
||||||
onChange={updateFieldWithTrim}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
label="Password"
|
|
||||||
name="password"
|
|
||||||
type="password"
|
|
||||||
value={data.password}
|
|
||||||
error={error.password !== undefined}
|
|
||||||
helperText={error.password}
|
|
||||||
variant="outlined"
|
|
||||||
size="small"
|
|
||||||
onChange={updateField}
|
|
||||||
onBlur={onPasswordBlur}
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<FormControl>
|
|
||||||
<FormLabel component="legend">User type</FormLabel>
|
|
||||||
<RadioGroup name="userType" value={data.userType} onChange={updateField}>
|
|
||||||
<FormControlLabel label="Regular" control={<Radio />} value="regular" />
|
|
||||||
<FormControlLabel label="Admin" control={<Radio />} value="admin" />
|
|
||||||
<FormControlLabel label="Read-only" control={<Radio />} value="read" />
|
|
||||||
</RadioGroup>
|
|
||||||
</FormControl>
|
|
||||||
</DialogContent>
|
|
||||||
</form>
|
|
||||||
</Dialogue>
|
</Dialogue>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -143,6 +58,7 @@ AddUser.propTypes = {
|
|||||||
closeDialog: PropTypes.func.isRequired,
|
closeDialog: PropTypes.func.isRequired,
|
||||||
addUser: PropTypes.func.isRequired,
|
addUser: PropTypes.func.isRequired,
|
||||||
validatePassword: PropTypes.func.isRequired,
|
validatePassword: PropTypes.func.isRequired,
|
||||||
|
roles: PropTypes.array.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AddUser;
|
export default AddUser;
|
||||||
|
@ -4,6 +4,7 @@ import { TextField, DialogTitle, DialogContent } from '@material-ui/core';
|
|||||||
import { trim } from '../../../component/common/util';
|
import { trim } from '../../../component/common/util';
|
||||||
import { modalStyles } from './util';
|
import { modalStyles } from './util';
|
||||||
import Dialogue from '../../../component/common/Dialogue/Dialogue';
|
import Dialogue from '../../../component/common/Dialogue/Dialogue';
|
||||||
|
import commonStyles from '../../../component/common/common.module.scss';
|
||||||
|
|
||||||
function ChangePassword({ showDialog, closeDialog, changePassword, validatePassword, user = {} }) {
|
function ChangePassword({ showDialog, closeDialog, changePassword, validatePassword, user = {} }) {
|
||||||
const [data, setData] = useState({});
|
const [data, setData] = useState({});
|
||||||
@ -67,11 +68,14 @@ function ChangePassword({ showDialog, closeDialog, changePassword, validatePassw
|
|||||||
>
|
>
|
||||||
<form onSubmit={submit}>
|
<form onSubmit={submit}>
|
||||||
<DialogTitle>Update password</DialogTitle>
|
<DialogTitle>Update password</DialogTitle>
|
||||||
<DialogContent>
|
<DialogContent
|
||||||
|
className={commonStyles.contentSpacing}
|
||||||
|
style={{ display: 'flex', flexDirection: 'column' }}
|
||||||
|
>
|
||||||
<p>User: {user.username || user.email}</p>
|
<p>User: {user.username || user.email}</p>
|
||||||
<p style={{ color: 'red' }}>{error.general}</p>
|
<p style={{ color: 'red' }}>{error.general}</p>
|
||||||
<TextField
|
<TextField
|
||||||
label="New passord"
|
label="New password"
|
||||||
name="password"
|
name="password"
|
||||||
type="password"
|
type="password"
|
||||||
value={data.password}
|
value={data.password}
|
||||||
@ -83,7 +87,7 @@ function ChangePassword({ showDialog, closeDialog, changePassword, validatePassw
|
|||||||
size="small"
|
size="small"
|
||||||
/>
|
/>
|
||||||
<TextField
|
<TextField
|
||||||
label="Confirm passord"
|
label="Confirm password"
|
||||||
name="confirm"
|
name="confirm"
|
||||||
type="password"
|
type="password"
|
||||||
value={data.confirm}
|
value={data.confirm}
|
||||||
|
@ -1,99 +1,60 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import {
|
import Dialogue from '../../../component/common/Dialogue';
|
||||||
Button,
|
import UserForm from './user-form';
|
||||||
TextField,
|
|
||||||
DialogTitle,
|
|
||||||
DialogContent,
|
|
||||||
DialogActions,
|
|
||||||
RadioGroup,
|
|
||||||
Radio,
|
|
||||||
Modal,
|
|
||||||
} from '@material-ui/core';
|
|
||||||
import { showPermissions, modalStyles } from './util';
|
|
||||||
|
|
||||||
function AddUser({ user, showDialog, closeDialog, updateUser }) {
|
function AddUser({ user = {}, showDialog, closeDialog, updateUser, roles }) {
|
||||||
const [data, setData] = useState(user);
|
const [data, setData] = useState({});
|
||||||
const [error, setError] = useState({});
|
const [error, setError] = useState({});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setData({
|
||||||
|
id: user.id,
|
||||||
|
email: user.email || '',
|
||||||
|
rootRole: user.rootRole || '',
|
||||||
|
name: user.name || '',
|
||||||
|
});
|
||||||
|
}, [user])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const updateField = e => {
|
|
||||||
setData({
|
|
||||||
...data,
|
|
||||||
[e.target.name]: e.target.value,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const submit = async e => {
|
const submit = async e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await updateUser(data);
|
await updateUser(data);
|
||||||
|
setData({});
|
||||||
|
setError({});
|
||||||
closeDialog();
|
closeDialog();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setError({ general: 'Could not create user' });
|
setError({ general: 'Could not update user' });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onCancel = e => {
|
const onCancel = e => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
setData({});
|
||||||
|
setError({});
|
||||||
closeDialog();
|
closeDialog();
|
||||||
};
|
};
|
||||||
|
|
||||||
const userType = data.userType || showPermissions(user.permissions);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal open={showDialog} style={modalStyles} onClose={onCancel}>
|
<Dialogue
|
||||||
<form onSubmit={submit}>
|
onClick={e => {
|
||||||
<DialogTitle>Edit user</DialogTitle>
|
submit(e);
|
||||||
|
}}
|
||||||
<DialogContent>
|
open={showDialog}
|
||||||
<p>{error.general}</p>
|
onClose={onCancel}
|
||||||
<TextField
|
primaryButtonText="Update user"
|
||||||
label="Full name"
|
secondaryButtonText="Cancel"
|
||||||
name="name"
|
fullWidth
|
||||||
value={data.name}
|
>
|
||||||
error={error.name}
|
<UserForm title="Update user" data={data} setData={setData} roles={roles} submit={submit} error={error} />
|
||||||
type="name"
|
</Dialogue>
|
||||||
onChange={updateField}
|
|
||||||
/>
|
|
||||||
<TextField
|
|
||||||
label="Email"
|
|
||||||
name="email"
|
|
||||||
contentEditable="false"
|
|
||||||
editable="false"
|
|
||||||
readOnly
|
|
||||||
value={data.email}
|
|
||||||
type="email"
|
|
||||||
/>
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<RadioGroup name="userType" value={userType} onChange={updateField} childContainer="div">
|
|
||||||
<Radio value="regular" ripple>
|
|
||||||
Regular user
|
|
||||||
</Radio>
|
|
||||||
<Radio value="admin" ripple>
|
|
||||||
Admin user
|
|
||||||
</Radio>
|
|
||||||
<Radio value="read" ripple>
|
|
||||||
Read only
|
|
||||||
</Radio>
|
|
||||||
</RadioGroup>
|
|
||||||
</DialogContent>
|
|
||||||
<DialogActions>
|
|
||||||
<Button raised colored type="submit">
|
|
||||||
Update
|
|
||||||
</Button>
|
|
||||||
<Button type="button" onClick={onCancel}>
|
|
||||||
Cancel
|
|
||||||
</Button>
|
|
||||||
</DialogActions>
|
|
||||||
</form>
|
|
||||||
</Modal>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,6 +63,7 @@ AddUser.propTypes = {
|
|||||||
closeDialog: PropTypes.func.isRequired,
|
closeDialog: PropTypes.func.isRequired,
|
||||||
updateUser: PropTypes.func.isRequired,
|
updateUser: PropTypes.func.isRequired,
|
||||||
user: PropTypes.object,
|
user: PropTypes.object,
|
||||||
|
roles: PropTypes.array.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AddUser;
|
export default AddUser;
|
||||||
|
103
frontend/src/page/admin/users/user-form.jsx
Normal file
103
frontend/src/page/admin/users/user-form.jsx
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import {
|
||||||
|
TextField,
|
||||||
|
DialogTitle,
|
||||||
|
DialogContent,
|
||||||
|
RadioGroup,
|
||||||
|
Radio,
|
||||||
|
FormControl,
|
||||||
|
FormLabel,
|
||||||
|
FormControlLabel,
|
||||||
|
} from '@material-ui/core';
|
||||||
|
import commonStyles from '../../../component/common/common.module.scss';
|
||||||
|
import { trim } from '../../../component/common/util';
|
||||||
|
|
||||||
|
function UserForm({ title, submit, data, error, setData, roles }) {
|
||||||
|
const updateField = e => {
|
||||||
|
setData({
|
||||||
|
...data,
|
||||||
|
[e.target.name]: e.target.value,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateFieldWithTrim = e => {
|
||||||
|
setData({
|
||||||
|
...data,
|
||||||
|
[e.target.name]: trim(e.target.value),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateNumberField = e => {
|
||||||
|
setData({
|
||||||
|
...data,
|
||||||
|
[e.target.name]: +e.target.value,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form onSubmit={submit}>
|
||||||
|
<DialogTitle>{title}</DialogTitle>
|
||||||
|
|
||||||
|
<DialogContent className={commonStyles.contentSpacing} style={{ display: 'flex', flexDirection: 'column' }}>
|
||||||
|
<p style={{ color: 'red' }}>{error.general}</p>
|
||||||
|
<TextField
|
||||||
|
label="Full name"
|
||||||
|
name="name"
|
||||||
|
value={data.name || ''}
|
||||||
|
error={error.name !== undefined}
|
||||||
|
helperText={error.name}
|
||||||
|
type="name"
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
onChange={updateField}
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
label="Email"
|
||||||
|
name="email"
|
||||||
|
required
|
||||||
|
value={data.email || ''}
|
||||||
|
error={error.email !== undefined}
|
||||||
|
helperText={error.email}
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
type="email"
|
||||||
|
onChange={updateFieldWithTrim}
|
||||||
|
/>
|
||||||
|
<br />
|
||||||
|
<br />
|
||||||
|
<FormControl>
|
||||||
|
<FormLabel component="legend">Role</FormLabel>
|
||||||
|
<RadioGroup name="rootRole" value={data.rootRole || ''} onChange={updateNumberField}>
|
||||||
|
{roles.map(role => (
|
||||||
|
<FormControlLabel
|
||||||
|
key={`role-${role.id}`}
|
||||||
|
labelPlacement="end"
|
||||||
|
style={{ margin: '3px 0', border: '1px solid #EFEFEF' }}
|
||||||
|
label={
|
||||||
|
<div>
|
||||||
|
<strong>{role.name}</strong>
|
||||||
|
<p>{role.description}</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
control={<Radio />}
|
||||||
|
value={role.id}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</RadioGroup>
|
||||||
|
</FormControl>
|
||||||
|
</DialogContent>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
UserForm.propTypes = {
|
||||||
|
title: PropTypes.string.isRequired,
|
||||||
|
data: PropTypes.object.isRequired,
|
||||||
|
error: PropTypes.object.isRequired,
|
||||||
|
submit: PropTypes.func.isRequired,
|
||||||
|
setData: PropTypes.func.isRequired,
|
||||||
|
roles: PropTypes.array.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UserForm;
|
@ -1,13 +1,3 @@
|
|||||||
export const showPermissions = permissions => {
|
|
||||||
if (!permissions || permissions.length === 0) {
|
|
||||||
return 'read';
|
|
||||||
} else if (permissions.includes('ADMIN')) {
|
|
||||||
return 'admin';
|
|
||||||
} else {
|
|
||||||
return 'regular';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const modalStyles = {
|
export const modalStyles = {
|
||||||
overlay: {
|
overlay: {
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import api from './api';
|
import api from './api';
|
||||||
import { dispatchError } from '../util';
|
import { dispatchError } from '../util';
|
||||||
export const START_FETCH_USERS = 'START_FETCH_USERS';
|
export const START_FETCH_USERS = 'START_FETCH_USERS';
|
||||||
export const RECIEVE_USERS = 'RECIEVE_USERS';
|
export const RECEIVE_USERS = 'RECEIVE_USERS';
|
||||||
export const ERROR_FETCH_USERS = 'ERROR_FETCH_USERS';
|
export const ERROR_FETCH_USERS = 'ERROR_FETCH_USERS';
|
||||||
export const REMOVE_USER = 'REMOVE_USER';
|
export const REMOVE_USER = 'REMOVE_USER';
|
||||||
export const REMOVE_USER_ERROR = 'REMOVE_USER_ERROR';
|
export const REMOVE_USER_ERROR = 'REMOVE_USER_ERROR';
|
||||||
@ -15,7 +15,7 @@ export const VALIDATE_PASSWORD_ERROR = 'VALIDATE_PASSWORD_ERROR';
|
|||||||
const debug = require('debug')('unleash:e-user-admin-actions');
|
const debug = require('debug')('unleash:e-user-admin-actions');
|
||||||
|
|
||||||
const gotUsers = value => ({
|
const gotUsers = value => ({
|
||||||
type: RECIEVE_USERS,
|
type: RECEIVE_USERS,
|
||||||
value,
|
value,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { List } from 'immutable';
|
import { List } from 'immutable';
|
||||||
import { RECIEVE_USERS, ADD_USER, REMOVE_USER, UPDATE_USER } from './actions';
|
import { RECEIVE_USERS, ADD_USER, REMOVE_USER, UPDATE_USER } from './actions';
|
||||||
|
|
||||||
const store = (state = new List(), action) => {
|
const store = (state = new List(), action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case RECIEVE_USERS:
|
case RECEIVE_USERS:
|
||||||
return new List(action.value);
|
return new List(action.value.users);
|
||||||
case ADD_USER:
|
case ADD_USER:
|
||||||
return state.push(action.user);
|
return state.push(action.user);
|
||||||
case UPDATE_USER:
|
case UPDATE_USER:
|
||||||
|
19
frontend/src/store/e-user-admin/roles-store.js
Normal file
19
frontend/src/store/e-user-admin/roles-store.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { List, fromJS } from 'immutable';
|
||||||
|
import { RECEIVE_USERS } from './actions';
|
||||||
|
|
||||||
|
function getInitialState() {
|
||||||
|
return fromJS({
|
||||||
|
root: [],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const store = (state = getInitialState(), action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case RECEIVE_USERS:
|
||||||
|
return state.set('root', new List(action.value.rootRoles));
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default store;
|
@ -17,6 +17,7 @@ import context from './context';
|
|||||||
import projects from './project';
|
import projects from './project';
|
||||||
import addons from './addons';
|
import addons from './addons';
|
||||||
import userAdmin from './e-user-admin';
|
import userAdmin from './e-user-admin';
|
||||||
|
import roles from './e-user-admin/roles-store';
|
||||||
import apiAdmin from './e-api-admin';
|
import apiAdmin from './e-api-admin';
|
||||||
import authAdmin from './e-admin-auth';
|
import authAdmin from './e-admin-auth';
|
||||||
import apiCalls from './api-calls';
|
import apiCalls from './api-calls';
|
||||||
@ -40,6 +41,7 @@ const unleashStore = combineReducers({
|
|||||||
projects,
|
projects,
|
||||||
addons,
|
addons,
|
||||||
userAdmin,
|
userAdmin,
|
||||||
|
roles,
|
||||||
apiAdmin,
|
apiAdmin,
|
||||||
authAdmin,
|
authAdmin,
|
||||||
apiCalls,
|
apiCalls,
|
||||||
|
Loading…
Reference in New Issue
Block a user