Update firmware on frontend

This commit is contained in:
Noe 2024-03-19 17:42:33 +01:00
parent 3a3f2fe1b8
commit 2f24f97304
5 changed files with 486 additions and 282 deletions

View File

@ -514,18 +514,16 @@ public class Controller : ControllerBase
} }
[HttpPost(nameof(UpdateFirmware))] [HttpPost(nameof(UpdateFirmware))]
public ActionResult UpdateFirmware(Int64 batteryNode, Int64 installationId,Token authToken) public async Task<ActionResult> UpdateFirmware(Int64 batteryNode, Int64 installationId,Token authToken)
{ {
var session = Db.GetSession(authToken); var session = Db.GetSession(authToken);
var installationToUpdate = Db.GetInstallationById(installationId); var installationToUpdate = Db.GetInstallationById(installationId);
Console.WriteLine("Inside firmware function controller,batteryNode="+batteryNode+ "and installation is "+installationId); Console.WriteLine("Inside firmware function controller,batteryNode="+batteryNode+ "and installation is "+installationId);
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
if (installationToUpdate != null) if (installationToUpdate != null)
{ {
session.RunScriptInBackground(installationToUpdate.VpnIp, batteryNode); _ = session.RunScriptInBackground(installationToUpdate.VpnIp, batteryNode);
} }
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
return Ok(); return Ok();
} }

View File

@ -1,4 +1,4 @@
import React from 'react'; import React, { useEffect, useState } from 'react';
import { import {
Container, Container,
Grid, Grid,
@ -8,7 +8,8 @@ import {
TableCell, TableCell,
TableContainer, TableContainer,
TableHead, TableHead,
TableRow TableRow,
Typography
} from '@mui/material'; } from '@mui/material';
import { TopologyValues } from '../Log/graph.util'; import { TopologyValues } from '../Log/graph.util';
import { import {
@ -24,10 +25,12 @@ import { I_S3Credentials } from '../../../interfaces/S3Types';
import routes from '../../../Resources/routes.json'; import routes from '../../../Resources/routes.json';
import MainStats from './MainStats'; import MainStats from './MainStats';
import DetailedBatteryView from './DetailedBatteryView'; import DetailedBatteryView from './DetailedBatteryView';
import CircularProgress from '@mui/material/CircularProgress';
interface BatteryViewProps { interface BatteryViewProps {
values: TopologyValues; values: TopologyValues;
s3Credentials: I_S3Credentials; s3Credentials: I_S3Credentials;
installationId: number;
} }
function BatteryView(props: BatteryViewProps) { function BatteryView(props: BatteryViewProps) {
@ -40,6 +43,10 @@ function BatteryView(props: BatteryViewProps) {
(a, b) => b.BatteryId - a.BatteryId (a, b) => b.BatteryId - a.BatteryId
); );
const [loading, setLoading] = useState(
sortedBatteryView.length == 0 ? true : false
);
const handleMainStatsButton = () => { const handleMainStatsButton = () => {
navigate(routes.mainstats); navigate(routes.mainstats);
}; };
@ -52,8 +59,42 @@ function BatteryView(props: BatteryViewProps) {
} }
}; };
useEffect(() => {
if (sortedBatteryView.length == 0) {
setLoading(true);
} else {
setLoading(false);
}
}, [sortedBatteryView]);
return ( return (
<> <>
{loading && (
<Container
maxWidth="xl"
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
height: '70vh'
}}
>
<CircularProgress size={60} style={{ color: '#ffc04d' }} />
<Typography
variant="body2"
style={{ color: 'black', fontWeight: 'bold' }}
mt={2}
>
Battery service is not available at the moment
</Typography>
<Typography variant="body2" style={{ color: 'black' }}>
Please wait or refresh the page
</Typography>
</Container>
)}
{!loading && (
<Container maxWidth="xl"> <Container maxWidth="xl">
<Grid container> <Grid container>
<Grid <Grid
@ -115,6 +156,7 @@ function BatteryView(props: BatteryViewProps) {
<DetailedBatteryView <DetailedBatteryView
s3Credentials={props.s3Credentials} s3Credentials={props.s3Credentials}
batteryData={findBatteryData(battery.BatteryId)} batteryData={findBatteryData(battery.BatteryId)}
installationId={props.installationId}
></DetailedBatteryView> ></DetailedBatteryView>
} }
/> />
@ -190,10 +232,12 @@ function BatteryView(props: BatteryViewProps) {
textAlign: 'center', textAlign: 'center',
backgroundColor: backgroundColor:
battery.Voltage.value < 44 || battery.Voltage.value > 57 battery.Voltage.value < 44 ||
battery.Voltage.value > 57
? '#FF033E' ? '#FF033E'
: '#32CD32', : '#32CD32',
color: battery.Voltage.value === '' ? 'white' : 'inherit' color:
battery.Voltage.value === '' ? 'white' : 'inherit'
}} }}
> >
{battery.Voltage.value + ' ' + battery.Voltage.unit} {battery.Voltage.value + ' ' + battery.Voltage.unit}
@ -237,7 +281,8 @@ function BatteryView(props: BatteryViewProps) {
battery.Warnings.value !== '' ? 'bold' : 'inherit', battery.Warnings.value !== '' ? 'bold' : 'inherit',
backgroundColor: backgroundColor:
battery.Warnings.value === '' ? 'inherit' : '#ff9900', battery.Warnings.value === '' ? 'inherit' : '#ff9900',
color: battery.Warnings.value != '' ? 'black' : 'inherit' color:
battery.Warnings.value != '' ? 'black' : 'inherit'
}} }}
> >
{battery.Warnings.value === '' ? ( {battery.Warnings.value === '' ? (
@ -299,6 +344,7 @@ function BatteryView(props: BatteryViewProps) {
</Table> </Table>
</TableContainer> </TableContainer>
</Container> </Container>
)}
</> </>
); );
} }

