Browse Source

reduce use of ternaries in form code

master
Rick Watson 5 years ago
parent
commit
ff85c2e661
  1. 10
      interface/src/components/RestComponent.js
  2. 24
      interface/src/containers/APSettings.js
  3. 36
      interface/src/containers/APStatus.js
  4. 26
      interface/src/containers/ManageUsers.js
  5. 28
      interface/src/containers/NTPSettings.js
  6. 38
      interface/src/containers/NTPStatus.js
  7. 30
      interface/src/containers/OTASettings.js
  8. 18
      interface/src/containers/SecuritySettings.js
  9. 38
      interface/src/containers/SystemStatus.js
  10. 2
      interface/src/containers/WiFiNetworkScanner.js
  11. 38
      interface/src/containers/WiFiSettings.js
  12. 40
      interface/src/containers/WiFiStatus.js
  13. 130
      interface/src/forms/APSettingsForm.js
  14. 174
      interface/src/forms/ManageUsersForm.js
  15. 103
      interface/src/forms/NTPSettingsForm.js
  16. 124
      interface/src/forms/OTASettingsForm.js
  17. 76
      interface/src/forms/SecuritySettingsForm.js
  18. 251
      interface/src/forms/WiFiSettingsForm.js

10
interface/src/components/RestComponent.js

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

24
interface/src/containers/APSettings.js

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

36
interface/src/containers/APStatus.js

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

26
interface/src/containers/ManageUsers.js

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

28
interface/src/containers/NTPSettings.js

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

38
interface/src/containers/NTPStatus.js

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

30
interface/src/containers/OTASettings.js

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

18
interface/src/containers/SecuritySettings.js

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

38
interface/src/containers/SystemStatus.js

