mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
fix: move showing version to settings. fixes JWT resetting after each version change
This commit is contained in:
@@ -1,12 +1,39 @@
|
||||
import React, { RefObject, Fragment } from 'react';
|
||||
import { Link, withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
|
||||
import { Drawer, AppBar, Toolbar, Avatar, Divider, Button, Box, IconButton } from '@material-ui/core';
|
||||
import { ClickAwayListener, Popper, Hidden, Typography } from '@material-ui/core';
|
||||
import { List, ListItem, ListItemIcon, ListItemText, ListItemAvatar } from '@material-ui/core';
|
||||
import {
|
||||
Drawer,
|
||||
AppBar,
|
||||
Toolbar,
|
||||
Avatar,
|
||||
Divider,
|
||||
Button,
|
||||
Box,
|
||||
IconButton
|
||||
} from '@material-ui/core';
|
||||
import {
|
||||
ClickAwayListener,
|
||||
Popper,
|
||||
Hidden,
|
||||
Typography
|
||||
} from '@material-ui/core';
|
||||
import {
|
||||
List,
|
||||
ListItem,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
ListItemAvatar
|
||||
} from '@material-ui/core';
|
||||
import { Card, CardContent, CardActions } from '@material-ui/core';
|
||||
|
||||
import { withStyles, createStyles, Theme, WithTheme, WithStyles, withTheme } from '@material-ui/core/styles';
|
||||
import {
|
||||
withStyles,
|
||||
createStyles,
|
||||
Theme,
|
||||
WithTheme,
|
||||
WithStyles,
|
||||
withTheme
|
||||
} from '@material-ui/core/styles';
|
||||
|
||||
import SettingsEthernetIcon from '@material-ui/icons/SettingsEthernet';
|
||||
import SettingsIcon from '@material-ui/icons/Settings';
|
||||
@@ -19,76 +46,84 @@ import MenuIcon from '@material-ui/icons/Menu';
|
||||
|
||||
import ProjectMenu from '../project/ProjectMenu';
|
||||
import { PROJECT_NAME } from '../api';
|
||||
import { withAuthenticatedContext, AuthenticatedContextProps } from '../authentication';
|
||||
import {
|
||||
withAuthenticatedContext,
|
||||
AuthenticatedContextProps
|
||||
} from '../authentication';
|
||||
import { withFeatures, WithFeaturesProps } from '../features/FeaturesContext';
|
||||
|
||||
const drawerWidth = 290;
|
||||
|
||||
const styles = (theme: Theme) => createStyles({
|
||||
root: {
|
||||
display: 'flex',
|
||||
},
|
||||
drawer: {
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width: drawerWidth,
|
||||
flexShrink: 0,
|
||||
const styles = (theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
display: 'flex'
|
||||
},
|
||||
},
|
||||
title: {
|
||||
flexGrow: 1
|
||||
},
|
||||
appBar: {
|
||||
marginLeft: drawerWidth,
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width: `calc(100% - ${drawerWidth}px)`,
|
||||
drawer: {
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width: drawerWidth,
|
||||
flexShrink: 0
|
||||
}
|
||||
},
|
||||
},
|
||||
toolbarImage: {
|
||||
[theme.breakpoints.up('xs')]: {
|
||||
height: 24,
|
||||
marginRight: theme.spacing(2)
|
||||
title: {
|
||||
flexGrow: 1
|
||||
},
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
height: 36,
|
||||
marginRight: theme.spacing(3)
|
||||
appBar: {
|
||||
marginLeft: drawerWidth,
|
||||
[theme.breakpoints.up('md')]: {
|
||||
width: `calc(100% - ${drawerWidth}px)`
|
||||
}
|
||||
},
|
||||
},
|
||||
menuButton: {
|
||||
marginRight: theme.spacing(2),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
display: 'none',
|
||||
toolbarImage: {
|
||||
[theme.breakpoints.up('xs')]: {
|
||||
height: 24,
|
||||
marginRight: theme.spacing(2)
|
||||
},
|
||||
[theme.breakpoints.up('sm')]: {
|
||||
height: 36,
|
||||
marginRight: theme.spacing(3)
|
||||
}
|
||||
},
|
||||
},
|
||||
toolbar: theme.mixins.toolbar,
|
||||
drawerPaper: {
|
||||
width: drawerWidth,
|
||||
},
|
||||
content: {
|
||||
flexGrow: 1
|
||||
},
|
||||
authMenu: {
|
||||
zIndex: theme.zIndex.tooltip,
|
||||
maxWidth: 400,
|
||||
},
|
||||
authMenuActions: {
|
||||
padding: theme.spacing(2),
|
||||
"& > * + *": {
|
||||
marginLeft: theme.spacing(2),
|
||||
menuButton: {
|
||||
marginRight: theme.spacing(2),
|
||||
[theme.breakpoints.up('md')]: {
|
||||
display: 'none'
|
||||
}
|
||||
},
|
||||
toolbar: theme.mixins.toolbar,
|
||||
drawerPaper: {
|
||||
width: drawerWidth
|
||||
},
|
||||
content: {
|
||||
flexGrow: 1
|
||||
},
|
||||
authMenu: {
|
||||
zIndex: theme.zIndex.tooltip,
|
||||
maxWidth: 400
|
||||
},
|
||||
authMenuActions: {
|
||||
padding: theme.spacing(2),
|
||||
'& > * + *': {
|
||||
marginLeft: theme.spacing(2)
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
interface MenuAppBarState {
|
||||
mobileOpen: boolean;
|
||||
authMenuOpen: boolean;
|
||||
}
|
||||
|
||||
interface MenuAppBarProps extends WithFeaturesProps, AuthenticatedContextProps, WithTheme, WithStyles<typeof styles>, RouteComponentProps {
|
||||
interface MenuAppBarProps
|
||||
extends WithFeaturesProps,
|
||||
AuthenticatedContextProps,
|
||||
WithTheme,
|
||||
WithStyles<typeof styles>,
|
||||
RouteComponentProps {
|
||||
sectionTitle: string;
|
||||
}
|
||||
|
||||
class MenuAppBar extends React.Component<MenuAppBarProps, MenuAppBarState> {
|
||||
|
||||
constructor(props: MenuAppBarProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
@@ -101,38 +136,48 @@ class MenuAppBar extends React.Component<MenuAppBarProps, MenuAppBarState> {
|
||||
|
||||
handleToggle = () => {
|
||||
this.setState({ authMenuOpen: !this.state.authMenuOpen });
|
||||
}
|
||||
};
|
||||
|
||||
handleClose = (event: React.MouseEvent<Document>) => {
|
||||
if (this.anchorRef.current && this.anchorRef.current.contains(event.currentTarget)) {
|
||||
if (
|
||||
this.anchorRef.current &&
|
||||
this.anchorRef.current.contains(event.currentTarget)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.setState({ authMenuOpen: false });
|
||||
}
|
||||
};
|
||||
|
||||
handleDrawerToggle = () => {
|
||||
this.setState({ mobileOpen: !this.state.mobileOpen });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { classes, theme, children, sectionTitle, authenticatedContext, features } = this.props;
|
||||
const {
|
||||
classes,
|
||||
theme,
|
||||
children,
|
||||
sectionTitle,
|
||||
authenticatedContext,
|
||||
features
|
||||
} = this.props;
|
||||
const { mobileOpen, authMenuOpen } = this.state;
|
||||
const path = this.props.match.url;
|
||||
const drawer = (
|
||||
<div>
|
||||
<Toolbar>
|
||||
<Box display="flex">
|
||||
<img src="/app/icon.png" className={classes.toolbarImage} alt={PROJECT_NAME} />
|
||||
<img
|
||||
src="/app/icon.png"
|
||||
className={classes.toolbarImage}
|
||||
alt={PROJECT_NAME}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Typography variant="h6" color="textPrimary">
|
||||
{PROJECT_NAME}
|
||||
</Typography>
|
||||
|
||||
<Typography align="right" variant="caption" color="textPrimary">
|
||||
v{authenticatedContext.me.version}
|
||||
</Typography>
|
||||
|
||||
<Divider absolute />
|
||||
</Toolbar>
|
||||
|
||||
@@ -144,20 +189,35 @@ class MenuAppBar extends React.Component<MenuAppBarProps, MenuAppBarState> {
|
||||
)}
|
||||
|
||||
<List>
|
||||
<ListItem to='/network/' selected={path.startsWith('/network/')} button component={Link}>
|
||||
<ListItem
|
||||
to="/network/"
|
||||
selected={path.startsWith('/network/')}
|
||||
button
|
||||
component={Link}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<SettingsEthernetIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Network Connection" />
|
||||
</ListItem>
|
||||
<ListItem to='/ap/' selected={path.startsWith('/ap/')} button component={Link}>
|
||||
<ListItem
|
||||
to="/ap/"
|
||||
selected={path.startsWith('/ap/')}
|
||||
button
|
||||
component={Link}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<SettingsInputAntennaIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Access Point" />
|
||||
</ListItem>
|
||||
{features.ntp && (
|
||||
<ListItem to='/ntp/' selected={path.startsWith('/ntp/')} button component={Link}>
|
||||
<ListItem
|
||||
to="/ntp/"
|
||||
selected={path.startsWith('/ntp/')}
|
||||
button
|
||||
component={Link}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<AccessTimeIcon />
|
||||
</ListItemIcon>
|
||||
@@ -165,7 +225,12 @@ class MenuAppBar extends React.Component<MenuAppBarProps, MenuAppBarState> {
|
||||
</ListItem>
|
||||
)}
|
||||
{features.mqtt && (
|
||||
<ListItem to='/mqtt/' selected={path.startsWith('/mqtt/')} button component={Link}>
|
||||
<ListItem
|
||||
to="/mqtt/"
|
||||
selected={path.startsWith('/mqtt/')}
|
||||
button
|
||||
component={Link}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<DeviceHubIcon />
|
||||
</ListItemIcon>
|
||||
@@ -173,14 +238,25 @@ class MenuAppBar extends React.Component<MenuAppBarProps, MenuAppBarState> {
|
||||
</ListItem>
|
||||
)}
|
||||
{features.security && (
|
||||
<ListItem to='/security/' selected={path.startsWith('/security/')} button component={Link} disabled={!authenticatedContext.me.admin}>
|
||||
<ListItem
|
||||
to="/security/"
|
||||
selected={path.startsWith('/security/')}
|
||||
button
|
||||
component={Link}
|
||||
disabled={!authenticatedContext.me.admin}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<LockIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary="Security" />
|
||||
</ListItem>
|
||||
)}
|
||||
<ListItem to='/system/' selected={path.startsWith('/system/')} button component={Link} >
|
||||
<ListItem
|
||||
to="/system/"
|
||||
selected={path.startsWith('/system/')}
|
||||
button
|
||||
component={Link}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<SettingsIcon />
|
||||
</ListItemIcon>
|
||||
@@ -201,7 +277,12 @@ class MenuAppBar extends React.Component<MenuAppBarProps, MenuAppBarState> {
|
||||
>
|
||||
<AccountCircleIcon />
|
||||
</IconButton>
|
||||
<Popper open={authMenuOpen} anchorEl={this.anchorRef.current} transition className={classes.authMenu}>
|
||||
<Popper
|
||||
open={authMenuOpen}
|
||||
anchorEl={this.anchorRef.current}
|
||||
transition
|
||||
className={classes.authMenu}
|
||||
>
|
||||
<ClickAwayListener onClickAway={this.handleClose}>
|
||||
<Card id="menu-list-grow">
|
||||
<CardContent>
|
||||
@@ -212,13 +293,27 @@ class MenuAppBar extends React.Component<MenuAppBarProps, MenuAppBarState> {
|
||||
<AccountCircleIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary={"Signed in as: " + authenticatedContext.me.username} secondary={authenticatedContext.me.admin ? "Admin User" : undefined} />
|
||||
<ListItemText
|
||||
primary={
|
||||
'Signed in as: ' + authenticatedContext.me.username
|
||||
}
|
||||
secondary={
|
||||
authenticatedContext.me.admin ? 'Admin User' : undefined
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
</CardContent>
|
||||
<Divider />
|
||||
<CardActions className={classes.authMenuActions}>
|
||||
<Button variant="contained" fullWidth color="primary" onClick={authenticatedContext.signOut}>Sign Out</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
fullWidth
|
||||
color="primary"
|
||||
onClick={authenticatedContext.signOut}
|
||||
>
|
||||
Sign Out
|
||||
</Button>
|
||||
</CardActions>
|
||||
</Card>
|
||||
</ClickAwayListener>
|
||||
@@ -239,7 +334,12 @@ class MenuAppBar extends React.Component<MenuAppBarProps, MenuAppBarState> {
|
||||
>
|
||||
<MenuIcon />
|
||||
</IconButton>
|
||||
<Typography variant="h6" color="inherit" noWrap className={classes.title}>
|
||||
<Typography
|
||||
variant="h6"
|
||||
color="inherit"
|
||||
noWrap
|
||||
className={classes.title}
|
||||
>
|
||||
{sectionTitle}
|
||||
</Typography>
|
||||
{features.security && userMenu}
|
||||
@@ -253,10 +353,10 @@ class MenuAppBar extends React.Component<MenuAppBarProps, MenuAppBarState> {
|
||||
open={mobileOpen}
|
||||
onClose={this.handleDrawerToggle}
|
||||
classes={{
|
||||
paper: classes.drawerPaper,
|
||||
paper: classes.drawerPaper
|
||||
}}
|
||||
ModalProps={{
|
||||
keepMounted: true,
|
||||
keepMounted: true
|
||||
}}
|
||||
>
|
||||
{drawer}
|
||||
@@ -265,7 +365,7 @@ class MenuAppBar extends React.Component<MenuAppBarProps, MenuAppBarState> {
|
||||
<Hidden smDown implementation="css">
|
||||
<Drawer
|
||||
classes={{
|
||||
paper: classes.drawerPaper,
|
||||
paper: classes.drawerPaper
|
||||
}}
|
||||
variant="permanent"
|
||||
open
|
||||
@@ -285,10 +385,6 @@ class MenuAppBar extends React.Component<MenuAppBarProps, MenuAppBarState> {
|
||||
|
||||
export default withRouter(
|
||||
withTheme(
|
||||
withFeatures(
|
||||
withAuthenticatedContext(
|
||||
withStyles(styles)(MenuAppBar)
|
||||
)
|
||||
)
|
||||
withFeatures(withAuthenticatedContext(withStyles(styles)(MenuAppBar)))
|
||||
)
|
||||
);
|
||||
|
||||
@@ -1,7 +1,21 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
|
||||
import { Avatar, Button, Divider, Dialog, DialogTitle, DialogContent, DialogActions, Box } from '@material-ui/core';
|
||||
import { List, ListItem, ListItemAvatar, ListItemText } from '@material-ui/core';
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
Divider,
|
||||
Dialog,
|
||||
DialogTitle,
|
||||
DialogContent,
|
||||
DialogActions,
|
||||
Box
|
||||
} from '@material-ui/core';
|
||||
import {
|
||||
List,
|
||||
ListItem,
|
||||
ListItemAvatar,
|
||||
ListItemText
|
||||
} from '@material-ui/core';
|
||||
|
||||
import DevicesIcon from '@material-ui/icons/Devices';
|
||||
import MemoryIcon from '@material-ui/icons/Memory';
|
||||
@@ -11,9 +25,14 @@ import AppsIcon from '@material-ui/icons/Apps';
|
||||
import PowerSettingsNewIcon from '@material-ui/icons/PowerSettingsNew';
|
||||
import RefreshIcon from '@material-ui/icons/Refresh';
|
||||
import SettingsBackupRestoreIcon from '@material-ui/icons/SettingsBackupRestore';
|
||||
import TimerIcon from "@material-ui/icons/Timer";
|
||||
import TimerIcon from '@material-ui/icons/Timer';
|
||||
import BuildIcon from '@material-ui/icons/Build';
|
||||
|
||||
import { redirectingAuthorizedFetch, AuthenticatedContextProps, withAuthenticatedContext } from '../authentication';
|
||||
import {
|
||||
redirectingAuthorizedFetch,
|
||||
AuthenticatedContextProps,
|
||||
withAuthenticatedContext
|
||||
} from '../authentication';
|
||||
import { RestFormProps, FormButton, ErrorButton } from '../components';
|
||||
import { FACTORY_RESET_ENDPOINT, RESTART_ENDPOINT } from '../api';
|
||||
|
||||
@@ -25,31 +44,48 @@ interface SystemStatusFormState {
|
||||
processing: boolean;
|
||||
}
|
||||
|
||||
type SystemStatusFormProps = AuthenticatedContextProps & RestFormProps<SystemStatus>;
|
||||
type SystemStatusFormProps = AuthenticatedContextProps &
|
||||
RestFormProps<SystemStatus>;
|
||||
|
||||
function formatNumber(num: number) {
|
||||
return new Intl.NumberFormat().format(num);
|
||||
}
|
||||
|
||||
class SystemStatusForm extends Component<SystemStatusFormProps, SystemStatusFormState> {
|
||||
|
||||
class SystemStatusForm extends Component<
|
||||
SystemStatusFormProps,
|
||||
SystemStatusFormState
|
||||
> {
|
||||
state: SystemStatusFormState = {
|
||||
confirmRestart: false,
|
||||
confirmFactoryReset: false,
|
||||
processing: false
|
||||
}
|
||||
};
|
||||
|
||||
createListItems() {
|
||||
const { data } = this.props
|
||||
const { data } = this.props;
|
||||
return (
|
||||
<Fragment>
|
||||
<ListItem >
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
<BuildIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary="EMS-ESP Version"
|
||||
secondary={'v' + data.emsesp_version}
|
||||
/>
|
||||
</ListItem>
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
<DevicesIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary="Device (Platform / SDK)" secondary={data.esp_platform + ' / ' + data.sdk_version} />
|
||||
<ListItemText
|
||||
primary="Device (Platform / SDK)"
|
||||
secondary={data.esp_platform + ' / ' + data.sdk_version}
|
||||
/>
|
||||
</ListItem>
|
||||
<Divider variant="inset" component="li" />
|
||||
<ListItem>
|
||||
@@ -61,45 +97,76 @@ class SystemStatusForm extends Component<SystemStatusFormProps, SystemStatusForm
|
||||
<ListItemText primary="System Uptime" secondary={data.uptime} />
|
||||
</ListItem>
|
||||
<Divider variant="inset" component="li" />
|
||||
<ListItem >
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
<ShowChartIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary="CPU Frequency" secondary={data.cpu_freq_mhz + ' MHz'} />
|
||||
<ListItemText
|
||||
primary="CPU Frequency"
|
||||
secondary={data.cpu_freq_mhz + ' MHz'}
|
||||
/>
|
||||
</ListItem>
|
||||
<Divider variant="inset" component="li" />
|
||||
<ListItem >
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
<MemoryIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary="Heap (Free / Max Alloc)" secondary={formatNumber(data.free_heap) + ' / ' + formatNumber(data.max_alloc_heap) + ' bytes ' + (data.esp_platform === EspPlatform.ESP8266 ? '(' + data.heap_fragmentation + '% fragmentation)' : '')} />
|
||||
<ListItemText
|
||||
primary="Heap (Free / Max Alloc)"
|
||||
secondary={
|
||||
formatNumber(data.free_heap) +
|
||||
' / ' +
|
||||
formatNumber(data.max_alloc_heap) +
|
||||
' bytes ' +
|
||||
(data.esp_platform === EspPlatform.ESP8266
|
||||
? '(' + data.heap_fragmentation + '% fragmentation)'
|
||||
: '')
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
{
|
||||
(data.esp_platform === EspPlatform.ESP32 && data.psram_size > 0) && (
|
||||
<Fragment>
|
||||
<Divider variant="inset" component="li" />
|
||||
<ListItem >
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
<AppsIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary="PSRAM (Size / Free)" secondary={formatNumber(data.psram_size) + ' / ' + formatNumber(data.free_psram) + ' bytes'} />
|
||||
</ListItem>
|
||||
</Fragment>)
|
||||
}
|
||||
{data.esp_platform === EspPlatform.ESP32 && data.psram_size > 0 && (
|
||||
<Fragment>
|
||||
<Divider variant="inset" component="li" />
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
<AppsIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText
|
||||
primary="PSRAM (Size / Free)"
|
||||
secondary={
|
||||
formatNumber(data.psram_size) +
|
||||
' / ' +
|
||||
formatNumber(data.free_psram) +
|
||||
' bytes'
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
</Fragment>
|
||||
)}
|
||||
<Divider variant="inset" component="li" />
|
||||
<ListItem >
|
||||
<ListItem>
|
||||
<ListItemAvatar>
|
||||
<Avatar>
|
||||
<FolderIcon />
|
||||
</Avatar>
|
||||
</ListItemAvatar>
|
||||
<ListItemText primary="File System (Used / Total)" secondary={formatNumber(data.fs_used) + ' / ' + formatNumber(data.fs_total) + ' bytes (' + formatNumber(data.fs_total - data.fs_used) + '\xa0bytes free)'} />
|
||||
<ListItemText
|
||||
primary="File System (Used / Total)"
|
||||
secondary={
|
||||
formatNumber(data.fs_used) +
|
||||
' / ' +
|
||||
formatNumber(data.fs_total) +
|
||||
' bytes (' +
|
||||
formatNumber(data.fs_total - data.fs_used) +
|
||||
'\xa0bytes free)'
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
<Divider variant="inset" component="li" />
|
||||
</Fragment>
|
||||
@@ -119,41 +186,57 @@ class SystemStatusForm extends Component<SystemStatusFormProps, SystemStatusForm
|
||||
Are you sure you want to restart the device?
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button variant="contained" onClick={this.onRestartRejected} color="secondary">
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={this.onRestartRejected}
|
||||
color="secondary"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button startIcon={<PowerSettingsNewIcon />} variant="contained" onClick={this.onRestartConfirmed} disabled={this.state.processing} color="primary" autoFocus>
|
||||
<Button
|
||||
startIcon={<PowerSettingsNewIcon />}
|
||||
variant="contained"
|
||||
onClick={this.onRestartConfirmed}
|
||||
disabled={this.state.processing}
|
||||
color="primary"
|
||||
autoFocus
|
||||
>
|
||||
Restart
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
onRestart = () => {
|
||||
this.setState({ confirmRestart: true });
|
||||
}
|
||||
};
|
||||
|
||||
onRestartRejected = () => {
|
||||
this.setState({ confirmRestart: false });
|
||||
}
|
||||
};
|
||||
|
||||
onRestartConfirmed = () => {
|
||||
this.setState({ processing: true });
|
||||
redirectingAuthorizedFetch(RESTART_ENDPOINT, { method: 'POST' })
|
||||
.then(response => {
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
this.props.enqueueSnackbar("Device is restarting", { variant: 'info' });
|
||||
this.props.enqueueSnackbar('Device is restarting', {
|
||||
variant: 'info'
|
||||
});
|
||||
this.setState({ processing: false, confirmRestart: false });
|
||||
} else {
|
||||
throw Error("Invalid status code: " + response.status);
|
||||
throw Error('Invalid status code: ' + response.status);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.props.enqueueSnackbar(error.message || "Problem restarting device", { variant: 'error' });
|
||||
.catch((error) => {
|
||||
this.props.enqueueSnackbar(
|
||||
error.message || 'Problem restarting device',
|
||||
{ variant: 'error' }
|
||||
);
|
||||
this.setState({ processing: false, confirmRestart: false });
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
renderFactoryResetDialog() {
|
||||
return (
|
||||
@@ -168,72 +251,98 @@ class SystemStatusForm extends Component<SystemStatusFormProps, SystemStatusForm
|
||||
Are you sure you want to reset the device to its factory defaults?
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button variant="contained" onClick={this.onFactoryResetRejected} color="secondary">
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={this.onFactoryResetRejected}
|
||||
color="secondary"
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<ErrorButton startIcon={<SettingsBackupRestoreIcon />} variant="contained" onClick={this.onFactoryResetConfirmed} disabled={this.state.processing} autoFocus>
|
||||
<ErrorButton
|
||||
startIcon={<SettingsBackupRestoreIcon />}
|
||||
variant="contained"
|
||||
onClick={this.onFactoryResetConfirmed}
|
||||
disabled={this.state.processing}
|
||||
autoFocus
|
||||
>
|
||||
Factory Reset
|
||||
</ErrorButton>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
onFactoryReset = () => {
|
||||
this.setState({ confirmFactoryReset: true });
|
||||
}
|
||||
};
|
||||
|
||||
onFactoryResetRejected = () => {
|
||||
this.setState({ confirmFactoryReset: false });
|
||||
}
|
||||
};
|
||||
|
||||
onFactoryResetConfirmed = () => {
|
||||
this.setState({ processing: true });
|
||||
redirectingAuthorizedFetch(FACTORY_RESET_ENDPOINT, { method: 'POST' })
|
||||
.then(response => {
|
||||
.then((response) => {
|
||||
if (response.status === 200) {
|
||||
this.props.enqueueSnackbar("Factory reset in progress.", { variant: 'error' });
|
||||
this.props.enqueueSnackbar('Factory reset in progress.', {
|
||||
variant: 'error'
|
||||
});
|
||||
this.setState({ processing: false, confirmFactoryReset: false });
|
||||
} else {
|
||||
throw Error("Invalid status code: " + response.status);
|
||||
throw Error('Invalid status code: ' + response.status);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
this.props.enqueueSnackbar(error.message || "Problem factory resetting device", { variant: 'error' });
|
||||
.catch((error) => {
|
||||
this.props.enqueueSnackbar(
|
||||
error.message || 'Problem factory resetting device',
|
||||
{ variant: 'error' }
|
||||
);
|
||||
this.setState({ processing: false, confirmRestart: false });
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const me = this.props.authenticatedContext.me;
|
||||
return (
|
||||
<Fragment>
|
||||
<List>
|
||||
{this.createListItems()}
|
||||
</List>
|
||||
<List>{this.createListItems()}</List>
|
||||
<Box display="flex" flexWrap="wrap">
|
||||
<Box flexGrow={1} padding={1}>
|
||||
<FormButton startIcon={<RefreshIcon />} variant="contained" color="secondary" onClick={this.props.loadData}>
|
||||
<FormButton
|
||||
startIcon={<RefreshIcon />}
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
onClick={this.props.loadData}
|
||||
>
|
||||
Refresh
|
||||
</FormButton>
|
||||
</Box>
|
||||
{me.admin &&
|
||||
{me.admin && (
|
||||
<Box flexWrap="none" padding={1} whiteSpace="nowrap">
|
||||
<FormButton startIcon={<PowerSettingsNewIcon />} variant="contained" color="primary" onClick={this.onRestart}>
|
||||
<FormButton
|
||||
startIcon={<PowerSettingsNewIcon />}
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={this.onRestart}
|
||||
>
|
||||
Restart
|
||||
</FormButton>
|
||||
<ErrorButton startIcon={<SettingsBackupRestoreIcon />} variant="contained" onClick={this.onFactoryReset}>
|
||||
<ErrorButton
|
||||
startIcon={<SettingsBackupRestoreIcon />}
|
||||
variant="contained"
|
||||
onClick={this.onFactoryReset}
|
||||
>
|
||||
Factory reset
|
||||
</ErrorButton>
|
||||
</Box>
|
||||
}
|
||||
)}
|
||||
</Box>
|
||||
{this.renderRestartDialog()}
|
||||
{this.renderFactoryResetDialog()}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default withAuthenticatedContext(SystemStatusForm);
|
||||
|
||||
@@ -64,7 +64,6 @@ Authentication SecuritySettingsService::authenticate(const String & username, co
|
||||
inline void populateJWTPayload(JsonObject & payload, User * user) {
|
||||
payload["username"] = user->username;
|
||||
payload["admin"] = user->admin;
|
||||
payload["version"] = EMSESP_APP_VERSION; // proddy added
|
||||
}
|
||||
|
||||
boolean SecuritySettingsService::validatePayload(JsonObject & parsedPayload, User * user) {
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
#include <SystemStatus.h>
|
||||
|
||||
#include "../../src/emsesp_stub.hpp" // proddy added
|
||||
|
||||
using namespace std::placeholders; // for `_1` etc
|
||||
|
||||
SystemStatus::SystemStatus(AsyncWebServer * server, SecurityManager * securityManager) {
|
||||
server->on(SYSTEM_STATUS_SERVICE_PATH, HTTP_GET, securityManager->wrapRequest(std::bind(&SystemStatus::systemStatus, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
server->on(SYSTEM_STATUS_SERVICE_PATH,
|
||||
HTTP_GET,
|
||||
securityManager->wrapRequest(std::bind(&SystemStatus::systemStatus, this, _1), AuthenticationPredicates::IS_AUTHENTICATED));
|
||||
}
|
||||
|
||||
void SystemStatus::systemStatus(AsyncWebServerRequest * request) {
|
||||
AsyncJsonResponse * response = new AsyncJsonResponse(false, MAX_ESP_STATUS_SIZE);
|
||||
JsonObject root = response->getRoot();
|
||||
root["emsesp_version"] = EMSESP_APP_VERSION;
|
||||
root["esp_platform"] = "ESP32";
|
||||
root["max_alloc_heap"] = ESP.getMaxAllocHeap();
|
||||
root["psram_size"] = ESP.getPsramSize();
|
||||
|
||||
@@ -10,8 +10,6 @@
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <SecurityManager.h>
|
||||
|
||||
#include <uuid/log.h> // proddy added
|
||||
|
||||
#define MAX_ESP_STATUS_SIZE 1024
|
||||
#define SYSTEM_STATUS_SERVICE_PATH "/rest/systemStatus"
|
||||
|
||||
|
||||
@@ -63,7 +63,6 @@ Authentication SecuritySettingsService::authenticate(const String& username, con
|
||||
inline void populateJWTPayload(JsonObject& payload, User* user) {
|
||||
payload["username"] = user->username;
|
||||
payload["admin"] = user->admin;
|
||||
payload["version"] = EMSESP_APP_VERSION; // proddy added
|
||||
}
|
||||
|
||||
boolean SecuritySettingsService::validatePayload(JsonObject& parsedPayload, User* user) {
|
||||
|
||||
Reference in New Issue
Block a user