This commit is contained in:
proddy
2021-05-14 12:45:57 +02:00
parent 15df0c0552
commit fec5ff3132
108 changed files with 3508 additions and 2455 deletions

View File

@@ -1,22 +1,31 @@
import React, { Component } from 'react';
import { Redirect, Switch, RouteComponentProps } from 'react-router-dom'
import { Component } from 'react';
import { Redirect, Switch, RouteComponentProps } from 'react-router-dom';
import { Tabs, Tab } from '@material-ui/core';
import { withAuthenticatedContext, AuthenticatedContextProps, AuthenticatedRoute } from '../authentication';
import {
withAuthenticatedContext,
AuthenticatedContextProps,
AuthenticatedRoute
} from '../authentication';
import { MenuAppBar } from '../components';
import NetworkStatusController from './NetworkStatusController';
import NetworkSettingsController from './NetworkSettingsController';
import WiFiNetworkScanner from './WiFiNetworkScanner';
import { NetworkConnectionContext, NetworkConnectionContextValue } from './NetworkConnectionContext';
import {
NetworkConnectionContext,
NetworkConnectionContextValue
} from './NetworkConnectionContext';
import { WiFiNetwork } from './types';
type NetworkConnectionProps = AuthenticatedContextProps & RouteComponentProps;
class NetworkConnection extends Component<NetworkConnectionProps, NetworkConnectionContextValue> {
class NetworkConnection extends Component<
NetworkConnectionProps,
NetworkConnectionContextValue
> {
constructor(props: NetworkConnectionProps) {
super(props);
this.state = {
@@ -28,13 +37,13 @@ class NetworkConnection extends Component<NetworkConnectionProps, NetworkConnect
selectNetwork = (network: WiFiNetwork) => {
this.setState({ selectedNetwork: network });
this.props.history.push('/network/settings');
}
};
deselectNetwork = () => {
this.setState({ selectedNetwork: undefined });
}
};
handleTabChange = (event: React.ChangeEvent<{}>, path: string) => {
handleTabChange = (path: string) => {
this.props.history.push(path);
};
@@ -43,20 +52,44 @@ class NetworkConnection extends Component<NetworkConnectionProps, NetworkConnect
return (
<NetworkConnectionContext.Provider value={this.state}>
<MenuAppBar sectionTitle="Network Connection">
<Tabs value={this.props.match.url} onChange={this.handleTabChange} variant="fullWidth">
<Tabs
value={this.props.match.url}
onChange={(e, path) => this.handleTabChange(path)}
variant="fullWidth"
>
<Tab value="/network/status" label="Network Status" />
<Tab value="/network/scan" label="Scan WiFi Networks" disabled={!authenticatedContext.me.admin} />
<Tab value="/network/settings" label="Network Settings" disabled={!authenticatedContext.me.admin} />
<Tab
value="/network/scan"
label="Scan WiFi Networks"
disabled={!authenticatedContext.me.admin}
/>
<Tab
value="/network/settings"
label="Network Settings"
disabled={!authenticatedContext.me.admin}
/>
</Tabs>
<Switch>
<AuthenticatedRoute exact path="/network/status" component={NetworkStatusController} />
<AuthenticatedRoute exact path="/network/scan" component={WiFiNetworkScanner} />
<AuthenticatedRoute exact path="/network/settings" component={NetworkSettingsController} />
<AuthenticatedRoute
exact
path="/network/status"
component={NetworkStatusController}
/>
<AuthenticatedRoute
exact
path="/network/scan"
component={WiFiNetworkScanner}
/>
<AuthenticatedRoute
exact
path="/network/settings"
component={NetworkSettingsController}
/>
<Redirect to="/network/status" />
</Switch>
</MenuAppBar>
</NetworkConnectionContext.Provider>
)
);
}
}

View File

