Compare commits

..

2 Commits

22 changed files with 543 additions and 381 deletions

View File

@ -16,7 +16,8 @@ dotnet publish \
-r linux-x64
echo -e "\n============================ Deploy ============================\n"
ip_addresses=("10.2.3.115" "10.2.3.104" "10.2.4.33" "10.2.4.32" "10.2.4.36" "10.2.4.35" "10.2.4.154" "10.2.4.113" "10.2.4.29" "10.2.4.211")
ip_addresses=("10.2.3.115" "10.2.3.104" "10.2.4.33" "10.2.4.32" "10.2.4.36" "10.2.4.35" "10.2.4.154" "10.2.4.113" "10.2.4.29")
for ip_address in "${ip_addresses[@]}"; do
rsync -v \

View File

@ -197,16 +197,17 @@ public static class Controller
(calibrationChargeForced == CalibrationChargeType.RepetitivelyEvery && repetitiveCalibrationRequired);
Console.WriteLine("Next Repetitive calibration charge date is "+statusRecord.Config.DayAndTimeForRepetitiveCalibration);
Console.WriteLine("Next Additional calibration charge date is "+statusRecord.Config.DayAndTimeForAdditionalCalibration);
//Console.WriteLine("Time now is "+DateTime.Now);
if (statusRecord.Battery is not null)
{
if (calibrationChargeForced == CalibrationChargeType.AdditionallyOnce && statusRecord.Battery.Eoc )
{
statusRecord.Config.ForceCalibrationChargeState = CalibrationChargeType.RepetitivelyEvery;
_hasAdditionalCalibrationChargeChecked = false;
//_hasAdditionalCalibrationChargeChecked = false;
}
else if (calibrationChargeForced == CalibrationChargeType.RepetitivelyEvery && statusRecord.Battery.Eoc )
else if (calibrationChargeForced == CalibrationChargeType.RepetitivelyEvery && statusRecord.Battery.Eoc && _hasRepetitiveCalibrationChargeChecked)
{
statusRecord.Config.DayAndTimeForRepetitiveCalibration = statusRecord.Config.DayAndTimeForRepetitiveCalibration.AddDays(7);
_hasRepetitiveCalibrationChargeChecked = false;
@ -217,30 +218,41 @@ public static class Controller
private static Boolean RepetitiveCalibrationDateHasBeenPassed(DateTime calibrationChargeDate)
{
if (!_hasRepetitiveCalibrationChargeChecked)
{
// if (!_hasRepetitiveCalibrationChargeChecked)
// {
// if (DateTime.Now >= calibrationChargeDate )
// {
// _hasRepetitiveCalibrationChargeChecked = true;
// return true;
// }
// return false;
// }
// return true;
if (DateTime.Now >= calibrationChargeDate )
{
_hasRepetitiveCalibrationChargeChecked = true;
return true;
}
return false;
}
return true;
}
private static Boolean AdditionalCalibrationDateHasBeenPassed(DateTime calibrationChargeDate)
{
if (!_hasAdditionalCalibrationChargeChecked)
{
// if (!_hasAdditionalCalibrationChargeChecked)
// {
if (DateTime.Now >= calibrationChargeDate )
{
_hasAdditionalCalibrationChargeChecked = true;
//_hasAdditionalCalibrationChargeChecked = true;
return true;
}
return false;
}
return true;
// }
// return true;
}

View File

@ -11,6 +11,7 @@ public static class MiddlewareAgent
{
public static UdpClient UdpListener = null!;
private static IPAddress? _controllerIpAddress;
private static EndPoint? _endPoint;
public static void InitializeCommunicationToMiddleware()
{
@ -21,11 +22,11 @@ public static class MiddlewareAgent
}
const Int32 udpPort = 9000;
var endPoint = new IPEndPoint(_controllerIpAddress, udpPort);
_endPoint = new IPEndPoint(_controllerIpAddress, udpPort);
UdpListener = new UdpClient();
UdpListener.Client.Blocking = false;
UdpListener.Client.Bind(endPoint);
UdpListener.Client.Bind(_endPoint);
}
private static IPAddress FindVpnIp()
@ -54,6 +55,7 @@ public static class MiddlewareAgent
{
if (UdpListener.Available > 0)
{
IPEndPoint? serverEndpoint = null;
var replyMessage = "ACK";
@ -72,6 +74,13 @@ public static class MiddlewareAgent
return config;
}
if (!_endPoint.Equals((IPEndPoint)UdpListener.Client.LocalEndPoint))
{
Console.WriteLine("UDP address has changed, rebinding...");
InitializeCommunicationToMiddleware();
}
return null;
}

View File

@ -1,4 +1,4 @@
#define Amax
#undef Amax
#undef GridLimit
using System.Reactive.Linq;

View File

@ -31,6 +31,7 @@ interface BatteryViewProps {
values: TopologyValues;
s3Credentials: I_S3Credentials;
installationId: number;
productNum: number;
}
function BatteryView(props: BatteryViewProps) {
@ -157,6 +158,7 @@ function BatteryView(props: BatteryViewProps) {
s3Credentials={props.s3Credentials}
batteryData={findBatteryData(battery.BatteryId)}
installationId={props.installationId}
productNum={props.productNum}
></DetailedBatteryView>
}
/>
@ -272,23 +274,29 @@ function BatteryView(props: BatteryViewProps) {
battery.AverageTemperature.unit}
</TableCell>
{props.productNum === 0 && (
<>
<TableCell
style={{
width: '20%',
textAlign: 'center',
padding: '8px',
fontWeight:
battery.Warnings.value !== '' ? 'bold' : 'inherit',
battery.Warnings.value !== ''
? 'bold'
: 'inherit',
backgroundColor:
battery.Warnings.value === '' ? 'inherit' : '#ff9900',
battery.Warnings.value === ''
? 'inherit'
: '#ff9900',
color:
battery.Warnings.value != '' ? 'black' : 'inherit'
}}
>
{battery.Warnings.value === '' ? (
'None'
) : battery.Warnings.value.toString().split('-').length >
1 ? (
) : battery.Warnings.value.toString().split('-')
.length > 1 ? (
<Link
style={{ color: 'black' }}
to={
@ -313,14 +321,17 @@ function BatteryView(props: BatteryViewProps) {
fontWeight:
battery.Alarms.value !== '' ? 'bold' : 'inherit',
backgroundColor:
battery.Alarms.value === '' ? 'inherit' : '#FF033E',
color: battery.Alarms.value != '' ? 'black' : 'inherit'
battery.Alarms.value === ''
? 'inherit'
: '#FF033E',
color:
battery.Alarms.value != '' ? 'black' : 'inherit'
}}
>
{battery.Alarms.value === '' ? (
'None'
) : battery.Alarms.value.toString().split('-').length >
1 ? (
) : battery.Alarms.value.toString().split('-')
.length > 1 ? (
<Link
style={{ color: 'black' }}
to={
@ -338,6 +349,8 @@ function BatteryView(props: BatteryViewProps) {
battery.Alarms.value
)}
</TableCell>
</>
)}
</TableRow>
))}
</TableBody>

View File

@ -25,6 +25,7 @@ interface DetailedBatteryViewProps {
s3Credentials: I_S3Credentials;
batteryData: Battery;
installationId: number;
productNum: number;
}
function DetailedBatteryView(props: DetailedBatteryViewProps) {
@ -273,6 +274,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
<ArrowBackIcon />
</IconButton>
{props.productNum === 0 && (
<Button
variant="contained"
onClick={handleUpdateFirmware}
@ -289,6 +291,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
defaultMessage="Update Firmware"
/>
</Button>
)}
</Grid>
</Grid>
<Grid container>
@ -310,7 +313,8 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
style={{
...batteryStringStyle,
backgroundColor:
props.batteryData.String1Active.value == 'True'
props.batteryData.String1Active.value == 'True' ||
props.batteryData.String4Active.value == 0
? '#32CD32'
: '#FF033E'
}}
@ -319,7 +323,8 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
style={{
...batteryStringStyle,
backgroundColor:
props.batteryData.String2Active.value == 'True'
props.batteryData.String2Active.value == 'True' ||
props.batteryData.String4Active.value == 0
? '#32CD32'
: '#FF033E'
}}
@ -328,7 +333,8 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
style={{
...batteryStringStyle,
backgroundColor:
props.batteryData.String3Active.value == 'True'
props.batteryData.String3Active.value == 'True' ||
props.batteryData.String4Active.value == 0
? '#32CD32'
: '#FF033E'
}}
@ -337,7 +343,8 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
style={{
...batteryStringStyle,
backgroundColor:
props.batteryData.String4Active.value == 'True'
props.batteryData.String4Active.value == 'True' ||
props.batteryData.String4Active.value == 0
? '#32CD32'
: '#FF033E'
}}
@ -346,7 +353,8 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
style={{
...batteryStringStyle,
backgroundColor:
props.batteryData.String5Active.value == 'True'
props.batteryData.String5Active.value == 'True' ||
props.batteryData.String4Active.value == 0
? '#32CD32'
: '#FF033E'
}}
@ -514,6 +522,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
props.batteryData.Power.unit}
</TableCell>
</TableRow>
<TableRow>
<TableCell
component="th"
@ -609,6 +618,8 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
</Card>
</Grid>
{/*----------------------------------------------------------------------------------------------------------------------------------*/}
{props.productNum === 0 && (
<>
<Grid item md={3} xs={3}>
<Card
sx={{
@ -799,6 +810,8 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
</TableContainer>
</Card>
</Grid>
</>
)}
{/*----------------------------------------------------------------------------------------------------------------------------------*/}
<Grid item md={3} xs={3}>
@ -807,6 +820,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
overflow: 'visible',
marginTop: '30px',
marginLeft: '20px',
marginBottom: '20px',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
@ -992,6 +1006,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
</Grid>
{/*----------------------------------------------------------------------------------------------------------------------------------*/}
<Grid item md={3} xs={3}>
<Card
sx={{
@ -1044,6 +1059,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
props.batteryData.Eoc.unit}
</TableCell>
</TableRow>
<TableRow>
<TableCell
component="th"
@ -1066,6 +1082,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
props.batteryData.SerialNumber.unit}
</TableCell>
</TableRow>
<TableRow>
<TableCell
component="th"
@ -1110,6 +1127,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
props.batteryData.TimeSinceTOC.unit}
</TableCell>
</TableRow>
{props.productNum === 0 && (
<TableRow>
<TableCell
component="th"
@ -1132,6 +1150,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
props.batteryData.CalibrationChargeRequested.unit}
</TableCell>
</TableRow>
)}
<TableRow>
<TableCell
component="th"
@ -1181,6 +1200,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
</TableContainer>
</Card>
</Grid>
{/*----------------------------------------------------------------------------------------------------------------------------------*/}
{/*<Grid item md={1.5} xs={1.5}>*/}

View File

@ -43,7 +43,7 @@ function Configuration(props: ConfigurationProps) {
const CalibrationChargeOptions = [
'Repetitive Calibration',
'Additional Calibration',
'Force Calibration Now'
'Force Permanent Calibration Now'
];
const CalibrationChargeOptionsController = [
@ -93,13 +93,11 @@ function Configuration(props: ConfigurationProps) {
CalibrationChargeOptionsController.indexOf(
props.values.calibrationChargeState[0].value.toString()
) == 0
? dayjs
.utc(props.values.repetitiveCalibrationChargeDate[0].value)
.add(localOffset, 'minute')
? dayjs(props.values.repetitiveCalibrationChargeDate[0].value)
// .add(localOffset, 'minute')
.toDate()
: dayjs
.utc(props.values.additionalCalibrationChargeDate[0].value)
.add(localOffset, 'minute')
: dayjs(props.values.additionalCalibrationChargeDate[0].value)
// .add(localOffset, 'minute')
.toDate()
});
@ -129,9 +127,14 @@ function Configuration(props: ConfigurationProps) {
minimumSoC: formValues.minimumSoC,
gridSetPoint: formValues.gridSetPoint,
CalibrationChargeState: formValues.CalibrationChargeState,
calibrationChargeDate: dayjs(formValues.calibrationChargeDate).toDate()
calibrationChargeDate: dayjs
.utc(formValues.calibrationChargeDate)
.add(localOffset, 'minute')
.toDate()
};
// console.log('will send ', dayjs(formValues.calibrationChargeDate));
setLoading(true);
const res = await axiosConfig
.post(
@ -157,9 +160,11 @@ function Configuration(props: ConfigurationProps) {
};
const handleConfirm = (newDate) => {
//console.log('non adapted day is ', newDate);
//console.log('adapted day is ', dayjs.utc(newDate).toDate());
setFormValues({
...formValues,
['calibrationChargeDate']: dayjs.utc(newDate).toDate()
['calibrationChargeDate']: dayjs(newDate).toDate()
});
};
@ -170,6 +175,7 @@ function Configuration(props: ConfigurationProps) {
if (difference < 0) {
difference += 7;
}
const adjustedDate = currentDate.add(difference, 'day');
setFormValues({
...formValues,
@ -185,13 +191,11 @@ function Configuration(props: ConfigurationProps) {
),
['calibrationChargeDate']:
CalibrationChargeOptions.indexOf(event.target.value) == 0
? dayjs
.utc(props.values.repetitiveCalibrationChargeDate[0].value)
.add(localOffset, 'minute')
? dayjs(props.values.repetitiveCalibrationChargeDate[0].value)
// .add(localOffset, 'minute')
.toDate()
: dayjs
.utc(props.values.additionalCalibrationChargeDate[0].value)
.add(localOffset, 'minute')
: dayjs(props.values.additionalCalibrationChargeDate[0].value)
// .add(localOffset, 'minute')
.toDate()
});
};
@ -349,7 +353,7 @@ function Configuration(props: ConfigurationProps) {
format="DD/MM/YYYY HH:mm"
ampm={false}
label="Select Next Calibration Charge Date"
value={dayjs.utc(formValues.calibrationChargeDate)}
value={dayjs(formValues.calibrationChargeDate)}
onChange={handleConfirm}
sx={{
marginTop: 2
@ -397,8 +401,8 @@ function Configuration(props: ConfigurationProps) {
<TimePicker
ampm={false}
label="Calibration Charge Hour"
value={dayjs.utc(formValues.calibrationChargeDate)}
onChange={handleConfirm}
value={dayjs(formValues.calibrationChargeDate)}
onChange={(newTime) => handleConfirm(dayjs(newTime))}
/>
</LocalizationProvider>
</div>

View File

@ -307,7 +307,7 @@ function Information(props: InformationProps) {
label="S3 Bucket Name"
name="s3writesecretkey"
value={
formValues.id +
formValues.s3BucketId +
'-3e5b3069-214a-43ee-8d85-57d72000c19d'
}
variant="outlined"

View File

@ -37,7 +37,7 @@ function InformationSalidomo(props: InformationSalidomoProps) {
const { currentUser } = context;
const theme = useTheme();
const [formValues, setFormValues] = useState(props.values);
const requiredFields = ['name', 'region', 'location', 'country'];
const requiredFields = ['installationName', 'region', 'location', 'country'];
const [openModalDeleteInstallation, setOpenModalDeleteInstallation] =
useState(false);
const navigate = useNavigate();
@ -194,7 +194,7 @@ function InformationSalidomo(props: InformationSalidomoProps) {
/>
}
name="installationName"
value={formValues.name}
value={formValues.installationName}
onChange={handleChange}
variant="outlined"
fullWidth
@ -280,7 +280,8 @@ function InformationSalidomo(props: InformationSalidomoProps) {
label="S3 Bucket Name"
name="s3writesecretkey"
value={
formValues.id + '-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e'
formValues.s3BucketId +
'-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e'
}
variant="outlined"
fullWidth

View File

@ -102,11 +102,11 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
<TableBody>
{props.installations.map((installation) => {
const isInstallationSelected =
installation.id === selectedInstallation;
installation.s3BucketId === selectedInstallation;
const status = getStatus(installation.id);
const rowStyles =
isRowHovered === installation.id
isRowHovered === installation.s3BucketId
? {
cursor: 'pointer',
backgroundColor: theme.colors.primary.lighter
@ -116,13 +116,15 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
return (
<TableRow
hover
key={installation.id}
key={installation.s3BucketId}
selected={isInstallationSelected}
style={rowStyles}
onClick={() =>
handleSelectOneInstallation(installation.id)
handleSelectOneInstallation(installation.s3BucketId)
}
onMouseEnter={() =>
handleRowMouseEnter(installation.s3BucketId)
}
onMouseEnter={() => handleRowMouseEnter(installation.id)}
onMouseLeave={() => handleRowMouseLeave()}
>
<TableCell>

View File

@ -1,5 +1,11 @@
import React, { useContext, useEffect, useState } from 'react';
import { Card, CircularProgress, Grid, Typography } from '@mui/material';
import {
Card,
CircularProgress,
Container,
Grid,
Typography
} from '@mui/material';
import { I_Installation } from 'src/interfaces/InstallationTypes';
import { UserContext } from 'src/contexts/userContext';
import AccessContextProvider from 'src/contexts/AccessContextProvider';
@ -39,6 +45,14 @@ function Installation(props: singleInstallationProps) {
const [currentTab, setCurrentTab] = useState<string>(undefined);
const [values, setValues] = useState<TopologyValues | null>(null);
const status = getStatus(props.current_installation.id);
const [
failedToCommunicateWithInstallation,
setFailedToCommunicateWithInstallation
] = useState(0);
const [
openModalUnableToCommunicateWIthInstallation,
setOpenModalUnableToCommunicateWIthInstallation
] = useState(false);
if (props.current_installation == undefined) {
return null;
@ -48,14 +62,15 @@ function Installation(props: singleInstallationProps) {
s3Region: props.current_installation.s3Region,
s3Provider: props.current_installation.s3Provider,
s3Key: props.current_installation.s3Key,
s3Secret: props.current_installation.s3Secret
s3Secret: props.current_installation.s3Secret,
s3BucketId: props.current_installation.s3BucketId
};
const s3Bucket =
props.current_installation.product === 0
? props.current_installation.id.toString() +
? props.current_installation.s3BucketId.toString() +
'-3e5b3069-214a-43ee-8d85-57d72000c19d'
: props.current_installation.id.toString() +
: props.current_installation.s3BucketId.toString() +
'-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e';
const s3Credentials = { s3Bucket, ...S3data };
@ -67,6 +82,8 @@ function Installation(props: singleInstallationProps) {
const res = await fetchData(now, s3Credentials);
if (res != FetchResult.notAvailable && res != FetchResult.tryLater) {
setFailedToCommunicateWithInstallation(0);
setOpenModalUnableToCommunicateWIthInstallation(false);
setValues(
extractValues({
time: now,
@ -74,6 +91,13 @@ function Installation(props: singleInstallationProps) {
})
);
return true;
} else {
setFailedToCommunicateWithInstallation((prevCount) => {
if (prevCount + 1 >= 3) {
setOpenModalUnableToCommunicateWIthInstallation(true);
}
return prevCount + 1;
});
}
} catch (err) {
return false;
@ -99,6 +123,12 @@ function Installation(props: singleInstallationProps) {
setCurrentTab(path[path.length - 1]);
}, [location]);
useEffect(() => {
if (status === -1) {
setOpenModalUnableToCommunicateWIthInstallation(true);
}
}, [status]);
useEffect(() => {
if (
currentTab == 'live' ||
@ -118,7 +148,7 @@ function Installation(props: singleInstallationProps) {
fetchDataOnlyOneTime();
}
// Cleanup function to cancel interval and update isMounted when unmounted
// Cleanup function to cancel interval
return () => {
if (
currentTab == 'live' ||
@ -130,6 +160,10 @@ function Installation(props: singleInstallationProps) {
}
}, [currentTab, location]);
const UnableToCommunicateModalHandleOk = () => {
setOpenModalUnableToCommunicateWIthInstallation(false);
};
return (
<>
<Grid item xs={12} md={12}>
@ -264,6 +298,31 @@ function Installation(props: singleInstallationProps) {
alignItems="stretch"
spacing={0}
>
{openModalUnableToCommunicateWIthInstallation && (
<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}
>
Unable to communicate with the installation
</Typography>
<Typography variant="body2" style={{ color: 'black' }}>
Please wait or refresh the page
</Typography>
</Container>
)}
<Routes>
<Route
path={routes.information}
@ -283,6 +342,7 @@ function Installation(props: singleInstallationProps) {
values={values}
s3Credentials={s3Credentials}
installationId={props.current_installation.id}
productNum={props.current_installation.product}
></BatteryView>
}
></Route>

View File

@ -63,11 +63,11 @@ function InstallationSearch(props: installationSearchProps) {
{filteredData.map((installation) => {
return (
<Route
key={installation.id}
path={routes.installation + installation.id + '*'}
key={installation.s3BucketId}
path={routes.installation + installation.s3BucketId + '*'}
element={
<Installation
key={installation.id}
key={installation.s3BucketId}
current_installation={installation}
type="installation"
></Installation>

View File

@ -25,6 +25,7 @@ function installationForm(props: installationFormProps) {
const theme = useTheme();
const [open, setOpen] = useState(true);
const [formValues, setFormValues] = useState<Partial<I_Installation>>({
installationName: '',
name: '',
region: '',
location: '',
@ -32,7 +33,14 @@ function installationForm(props: installationFormProps) {
vpnIp: '',
orderNumbers: ''
});
const requiredFields = ['name', 'region', 'location', 'country', 'vpnIp'];
const requiredFields = [
'installationName',
'name',
'region',
'location',
'country',
'vpnIp'
];
const tokencontext = useContext(TokenContext);
const { removeToken } = tokencontext;
@ -105,6 +113,21 @@ function installationForm(props: installationFormProps) {
noValidate
autoComplete="off"
>
<div>
<TextField
label={
<FormattedMessage
id="installationName"
defaultMessage="Installation Name"
/>
}
name="installationName"
value={formValues.installationName}
onChange={handleChange}
required
error={formValues.installationName === ''}
/>
</div>
<div>
<TextField
label={
@ -120,6 +143,7 @@ function installationForm(props: installationFormProps) {
error={formValues.name === ''}
/>
</div>
<div>
<TextField
label={<FormattedMessage id="region" defaultMessage="Region" />}

View File

@ -174,7 +174,6 @@ const batteryPaths = [
'/Battery/Devices/%id%/Dc/Voltage',
'/Battery/Devices/%id%/Soc',
'/Battery/Devices/%id%/Temperatures/Cells/Average',
//'/Log/SalimaxWarnings/Battery/%id%',
'/Battery/Devices/%id%/Warnings',
'/Battery/Devices/%id%/Alarms',
@ -319,6 +318,8 @@ export const extractValues = (
): TopologyValues | null => {
const extractedValues: TopologyValues = {} as TopologyValues;
// console.log('timeSeriesData=', timeSeriesData);
for (const topologyKey of Object.keys(topologyPaths)) {
//Each topologykey may have more than one paths (for example inverter)
const paths = topologyPaths[topologyKey];

View File

@ -100,11 +100,11 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
<TableBody>
{props.installations.map((installation) => {
const isInstallationSelected =
installation.id === selectedInstallation;
installation.s3BucketId === selectedInstallation;
const status = getStatus(installation.id);
const rowStyles =
isRowHovered === installation.id
isRowHovered === installation.s3BucketId
? {
cursor: 'pointer',
backgroundColor: theme.colors.primary.lighter
@ -114,13 +114,15 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
return (
<TableRow
hover
key={installation.id}
key={installation.s3BucketId}
selected={isInstallationSelected}
style={rowStyles}
onClick={() =>
handleSelectOneInstallation(installation.id)
handleSelectOneInstallation(installation.s3BucketId)
}
onMouseEnter={() =>
handleRowMouseEnter(installation.s3BucketId)
}
onMouseEnter={() => handleRowMouseEnter(installation.id)}
onMouseLeave={() => handleRowMouseLeave()}
>
<TableCell>
@ -132,7 +134,7 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
noWrap
sx={{ marginTop: '10px', fontSize: 'small' }}
>
{installation.name}
{installation.installationName}
</Typography>
</TableCell>

View File

@ -10,7 +10,6 @@ import {
} from 'src/content/dashboards/Log/graph.util';
import { WebSocketContext } from 'src/contexts/WebSocketContextProvider';
import { FormattedMessage } from 'react-intl';
import Overview from '../Overview/overview';
import { fetchData } from 'src/content/dashboards/Installations/fetchData';
import { Navigate, Route, Routes, useLocation } from 'react-router-dom';
import routes from '../../../Resources/routes.json';
@ -41,11 +40,12 @@ function Installation(props: singleInstallationProps) {
s3Region: props.current_installation.s3Region,
s3Provider: props.current_installation.s3Provider,
s3Key: props.current_installation.s3Key,
s3Secret: props.current_installation.s3Secret
s3Secret: props.current_installation.s3Secret,
s3BucketId: props.current_installation.s3BucketId
};
const s3Bucket =
props.current_installation.id.toString() +
props.current_installation.s3BucketId.toString() +
'-' +
'c0436b6a-d276-4cd8-9c44-1eae86cf5d0e';
@ -182,13 +182,10 @@ function Installation(props: singleInstallationProps) {
values={values}
s3Credentials={s3Credentials}
installationId={props.current_installation.id}
productNum={props.current_installation.product}
></BatteryView>
}
></Route>
<Route
path={routes.overview}
element={<Overview s3Credentials={s3Credentials}></Overview>}
/>
<Route
path={'*'}

View File

@ -107,11 +107,11 @@ function InstallationSearch(props: installationSearchProps) {
{filteredData.map((installation) => {
return (
<Route
key={installation.id}
path={routes.installation + installation.id + '*'}
key={installation.s3BucketId}
path={routes.installation + installation.s3BucketId + '*'}
element={
<Installation
key={installation.id}
key={installation.s3BucketId}
current_installation={installation}
type="installation"
></Installation>

View File

@ -23,14 +23,20 @@ function SalidomonstallationForm(props: SalidomoInstallationFormProps) {
const theme = useTheme();
const [open, setOpen] = useState(true);
const [formValues, setFormValues] = useState<Partial<I_Installation>>({
name: '',
installationName: '',
region: '',
location: '',
country: '',
vpnIp: '',
vrmLink: ''
});
const requiredFields = ['name', 'location', 'country', 'vpnIp', 'vrmLink'];
const requiredFields = [
'installationName',
'location',
'country',
'vpnIp',
'vrmLink'
];
const installationContext = useContext(InstallationsContext);
const { createInstallation, loading, setLoading, error, setError } =
installationContext;
@ -108,11 +114,11 @@ function SalidomonstallationForm(props: SalidomoInstallationFormProps) {
defaultMessage="Installation Name"
/>
}
name="name"
value={formValues.name}
name="installationName"
value={formValues.installationName}
onChange={handleChange}
required
error={formValues.name === ''}
error={formValues.installationName === ''}
/>
</div>
<div>

View File

@ -52,7 +52,7 @@ function CustomTreeItem(props: CustomTreeItemProps) {
routes.installations +
routes.tree +
routes.installation +
installation.id +
installation.s3BucketId +
'/' +
routes.live,
{

View File

@ -28,7 +28,11 @@ function InstallationTree() {
subnode != node &&
subnode.parentId == node.id && (
<TreeNode
key={subnode.id.toString() + subnode.type}
key={
subnode.type == 'Installation'
? subnode.s3BucketId.toString() + subnode.type
: subnode.id.toString() + subnode.type
}
node={subnode}
parent_id={node.id}
/>
@ -58,7 +62,11 @@ function InstallationTree() {
{foldersAndInstallations.map((node, index) => {
return (
<TreeNode
key={node.id.toString() + node.type}
key={
node.type == 'Installation'
? node.s3BucketId.toString() + node.type
: node.id.toString() + node.type
}
node={node}
parent_id={'0'}
/>
@ -72,11 +80,11 @@ function InstallationTree() {
if (installation.type == 'Installation') {
return (
<Route
key={installation.id}
path={routes.installation + installation.id + '*'}
key={installation.s3BucketId}
path={routes.installation + installation.s3BucketId + '*'}
element={
<Installation
key={installation.id}
key={installation.s3BucketId}
current_installation={installation}
type="installation"
></Installation>

View File

@ -25,5 +25,6 @@ export interface I_Folder {
information: string;
parentId: number;
type: string;
s3BucketId: number;
children?: (I_Installation | I_Folder)[];
}

View File

@ -3,7 +3,8 @@ export interface I_S3Credentials {
s3Provider: string;
s3Key: string;
s3Secret: string;
s3Bucket?: string;
s3Bucket: string;
s3BucketId: number;
}
export interface ErrorMessage {