mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-11 10:19:55 +03:00
eslint
This commit is contained in:
@@ -1,5 +1,14 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { Dialog, DialogTitle, DialogContent, DialogActions, Box, LinearProgress, Typography, TextField } from '@material-ui/core';
|
||||
import {
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
Box,
|
||||
LinearProgress,
|
||||
Typography,
|
||||
TextField
|
||||
} from '@material-ui/core';
|
||||
|
||||
import { FormButton } from '../components';
|
||||
import { redirectingAuthorizedFetch } from '../authentication';
|
||||
@@ -7,71 +16,105 @@ import { GENERATE_TOKEN_ENDPOINT } from '../api';
|
||||
import { withSnackbar, WithSnackbarProps } from 'notistack';
|
||||
|
||||
interface GenerateTokenProps extends WithSnackbarProps {
|
||||
username: string;
|
||||
onClose: () => void;
|
||||
username: string;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
interface GenerateTokenState {
|
||||
token?: string;
|
||||
token?: string;
|
||||
}
|
||||
|
||||
class GenerateToken extends React.Component<GenerateTokenProps, GenerateTokenState> {
|
||||
class GenerateToken extends React.Component<
|
||||
GenerateTokenProps,
|
||||
GenerateTokenState
|
||||
> {
|
||||
state: GenerateTokenState = {};
|
||||
|
||||
state: GenerateTokenState = {};
|
||||
|
||||
componentDidMount() {
|
||||
const { username } = this.props;
|
||||
redirectingAuthorizedFetch(GENERATE_TOKEN_ENDPOINT + "?" + new URLSearchParams({ username }), { method: 'GET' })
|
||||
.then(response => {
|
||||
if (response.status === 200) {
|
||||
return response.json();
|
||||
} else {
|
||||
throw Error("Error generating token: " + response.status);
|
||||
}
|
||||
}).then(generatedToken => {
|
||||
console.log(generatedToken);
|
||||
this.setState({ token: generatedToken.token });
|
||||
})
|
||||
.catch(error => {
|
||||
this.props.enqueueSnackbar(error.message || "Problem generating token", { variant: 'error' });
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { onClose, username } = this.props;
|
||||
const { token } = this.state;
|
||||
return (
|
||||
<Dialog onClose={onClose} aria-labelledby="generate-token-dialog-title" open fullWidth maxWidth="sm">
|
||||
<DialogTitle id="generate-token-dialog-title">Token for: {username}</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
{token ?
|
||||
<Fragment>
|
||||
<Box bgcolor="primary.main" color="primary.contrastText" p={2} mt={2} mb={2}>
|
||||
<Typography variant="body1">
|
||||
The token below may be used to access the secured APIs, either as a Bearer authentication in the "Authorization" header or using the "access_token" query parameter.
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box mt={2} mb={2}>
|
||||
<TextField label="Token" multiline value={token} fullWidth contentEditable={false} />
|
||||
</Box>
|
||||
</Fragment>
|
||||
:
|
||||
<Box m={4} textAlign="center">
|
||||
<LinearProgress />
|
||||
<Typography variant="h6">
|
||||
Generating token…
|
||||
</Typography>
|
||||
</Box>
|
||||
}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<FormButton variant="contained" color="primary" type="submit" onClick={onClose}>
|
||||
Close
|
||||
</FormButton>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
componentDidMount() {
|
||||
const { username } = this.props;
|
||||
redirectingAuthorizedFetch(
|
||||
GENERATE_TOKEN_ENDPOINT + '?' + new URLSearchParams({ username }),
|
||||
{ method: 'GET' }
|
||||
)
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
return response.json();
|
||||
} else {
|
||||
throw Error('Error generating token: ' + response.status);
|
||||
}
|
||||
})
|
||||
.then((generatedToken) => {
|
||||
console.log(generatedToken);
|
||||
this.setState({ token: generatedToken.token });
|
||||
})
|
||||
.catch((error) => {
|
||||
this.props.enqueueSnackbar(
|
||||
error.message || 'Problem generating token',
|
||||
{ variant: 'error' }
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { onClose, username } = this.props;
|
||||
const { token } = this.state;
|
||||
return (
|
||||
<Dialog
|
||||
onClose={onClose}
|
||||
aria-labelledby="generate-token-dialog-title"
|
||||
open
|
||||
fullWidth
|
||||
maxWidth="sm"
|
||||
>
|
||||
<DialogTitle id="generate-token-dialog-title">
|
||||
Token for: {username}
|
||||
</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
{token ? (
|
||||
<Fragment>
|
||||
<Box
|
||||
bgcolor="primary.main"
|
||||
color="primary.contrastText"
|
||||
p={2}
|
||||
mt={2}
|
||||
mb={2}
|
||||
>
|
||||
<Typography variant="body1">
|
||||
The token below may be used to access the secured APIs, either
|
||||
as a Bearer authentication in the "Authorization" header or
|
||||
using the "access_token" query parameter.
|
||||
</Typography>
|
||||
</Box>
|
||||
<Box mt={2} mb={2}>
|
||||
<TextField
|
||||
label="Token"
|
||||
multiline
|
||||
value={token}
|
||||
fullWidth
|
||||
contentEditable={false}
|
||||
/>
|
||||
</Box>
|
||||
</Fragment>
|
||||
) : (
|
||||
<Box m={4} textAlign="center">
|
||||
<LinearProgress />
|
||||
<Typography variant="h6">Generating token…</Typography>
|
||||
</Box>
|
||||
)}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<FormButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
type="submit"
|
||||
onClick={onClose}
|
||||
>
|
||||
Close
|
||||
</FormButton>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withSnackbar(GenerateToken);
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Component } from 'react';
|
||||
|
||||
import { restController, RestControllerProps, RestFormLoader, SectionContent } from '../components';
|
||||
import {
|
||||
restController,
|
||||
RestControllerProps,
|
||||
RestFormLoader,
|
||||
SectionContent
|
||||
} from '../components';
|
||||
import { SECURITY_SETTINGS_ENDPOINT } from '../api';
|
||||
|
||||
import ManageUsersForm from './ManageUsersForm';
|
||||
@@ -9,7 +14,6 @@ import { SecuritySettings } from './types';
|
||||
type ManageUsersControllerProps = RestControllerProps<SecuritySettings>;
|
||||
|
||||
class ManageUsersController extends Component<ManageUsersControllerProps> {
|
||||
|
||||
componentDidMount() {
|
||||
this.props.loadData();
|
||||
}
|
||||
@@ -19,12 +23,14 @@ class ManageUsersController extends Component<ManageUsersControllerProps> {
|
||||
<SectionContent title="Manage Users" titleGutter>
|
||||
<RestFormLoader
|
||||
{...this.props}
|
||||
render={formProps => <ManageUsersForm {...formProps} />}
|
||||
render={(formProps) => <ManageUsersForm {...formProps} />}
|
||||
/>
|
||||
</SectionContent>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default restController(SECURITY_SETTINGS_ENDPOINT, ManageUsersController);
|
||||
export default restController(
|
||||
SECURITY_SETTINGS_ENDPOINT,
|
||||
ManageUsersController
|
||||
);
|
||||
|
||||
@@ -1,8 +1,18 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { ValidatorForm } from 'react-material-ui-form-validator';
|
||||
|
||||
import { Table, TableBody, TableCell, TableHead, TableFooter, TableRow, withWidth, WithWidthProps, isWidthDown } from '@material-ui/core';
|
||||
import { Box, Button, Typography, } from '@material-ui/core';
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableFooter,
|
||||
TableRow,
|
||||
withWidth,
|
||||
WithWidthProps,
|
||||
isWidthDown
|
||||
} from '@material-ui/core';
|
||||
import { Box, Button, Typography } from '@material-ui/core';
|
||||
|
||||
import EditIcon from '@material-ui/icons/Edit';
|
||||
import DeleteIcon from '@material-ui/icons/Delete';
|
||||
@@ -13,8 +23,16 @@ import SaveIcon from '@material-ui/icons/Save';
|
||||
import PersonAddIcon from '@material-ui/icons/PersonAdd';
|
||||
import VpnKeyIcon from '@material-ui/icons/VpnKey';
|
||||
|
||||
import { withAuthenticatedContext, AuthenticatedContextProps } from '../authentication';
|
||||
import { RestFormProps, FormActions, FormButton, extractEventValue } from '../components';
|
||||
import {
|
||||
withAuthenticatedContext,
|
||||
AuthenticatedContextProps
|
||||
} from '../authentication';
|
||||
import {
|
||||
RestFormProps,
|
||||
FormActions,
|
||||
FormButton,
|
||||
extractEventValue
|
||||
} from '../components';
|
||||
|
||||
import UserForm from './UserForm';
|
||||
import { SecuritySettings, User } from './types';
|
||||
@@ -30,16 +48,20 @@ function compareUsers(a: User, b: User) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
type ManageUsersFormProps = RestFormProps<SecuritySettings> & AuthenticatedContextProps & WithWidthProps;
|
||||
type ManageUsersFormProps = RestFormProps<SecuritySettings> &
|
||||
AuthenticatedContextProps &
|
||||
WithWidthProps;
|
||||
|
||||
type ManageUsersFormState = {
|
||||
creating: boolean;
|
||||
user?: User;
|
||||
generateTokenFor?: string;
|
||||
}
|
||||
|
||||
class ManageUsersForm extends React.Component<ManageUsersFormProps, ManageUsersFormState> {
|
||||
};
|
||||
|
||||
class ManageUsersForm extends React.Component<
|
||||
ManageUsersFormProps,
|
||||
ManageUsersFormState
|
||||
> {
|
||||
state: ManageUsersFormState = {
|
||||
creating: false
|
||||
};
|
||||
@@ -48,38 +70,38 @@ class ManageUsersForm extends React.Component<ManageUsersFormProps, ManageUsersF
|
||||
this.setState({
|
||||
creating: true,
|
||||
user: {
|
||||
username: "",
|
||||
password: "",
|
||||
username: '',
|
||||
password: '',
|
||||
admin: true
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
uniqueUsername = (username: string) => {
|
||||
return !this.props.data.users.find(u => u.username === username);
|
||||
}
|
||||
return !this.props.data.users.find((u) => u.username === username);
|
||||
};
|
||||
|
||||
noAdminConfigured = () => {
|
||||
return !this.props.data.users.find(u => u.admin);
|
||||
}
|
||||
return !this.props.data.users.find((u) => u.admin);
|
||||
};
|
||||
|
||||
removeUser = (user: User) => {
|
||||
const { data } = this.props;
|
||||
const users = data.users.filter(u => u.username !== user.username);
|
||||
const users = data.users.filter((u) => u.username !== user.username);
|
||||
this.props.setData({ ...data, users });
|
||||
}
|
||||
};
|
||||
|
||||
closeGenerateToken = () => {
|
||||
this.setState({
|
||||
generateTokenFor: undefined
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
generateToken = (user: User) => {
|
||||
this.setState({
|
||||
generateTokenFor: user.username
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
startEditingUser = (user: User) => {
|
||||
this.setState({
|
||||
@@ -92,13 +114,13 @@ class ManageUsersForm extends React.Component<ManageUsersFormProps, ManageUsersF
|
||||
this.setState({
|
||||
user: undefined
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
doneEditingUser = () => {
|
||||
const { user } = this.state;
|
||||
if (user) {
|
||||
const { data } = this.props;
|
||||
const users = data.users.filter(u => u.username !== user.username);
|
||||
const users = data.users.filter((u) => u.username !== user.username);
|
||||
users.push(user);
|
||||
this.props.setData({ ...data, users });
|
||||
this.setState({
|
||||
@@ -107,14 +129,18 @@ class ManageUsersForm extends React.Component<ManageUsersFormProps, ManageUsersF
|
||||
}
|
||||
};
|
||||
|
||||
handleUserValueChange = (name: keyof User) => (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({ user: { ...this.state.user!, [name]: extractEventValue(event) } });
|
||||
handleUserValueChange = (name: keyof User) => (
|
||||
event: React.ChangeEvent<HTMLInputElement>
|
||||
) => {
|
||||
this.setState({
|
||||
user: { ...this.state.user!, [name]: extractEventValue(event) }
|
||||
});
|
||||
};
|
||||
|
||||
onSubmit = () => {
|
||||
this.props.saveData();
|
||||
this.props.authenticatedContext.refresh();
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { width, data } = this.props;
|
||||
@@ -122,7 +148,10 @@ class ManageUsersForm extends React.Component<ManageUsersFormProps, ManageUsersF
|
||||
return (
|
||||
<Fragment>
|
||||
<ValidatorForm onSubmit={this.onSubmit}>
|
||||
<Table size="small" padding={isWidthDown('xs', width!) ? "none" : "default"}>
|
||||
<Table
|
||||
size="small"
|
||||
padding={isWidthDown('xs', width!) ? 'none' : 'default'}
|
||||
>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Username</TableCell>
|
||||
@@ -131,7 +160,7 @@ class ManageUsersForm extends React.Component<ManageUsersFormProps, ManageUsersF
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{data.users.sort(compareUsers).map(user => (
|
||||
{data.users.sort(compareUsers).map((user) => (
|
||||
<TableRow key={user.username}>
|
||||
<TableCell component="th" scope="row">
|
||||
{user.username}
|
||||
@@ -140,51 +169,79 @@ class ManageUsersForm extends React.Component<ManageUsersFormProps, ManageUsersF
|
||||
{user.admin ? <CheckIcon /> : <CloseIcon />}
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
<IconButton size="small" aria-label="Generate Token" onClick={() => this.generateToken(user)}>
|
||||
<IconButton
|
||||
size="small"
|
||||
aria-label="Generate Token"
|
||||
onClick={() => this.generateToken(user)}
|
||||
>
|
||||
<VpnKeyIcon />
|
||||
</IconButton>
|
||||
<IconButton size="small" aria-label="Delete" onClick={() => this.removeUser(user)}>
|
||||
<IconButton
|
||||
size="small"
|
||||
aria-label="Delete"
|
||||
onClick={() => this.removeUser(user)}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
<IconButton size="small" aria-label="Edit" onClick={() => this.startEditingUser(user)}>
|
||||
<IconButton
|
||||
size="small"
|
||||
aria-label="Edit"
|
||||
onClick={() => this.startEditingUser(user)}
|
||||
>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
<TableFooter >
|
||||
<TableFooter>
|
||||
<TableRow>
|
||||
<TableCell colSpan={2} />
|
||||
<TableCell align="center" padding="default">
|
||||
<Button startIcon={<PersonAddIcon />} variant="contained" color="secondary" onClick={this.createUser}>
|
||||
<Button
|
||||
startIcon={<PersonAddIcon />}
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
onClick={this.createUser}
|
||||
>
|
||||
Add
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableFooter>
|
||||
</Table>
|
||||
{
|
||||
this.noAdminConfigured() &&
|
||||
(
|
||||
<Box bgcolor="error.main" color="error.contrastText" p={2} mt={2} mb={2}>
|
||||
<Typography variant="body1">
|
||||
You must have at least one admin user configured.
|
||||
</Typography>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
{this.noAdminConfigured() && (
|
||||
<Box
|
||||
bgcolor="error.main"
|
||||
color="error.contrastText"
|
||||
p={2}
|
||||
mt={2}
|
||||
mb={2}
|
||||
>
|
||||
<Typography variant="body1">
|
||||
You must have at least one admin user configured.
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
<FormActions>
|
||||
<FormButton startIcon={<SaveIcon />} variant="contained" color="primary" type="submit" disabled={this.noAdminConfigured()}>
|
||||
<FormButton
|
||||
startIcon={<SaveIcon />}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
type="submit"
|
||||
disabled={this.noAdminConfigured()}
|
||||
>
|
||||
Save
|
||||
</FormButton>
|
||||
</FormActions>
|
||||
</ValidatorForm>
|
||||
{
|
||||
generateTokenFor && <GenerateToken username={generateTokenFor} onClose={this.closeGenerateToken} />
|
||||
}
|
||||
{
|
||||
user &&
|
||||
{generateTokenFor && (
|
||||
<GenerateToken
|
||||
username={generateTokenFor}
|
||||
onClose={this.closeGenerateToken}
|
||||
/>
|
||||
)}
|
||||
{user && (
|
||||
<UserForm
|
||||
user={user}
|
||||
creating={creating}
|
||||
@@ -193,11 +250,10 @@ class ManageUsersForm extends React.Component<ManageUsersFormProps, ManageUsersF
|
||||
handleValueChange={this.handleUserValueChange}
|
||||
uniqueUsername={this.uniqueUsername}
|
||||
/>
|
||||
}
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default withAuthenticatedContext(withWidth()(ManageUsersForm));
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Redirect, Switch, RouteComponentProps } from 'react-router-dom'
|
||||
import { Component } from 'react';
|
||||
import { Redirect, Switch, RouteComponentProps } from 'react-router-dom';
|
||||
|
||||
import { Tabs, Tab } from '@material-ui/core';
|
||||
|
||||
import { AuthenticatedContextProps, AuthenticatedRoute } from '../authentication';
|
||||
import {
|
||||
AuthenticatedContextProps,
|
||||
AuthenticatedRoute
|
||||
} from '../authentication';
|
||||
import { MenuAppBar } from '../components';
|
||||
|
||||
import ManageUsersController from './ManageUsersController';
|
||||
@@ -12,25 +15,36 @@ import SecuritySettingsController from './SecuritySettingsController';
|
||||
type SecurityProps = AuthenticatedContextProps & RouteComponentProps;
|
||||
|
||||
class Security extends Component<SecurityProps> {
|
||||
|
||||
handleTabChange = (event: React.ChangeEvent<{}>, path: string) => {
|
||||
handleTabChange = (path: string) => {
|
||||
this.props.history.push(path);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<MenuAppBar sectionTitle="Security">
|
||||
<Tabs value={this.props.match.url} onChange={this.handleTabChange} variant="fullWidth">
|
||||
<Tabs
|
||||
value={this.props.match.url}
|
||||
onChange={(e, path) => this.handleTabChange(path)}
|
||||
variant="fullWidth"
|
||||
>
|
||||
<Tab value="/security/users" label="Manage Users" />
|
||||
<Tab value="/security/settings" label="Security Settings" />
|
||||
</Tabs>
|
||||
<Switch>
|
||||
<AuthenticatedRoute exact path="/security/users" component={ManageUsersController} />
|
||||
<AuthenticatedRoute exact path="/security/settings" component={SecuritySettingsController} />
|
||||
<AuthenticatedRoute
|
||||
exact
|
||||
path="/security/users"
|
||||
component={ManageUsersController}
|
||||
/>
|
||||
<AuthenticatedRoute
|
||||
exact
|
||||
path="/security/settings"
|
||||
component={SecuritySettingsController}
|
||||
/>
|
||||
<Redirect to="/security/users" />
|
||||
</Switch>
|
||||
</MenuAppBar>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { restController, RestControllerProps, RestFormLoader, SectionContent } from '../components';
|
||||
import {
|
||||
restController,
|
||||
RestControllerProps,
|
||||
RestFormLoader,
|
||||
SectionContent
|
||||
} from '../components';
|
||||
import { SECURITY_SETTINGS_ENDPOINT } from '../api';
|
||||
|
||||
import SecuritySettingsForm from './SecuritySettingsForm';
|
||||
@@ -9,7 +14,6 @@ import { SecuritySettings } from './types';
|
||||
type SecuritySettingsControllerProps = RestControllerProps<SecuritySettings>;
|
||||
|
||||
class SecuritySettingsController extends Component<SecuritySettingsControllerProps> {
|
||||
|
||||
componentDidMount() {
|
||||
this.props.loadData();
|
||||
}
|
||||
@@ -19,12 +23,14 @@ class SecuritySettingsController extends Component<SecuritySettingsControllerPro
|
||||
<SectionContent title="Security Settings" titleGutter>
|
||||
<RestFormLoader
|
||||
{...this.props}
|
||||
render={formProps => <SecuritySettingsForm {...formProps} />}
|
||||
render={(formProps) => <SecuritySettingsForm {...formProps} />}
|
||||
/>
|
||||
</SectionContent>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default restController(SECURITY_SETTINGS_ENDPOINT, SecuritySettingsController);
|
||||
export default restController(
|
||||
SECURITY_SETTINGS_ENDPOINT,
|
||||
SecuritySettingsController
|
||||
);
|
||||
|
||||
@@ -4,19 +4,27 @@ import { ValidatorForm } from 'react-material-ui-form-validator';
|
||||
import { Box, Typography } from '@material-ui/core';
|
||||
import SaveIcon from '@material-ui/icons/Save';
|
||||
|
||||
import { withAuthenticatedContext, AuthenticatedContextProps } from '../authentication';
|
||||
import { RestFormProps, PasswordValidator, FormActions, FormButton } from '../components';
|
||||
import {
|
||||
withAuthenticatedContext,
|
||||
AuthenticatedContextProps
|
||||
} from '../authentication';
|
||||
import {
|
||||
RestFormProps,
|
||||
PasswordValidator,
|
||||
FormActions,
|
||||
FormButton
|
||||
} from '../components';
|
||||
|
||||
import { SecuritySettings } from './types';
|
||||
|
||||
type SecuritySettingsFormProps = RestFormProps<SecuritySettings> & AuthenticatedContextProps;
|
||||
type SecuritySettingsFormProps = RestFormProps<SecuritySettings> &
|
||||
AuthenticatedContextProps;
|
||||
|
||||
class SecuritySettingsForm extends React.Component<SecuritySettingsFormProps> {
|
||||
|
||||
onSubmit = () => {
|
||||
this.props.saveData();
|
||||
this.props.authenticatedContext.refresh();
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { data, handleValueChange } = this.props;
|
||||
@@ -24,7 +32,10 @@ class SecuritySettingsForm extends React.Component<SecuritySettingsFormProps> {
|
||||
<ValidatorForm onSubmit={this.onSubmit}>
|
||||
<PasswordValidator
|
||||
validators={['required', 'matchRegexp:^.{1,64}$']}
|
||||
errorMessages={['Password Required', 'Password must be 64 characters or less']}
|
||||
errorMessages={[
|
||||
'Password Required',
|
||||
'Password must be 64 characters or less'
|
||||
]}
|
||||
name="jwt_secret"
|
||||
label="Super User Password"
|
||||
fullWidth
|
||||
@@ -33,20 +44,32 @@ class SecuritySettingsForm extends React.Component<SecuritySettingsFormProps> {
|
||||
onChange={handleValueChange('jwt_secret')}
|
||||
margin="normal"
|
||||
/>
|
||||
<Box bgcolor="primary.main" color="primary.contrastText" p={2} mt={2} mb={2}>
|
||||
<Box
|
||||
bgcolor="primary.main"
|
||||
color="primary.contrastText"
|
||||
p={2}
|
||||
mt={2}
|
||||
mb={2}
|
||||
>
|
||||
<Typography variant="body1">
|
||||
The Super User password is used to sign authentication tokens and is also the Console's `su` password. If you modify this all users will be signed out.
|
||||
The Super User password is used to sign authentication tokens and is
|
||||
also the Console's `su` password. If you modify this all users will
|
||||
be signed out.
|
||||
</Typography>
|
||||
</Box>
|
||||
<FormActions>
|
||||
<FormButton startIcon={<SaveIcon />} variant="contained" color="primary" type="submit">
|
||||
<FormButton
|
||||
startIcon={<SaveIcon />}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
type="submit"
|
||||
>
|
||||
Save
|
||||
</FormButton>
|
||||
</FormActions>
|
||||
</ValidatorForm>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default withAuthenticatedContext(SecuritySettingsForm);
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
import React, { RefObject } from 'react';
|
||||
import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator';
|
||||
|
||||
import { Dialog, DialogTitle, DialogContent, DialogActions, Checkbox } from '@material-ui/core';
|
||||
import {
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
Checkbox
|
||||
} from '@material-ui/core';
|
||||
|
||||
import { PasswordValidator, BlockFormControlLabel, FormButton } from '../components';
|
||||
import {
|
||||
PasswordValidator,
|
||||
BlockFormControlLabel,
|
||||
FormButton
|
||||
} from '../components';
|
||||
|
||||
import { User } from './types';
|
||||
|
||||
@@ -11,33 +21,67 @@ interface UserFormProps {
|
||||
creating: boolean;
|
||||
user: User;
|
||||
uniqueUsername: (value: any) => boolean;
|
||||
handleValueChange: (name: keyof User) => (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
handleValueChange: (
|
||||
name: keyof User
|
||||
) => (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
onDoneEditing: () => void;
|
||||
onCancelEditing: () => void;
|
||||
}
|
||||
|
||||
class UserForm extends React.Component<UserFormProps> {
|
||||
|
||||
formRef: RefObject<any> = React.createRef();
|
||||
|
||||
componentDidMount() {
|
||||
ValidatorForm.addValidationRule('uniqueUsername', this.props.uniqueUsername);
|
||||
ValidatorForm.addValidationRule(
|
||||
'uniqueUsername',
|
||||
this.props.uniqueUsername
|
||||
);
|
||||
}
|
||||
|
||||
submit = () => {
|
||||
this.formRef.current.submit();
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { user, creating, handleValueChange, onDoneEditing, onCancelEditing } = this.props;
|
||||
const {
|
||||
user,
|
||||
creating,
|
||||
handleValueChange,
|
||||
onDoneEditing,
|
||||
onCancelEditing
|
||||
} = this.props;
|
||||
return (
|
||||
<ValidatorForm onSubmit={onDoneEditing} ref={this.formRef}>
|
||||
<Dialog onClose={onCancelEditing} aria-labelledby="user-form-dialog-title" open fullWidth maxWidth="sm">
|
||||
<DialogTitle id="user-form-dialog-title">{creating ? 'Add' : 'Modify'} User</DialogTitle>
|
||||
<Dialog
|
||||
onClose={onCancelEditing}
|
||||
aria-labelledby="user-form-dialog-title"
|
||||
open
|
||||
fullWidth
|
||||
maxWidth="sm"
|
||||
>
|
||||
<DialogTitle id="user-form-dialog-title">
|
||||
{creating ? 'Add' : 'Modify'} User
|
||||
</DialogTitle>
|
||||
<DialogContent dividers>
|
||||
<TextValidator
|
||||
validators={creating ? ['required', 'uniqueUsername', 'matchRegexp:^[a-zA-Z0-9_\\.]{1,24}$'] : []}
|
||||
errorMessages={creating ? ['Username is required', "Username already exists", "Must be 1-24 characters: alpha numeric, '_' or '.'"] : []}
|
||||
validators={
|
||||
creating
|
||||
? [
|
||||
'required',
|
||||
'uniqueUsername',
|
||||
'matchRegexp:^[a-zA-Z0-9_\\.]{1,24}$'
|
||||
]
|
||||
: []
|
||||
}
|
||||
errorMessages={
|
||||
creating
|
||||
? [
|
||||
'Username is required',
|
||||
'Username already exists',
|
||||
"Must be 1-24 characters: alpha numeric, '_' or '.'"
|
||||
]
|
||||
: []
|
||||
}
|
||||
name="username"
|
||||
label="Username"
|
||||
fullWidth
|
||||
@@ -49,7 +93,10 @@ class UserForm extends React.Component<UserFormProps> {
|
||||
/>
|
||||
<PasswordValidator
|
||||
validators={['required', 'matchRegexp:^.{1,64}$']}
|
||||
errorMessages={['Password is required', 'Password must be 64 characters or less']}
|
||||
errorMessages={[
|
||||
'Password is required',
|
||||
'Password must be 64 characters or less'
|
||||
]}
|
||||
name="password"
|
||||
label="Password"
|
||||
fullWidth
|
||||
@@ -70,10 +117,19 @@ class UserForm extends React.Component<UserFormProps> {
|
||||
/>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<FormButton variant="contained" color="secondary" onClick={onCancelEditing}>
|
||||
<FormButton
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
onClick={onCancelEditing}
|
||||
>
|
||||
Cancel
|
||||
</FormButton>
|
||||
<FormButton variant="contained" color="primary" type="submit" onClick={this.submit}>
|
||||
<FormButton
|
||||
variant="contained"
|
||||
color="primary"
|
||||
type="submit"
|
||||
onClick={this.submit}
|
||||
>
|
||||
Done
|
||||
</FormButton>
|
||||
</DialogActions>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
export interface User {
|
||||
username: string
|
||||
password: string
|
||||
admin: boolean
|
||||
username: string;
|
||||
password: string;
|
||||
admin: boolean;
|
||||
}
|
||||
|
||||
export interface SecuritySettings {
|
||||
users: User[]
|
||||
jwt_secret: string
|
||||
users: User[];
|
||||
jwt_secret: string;
|
||||
}
|
||||
|
||||
export interface GeneratedToken {
|
||||
token: string
|
||||
token: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user