Merge remote-tracking branch 'origin/main'

This commit is contained in:
atef 2024-02-23 13:08:25 +01:00
commit d500b500d9
24 changed files with 2642 additions and 1578 deletions

View File

@ -299,6 +299,7 @@ internal static class Program
{
subscribedNow = true;
_subscribeToQueueForTheFirstTime = true;
_prevSalimaxState = currentSalimaxState.Status;
_subscribedToQueue = RabbitMqManager.SubscribeToQueue(currentSalimaxState, s3Bucket, VpnServerIp);
}

View File

@ -128,8 +128,8 @@ public partial class Battery48TlRecord
{
Boolean HasBit(Int16 bit) => (_AlarmFlags & 1uL << bit) > 0;
if (HasBit(0) ) yield return "Tam : BMS temperature too low";
if (HasBit(2) ) yield return "TaM2 : BMS temperature too high";
if (HasBit(0)) yield return "Tam : BMS temperature too low";
if (HasBit(2)) yield return "TaM2 : BMS temperature too high";
if (HasBit(3) ) yield return "Tbm : Battery temperature too low";
if (HasBit(5) ) yield return "TbM2 : Battery temperature too high";
if (HasBit(7) ) yield return "VBm2 : Bus voltage too low";

View File

@ -25,8 +25,7 @@ function App() {
const context = useContext(UserContext);
const { currentUser, setUser } = context;
const tokencontext = useContext(TokenContext);
const { token, setNewToken, removeToken } = tokencontext;
const [forgotPassword, setForgotPassword] = useState(false);
const { token, setNewToken } = tokencontext;
const navigate = useNavigate();
const searchParams = new URLSearchParams(location.search);
const username = searchParams.get('username');
@ -43,14 +42,6 @@ function App() {
}
};
const onForgotPassword = () => {
setForgotPassword(true);
};
const resetPassword = () => {
setForgotPassword(false);
};
const Loader = (Component) => (props) =>
(
<Suspense fallback={<SuspenseLoader />}>
@ -58,11 +49,6 @@ function App() {
</Suspense>
);
// Dashboards
const Installations = Loader(
lazy(() => import('src/content/dashboards/Installations/'))
);
const ResetPassword = Loader(
lazy(() => import('src/components/ResetPassword'))
);
@ -84,23 +70,9 @@ function App() {
navigate(routes.installations);
}
})
.catch((error) => {});
.catch(() => {});
};
// Status
const Status404 = Loader(
lazy(() => import('src/content/pages/Status/Status404'))
);
const Status500 = Loader(
lazy(() => import('src/content/pages/Status/Status500'))
);
const StatusComingSoon = Loader(
lazy(() => import('src/content/pages/Status/ComingSoon'))
);
const StatusMaintenance = Loader(
lazy(() => import('src/content/pages/Status/Maintenance'))
);
if (username) {
loginToResetPassword();
}
@ -174,7 +146,6 @@ function App() {
</AccessContextProvider>
}
/>
<Route path={routes.users + '*'} element={<Users />} />
<Route
path={'*'}

View File

@ -18,5 +18,7 @@
"information": "information",
"configuration": "configuration",
"login": "/login/",
"forgotPassword": "/forgotPassword/"
"forgotPassword": "/forgotPassword/",
"mainstats": "mainstats",
"general": "general"
}

View File

