diff --git a/interface/src/components/MenuAppBar.tsx b/interface/src/components/MenuAppBar.tsx index 1f3902a48..f33b6cb66 100644 --- a/interface/src/components/MenuAppBar.tsx +++ b/interface/src/components/MenuAppBar.tsx @@ -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, RouteComponentProps { +interface MenuAppBarProps + extends WithFeaturesProps, + AuthenticatedContextProps, + WithTheme, + WithStyles, + RouteComponentProps { sectionTitle: string; } class MenuAppBar extends React.Component { - constructor(props: MenuAppBarProps) { super(props); this.state = { @@ -101,38 +136,48 @@ class MenuAppBar extends React.Component { handleToggle = () => { this.setState({ authMenuOpen: !this.state.authMenuOpen }); - } + }; handleClose = (event: React.MouseEvent) => { - 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 = (
- {PROJECT_NAME} + {PROJECT_NAME} {PROJECT_NAME} - -   v{authenticatedContext.me.version} - - @@ -144,20 +189,35 @@ class MenuAppBar extends React.Component { )} - + - + {features.ntp && ( - + @@ -165,7 +225,12 @@ class MenuAppBar extends React.Component { )} {features.mqtt && ( - + @@ -173,14 +238,25 @@ class MenuAppBar extends React.Component { )} {features.security && ( - + )} - + @@ -201,7 +277,12 @@ class MenuAppBar extends React.Component { > - + @@ -212,13 +293,27 @@ class MenuAppBar extends React.Component { - + - + @@ -239,7 +334,12 @@ class MenuAppBar extends React.Component { > - + {sectionTitle} {features.security && userMenu} @@ -253,10 +353,10 @@ class MenuAppBar extends React.Component { 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 { { export default withRouter( withTheme( - withFeatures( - withAuthenticatedContext( - withStyles(styles)(MenuAppBar) - ) - ) + withFeatures(withAuthenticatedContext(withStyles(styles)(MenuAppBar))) ) ); diff --git a/interface/src/system/SystemStatusForm.tsx b/interface/src/system/SystemStatusForm.tsx index ad59fabf3..1fa18647b 100644 --- a/interface/src/system/SystemStatusForm.tsx +++ b/interface/src/system/SystemStatusForm.tsx @@ -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; +type SystemStatusFormProps = AuthenticatedContextProps & + RestFormProps; function formatNumber(num: number) { return new Intl.NumberFormat().format(num); } -class SystemStatusForm extends Component { - +class SystemStatusForm extends Component< + SystemStatusFormProps, + SystemStatusFormState +> { state: SystemStatusFormState = { confirmRestart: false, confirmFactoryReset: false, processing: false - } + }; createListItems() { - const { data } = this.props + const { data } = this.props; return ( - + + + + + + + + + - + @@ -61,45 +97,76 @@ class SystemStatusForm extends Component - + - + - + - + - { - (data.esp_platform === EspPlatform.ESP32 && data.psram_size > 0) && ( - - - - - - - - - - - ) - } + {data.esp_platform === EspPlatform.ESP32 && data.psram_size > 0 && ( + + + + + + + + + + + + )} - + - + @@ -119,41 +186,57 @@ class SystemStatusForm extends Component - - - ) + ); } 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 - - } variant="contained" onClick={this.onFactoryResetConfirmed} disabled={this.state.processing} autoFocus> + } + variant="contained" + onClick={this.onFactoryResetConfirmed} + disabled={this.state.processing} + autoFocus + > Factory Reset - ) + ); } 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 ( - - {this.createListItems()} - + {this.createListItems()} - } variant="contained" color="secondary" onClick={this.props.loadData}> + } + variant="contained" + color="secondary" + onClick={this.props.loadData} + > Refresh - {me.admin && + {me.admin && ( - } variant="contained" color="primary" onClick={this.onRestart}> + } + variant="contained" + color="primary" + onClick={this.onRestart} + > Restart - } variant="contained" onClick={this.onFactoryReset}> + } + variant="contained" + onClick={this.onFactoryReset} + > Factory reset - } + )} {this.renderRestartDialog()} {this.renderFactoryResetDialog()} ); } - } export default withAuthenticatedContext(SystemStatusForm); diff --git a/lib/framework/SecuritySettingsService.cpp b/lib/framework/SecuritySettingsService.cpp index 302770be7..005a33baf 100644 --- a/lib/framework/SecuritySettingsService.cpp +++ b/lib/framework/SecuritySettingsService.cpp @@ -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) { diff --git a/lib/framework/SystemStatus.cpp b/lib/framework/SystemStatus.cpp index 98714d671..fa55d0e3b 100644 --- a/lib/framework/SystemStatus.cpp +++ b/lib/framework/SystemStatus.cpp @@ -1,14 +1,19 @@ #include +#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(); diff --git a/lib/framework/SystemStatus.h b/lib/framework/SystemStatus.h index 5ac388590..584580f67 100644 --- a/lib/framework/SystemStatus.h +++ b/lib/framework/SystemStatus.h @@ -10,8 +10,6 @@ #include #include -#include // proddy added - #define MAX_ESP_STATUS_SIZE 1024 #define SYSTEM_STATUS_SERVICE_PATH "/rest/systemStatus" diff --git a/lib_standalone/SecuritySettingsService.cpp b/lib_standalone/SecuritySettingsService.cpp index 61f42e7c6..bfdc0a211 100644 --- a/lib_standalone/SecuritySettingsService.cpp +++ b/lib_standalone/SecuritySettingsService.cpp @@ -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) {