@@ -7,7 +7,7 @@ export interface NetworkConnectionContextValue {
deselectNetwork: () => void;
}
const NetworkConnectionContextDefaultValue = {} as NetworkConnectionContextValue
const NetworkConnectionContextDefaultValue = {} as NetworkConnectionContextValue;
export const NetworkConnectionContext = React.createContext(
NetworkConnectionContextDefaultValue
);

View File

@@ -1,6 +1,11 @@
import React, { Component } from 'react';
import { Component } from 'react';
import { restController, RestControllerProps, RestFormLoader, SectionContent } from '../components';
import {
restController,
RestControllerProps,
RestFormLoader,
SectionContent
} from '../components';
import NetworkSettingsForm from './NetworkSettingsForm';
import { NETWORK_SETTINGS_ENDPOINT } from '../api';
import { NetworkSettings } from './types';
@@ -8,7 +13,6 @@ import { NetworkSettings } from './types';
type NetworkSettingsControllerProps = RestControllerProps<NetworkSettings>;
class NetworkSettingsController extends Component<NetworkSettingsControllerProps> {
componentDidMount() {
this.props.loadData();
}
@@ -18,12 +22,14 @@ class NetworkSettingsController extends Component<NetworkSettingsControllerProps
<SectionContent title="Network Settings">
<RestFormLoader
{...this.props}
render={formProps => <NetworkSettingsForm {...formProps} />}
render={(formProps) => <NetworkSettingsForm {...formProps} />}
/>
</SectionContent>
);
}
}
export default restController(NETWORK_SETTINGS_ENDPOINT, NetworkSettingsController);
export default restController(
NETWORK_SETTINGS_ENDPOINT,
NetworkSettingsController
);

View File