@ -1,37 +1,47 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import {
Container,
Grid,
Paper,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
useTheme
TableRow
} from '@mui/material';
import { TopologyValues } from '../Log/graph.util';
import { Link } from 'react-router-dom';
import {
Link,
Route,
Routes,
useLocation,
useNavigate
} from 'react-router-dom';
import Button from '@mui/material/Button';
import { FormattedMessage } from 'react-intl';
import { I_S3Credentials } from '../../../interfaces/S3Types';
import routes from '../../../Resources/routes.json';
import MainStats from './MainStats';
interface BatteryViewProps {
values: TopologyValues;
s3Credentials: I_S3Credentials;
}
function BatteryView(props: BatteryViewProps) {
if (props.values === null) {
return null;
}
const theme = useTheme();
const searchParams = new URLSearchParams(location.search);
const installationId = parseInt(searchParams.get('installation'));
const currentTab = searchParams.get('tab');
const currentPath = useLocation();
const navigate = useNavigate();
const [currentTab, setCurrentTab] = useState<string>(undefined);
const numOfBatteries = props.values.batteryView.values[0].value
.toString()
.split(',').length;
const batteryData = [];
let batteryId = 1;
// Use a for loop to generate battery data
for (let index = 1; index <= numOfBatteries * 7; index += 7) {
const battery = {
@ -61,155 +71,225 @@ function BatteryView(props: BatteryViewProps) {
batteryData.push(battery);
}
const handleMainStatsButton = () => {
navigate(routes.mainstats);
};
useEffect(() => {
let path = currentPath.pathname.split('/');
setCurrentTab(path[path.length - 1]);
}, [currentPath]);
return (
<TableContainer component={Paper}>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell align="center">Battery</TableCell>
<TableCell align="center">Firmware</TableCell>
<TableCell align="center">Power</TableCell>
<TableCell align="center">Voltage</TableCell>
<TableCell align="center">SoC</TableCell>
<TableCell align="center">Temperature</TableCell>
<TableCell align="center">Warnings</TableCell>
<TableCell align="center">Alarms</TableCell>
</TableRow>
</TableHead>
<TableBody>
{batteryData.map((battery) => (
<TableRow
key={battery.BatteryId}
style={{
height: '10px'
}}
>
<TableCell
component="th"
scope="row"
align="center"
sx={{ fontWeight: 'bold' }}
>
{battery.BatteryId}
</TableCell>
<TableCell
<>
<Container maxWidth="xl">
<Grid container>
<Routes>
<Route
path={routes.mainstats}
element={
<MainStats s3Credentials={props.s3Credentials}></MainStats>
}
/>
</Routes>
{currentTab === 'batteryview' && (
<Grid item xs={6} md={6}>
<Button
variant="contained"
sx={{
width: '10%',
textAlign: 'center'
marginTop: '20px',
backgroundColor: '#808080',
color: '#000000',
'&:hover': { bgcolor: '#f7b34d' }
}}
>
{battery.FwVersion}
</TableCell>
<TableCell
sx={{
width: '10%',
textAlign: 'center'
}}
>
{battery.Power}
</TableCell>
<TableCell
sx={{
width: '10%',
textAlign: 'center',
<FormattedMessage
id="main_stats"
defaultMessage="Battery View"
/>
</Button>
backgroundColor:
battery.Voltage < 44 || battery.Voltage > 57
? '#FF033E'
: '#32CD32',
color: battery.Voltage === '' ? 'white' : 'inherit'
}}
>
{battery.Voltage}
</TableCell>
<TableCell
<Button
variant="contained"
onClick={handleMainStatsButton}
sx={{
width: '10%',
textAlign: 'center',
backgroundColor:
battery.Soc < 20
? '#FF033E'
: battery.Soc < 50
? '#ffbf00 '
: '#32CD32',
color: battery.Soc === '' ? 'white' : 'inherit'
marginTop: '20px',
marginLeft: '20px',
// backgroundColor: mainStatsData ? '#808080' : '#ffc04d',
backgroundColor: '#ffc04d',
color: '#000000',
'&:hover': { bgcolor: '#f7b34d' }
}}
>
{battery.Soc}
</TableCell>
<TableCell
sx={{
width: '10%',
textAlign: 'center',
backgroundColor:
battery.AverageTemperature > 270 ? '#FF033E' : '#32CD32 '
}}
>
{battery.AverageTemperature}
</TableCell>
<FormattedMessage id="main_stats" defaultMessage="Main Stats" />
</Button>
</Grid>
)}
</Grid>
<TableCell
style={{
width: '20%',
textAlign: 'center',
padding: '8px',
fontWeight: battery.Warnings !== '' ? 'bold' : 'inherit',
backgroundColor:
battery.Warnings === '' ? 'inherit' : '#ff9900',
color: battery.Warnings != '' ? 'black' : 'inherit'
}}
>
{battery.Warnings === '' ? (
'None'
) : battery.Warnings.split(';').length > 1 ? (
<Link
style={{ color: 'black' }}
to={
'?installation=' +
installationId +
'&tab=log' +
'&open=warning'
}
{currentTab === 'batteryview' && (
<TableContainer
component={Paper}
sx={{ marginTop: '20px', marginBottom: '20px' }}
>
<Table sx={{ minWidth: 650 }} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell align="center">Battery</TableCell>
<TableCell align="center">Firmware</TableCell>
<TableCell align="center">Power</TableCell>
<TableCell align="center">Voltage</TableCell>
<TableCell align="center">SoC</TableCell>
<TableCell align="center">Temperature</TableCell>
<TableCell align="center">Warnings</TableCell>
<TableCell align="center">Alarms</TableCell>
</TableRow>
</TableHead>
<TableBody>
{batteryData.map((battery) => (
<TableRow
key={battery.BatteryId}
style={{
height: '10px'
}}
>
Multiple Warnings
</Link>
) : (
battery.Warnings
)}
</TableCell>
<TableCell
sx={{
width: '20%',
textAlign: 'center',
fontWeight: battery.Alarms !== '' ? 'bold' : 'inherit',
backgroundColor:
battery.Alarms === '' ? 'inherit' : '#FF033E',
color: battery.Alarms != '' ? 'black' : 'inherit'
}}
>
{battery.Alarms === '' ? (
'None'
) : battery.Alarms.split(';').length > 1 ? (
<Link
style={{ color: 'black' }}
to={
'?installation=' +
installationId +
'&tab=log' +
'&open=error'
}
>
Multiple Alarms
</Link>
) : (
battery.Alarms
)}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<TableCell
component="th"
scope="row"
align="center"
sx={{ fontWeight: 'bold' }}
>
{battery.BatteryId}
</TableCell>
<TableCell
sx={{
width: '10%',
textAlign: 'center'
}}
>
{battery.FwVersion}
</TableCell>
<TableCell
sx={{
width: '10%',
textAlign: 'center'
}}
>
{battery.Power}
</TableCell>
<TableCell
sx={{
width: '10%',
textAlign: 'center',
backgroundColor:
battery.Voltage < 44 || battery.Voltage > 57
? '#FF033E'
: '#32CD32',
color: battery.Voltage === '' ? 'white' : 'inherit'
}}
>
{battery.Voltage}
</TableCell>
<TableCell
sx={{
width: '10%',
textAlign: 'center',
backgroundColor:
battery.Soc < 20
? '#FF033E'
: battery.Soc < 50
? '#ffbf00 '
: '#32CD32',
color: battery.Soc === '' ? 'white' : 'inherit'
}}
>
{battery.Soc}
</TableCell>
<TableCell
sx={{
width: '10%',
textAlign: 'center',
backgroundColor:
battery.AverageTemperature > 270
? '#FF033E'
: '#32CD32 '
}}
>
{battery.AverageTemperature}
</TableCell>
<TableCell
style={{
width: '20%',
textAlign: 'center',
padding: '8px',
fontWeight:
battery.Warnings !== '' ? 'bold' : 'inherit',
backgroundColor:
battery.Warnings === '' ? 'inherit' : '#ff9900',
color: battery.Warnings != '' ? 'black' : 'inherit'
}}
>
{battery.Warnings === '' ? (
'None'
) : battery.Warnings.split(';').length > 1 ? (
<Link
style={{ color: 'black' }}
to={
currentPath.pathname.substring(
0,
currentPath.pathname.lastIndexOf('/') + 1
) +
routes.log +
'?open=warning'
}
>
Multiple Warnings
</Link>
) : (
battery.Warnings
)}
</TableCell>
<TableCell
sx={{
width: '20%',
textAlign: 'center',
fontWeight: battery.Alarms !== '' ? 'bold' : 'inherit',
backgroundColor:
battery.Alarms === '' ? 'inherit' : '#FF033E',
color: battery.Alarms != '' ? 'black' : 'inherit'
}}
>
{battery.Alarms === '' ? (
'None'
) : battery.Alarms.split(';').length > 1 ? (
<Link
style={{ color: 'black' }}
to={
currentPath.pathname.substring(
0,
currentPath.pathname.lastIndexOf('/') + 1
) +
routes.log +
'?open=error'
}
>
Multiple Alarms
</Link>
) : (
battery.Alarms
)}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
)}
</Container>
</>
);
}

View File

@ -0,0 +1,772 @@
import { Box, Card, Container, Grid, Modal, Typography } from '@mui/material';
import { FormattedMessage } from 'react-intl';
import React, { useEffect, useState } from 'react';
import { I_S3Credentials } from '../../../interfaces/S3Types';
import ReactApexChart from 'react-apexcharts';
import { getChartOptions } from '../Overview/chartOptions';
import {
BatteryDataInterface,
BatteryOverviewInterface,
transformInputToBatteryViewData
} from '../../../interfaces/Chart';
import dayjs from 'dayjs';
import { TimeSpan, UnixTime } from '../../../dataCache/time';
import Button from '@mui/material/Button';
import { DateTimePicker, LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import CircularProgress from '@mui/material/CircularProgress';
import { useLocation, useNavigate } from 'react-router-dom';
interface MainStatsProps {
s3Credentials: I_S3Credentials;
}
function MainStats(props: MainStatsProps) {
const [chartState, setChartState] = useState(0);
const [batteryViewDataArray, setBatteryViewDataArray] = useState<
{
chartData: BatteryDataInterface;
chartOverview: BatteryOverviewInterface;
}[]
>([]);
const [isDateModalOpen, setIsDateModalOpen] = useState(false);
const [dateOpen, setDateOpen] = useState(false);
const navigate = useNavigate();
const [startDate, setStartDate] = useState(dayjs().add(-1, 'day'));
const [endDate, setEndDate] = useState(dayjs());
const [isErrorDateModalOpen, setErrorDateModalOpen] = useState(false);
const [dateSelectionError, setDateSelectionError] = useState('');
const [loading, setLoading] = useState(true);
const location = useLocation();
const blueColors = [
'#99CCFF',
'#80BFFF',
'#6699CC',
'#4D99FF',
'#2670E6',
'#3366CC',
'#1A4D99',
'#133366',
'#0D274D',
'#081A33'
];
const redColors = [
'#ff9090',
'#ff7070',
'#ff3f3f',
'#ff1e1e',
'#ff0606',
'#fc0000',
'#f40000',
'#d40000',
'#a30000',
'#7a0000'
];
const orangeColors