Merge remote-tracking branch 'origin/main'

This commit is contained in:
atef 2024-02-20 17:07:10 +01:00
commit 179c2fe0fc
17 changed files with 498 additions and 342 deletions

View File

@ -119,6 +119,10 @@ function App() {
path={routes.forgotPassword} path={routes.forgotPassword}
element={<ForgotPassword />} element={<ForgotPassword />}
></Route> ></Route>
<Route
path={'*'}
element={<Navigate to={routes.login}></Navigate>}
></Route>
</Routes> </Routes>
</ThemeProvider> </ThemeProvider>
); );
@ -147,6 +151,10 @@ function App() {
path={''} path={''}
element={<Navigate to={routes.installations}></Navigate>} element={<Navigate to={routes.installations}></Navigate>}
></Route> ></Route>
<Route
path={'login'}
element={<Navigate to={routes.installations}></Navigate>}
></Route>
<Route <Route
path="/" path="/"
element={ element={
@ -168,7 +176,10 @@ function App() {
/> />
<Route path={routes.users + '*'} element={<Users />} /> <Route path={routes.users + '*'} element={<Users />} />
<Route
path={'*'}
element={<Navigate to={routes.installations}></Navigate>}
></Route>
<Route path="ResetPassword" element={<ResetPassword />}></Route> <Route path="ResetPassword" element={<ResetPassword />}></Route>
</Route> </Route>
</Routes> </Routes>

View File

@ -91,7 +91,7 @@ function Login() {
}; };
return ( return (
<> <div style={{ userSelect: 'none' }}>
<Container maxWidth="xl" sx={{ pt: 2 }} className="login"> <Container maxWidth="xl" sx={{ pt: 2 }} className="login">
<Grid container> <Grid container>
<Grid item xs={3} container justifyContent="flex-start" mb={2}> <Grid item xs={3} container justifyContent="flex-start" mb={2}>
@ -263,7 +263,7 @@ function Login() {
</Grid> </Grid>
</Box> </Box>
</Box> </Box>
</> </div>
); );
} }

View File

@ -104,7 +104,10 @@ function InstallationTabs() {
value: 'live', value: 'live',
label: <FormattedMessage id="live" defaultMessage="Live" /> label: <FormattedMessage id="live" defaultMessage="Live" />
}, },
{
value: 'overview',
label: <FormattedMessage id="overview" defaultMessage="Overview" />
},
{ {
value: 'batteryview', value: 'batteryview',
label: ( label: (
@ -148,12 +151,7 @@ function InstallationTabs() {
value: 'overview', value: 'overview',
label: <FormattedMessage id="overview" defaultMessage="Overview" /> label: <FormattedMessage id="overview" defaultMessage="Overview" />
}, },
{
value: 'batteryview',
label: (
<FormattedMessage id="batteryview" defaultMessage="Battery View" />
)
},
{ {
value: 'log', value: 'log',
label: <FormattedMessage id="log" defaultMessage="Log" /> label: <FormattedMessage id="log" defaultMessage="Log" />

View File

@ -29,10 +29,17 @@ interface LogProps {
function Log(props: LogProps) { function Log(props: LogProps) {
const theme = useTheme(); const theme = useTheme();
const searchParams = new URLSearchParams(location.search);
const openModal = searchParams.get('open');
const [warnings, setWarnings] = useState<ErrorMessage[]>([]); const [warnings, setWarnings] = useState<ErrorMessage[]>([]);
const [errors, setErrors] = useState<ErrorMessage[]>([]); const [errors, setErrors] = useState<ErrorMessage[]>([]);
const [errorButtonPressed, setErrorButtonPressed] = useState(false); const [errorButtonPressed, setErrorButtonPressed] = useState(
const [warningButtonPressed, setWarningButtonPressed] = useState(false); openModal === 'error' ? true : false
);
const [warningButtonPressed, setWarningButtonPressed] = useState(
openModal === 'warning' ? true : false
);
const [updateCount, setUpdateCount] = useState(0); const [updateCount, setUpdateCount] = useState(0);
const navigate = useNavigate(); const navigate = useNavigate();
const tokencontext = useContext(TokenContext); const tokencontext = useContext(TokenContext);

View File

@ -260,7 +260,7 @@ export const getChartOptions = (
: chartInfo.max <= 0 : chartInfo.max <= 0
? Math.ceil(chartInfo.min / findPower(chartInfo.min).value) * ? Math.ceil(chartInfo.min / findPower(chartInfo.min).value) *
findPower(chartInfo.min).value findPower(chartInfo.min).value
: Math.abs(chartInfo.min) < 1 : Math.abs(chartInfo.min) < 1 || Math.abs(chartInfo.max) < 1
? -Math.max( ? -Math.max(
Math.abs( Math.abs(
Math.ceil(chartInfo.min / findPower(chartInfo.min).value) * Math.ceil(chartInfo.min / findPower(chartInfo.min).value) *
@ -278,7 +278,7 @@ export const getChartOptions = (
).toFixed(2) ).toFixed(2)
: chartInfo.max <= 0 : chartInfo.max <= 0
? 0 ? 0
: Math.abs(chartInfo.min) < 1 : Math.abs(chartInfo.min) < 1 || Math.abs(chartInfo.max) < 1
? +Math.max( ? +Math.max(
Math.abs( Math.abs(
Math.ceil(chartInfo.min / findPower(chartInfo.min).value) * Math.ceil(chartInfo.min / findPower(chartInfo.min).value) *
@ -306,6 +306,17 @@ export const getChartOptions = (
} }
} }
}, },
annotations: {
yaxis: [
{
y: 0,
strokeDashArray: 0,
borderColor: '#d3d3d3',
borderWidth: 1,
yAxisIndex: 0
}
]
},
tooltip: { tooltip: {
y: { y: {
formatter: function (val) { formatter: function (val) {

View File

@ -687,7 +687,7 @@ function Overview(props: OverviewProps) {
}, },
{ {
name: 'Net Energy', name: 'Net Energy',
color: '#666666', color: '#ff3333',
type: 'line', type: 'line',
data: weeklybalance data: weeklybalance
} }
@ -917,7 +917,7 @@ function Overview(props: OverviewProps) {
/> />
)} )}
{weeklyData && ( {weeklyData && currentUser.hasWriteAccess && (
<ReactApexChart <ReactApexChart
options={{ options={{
...getChartOptions( ...getChartOptions(
@ -930,7 +930,7 @@ function Overview(props: OverviewProps) {
series={[ series={[
{ {
...weeklyDataArray.chartData.dcChargingPower, ...weeklyDataArray.chartData.dcChargingPower,
color: '#69d2e7' color: '#008FFB'
}, },
{ {
...weeklyDataArray.chartData.heatingPower, ...weeklyDataArray.chartData.heatingPower,
@ -938,7 +938,7 @@ function Overview(props: OverviewProps) {
}, },
{ {
...weeklyDataArray.chartData.dcDischargingPower, ...weeklyDataArray.chartData.dcDischargingPower,
color: '#008FFB' color: '#69d2e7'
} }
]} ]}
type="bar" type="bar"
@ -946,7 +946,33 @@ function Overview(props: OverviewProps) {
/> />
)} )}
{monthlyData && ( {weeklyData && !currentUser.hasWriteAccess && (
<ReactApexChart
options={{
...getChartOptions(
weeklyDataArray.chartOverview.dcPowerWithoutHeating,
'weekly',
weeklyDateList,
true
)
}}
series={[
{
...weeklyDataArray.chartData.dcChargingPower,
color: '#008FFB'
},
{
...weeklyDataArray.chartData.dcDischargingPower,
color: '#69d2e7'
}
]}
type="bar"
height={400}
/>
)}
{monthlyData && currentUser.hasWriteAccess && (
<ReactApexChart <ReactApexChart
options={{ options={{
...getChartOptions( ...getChartOptions(
@ -959,7 +985,7 @@ function Overview(props: OverviewProps) {
series={[ series={[
{ {
...monthlyDataArray.chartData.dcChargingPower, ...monthlyDataArray.chartData.dcChargingPower,
color: '#69d2e7' color: '#008FFB'
}, },
{ {
...weeklyDataArray.chartData.heatingPower, ...weeklyDataArray.chartData.heatingPower,
@ -967,7 +993,34 @@ function Overview(props: OverviewProps) {
}, },
{ {
...monthlyDataArray.chartData.dcDischargingPower, ...monthlyDataArray.chartData.dcDischargingPower,
color: '#69d2e7'
}
]}
type="bar"
height={400}
/>
)}
{monthlyData && !currentUser.hasWriteAccess && (
<ReactApexChart
options={{
...getChartOptions(
monthlyDataArray.chartOverview
.dcPowerWithoutHeating,
'monthly',
monthlyDateList,
true
)
}}
series={[
{
...monthlyDataArray.chartData.dcChargingPower,
color: '#008FFB' color: '#008FFB'
},
{
...monthlyDataArray.chartData.dcDischargingPower,
color: '#69d2e7'
} }
]} ]}
type="bar" type="bar"
@ -1106,232 +1159,229 @@ function Overview(props: OverviewProps) {
</Grid> </Grid>
)} )}
{currentUser.hasWriteAccess && ( <Grid
<Grid container
container direction="row"
direction="row" justifyContent="center"
justifyContent="center" alignItems="stretch"
alignItems="stretch" spacing={3}
spacing={3} >
> <Grid item md={6} xs={12}>
<Grid item md={6} xs={12}> <Card
<Card sx={{
overflow: 'visible',
marginTop: '30px',
marginBottom: '30px'
}}
>
<Box
sx={{ sx={{
overflow: 'visible', marginLeft: '20px'
marginTop: '30px',
marginBottom: '30px'
}} }}
> >
<Box display="flex" alignItems="center">
<Box>
<Typography variant="subtitle1" noWrap>
<FormattedMessage
id="pv_production"
defaultMessage="PV Production"
/>
</Typography>
</Box>
</Box>
<Box <Box
sx={{ sx={{
marginLeft: '20px' display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
pt: 3
}} }}
> ></Box>
<Box display="flex" alignItems="center"> </Box>
<Box>
<Typography variant="subtitle1" noWrap>
<FormattedMessage
id="pv_production"
defaultMessage="PV Production"
/>
</Typography>
</Box>
</Box>
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
pt: 3
}}
></Box>
</Box>
{dailyData && ( {dailyData && (
<ReactApexChart <ReactApexChart
options={{ options={{
...getChartOptions( ...getChartOptions(
dailyDataArray[chartState].chartOverview dailyDataArray[chartState].chartOverview
.pvProduction, .pvProduction,
'daily', 'daily',
[], [],
true true
), ),
chart: { chart: {
events: { events: {
beforeZoom: handleBeforeZoom beforeZoom: handleBeforeZoom
}
} }
}} }
series={[
{
...dailyDataArray[chartState].chartData
.pvProduction,
color: '#ff9900'
}
]}
type="line"
height={400}
/>
)}
{weeklyData && (
<ReactApexChart
options={{
...getChartOptions(
weeklyDataArray.chartOverview.pvProduction,
'weekly',
weeklyDateList,
true
)
}}
series={[
{
...weeklyDataArray.chartData.pvProduction,
color: '#ff9900'
}
]}
type="bar"
height={400}
/>
)}
{monthlyData && (
<ReactApexChart
options={{
...getChartOptions(
monthlyDataArray.chartOverview.pvProduction,
'monthly',
monthlyDateList,
true
)
}}
series={[
{
...monthlyDataArray.chartData.pvProduction,
color: '#ff9900'
}
]}
type="bar"
height={400}
/>
)}
</Card>
</Grid>
<Grid item md={6} xs={12}>
<Card
sx={{
overflow: 'visible',
marginTop: '30px',
marginBottom: '30px'
}}
>
<Box
sx={{
marginLeft: '20px'
}} }}
> series={[
<Box display="flex" alignItems="center"> {
<Box> ...dailyDataArray[chartState].chartData
<Typography variant="subtitle1" noWrap> .pvProduction,
<FormattedMessage color: '#ff9900'
id="grid_power" }
defaultMessage={ ]}
dailyData ? 'Grid Power' : 'Grid Energy' type="line"
} height={400}
/> />
</Typography> )}
</Box>
</Box>
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
pt: 3
}}
></Box>
</Box>
{dailyData && (
<ReactApexChart
options={{
...getChartOptions(
dailyDataArray[chartState].chartOverview
.gridPower,
'daily',
[],
true
),
chart: {
events: {
beforeZoom: handleBeforeZoom
}
}
}}
series={[
{
...dailyDataArray[chartState].chartData.gridPower,
color: '#ff3333'
}
]}
type="line"
height={400}
/>
)}
{weeklyData && (
<ReactApexChart
options={{
...getChartOptions(
weeklyDataArray.chartOverview.gridPower,
'weekly',
weeklyDateList,
true
)
}}
series={[
{
...weeklyDataArray.chartData.gridImportPower,
color: '#b30000'
},
{ {weeklyData && (
...weeklyDataArray.chartData.gridExportPower, <ReactApexChart
color: '#ff3333' options={{
} ...getChartOptions(
]} weeklyDataArray.chartOverview.pvProduction,
type="bar" 'weekly',
height={400} weeklyDateList,
/> true
)} )
}}
series={[
{
...weeklyDataArray.chartData.pvProduction,
color: '#ff9900'
}
]}
type="bar"
height={400}
/>
)}
{monthlyData && ( {monthlyData && (
<ReactApexChart <ReactApexChart
options={{ options={{
...getChartOptions( ...getChartOptions(
monthlyDataArray.chartOverview.gridPower, monthlyDataArray.chartOverview.pvProduction,
'monthly', 'monthly',
monthlyDateList, monthlyDateList,
true true
) )
}} }}
series={[ series={[
{ {
...monthlyDataArray.chartData.gridImportPower, ...monthlyDataArray.chartData.pvProduction,
color: '#b30000' color: '#ff9900'
}, }
{ ]}
...monthlyDataArray.chartData.gridExportPower, type="bar"
color: '#ff3333' height={400}
} />
]} )}
type="bar" </Card>
height={400}
/>
)}
</Card>
</Grid>
</Grid> </Grid>
)} <Grid item md={6} xs={12}>
<Card
sx={{
overflow: 'visible',
marginTop: '30px',
marginBottom: '30px'
}}
>
<Box
sx={{
marginLeft: '20px'
}}
>
<Box display="flex" alignItems="center">
<Box>
<Typography variant="subtitle1" noWrap>
<FormattedMessage
id="grid_power"
defaultMessage={
dailyData ? 'Grid Power' : 'Grid Energy'
}
/>
</Typography>
</Box>
</Box>
<Box
sx={{
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
pt: 3
}}
></Box>
</Box>
{dailyData && (
<ReactApexChart
options={{
...getChartOptions(
dailyDataArray[chartState].chartOverview.gridPower,
'daily',
[],
true
),
chart: {
events: {
beforeZoom: handleBeforeZoom
}
}
}}
series={[
{
...dailyDataArray[chartState].chartData.gridPower,
color: '#ff3333'
}
]}
type="line"
height={400}
/>
)}
{weeklyData && (
<ReactApexChart
options={{
...getChartOptions(
weeklyDataArray.chartOverview.gridPower,
'weekly',
weeklyDateList,
true
)
}}
series={[
{
...weeklyDataArray.chartData.gridImportPower,
color: '#b30000'
},
{
...weeklyDataArray.chartData.gridExportPower,
color: '#ff3333'
}
]}
type="bar"
height={400}
/>
)}
{monthlyData && (
<ReactApexChart
options={{
...getChartOptions(
monthlyDataArray.chartOverview.gridPower,
'monthly',
monthlyDateList,
true
)
}}
series={[
{
...monthlyDataArray.chartData.gridImportPower,
color: '#b30000'
},
{
...monthlyDataArray.chartData.gridExportPower,
color: '#ff3333'
}
]}
type="bar"
height={400}
/>
)}
</Card>
</Grid>
</Grid>
</Grid> </Grid>
)} )}
</Grid> </Grid>

View File

@ -1,5 +1,5 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { Container, Grid, Switch } from '@mui/material'; import { Container, Grid, Switch, Typography } from '@mui/material';
import TopologyColumn from './topologyColumn'; import TopologyColumn from './topologyColumn';
import { import {
getAmount, getAmount,
@ -41,16 +41,33 @@ function Topology(props: TopologyProps) {
justifyContent: 'right' justifyContent: 'right'
}} }}
> >
<Switch <div>
edge="start" <Typography sx={{ marginTop: '5px', marginRight: '20px' }}>
color="secondary" Display Values
onChange={handleSwitch()} </Typography>
sx={{ <Switch
'& .MuiSwitch-thumb': { edge="start"
backgroundColor: 'orange' color="secondary"
} onChange={handleSwitch()}
}} sx={{
/> '& .MuiSwitch-thumb': {
backgroundColor: 'orange'
},
marginLeft: '20px'
}}
/>
</div>
{/*<Switch*/}
{/* edge="start"*/}
{/* color="secondary"*/}
{/* onChange={handleSwitch()}*/}
{/* sx={{*/}
{/* '& .MuiSwitch-thumb': {*/}
{/* backgroundColor: 'orange'*/}
{/* }*/}
{/* }}*/}
{/*/>*/}
</Grid> </Grid>
<Grid <Grid

View File

@ -29,7 +29,7 @@ const isInt = (value: number) => {
return value % 1 === 0; return value % 1 === 0;
}; };
function formatPower(value) { function formatPower(value, unit) {
if (isNaN(value)) { if (isNaN(value)) {
return 'Invalid'; return 'Invalid';
} }
@ -47,7 +47,12 @@ function formatPower(value) {
magnitude++; magnitude++;
} }
const roundedValue = value.toFixed(1); const roundedValue = Math.round(value);
//Filter all values less than 100 Watts
if (magnitude === 0 && value < 100 && unit === 'W') {
return 0;
}
return negative === false return negative === false
? `${roundedValue} ${prefixes[magnitude]}` ? `${roundedValue} ${prefixes[magnitude]}`
@ -243,8 +248,12 @@ function TopologyBox(props: TopologyBoxProps) {
{props.data.values.map((boxData, index) => { {props.data.values.map((boxData, index) => {
return ( return (
<Typography key={index}> <Typography key={index}>
{formatPower(boxData.value)} {formatPower(boxData.value, boxData.unit) === 0
{boxData.unit} ? null
: formatPower(boxData.value, boxData.unit)}
{formatPower(boxData.value, boxData.unit) === 0
? null
: boxData.unit}
</Typography> </Typography>
); );
})} })}

View File

@ -45,7 +45,12 @@ function formatPower(value) {
magnitude++; magnitude++;
} }
const roundedValue = value.toFixed(1); const roundedValue = Math.round(value);
//Filter all values less than 100 Watts
if (magnitude === 0 && value < 100) {
return 0;
}
return negative === false return negative === false
? `${roundedValue} ${prefixes[magnitude]}` ? `${roundedValue} ${prefixes[magnitude]}`
@ -113,8 +118,12 @@ function TopologyFlow(props: TopologyFlowProps) {
zIndex: 1 zIndex: 1
}} }}
> >
{formatPower(props.data.values[0].value)} {formatPower(props.data.values[0].value) === 0
{props.data.values[0].unit} ? null
: formatPower(props.data.values[0].value)}
{formatPower(props.data.values[0].value) === 0
? null
: props.data.values[0].unit}
</Typography> </Typography>
)} )}
</Box> </Box>

View File

@ -9,6 +9,7 @@ import {
Grid, Grid,
IconButton, IconButton,
Modal, Modal,
Switch,
Tab, Tab,
Tabs, Tabs,
TextField, TextField,
@ -22,6 +23,7 @@ import { InnovEnergyUser } from 'src/interfaces/UserTypes';
import { TokenContext } from 'src/contexts/tokenContext'; import { TokenContext } from 'src/contexts/tokenContext';
import { TabsContainerWrapper } from 'src/layouts/TabsContainerWrapper'; import { TabsContainerWrapper } from 'src/layouts/TabsContainerWrapper';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import FormControlLabel from '@mui/material/FormControlLabel';
interface singleUserProps { interface singleUserProps {
current_user: InnovEnergyUser; current_user: InnovEnergyUser;
@ -80,6 +82,14 @@ function User(props: singleUserProps) {
[name]: value [name]: value
}); });
}; };
const handleAdminChange = (event) => {
setFormValues({
...formValues,
['hasWriteAccess']: event.target.checked
});
};
const handleSubmit = async (e) => { const handleSubmit = async (e) => {
setLoading(true); setLoading(true);
setError(false); setError(false);
@ -94,8 +104,13 @@ function User(props: singleUserProps) {
}); });
if (res) { if (res) {
setUpdated(true); props.fetchDataAgain();
setLoading(false); setLoading(false);
setUpdated(true);
setTimeout(() => {
setUpdated(false);
}, 3000);
} }
}; };
@ -278,6 +293,34 @@ function User(props: singleUserProps) {
fullWidth fullWidth
/> />
</div> </div>
<div>
<FormControlLabel
labelPlacement="start"
control={
<Switch
checked={
formValues.hasWriteAccess ? true : false
}
color="primary"
name="hasWriteAccess"
onChange={handleAdminChange}
sx={{
marginLeft: '8px',
marginTop: '2px'
}}
/>
}
label={
<Typography sx={{ marginTop: '4px' }}>
Admin
</Typography>
}
sx={{
marginLeft: '10px'
}}
/>
</div>
<div <div
style={{ style={{
display: 'flex', display: 'flex',

View File

@ -8,7 +8,7 @@ function Users() {
const theme = useTheme(); const theme = useTheme();
return ( return (
<> <div style={{ userSelect: 'none' }}>
<AccessContextProvider> <AccessContextProvider>
<Container maxWidth="xl" sx={{ marginTop: '20px' }}> <Container maxWidth="xl" sx={{ marginTop: '20px' }}>
<Grid item xs={12}> <Grid item xs={12}>
@ -19,7 +19,7 @@ function Users() {
</Container> </Container>
<Footer /> <Footer />
</AccessContextProvider> </AccessContextProvider>
</> </div>
); );
} }

View File

@ -9,7 +9,9 @@ import {
MenuItem, MenuItem,
Modal, Modal,
Select, Select,
Switch,
TextField, TextField,
Typography,
useTheme useTheme
} from '@mui/material'; } from '@mui/material';
import Button from '@mui/material/Button'; import Button from '@mui/material/Button';
@ -17,10 +19,9 @@ import { Close as CloseIcon } from '@mui/icons-material';
import { InnovEnergyUser } from 'src/interfaces/UserTypes'; import { InnovEnergyUser } from 'src/interfaces/UserTypes';
import axiosConfig from 'src/Resources/axiosConfig'; import axiosConfig from 'src/Resources/axiosConfig';
import { TokenContext } from 'src/contexts/tokenContext'; import { TokenContext } from 'src/contexts/tokenContext';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import { I_Folder, I_Installation } from 'src/interfaces/InstallationTypes'; import { I_Folder, I_Installation } from 'src/interfaces/InstallationTypes';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import FormControlLabel from '@mui/material/FormControlLabel';
interface userFormProps { interface userFormProps {
cancel: () => void; cancel: () => void;
@ -385,16 +386,22 @@ function userForm(props: userFormProps) {
<div> <div>
<FormControlLabel <FormControlLabel
labelPlacement="start"
control={ control={
<Checkbox <Switch
color="primary"
onChange={handleAdminChange} onChange={handleAdminChange}
sx={{ sx={{
marginLeft: '11px' marginLeft: '8px',
marginTop: '2px'
}} }}
/> />
} }
label="Admin" label={<Typography sx={{ marginTop: '6px' }}>Admin</Typography>}
sx={{ marginTop: 1 }} sx={{
marginLeft: '10px',
marginTop: '9px'
}}
/> />
</div> </div>

View File

@ -1,17 +1,12 @@
import { import {
Box, Box,
Card,
Typography,
Container,
Divider,
Button, Button,
FormControl, Container,
OutlinedInput, OutlinedInput,
InputAdornment, styled,
styled Typography
} from '@mui/material'; } from '@mui/material';
import { Helmet } from 'react-helmet-async'; import { Helmet } from 'react-helmet-async';
import SearchTwoToneIcon from '@mui/icons-material/SearchTwoTone';
const MainContent = styled(Box)( const MainContent = styled(Box)(
({ theme }) => ` ({ theme }) => `
@ -50,42 +45,14 @@ function Status404() {
<Typography variant="h2" sx={{ my: 2 }}> <Typography variant="h2" sx={{ my: 2 }}>
The page you were looking for doesn't exist. The page you were looking for doesn't exist.
</Typography> </Typography>
<Typography <Button
variant="h4" href="/login"
color="text.secondary" variant="outlined"
fontWeight="normal" sx={{ backgroundColor: 'white' }}
sx={{ mb: 4 }}
> >
It's on us, we moved the content to a different page. The search Go to homepage
below should help! </Button>
</Typography>
</Box> </Box>
<Container maxWidth="sm">
<Card sx={{ textAlign: 'center', mt: 3, p: 4 }}>
<FormControl variant="outlined" fullWidth>
<OutlinedInputWrapper
type="text"
placeholder="Search terms here..."
endAdornment={
<InputAdornment position="end">
<ButtonSearch variant="contained" size="small">
Search
</ButtonSearch>
</InputAdornment>
}
startAdornment={
<InputAdornment position="start">
<SearchTwoToneIcon />
</InputAdornment>
}
/>
</FormControl>
<Divider sx={{ my: 4 }}>OR</Divider>
<Button href="/overview" variant="outlined">
Go to homepage
</Button>
</Card>
</Container>
</Container> </Container>
</MainContent> </MainContent>
</> </>

View File

@ -11,6 +11,7 @@ export interface overviewInterface {
soc: chartInfoInterface; soc: chartInfoInterface;
temperature: chartInfoInterface; temperature: chartInfoInterface;
dcPower: chartInfoInterface; dcPower: chartInfoInterface;
dcPowerWithoutHeating: chartInfoInterface;
gridPower: chartInfoInterface; gridPower: chartInfoInterface;
pvProduction: chartInfoInterface; pvProduction: chartInfoInterface;
dcBusVoltage: chartInfoInterface; dcBusVoltage: chartInfoInterface;
@ -78,6 +79,7 @@ export const transformInputToDailyData = async (
soc: { magnitude: 0, unit: '', min: 0, max: 0 }, soc: { magnitude: 0, unit: '', min: 0, max: 0 },
temperature: { magnitude: 0, unit: '', min: 0, max: 0 }, temperature: { magnitude: 0, unit: '', min: 0, max: 0 },
dcPower: { magnitude: 0, unit: '', min: 0, max: 0 }, dcPower: { magnitude: 0, unit: '', min: 0, max: 0 },
dcPowerWithoutHeating: { magnitude: 0, unit: '', min: 0, max: 0 },
gridPower: { magnitude: 0, unit: '', min: 0, max: 0 }, gridPower: { magnitude: 0, unit: '', min: 0, max: 0 },
pvProduction: { magnitude: 0, unit: '', min: 0, max: 0 }, pvProduction: { magnitude: 0, unit: '', min: 0, max: 0 },
dcBusVoltage: { magnitude: 0, unit: '', min: 0, max: 0 }, dcBusVoltage: { magnitude: 0, unit: '', min: 0, max: 0 },
@ -108,7 +110,7 @@ export const transformInputToDailyData = async (
while (startUnixTime < endTimestamp) { while (startUnixTime < endTimestamp) {
timestampPromises.push(fetchData(startUnixTime, s3Credentials)); timestampPromises.push(fetchData(startUnixTime, s3Credentials));
startUnixTime = UnixTime.fromTicks(startUnixTime.ticks + diff / 200); startUnixTime = UnixTime.fromTicks(startUnixTime.ticks + diff / 100);
if (startUnixTime.ticks % 2 !== 0) { if (startUnixTime.ticks % 2 !== 0) {
startUnixTime = UnixTime.fromTicks(startUnixTime.ticks + 1); startUnixTime = UnixTime.fromTicks(startUnixTime.ticks + 1);
} }
@ -280,7 +282,7 @@ export const transformInputToAggregatedData = async (
maxsoc: { name: 'max SOC', data: [] }, maxsoc: { name: 'max SOC', data: [] },
pvProduction: { name: 'Pv Energy', data: [] }, pvProduction: { name: 'Pv Energy', data: [] },
dcChargingPower: { name: 'Charging Battery Energy', data: [] }, dcChargingPower: { name: 'Charging Battery Energy', data: [] },
heatingPower: { name: 'Heating Power', data: [] }, heatingPower: { name: 'Heating Energy', data: [] },
dcDischargingPower: { name: 'Discharging Battery Energy', data: [] }, dcDischargingPower: { name: 'Discharging Battery Energy', data: [] },
gridImportPower: { name: 'Grid Import Energy', data: [] }, gridImportPower: { name: 'Grid Import Energy', data: [] },
gridExportPower: { name: 'Grid Export Energy', data: [] } gridExportPower: { name: 'Grid Export Energy', data: [] }
@ -290,6 +292,7 @@ export const transformInputToAggregatedData = async (
soc: { magnitude: 0, unit: '', min: 0, max: 0 }, soc: { magnitude: 0, unit: '', min: 0, max: 0 },
temperature: { magnitude: 0, unit: '', min: 0, max: 0 }, temperature: { magnitude: 0, unit: '', min: 0, max: 0 },
dcPower: { magnitude: 0, unit: '', min: 0, max: 0 }, dcPower: { magnitude: 0, unit: '', min: 0, max: 0 },
dcPowerWithoutHeating: { magnitude: 0, unit: '', min: 0, max: 0 },
gridPower: { magnitude: 0, unit: '', min: 0, max: 0 }, gridPower: { magnitude: 0, unit: '', min: 0, max: 0 },
pvProduction: { magnitude: 0, unit: '', min: 0, max: 0 }, pvProduction: { magnitude: 0, unit: '', min: 0, max: 0 },
dcBusVoltage: { magnitude: 0, unit: '', min: 0, max: 0 }, dcBusVoltage: { magnitude: 0, unit: '', min: 0, max: 0 },
@ -329,6 +332,9 @@ export const transformInputToAggregatedData = async (
dateList.push(currentDay.format('DD-MM')); dateList.push(currentDay.format('DD-MM'));
pathsToSearch.forEach((path) => { pathsToSearch.forEach((path) => {
if (result[path]) { if (result[path]) {
if (path === '/GridExportPower') {
result[path].value = -result[path].value;
}
if (result[path].value < overviewData[path].min) { if (result[path].value < overviewData[path].min) {
overviewData[path].min = result[path].value; overviewData[path].min = result[path].value;
} }
@ -336,9 +342,9 @@ export const transformInputToAggregatedData = async (
if (result[path].value > overviewData[path].max) { if (result[path].value > overviewData[path].max) {
overviewData[path].max = result[path].value; overviewData[path].max = result[path].value;
} }
if (path === '/GridExportPower' && result[path].value < 0.1) { // if (path === '/GridExportPower' && Math.abs(result[path].value) < 0.1) {
result[path].value = 0.3; // result[path].value = -0.3;
} // }
data[path].push(result[path].value as number); data[path].push(result[path].value as number);
} }
}); });
@ -395,6 +401,16 @@ export const transformInputToAggregatedData = async (
path = '/HeatingPower'; path = '/HeatingPower';
chartAggregatedData.heatingPower.data = data[path]; chartAggregatedData.heatingPower.data = data[path];
chartOverview.dcPowerWithoutHeating = {
magnitude: Math.max(
overviewData['/ChargingBatteryPower'].magnitude,
overviewData['/DischargingBatteryPower'].magnitude
),
unit: '(kWh)',
min: overviewData['/DischargingBatteryPower'].min,
max: overviewData['/ChargingBatteryPower'].max
};
chartOverview.dcPower = { chartOverview.dcPower = {
magnitude: Math.max( magnitude: Math.max(
overviewData['/ChargingBatteryPower'].magnitude, overviewData['/ChargingBatteryPower'].magnitude,
@ -420,12 +436,8 @@ export const transformInputToAggregatedData = async (
overviewData['/GridExportPower'].magnitude overviewData['/GridExportPower'].magnitude
), ),
unit: '(kWh)', unit: '(kWh)',
min: min: overviewData['/GridExportPower'].min,
overviewData['/GridImportPower'].min + max: overviewData['/GridImportPower'].max
overviewData['/GridExportPower'].min,
max:
overviewData['/GridImportPower'].max +
overviewData['/GridExportPower'].max
}; };
chartOverview.overview = { chartOverview.overview = {

View File

@ -11,6 +11,7 @@ import { styled } from '@mui/material/styles';
import ExpandMoreTwoToneIcon from '@mui/icons-material/ExpandMoreTwoTone'; import ExpandMoreTwoToneIcon from '@mui/icons-material/ExpandMoreTwoTone';
import { ThemeContext } from '../../../../theme/ThemeProvider'; import { ThemeContext } from '../../../../theme/ThemeProvider';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import '../../../../App.css';
interface HeaderButtonsProps { interface HeaderButtonsProps {
language: string; language: string;
@ -106,7 +107,7 @@ function HeaderMenu(props: HeaderButtonsProps) {
const isMobile = window.innerWidth <= 1280; const isMobile = window.innerWidth <= 1280;
return ( return (
<> <div style={{ userSelect: 'none' }}>
<ListWrapper <ListWrapper
sx={{ sx={{
color: isMobile ? 'white' : '' color: isMobile ? 'white' : ''
@ -132,18 +133,22 @@ function HeaderMenu(props: HeaderButtonsProps) {
</ListItem> </ListItem>
</List> </List>
</ListWrapper> </ListWrapper>
<Menu anchorEl={ref.current} onClose={handleClose} open={isOpen}> <div
<MenuItem value="en" onClick={() => handleLanguageSelect('en')}> style={{ userSelect: 'none', pointerEvents: 'none', cursor: 'default' }}
English >
</MenuItem> <Menu anchorEl={ref.current} onClose={handleClose} open={isOpen}>
<MenuItem value="de" onClick={() => handleLanguageSelect('de')}> <MenuItem value="en" onClick={() => handleLanguageSelect('en')}>
German English
</MenuItem> </MenuItem>
<MenuItem value="fr" onClick={() => handleLanguageSelect('fr')}> <MenuItem value="de" onClick={() => handleLanguageSelect('de')}>
French German
</MenuItem> </MenuItem>
</Menu> <MenuItem value="fr" onClick={() => handleLanguageSelect('fr')}>
</> French
</MenuItem>
</Menu>
</div>
</div>
); );
} }

View File

@ -19,6 +19,7 @@ import { TokenContext } from 'src/contexts/tokenContext';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import routes from 'src/Resources/routes.json'; import routes from 'src/Resources/routes.json';
import { WebSocketContext } from '../../../../contexts/WebSocketContextProvider'; import { WebSocketContext } from '../../../../contexts/WebSocketContextProvider';
import '../../../../App.css';
const UserBoxButton = styled(Button)( const UserBoxButton = styled(Button)(
({ theme }) => ` ({ theme }) => `
@ -86,8 +87,13 @@ function HeaderUserbox() {
}; };
return ( return (
<> <div style={{ userSelect: 'none' }}>
<UserBoxButton color="secondary" ref={ref} onClick={handleOpen}> <UserBoxButton
color="secondary"
ref={ref}
onClick={handleOpen}
style={{ cursor: 'pointer' }}
>
<Hidden mdDown> <Hidden mdDown>
<UserBoxText> <UserBoxText>
<UserBoxLabel variant="body1">{currentUser?.name}</UserBoxLabel> <UserBoxLabel variant="body1">{currentUser?.name}</UserBoxLabel>
@ -113,14 +119,16 @@ function HeaderUserbox() {
horizontal: 'right' horizontal: 'right'
}} }}
> >
<MenuUserBox sx={{ minWidth: 210 }} display="flex"> <div style={{ userSelect: 'none', cursor: 'none' }}>
<UserBoxText> <MenuUserBox sx={{ minWidth: 210 }} display="flex">
<UserBoxLabel variant="body1">{currentUser?.name}</UserBoxLabel> <UserBoxText>
<UserBoxDescription variant="body2"> <UserBoxLabel variant="body1">{currentUser?.name}</UserBoxLabel>
{currentUser?.email} <UserBoxDescription variant="body2">
</UserBoxDescription> {currentUser?.email}
</UserBoxText> </UserBoxDescription>
</MenuUserBox> </UserBoxText>
</MenuUserBox>
</div>
<Divider /> <Divider />
<Box sx={{ m: 1 }}> <Box sx={{ m: 1 }}>
@ -130,7 +138,7 @@ function HeaderUserbox() {
</Button> </Button>
</Box> </Box>
</Popover> </Popover>
</> </div>
); );
} }

View File

@ -43,10 +43,12 @@ const SidebarLayout = (props: SidebarLayoutProps) => {
} }
}} }}
> >
<Header <div style={{ userSelect: 'none' }}>
language={props.language} <Header
onSelectLanguage={props.onSelectLanguage} language={props.language}
/> onSelectLanguage={props.onSelectLanguage}
/>
</div>
<Sidebar /> <Sidebar />
<Box <Box
sx={{ sx={{