Extended Devices with buttons and status

This commit is contained in:
kunkliricsi 2020-11-18 14:04:57 +01:00
parent 181985859e
commit f84ea8f0c5
7 changed files with 119 additions and 23 deletions

View File

@ -52,7 +52,7 @@ function App() {
}; };
const DevicesComponent = () => { const DevicesComponent = () => {
return <Devices/>; return <Devices isAdmin={isAdmin}/>;
}; };
const HeatmapComponent = () => { const HeatmapComponent = () => {
@ -69,9 +69,9 @@ function App() {
<Switch> <Switch>
<PublicRoute path="/login" component={AuthComponent} /> <PublicRoute path="/login" component={AuthComponent} />
<DevicesContextProvider> <DevicesContextProvider>
<PrivateRoute path="/" exact authenticated={authenticated} isAdmin={isAdmin} component={DashboardComponent} /> <PrivateRoute path="/" exact authenticated={authenticated} component={DashboardComponent} />
<PrivateRoute path="/devices/:id?" exact authenticated={authenticated} isAdmin={isAdmin} component={DevicesComponent} /> <PrivateRoute path="/devices/:id?" exact authenticated={authenticated} component={DevicesComponent} />
<PrivateRoute path="/heatmap" exact authenticated={authenticated} isAdmin={isAdmin} component={HeatmapComponent} /> <PrivateRoute path="/heatmap" exact authenticated={authenticated} component={HeatmapComponent} />
</DevicesContextProvider> </DevicesContextProvider>
</Switch> </Switch>
</BrowserRouter> </BrowserRouter>
@ -89,17 +89,17 @@ const PublicRoute = ({ component: Component, ...rest }: { [x: string]: any, comp
); );
} }
const PrivateRoute = ({ component: Component, authenticated: Authenticated, isAdmin: IsAdmin, ...rest }: { [x: string]: any, component: any, authenticated: any, isAdmin: any }) => { const PrivateRoute = ({ component: Component, authenticated: Authenticated, ...rest }: { [x: string]: any, component: any, authenticated: any }) => {
return ( return (
<Route {...rest} render={matchProps => ( <Route {...rest} render={matchProps => (
Authenticated Authenticated
? <DefaultLayout component={Component} authenticated={Authenticated} isAdmin={IsAdmin} {...matchProps} /> ? <DefaultLayout component={Component} authenticated={Authenticated} {...matchProps} />
: <Redirect to='/login' /> : <Redirect to='/login' />
)} /> )} />
); );
}; };
const DefaultLayout = ({ component: Component, authenticated: Authenticated, isAdmin: IsAdmin, ...rest }: { [x: string]: any, component: any, authenticated: any, isAdmin: any }) => { const DefaultLayout = ({ component: Component, authenticated: Authenticated, ...rest }: { [x: string]: any, component: any, authenticated: any }) => {
const classes = useDefaultLayoutStyles(); const classes = useDefaultLayoutStyles();
const [open, setOpen] = React.useState(false); const [open, setOpen] = React.useState(false);
const anchorRef = React.useRef<HTMLButtonElement>(null); const anchorRef = React.useRef<HTMLButtonElement>(null);
@ -186,7 +186,7 @@ const DefaultLayout = ({ component: Component, authenticated: Authenticated, isA
</Toolbar> </Toolbar>
</AppBar> </AppBar>
<Box zIndex="modal" className={classes.box_root}> <Box zIndex="modal" className={classes.box_root}>
<Component isAdmin={IsAdmin} {...rest} /> <Component {...rest} />
</Box> </Box>
</React.Fragment> </React.Fragment>
); );

View File

@ -430,7 +430,9 @@ var DeviceService = /** @class */ (function () {
url_ = url_.replace(/[?&]$/, ""); url_ = url_.replace(/[?&]$/, "");
var options_ = { var options_ = {
method: "POST", method: "POST",
headers: {} headers: {
'Authorization': sessionStorage.getItem('user')
}
}; };
return this.http.fetch(url_, options_).then(function (_response) { return this.http.fetch(url_, options_).then(function (_response) {
return _this.processOnlinesensor(_response); return _this.processOnlinesensor(_response);

File diff suppressed because one or more lines are too long

View File

@ -391,6 +391,7 @@ export default class DeviceService {
let options_ = <RequestInit>{ let options_ = <RequestInit>{
method: "POST", method: "POST",
headers: { headers: {
'Authorization': sessionStorage.getItem('user')
} }
}; };

View File

@ -1,14 +1,22 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import Accordion from '@material-ui/core/Accordion'; import Accordion from '@material-ui/core/Accordion';
import { blue, red, yellow } from '@material-ui/core/colors'; import { blue, blueGrey, green, orange, red, yellow } from '@material-ui/core/colors';
import AccordionSummary from '@material-ui/core/AccordionSummary'; import AccordionSummary from '@material-ui/core/AccordionSummary';
import AccordionDetails from '@material-ui/core/AccordionDetails'; import AccordionDetails from '@material-ui/core/AccordionDetails';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import { Grid, Typography, Paper } from '@material-ui/core'; import { Grid, Typography, Paper, IconButton, Box, FormControlLabel } from '@material-ui/core';
import { withStyles } from '@material-ui/styles'; import { withStyles } from '@material-ui/styles';
import { withRouter } from "react-router"; import { withRouter } from "react-router";
import { Power, PowerOff, Refresh } from '@material-ui/icons/';
import DeviceService from '../../common/DeviceService'
const styles = theme => ({ const styles = theme => ({
acc_summary: {
backgroundColor: blueGrey[50],
},
acc_details: {
backgroundColor: blueGrey[100],
},
grid_typo: { grid_typo: {
fontSize: theme.typography.pxToRem(20), fontSize: theme.typography.pxToRem(20),
fontWeight: theme.typography.fontWeightRegular, fontWeight: theme.typography.fontWeightRegular,
@ -32,6 +40,9 @@ const styles = theme => ({
fontSize: theme.typography.pxToRem(15), fontSize: theme.typography.pxToRem(15),
fontWeight: theme.typography.fontWeightRegular, fontWeight: theme.typography.fontWeightRegular,
color: theme.palette.text.secondary, color: theme.palette.text.secondary,
},
icon_box: {
marginRight: '15px',
} }
}); });
@ -46,9 +57,9 @@ class DeviceComponent extends Component {
getColor(status) { getColor(status) {
if (status == "Online") { if (status == "Online") {
return { color: blue[800] }; return { color: green[600] };
} else if (status == "Offline") { } else if (status == "Offline") {
return { color: yellow[800] }; return { color: orange[900] };
} else /* if (device.status == "unknown") */ { } else /* if (device.status == "unknown") */ {
return { color: red[800] }; return { color: red[800] };
} }
@ -59,13 +70,72 @@ class DeviceComponent extends Component {
this.setState({ expanded: id }); this.setState({ expanded: id });
} }
renderSensorButtons(device, sensor) {
var service = new DeviceService();
return this.renderButtons(
() => service.onlinesensor(device.id, sensor.id),
() => service.offlinesensor(device.id, sensor.id),
() => service.getsensor(device.id, sensor.id)
);
}
renderDeviceButtons(device) {
var service = new DeviceService();
return this.renderButtons(
() => service.onlinedevice(device.id),
() => service.offlinedevice(device.id),
() => service.getdevice(device.id)
);
}
renderButtons(onPower, onPowerOff, onRefresh) {
const renderOnOff = () => {
return (
<React.Fragment>
<IconButton color="primary" onClick={onPower}>
<Power />
</IconButton>
<IconButton color="primary" onClick={onPowerOff}>
<PowerOff />
</IconButton>
</React.Fragment>
);
}
const { classes } = this.props;
return (
<Box className={classes.icon_box}>
{this.props.isAdmin ? renderOnOff() : null}
<IconButton color="primary" onClick={onRefresh}>
<Refresh />
</IconButton>
</Box>
);
}
render() { render() {
const { classes } = this.props; const { classes } = this.props;
const Sensors = this.props.device.sensors.map((sensor, index) => ( const Sensors = this.props.device.sensors.map((sensor, index) => (
<Grid item className={classes.grid_item} key={sensor.id}> <Grid item className={classes.grid_item} key={sensor.id}>
<Grid container
spacing={3}
direction="row"
justify="space-between"
alignItems="center">
<Grid item>
<Typography className={classes.grid_item_typo}>Sensor {index}</Typography> <Typography className={classes.grid_item_typo}>Sensor {index}</Typography>
</Grid>
<Grid item>
<Typography className={classes.grid_item_typo_2}>{sensor.id}</Typography> <Typography className={classes.grid_item_typo_2}>{sensor.id}</Typography>
</Grid> </Grid>
<Grid item>
<Typography style={this.getColor(sensor.status)}>Status: <b>{sensor.status}</b></Typography>
</Grid>
<Grid item>
{this.renderSensorButtons(this.props.device, sensor)}
</Grid>
</Grid>
</Grid>
)); ));
const handleChange = (panel) => (event, isExpanded) => { const handleChange = (panel) => (event, isExpanded) => {
@ -74,14 +144,33 @@ class DeviceComponent extends Component {
return ( return (
<Accordion expanded={this.state.expanded === this.props.device.id} onChange={handleChange(this.props.device.id)}> <Accordion expanded={this.state.expanded === this.props.device.id} onChange={handleChange(this.props.device.id)}>
<AccordionSummary <AccordionSummary className={classes.acc_summary}
expandIcon={<ExpandMoreIcon />} expandIcon={<ExpandMoreIcon />}
aria-controls={"device-panel-/" + this.props.device.id} aria-controls={"device-panel-/" + this.props.device.id}
id={"device-panel-/" + this.props.device.id}> id={"device-panel-/" + this.props.device.id}>
<Grid container
spacing={3}
direction="row"
justify="space-between"
alignItems="center">
<Grid item>
<Typography className={classes.grid_typo}>Device {this.props.index}</Typography> <Typography className={classes.grid_typo}>Device {this.props.index}</Typography>
</Grid>
<Grid item>
<Typography className={classes.grid_typo_2}>{this.props.device.id}</Typography> <Typography className={classes.grid_typo_2}>{this.props.device.id}</Typography>
</Grid>
<Grid item>
<Typography style={this.getColor(this.props.device.status)}>Status: <b>{this.props.device.status}</b></Typography>
</Grid>
<Grid item>
<FormControlLabel
onClick={(event) => event.stopPropagation()}
onFocus={(event) => event.stopPropagation()}
control={this.renderDeviceButtons(this.props.device)}/>
</Grid>
</Grid>
</AccordionSummary> </AccordionSummary>
<AccordionDetails> <AccordionDetails className={classes.acc_details}>
<Grid className={classes.grid_item} <Grid className={classes.grid_item}
container container
spacing={3} spacing={3}

View File

@ -24,7 +24,7 @@ class Devices extends React.Component {
render() { render() {
const { classes } = this.props; const { classes } = this.props;
const Devices = this.context.devices.map((device, index) => ( const Devices = this.context.devices.map((device, index) => (
<DeviceComponent device={device} index={index} key={device.id}/> <DeviceComponent isAdmin={this.props.isAdmin} device={device} index={index} key={device.id}/>
)); ));
return ( return (

View File

@ -75,6 +75,7 @@ namespace Birdmap.API.Controllers
{ {
_logger.LogInformation($"Getting device [{deviceID}]..."); _logger.LogInformation($"Getting device [{deviceID}]...");
await _hubContext.Clients.All.NotifyDeviceUpdatedAsync(deviceID);
return await _service.GetdeviceAsync(deviceID); return await _service.GetdeviceAsync(deviceID);
} }
@ -117,6 +118,7 @@ namespace Birdmap.API.Controllers
{ {
_logger.LogInformation($"Getting sensor [{sensorID}] of device [{deviceID}]..."); _logger.LogInformation($"Getting sensor [{sensorID}] of device [{deviceID}]...");
await _hubContext.Clients.All.NotifyDeviceUpdatedAsync(deviceID);
return await _service.GetsensorAsync(deviceID, sensorID); return await _service.GetsensorAsync(deviceID, sensorID);
} }
@ -131,6 +133,7 @@ namespace Birdmap.API.Controllers
_logger.LogInformation($"Turning off sensor [{sensorID}] of device [{deviceID}]..."); _logger.LogInformation($"Turning off sensor [{sensorID}] of device [{deviceID}]...");
await _service.OfflinesensorAsync(deviceID, sensorID); await _service.OfflinesensorAsync(deviceID, sensorID);
await _hubContext.Clients.All.NotifyDeviceUpdatedAsync(deviceID);
return Ok(); return Ok();
} }
@ -146,6 +149,7 @@ namespace Birdmap.API.Controllers
_logger.LogInformation($"Turning on sensor [{sensorID}] of device [{deviceID}]..."); _logger.LogInformation($"Turning on sensor [{sensorID}] of device [{deviceID}]...");
await _service.OnlinesensorAsync(deviceID, sensorID); await _service.OnlinesensorAsync(deviceID, sensorID);
await _hubContext.Clients.All.NotifyDeviceUpdatedAsync(deviceID);
return Ok(); return Ok();
} }