View File

@ -1,8 +1,11 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { I_S3Credentials } from '../../../interfaces/S3Types'; import { I_S3Credentials } from '../../../interfaces/S3Types';
import { import {
Box,
Card, Card,
Grid, Grid,
IconButton,
Modal,
Paper, Paper,
Table, Table,
TableBody, TableBody,
@ -12,14 +15,16 @@ import {
Typography Typography
} from '@mui/material'; } from '@mui/material';
import { Battery } from '../Log/graph.util'; import { Battery } from '../Log/graph.util';
import { useNavigate } from 'react-router-dom';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import { useNavigate } from 'react-router-dom'; import axiosConfig from '../../../Resources/axiosConfig';
import routes from '../../../Resources/routes.json';
interface DetailedBatteryViewProps { interface DetailedBatteryViewProps {
s3Credentials: I_S3Credentials; s3Credentials: I_S3Credentials;
batteryData: Battery; batteryData: Battery;
installationId: number;
} }
function DetailedBatteryView(props: DetailedBatteryViewProps) { function DetailedBatteryView(props: DetailedBatteryViewProps) {
@ -27,16 +32,20 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
return null; return null;
} }
const navigate = useNavigate(); const navigate = useNavigate();
const [openModalFirmwareUpdate, setOpenModalFirmwareUpdate] = useState(false);
const [openModalResultFirmwareUpdate, setOpenModalResultFirmwareUpdate] =
useState(false);
const handleBatteryViewButton = () => { const handleBatteryViewButton = () => {
navigate(location.pathname.split('/').slice(0, -2).join('/')); navigate(location.pathname.split('/').slice(0, -2).join('/'));
}; };
const handleMainStatsButton = () => {
navigate( const handleUpdateFirmware = () => {
location.pathname.split('/').slice(0, -2).join('/') + setOpenModalFirmwareUpdate(true);
'/' + };
routes.mainstats
); const firmwareModalResultHandleOk = () => {
navigate(location.pathname.split('/').slice(0, -2).join('/'));
}; };
const [GreenisBlinking, setGreenisBlinking] = useState( const [GreenisBlinking, setGreenisBlinking] = useState(
@ -96,26 +105,177 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
backgroundColor: '#bfbfbf' backgroundColor: '#bfbfbf'
}; };
const FirmwareModalHandleProceed = async (e) => {
setOpenModalFirmwareUpdate(false);
const res = await axiosConfig
.post(
`/UpdateFirmware?batteryNode=${props.batteryData.BatteryId.toString()}&installationId=${
props.installationId
}`
)
.catch((err) => {
if (err.response) {
// setError(true);
// setLoading(false);
}
});
//if (res) {
setOpenModalResultFirmwareUpdate(true);
//}
};
const FirmwareModalHandleCancel = () => {
setOpenModalFirmwareUpdate(false);
};
return ( return (
<> <>
{openModalResultFirmwareUpdate && (
<Modal
open={openModalResultFirmwareUpdate}
aria-labelledby="error-modal"
aria-describedby="error-modal-description"
>
<Box
sx={{
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 420,
bgcolor: 'background.paper',
borderRadius: 4,
boxShadow: 24,
p: 4,
display: 'flex',
flexDirection: 'column',
alignItems: 'center'
}}
>
<Typography
variant="body1"
gutterBottom
sx={{ fontWeight: 'bold' }}
>
The firmware is getting updated. Please wait...
</Typography>
<div
style={{
display: 'flex',
alignItems: 'center',
marginTop: 10
}}
>
<Button
sx={{
marginTop: 2,
textTransform: 'none',
bgcolor: '#ffc04d',
color: '#111111',
'&:hover': { bgcolor: '#f7b34d' }
}}
onClick={firmwareModalResultHandleOk}
>
Ok
</Button>
</div>
</Box>
</Modal>
)}
{openModalFirmwareUpdate && (
<Modal
open={openModalFirmwareUpdate}
onClose={FirmwareModalHandleCancel}
aria-labelledby="error-modal"
aria-describedby="error-modal-description"
>
<Box
sx={{
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
width: 420,
bgcolor: 'background.paper',
borderRadius: 4,
boxShadow: 24,
p: 4,
display: 'flex',
flexDirection: 'column',
alignItems: 'center'
}}
>
<Typography
variant="body1"
gutterBottom
sx={{ fontWeight: 'bold' }}
>
Do you really want to update the firmware?
</Typography>
<Typography variant="body1" gutterBottom>
This action requires the battery service to be stopped.
</Typography>
<div
style={{
display: 'flex',
alignItems: 'center',
marginTop: 10
}}
>
<Button
sx={{
marginTop: 2,
textTransform: 'none',
bgcolor: '#ffc04d',
color: '#111111',
'&:hover': { bgcolor: '#f7b34d' }
}}
onClick={FirmwareModalHandleProceed}
>
Proceed
</Button>
<Button
sx={{
marginTop: 2,
marginLeft: 2,
textTransform: 'none',
bgcolor: '#ffc04d',
color: '#111111',
'&:hover': { bgcolor: '#f7b34d' }
}}
onClick={FirmwareModalHandleCancel}
>
Cancel
</Button>
</div>
</Box>
</Modal>
)}
<Grid container> <Grid container>
<Grid item xs={6} md={6}> <Grid item xs={6} md={6}>
<Button <IconButton
variant="contained" aria-label="go back"
onClick={handleBatteryViewButton}
sx={{ sx={{
marginTop: '20px', marginTop: '20px',
backgroundColor: '#ffc04d', backgroundColor: 'grey',
color: '#000000', color: '#000000',
'&:hover': { bgcolor: '#f7b34d' } '&:hover': { bgcolor: '#f7b34d' }
}} }}
onClick={handleBatteryViewButton}
> >
<FormattedMessage id="main_stats" defaultMessage="Battery View" /> <ArrowBackIcon />
</Button> </IconButton>
<Button <Button
variant="contained" variant="contained"
onClick={handleMainStatsButton} onClick={handleUpdateFirmware}
sx={{ sx={{
marginTop: '20px', marginTop: '20px',
marginLeft: '20px', marginLeft: '20px',
@ -124,7 +284,10 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
'&:hover': { bgcolor: '#f7b34d' } '&:hover': { bgcolor: '#f7b34d' }
}} }}
> >
<FormattedMessage id="main_stats" defaultMessage="Main Stats" /> <FormattedMessage
id="update_firmware"
defaultMessage="Update Firmware"
/>
</Button> </Button>
</Grid> </Grid>
</Grid> </Grid>

View File

@ -1,4 +1,12 @@
import { Box, Card, Container, Grid, Modal, Typography } from '@mui/material'; import {
Box,
Card,
Container,
Grid,
IconButton,
Modal,
Typography
} from '@mui/material';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { I_S3Credentials } from '../../../interfaces/S3Types'; import { I_S3Credentials } from '../../../interfaces/S3Types';
@ -16,6 +24,7 @@ import { DateTimePicker, LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import CircularProgress from '@mui/material/CircularProgress'; import CircularProgress from '@mui/material/CircularProgress';
import { useLocation, useNavigate } from 'react-router-dom'; import { useLocation, useNavigate } from 'react-router-dom';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
interface MainStatsProps { interface MainStatsProps {
s3Credentials: I_S3Credentials; s3Credentials: I_S3Credentials;
@ -384,31 +393,18 @@ function MainStats(props: MainStatsProps) {
{!loading && ( {!loading && (
<> <>
<Grid item xs={6} md={6}> <Grid item xs={6} md={6}>
<Button <IconButton
variant="contained" aria-label="go back"
sx={{
marginTop: '20px',
backgroundColor: 'grey',
color: '#000000',
'&:hover': { bgcolor: '#f7b34d' }
}}
onClick={handleBatteryViewButton} onClick={handleBatteryViewButton}
sx={{
marginTop: '20px',
backgroundColor: '#ffc04d',
color: '#000000',
'&:hover': { bgcolor: '#f7b34d' }
}}
> >
<FormattedMessage id="main_stats" defaultMessage="Battery View" /> <ArrowBackIcon />
</Button> </IconButton>
<Button
variant="contained"
sx={{
marginTop: '20px',
marginLeft: '20px',
backgroundColor: '#808080',
color: '#000000',
'&:hover': { bgcolor: '#f7b34d' }
}}
>
<FormattedMessage id="main_stats" defaultMessage="Main Stats" />
</Button>
<Button <Button
variant="contained" variant="contained"

View File

@ -278,6 +278,7 @@ function Installation(props: singleInstallationProps) {
<BatteryView <BatteryView
values={values} values={values}
s3Credentials={s3Credentials} s3Credentials={s3Credentials}
installationId={props.current_installation.id}
></BatteryView> ></BatteryView>
} }
></Route> ></Route>