Update frontend to support json using the same interfaces.
All the products use json over the same message interfaces. Salimax and sodistoreMax use the same files avoiding copying everything twice.
This commit is contained in:
parent
4f75912026
commit
5849507ad1
|
|
@ -30,7 +30,7 @@ function App() {
|
|||
const navigate = useNavigate();
|
||||
const searchParams = new URLSearchParams(location.search);
|
||||
const username = searchParams.get('username');
|
||||
const { setAccessToSalimax, setAccessToSalidomo,setAccessToSodiohome } =
|
||||
const { setAccessToSalimax, setAccessToSalidomo, setAccessToSodiohome } =
|
||||
useContext(ProductIdContext);
|
||||
|
||||
const [language, setLanguage] = useState('en');
|
||||
|
|
@ -75,9 +75,9 @@ function App() {
|
|||
setAccessToSodiohome(response.data.accessToSodiohome);
|
||||
if (response.data.accessToSalimax) {
|
||||
navigate(routes.installations);
|
||||
} else if(response.data.accessToSalidomo){
|
||||
} else if (response.data.accessToSalidomo) {
|
||||
navigate(routes.salidomo_installations);
|
||||
} else{
|
||||
} else {
|
||||
navigate(routes.sodiohome_installations);
|
||||
}
|
||||
}
|
||||
|
|
@ -152,7 +152,16 @@ function App() {
|
|||
path={routes.installations + '*'}
|
||||
element={
|
||||
<AccessContextProvider>
|
||||
<InstallationTabs />
|
||||
<InstallationTabs product={0} />
|
||||
</AccessContextProvider>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route
|
||||
path={routes.sodistore_installations + '*'}
|
||||
element={
|
||||
<AccessContextProvider>
|
||||
<InstallationTabs product={3} />
|
||||
</AccessContextProvider>
|
||||
}
|
||||
/>
|
||||
|
|
@ -161,7 +170,7 @@ function App() {
|
|||
path={routes.salidomo_installations + '*'}
|
||||
element={
|
||||
<AccessContextProvider>
|
||||
<SalidomoInstallationTabs />
|
||||
<SalidomoInstallationTabs product={1} />
|
||||
</AccessContextProvider>
|
||||
}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
"users": "/users/",
|
||||
"installations": "/installations/",
|
||||
"salidomo_installations": "/salidomo_installations/",
|
||||
"sodistore_installations": "/sodistore_installations/",
|
||||
"sodiohome_installations": "/sodiohome_installations/",
|
||||
"installation": "installation/",
|
||||
"login": "/login/",
|
||||
|
|
|
|||
|
|
@ -40,8 +40,6 @@ function Configuration(props: ConfigurationProps) {
|
|||
return null;
|
||||
}
|
||||
|
||||
console.log('111111111111111111111111111111111111111111111111');
|
||||
|
||||
const CalibrationChargeOptions = [
|
||||
'Repetitive Calibration',
|
||||
'Additional Calibration',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState } from 'react';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import {
|
||||
Card,
|
||||
CircularProgress,
|
||||
|
|
@ -18,6 +18,7 @@ import BuildIcon from '@mui/icons-material/Build';
|
|||
import { FormattedMessage } from 'react-intl';
|
||||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import routes from '../../../Resources/routes.json';
|
||||
import { ProductIdContext } from '../../../contexts/ProductIdContextProvider';
|
||||
|
||||
interface FlatInstallationViewProps {
|
||||
installations: I_Installation[];
|
||||
|
|
@ -28,6 +29,7 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
|||
const navigate = useNavigate();
|
||||
const [selectedInstallation, setSelectedInstallation] = useState<number>(-1);
|
||||
const currentLocation = useLocation();
|
||||
const { product, setProduct } = useContext(ProductIdContext);
|
||||
|
||||
const sortedInstallations = [...props.installations].sort((a, b) => {
|
||||
// Compare the status field of each installation and sort them based on the status.
|
||||
|
|
@ -45,17 +47,25 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
|||
});
|
||||
|
||||
const handleSelectOneInstallation = (installationID: number): void => {
|
||||
console.log('when selecting installation', product);
|
||||
if (selectedInstallation != installationID) {
|
||||
setSelectedInstallation(installationID);
|
||||
setSelectedInstallation(-1);
|
||||
|
||||
navigate(
|
||||
routes.installations +
|
||||
routes.list +
|
||||
routes.installation +
|
||||
`${installationID}` +
|
||||
'/' +
|
||||
routes.live,
|
||||
product === 0
|
||||
? routes.installations +
|
||||
routes.list +
|
||||
routes.installation +
|
||||
`${installationID}` +
|
||||
'/' +
|
||||
routes.live
|
||||
: routes.sodistore_installations +
|
||||
routes.list +
|
||||
routes.installation +
|
||||
`${installationID}` +
|
||||
'/' +
|
||||
routes.live,
|
||||
{
|
||||
replace: true
|
||||
}
|
||||
|
|
@ -82,7 +92,11 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
|||
sx={{
|
||||
display:
|
||||
currentLocation.pathname === routes.installations + 'list' ||
|
||||
currentLocation.pathname === routes.installations + routes.list
|
||||
currentLocation.pathname === routes.installations + routes.list ||
|
||||
currentLocation.pathname ===
|
||||
routes.sodistore_installations + 'list' ||
|
||||
currentLocation.pathname ===
|
||||
routes.sodistore_installations + routes.list
|
||||
? 'block'
|
||||
: 'none'
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import { FormControl, Grid, InputAdornment, TextField } from '@mui/material';
|
||||
import SearchTwoToneIcon from '@mui/icons-material/SearchTwoTone';
|
||||
import FlatInstallationView from 'src/content/dashboards/Installations/FlatInstallationView';
|
||||
|
|
@ -6,6 +6,7 @@ import { I_Installation } from '../../../interfaces/InstallationTypes';
|
|||
import { Route, Routes, useLocation } from 'react-router-dom';
|
||||
import routes from '../../../Resources/routes.json';
|
||||
import Installation from './Installation';
|
||||
import { ProductIdContext } from '../../../contexts/ProductIdContextProvider';
|
||||
|
||||
interface installationSearchProps {
|
||||
installations: I_Installation[];
|
||||
|
|
@ -15,6 +16,7 @@ function InstallationSearch(props: installationSearchProps) {
|
|||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const currentLocation = useLocation();
|
||||
const [filteredData, setFilteredData] = useState(props.installations);
|
||||
const { product, setProduct } = useContext(ProductIdContext);
|
||||
|
||||
useEffect(() => {
|
||||
const filtered = props.installations.filter(
|
||||
|
|
@ -35,7 +37,11 @@ function InstallationSearch(props: installationSearchProps) {
|
|||
sx={{
|
||||
display:
|
||||
currentLocation.pathname === routes.installations + 'list' ||
|
||||
currentLocation.pathname === routes.installations + routes.list
|
||||
currentLocation.pathname === routes.installations + routes.list ||
|
||||
currentLocation.pathname ===
|
||||
routes.sodistore_installations + 'list' ||
|
||||
currentLocation.pathname ===
|
||||
routes.sodistore_installations + routes.list
|
||||
? 'block'
|
||||
: 'none'
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ export const fetchAggregatedDataJson = (
|
|||
s3Credentials?: I_S3Credentials
|
||||
): Promise<FetchResult<any>> => {
|
||||
const s3Path = `${date}.json`;
|
||||
|
||||
if (s3Credentials && s3Credentials.s3Bucket) {
|
||||
const s3Access = new S3Access(
|
||||
s3Credentials.s3Bucket,
|
||||
|
|
@ -81,7 +82,7 @@ export const fetchAggregatedDataJson = (
|
|||
const zip = await JSZip.loadAsync(byteArray);
|
||||
// Assuming the CSV file is named "data.csv" inside the ZIP archive
|
||||
const jsonContent = await zip.file('data.json').async('text');
|
||||
// console.log(jsonContent);
|
||||
//console.log(jsonContent);
|
||||
return JSON.parse(jsonContent);
|
||||
} else {
|
||||
return Promise.resolve(FetchResult.notAvailable);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,11 @@ import Installation from './Installation';
|
|||
import { UserType } from '../../../interfaces/UserTypes';
|
||||
import { ProductIdContext } from '../../../contexts/ProductIdContextProvider';
|
||||
|
||||
function InstallationTabs() {
|
||||
interface InstallationTabsProps {
|
||||
product: number;
|
||||
}
|
||||
|
||||
function InstallationTabs(props: InstallationTabsProps) {
|
||||
const location = useLocation();
|
||||
const context = useContext(UserContext);
|
||||
const { currentUser } = context;
|
||||
|
|
@ -32,10 +36,10 @@ function InstallationTabs() {
|
|||
];
|
||||
|
||||
const [currentTab, setCurrentTab] = useState<string>(undefined);
|
||||
|
||||
const {
|
||||
salimaxInstallations,
|
||||
salimax_or_sodistore_Installations,
|
||||
fetchAllInstallations,
|
||||
currentProduct,
|
||||
socket,
|
||||
openSocket,
|
||||
closeSocket
|
||||
|
|
@ -56,25 +60,14 @@ function InstallationTabs() {
|
|||
}, [location]);
|
||||
|
||||
useEffect(() => {
|
||||
if (salimaxInstallations.length === 0) {
|
||||
fetchAllInstallations();
|
||||
}
|
||||
}, [salimaxInstallations]);
|
||||
setProduct(props.product);
|
||||
}, [props.product]);
|
||||
|
||||
useEffect(() => {
|
||||
if (salimaxInstallations && salimaxInstallations.length > 0) {
|
||||
if (!socket) {
|
||||
openSocket(0);
|
||||
} else if (currentProduct != 0) {
|
||||
closeSocket();
|
||||
openSocket(0);
|
||||
}
|
||||
if (product == props.product) {
|
||||
fetchAllInstallations(product);
|
||||
}
|
||||
}, [salimaxInstallations, currentProduct]);
|
||||
|
||||
useEffect(() => {
|
||||
setProduct(0);
|
||||
}, []);
|
||||
}, [product]);
|
||||
|
||||
const handleTabsChange = (_event: ChangeEvent<{}>, value: string): void => {
|
||||
setCurrentTab(value);
|
||||
|
|
@ -378,7 +371,7 @@ function InstallationTabs() {
|
|||
}
|
||||
];
|
||||
|
||||
return salimaxInstallations.length > 1 ? (
|
||||
return salimax_or_sodistore_Installations.length > 1 ? (
|
||||
<>
|
||||
<Container maxWidth="xl" sx={{ marginTop: '20px' }} className="mainframe">
|
||||
<TabsContainerWrapper>
|
||||
|
|
@ -421,17 +414,24 @@ function InstallationTabs() {
|
|||
<Grid item xs={12}>
|
||||
<Box p={4}>
|
||||
<InstallationSearch
|
||||
installations={salimaxInstallations}
|
||||
installations={salimax_or_sodistore_Installations}
|
||||
/>
|
||||
</Box>
|
||||
</Grid>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route path={routes.tree + '*'} element={<TreeView />} />
|
||||
<Route
|
||||
path={'*'}
|
||||
element={
|
||||
<Navigate to={routes.installations + routes.list}></Navigate>
|
||||
props.product === 0 ? (
|
||||
<Navigate to={routes.installations + routes.list} />
|
||||
) : (
|
||||
<Navigate
|
||||
to={routes.sodistore_installations + routes.list}
|
||||
/>
|
||||
)
|
||||
}
|
||||
></Route>
|
||||
</Routes>
|
||||
|
|
@ -440,7 +440,7 @@ function InstallationTabs() {
|
|||
</Container>
|
||||
<Footer />
|
||||
</>
|
||||
) : salimaxInstallations.length === 1 ? (
|
||||
) : salimax_or_sodistore_Installations.length === 1 ? (
|
||||
<>
|
||||
<Container maxWidth="xl" sx={{ marginTop: '20px' }} className="mainframe">
|
||||
<TabsContainerWrapper>
|
||||
|
|
@ -478,7 +478,9 @@ function InstallationTabs() {
|
|||
<Grid item xs={12}>
|
||||
<Box p={4}>
|
||||
<Installation
|
||||
current_installation={salimaxInstallations[0]}
|
||||
current_installation={
|
||||
salimax_or_sodistore_Installations[0]
|
||||
}
|
||||
type="installation"
|
||||
></Installation>
|
||||
</Box>
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import { UserContext } from '../../../contexts/userContext';
|
|||
import { UserType } from '../../../interfaces/UserTypes';
|
||||
import { TimeSpan, UnixTime } from '../../../dataCache/time';
|
||||
import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker';
|
||||
import { ProductIdContext } from '../../../contexts/ProductIdContextProvider';
|
||||
|
||||
interface OverviewProps {
|
||||
s3Credentials: I_S3Credentials;
|
||||
|
|
@ -69,6 +70,8 @@ function Overview(props: OverviewProps) {
|
|||
}[]
|
||||
>([]);
|
||||
|
||||
//console.log(dailyData);
|
||||
|
||||
const [aggregatedDataArray, setAggregatedDataArray] = useState<
|
||||
{
|
||||
chartData: chartAggregatedDataInterface;
|
||||
|
|
@ -82,6 +85,8 @@ function Overview(props: OverviewProps) {
|
|||
const [endDate, setEndDate] = useState(dayjs());
|
||||
const [isZooming, setIsZooming] = useState(false);
|
||||
|
||||
const { product } = useContext(ProductIdContext);
|
||||
|
||||
// console.log(
|
||||
// UnixTime.fromTicks(new Date().getTime() / 1000).earlier(
|
||||
// TimeSpan.fromDays(1)
|
||||
|
|
@ -102,6 +107,7 @@ function Overview(props: OverviewProps) {
|
|||
chartData: chartDataInterface;
|
||||
chartOverview: overviewInterface;
|
||||
}> = transformInputToDailyDataJson(
|
||||
product,
|
||||
props.s3Credentials,
|
||||
props.id,
|
||||
UnixTime.fromTicks(new Date().getTime() / 1000).earlier(
|
||||
|
|
@ -137,6 +143,7 @@ function Overview(props: OverviewProps) {
|
|||
chartData: chartDataInterface;
|
||||
chartOverview: overviewInterface;
|
||||
}> = transformInputToDailyDataJson(
|
||||
product,
|
||||
props.s3Credentials,
|
||||
props.id,
|
||||
UnixTime.fromTicks(startX).earlier(TimeSpan.fromHours(2)),
|
||||
|
|
@ -265,6 +272,7 @@ function Overview(props: OverviewProps) {
|
|||
chartData: chartDataInterface;
|
||||
chartOverview: overviewInterface;
|
||||
}> = transformInputToDailyDataJson(
|
||||
product,
|
||||
props.s3Credentials,
|
||||
props.id,
|
||||
UnixTime.fromTicks(startDate.unix()),
|
||||
|
|
@ -1320,47 +1328,47 @@ function Overview(props: OverviewProps) {
|
|||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
container
|
||||
direction="row"
|
||||
justifyContent="center"
|
||||
alignItems="stretch"
|
||||
spacing={3}
|
||||
>
|
||||
<Grid item md={6} xs={12}>
|
||||
<Card
|
||||
sx={{
|
||||
overflow: 'visible',
|
||||
marginTop: '30px',
|
||||
marginBottom: '30px'
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
{dailyData && (
|
||||
<Grid
|
||||
container
|
||||
direction="row"
|
||||
justifyContent="center"
|
||||
alignItems="stretch"
|
||||
spacing={3}
|
||||
>
|
||||
<Grid item md={6} xs={12}>
|
||||
<Card
|
||||
sx={{
|
||||
marginLeft: '20px'
|
||||
overflow: 'visible',
|
||||
marginTop: '30px',
|
||||
marginBottom: '30px'
|
||||
}}
|
||||
>
|
||||
<Box display="flex" alignItems="center">
|
||||
<Box>
|
||||
<Typography variant="subtitle1" noWrap>
|
||||
<FormattedMessage
|
||||
id="ac_load"
|
||||
defaultMessage="AC Load"
|
||||
/>
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
pt: 3
|
||||
marginLeft: '20px'
|
||||
}}
|
||||
></Box>
|
||||
</Box>
|
||||
>
|
||||
<Box display="flex" alignItems="center">
|
||||
<Box>
|
||||
<Typography variant="subtitle1" noWrap>
|
||||
<FormattedMessage
|
||||
id="ac_load"
|
||||
defaultMessage="AC Load"
|
||||
/>
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
pt: 3
|
||||
}}
|
||||
></Box>
|
||||
</Box>
|
||||
|
||||
{dailyData && (
|
||||
<ReactApexChart
|
||||
options={{
|
||||
...getChartOptions(
|
||||
|
|
@ -1387,42 +1395,41 @@ function Overview(props: OverviewProps) {
|
|||
type="line"
|
||||
height={400}
|
||||
/>
|
||||
)}
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid item md={6} xs={12}>
|
||||
<Card
|
||||
sx={{
|
||||
overflow: 'visible',
|
||||
marginTop: '30px',
|
||||
marginBottom: '30px'
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
</Card>
|
||||
</Grid>
|
||||
<Grid item md={6} xs={12}>
|
||||
<Card
|
||||
sx={{
|
||||
marginLeft: '20px'
|
||||
overflow: 'visible',
|
||||
marginTop: '30px',
|
||||
marginBottom: '30px'
|
||||
}}
|
||||
>
|
||||
<Box display="flex" alignItems="center">
|
||||
<Box>
|
||||
<Typography variant="subtitle1" noWrap>
|
||||
<FormattedMessage
|
||||
id="dc_load"
|
||||
defaultMessage="DC Load"
|
||||
/>
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
pt: 3
|
||||
marginLeft: '20px'
|
||||
}}
|
||||
></Box>
|
||||
</Box>
|
||||
{dailyData && (
|
||||
>
|
||||
<Box display="flex" alignItems="center">
|
||||
<Box>
|
||||
<Typography variant="subtitle1" noWrap>
|
||||
<FormattedMessage
|
||||
id="dc_load"
|
||||
defaultMessage="DC Load"
|
||||
/>
|
||||
</Typography>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box
|
||||
sx={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-start',
|
||||
pt: 3
|
||||
}}
|
||||
></Box>
|
||||
</Box>
|
||||
|
||||
<ReactApexChart
|
||||
options={{
|
||||
...getChartOptions(
|
||||
|
|
@ -1449,10 +1456,10 @@ function Overview(props: OverviewProps) {
|
|||
type="line"
|
||||
height={400}
|
||||
/>
|
||||
)}
|
||||
</Card>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
)}
|
||||
</Grid>
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
|||
{sortedInstallations
|
||||
// .filter(
|
||||
// (installation) =>
|
||||
// installation.status === -1 &&
|
||||
// installation.status === -1 &&
|
||||
// installation.testingMode == false
|
||||
// )
|
||||
.map((installation) => {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,11 @@ import { ProductIdContext } from '../../../contexts/ProductIdContextProvider';
|
|||
import { UserType } from '../../../interfaces/UserTypes';
|
||||
import SalidomoInstallation from './Installation';
|
||||
|
||||
function SalidomoInstallationTabs() {
|
||||
interface InstallationTabsProps {
|
||||
product: number;
|
||||
}
|
||||
|
||||
function SalidomoInstallationTabs(props: InstallationTabsProps) {
|
||||
const location = useLocation();
|
||||
const context = useContext(UserContext);
|
||||
const { currentUser } = context;
|
||||
|
|
@ -28,12 +32,10 @@ function SalidomoInstallationTabs() {
|
|||
];
|
||||
|
||||
const [currentTab, setCurrentTab] = useState<string>(undefined);
|
||||
const [fetchedInstallations, setFetchedInstallations] =
|
||||
useState<boolean>(false);
|
||||
|
||||
const {
|
||||
salidomoInstallations,
|
||||
fetchAllSalidomoInstallations,
|
||||
currentProduct,
|
||||
socket,
|
||||
openSocket,
|
||||
closeSocket
|
||||
|
|
@ -55,29 +57,14 @@ function SalidomoInstallationTabs() {
|
|||
}, [location]);
|
||||
|
||||
useEffect(() => {
|
||||
//The first time this component will be loaded, it needs to call the fetchAllSalidomoInstallations function from the InstallationsContextProvider
|
||||
if (salidomoInstallations.length === 0 && fetchedInstallations === false) {
|
||||
setProduct(props.product);
|
||||
}, [props.product]);
|
||||
|
||||
useEffect(() => {
|
||||
if (product == props.product) {
|
||||
fetchAllSalidomoInstallations();
|
||||
setFetchedInstallations(true);
|
||||
}
|
||||
}, [salidomoInstallations]);
|
||||
|
||||
useEffect(() => {
|
||||
//Since we know the ids of the installations we have access to, we need to open a web socket with the backend.
|
||||
if (salidomoInstallations && salidomoInstallations.length > 0) {
|
||||
if (!socket) {
|
||||
openSocket(1);
|
||||
} else if (currentProduct != 1) {
|
||||
//If there is any other open websocket for another product, close it.
|
||||
closeSocket();
|
||||
openSocket(1);
|
||||
}
|
||||
}
|
||||
}, [salidomoInstallations]);
|
||||
|
||||
useEffect(() => {
|
||||
setProduct(1);
|
||||
}, []);
|
||||
}, [product]);
|
||||
|
||||
const handleTabsChange = (_event: ChangeEvent<{}>, value: string): void => {
|
||||
setCurrentTab(value);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ function SodioHomeInstallationTabs() {
|
|||
const {
|
||||
sodiohomeInstallations,
|
||||
fetchAllSodiohomeInstallations,
|
||||
currentProduct,
|
||||
socket,
|
||||
openSocket,
|
||||
closeSocket
|
||||
|
|
@ -64,7 +63,7 @@ function SodioHomeInstallationTabs() {
|
|||
if (sodiohomeInstallations && sodiohomeInstallations.length > 0) {
|
||||
if (!socket) {
|
||||
openSocket(2);
|
||||
} else if (currentProduct != 2) {
|
||||
} else if (product != 2) {
|
||||
closeSocket();
|
||||
openSocket(2);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState } from 'react';
|
||||
import React, { useContext, useState } from 'react';
|
||||
import {
|
||||
CircularProgress,
|
||||
Container,
|
||||
|
|
@ -12,6 +12,7 @@ import {
|
|||
getHighestConnectionValue,
|
||||
JSONRecordData
|
||||
} from '../Log/graph.util';
|
||||
import { ProductIdContext } from '../../../contexts/ProductIdContextProvider';
|
||||
|
||||
interface TopologyProps {
|
||||
values: JSONRecordData;
|
||||
|
|
@ -26,6 +27,10 @@ function Topology(props: TopologyProps) {
|
|||
const highestConnectionValue =
|
||||
props.values != null ? getHighestConnectionValue(props.values) : 0;
|
||||
|
||||
const { product, setProduct } = useContext(ProductIdContext);
|
||||
|
||||
console.log('product VALUE IS ', product);
|
||||
|
||||
//console.log(props.values.DcDc.Dc.Battery.Voltage);
|
||||
|
||||
const [showValues, setShowValues] = useState(false);
|
||||
|
|
@ -514,14 +519,19 @@ function Topology(props: TopologyProps) {
|
|||
data: props.values?.Battery
|
||||
? {
|
||||
//value: props.values.Battery.Dc.Power for salimax,
|
||||
value: props.values.Battery.Power,
|
||||
value:
|
||||
product == 0
|
||||
? props.values.Battery.Dc.Power
|
||||
: props.values.Battery.Power,
|
||||
unit: 'W'
|
||||
}
|
||||
: undefined,
|
||||
amount: props.values?.Battery
|
||||
? getAmount(
|
||||
highestConnectionValue,
|
||||
props.values.Battery.Power
|
||||
product == 0
|
||||
? props.values.Battery.Dc.Power
|
||||
: props.values.Battery.Power
|
||||
)
|
||||
: 0,
|
||||
showValues: showValues
|
||||
|
|
@ -540,18 +550,27 @@ function Topology(props: TopologyProps) {
|
|||
},
|
||||
{
|
||||
//value: props.values.Battery.Dc.Voltage for salimax,
|
||||
value: props.values.Battery.Voltage,
|
||||
value:
|
||||
product === 0
|
||||
? props.values.Battery.Dc.Voltage
|
||||
: props.values.Battery.Voltage,
|
||||
unit: 'V'
|
||||
},
|
||||
{
|
||||
//value: props.values.Battery.Dc.Current for salimax,
|
||||
|
||||
value: props.values.Battery.Current,
|
||||
value:
|
||||
product == 0
|
||||
? props.values.Battery.Dc.Current
|
||||
: props.values.Battery.Current,
|
||||
unit: 'A'
|
||||
},
|
||||
{
|
||||
//value: props.values.Battery.Temperature for salimax,
|
||||
value: props.values.Battery.TemperatureCell1,
|
||||
value:
|
||||
product == 0
|
||||
? props.values.Battery.Temperature
|
||||
: props.values.Battery.TemperatureCell1,
|
||||
unit: '°C'
|
||||
}
|
||||
// {
|
||||
|
|
|
|||
|
|
@ -51,14 +51,18 @@ function CustomTreeItem(props: CustomTreeItemProps) {
|
|||
? routes.installations
|
||||
: installation.product == 1
|
||||
? routes.salidomo_installations
|
||||
: routes.sodiohome_installations;
|
||||
: installation.product == 2
|
||||
? routes.sodiohome_installations
|
||||
: routes.sodistore_installations;
|
||||
|
||||
let folder_path =
|
||||
product == 0
|
||||
? routes.installations
|
||||
: product == 1
|
||||
? routes.salidomo_installations
|
||||
: routes.sodiohome_installations;
|
||||
: installation.product == 2
|
||||
? routes.sodiohome_installations
|
||||
: routes.sodistore_installations;
|
||||
|
||||
if (installation.type != 'Folder') {
|
||||
navigate(
|
||||
|
|
@ -175,6 +179,8 @@ function CustomTreeItem(props: CustomTreeItemProps) {
|
|||
display:
|
||||
currentLocation.pathname ===
|
||||
routes.salidomo_installations + routes.tree ||
|
||||
currentLocation.pathname ===
|
||||
routes.sodistore_installations + routes.tree ||
|
||||
currentLocation.pathname === routes.installations + routes.tree ||
|
||||
currentLocation.pathname ===
|
||||
routes.sodiohome_installations + routes.tree ||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import routes from '../../../Resources/routes.json';
|
|||
import SalidomoInstallation from '../SalidomoInstallations/Installation';
|
||||
import Folder from './Folder';
|
||||
import SodioHomeInstallation from '../SodiohomeInstallations/Installation';
|
||||
import { ProductIdContext } from '../../../contexts/ProductIdContextProvider';
|
||||
|
||||
function InstallationTree() {
|
||||
const { foldersAndInstallations, fetchAllFoldersAndInstallations } =
|
||||
|
|
@ -36,8 +35,6 @@ function InstallationTree() {
|
|||
return 0;
|
||||
});
|
||||
|
||||
const { product } = useContext(ProductIdContext);
|
||||
|
||||
useEffect(() => {
|
||||
fetchAllFoldersAndInstallations();
|
||||
}, []);
|
||||
|
|
|
|||
|
|
@ -22,9 +22,10 @@ const InstallationsContextProvider = ({
|
|||
}: {
|
||||
children: ReactNode;
|
||||
}) => {
|
||||
const [salimaxInstallations, setSalimaxInstallations] = useState<
|
||||
I_Installation[]
|
||||
>([]);
|
||||
const [
|
||||
salimax_or_sodistore_Installations,
|
||||
setSalimax_Or_Sodistore_Installations
|
||||
] = useState<I_Installation[]>([]);
|
||||
const [salidomoInstallations, setSalidomoInstallations] = useState<
|
||||
I_Installation[]
|
||||
>([]);
|
||||
|
|
@ -38,8 +39,11 @@ const InstallationsContextProvider = ({
|
|||
const navigate = useNavigate();
|
||||
const tokencontext = useContext(TokenContext);
|
||||
const { removeToken } = tokencontext;
|
||||
const [socket, setSocket] = useState<WebSocket>(null);
|
||||
const [currentProduct, setcurrentProduct] = useState<number>(0);
|
||||
// const [socket, setSocket] = useState<WebSocket>(null);
|
||||
|
||||
const socket = useRef<WebSocket | null>(null); // Using useRef instead of useState
|
||||
|
||||
//const [currentProduct, setcurrentProduct] = useState<number>(0);
|
||||
|
||||
//Store pending updates and apply them in batches
|
||||
const pendingUpdates = useRef<
|
||||
|
|
@ -66,16 +70,18 @@ const InstallationsContextProvider = ({
|
|||
: installation;
|
||||
});
|
||||
|
||||
const updatedSalimax = salimaxInstallations.map((installation) => {
|
||||
const update = pendingUpdates.current[installation.id];
|
||||
return update
|
||||
? {
|
||||
...installation,
|
||||
status: update.status,
|
||||
testingMode: update.testingMode
|
||||
}
|
||||
: installation;
|
||||
});
|
||||
const updatedSalimax = salimax_or_sodistore_Installations.map(
|
||||
(installation) => {
|
||||
const update = pendingUpdates.current[installation.id];
|
||||
return update
|
||||
? {
|
||||
...installation,
|
||||
status: update.status,
|
||||
testingMode: update.testingMode
|
||||
}
|
||||
: installation;
|
||||
}
|
||||
);
|
||||
|
||||
const updatedSodiohome = sodiohomeInstallations.map((installation) => {
|
||||
const update = pendingUpdates.current[installation.id];
|
||||
|
|
@ -89,12 +95,16 @@ const InstallationsContextProvider = ({
|
|||
});
|
||||
|
||||
setSalidomoInstallations(updatedSalidomo);
|
||||
setSalimaxInstallations(updatedSalimax);
|
||||
setSalimax_Or_Sodistore_Installations(updatedSalimax);
|
||||
setSodiohomeInstallations(updatedSodiohome);
|
||||
|
||||
// Clear the pending updates after applying
|
||||
pendingUpdates.current = {};
|
||||
}, [salidomoInstallations, salimaxInstallations, sodiohomeInstallations]);
|
||||
}, [
|
||||
salidomoInstallations,
|
||||
salimax_or_sodistore_Installations,
|
||||
sodiohomeInstallations
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
|
|
@ -104,27 +114,20 @@ const InstallationsContextProvider = ({
|
|||
return () => clearInterval(timer); // Cleanup timer on component unmount
|
||||
}, [applyBatchUpdates]);
|
||||
|
||||
const openSocket = (product) => {
|
||||
setcurrentProduct(product);
|
||||
const openSocket = (installationsToSend) => {
|
||||
if (socket.current) {
|
||||
socket.current.close();
|
||||
socket.current = null;
|
||||
}
|
||||
const tokenString = localStorage.getItem('token');
|
||||
const token = tokenString !== null ? tokenString : '';
|
||||
const urlWithToken = `wss://monitor.innov.energy/api/CreateWebSocket?authToken=${token}`;
|
||||
|
||||
const socket = new WebSocket(urlWithToken);
|
||||
|
||||
socket.addEventListener('open', () => {
|
||||
let installationsToSend = [];
|
||||
|
||||
if (product === 0) {
|
||||
installationsToSend = salimaxInstallations;
|
||||
} else if (product === 1) {
|
||||
installationsToSend = salidomoInstallations;
|
||||
} else if (product === 2) {
|
||||
installationsToSend = sodiohomeInstallations;
|
||||
}
|
||||
const new_socket = new WebSocket(urlWithToken);
|
||||
|
||||
new_socket.addEventListener('open', () => {
|
||||
// Send the corresponding installation IDs to the backend
|
||||
socket.send(
|
||||
new_socket.send(
|
||||
JSON.stringify(
|
||||
installationsToSend.map((installation) => installation.id)
|
||||
)
|
||||
|
|
@ -133,12 +136,12 @@ const InstallationsContextProvider = ({
|
|||
|
||||
// Periodically send ping messages to keep the connection alive
|
||||
const pingInterval = setInterval(() => {
|
||||
if (socket.readyState === WebSocket.OPEN) {
|
||||
socket.send(JSON.stringify([-1]));
|
||||
if (new_socket.readyState === WebSocket.OPEN) {
|
||||
new_socket.send(JSON.stringify([-1]));
|
||||
}
|
||||
}, 10000);
|
||||
|
||||
socket.addEventListener('message', (event) => {
|
||||
new_socket.addEventListener('message', (event) => {
|
||||
const message = JSON.parse(event.data); // Parse the JSON data
|
||||
if (message.id !== -1) {
|
||||
//For each received message (except the first one which is a batch, call the updateInstallationStatus function in order to import the message to the pendingUpdates list
|
||||
|
|
@ -150,36 +153,42 @@ const InstallationsContextProvider = ({
|
|||
}
|
||||
});
|
||||
|
||||
socket.addEventListener('close', () => {
|
||||
new_socket.addEventListener('close', () => {
|
||||
clearInterval(pingInterval); // Cleanup ping interval on socket close
|
||||
setSocket(null);
|
||||
//socket.current = null;
|
||||
});
|
||||
|
||||
setSocket(socket);
|
||||
socket.current = new_socket;
|
||||
};
|
||||
|
||||
const closeSocket = () => socket?.close();
|
||||
const closeSocket = () => socket?.current?.close();
|
||||
|
||||
const fetchAllInstallations = useCallback(async () => {
|
||||
axiosConfig
|
||||
.get('/GetAllInstallations')
|
||||
.then((res: AxiosResponse<I_Installation[]>) =>
|
||||
setSalimaxInstallations(res.data)
|
||||
)
|
||||
.catch((err: AxiosError) => {
|
||||
if (err.response?.status === 401) {
|
||||
removeToken();
|
||||
navigate(routes.login);
|
||||
}
|
||||
});
|
||||
}, [navigate, removeToken]);
|
||||
// Function to fetch installations and manage the socket
|
||||
const fetchAllInstallations = useCallback(
|
||||
async (product: number) => {
|
||||
axiosConfig
|
||||
.get(`/GetAllInstallationsFromProduct?product=${product}`)
|
||||
.then((res: AxiosResponse<I_Installation[]>) => {
|
||||
setSalimax_Or_Sodistore_Installations(res.data); // Update installations
|
||||
openSocket(res.data); // Open a new socket after installations are fetched
|
||||
})
|
||||
.catch((err: AxiosError) => {
|
||||
if (err.response?.status === 401) {
|
||||
removeToken();
|
||||
navigate(routes.login);
|
||||
}
|
||||
});
|
||||
},
|
||||
[navigate, removeToken]
|
||||
);
|
||||
|
||||
const fetchAllSalidomoInstallations = useCallback(async () => {
|
||||
axiosConfig
|
||||
.get('/GetAllSalidomoInstallations')
|
||||
.then((res: AxiosResponse<I_Installation[]>) =>
|
||||
setSalidomoInstallations(res.data)
|
||||
)
|
||||
.then((res: AxiosResponse<I_Installation[]>) => {
|
||||
setSalidomoInstallations(res.data);
|
||||
openSocket(res.data);
|
||||
})
|
||||
.catch((err: AxiosError) => {
|
||||
if (err.response?.status === 401) {
|
||||
removeToken();
|
||||
|
|
@ -244,7 +253,7 @@ const InstallationsContextProvider = ({
|
|||
setUpdated(true);
|
||||
setLoading(false);
|
||||
if (formValues.product === 0 && view === 'installation')
|
||||
fetchAllInstallations();
|
||||
fetchAllInstallations(formValues.product);
|
||||
else if (formValues.product === 1 && view === 'installation')
|
||||
fetchAllSalidomoInstallations();
|
||||
else if (formValues.product === 2 && view === 'installation')
|
||||
|
|
@ -278,7 +287,7 @@ const InstallationsContextProvider = ({
|
|||
setUpdated(true);
|
||||
setLoading(false);
|
||||
if (formValues.product === 0 && view === 'installation')
|
||||
fetchAllInstallations();
|
||||
fetchAllInstallations(formValues.product);
|
||||
else if (formValues.product === 1 && view === 'installation')
|
||||
fetchAllSalidomoInstallations();
|
||||
else if (formValues.product === 2 && view === 'installation')
|
||||
|
|
@ -369,7 +378,7 @@ const InstallationsContextProvider = ({
|
|||
|
||||
const contextValue = useMemo(
|
||||
() => ({
|
||||
salimaxInstallations,
|
||||
salimax_or_sodistore_Installations,
|
||||
salidomoInstallations,
|
||||
sodiohomeInstallations,
|
||||
foldersAndInstallations,
|
||||
|
|
@ -389,21 +398,21 @@ const InstallationsContextProvider = ({
|
|||
createFolder,
|
||||
updateFolder,
|
||||
deleteFolder,
|
||||
currentProduct,
|
||||
//currentProduct,
|
||||
socket,
|
||||
openSocket,
|
||||
closeSocket
|
||||
}),
|
||||
[
|
||||
salimaxInstallations,
|
||||
salimax_or_sodistore_Installations,
|
||||
salidomoInstallations,
|
||||
sodiohomeInstallations,
|
||||
foldersAndInstallations,
|
||||
loading,
|
||||
error,
|
||||
updated,
|
||||
socket,
|
||||
currentProduct
|
||||
socket
|
||||
//currentProduct
|
||||
]
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,9 +8,11 @@ interface ProductIdContextType {
|
|||
accessToSalimax: boolean;
|
||||
accessToSalidomo: boolean;
|
||||
accessToSodiohome: boolean;
|
||||
accessToSodistore: boolean;
|
||||
setAccessToSalimax: (access: boolean) => void;
|
||||
setAccessToSalidomo: (access: boolean) => void;
|
||||
setAccessToSodiohome: (access: boolean) => void;
|
||||
setAccessToSodistore: (access: boolean) => void;
|
||||
}
|
||||
|
||||
// Create the context.
|
||||
|
|
@ -37,6 +39,10 @@ export const ProductIdContextProvider = ({
|
|||
const storedValue = localStorage.getItem('accessToSodiohome');
|
||||
return storedValue === 'true';
|
||||
});
|
||||
const [accessToSodistore, setAccessToSodistore] = useState(() => {
|
||||
const storedValue = localStorage.getItem('accessToSodistore');
|
||||
return storedValue === 'true';
|
||||
});
|
||||
// const [product, setProduct] = useState(location.includes('salidomo') ? 1 : 0);
|
||||
// const [product, setProduct] = useState<number>(
|
||||
// productMapping[Object.keys(productMapping).find((key) => location.includes(key)) || ''] || -1
|
||||
|
|
@ -70,6 +76,10 @@ export const ProductIdContextProvider = ({
|
|||
setAccessToSodiohome(access);
|
||||
localStorage.setItem('accessToSodiohome', JSON.stringify(access));
|
||||
};
|
||||
const changeAccessSodistore = (access: boolean) => {
|
||||
setAccessToSodistore(access);
|
||||
localStorage.setItem('accessToSodistore', JSON.stringify(access));
|
||||
};
|
||||
|
||||
return (
|
||||
<ProductIdContext.Provider
|
||||
|
|
@ -79,9 +89,11 @@ export const ProductIdContextProvider = ({
|
|||
accessToSalimax,
|
||||
accessToSalidomo,
|
||||
accessToSodiohome,
|
||||
accessToSodistore,
|
||||
setAccessToSalimax: changeAccessSalimax,
|
||||
setAccessToSalidomo: changeAccessSalidomo,
|
||||
setAccessToSodiohome: changeAccessSodiohome
|
||||
setAccessToSodiohome: changeAccessSodiohome,
|
||||
setAccessToSodistore: changeAccessSodistore
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
|
|
|||
|
|
@ -287,6 +287,7 @@ export const transformInputToBatteryViewDataJson = async (
|
|||
};
|
||||
|
||||
export const transformInputToDailyDataJson = async (
|
||||
product: number,
|
||||
s3Credentials: I_S3Credentials,
|
||||
id: number,
|
||||
start_time?: UnixTime,
|
||||
|
|
@ -296,14 +297,17 @@ export const transformInputToDailyDataJson = async (
|
|||
chartOverview: overviewInterface;
|
||||
}> => {
|
||||
const prefixes = ['', 'k', 'M', 'G', 'T'];
|
||||
|
||||
const MAX_NUMBER = 9999999;
|
||||
const pathsToSearch = [
|
||||
'Battery.Soc',
|
||||
product == 0 ? 'Battery.Temperature' : 'Battery.TemperatureCell1',
|
||||
|
||||
//'Battery.Temperature' for salimax,
|
||||
'Battery.TemperatureCell1',
|
||||
//'Battery.TemperatureCell1',
|
||||
product == 0 ? 'Battery.Dc.Power' : 'Battery.Power',
|
||||
//'Battery.Dc.Power' for salimax,
|
||||
'Battery.Power',
|
||||
// 'Battery.Power',
|
||||
'GridMeter.Ac.Power.Active',
|
||||
'PvOnDc.Dc.Power',
|
||||
'DcDc.Dc.Link.Voltage',
|
||||
|
|
@ -400,6 +404,7 @@ export const transformInputToDailyDataJson = async (
|
|||
Object.keys(results[i]).length - 1
|
||||
];
|
||||
const result = results[i][timestamp];
|
||||
//console.log(result);
|
||||
let category_index = 0;
|
||||
// eslint-disable-next-line @typescript-eslint/no-loop-func
|
||||
pathsToSearch.forEach((path) => {
|
||||
|
|
@ -596,6 +601,7 @@ export const transformInputToAggregatedDataJson = async (
|
|||
) {
|
||||
// Handle not available or try later case
|
||||
} else {
|
||||
// console.log(result);
|
||||
dateList.push(currentDay.format('DD-MM'));
|
||||
pathsToSearch.forEach((path) => {
|
||||
const value = path
|
||||
|
|
|
|||
|
|
@ -164,8 +164,12 @@ function SidebarMenu() {
|
|||
const { closeSidebar } = useContext(SidebarContext);
|
||||
const context = useContext(UserContext);
|
||||
const { currentUser, setUser } = context;
|
||||
const { accessToSalimax, accessToSalidomo, accessToSodiohome } =
|
||||
useContext(ProductIdContext);
|
||||
const {
|
||||
accessToSalimax,
|
||||
accessToSodistore,
|
||||
accessToSalidomo,
|
||||
accessToSodiohome
|
||||
} = useContext(ProductIdContext);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
@ -197,6 +201,25 @@ function SidebarMenu() {
|
|||
</List>
|
||||
)}
|
||||
|
||||
<List component="div">
|
||||
<ListItem component="div">
|
||||
<Button
|
||||
disableRipple
|
||||
component={RouterLink}
|
||||
onClick={closeSidebar}
|
||||
to="/sodistore_installations"
|
||||
startIcon={<BrightnessLowTwoToneIcon />}
|
||||
>
|
||||
<Box sx={{ marginTop: '3px' }}>
|
||||
<FormattedMessage
|
||||
id="sodistore"
|
||||
defaultMessage="Sodistore"
|
||||
/>
|
||||
</Box>
|
||||
</Button>
|
||||
</ListItem>
|
||||
</List>
|
||||
|
||||
{accessToSalidomo && (
|
||||
<List component="div">
|
||||
<ListItem component="div">
|
||||
|
|
|
|||
Loading…
Reference in New Issue