reduce use of ternaries in form code

This commit is contained in:
Rick Watson 2019-08-09 18:21:28 +01:00
parent df06e58fb0
commit ff85c2e661
18 changed files with 456 additions and 730 deletions

View File

@ -52,10 +52,11 @@ export const restComponent = (endpointUrl, FormComponent) => {
}) })
.then(json => { this.setState({ data: json, fetched: true }) }) .then(json => { this.setState({ data: json, fetched: true }) })
.catch(error => { .catch(error => {
this.props.enqueueSnackbar("Problem fetching: " + error.message, { const errorMessage = error.message || "Unknown error";
this.props.enqueueSnackbar("Problem fetching: " + errorMessage, {
variant: 'error', variant: 'error',
}); });
this.setState({ data: null, fetched: true, errorMessage: error.message }); this.setState({ data: null, fetched: true, errorMessage });
}); });
} }
@ -80,10 +81,11 @@ export const restComponent = (endpointUrl, FormComponent) => {
}); });
this.setState({ data: json, fetched: true }); this.setState({ data: json, fetched: true });
}).catch(error => { }).catch(error => {
this.props.enqueueSnackbar("Problem saving: " + error.message, { const errorMessage = error.message || "Unknown error";
this.props.enqueueSnackbar("Problem saving: " + errorMessage, {
variant: 'error', variant: 'error',
}); });
this.setState({ data: null, fetched: true, errorMessage: error.message }); this.setState({ data: null, fetched: true, errorMessage });
}); });
} }

View File

@ -1,7 +1,8 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { AP_SETTINGS_ENDPOINT } from '../constants/Endpoints'; import { AP_SETTINGS_ENDPOINT } from '../constants/Endpoints';
import { restComponent } from '../components/RestComponent'; import { restComponent } from '../components/RestComponent';
import LoadingNotification from '../components/LoadingNotification';
import SectionContent from '../components/SectionContent'; import SectionContent from '../components/SectionContent';
import APSettingsForm from '../forms/APSettingsForm'; import APSettingsForm from '../forms/APSettingsForm';
@ -12,17 +13,20 @@ class APSettings extends Component {
} }
render() { render() {
const { data, fetched, errorMessage } = this.props; const { fetched, errorMessage, data, saveData, loadData, handleValueChange } = this.props;
return ( return (
<SectionContent title="AP Settings"> <SectionContent title="AP Settings">
<APSettingsForm <LoadingNotification
apSettings={data} onReset={loadData}
apSettingsFetched={fetched} fetched={fetched}
errorMessage={errorMessage} errorMessage={errorMessage}>
onSubmit={this.props.saveData} <APSettingsForm
onReset={this.props.loadData} apSettings={data}
handleValueChange={this.props.handleValueChange} onSubmit={saveData}
/> onReset={loadData}
handleValueChange={handleValueChange}
/>
</LoadingNotification>
</SectionContent> </SectionContent>
) )
} }

View File