@@ -1,7 +1,14 @@
import React, { Fragment } from 'react';
import { TextValidator, ValidatorForm } from 'react-material-ui-form-validator';
import { Checkbox, List, ListItem, ListItemText, ListItemAvatar, ListItemSecondaryAction } from '@material-ui/core';
import {
Checkbox,
List,
ListItem,
ListItemText,
ListItemAvatar,
ListItemSecondaryAction
} from '@material-ui/core';
import Avatar from '@material-ui/core/Avatar';
import IconButton from '@material-ui/core/IconButton';
@@ -10,31 +17,42 @@ import LockOpenIcon from '@material-ui/icons/LockOpen';
import DeleteIcon from '@material-ui/icons/Delete';
import SaveIcon from '@material-ui/icons/Save';
import { RestFormProps, PasswordValidator, BlockFormControlLabel, FormActions, FormButton } from '../components';
import {
RestFormProps,
PasswordValidator,
BlockFormControlLabel,
FormActions,
FormButton
} from '../components';
import { isIP, isHostname, optional } from '../validators';
import { NetworkConnectionContext, NetworkConnectionContextValue } from './NetworkConnectionContext';
import {
NetworkConnectionContext,
NetworkConnectionContextValue
} from './NetworkConnectionContext';
import { isNetworkOpen, networkSecurityMode } from './WiFiSecurityModes';
import { NetworkSettings } from './types';
type NetworkStatusFormProps = RestFormProps<NetworkSettings>;
class NetworkSettingsForm extends React.Component<NetworkStatusFormProps> {
static contextType = NetworkConnectionContext;
context!: React.ContextType<typeof NetworkConnectionContext>;
constructor(props: NetworkStatusFormProps, context: NetworkConnectionContextValue) {
constructor(
props: NetworkStatusFormProps,
context: NetworkConnectionContextValue
) {
super(props);
const { selectedNetwork } = context;
if (selectedNetwork) {
const networkSettings: NetworkSettings = {
ssid: selectedNetwork.ssid,
password: "",
password: '',
hostname: props.data.hostname,
static_ip_config: false,
}
static_ip_config: false
};
props.setData(networkSettings);
}
}
@@ -48,7 +66,7 @@ class NetworkSettingsForm extends React.Component<NetworkStatusFormProps> {
deselectNetworkAndLoadData = () => {
this.context.deselectNetwork();
this.props.loadData();
}
};
componentWillUnmount() {
this.context.deselectNetwork();
@@ -59,41 +77,51 @@ class NetworkSettingsForm extends React.Component<NetworkStatusFormProps> {
const { data, handleValueChange, saveData } = this.props;
return (
<ValidatorForm onSubmit={saveData} ref="NetworkSettingsForm">
{
selectedNetwork ?
<List>
<ListItem>
<ListItemAvatar>
<Avatar>
{isNetworkOpen(selectedNetwork) ? <LockOpenIcon /> : <LockIcon />}
</Avatar>
</ListItemAvatar>
<ListItemText
primary={selectedNetwork.ssid}
secondary={"Security: " + networkSecurityMode(selectedNetwork) + ", Ch: " + selectedNetwork.channel}
/>
<ListItemSecondaryAction>
<IconButton aria-label="Manual Config" onClick={deselectNetwork}>
<DeleteIcon />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
</List>
:
<TextValidator
validators={['matchRegexp:^.{0,32}$']}
errorMessages={['SSID must be 32 characters or less']}
name="ssid"
label="SSID (leave blank to disable WiFi)"
fullWidth
variant="outlined"
value={data.ssid}
onChange={handleValueChange('ssid')}
margin="normal"
/>
}
{
(!selectedNetwork || !isNetworkOpen(selectedNetwork)) &&
{selectedNetwork ? (
<List>
<ListItem>
<ListItemAvatar>
<Avatar>
{isNetworkOpen(selectedNetwork) ? (
<LockOpenIcon />
) : (
<LockIcon />
)}
</Avatar>
</ListItemAvatar>
<ListItemText
primary={selectedNetwork.ssid}
secondary={
'Security: ' +
networkSecurityMode(selectedNetwork) +
', Ch: ' +
selectedNetwork.channel
}
/>
<ListItemSecondaryAction>
<IconButton
aria-label="Manual Config"
onClick={deselectNetwork}
>
<DeleteIcon />
</IconButton>
</ListItemSecondaryAction>
</ListItem>
</List>
) : (
<TextValidator
validators={['matchRegexp:^.{0,32}$']}
errorMessages={['SSID must be 32 characters or less']}
name="ssid"
label="SSID (leave blank to disable WiFi)"
fullWidth
variant="outlined"
value={data.ssid}
onChange={handleValueChange('ssid')}
margin="normal"
/>
)}
{(!selectedNetwork || !isNetworkOpen(selectedNetwork)) && (
<PasswordValidator
validators={['matchRegexp:^.{0,64}$']}
errorMessages={['Password must be 64 characters or less']}
@@ -105,10 +133,10 @@ class NetworkSettingsForm extends React.Component<NetworkStatusFormProps> {
onChange={handleValueChange('password')}
margin="normal"
/>
}
)}
<TextValidator
validators={['required', 'isHostname']}
errorMessages={['Hostname is required', "Not a valid hostname"]}
errorMessages={['Hostname is required', 'Not a valid hostname']}
name="hostname"
label="Hostname"
fullWidth
@@ -122,13 +150,12 @@ class NetworkSettingsForm extends React.Component<NetworkStatusFormProps> {
<Checkbox
value="static_ip_config"
checked={data.static_ip_config}
onChange={handleValueChange("static_ip_config")}
onChange={handleValueChange('static_ip_config')}
/>
}
label="Static IP Config"
/>
{
data.static_ip_config &&
{data.static_ip_config && (
<Fragment>
<TextValidator
validators={['required', 'isIP']}
@@ -154,7 +181,10 @@ class NetworkSettingsForm extends React.Component<NetworkStatusFormProps> {
/>
<TextValidator
validators={['required', 'isIP']}
errorMessages={['Subnet mask is required', 'Must be an IP address']}
errorMessages={[
'Subnet mask is required',
'Must be an IP address'
]}
name="subnet_mask"
label="Subnet"
fullWidth
@@ -186,9 +216,14 @@ class NetworkSettingsForm extends React.Component<NetworkStatusFormProps> {
margin="normal"
/>
</Fragment>
}
)}
<FormActions>
<FormButton startIcon={<SaveIcon />} variant="contained" color="primary" type="submit">
<FormButton
startIcon={<SaveIcon />}
variant="contained"
color="primary"
type="submit"
>
Save
</FormButton>
</FormActions>
@@ -197,4 +232,4 @@ class NetworkSettingsForm extends React.Component<NetworkStatusFormProps> {
}
}
export default NetworkSettingsForm;
export default NetworkSettingsForm;

View File

@@ -1,57 +1,57 @@
import { Theme } from '@material-ui/core'
import { NetworkStatus, NetworkConnectionStatus } from './types'
import { Theme } from '@material-ui/core';
import { NetworkStatus, NetworkConnectionStatus } from './types';
export const isConnected = ({ status }: NetworkStatus) => {
return (
status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED ||
status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED
)
}
);
};
export const isWiFi = ({ status }: NetworkStatus) =>
status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED
status === NetworkConnectionStatus.WIFI_STATUS_CONNECTED;
export const isEthernet = ({ status }: NetworkStatus) =>
status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED
status === NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED;
export const networkStatusHighlight = (
{ status }: NetworkStatus,
theme: Theme,
theme: Theme
) => {
switch (status) {
case NetworkConnectionStatus.WIFI_STATUS_IDLE:
case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED:
case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD:
return theme.palette.info.main
return theme.palette.info.main;
case NetworkConnectionStatus.WIFI_STATUS_CONNECTED:
case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED:
return theme.palette.success.main
return theme.palette.success.main;
case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED:
case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST:
return theme.palette.error.main
return theme.palette.error.main;
default:
return theme.palette.warning.main
return theme.palette.warning.main;
}
}
};
export const networkStatus = ({ status }: NetworkStatus) => {
switch (status) {
case NetworkConnectionStatus.WIFI_STATUS_NO_SHIELD:
return 'Inactive'
return 'Inactive';
case NetworkConnectionStatus.WIFI_STATUS_IDLE:
return 'Idle'
return 'Idle';
case NetworkConnectionStatus.WIFI_STATUS_NO_SSID_AVAIL:
return 'No SSID Available'
return 'No SSID Available';
case NetworkConnectionStatus.WIFI_STATUS_CONNECTED:
return 'Connected (WiFi)'
return 'Connected (WiFi)';
case NetworkConnectionStatus.ETHERNET_STATUS_CONNECTED:
return 'Connected (Ethernet)'
return 'Connected (Ethernet)';
case NetworkConnectionStatus.WIFI_STATUS_CONNECT_FAILED:
return 'Connection Failed'
return 'Connection Failed';
case NetworkConnectionStatus.WIFI_STATUS_CONNECTION_LOST:
return 'Connection Lost'
return 'Connection Lost';
case NetworkConnectionStatus.WIFI_STATUS_DISCONNECTED:
return 'Disconnected'
return 'Disconnected';
default:
return 'Unknown'
return 'Unknown';
}
}
};

View File

@@ -1,6 +1,11 @@
import React, { Component } from 'react';
import { Component } from 'react';
import { restController, RestControllerProps, RestFormLoader, SectionContent } from '../components';
import {
restController,
RestControllerProps,
RestFormLoader,
SectionContent
} from '../components';
import NetworkStatusForm from './NetworkStatusForm';
import { NETWORK_STATUS_ENDPOINT } from '../api';
import { NetworkStatus } from './types';
@@ -8,7 +13,6 @@ import { NetworkStatus } from './types';
type NetworkStatusControllerProps = RestControllerProps<NetworkStatus>;
class NetworkStatusController extends Component<NetworkStatusControllerProps> {
componentDidMount() {
this.props.loadData();
}
@@ -18,12 +22,11 @@ class NetworkStatusController extends Component<NetworkStatusControllerProps> {
<SectionContent title="Network Status">
<RestFormLoader
{...this.props}
render={formProps => <NetworkStatusForm {...formProps} />}
render={(formProps) => <NetworkStatusForm {...formProps} />}
/>
</SectionContent>
);
}
}
export default restController(NETWORK_STATUS_ENDPOINT, NetworkStatusController);

View File

@@ -1,46 +1,46 @@
import React, { Component, Fragment } from "react";
import { Component, Fragment } from 'react';
import { WithTheme, withTheme } from "@material-ui/core/styles";
import { WithTheme, withTheme } from '@material-ui/core/styles';
import {
Avatar,
Divider,
List,
ListItem,
ListItemAvatar,
ListItemText,
} from "@material-ui/core";
ListItemText
} from '@material-ui/core';
import DNSIcon from "@material-ui/icons/Dns";
import WifiIcon from "@material-ui/icons/Wifi";
import RouterIcon from "@material-ui/icons/Router";
import SettingsInputComponentIcon from "@material-ui/icons/SettingsInputComponent";
import SettingsInputAntennaIcon from "@material-ui/icons/SettingsInputAntenna";
import DeviceHubIcon from "@material-ui/icons/DeviceHub";
import RefreshIcon from "@material-ui/icons/Refresh";
import DNSIcon from '@material-ui/icons/Dns';
import WifiIcon from '@material-ui/icons/Wifi';
import RouterIcon from '@material-ui/icons/Router';
import SettingsInputComponentIcon from '@material-ui/icons/SettingsInputComponent';
import SettingsInputAntennaIcon from '@material-ui/icons/SettingsInputAntenna';
import DeviceHubIcon from '@material-ui/icons/DeviceHub';
import RefreshIcon from '@material-ui/icons/Refresh';
import {
RestFormProps,
FormActions,
FormButton,
HighlightAvatar,
} from "../components";
HighlightAvatar
} from '../components';
import {
networkStatus,
networkStatusHighlight,
isConnected,
isWiFi,
isEthernet,
} from "./NetworkStatus";
import { NetworkStatus } from "./types";
isEthernet
} from './NetworkStatus';
import { NetworkStatus } from './types';
type NetworkStatusFormProps = RestFormProps<NetworkStatus> & WithTheme;
class NetworkStatusForm extends Component<NetworkStatusFormProps> {
dnsServers(status: NetworkStatus) {
if (!status.dns_ip_1) {
return "none";
return 'none';
}
return status.dns_ip_1 + (status.dns_ip_2 ? "," + status.dns_ip_2 : "");
return status.dns_ip_1 + (status.dns_ip_2 ? ',' + status.dns_ip_2 : '');
}
createListItems() {
@@ -110,7 +110,7 @@ class NetworkStatusForm extends Component<NetworkStatusFormProps> {
</ListItemAvatar>
<ListItemText
primary="Gateway IP"
secondary={data.gateway_ip || "none"}
secondary={data.gateway_ip || 'none'}
/>
</ListItem>
<Divider variant="inset" component="li" />

View File

@@ -1,7 +1,14 @@
import React, { Component } from 'react';
import { Component } from 'react';
import { withSnackbar, WithSnackbarProps } from 'notistack';
import { createStyles, WithStyles, Theme, withStyles, Typography, LinearProgress } from '@material-ui/core';
import {
createStyles,
WithStyles,
Theme,
withStyles,
Typography,
LinearProgress
} from '@material-ui/core';
import PermScanWifiIcon from '@material-ui/icons/PermScanWifi';
import { FormActions, FormButton, SectionContent } from '../components';
@@ -11,9 +18,9 @@ import { SCAN_NETWORKS_ENDPOINT, LIST_NETWORKS_ENDPOINT } from '../api';
import WiFiNetworkSelector from './WiFiNetworkSelector';
import { WiFiNetworkList, WiFiNetwork } from './types';
const NUM_POLLS = 10
const POLLING_FREQUENCY = 500
const RETRY_EXCEPTION_TYPE = "retry"
const NUM_POLLS = 10;
const POLLING_FREQUENCY = 500;
const RETRY_EXCEPTION_TYPE = 'retry';
interface WiFiNetworkScannerState {
scanningForNetworks: boolean;
@@ -21,28 +28,31 @@ interface WiFiNetworkScannerState {
networkList?: WiFiNetworkList;
}
const styles = (theme: Theme) => createStyles({
scanningSettings: {
margin: theme.spacing(0.5),
},
scanningSettingsDetails: {
margin: theme.spacing(4),
textAlign: "center"
},
scanningProgress: {
margin: theme.spacing(4),
textAlign: "center"
}
});
const styles = (theme: Theme) =>
createStyles({
scanningSettings: {
margin: theme.spacing(0.5)
},
scanningSettingsDetails: {
margin: theme.spacing(4),
textAlign: 'center'
},
scanningProgress: {
margin: theme.spacing(4),
textAlign: 'center'
}
});
type WiFiNetworkScannerProps = WithSnackbarProps & WithStyles<typeof styles>;
class WiFiNetworkScanner extends Component<WiFiNetworkScannerProps, WiFiNetworkScannerState> {
pollCount: number = 0;
class WiFiNetworkScanner extends Component<
WiFiNetworkScannerProps,
WiFiNetworkScannerState
> {
pollCount = 0;
state: WiFiNetworkScannerState = {
scanningForNetworks: false,
scanningForNetworks: false
};
componentDidMount() {
@@ -54,23 +64,36 @@ class WiFiNetworkScanner extends Component<WiFiNetworkScannerProps, WiFiNetworkS
if (!scanningForNetworks) {
this.scanNetworks();
}
}
};
scanNetworks() {
this.pollCount = 0;
this.setState({ scanningForNetworks: true, networkList: undefined, errorMessage: undefined });
redirectingAuthorizedFetch(SCAN_NETWORKS_ENDPOINT).then(response => {
if (response.status === 202) {
this.schedulePollTimeout();
return;
}
throw Error("Scanning for networks returned unexpected response code: " + response.status);
}).catch(error => {
this.props.enqueueSnackbar("Problem scanning: " + error.message, {
variant: 'error',
});
this.setState({ scanningForNetworks: false, networkList: undefined, errorMessage: error.message });
this.setState({
scanningForNetworks: true,
networkList: undefined,
errorMessage: undefined
});
redirectingAuthorizedFetch(SCAN_NETWORKS_ENDPOINT)
.then((response) => {
if (response.status === 202) {
this.schedulePollTimeout();
return;
}
throw Error(
'Scanning for networks returned unexpected response code: ' +
response.status
);
})
.catch((error) => {
this.props.enqueueSnackbar('Problem scanning: ' + error.message, {
variant: 'error'
});
this.setState({
scanningForNetworks: false,
networkList: undefined,
errorMessage: error.message
});
});
}
schedulePollTimeout() {
@@ -80,21 +103,20 @@ class WiFiNetworkScanner extends Component<WiFiNetworkScannerProps, WiFiNetworkS
retryError() {
return {
name: RETRY_EXCEPTION_TYPE,
message: "Network list not ready, will retry in " + POLLING_FREQUENCY + "ms."
message:
'Network list not ready, will retry in ' + POLLING_FREQUENCY + 'ms.'
};
}
compareNetworks(network1: WiFiNetwork, network2: WiFiNetwork) {
if (network1.rssi < network2.rssi)
return 1;
if (network1.rssi > network2.rssi)
return -1;
if (network1.rssi < network2.rssi) return 1;
if (network1.rssi > network2.rssi) return -1;
return 0;
}
pollNetworkList = () => {
redirectingAuthorizedFetch(LIST_NETWORKS_ENDPOINT)
.then(response => {
.then((response) => {
if (response.status === 200) {
return response.json();
}
@@ -103,24 +125,34 @@ class WiFiNetworkScanner extends Component<WiFiNetworkScannerProps, WiFiNetworkS
this.schedulePollTimeout();
throw this.retryError();
} else {
throw Error("Device did not return network list in timely manner.");
throw Error('Device did not return network list in timely manner.');
}
}
throw Error("Device returned unexpected response code: " + response.status);
throw Error(
'Device returned unexpected response code: ' + response.status
);
})
.then(json => {
json.networks.sort(this.compareNetworks)
this.setState({ scanningForNetworks: false, networkList: json, errorMessage: undefined })
.then((json) => {
json.networks.sort(this.compareNetworks);
this.setState({
scanningForNetworks: false,
networkList: json,
errorMessage: undefined
});
})
.catch(error => {
.catch((error) => {
if (error.name !== RETRY_EXCEPTION_TYPE) {
this.props.enqueueSnackbar("Problem scanning: " + error.message, {
variant: 'error',
this.props.enqueueSnackbar('Problem scanning: ' + error.message, {
variant: 'error'
});
this.setState({
scanningForNetworks: false,
networkList: undefined,
errorMessage: error.message
});
this.setState({ scanningForNetworks: false, networkList: undefined, errorMessage: error.message });
}
});
}
};
renderNetworkScanner() {
const { classes } = this.props;
@@ -144,9 +176,7 @@ class WiFiNetworkScanner extends Component<WiFiNetworkScannerProps, WiFiNetworkS
</div>
);
}
return (
<WiFiNetworkSelector networkList={networkList} />
);
return <WiFiNetworkSelector networkList={networkList} />;
}
render() {
@@ -155,14 +185,19 @@ class WiFiNetworkScanner extends Component<WiFiNetworkScannerProps, WiFiNetworkS
<SectionContent title="Network Scanner">
{this.renderNetworkScanner()}
<FormActions>
<FormButton startIcon={<PermScanWifiIcon />} variant="contained" color="secondary" onClick={this.requestNetworkScan} disabled={scanningForNetworks}>
<FormButton
startIcon={<PermScanWifiIcon />}
variant="contained"
color="secondary"
onClick={this.requestNetworkScan}
disabled={scanningForNetworks}
>
Scan again&hellip;
</FormButton>
</FormActions>
</SectionContent>
);
}
}
export default withSnackbar(withStyles(styles)(WiFiNetworkScanner));

View File

@@ -1,7 +1,13 @@
import React, { Component } from 'react';
import { Avatar, Badge } from '@material-ui/core';
import { List, ListItem, ListItemIcon, ListItemText, ListItemAvatar } from '@material-ui/core';
import {
List,
ListItem,
ListItemIcon,
ListItemText,
ListItemAvatar
} from '@material-ui/core';
import WifiIcon from '@material-ui/icons/Wifi';
import LockIcon from '@material-ui/icons/Lock';
@@ -16,13 +22,16 @@ interface WiFiNetworkSelectorProps {
}
class WiFiNetworkSelector extends Component<WiFiNetworkSelectorProps> {
static contextType = NetworkConnectionContext;
context!: React.ContextType<typeof NetworkConnectionContext>;
renderNetwork = (network: WiFiNetwork) => {
return (
<ListItem key={network.bssid} button onClick={() => this.context.selectNetwork(network)}>
<ListItem
key={network.bssid}
button
onClick={() => this.context.selectNetwork(network)}
>
<ListItemAvatar>
<Avatar>
{isNetworkOpen(network) ? <LockOpenIcon /> : <LockIcon />}
@@ -30,25 +39,27 @@ class WiFiNetworkSelector extends Component<WiFiNetworkSelectorProps> {
</ListItemAvatar>
<ListItemText
primary={network.ssid}
secondary={"Security: " + networkSecurityMode(network) + ", Ch: " + network.channel}
secondary={
'Security: ' +
networkSecurityMode(network) +
', Ch: ' +
network.channel
}
/>
<ListItemIcon>
<Badge badgeContent={network.rssi + "db"}>
<Badge badgeContent={network.rssi + 'db'}>
<WifiIcon />
</Badge>
</ListItemIcon>
</ListItem>
);
}
};
render() {
return (
<List>
{this.props.networkList.networks.map(this.renderNetwork)}
</List>
<List>{this.props.networkList.networks.map(this.renderNetwork)}</List>
);
}
}
export default WiFiNetworkSelector;

View File

@@ -1,23 +1,23 @@
import { WiFiNetwork, WiFiEncryptionType } from './types'
import { WiFiNetwork, WiFiEncryptionType } from './types';
export const isNetworkOpen = ({ encryption_type }: WiFiNetwork) =>
encryption_type === WiFiEncryptionType.WIFI_AUTH_OPEN
encryption_type === WiFiEncryptionType.WIFI_AUTH_OPEN;
export const networkSecurityMode = ({ encryption_type }: WiFiNetwork) => {
switch (encryption_type) {
case WiFiEncryptionType.WIFI_AUTH_WEP:
return 'WEP'
return 'WEP';
case WiFiEncryptionType.WIFI_AUTH_WPA_PSK:
return 'WPA'
return 'WPA';
case WiFiEncryptionType.WIFI_AUTH_WPA2_PSK:
return 'WPA2'
return 'WPA2';
case WiFiEncryptionType.WIFI_AUTH_WPA_WPA2_PSK:
return 'WPA/WPA2'
return 'WPA/WPA2';
case WiFiEncryptionType.WIFI_AUTH_WPA2_ENTERPRISE:
return 'WPA2 Enterprise'
return 'WPA2 Enterprise';
case WiFiEncryptionType.WIFI_AUTH_OPEN:
return 'None'
return 'None';
default:
return 'Unknown'
return 'Unknown';
}
}
};

View File

@@ -6,7 +6,7 @@ export enum NetworkConnectionStatus {
WIFI_STATUS_CONNECTION_LOST = 5,
WIFI_STATUS_DISCONNECTED = 6,
ETHERNET_STATUS_CONNECTED = 10,
WIFI_STATUS_NO_SHIELD = 255,
WIFI_STATUS_NO_SHIELD = 255
}
export enum WiFiEncryptionType {
@@ -15,43 +15,43 @@ export enum WiFiEncryptionType {
WIFI_AUTH_WPA_PSK = 2,
WIFI_AUTH_WPA2_PSK = 3,
WIFI_AUTH_WPA_WPA2_PSK = 4,
WIFI_AUTH_WPA2_ENTERPRISE = 5,
WIFI_AUTH_WPA2_ENTERPRISE = 5
}
export interface NetworkStatus {
status: NetworkConnectionStatus
local_ip: string
mac_address: string
rssi: number
ssid: string
bssid: string
channel: number
subnet_mask: string
gateway_ip: string
dns_ip_1: string
dns_ip_2: string
status: NetworkConnectionStatus;
local_ip: string;
mac_address: string;
rssi: number;
ssid: string;
bssid: string;
channel: number;
subnet_mask: string;
gateway_ip: string;
dns_ip_1: string;
dns_ip_2: string;
}
export interface NetworkSettings {
ssid: string
password: string
hostname: string
static_ip_config: boolean
local_ip?: string
gateway_ip?: string
subnet_mask?: string
dns_ip_1?: string
dns_ip_2?: string
ssid: string;
password: string;
hostname: string;
static_ip_config: boolean;
local_ip?: string;
gateway_ip?: string;
subnet_mask?: string;
dns_ip_1?: string;
dns_ip_2?: string;
}
export interface WiFiNetworkList {
networks: WiFiNetwork[]
networks: WiFiNetwork[];
}
export interface WiFiNetwork {
rssi: number
ssid: string
bssid: string
channel: number
encryption_type: WiFiEncryptionType
rssi: number;
ssid: string;
bssid: string;
channel: number;
encryption_type: WiFiEncryptionType;
}