@ -2,8 +2,6 @@ import React, { Component, Fragment } from 'react';
import { withStyles } from '@material-ui/core/styles';
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 ListItem from '@material-ui/core/ListItem';
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 DataUsageIcon from '@material-ui/icons/DataUsage';
import { SYSTEM_STATUS_ENDPOINT } from '../constants/Endpoints';
import { restComponent } from '../components/RestComponent';
import LoadingNotification from '../components/LoadingNotification';
import SectionContent from '../components/SectionContent';
const styles = theme => ({
fetching: {
margin: theme.spacing(4),
textAlign: "center"
},
button: {
marginRight: theme.spacing(2),
marginTop: theme.spacing(2),
@ -85,7 +79,7 @@ class SystemStatus extends Component {
</ListItemAvatar>
<ListItemText primary="Flash Chip Size" secondary={data.flash_chip_size + ' bytes'} />
</ListItem>
<Divider variant="inset" component="li" />
<Divider variant="inset" component="li" />
</Fragment>
);
}
@ -104,29 +98,15 @@ class SystemStatus extends Component {
}
render() {
const { data, fetched, errorMessage, classes } = this.props;
const { data, fetched, errorMessage, loadData, classes } = this.props;
return (
<SectionContent title="System Status">
{
!fetched ?
<div>
<LinearProgress className={classes.fetching} />
<Typography variant="h4" className={classes.fetching}>
Loading...
</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>
}
<LoadingNotification
onReset={loadData}
fetched={fetched}
errorMessage={errorMessage}>
{this.renderNTPStatus(data, classes)}
</LoadingNotification>
</SectionContent>
)
}

2
interface/src/containers/WiFiNetworkScanner.js

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

38
interface/src/containers/WiFiSettings.js

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

40
interface/src/containers/WiFiStatus.js

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

130
interface/src/forms/APSettingsForm.js

@ -1,29 +1,19 @@
import React, { Fragment } from 'react';
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 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 { TextValidator, ValidatorForm, SelectValidator } from 'react-material-ui-form-validator';
import {isAPEnabled} from '../constants/WiFiAPModes';
import PasswordValidator from '../components/PasswordValidator';
const styles = theme => ({
loadingSettings: {
margin: theme.spacing(0.5),
},
loadingSettingsDetails: {
margin: theme.spacing(4),
textAlign: "center"
},
textField: {
width: "100%"
},
selectField:{
selectField: {
width: "100%",
marginTop: theme.spacing(2),
marginBottom: theme.spacing(0.5)
@ -37,86 +27,54 @@ const styles = theme => ({
class APSettingsForm extends React.Component {
render() {
const { classes, apSettingsFetched, apSettings, errorMessage, handleValueChange, onSubmit, onReset } = this.props;
const { classes, apSettings, handleValueChange, onSubmit, onReset } = this.props;
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 ?
<div className={classes.loadingSettings}>
<LinearProgress className={classes.loadingSettingsDetails}/>
<Typography variant="h4" className={classes.loadingSettingsDetails}>
Loading...
</Typography>
</div>
: apSettings ?
<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>
{
isAPEnabled(apSettings.provision_mode) &&
<Fragment>
<TextValidator
validators={['required', 'matchRegexp:^.{1,32}$']}
errorMessages={['Access Point SSID is required', 'Access Point SSID must be 32 characters or less']}
name="ssid"
label="Access Point SSID"
className={classes.textField}
value={apSettings.ssid}
onChange={handleValueChange('ssid')}
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>
isAPEnabled(apSettings.provision_mode) &&
<Fragment>
<TextValidator
validators={['required', 'matchRegexp:^.{1,32}$']}
errorMessages={['Access Point SSID is required', 'Access Point SSID must be 32 characters or less']}
name="ssid"
label="Access Point SSID"
className={classes.textField}
value={apSettings.ssid}
onChange={handleValueChange('ssid')}
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>
);
}
}
APSettingsForm.propTypes = {
classes: PropTypes.object.isRequired,
apSettingsFetched: PropTypes.bool.isRequired,
apSettings: PropTypes.object,
errorMessage: PropTypes.string,
onSubmit: PropTypes.func.isRequired,
onReset: PropTypes.func.isRequired,
handleValueChange: PropTypes.func.isRequired

174
interface/src/forms/ManageUsersForm.js

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

103
interface/src/forms/NTPSettingsForm.js

@ -1,24 +1,15 @@
import React from 'react';
import PropTypes from 'prop-types';
import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator';
import { withStyles } from '@material-ui/core/styles';
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 isHostname from '../validators/isHostname';
import or from '../validators/or';
const styles = theme => ({
loadingSettings: {
margin: theme.spacing(0.5),
},
loadingSettingsDetails: {
margin: theme.spacing(4),
textAlign: "center"
},
textField: {
width: "100%"
},
@ -35,76 +26,44 @@ class NTPSettingsForm extends React.Component {
}
render() {
const { classes, ntpSettingsFetched, ntpSettings, errorMessage, handleValueChange, onSubmit, onReset } = this.props;
const { classes, ntpSettings, handleValueChange, onSubmit, onReset } = this.props;
return (
<div>
{
!ntpSettingsFetched ?
<div className={classes.loadingSettings}>
<LinearProgress className={classes.loadingSettingsDetails}/>
<Typography variant="h4" className={classes.loadingSettingsDetails}>
Loading...
</Typography>
</div>
: ntpSettings ?
<ValidatorForm onSubmit={onSubmit}>
<TextValidator
validators={['required', 'isIPOrHostname']}
errorMessages={['Server is required', "Not a valid IP address or hostname"]}
name="server"
label="Server"
className={classes.textField}
value={ntpSettings.server}
onChange={handleValueChange('server')}
margin="normal"
/>
<TextValidator
validators={['required','isNumber','minNumber:60','maxNumber:86400']}
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"
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>
<ValidatorForm onSubmit={onSubmit}>
<TextValidator
validators={['required', 'isIPOrHostname']}
errorMessages={['Server is required', "Not a valid IP address or hostname"]}
name="server"
label="Server"
className={classes.textField}
value={ntpSettings.server}
onChange={handleValueChange('server')}
margin="normal"
/>
<TextValidator
validators={['required', 'isNumber', 'minNumber:60', 'maxNumber:86400']}
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"
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>
);
}
}
NTPSettingsForm.propTypes = {
classes: PropTypes.object.isRequired,
ntpSettingsFetched: PropTypes.bool.isRequired,
ntpSettings: PropTypes.object,
errorMessage: PropTypes.string,
onSubmit: PropTypes.func.isRequired,
onReset: PropTypes.func.isRequired,
handleValueChange: PropTypes.func.isRequired,

124
interface/src/forms/OTASettingsForm.js

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

76
interface/src/forms/SecuritySettingsForm.js

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

251
interface/src/forms/WiFiSettingsForm.js

@ -3,10 +3,8 @@ import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import LinearProgress from '@material-ui/core/LinearProgress';
import Checkbox from '@material-ui/core/Checkbox';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import Typography from '@material-ui/core/Typography';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
@ -80,157 +78,124 @@ class WiFiSettingsForm extends React.Component {
}
render() {
const { classes, wifiSettingsFetched, wifiSettings, errorMessage, selectedNetwork, handleValueChange, handleCheckboxChange, onSubmit, onReset } = this.props;
const { classes, wifiSettings, selectedNetwork, handleValueChange, handleCheckboxChange, onSubmit, onReset } = this.props;
return (
<div>
<ValidatorForm onSubmit={onSubmit} ref="WiFiSettingsForm">
{
!wifiSettingsFetched ?
<div className={classes.loadingSettings}>
<LinearProgress className={classes.loadingSettingsDetails} />
<Typography variant="h4" className={classes.loadingSettingsDetails}>
Loading...
</Typography>
</div>
: wifiSettings ?
<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>
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>
}
</div>
<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 = {
classes: PropTypes.object.isRequired,
wifiSettingsFetched: PropTypes.bool.isRequired,
wifiSettings: PropTypes.object,
errorMessage: PropTypes.string,
deselectNetwork: PropTypes.func,
selectedNetwork: PropTypes.object,
onSubmit: PropTypes.func.isRequired,

Loading…
Cancel
Save