@ -2,8 +2,6 @@ import React, { Component, Fragment } from 'react';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
import LinearProgress from '@material-ui/core/LinearProgress';
import Typography from '@material-ui/core/Typography';
import List from '@material-ui/core/List'; import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem'; import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText'; import ListItemText from '@material-ui/core/ListItemText';
@ -15,6 +13,7 @@ import DeviceHubIcon from '@material-ui/icons/DeviceHub';
import ComputerIcon from '@material-ui/icons/Computer'; import ComputerIcon from '@material-ui/icons/Computer';
import { restComponent } from '../components/RestComponent'; import { restComponent } from '../components/RestComponent';
import LoadingNotification from '../components/LoadingNotification';
import SectionContent from '../components/SectionContent' import SectionContent from '../components/SectionContent'
import * as Highlight from '../constants/Highlight'; import * as Highlight from '../constants/Highlight';
@ -27,10 +26,6 @@ const styles = theme => ({
["apStatus_" + Highlight.IDLE]: { ["apStatus_" + Highlight.IDLE]: {
backgroundColor: theme.palette.highlight_idle backgroundColor: theme.palette.highlight_idle
}, },
fetching: {
margin: theme.spacing(4),
textAlign: "center"
},
button: { button: {
marginRight: theme.spacing(2), marginRight: theme.spacing(2),
marginTop: theme.spacing(2), marginTop: theme.spacing(2),
@ -106,30 +101,15 @@ class APStatus extends Component {
} }
render() { render() {
const { data, fetched, errorMessage, classes } = this.props; const { fetched, errorMessage, data, loadData, classes } = this.props;
return ( return (
<SectionContent title="AP Status"> <SectionContent title="AP Status">
{ <LoadingNotification
!fetched ? onReset={loadData}
<div> fetched={fetched}
<LinearProgress className={classes.fetching} /> errorMessage={errorMessage}>
<Typography variant="h4" className={classes.fetching}> {this.renderAPStatus(data, classes)}
Loading... </LoadingNotification>
</Typography>
</div>
:
data ? this.renderAPStatus(data, classes)
:
<div>
<Typography variant="h4" className={classes.fetching}>
{errorMessage}
</Typography>
<Button variant="contained" color="secondary" className={classes.button} onClick={this.props.loadData}>
Refresh
</Button>
</div>
}
</SectionContent> </SectionContent>
) )
} }

View File

@ -2,8 +2,9 @@ import React, { Component } from 'react';
import { SECURITY_SETTINGS_ENDPOINT } from '../constants/Endpoints'; import { SECURITY_SETTINGS_ENDPOINT } from '../constants/Endpoints';
import { restComponent } from '../components/RestComponent'; import { restComponent } from '../components/RestComponent';
import ManageUsersForm from '../forms/ManageUsersForm'; import LoadingNotification from '../components/LoadingNotification';
import SectionContent from '../components/SectionContent'; import SectionContent from '../components/SectionContent';
import ManageUsersForm from '../forms/ManageUsersForm';
class ManageUsers extends Component { class ManageUsers extends Component {
@ -12,18 +13,21 @@ class ManageUsers extends Component {
} }
render() { render() {
const { data, fetched, errorMessage } = this.props; const { fetched, errorMessage, data, saveData, loadData, setData, handleValueChange } = this.props;
return ( return (
<SectionContent title="Manage Users" titleGutter> <SectionContent title="Manage Users" titleGutter>
<ManageUsersForm <LoadingNotification
userData={data} onReset={loadData}
userDataFetched={fetched} fetched={fetched}
errorMessage={errorMessage} errorMessage={errorMessage}>
onSubmit={this.props.saveData} <ManageUsersForm
onReset={this.props.loadData} userData={data}
setData={this.props.setData} onSubmit={saveData}
handleValueChange={this.props.handleValueChange} onReset={loadData}
/> setData={setData}
handleValueChange={handleValueChange}
/>
</LoadingNotification>
</SectionContent> </SectionContent>
) )
} }

View File

@ -1,28 +1,32 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { NTP_SETTINGS_ENDPOINT } from '../constants/Endpoints'; import { NTP_SETTINGS_ENDPOINT } from '../constants/Endpoints';
import {restComponent} from '../components/RestComponent'; import { restComponent } from '../components/RestComponent';
import LoadingNotification from '../components/LoadingNotification';
import SectionContent from '../components/SectionContent'; import SectionContent from '../components/SectionContent';
import NTPSettingsForm from '../forms/NTPSettingsForm'; import NTPSettingsForm from '../forms/NTPSettingsForm';
class NTPSettings extends Component { class NTPSettings extends Component {
componentDidMount() { componentDidMount() {
this.props.loadData(); this.props.loadData();
} }
render() { render() {
const { data, fetched, errorMessage } = this.props; const { fetched, errorMessage, data, saveData, loadData, handleValueChange } = this.props;
return ( return (
<SectionContent title="NTP Settings"> <SectionContent title="NTP Settings">
<NTPSettingsForm <LoadingNotification
ntpSettings={data} onReset={loadData}
ntpSettingsFetched={fetched} fetched={fetched}
errorMessage={errorMessage} errorMessage={errorMessage}>
onSubmit={this.props.saveData} <NTPSettingsForm
onReset={this.props.loadData} ntpSettings={data}
handleValueChange={this.props.handleValueChange} onSubmit={saveData}
/> onReset={loadData}
handleValueChange={handleValueChange}
/>
</LoadingNotification>
</SectionContent> </SectionContent>
) )
} }

View File

@ -2,8 +2,6 @@ import React, { Component, Fragment } from 'react';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
import LinearProgress from '@material-ui/core/LinearProgress';
import Typography from '@material-ui/core/Typography';
import List from '@material-ui/core/List'; import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem'; import ListItem from '@material-ui/core/ListItem';
import ListItemAvatar from '@material-ui/core/ListItemAvatar'; import ListItemAvatar from '@material-ui/core/ListItemAvatar';
@ -22,6 +20,7 @@ import * as Highlight from '../constants/Highlight';
import { unixTimeToTimeAndDate } from '../constants/TimeFormat'; import { unixTimeToTimeAndDate } from '../constants/TimeFormat';
import { NTP_STATUS_ENDPOINT } from '../constants/Endpoints'; import { NTP_STATUS_ENDPOINT } from '../constants/Endpoints';
import { restComponent } from '../components/RestComponent'; import { restComponent } from '../components/RestComponent';
import LoadingNotification from '../components/LoadingNotification';
import SectionContent from '../components/SectionContent'; import SectionContent from '../components/SectionContent';
import moment from 'moment'; import moment from 'moment';
@ -36,10 +35,6 @@ const styles = theme => ({
["ntpStatus_" + Highlight.WARN]: { ["ntpStatus_" + Highlight.WARN]: {
backgroundColor: theme.palette.highlight_warn backgroundColor: theme.palette.highlight_warn
}, },
fetching: {
margin: theme.spacing(4),
textAlign: "center"
},
button: { button: {
marginRight: theme.spacing(2), marginRight: theme.spacing(2),
marginTop: theme.spacing(2), marginTop: theme.spacing(2),
@ -131,32 +126,17 @@ class NTPStatus extends Component {
} }
render() { render() {
const { data, fetched, errorMessage, classes } = this.props; const { data, fetched, errorMessage, loadData, classes } = this.props;
return ( return (
<SectionContent title="NTP Status"> <SectionContent title="NTP Status">
{ <LoadingNotification
!fetched ? onReset={loadData}
<div> fetched={fetched}
<LinearProgress className={classes.fetching} /> errorMessage={errorMessage}>
<Typography variant="h4" className={classes.fetching}> {this.renderNTPStatus(data, classes)}
Loading... </LoadingNotification>
</Typography>
</div>
:
data ? this.renderNTPStatus(data, classes)
:
<div>
<Typography variant="h4" className={classes.fetching}>
{errorMessage}
</Typography>
<Button variant="contained" color="secondary" className={classes.button} onClick={this.props.loadData}>
Refresh
</Button>
</div>
}
</SectionContent> </SectionContent>
) );
} }
} }

View File

@ -1,29 +1,33 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import { OTA_SETTINGS_ENDPOINT } from '../constants/Endpoints'; import { OTA_SETTINGS_ENDPOINT } from '../constants/Endpoints';
import {restComponent} from '../components/RestComponent'; import { restComponent } from '../components/RestComponent';
import LoadingNotification from '../components/LoadingNotification';
import SectionContent from '../components/SectionContent'; import SectionContent from '../components/SectionContent';
import OTASettingsForm from '../forms/OTASettingsForm'; import OTASettingsForm from '../forms/OTASettingsForm';
class OTASettings extends Component { class OTASettings extends Component {
componentDidMount() { componentDidMount() {
this.props.loadData(); this.props.loadData();
} }
render() { render() {
const { data, fetched, errorMessage } = this.props; const { fetched, errorMessage, data, saveData, loadData, handleValueChange, handleCheckboxChange } = this.props;
return ( return (
<SectionContent title="OTA Settings"> <SectionContent title="OTA Settings">
<OTASettingsForm <LoadingNotification
otaSettings={data} onReset={loadData}
otaSettingsFetched={fetched} fetched={fetched}
errorMessage={errorMessage} errorMessage={errorMessage}>
onSubmit={this.props.saveData} <OTASettingsForm
onReset={this.props.loadData} otaSettings={data}
handleValueChange={this.props.handleValueChange} onSubmit={saveData}
handleCheckboxChange={this.props.handleCheckboxChange} onReset={loadData}
/> handleValueChange={handleValueChange}
handleCheckboxChange={handleCheckboxChange}
/>
</LoadingNotification>
</SectionContent> </SectionContent>
) )
} }

View File

@ -2,6 +2,7 @@ import React, { Component } from 'react';
import { SECURITY_SETTINGS_ENDPOINT } from '../constants/Endpoints'; import { SECURITY_SETTINGS_ENDPOINT } from '../constants/Endpoints';
import { restComponent } from '../components/RestComponent'; import { restComponent } from '../components/RestComponent';
import LoadingNotification from '../components/LoadingNotification';
import SecuritySettingsForm from '../forms/SecuritySettingsForm'; import SecuritySettingsForm from '../forms/SecuritySettingsForm';
import SectionContent from '../components/SectionContent'; import SectionContent from '../components/SectionContent';
@ -15,14 +16,17 @@ class SecuritySettings extends Component {
const { data, fetched, errorMessage, saveData, loadData, handleValueChange } = this.props; const { data, fetched, errorMessage, saveData, loadData, handleValueChange } = this.props;
return ( return (
<SectionContent title="Security Settings"> <SectionContent title="Security Settings">
<SecuritySettingsForm <LoadingNotification
securitySettings={data}
securitySettingsFetched={fetched}
errorMessage={errorMessage}
onSubmit={saveData}
onReset={loadData} onReset={loadData}
handleValueChange={handleValueChange} fetched={fetched}
/> errorMessage={errorMessage}>
<SecuritySettingsForm
securitySettings={data}
onSubmit={saveData}
onReset={loadData}
handleValueChange={handleValueChange}
/>
</LoadingNotification>
</SectionContent> </SectionContent>
) )
} }

View File

@ -2,8 +2,6 @@ import React, { Component, Fragment } from 'react';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
import LinearProgress from '@material-ui/core/LinearProgress';
import Typography from '@material-ui/core/Typography';
import List from '@material-ui/core/List'; import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem'; import ListItem from '@material-ui/core/ListItem';
import ListItemAvatar from '@material-ui/core/ListItemAvatar'; import ListItemAvatar from '@material-ui/core/ListItemAvatar';
@ -16,16 +14,12 @@ import ShowChartIcon from '@material-ui/icons/ShowChart';
import SdStorageIcon from '@material-ui/icons/SdStorage'; import SdStorageIcon from '@material-ui/icons/SdStorage';
import DataUsageIcon from '@material-ui/icons/DataUsage'; import DataUsageIcon from '@material-ui/icons/DataUsage';
import { SYSTEM_STATUS_ENDPOINT } from '../constants/Endpoints'; import { SYSTEM_STATUS_ENDPOINT } from '../constants/Endpoints';
import { restComponent } from '../components/RestComponent'; import { restComponent } from '../components/RestComponent';
import LoadingNotification from '../components/LoadingNotification';
import SectionContent from '../components/SectionContent'; import SectionContent from '../components/SectionContent';
const styles = theme => ({ const styles = theme => ({
fetching: {
margin: theme.spacing(4),
textAlign: "center"
},
button: { button: {
marginRight: theme.spacing(2), marginRight: theme.spacing(2),
marginTop: theme.spacing(2), marginTop: theme.spacing(2),
@ -104,29 +98,15 @@ class SystemStatus extends Component {
} }
render() { render() {
const { data, fetched, errorMessage, classes } = this.props; const { data, fetched, errorMessage, loadData, classes } = this.props;
return ( return (
<SectionContent title="System Status"> <SectionContent title="System Status">
{ <LoadingNotification
!fetched ? onReset={loadData}
<div> fetched={fetched}
<LinearProgress className={classes.fetching} /> errorMessage={errorMessage}>
<Typography variant="h4" className={classes.fetching}> {this.renderNTPStatus(data, classes)}
Loading... </LoadingNotification>
</Typography>
</div>
:
data ? this.renderNTPStatus(data, classes)
:
<div>
<Typography variant="h4" className={classes.fetching}>
{errorMessage}
</Typography>
<Button variant="contained" color="secondary" className={classes.button} onClick={this.props.loadData}>
Refresh
</Button>
</div>
}
</SectionContent> </SectionContent>
) )
} }

View File

@ -1,10 +1,10 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { withSnackbar } from 'notistack';
import { SCAN_NETWORKS_ENDPOINT, LIST_NETWORKS_ENDPOINT } from '../constants/Endpoints'; import { SCAN_NETWORKS_ENDPOINT, LIST_NETWORKS_ENDPOINT } from '../constants/Endpoints';
import SectionContent from '../components/SectionContent'; import SectionContent from '../components/SectionContent';
import WiFiNetworkSelector from '../forms/WiFiNetworkSelector'; import WiFiNetworkSelector from '../forms/WiFiNetworkSelector';
import { withSnackbar } from 'notistack';
import { redirectingAuthorizedFetch } from '../authentication/Authentication'; import { redirectingAuthorizedFetch } from '../authentication/Authentication';
const NUM_POLLS = 10 const NUM_POLLS = 10

View File

@ -1,8 +1,9 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { WIFI_SETTINGS_ENDPOINT } from '../constants/Endpoints'; import { WIFI_SETTINGS_ENDPOINT } from '../constants/Endpoints';
import { restComponent } from '../components/RestComponent'; import { restComponent } from '../components/RestComponent';
import LoadingNotification from '../components/LoadingNotification';
import SectionContent from '../components/SectionContent'; import SectionContent from '../components/SectionContent';
import WiFiSettingsForm from '../forms/WiFiSettingsForm'; import WiFiSettingsForm from '../forms/WiFiSettingsForm';
@ -18,10 +19,10 @@ class WiFiSettings extends Component {
const { selectedNetwork } = this.props; const { selectedNetwork } = this.props;
if (selectedNetwork) { if (selectedNetwork) {
var wifiSettings = { var wifiSettings = {
ssid:selectedNetwork.ssid, ssid: selectedNetwork.ssid,
password:"", password: "",
hostname:"esp8266-react", hostname: "esp8266-react",
static_ip_config:false, static_ip_config: false,
} }
this.props.setData(wifiSettings); this.props.setData(wifiSettings);
} else { } else {
@ -35,20 +36,23 @@ class WiFiSettings extends Component {
} }
render() { render() {
const { data, fetched, errorMessage, selectedNetwork } = this.props; const { data, fetched, errorMessage, saveData, loadData, handleValueChange, handleCheckboxChange, selectedNetwork, deselectNetwork } = this.props;
return ( return (
<SectionContent title="WiFi Settings"> <SectionContent title="WiFi Settings">
<WiFiSettingsForm <LoadingNotification
wifiSettings={data} onReset={loadData}
wifiSettingsFetched={fetched} fetched={fetched}
errorMessage={errorMessage} errorMessage={errorMessage}>
selectedNetwork={selectedNetwork} <WiFiSettingsForm
deselectNetwork={this.props.deselectNetwork} wifiSettings={data}
onSubmit={this.props.saveData} selectedNetwork={selectedNetwork}
onReset={this.deselectNetworkAndLoadData} deselectNetwork={deselectNetwork}
handleValueChange={this.props.handleValueChange} onSubmit={saveData}
handleCheckboxChange={this.props.handleCheckboxChange} onReset={this.deselectNetworkAndLoadData}
/> handleValueChange={handleValueChange}
handleCheckboxChange={handleCheckboxChange}
/>
</LoadingNotification>
</SectionContent> </SectionContent>
) )
} }

View File

@ -2,14 +2,10 @@ import React, { Component, Fragment } from 'react';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
import LinearProgress from '@material-ui/core/LinearProgress';
import Typography from '@material-ui/core/Typography';
import List from '@material-ui/core/List'; import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem'; import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText'; import ListItemText from '@material-ui/core/ListItemText';
import ListItemAvatar from '@material-ui/core/ListItemAvatar'; import ListItemAvatar from '@material-ui/core/ListItemAvatar';
import Avatar from '@material-ui/core/Avatar'; import Avatar from '@material-ui/core/Avatar';
import Divider from '@material-ui/core/Divider'; import Divider from '@material-ui/core/Divider';
import WifiIcon from '@material-ui/icons/Wifi'; import WifiIcon from '@material-ui/icons/Wifi';
@ -23,6 +19,7 @@ import { WIFI_STATUS_ENDPOINT } from '../constants/Endpoints';
import { isConnected, connectionStatus, connectionStatusHighlight } from '../constants/WiFiConnectionStatus'; import { isConnected, connectionStatus, connectionStatusHighlight } from '../constants/WiFiConnectionStatus';
import * as Highlight from '../constants/Highlight'; import * as Highlight from '../constants/Highlight';
import { restComponent } from '../components/RestComponent'; import { restComponent } from '../components/RestComponent';
import LoadingNotification from '../components/LoadingNotification';
const styles = theme => ({ const styles = theme => ({
["wifiStatus_" + Highlight.IDLE]: { ["wifiStatus_" + Highlight.IDLE]: {
@ -37,10 +34,6 @@ const styles = theme => ({
["wifiStatus_" + Highlight.WARN]: { ["wifiStatus_" + Highlight.WARN]: {
backgroundColor: theme.palette.highlight_warn backgroundColor: theme.palette.highlight_warn
}, },
fetching: {
margin: theme.spacing(4),
textAlign: "center"
},
button: { button: {
marginRight: theme.spacing(2), marginRight: theme.spacing(2),
marginTop: theme.spacing(2), marginTop: theme.spacing(2),
@ -145,32 +138,19 @@ class WiFiStatus extends Component {
} }
render() { render() {
const { data, fetched, errorMessage, classes } = this.props; const { data, fetched, errorMessage, loadData, classes } = this.props;
return ( return (
<SectionContent title="WiFi Status"> <SectionContent title="WiFi Status">
{ <LoadingNotification
!fetched ? onReset={loadData}
<div> fetched={fetched}
<LinearProgress className={classes.fetching} /> errorMessage={errorMessage}>
<Typography variant="h4" className={classes.fetching}> {this.renderWiFiStatus(data, classes)}
Loading... </LoadingNotification>
</Typography>
</div>
:
data ? this.renderWiFiStatus(data, classes)
:
<div>
<Typography variant="h4" className={classes.fetching}>
{errorMessage}
</Typography>
<Button variant="contained" color="secondary" className={classes.button} onClick={this.props.loadData}>
Refresh
</Button>
</div>
}
</SectionContent> </SectionContent>
) );
} }
} }
export default restComponent(WIFI_STATUS_ENDPOINT, withStyles(styles)(WiFiStatus)); export default restComponent(WIFI_STATUS_ENDPOINT, withStyles(styles)(WiFiStatus));

View File

@ -1,29 +1,19 @@
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { TextValidator, ValidatorForm, SelectValidator } from 'react-material-ui-form-validator';
import { isAPEnabled } from '../constants/WiFiAPModes';
import PasswordValidator from '../components/PasswordValidator';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
import LinearProgress from '@material-ui/core/LinearProgress';
import Typography from '@material-ui/core/Typography';
import MenuItem from '@material-ui/core/MenuItem'; import MenuItem from '@material-ui/core/MenuItem';
import { TextValidator, ValidatorForm, SelectValidator } from 'react-material-ui-form-validator';
import {isAPEnabled} from '../constants/WiFiAPModes';
import PasswordValidator from '../components/PasswordValidator';
const styles = theme => ({ const styles = theme => ({
loadingSettings: {
margin: theme.spacing(0.5),
},
loadingSettingsDetails: {
margin: theme.spacing(4),
textAlign: "center"
},
textField: { textField: {
width: "100%" width: "100%"
}, },
selectField:{ selectField: {
width: "100%", width: "100%",
marginTop: theme.spacing(2), marginTop: theme.spacing(2),
marginBottom: theme.spacing(0.5) marginBottom: theme.spacing(0.5)
@ -37,86 +27,54 @@ const styles = theme => ({
class APSettingsForm extends React.Component { class APSettingsForm extends React.Component {
render() { render() {
const { classes, apSettingsFetched, apSettings, errorMessage, handleValueChange, onSubmit, onReset } = this.props; const { classes, apSettings, handleValueChange, onSubmit, onReset } = this.props;
return ( return (
<div> <ValidatorForm onSubmit={onSubmit} ref="APSettingsForm">
<SelectValidator name="provision_mode" label="Provide Access Point..." value={apSettings.provision_mode} className={classes.selectField}
onChange={handleValueChange('provision_mode')}>
<MenuItem value={0}>Always</MenuItem>
<MenuItem value={1}>When WiFi Disconnected</MenuItem>
<MenuItem value={2}>Never</MenuItem>
</SelectValidator>
{ {
!apSettingsFetched ? isAPEnabled(apSettings.provision_mode) &&
<Fragment>
<div className={classes.loadingSettings}> <TextValidator
<LinearProgress className={classes.loadingSettingsDetails}/> validators={['required', 'matchRegexp:^.{1,32}$']}
<Typography variant="h4" className={classes.loadingSettingsDetails}> errorMessages={['Access Point SSID is required', 'Access Point SSID must be 32 characters or less']}
Loading... name="ssid"
</Typography> label="Access Point SSID"
</div> className={classes.textField}
value={apSettings.ssid}
: apSettings ? onChange={handleValueChange('ssid')}
margin="normal"
<ValidatorForm onSubmit={onSubmit} ref="APSettingsForm"> />
<PasswordValidator
<SelectValidator name="provision_mode" label="Provide Access Point..." value={apSettings.provision_mode} className={classes.selectField} validators={['required', 'matchRegexp:^.{1,64}$']}
onChange={handleValueChange('provision_mode')}> errorMessages={['Access Point Password is required', 'Access Point Password must be 64 characters or less']}
<MenuItem value={0}>Always</MenuItem> name="password"
<MenuItem value={1}>When WiFi Disconnected</MenuItem> label="Access Point Password"
<MenuItem value={2}>Never</MenuItem> className={classes.textField}
</SelectValidator> value={apSettings.password}
onChange={handleValueChange('password')}
{ margin="normal"
isAPEnabled(apSettings.provision_mode) && />
<Fragment> </Fragment>
<TextValidator }
validators={['required', 'matchRegexp:^.{1,32}$']} <Button variant="contained" color="primary" className={classes.button} type="submit">
errorMessages={['Access Point SSID is required', 'Access Point SSID must be 32 characters or less']} Save
name="ssid" </Button>
label="Access Point SSID" <Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
className={classes.textField} Reset
value={apSettings.ssid} </Button>
onChange={handleValueChange('ssid')} </ValidatorForm>
margin="normal"
/>
<PasswordValidator
validators={['required', 'matchRegexp:^.{1,64}$']}
errorMessages={['Access Point Password is required', 'Access Point Password must be 64 characters or less']}
name="password"
label="Access Point Password"
className={classes.textField}
value={apSettings.password}
onChange={handleValueChange('password')}
margin="normal"
/>
</Fragment>
}
<Button variant="contained" color="primary" className={classes.button} type="submit">
Save
</Button>
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
Reset
</Button>
</ValidatorForm>
:
<div className={classes.loadingSettings}>
<Typography variant="h4" className={classes.loadingSettingsDetails}>
{errorMessage}
</Typography>
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
Reset
</Button>
</div>
}
</div>
); );
} }
} }
APSettingsForm.propTypes = { APSettingsForm.propTypes = {
classes: PropTypes.object.isRequired, classes: PropTypes.object.isRequired,
apSettingsFetched: PropTypes.bool.isRequired,
apSettings: PropTypes.object, apSettings: PropTypes.object,
errorMessage: PropTypes.string,
onSubmit: PropTypes.func.isRequired, onSubmit: PropTypes.func.isRequired,
onReset: PropTypes.func.isRequired, onReset: PropTypes.func.isRequired,
handleValueChange: PropTypes.func.isRequired handleValueChange: PropTypes.func.isRequired

View File

@ -5,7 +5,6 @@ import { ValidatorForm } from 'react-material-ui-form-validator';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
import LinearProgress from '@material-ui/core/LinearProgress';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import Table from '@material-ui/core/Table'; import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody'; import TableBody from '@material-ui/core/TableBody';
@ -14,7 +13,6 @@ import TableFooter from '@material-ui/core/TableFooter';
import TableHead from '@material-ui/core/TableHead'; import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow'; import TableRow from '@material-ui/core/TableRow';
import Box from '@material-ui/core/Box'; import Box from '@material-ui/core/Box';
import EditIcon from '@material-ui/icons/Edit'; import EditIcon from '@material-ui/icons/Edit';
import DeleteIcon from '@material-ui/icons/Delete'; import DeleteIcon from '@material-ui/icons/Delete';
import CloseIcon from '@material-ui/icons/Close'; import CloseIcon from '@material-ui/icons/Close';
@ -25,22 +23,12 @@ import UserForm from './UserForm';
import { withAuthenticationContext } from '../authentication/Context'; import { withAuthenticationContext } from '../authentication/Context';
const styles = theme => ({ const styles = theme => ({
loadingSettings: {
margin: theme.spacing(0.5),
},
loadingSettingsDetails: {
margin: theme.spacing(4),
textAlign: "center"
},
button: { button: {
marginRight: theme.spacing(2), marginRight: theme.spacing(2),
marginTop: theme.spacing(2), marginTop: theme.spacing(2),
}, },
table: { table: {
'& td, & th': { padding: theme.spacing(0.5) } '& td, & th': { padding: theme.spacing(0.5) }
},
actions: {
whiteSpace: "nowrap"
} }
}); });
@ -134,98 +122,80 @@ class ManageUsersForm extends React.Component {
} }
render() { render() {
const { classes, userData, userDataFetched, errorMessage, onReset } = this.props; const { classes, userData, onReset } = this.props;
const { user, creating } = this.state; const { user, creating } = this.state;
return ( return (
!userDataFetched ? <Fragment>
<div className={classes.loadingSettings}> <ValidatorForm onSubmit={this.onSubmit}>
<LinearProgress className={classes.loadingSettingsDetails} /> <Table className={classes.table}>
<Typography variant="h4" className={classes.loadingSettingsDetails}> <TableHead>
Loading... <TableRow>
</Typography> <TableCell>Username</TableCell>
</div> <TableCell align="center">Admin?</TableCell>
: <TableCell />
userData ? </TableRow>
<Fragment> </TableHead>
<ValidatorForm onSubmit={this.onSubmit}> <TableBody>
<Table className={classes.table}> {userData.users.sort(compareUsers).map(user => (
<TableHead> <TableRow key={user.username}>
<TableRow> <TableCell component="th" scope="row">
<TableCell>Username</TableCell> {user.username}
<TableCell align="center">Admin?</TableCell> </TableCell>
<TableCell /> <TableCell align="center">
</TableRow> {
</TableHead> user.admin ? <CheckIcon /> : <CloseIcon />
<TableBody> }
{userData.users.sort(compareUsers).map(user => ( </TableCell>
<TableRow key={user.username}> <TableCell align="center">
<TableCell component="th" scope="row"> <IconButton aria-label="Delete" onClick={() => this.removeUser(user)}>
{user.username} <DeleteIcon />
</TableCell> </IconButton>
<TableCell align="center"> <IconButton aria-label="Edit" onClick={() => this.startEditingUser(user)}>
{ <EditIcon />
user.admin ? <CheckIcon /> : <CloseIcon /> </IconButton>
} </TableCell>
</TableCell> </TableRow>
<TableCell align="center"> ))}
<IconButton aria-label="Delete" onClick={() => this.removeUser(user)}> </TableBody>
<DeleteIcon /> <TableFooter>
</IconButton> <TableRow>
<IconButton aria-label="Edit" onClick={() => this.startEditingUser(user)}> <TableCell colSpan={2} />
<EditIcon /> <TableCell align="center">
</IconButton> <Button variant="contained" color="secondary" onClick={this.createUser}>
</TableCell> Add User
</TableRow> </Button>
))} </TableCell>
</TableBody> </TableRow>
<TableFooter> </TableFooter>
<TableRow> </Table>
<TableCell colSpan={2} /> {
<TableCell align="center"> this.noAdminConfigured() &&
<Button variant="contained" color="secondary" onClick={this.createUser}> <Typography component="div" variant="body1">
Add User <Box bgcolor="error.main" color="error.contrastText" p={2} mt={2} mb={2}>
</Button> You must have at least one admin user configured.
</TableCell> </Box>
</TableRow>
</TableFooter>
</Table>
{
this.noAdminConfigured() &&
<Typography component="div" variant="body1">
<Box bgcolor="error.main" color="error.contrastText" p={2} mt={2} mb={2}>
You must have at least one admin user configured.
</Box>
</Typography>
}
<Button variant="contained" color="primary" className={classes.button} type="submit" disabled={this.noAdminConfigured()}>
Save
</Button>
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
Reset
</Button>
</ValidatorForm>
{
user &&
<UserForm
user={user}
creating={creating}
onDoneEditing={this.doneEditingUser}
onCancelEditing={this.cancelEditingUser}
handleValueChange={this.handleUserValueChange}
handleCheckboxChange={this.handleUserCheckboxChange}
uniqueUsername={this.uniqueUsername}
/>
}
</Fragment>
:
<div className={classes.loadingSettings}>
<Typography variant="h4" className={classes.loadingSettingsDetails}>
{errorMessage}
</Typography> </Typography>
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}> }
Reset <Button variant="contained" color="primary" className={classes.button} type="submit" disabled={this.noAdminConfigured()}>
</Button> Save
</div> </Button>
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
Reset
</Button>
</ValidatorForm>
{
user &&
<UserForm
user={user}
creating={creating}
onDoneEditing={this.doneEditingUser}
onCancelEditing={this.cancelEditingUser}
handleValueChange={this.handleUserValueChange}
handleCheckboxChange={this.handleUserCheckboxChange}
uniqueUsername={this.uniqueUsername}
/>
}
</Fragment>
); );
} }
@ -234,8 +204,6 @@ class ManageUsersForm extends React.Component {
ManageUsersForm.propTypes = { ManageUsersForm.propTypes = {
classes: PropTypes.object.isRequired, classes: PropTypes.object.isRequired,
userData: PropTypes.object, userData: PropTypes.object,
userDataFetched: PropTypes.bool.isRequired,
errorMessage: PropTypes.string,
onSubmit: PropTypes.func.isRequired, onSubmit: PropTypes.func.isRequired,
onReset: PropTypes.func.isRequired, onReset: PropTypes.func.isRequired,
setData: PropTypes.func.isRequired, setData: PropTypes.func.isRequired,

View File

@ -1,24 +1,15 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
import LinearProgress from '@material-ui/core/LinearProgress';
import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator';
import Typography from '@material-ui/core/Typography';
import isIP from '../validators/isIP'; import isIP from '../validators/isIP';
import isHostname from '../validators/isHostname'; import isHostname from '../validators/isHostname';
import or from '../validators/or'; import or from '../validators/or';
const styles = theme => ({ const styles = theme => ({
loadingSettings: {
margin: theme.spacing(0.5),
},
loadingSettingsDetails: {
margin: theme.spacing(4),
textAlign: "center"
},
textField: { textField: {
width: "100%" width: "100%"
}, },
@ -35,76 +26,44 @@ class NTPSettingsForm extends React.Component {
} }
render() { render() {
const { classes, ntpSettingsFetched, ntpSettings, errorMessage, handleValueChange, onSubmit, onReset } = this.props; const { classes, ntpSettings, handleValueChange, onSubmit, onReset } = this.props;
return ( return (
<div> <ValidatorForm onSubmit={onSubmit}>
{ <TextValidator
!ntpSettingsFetched ? validators={['required', 'isIPOrHostname']}
errorMessages={['Server is required', "Not a valid IP address or hostname"]}
<div className={classes.loadingSettings}> name="server"
<LinearProgress className={classes.loadingSettingsDetails}/> label="Server"
<Typography variant="h4" className={classes.loadingSettingsDetails}> className={classes.textField}
Loading... value={ntpSettings.server}
</Typography> onChange={handleValueChange('server')}
</div> margin="normal"
/>
: ntpSettings ? <TextValidator
validators={['required', 'isNumber', 'minNumber:60', 'maxNumber:86400']}
<ValidatorForm onSubmit={onSubmit}> errorMessages={['Interval is required', 'Interval must be a number', 'Must be at least 60 seconds', "Must not be more than 86400 seconds (24 hours)"]}
name="interval"
<TextValidator label="Interval (Seconds)"
validators={['required', 'isIPOrHostname']} className={classes.textField}
errorMessages={['Server is required', "Not a valid IP address or hostname"]} value={ntpSettings.interval}
name="server" type="number"
label="Server" onChange={handleValueChange('interval')}
className={classes.textField} margin="normal"
value={ntpSettings.server} />
onChange={handleValueChange('server')} <Button variant="contained" color="primary" className={classes.button} type="submit">
margin="normal" Save
/> </Button>
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
<TextValidator Reset
validators={['required','isNumber','minNumber:60','maxNumber:86400']} </Button>
errorMessages={['Interval is required','Interval must be a number','Must be at least 60 seconds',"Must not be more than 86400 seconds (24 hours)"]} </ValidatorForm>
name="interval"
label="Interval (Seconds)"
className={classes.textField}
value={ntpSettings.interval}
type="number"
onChange={handleValueChange('interval')}
margin="normal"
/>
<Button variant="contained" color="primary" className={classes.button} type="submit">
Save
</Button>
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
Reset
</Button>
</ValidatorForm>
:
<div className={classes.loadingSettings}>
<Typography variant="h4" className={classes.loadingSettingsDetails}>
{errorMessage}
</Typography>
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
Reset
</Button>
</div>
}
</div>
); );
} }
} }
NTPSettingsForm.propTypes = { NTPSettingsForm.propTypes = {
classes: PropTypes.object.isRequired, classes: PropTypes.object.isRequired,
ntpSettingsFetched: PropTypes.bool.isRequired,
ntpSettings: PropTypes.object, ntpSettings: PropTypes.object,
errorMessage: PropTypes.string,
onSubmit: PropTypes.func.isRequired, onSubmit: PropTypes.func.isRequired,
onReset: PropTypes.func.isRequired, onReset: PropTypes.func.isRequired,
handleValueChange: PropTypes.func.isRequired, handleValueChange: PropTypes.func.isRequired,

View File

@ -4,9 +4,7 @@ import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
import Switch from '@material-ui/core/Switch'; import Switch from '@material-ui/core/Switch';
import LinearProgress from '@material-ui/core/LinearProgress';
import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator'; import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator';
import Typography from '@material-ui/core/Typography';
import FormControlLabel from '@material-ui/core/FormControlLabel'; import FormControlLabel from '@material-ui/core/FormControlLabel';
import isIP from '../validators/isIP'; import isIP from '../validators/isIP';
@ -15,13 +13,6 @@ import or from '../validators/or';
import PasswordValidator from '../components/PasswordValidator'; import PasswordValidator from '../components/PasswordValidator';
const styles = theme => ({ const styles = theme => ({
loadingSettings: {
margin: theme.spacing(0.5),
},
loadingSettingsDetails: {
margin: theme.spacing(4),
textAlign: "center"
},
switchControl: { switchControl: {
width: "100%", width: "100%",
marginTop: theme.spacing(2), marginTop: theme.spacing(2),
@ -43,88 +34,55 @@ class OTASettingsForm extends React.Component {
} }
render() { render() {
const { classes, otaSettingsFetched, otaSettings, errorMessage, handleValueChange, handleCheckboxChange, onSubmit, onReset } = this.props; const { classes, otaSettings, handleValueChange, handleCheckboxChange, onSubmit, onReset } = this.props;
return ( return (
<div> <ValidatorForm onSubmit={onSubmit}>
{ <FormControlLabel className={classes.switchControl}
!otaSettingsFetched ? control={
<Switch
<div className={classes.loadingSettings}> checked={otaSettings.enabled}
<LinearProgress className={classes.loadingSettingsDetails}/> onChange={handleCheckboxChange('enabled')}
<Typography variant="h4" className={classes.loadingSettingsDetails}> value="enabled"
Loading... color="primary"
</Typography> />
</div> }
label="Enable OTA Updates?"
: otaSettings ? />
<TextValidator
<ValidatorForm onSubmit={onSubmit}> validators={['required', 'isNumber', 'minNumber:1025', 'maxNumber:65535']}
errorMessages={['Port is required', "Must be a number", "Must be greater than 1024 ", "Max value is 65535"]}
<FormControlLabel className={classes.switchControl} name="port"
control={ label="Port"
<Switch className={classes.textField}
checked={otaSettings.enabled} value={otaSettings.port}
onChange={handleCheckboxChange('enabled')} type="number"
value="enabled" onChange={handleValueChange('port')}
color="primary" margin="normal"
/> />
} <PasswordValidator
label="Enable OTA Updates?" validators={['required', 'matchRegexp:^.{1,64}$']}
/> errorMessages={['OTA Password is required', 'OTA Point Password must be 64 characters or less']}
name="password"
<TextValidator label="Password"
validators={['required', 'isNumber', 'minNumber:1025', 'maxNumber:65535']} className={classes.textField}
errorMessages={['Port is required', "Must be a number", "Must be greater than 1024 ", "Max value is 65535"]} value={otaSettings.password}
name="port" onChange={handleValueChange('password')}
label="Port" margin="normal"
className={classes.textField} />
value={otaSettings.port} <Button variant="contained" color="primary" className={classes.button} type="submit">
type="number" Save
onChange={handleValueChange('port')} </Button>
margin="normal" <Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
/> Reset
</Button>
<PasswordValidator </ValidatorForm>
validators={['required', 'matchRegexp:^.{1,64}$']}
errorMessages={['OTA Password is required', 'OTA Point Password must be 64 characters or less']}
name="password"
label="Password"
className={classes.textField}
value={otaSettings.password}
onChange={handleValueChange('password')}
margin="normal"
/>
<Button variant="contained" color="primary" className={classes.button} type="submit">
Save
</Button>
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
Reset
</Button>
</ValidatorForm>
:
<div className={classes.loadingSettings}>
<Typography variant="h4" className={classes.loadingSettingsDetails}>
{errorMessage}
</Typography>
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
Reset
</Button>
</div>
}
</div>
); );
} }
} }
OTASettingsForm.propTypes = { OTASettingsForm.propTypes = {
classes: PropTypes.object.isRequired, classes: PropTypes.object.isRequired,
otaSettingsFetched: PropTypes.bool.isRequired,
otaSettings: PropTypes.object, otaSettings: PropTypes.object,
errorMessage: PropTypes.string,
onSubmit: PropTypes.func.isRequired, onSubmit: PropTypes.func.isRequired,
onReset: PropTypes.func.isRequired, onReset: PropTypes.func.isRequired,
handleValueChange: PropTypes.func.isRequired, handleValueChange: PropTypes.func.isRequired,

View File

@ -4,7 +4,6 @@ import { ValidatorForm } from 'react-material-ui-form-validator';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
import LinearProgress from '@material-ui/core/LinearProgress';
import Typography from '@material-ui/core/Typography'; import Typography from '@material-ui/core/Typography';
import Box from '@material-ui/core/Box'; import Box from '@material-ui/core/Box';
@ -12,13 +11,6 @@ import PasswordValidator from '../components/PasswordValidator';
import { withAuthenticationContext } from '../authentication/Context'; import { withAuthenticationContext } from '../authentication/Context';
const styles = theme => ({ const styles = theme => ({
loadingSettings: {
margin: theme.spacing(0.5),
},
loadingSettingsDetails: {
margin: theme.spacing(4),
textAlign: "center"
},
textField: { textField: {
width: "100%" width: "100%"
}, },
@ -36,58 +28,38 @@ class SecuritySettingsForm extends React.Component {
} }
render() { render() {
const { classes, securitySettingsFetched, securitySettings, errorMessage, handleValueChange, onReset } = this.props; const { classes, securitySettings, handleValueChange, onReset } = this.props;
return ( return (
!securitySettingsFetched ? <ValidatorForm onSubmit={this.onSubmit} ref="SecuritySettingsForm">
<div className={classes.loadingSettings}> <PasswordValidator
<LinearProgress className={classes.loadingSettingsDetails} /> validators={['required', 'matchRegexp:^.{1,64}$']}
<Typography variant="h4" className={classes.loadingSettingsDetails}> errorMessages={['JWT Secret Required', 'JWT Secret must be 64 characters or less']}
Loading... name="jwt_secret"
</Typography> label="JWT Secret"
</div> className={classes.textField}
: value={securitySettings.jwt_secret}
securitySettings ? onChange={handleValueChange('jwt_secret')}
<ValidatorForm onSubmit={this.onSubmit} ref="SecuritySettingsForm"> margin="normal"
<PasswordValidator />
validators={['required', 'matchRegexp:^.{1,64}$']} <Typography component="div" variant="body1">
errorMessages={['JWT Secret Required', 'JWT Secret must be 64 characters or less']} <Box bgcolor="primary.main" color="primary.contrastText" p={2} mt={2} mb={2}>
name="jwt_secret" If you modify the JWT Secret, all users will be logged out.
label="JWT Secret" </Box>
className={classes.textField} </Typography>
value={securitySettings.jwt_secret} <Button variant="contained" color="primary" className={classes.button} type="submit">
onChange={handleValueChange('jwt_secret')} Save
margin="normal" </Button>
/> <Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
<Typography component="div" variant="body1"> Reset
<Box bgcolor="primary.main" color="primary.contrastText" p={2} mt={2} mb={2}> </Button>
If you modify the JWT Secret, all users will be logged out. </ValidatorForm>
</Box>
</Typography>
<Button variant="contained" color="primary" className={classes.button} type="submit">
Save
</Button>
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
Reset
</Button>
</ValidatorForm>
:
<div className={classes.loadingSettings}>
<Typography variant="h4" className={classes.loadingSettingsDetails}>
{errorMessage}
</Typography>
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
Reset
</Button>
</div>
); );
} }
} }
SecuritySettingsForm.propTypes = { SecuritySettingsForm.propTypes = {
classes: PropTypes.object.isRequired, classes: PropTypes.object.isRequired,
securitySettingsFetched: PropTypes.bool.isRequired,
securitySettings: PropTypes.object, securitySettings: PropTypes.object,
errorMessage: PropTypes.string,
onSubmit: PropTypes.func.isRequired, onSubmit: PropTypes.func.isRequired,
onReset: PropTypes.func.isRequired, onReset: PropTypes.func.isRequired,
handleValueChange: PropTypes.func.isRequired, handleValueChange: PropTypes.func.isRequired,

View File

@ -3,10 +3,8 @@ import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
import LinearProgress from '@material-ui/core/LinearProgress';
import Checkbox from '@material-ui/core/Checkbox'; import Checkbox from '@material-ui/core/Checkbox';
import FormControlLabel from '@material-ui/core/FormControlLabel'; import FormControlLabel from '@material-ui/core/FormControlLabel';
import Typography from '@material-ui/core/Typography';
import List from '@material-ui/core/List'; import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem'; import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText'; import ListItemText from '@material-ui/core/ListItemText';
@ -80,157 +78,124 @@ class WiFiSettingsForm extends React.Component {
} }
render() { render() {
const { classes, wifiSettingsFetched, wifiSettings, errorMessage, selectedNetwork, handleValueChange, handleCheckboxChange, onSubmit, onReset } = this.props; const { classes, wifiSettings, selectedNetwork, handleValueChange, handleCheckboxChange, onSubmit, onReset } = this.props;
return ( return (
<div> <ValidatorForm onSubmit={onSubmit} ref="WiFiSettingsForm">
{ {
!wifiSettingsFetched ? selectedNetwork ? this.renderSelectedNetwork() :
<TextValidator
<div className={classes.loadingSettings}> validators={['matchRegexp:^.{0,32}$']}
<LinearProgress className={classes.loadingSettingsDetails} /> errorMessages={['SSID must be 32 characters or less']}
<Typography variant="h4" className={classes.loadingSettingsDetails}> name="ssid"
Loading... label="SSID"
</Typography> className={classes.textField}
</div> value={wifiSettings.ssid}
onChange={handleValueChange('ssid')}
: wifiSettings ? margin="normal"
/>
<ValidatorForm onSubmit={onSubmit} ref="WiFiSettingsForm">
{
selectedNetwork ? this.renderSelectedNetwork() :
<TextValidator
validators={['matchRegexp:^.{0,32}$']}
errorMessages={['SSID must be 32 characters or less']}
name="ssid"
label="SSID"
className={classes.textField}
value={wifiSettings.ssid}
onChange={handleValueChange('ssid')}
margin="normal"
/>
}
{
!isNetworkOpen(selectedNetwork) &&
<PasswordValidator
validators={['matchRegexp:^.{0,64}$']}
errorMessages={['Password must be 64 characters or less']}
name="password"
label="Password"
className={classes.textField}
value={wifiSettings.password}
onChange={handleValueChange('password')}
margin="normal"
/>
}
<TextValidator
validators={['required', 'isHostname']}
errorMessages={['Hostname is required', "Not a valid hostname"]}
name="hostname"
label="Hostname"
className={classes.textField}
value={wifiSettings.hostname}
onChange={handleValueChange('hostname')}
margin="normal"
/>
<FormControlLabel className={classes.checkboxControl}
control={
<Checkbox
value="static_ip_config"
checked={wifiSettings.static_ip_config}
onChange={handleCheckboxChange("static_ip_config")}
/>
}
label="Static IP Config?"
/>
{
wifiSettings.static_ip_config &&
<Fragment>
<TextValidator
validators={['required', 'isIP']}
errorMessages={['Local IP is required', 'Must be an IP address']}
name="local_ip"
label="Local IP"
className={classes.textField}
value={wifiSettings.local_ip}
onChange={handleValueChange('local_ip')}
margin="normal"
/>
<TextValidator
validators={['required', 'isIP']}
errorMessages={['Gateway IP is required', 'Must be an IP address']}
name="gateway_ip"
label="Gateway"
className={classes.textField}
value={wifiSettings.gateway_ip}
onChange={handleValueChange('gateway_ip')}
margin="normal"
/>
<TextValidator
validators={['required', 'isIP']}
errorMessages={['Subnet mask is required', 'Must be an IP address']}
name="subnet_mask"
label="Subnet"
className={classes.textField}
value={wifiSettings.subnet_mask}
onChange={handleValueChange('subnet_mask')}
margin="normal"
/>
<TextValidator
validators={['isOptionalIP']}
errorMessages={['Must be an IP address']}
name="dns_ip_1"
label="DNS IP #1"
className={classes.textField}
value={wifiSettings.dns_ip_1}
onChange={handleValueChange('dns_ip_1')}
margin="normal"
/>
<TextValidator
validators={['isOptionalIP']}
errorMessages={['Must be an IP address']}
name="dns_ip_2"
label="DNS IP #2"
className={classes.textField}
value={wifiSettings.dns_ip_2}
onChange={handleValueChange('dns_ip_2')}
margin="normal"
/>
</Fragment>
}
<Button variant="contained" color="primary" className={classes.button} type="submit">
Save
</Button>
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
Reset
</Button>
</ValidatorForm>
:
<div className={classes.loadingSettings}>
<Typography variant="h4" className={classes.loadingSettingsDetails}>
{errorMessage}
</Typography>
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
Reset
</Button>
</div>
} }
</div> {
!isNetworkOpen(selectedNetwork) &&
<PasswordValidator
validators={['matchRegexp:^.{0,64}$']}
errorMessages={['Password must be 64 characters or less']}
name="password"
label="Password"
className={classes.textField}
value={wifiSettings.password}
onChange={handleValueChange('password')}
margin="normal"
/>
}
<TextValidator
validators={['required', 'isHostname']}
errorMessages={['Hostname is required', "Not a valid hostname"]}
name="hostname"
label="Hostname"
className={classes.textField}
value={wifiSettings.hostname}
onChange={handleValueChange('hostname')}
margin="normal"
/>
<FormControlLabel className={classes.checkboxControl}
control={
<Checkbox
value="static_ip_config"
checked={wifiSettings.static_ip_config}
onChange={handleCheckboxChange("static_ip_config")}
/>
}
label="Static IP Config?"
/>
{
wifiSettings.static_ip_config &&
<Fragment>
<TextValidator
validators={['required', 'isIP']}
errorMessages={['Local IP is required', 'Must be an IP address']}
name="local_ip"
label="Local IP"
className={classes.textField}
value={wifiSettings.local_ip}
onChange={handleValueChange('local_ip')}
margin="normal"
/>
<TextValidator
validators={['required', 'isIP']}
errorMessages={['Gateway IP is required', 'Must be an IP address']}
name="gateway_ip"
label="Gateway"
className={classes.textField}
value={wifiSettings.gateway_ip}
onChange={handleValueChange('gateway_ip')}
margin="normal"
/>
<TextValidator
validators={['required', 'isIP']}
errorMessages={['Subnet mask is required', 'Must be an IP address']}
name="subnet_mask"
label="Subnet"
className={classes.textField}
value={wifiSettings.subnet_mask}
onChange={handleValueChange('subnet_mask')}
margin="normal"
/>
<TextValidator
validators={['isOptionalIP']}
errorMessages={['Must be an IP address']}
name="dns_ip_1"
label="DNS IP #1"
className={classes.textField}
value={wifiSettings.dns_ip_1}
onChange={handleValueChange('dns_ip_1')}
margin="normal"
/>
<TextValidator
validators={['isOptionalIP']}
errorMessages={['Must be an IP address']}
name="dns_ip_2"
label="DNS IP #2"
className={classes.textField}
value={wifiSettings.dns_ip_2}
onChange={handleValueChange('dns_ip_2')}
margin="normal"
/>
</Fragment>
}
<Button variant="contained" color="primary" className={classes.button} type="submit">
Save
</Button>
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
Reset
</Button>
</ValidatorForm>
); );
} }
} }
WiFiSettingsForm.propTypes = { WiFiSettingsForm.propTypes = {
classes: PropTypes.object.isRequired, classes: PropTypes.object.isRequired,
wifiSettingsFetched: PropTypes.bool.isRequired,
wifiSettings: PropTypes.object, wifiSettings: PropTypes.object,
errorMessage: PropTypes.string,
deselectNetwork: PropTypes.func, deselectNetwork: PropTypes.func,
selectedNetwork: PropTypes.object, selectedNetwork: PropTypes.object,
onSubmit: PropTypes.func.isRequired, onSubmit: PropTypes.func.isRequired,