Compare commits
No commits in common. "cee72bebe636281853d425e0ce6c59f46395881c" and "453768c7090a0721cba2c0d8ae1a1fac82f9aae8" have entirely different histories.
cee72bebe6
...
453768c709
|
@ -16,8 +16,7 @@ dotnet publish \
|
||||||
-r linux-x64
|
-r linux-x64
|
||||||
|
|
||||||
echo -e "\n============================ Deploy ============================\n"
|
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")
|
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")
|
||||||
|
|
||||||
|
|
||||||
for ip_address in "${ip_addresses[@]}"; do
|
for ip_address in "${ip_addresses[@]}"; do
|
||||||
rsync -v \
|
rsync -v \
|
||||||
|
|
|
@ -197,17 +197,16 @@ public static class Controller
|
||||||
(calibrationChargeForced == CalibrationChargeType.RepetitivelyEvery && repetitiveCalibrationRequired);
|
(calibrationChargeForced == CalibrationChargeType.RepetitivelyEvery && repetitiveCalibrationRequired);
|
||||||
Console.WriteLine("Next Repetitive calibration charge date is "+statusRecord.Config.DayAndTimeForRepetitiveCalibration);
|
Console.WriteLine("Next Repetitive calibration charge date is "+statusRecord.Config.DayAndTimeForRepetitiveCalibration);
|
||||||
Console.WriteLine("Next Additional calibration charge date is "+statusRecord.Config.DayAndTimeForAdditionalCalibration);
|
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 (statusRecord.Battery is not null)
|
||||||
{
|
{
|
||||||
if (calibrationChargeForced == CalibrationChargeType.AdditionallyOnce && statusRecord.Battery.Eoc )
|
if (calibrationChargeForced == CalibrationChargeType.AdditionallyOnce && statusRecord.Battery.Eoc )
|
||||||
{
|
{
|
||||||
statusRecord.Config.ForceCalibrationChargeState = CalibrationChargeType.RepetitivelyEvery;
|
statusRecord.Config.ForceCalibrationChargeState = CalibrationChargeType.RepetitivelyEvery;
|
||||||
//_hasAdditionalCalibrationChargeChecked = false;
|
_hasAdditionalCalibrationChargeChecked = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (calibrationChargeForced == CalibrationChargeType.RepetitivelyEvery && statusRecord.Battery.Eoc && _hasRepetitiveCalibrationChargeChecked)
|
else if (calibrationChargeForced == CalibrationChargeType.RepetitivelyEvery && statusRecord.Battery.Eoc )
|
||||||
{
|
{
|
||||||
statusRecord.Config.DayAndTimeForRepetitiveCalibration = statusRecord.Config.DayAndTimeForRepetitiveCalibration.AddDays(7);
|
statusRecord.Config.DayAndTimeForRepetitiveCalibration = statusRecord.Config.DayAndTimeForRepetitiveCalibration.AddDays(7);
|
||||||
_hasRepetitiveCalibrationChargeChecked = false;
|
_hasRepetitiveCalibrationChargeChecked = false;
|
||||||
|
@ -218,41 +217,30 @@ public static class Controller
|
||||||
|
|
||||||
private static Boolean RepetitiveCalibrationDateHasBeenPassed(DateTime calibrationChargeDate)
|
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;
|
if (DateTime.Now >= calibrationChargeDate )
|
||||||
return true;
|
{
|
||||||
|
_hasRepetitiveCalibrationChargeChecked = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
return true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
private static Boolean AdditionalCalibrationDateHasBeenPassed(DateTime calibrationChargeDate)
|
private static Boolean AdditionalCalibrationDateHasBeenPassed(DateTime calibrationChargeDate)
|
||||||
{
|
{
|
||||||
// if (!_hasAdditionalCalibrationChargeChecked)
|
if (!_hasAdditionalCalibrationChargeChecked)
|
||||||
// {
|
{
|
||||||
if (DateTime.Now >= calibrationChargeDate )
|
if (DateTime.Now >= calibrationChargeDate )
|
||||||
{
|
{
|
||||||
//_hasAdditionalCalibrationChargeChecked = true;
|
_hasAdditionalCalibrationChargeChecked = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
// }
|
}
|
||||||
// return true;
|
return true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ public static class MiddlewareAgent
|
||||||
{
|
{
|
||||||
public static UdpClient UdpListener = null!;
|
public static UdpClient UdpListener = null!;
|
||||||
private static IPAddress? _controllerIpAddress;
|
private static IPAddress? _controllerIpAddress;
|
||||||
private static EndPoint? _endPoint;
|
|
||||||
|
|
||||||
public static void InitializeCommunicationToMiddleware()
|
public static void InitializeCommunicationToMiddleware()
|
||||||
{
|
{
|
||||||
|
@ -22,11 +21,11 @@ public static class MiddlewareAgent
|
||||||
}
|
}
|
||||||
|
|
||||||
const Int32 udpPort = 9000;
|
const Int32 udpPort = 9000;
|
||||||
_endPoint = new IPEndPoint(_controllerIpAddress, udpPort);
|
var endPoint = new IPEndPoint(_controllerIpAddress, udpPort);
|
||||||
|
|
||||||
UdpListener = new UdpClient();
|
UdpListener = new UdpClient();
|
||||||
UdpListener.Client.Blocking = false;
|
UdpListener.Client.Blocking = false;
|
||||||
UdpListener.Client.Bind(_endPoint);
|
UdpListener.Client.Bind(endPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IPAddress FindVpnIp()
|
private static IPAddress FindVpnIp()
|
||||||
|
@ -55,7 +54,6 @@ public static class MiddlewareAgent
|
||||||
{
|
{
|
||||||
if (UdpListener.Available > 0)
|
if (UdpListener.Available > 0)
|
||||||
{
|
{
|
||||||
|
|
||||||
IPEndPoint? serverEndpoint = null;
|
IPEndPoint? serverEndpoint = null;
|
||||||
|
|
||||||
var replyMessage = "ACK";
|
var replyMessage = "ACK";
|
||||||
|
@ -74,13 +72,6 @@ public static class MiddlewareAgent
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_endPoint.Equals((IPEndPoint)UdpListener.Client.LocalEndPoint))
|
|
||||||
{
|
|
||||||
Console.WriteLine("UDP address has changed, rebinding...");
|
|
||||||
InitializeCommunicationToMiddleware();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#undef Amax
|
#define Amax
|
||||||
#undef GridLimit
|
#undef GridLimit
|
||||||
|
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
|
|
|
@ -31,7 +31,6 @@ interface BatteryViewProps {
|
||||||
values: TopologyValues;
|
values: TopologyValues;
|
||||||
s3Credentials: I_S3Credentials;
|
s3Credentials: I_S3Credentials;
|
||||||
installationId: number;
|
installationId: number;
|
||||||
productNum: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function BatteryView(props: BatteryViewProps) {
|
function BatteryView(props: BatteryViewProps) {
|
||||||
|
@ -158,7 +157,6 @@ function BatteryView(props: BatteryViewProps) {
|
||||||
s3Credentials={props.s3Credentials}
|
s3Credentials={props.s3Credentials}
|
||||||
batteryData={findBatteryData(battery.BatteryId)}
|
batteryData={findBatteryData(battery.BatteryId)}
|
||||||
installationId={props.installationId}
|
installationId={props.installationId}
|
||||||
productNum={props.productNum}
|
|
||||||
></DetailedBatteryView>
|
></DetailedBatteryView>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
@ -274,83 +272,72 @@ function BatteryView(props: BatteryViewProps) {
|
||||||
battery.AverageTemperature.unit}
|
battery.AverageTemperature.unit}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
||||||
{props.productNum === 0 && (
|
<TableCell
|
||||||
<>
|
style={{
|
||||||
<TableCell
|
width: '20%',
|
||||||
style={{
|
textAlign: 'center',
|
||||||
width: '20%',
|
padding: '8px',
|
||||||
textAlign: 'center',
|
fontWeight:
|
||||||
padding: '8px',
|
battery.Warnings.value !== '' ? 'bold' : 'inherit',
|
||||||
fontWeight:
|
backgroundColor:
|
||||||
battery.Warnings.value !== ''
|
battery.Warnings.value === '' ? 'inherit' : '#ff9900',
|
||||||
? 'bold'
|
color:
|
||||||
: 'inherit',
|
battery.Warnings.value != '' ? 'black' : 'inherit'
|
||||||
backgroundColor:
|
}}
|
||||||
battery.Warnings.value === ''
|
>
|
||||||
? 'inherit'
|
{battery.Warnings.value === '' ? (
|
||||||
: '#ff9900',
|
'None'
|
||||||
color:
|
) : battery.Warnings.value.toString().split('-').length >
|
||||||
battery.Warnings.value != '' ? 'black' : 'inherit'
|
1 ? (
|
||||||
}}
|
<Link
|
||||||
|
style={{ color: 'black' }}
|
||||||
|
to={
|
||||||
|
currentLocation.pathname.substring(
|
||||||
|
0,
|
||||||
|
currentLocation.pathname.lastIndexOf('/') + 1
|
||||||
|
) +
|
||||||
|
routes.log +
|
||||||
|
'?open=warning'
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{battery.Warnings.value === '' ? (
|
Multiple Warnings
|
||||||
'None'
|
</Link>
|
||||||
) : battery.Warnings.value.toString().split('-')
|
) : (
|
||||||
.length > 1 ? (
|
battery.Warnings.value
|
||||||
<Link
|
)}
|
||||||
style={{ color: 'black' }}
|
</TableCell>
|
||||||
to={
|
<TableCell
|
||||||
currentLocation.pathname.substring(
|
sx={{
|
||||||
0,
|
width: '20%',
|
||||||
currentLocation.pathname.lastIndexOf('/') + 1
|
textAlign: 'center',
|
||||||
) +
|
fontWeight:
|
||||||
routes.log +
|
battery.Alarms.value !== '' ? 'bold' : 'inherit',
|
||||||
'?open=warning'
|
backgroundColor:
|
||||||
}
|
battery.Alarms.value === '' ? 'inherit' : '#FF033E',
|
||||||
>
|
color: battery.Alarms.value != '' ? 'black' : 'inherit'
|
||||||
Multiple Warnings
|
}}
|
||||||
</Link>
|
>
|
||||||
) : (
|
{battery.Alarms.value === '' ? (
|
||||||
battery.Warnings.value
|
'None'
|
||||||
)}
|
) : battery.Alarms.value.toString().split('-').length >
|
||||||
</TableCell>
|
1 ? (
|
||||||
<TableCell
|
<Link
|
||||||
sx={{
|
style={{ color: 'black' }}
|
||||||
width: '20%',
|
to={
|
||||||
textAlign: 'center',
|
currentLocation.pathname.substring(
|
||||||
fontWeight:
|
0,
|
||||||
battery.Alarms.value !== '' ? 'bold' : 'inherit',
|
currentLocation.pathname.lastIndexOf('/') + 1
|
||||||
backgroundColor:
|
) +
|
||||||
battery.Alarms.value === ''
|
routes.log +
|
||||||
? 'inherit'
|
'?open=error'
|
||||||
: '#FF033E',
|
}
|
||||||
color:
|
|
||||||
battery.Alarms.value != '' ? 'black' : 'inherit'
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{battery.Alarms.value === '' ? (
|
Multiple Alarms
|
||||||
'None'
|
</Link>
|
||||||
) : battery.Alarms.value.toString().split('-')
|
) : (
|
||||||
.length > 1 ? (
|
battery.Alarms.value
|
||||||
<Link
|
)}
|
||||||
style={{ color: 'black' }}
|
</TableCell>
|
||||||
to={
|
|
||||||
currentLocation.pathname.substring(
|
|
||||||
0,
|
|
||||||
currentLocation.pathname.lastIndexOf('/') + 1
|
|
||||||
) +
|
|
||||||
routes.log +
|
|
||||||
'?open=error'
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Multiple Alarms
|
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
battery.Alarms.value
|
|
||||||
)}
|
|
||||||
</TableCell>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</TableRow>
|
</TableRow>
|
||||||
))}
|
))}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
|
|
|
@ -25,7 +25,6 @@ interface DetailedBatteryViewProps {
|
||||||
s3Credentials: I_S3Credentials;
|
s3Credentials: I_S3Credentials;
|
||||||
batteryData: Battery;
|
batteryData: Battery;
|
||||||
installationId: number;
|
installationId: number;
|
||||||
productNum: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
||||||
|
@ -274,24 +273,22 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
||||||
<ArrowBackIcon />
|
<ArrowBackIcon />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|
||||||
{props.productNum === 0 && (
|
<Button
|
||||||
<Button
|
variant="contained"
|
||||||
variant="contained"
|
onClick={handleUpdateFirmware}
|
||||||
onClick={handleUpdateFirmware}
|
sx={{
|
||||||
sx={{
|
marginTop: '20px',
|
||||||
marginTop: '20px',
|
marginLeft: '20px',
|
||||||
marginLeft: '20px',
|
backgroundColor: '#ffc04d',
|
||||||
backgroundColor: '#ffc04d',
|
color: '#000000',
|
||||||
color: '#000000',
|
'&:hover': { bgcolor: '#f7b34d' }
|
||||||
'&:hover': { bgcolor: '#f7b34d' }
|
}}
|
||||||
}}
|
>
|
||||||
>
|
<FormattedMessage
|
||||||
<FormattedMessage
|
id="update_firmware"
|
||||||
id="update_firmware"
|
defaultMessage="Update Firmware"
|
||||||
defaultMessage="Update Firmware"
|
/>
|
||||||
/>
|
</Button>
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid container>
|
<Grid container>
|
||||||
|
@ -313,8 +310,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
||||||
style={{
|
style={{
|
||||||
...batteryStringStyle,
|
...batteryStringStyle,
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
props.batteryData.String1Active.value == 'True' ||
|
props.batteryData.String1Active.value == 'True'
|
||||||
props.batteryData.String4Active.value == 0
|
|
||||||
? '#32CD32'
|
? '#32CD32'
|
||||||
: '#FF033E'
|
: '#FF033E'
|
||||||
}}
|
}}
|
||||||
|
@ -323,8 +319,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
||||||
style={{
|
style={{
|
||||||
...batteryStringStyle,
|
...batteryStringStyle,
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
props.batteryData.String2Active.value == 'True' ||
|
props.batteryData.String2Active.value == 'True'
|
||||||
props.batteryData.String4Active.value == 0
|
|
||||||
? '#32CD32'
|
? '#32CD32'
|
||||||
: '#FF033E'
|
: '#FF033E'
|
||||||
}}
|
}}
|
||||||
|
@ -333,8 +328,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
||||||
style={{
|
style={{
|
||||||
...batteryStringStyle,
|
...batteryStringStyle,
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
props.batteryData.String3Active.value == 'True' ||
|
props.batteryData.String3Active.value == 'True'
|
||||||
props.batteryData.String4Active.value == 0
|
|
||||||
? '#32CD32'
|
? '#32CD32'
|
||||||
: '#FF033E'
|
: '#FF033E'
|
||||||
}}
|
}}
|
||||||
|
@ -343,8 +337,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
||||||
style={{
|
style={{
|
||||||
...batteryStringStyle,
|
...batteryStringStyle,
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
props.batteryData.String4Active.value == 'True' ||
|
props.batteryData.String4Active.value == 'True'
|
||||||
props.batteryData.String4Active.value == 0
|
|
||||||
? '#32CD32'
|
? '#32CD32'
|
||||||
: '#FF033E'
|
: '#FF033E'
|
||||||
}}
|
}}
|
||||||
|
@ -353,8 +346,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
||||||
style={{
|
style={{
|
||||||
...batteryStringStyle,
|
...batteryStringStyle,
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
props.batteryData.String5Active.value == 'True' ||
|
props.batteryData.String5Active.value == 'True'
|
||||||
props.batteryData.String4Active.value == 0
|
|
||||||
? '#32CD32'
|
? '#32CD32'
|
||||||
: '#FF033E'
|
: '#FF033E'
|
||||||
}}
|
}}
|
||||||
|
@ -522,7 +514,6 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
||||||
props.batteryData.Power.unit}
|
props.batteryData.Power.unit}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell
|
<TableCell
|
||||||
component="th"
|
component="th"
|
||||||
|
@ -618,200 +609,196 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
||||||
</Card>
|
</Card>
|
||||||
</Grid>
|
</Grid>
|
||||||
{/*----------------------------------------------------------------------------------------------------------------------------------*/}
|
{/*----------------------------------------------------------------------------------------------------------------------------------*/}
|
||||||
{props.productNum === 0 && (
|
<Grid item md={3} xs={3}>
|
||||||
<>
|
<Card
|
||||||
<Grid item md={3} xs={3}>
|
sx={{
|
||||||
<Card
|
overflow: 'visible',
|
||||||
sx={{
|
marginTop: '30px',
|
||||||
overflow: 'visible',
|
marginLeft: '20px',
|
||||||
marginTop: '30px',
|
display: 'flex',
|
||||||
marginLeft: '20px',
|
flexDirection: 'column',
|
||||||
display: 'flex',
|
alignItems: 'center',
|
||||||
flexDirection: 'column',
|
border: '2px solid #ccc',
|
||||||
alignItems: 'center',
|
borderRadius: '12px'
|
||||||
border: '2px solid #ccc',
|
}}
|
||||||
borderRadius: '12px'
|
>
|
||||||
}}
|
<Typography
|
||||||
>
|
variant="h6"
|
||||||
<Typography
|
component="div"
|
||||||
variant="h6"
|
sx={{
|
||||||
component="div"
|
marginTop: '10px',
|
||||||
sx={{
|
borderBottom: '1px solid #ccc',
|
||||||
marginTop: '10px',
|
fontWeight: 'bold'
|
||||||
borderBottom: '1px solid #ccc',
|
}}
|
||||||
fontWeight: 'bold'
|
>
|
||||||
}}
|
Temperature
|
||||||
>
|
</Typography>
|
||||||
Temperature
|
|
||||||
</Typography>
|
|
||||||
|
|
||||||
<TableContainer
|
<TableContainer
|
||||||
component={Paper}
|
component={Paper}
|
||||||
sx={{ marginTop: '20px', width: '100%' }}
|
sx={{ marginTop: '20px', width: '100%' }}
|
||||||
>
|
>
|
||||||
<Table size="medium" aria-label="a dense table">
|
<Table size="medium" aria-label="a dense table">
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell
|
<TableCell
|
||||||
component="th"
|
component="th"
|
||||||
scope="row"
|
scope="row"
|
||||||
align="left"
|
align="left"
|
||||||
sx={{ fontWeight: 'bold' }}
|
sx={{ fontWeight: 'bold' }}
|
||||||
>
|
>
|
||||||
Heating
|
Heating
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell
|
<TableCell
|
||||||
align="right"
|
align="right"
|
||||||
sx={{
|
sx={{
|
||||||
width: '6ch',
|
width: '6ch',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
paddingRight: '12px'
|
paddingRight: '12px'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.batteryData.HeatingTemperature.value +
|
{props.batteryData.HeatingTemperature.value +
|
||||||
' ' +
|
' ' +
|
||||||
props.batteryData.HeatingTemperature.unit}
|
props.batteryData.HeatingTemperature.unit}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell
|
<TableCell
|
||||||
component="th"
|
component="th"
|
||||||
scope="row"
|
scope="row"
|
||||||
align="left"
|
align="left"
|
||||||
sx={{ fontWeight: 'bold' }}
|
sx={{ fontWeight: 'bold' }}
|
||||||
>
|
>
|
||||||
Board Temperature
|
Board Temperature
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell
|
<TableCell
|
||||||
align="right"
|
align="right"
|
||||||
sx={{
|
sx={{
|
||||||
width: '6ch',
|
width: '6ch',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
paddingRight: '12px'
|
paddingRight: '12px'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.batteryData.BoardTemperature.value +
|
{props.batteryData.BoardTemperature.value +
|
||||||
' ' +
|
' ' +
|
||||||
props.batteryData.BoardTemperature.unit}
|
props.batteryData.BoardTemperature.unit}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell
|
<TableCell
|
||||||
component="th"
|
component="th"
|
||||||
scope="row"
|
scope="row"
|
||||||
align="left"
|
align="left"
|
||||||
sx={{ fontWeight: 'bold' }}
|
sx={{ fontWeight: 'bold' }}
|
||||||
>
|
>
|
||||||
Center Cells Temperature
|
Center Cells Temperature
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell
|
<TableCell
|
||||||
align="right"
|
align="right"
|
||||||
sx={{
|
sx={{
|
||||||
width: '6ch',
|
width: '6ch',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
paddingRight: '12px'
|
paddingRight: '12px'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.batteryData.AverageTemperature.value +
|
{props.batteryData.AverageTemperature.value +
|
||||||
' ' +
|
' ' +
|
||||||
props.batteryData.AverageTemperature.unit}
|
props.batteryData.AverageTemperature.unit}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell
|
<TableCell
|
||||||
component="th"
|
component="th"
|
||||||
scope="row"
|
scope="row"
|
||||||
align="left"
|
align="left"
|
||||||
sx={{ fontWeight: 'bold' }}
|
sx={{ fontWeight: 'bold' }}
|
||||||
>
|
>
|
||||||
Left Cells Temperature
|
Left Cells Temperature
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell
|
<TableCell
|
||||||
align="right"
|
align="right"
|
||||||
sx={{
|
sx={{
|
||||||
width: '6ch',
|
width: '6ch',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
paddingRight: '12px'
|
paddingRight: '12px'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.batteryData.LeftCellsTemperature.value +
|
{props.batteryData.LeftCellsTemperature.value +
|
||||||
' ' +
|
' ' +
|
||||||
props.batteryData.LeftCellsTemperature.unit}
|
props.batteryData.LeftCellsTemperature.unit}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell
|
<TableCell
|
||||||
component="th"
|
component="th"
|
||||||
scope="row"
|
scope="row"
|
||||||
align="left"
|
align="left"
|
||||||
sx={{ fontWeight: 'bold' }}
|
sx={{ fontWeight: 'bold' }}
|
||||||
>
|
>
|
||||||
Right Cells Temperature
|
Right Cells Temperature
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell
|
<TableCell
|
||||||
align="right"
|
align="right"
|
||||||
sx={{
|
sx={{
|
||||||
width: '6ch',
|
width: '6ch',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
paddingRight: '12px'
|
paddingRight: '12px'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.batteryData.RightCellsTemperature.value +
|
{props.batteryData.RightCellsTemperature.value +
|
||||||
' ' +
|
' ' +
|
||||||
props.batteryData.RightCellsTemperature.unit}
|
props.batteryData.RightCellsTemperature.unit}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell
|
<TableCell
|
||||||
component="th"
|
component="th"
|
||||||
scope="row"
|
scope="row"
|
||||||
align="left"
|
align="left"
|
||||||
sx={{ fontWeight: 'bold' }}
|
sx={{ fontWeight: 'bold' }}
|
||||||
>
|
>
|
||||||
Average Temperature
|
Average Temperature
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell
|
<TableCell
|
||||||
align="right"
|
align="right"
|
||||||
sx={{
|
sx={{
|
||||||
width: '6ch',
|
width: '6ch',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
paddingRight: '12px'
|
paddingRight: '12px'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.batteryData.AverageTemperature.value +
|
{props.batteryData.AverageTemperature.value +
|
||||||
' ' +
|
' ' +
|
||||||
props.batteryData.AverageTemperature.unit}
|
props.batteryData.AverageTemperature.unit}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell
|
<TableCell
|
||||||
component="th"
|
component="th"
|
||||||
scope="row"
|
scope="row"
|
||||||
align="left"
|
align="left"
|
||||||
sx={{ fontWeight: 'bold' }}
|
sx={{ fontWeight: 'bold' }}
|
||||||
>
|
>
|
||||||
State
|
State
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell
|
<TableCell
|
||||||
align="right"
|
align="right"
|
||||||
sx={{
|
sx={{
|
||||||
width: '6ch',
|
width: '6ch',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
paddingRight: '12px'
|
paddingRight: '12px'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.batteryData.StateTemperature.value +
|
{props.batteryData.StateTemperature.value +
|
||||||
' ' +
|
' ' +
|
||||||
props.batteryData.StateTemperature.unit}
|
props.batteryData.StateTemperature.unit}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
</Card>
|
</Card>
|
||||||
</Grid>
|
</Grid>
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/*----------------------------------------------------------------------------------------------------------------------------------*/}
|
{/*----------------------------------------------------------------------------------------------------------------------------------*/}
|
||||||
<Grid item md={3} xs={3}>
|
<Grid item md={3} xs={3}>
|
||||||
|
@ -820,7 +807,6 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
||||||
overflow: 'visible',
|
overflow: 'visible',
|
||||||
marginTop: '30px',
|
marginTop: '30px',
|
||||||
marginLeft: '20px',
|
marginLeft: '20px',
|
||||||
marginBottom: '20px',
|
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
|
@ -1006,7 +992,6 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{/*----------------------------------------------------------------------------------------------------------------------------------*/}
|
{/*----------------------------------------------------------------------------------------------------------------------------------*/}
|
||||||
|
|
||||||
<Grid item md={3} xs={3}>
|
<Grid item md={3} xs={3}>
|
||||||
<Card
|
<Card
|
||||||
sx={{
|
sx={{
|
||||||
|
@ -1059,7 +1044,6 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
||||||
props.batteryData.Eoc.unit}
|
props.batteryData.Eoc.unit}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell
|
<TableCell
|
||||||
component="th"
|
component="th"
|
||||||
|
@ -1082,7 +1066,6 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
||||||
props.batteryData.SerialNumber.unit}
|
props.batteryData.SerialNumber.unit}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell
|
<TableCell
|
||||||
component="th"
|
component="th"
|
||||||
|
@ -1127,30 +1110,28 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
||||||
props.batteryData.TimeSinceTOC.unit}
|
props.batteryData.TimeSinceTOC.unit}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
{props.productNum === 0 && (
|
<TableRow>
|
||||||
<TableRow>
|
<TableCell
|
||||||
<TableCell
|
component="th"
|
||||||
component="th"
|
scope="row"
|
||||||
scope="row"
|
align="left"
|
||||||
align="left"
|
sx={{ fontWeight: 'bold' }}
|
||||||
sx={{ fontWeight: 'bold' }}
|
>
|
||||||
>
|
Calibration Charge Requested
|
||||||
Calibration Charge Requested
|
</TableCell>
|
||||||
</TableCell>
|
<TableCell
|
||||||
<TableCell
|
align="right"
|
||||||
align="right"
|
sx={{
|
||||||
sx={{
|
width: '6ch',
|
||||||
width: '6ch',
|
whiteSpace: 'nowrap',
|
||||||
whiteSpace: 'nowrap',
|
paddingRight: '12px'
|
||||||
paddingRight: '12px'
|
}}
|
||||||
}}
|
>
|
||||||
>
|
{props.batteryData.CalibrationChargeRequested.value +
|
||||||
{props.batteryData.CalibrationChargeRequested.value +
|
' ' +
|
||||||
' ' +
|
props.batteryData.CalibrationChargeRequested.unit}
|
||||||
props.batteryData.CalibrationChargeRequested.unit}
|
</TableCell>
|
||||||
</TableCell>
|
</TableRow>
|
||||||
</TableRow>
|
|
||||||
)}
|
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell
|
<TableCell
|
||||||
component="th"
|
component="th"
|
||||||
|
@ -1200,7 +1181,6 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
</Card>
|
</Card>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
{/*----------------------------------------------------------------------------------------------------------------------------------*/}
|
{/*----------------------------------------------------------------------------------------------------------------------------------*/}
|
||||||
|
|
||||||
{/*<Grid item md={1.5} xs={1.5}>*/}
|
{/*<Grid item md={1.5} xs={1.5}>*/}
|
||||||
|
|
|
@ -43,7 +43,7 @@ function Configuration(props: ConfigurationProps) {
|
||||||
const CalibrationChargeOptions = [
|
const CalibrationChargeOptions = [
|
||||||
'Repetitive Calibration',
|
'Repetitive Calibration',
|
||||||
'Additional Calibration',
|
'Additional Calibration',
|
||||||
'Force Permanent Calibration Now'
|
'Force Calibration Now'
|
||||||
];
|
];
|
||||||
|
|
||||||
const CalibrationChargeOptionsController = [
|
const CalibrationChargeOptionsController = [
|
||||||
|
@ -93,11 +93,13 @@ function Configuration(props: ConfigurationProps) {
|
||||||
CalibrationChargeOptionsController.indexOf(
|
CalibrationChargeOptionsController.indexOf(
|
||||||
props.values.calibrationChargeState[0].value.toString()
|
props.values.calibrationChargeState[0].value.toString()
|
||||||
) == 0
|
) == 0
|
||||||
? dayjs(props.values.repetitiveCalibrationChargeDate[0].value)
|
? dayjs
|
||||||
// .add(localOffset, 'minute')
|
.utc(props.values.repetitiveCalibrationChargeDate[0].value)
|
||||||
|
.add(localOffset, 'minute')
|
||||||
.toDate()
|
.toDate()
|
||||||
: dayjs(props.values.additionalCalibrationChargeDate[0].value)
|
: dayjs
|
||||||
// .add(localOffset, 'minute')
|
.utc(props.values.additionalCalibrationChargeDate[0].value)
|
||||||
|
.add(localOffset, 'minute')
|
||||||
.toDate()
|
.toDate()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -122,19 +124,14 @@ function Configuration(props: ConfigurationProps) {
|
||||||
setErrorDateModalOpen(true);
|
setErrorDateModalOpen(true);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// console.log('asked for', dayjs(formValues.calibrationChargeDate));
|
//console.log('asked for', dayjs(formValues.calibrationChargeDate));
|
||||||
const configurationToSend: ConfigurationValues = {
|
const configurationToSend: ConfigurationValues = {
|
||||||
minimumSoC: formValues.minimumSoC,
|
minimumSoC: formValues.minimumSoC,
|
||||||
gridSetPoint: formValues.gridSetPoint,
|
gridSetPoint: formValues.gridSetPoint,
|
||||||
CalibrationChargeState: formValues.CalibrationChargeState,
|
CalibrationChargeState: formValues.CalibrationChargeState,
|
||||||
calibrationChargeDate: dayjs
|
calibrationChargeDate: dayjs(formValues.calibrationChargeDate).toDate()
|
||||||
.utc(formValues.calibrationChargeDate)
|
|
||||||
.add(localOffset, 'minute')
|
|
||||||
.toDate()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// console.log('will send ', dayjs(formValues.calibrationChargeDate));
|
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const res = await axiosConfig
|
const res = await axiosConfig
|
||||||
.post(
|
.post(
|
||||||
|
@ -160,11 +157,9 @@ function Configuration(props: ConfigurationProps) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleConfirm = (newDate) => {
|
const handleConfirm = (newDate) => {
|
||||||
//console.log('non adapted day is ', newDate);
|
|
||||||
//console.log('adapted day is ', dayjs.utc(newDate).toDate());
|
|
||||||
setFormValues({
|
setFormValues({
|
||||||
...formValues,
|
...formValues,
|
||||||
['calibrationChargeDate']: dayjs(newDate).toDate()
|
['calibrationChargeDate']: dayjs.utc(newDate).toDate()
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -175,7 +170,6 @@ function Configuration(props: ConfigurationProps) {
|
||||||
if (difference < 0) {
|
if (difference < 0) {
|
||||||
difference += 7;
|
difference += 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
const adjustedDate = currentDate.add(difference, 'day');
|
const adjustedDate = currentDate.add(difference, 'day');
|
||||||
setFormValues({
|
setFormValues({
|
||||||
...formValues,
|
...formValues,
|
||||||
|
@ -191,11 +185,13 @@ function Configuration(props: ConfigurationProps) {
|
||||||
),
|
),
|
||||||
['calibrationChargeDate']:
|
['calibrationChargeDate']:
|
||||||
CalibrationChargeOptions.indexOf(event.target.value) == 0
|
CalibrationChargeOptions.indexOf(event.target.value) == 0
|
||||||
? dayjs(props.values.repetitiveCalibrationChargeDate[0].value)
|
? dayjs
|
||||||
// .add(localOffset, 'minute')
|
.utc(props.values.repetitiveCalibrationChargeDate[0].value)
|
||||||
|
.add(localOffset, 'minute')
|
||||||
.toDate()
|
.toDate()
|
||||||
: dayjs(props.values.additionalCalibrationChargeDate[0].value)
|
: dayjs
|
||||||
// .add(localOffset, 'minute')
|
.utc(props.values.additionalCalibrationChargeDate[0].value)
|
||||||
|
.add(localOffset, 'minute')
|
||||||
.toDate()
|
.toDate()
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -353,7 +349,7 @@ function Configuration(props: ConfigurationProps) {
|
||||||
format="DD/MM/YYYY HH:mm"
|
format="DD/MM/YYYY HH:mm"
|
||||||
ampm={false}
|
ampm={false}
|
||||||
label="Select Next Calibration Charge Date"
|
label="Select Next Calibration Charge Date"
|
||||||
value={dayjs(formValues.calibrationChargeDate)}
|
value={dayjs.utc(formValues.calibrationChargeDate)}
|
||||||
onChange={handleConfirm}
|
onChange={handleConfirm}
|
||||||
sx={{
|
sx={{
|
||||||
marginTop: 2
|
marginTop: 2
|
||||||
|
@ -401,8 +397,8 @@ function Configuration(props: ConfigurationProps) {
|
||||||
<TimePicker
|
<TimePicker
|
||||||
ampm={false}
|
ampm={false}
|
||||||
label="Calibration Charge Hour"
|
label="Calibration Charge Hour"
|
||||||
value={dayjs(formValues.calibrationChargeDate)}
|
value={dayjs.utc(formValues.calibrationChargeDate)}
|
||||||
onChange={(newTime) => handleConfirm(dayjs(newTime))}
|
onChange={handleConfirm}
|
||||||
/>
|
/>
|
||||||
</LocalizationProvider>
|
</LocalizationProvider>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -307,7 +307,7 @@ function Information(props: InformationProps) {
|
||||||
label="S3 Bucket Name"
|
label="S3 Bucket Name"
|
||||||
name="s3writesecretkey"
|
name="s3writesecretkey"
|
||||||
value={
|
value={
|
||||||
formValues.s3BucketId +
|
formValues.id +
|
||||||
'-3e5b3069-214a-43ee-8d85-57d72000c19d'
|
'-3e5b3069-214a-43ee-8d85-57d72000c19d'
|
||||||
}
|
}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
|
|
@ -37,7 +37,7 @@ function InformationSalidomo(props: InformationSalidomoProps) {
|
||||||
const { currentUser } = context;
|
const { currentUser } = context;
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [formValues, setFormValues] = useState(props.values);
|
const [formValues, setFormValues] = useState(props.values);
|
||||||
const requiredFields = ['installationName', 'region', 'location', 'country'];
|
const requiredFields = ['name', 'region', 'location', 'country'];
|
||||||
const [openModalDeleteInstallation, setOpenModalDeleteInstallation] =
|
const [openModalDeleteInstallation, setOpenModalDeleteInstallation] =
|
||||||
useState(false);
|
useState(false);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
@ -194,7 +194,7 @@ function InformationSalidomo(props: InformationSalidomoProps) {
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
name="installationName"
|
name="installationName"
|
||||||
value={formValues.installationName}
|
value={formValues.name}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
fullWidth
|
fullWidth
|
||||||
|
@ -280,8 +280,7 @@ function InformationSalidomo(props: InformationSalidomoProps) {
|
||||||
label="S3 Bucket Name"
|
label="S3 Bucket Name"
|
||||||
name="s3writesecretkey"
|
name="s3writesecretkey"
|
||||||
value={
|
value={
|
||||||
formValues.s3BucketId +
|
formValues.id + '-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e'
|
||||||
'-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e'
|
|
||||||
}
|
}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
fullWidth
|
fullWidth
|
||||||
|
|
|
@ -102,11 +102,11 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{props.installations.map((installation) => {
|
{props.installations.map((installation) => {
|
||||||
const isInstallationSelected =
|
const isInstallationSelected =
|
||||||
installation.s3BucketId === selectedInstallation;
|
installation.id === selectedInstallation;
|
||||||
|
|
||||||
const status = getStatus(installation.id);
|
const status = getStatus(installation.id);
|
||||||
const rowStyles =
|
const rowStyles =
|
||||||
isRowHovered === installation.s3BucketId
|
isRowHovered === installation.id
|
||||||
? {
|
? {
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
backgroundColor: theme.colors.primary.lighter
|
backgroundColor: theme.colors.primary.lighter
|
||||||
|
@ -116,15 +116,13 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
||||||
return (
|
return (
|
||||||
<TableRow
|
<TableRow
|
||||||
hover
|
hover
|
||||||
key={installation.s3BucketId}
|
key={installation.id}
|
||||||
selected={isInstallationSelected}
|
selected={isInstallationSelected}
|
||||||
style={rowStyles}
|
style={rowStyles}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
handleSelectOneInstallation(installation.s3BucketId)
|
handleSelectOneInstallation(installation.id)
|
||||||
}
|
|
||||||
onMouseEnter={() =>
|
|
||||||
handleRowMouseEnter(installation.s3BucketId)
|
|
||||||
}
|
}
|
||||||
|
onMouseEnter={() => handleRowMouseEnter(installation.id)}
|
||||||
onMouseLeave={() => handleRowMouseLeave()}
|
onMouseLeave={() => handleRowMouseLeave()}
|
||||||
>
|
>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
|
|
|
@ -1,11 +1,5 @@
|
||||||
import React, { useContext, useEffect, useState } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import {
|
import { Card, CircularProgress, Grid, Typography } from '@mui/material';
|
||||||
Card,
|
|
||||||
CircularProgress,
|
|
||||||
Container,
|
|
||||||
Grid,
|
|
||||||
Typography
|
|
||||||
} from '@mui/material';
|
|
||||||
import { I_Installation } from 'src/interfaces/InstallationTypes';
|
import { I_Installation } from 'src/interfaces/InstallationTypes';
|
||||||
import { UserContext } from 'src/contexts/userContext';
|
import { UserContext } from 'src/contexts/userContext';
|
||||||
import AccessContextProvider from 'src/contexts/AccessContextProvider';
|
import AccessContextProvider from 'src/contexts/AccessContextProvider';
|
||||||
|
@ -45,14 +39,6 @@ function Installation(props: singleInstallationProps) {
|
||||||
const [currentTab, setCurrentTab] = useState<string>(undefined);
|
const [currentTab, setCurrentTab] = useState<string>(undefined);
|
||||||
const [values, setValues] = useState<TopologyValues | null>(null);
|
const [values, setValues] = useState<TopologyValues | null>(null);
|
||||||
const status = getStatus(props.current_installation.id);
|
const status = getStatus(props.current_installation.id);
|
||||||
const [
|
|
||||||
failedToCommunicateWithInstallation,
|
|
||||||
setFailedToCommunicateWithInstallation
|
|
||||||
] = useState(0);
|
|
||||||
const [
|
|
||||||
openModalUnableToCommunicateWIthInstallation,
|
|
||||||
setOpenModalUnableToCommunicateWIthInstallation
|
|
||||||
] = useState(false);
|
|
||||||
|
|
||||||
if (props.current_installation == undefined) {
|
if (props.current_installation == undefined) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -62,15 +48,14 @@ function Installation(props: singleInstallationProps) {
|
||||||
s3Region: props.current_installation.s3Region,
|
s3Region: props.current_installation.s3Region,
|
||||||
s3Provider: props.current_installation.s3Provider,
|
s3Provider: props.current_installation.s3Provider,
|
||||||
s3Key: props.current_installation.s3Key,
|
s3Key: props.current_installation.s3Key,
|
||||||
s3Secret: props.current_installation.s3Secret,
|
s3Secret: props.current_installation.s3Secret
|
||||||
s3BucketId: props.current_installation.s3BucketId
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const s3Bucket =
|
const s3Bucket =
|
||||||
props.current_installation.product === 0
|
props.current_installation.product === 0
|
||||||
? props.current_installation.s3BucketId.toString() +
|
? props.current_installation.id.toString() +
|
||||||
'-3e5b3069-214a-43ee-8d85-57d72000c19d'
|
'-3e5b3069-214a-43ee-8d85-57d72000c19d'
|
||||||
: props.current_installation.s3BucketId.toString() +
|
: props.current_installation.id.toString() +
|
||||||
'-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e';
|
'-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e';
|
||||||
|
|
||||||
const s3Credentials = { s3Bucket, ...S3data };
|
const s3Credentials = { s3Bucket, ...S3data };
|
||||||
|
@ -82,8 +67,6 @@ function Installation(props: singleInstallationProps) {
|
||||||
const res = await fetchData(now, s3Credentials);
|
const res = await fetchData(now, s3Credentials);
|
||||||
|
|
||||||
if (res != FetchResult.notAvailable && res != FetchResult.tryLater) {
|
if (res != FetchResult.notAvailable && res != FetchResult.tryLater) {
|
||||||
setFailedToCommunicateWithInstallation(0);
|
|
||||||
setOpenModalUnableToCommunicateWIthInstallation(false);
|
|
||||||
setValues(
|
setValues(
|
||||||
extractValues({
|
extractValues({
|
||||||
time: now,
|
time: now,
|
||||||
|
@ -91,13 +74,6 @@ function Installation(props: singleInstallationProps) {
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
setFailedToCommunicateWithInstallation((prevCount) => {
|
|
||||||
if (prevCount + 1 >= 3) {
|
|
||||||
setOpenModalUnableToCommunicateWIthInstallation(true);
|
|
||||||
}
|
|
||||||
return prevCount + 1;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -123,12 +99,6 @@ function Installation(props: singleInstallationProps) {
|
||||||
setCurrentTab(path[path.length - 1]);
|
setCurrentTab(path[path.length - 1]);
|
||||||
}, [location]);
|
}, [location]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (status === -1) {
|
|
||||||
setOpenModalUnableToCommunicateWIthInstallation(true);
|
|
||||||
}
|
|
||||||
}, [status]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
currentTab == 'live' ||
|
currentTab == 'live' ||
|
||||||
|
@ -148,7 +118,7 @@ function Installation(props: singleInstallationProps) {
|
||||||
fetchDataOnlyOneTime();
|
fetchDataOnlyOneTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup function to cancel interval
|
// Cleanup function to cancel interval and update isMounted when unmounted
|
||||||
return () => {
|
return () => {
|
||||||
if (
|
if (
|
||||||
currentTab == 'live' ||
|
currentTab == 'live' ||
|
||||||
|
@ -160,10 +130,6 @@ function Installation(props: singleInstallationProps) {
|
||||||
}
|
}
|
||||||
}, [currentTab, location]);
|
}, [currentTab, location]);
|
||||||
|
|
||||||
const UnableToCommunicateModalHandleOk = () => {
|
|
||||||
setOpenModalUnableToCommunicateWIthInstallation(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Grid item xs={12} md={12}>
|
<Grid item xs={12} md={12}>
|
||||||
|
@ -298,31 +264,6 @@ function Installation(props: singleInstallationProps) {
|
||||||
alignItems="stretch"
|
alignItems="stretch"
|
||||||
spacing={0}
|
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>
|
<Routes>
|
||||||
<Route
|
<Route
|
||||||
path={routes.information}
|
path={routes.information}
|
||||||
|
@ -342,7 +283,6 @@ function Installation(props: singleInstallationProps) {
|
||||||
values={values}
|
values={values}
|
||||||
s3Credentials={s3Credentials}
|
s3Credentials={s3Credentials}
|
||||||
installationId={props.current_installation.id}
|
installationId={props.current_installation.id}
|
||||||
productNum={props.current_installation.product}
|
|
||||||
></BatteryView>
|
></BatteryView>
|
||||||
}
|
}
|
||||||
></Route>
|
></Route>
|
||||||
|
|
|
@ -63,11 +63,11 @@ function InstallationSearch(props: installationSearchProps) {
|
||||||
{filteredData.map((installation) => {
|
{filteredData.map((installation) => {
|
||||||
return (
|
return (
|
||||||
<Route
|
<Route
|
||||||
key={installation.s3BucketId}
|
key={installation.id}
|
||||||
path={routes.installation + installation.s3BucketId + '*'}
|
path={routes.installation + installation.id + '*'}
|
||||||
element={
|
element={
|
||||||
<Installation
|
<Installation
|
||||||
key={installation.s3BucketId}
|
key={installation.id}
|
||||||
current_installation={installation}
|
current_installation={installation}
|
||||||
type="installation"
|
type="installation"
|
||||||
></Installation>
|
></Installation>
|
||||||
|
|
|
@ -25,7 +25,6 @@ function installationForm(props: installationFormProps) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [open, setOpen] = useState(true);
|
const [open, setOpen] = useState(true);
|
||||||
const [formValues, setFormValues] = useState<Partial<I_Installation>>({
|
const [formValues, setFormValues] = useState<Partial<I_Installation>>({
|
||||||
installationName: '',
|
|
||||||
name: '',
|
name: '',
|
||||||
region: '',
|
region: '',
|
||||||
location: '',
|
location: '',
|
||||||
|
@ -33,14 +32,7 @@ function installationForm(props: installationFormProps) {
|
||||||
vpnIp: '',
|
vpnIp: '',
|
||||||
orderNumbers: ''
|
orderNumbers: ''
|
||||||
});
|
});
|
||||||
const requiredFields = [
|
const requiredFields = ['name', 'region', 'location', 'country', 'vpnIp'];
|
||||||
'installationName',
|
|
||||||
'name',
|
|
||||||
'region',
|
|
||||||
'location',
|
|
||||||
'country',
|
|
||||||
'vpnIp'
|
|
||||||
];
|
|
||||||
const tokencontext = useContext(TokenContext);
|
const tokencontext = useContext(TokenContext);
|
||||||
const { removeToken } = tokencontext;
|
const { removeToken } = tokencontext;
|
||||||
|
|
||||||
|
@ -113,21 +105,6 @@ function installationForm(props: installationFormProps) {
|
||||||
noValidate
|
noValidate
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
>
|
>
|
||||||
<div>
|
|
||||||
<TextField
|
|
||||||
label={
|
|
||||||
<FormattedMessage
|
|
||||||
id="installationName"
|
|
||||||
defaultMessage="Installation Name"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
name="installationName"
|
|
||||||
value={formValues.installationName}
|
|
||||||
onChange={handleChange}
|
|
||||||
required
|
|
||||||
error={formValues.installationName === ''}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<TextField
|
<TextField
|
||||||
label={
|
label={
|
||||||
|
@ -143,7 +120,6 @@ function installationForm(props: installationFormProps) {
|
||||||
error={formValues.name === ''}
|
error={formValues.name === ''}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<TextField
|
<TextField
|
||||||
label={<FormattedMessage id="region" defaultMessage="Region" />}
|
label={<FormattedMessage id="region" defaultMessage="Region" />}
|
||||||
|
|
|
@ -174,6 +174,7 @@ const batteryPaths = [
|
||||||
'/Battery/Devices/%id%/Dc/Voltage',
|
'/Battery/Devices/%id%/Dc/Voltage',
|
||||||
'/Battery/Devices/%id%/Soc',
|
'/Battery/Devices/%id%/Soc',
|
||||||
'/Battery/Devices/%id%/Temperatures/Cells/Average',
|
'/Battery/Devices/%id%/Temperatures/Cells/Average',
|
||||||
|
//'/Log/SalimaxWarnings/Battery/%id%',
|
||||||
'/Battery/Devices/%id%/Warnings',
|
'/Battery/Devices/%id%/Warnings',
|
||||||
'/Battery/Devices/%id%/Alarms',
|
'/Battery/Devices/%id%/Alarms',
|
||||||
|
|
||||||
|
@ -318,8 +319,6 @@ export const extractValues = (
|
||||||
): TopologyValues | null => {
|
): TopologyValues | null => {
|
||||||
const extractedValues: TopologyValues = {} as TopologyValues;
|
const extractedValues: TopologyValues = {} as TopologyValues;
|
||||||
|
|
||||||
// console.log('timeSeriesData=', timeSeriesData);
|
|
||||||
|
|
||||||
for (const topologyKey of Object.keys(topologyPaths)) {
|
for (const topologyKey of Object.keys(topologyPaths)) {
|
||||||
//Each topologykey may have more than one paths (for example inverter)
|
//Each topologykey may have more than one paths (for example inverter)
|
||||||
const paths = topologyPaths[topologyKey];
|
const paths = topologyPaths[topologyKey];
|
||||||
|
|
|
@ -100,11 +100,11 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{props.installations.map((installation) => {
|
{props.installations.map((installation) => {
|
||||||
const isInstallationSelected =
|
const isInstallationSelected =
|
||||||
installation.s3BucketId === selectedInstallation;
|
installation.id === selectedInstallation;
|
||||||
|
|
||||||
const status = getStatus(installation.id);
|
const status = getStatus(installation.id);
|
||||||
const rowStyles =
|
const rowStyles =
|
||||||
isRowHovered === installation.s3BucketId
|
isRowHovered === installation.id
|
||||||
? {
|
? {
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
backgroundColor: theme.colors.primary.lighter
|
backgroundColor: theme.colors.primary.lighter
|
||||||
|
@ -114,15 +114,13 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
||||||
return (
|
return (
|
||||||
<TableRow
|
<TableRow
|
||||||
hover
|
hover
|
||||||
key={installation.s3BucketId}
|
key={installation.id}
|
||||||
selected={isInstallationSelected}
|
selected={isInstallationSelected}
|
||||||
style={rowStyles}
|
style={rowStyles}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
handleSelectOneInstallation(installation.s3BucketId)
|
handleSelectOneInstallation(installation.id)
|
||||||
}
|
|
||||||
onMouseEnter={() =>
|
|
||||||
handleRowMouseEnter(installation.s3BucketId)
|
|
||||||
}
|
}
|
||||||
|
onMouseEnter={() => handleRowMouseEnter(installation.id)}
|
||||||
onMouseLeave={() => handleRowMouseLeave()}
|
onMouseLeave={() => handleRowMouseLeave()}
|
||||||
>
|
>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
|
@ -134,7 +132,7 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
||||||
noWrap
|
noWrap
|
||||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||||
>
|
>
|
||||||
{installation.installationName}
|
{installation.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
} from 'src/content/dashboards/Log/graph.util';
|
} from 'src/content/dashboards/Log/graph.util';
|
||||||
import { WebSocketContext } from 'src/contexts/WebSocketContextProvider';
|
import { WebSocketContext } from 'src/contexts/WebSocketContextProvider';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
import Overview from '../Overview/overview';
|
||||||
import { fetchData } from 'src/content/dashboards/Installations/fetchData';
|
import { fetchData } from 'src/content/dashboards/Installations/fetchData';
|
||||||
import { Navigate, Route, Routes, useLocation } from 'react-router-dom';
|
import { Navigate, Route, Routes, useLocation } from 'react-router-dom';
|
||||||
import routes from '../../../Resources/routes.json';
|
import routes from '../../../Resources/routes.json';
|
||||||
|
@ -40,12 +41,11 @@ function Installation(props: singleInstallationProps) {
|
||||||
s3Region: props.current_installation.s3Region,
|
s3Region: props.current_installation.s3Region,
|
||||||
s3Provider: props.current_installation.s3Provider,
|
s3Provider: props.current_installation.s3Provider,
|
||||||
s3Key: props.current_installation.s3Key,
|
s3Key: props.current_installation.s3Key,
|
||||||
s3Secret: props.current_installation.s3Secret,
|
s3Secret: props.current_installation.s3Secret
|
||||||
s3BucketId: props.current_installation.s3BucketId
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const s3Bucket =
|
const s3Bucket =
|
||||||
props.current_installation.s3BucketId.toString() +
|
props.current_installation.id.toString() +
|
||||||
'-' +
|
'-' +
|
||||||
'c0436b6a-d276-4cd8-9c44-1eae86cf5d0e';
|
'c0436b6a-d276-4cd8-9c44-1eae86cf5d0e';
|
||||||
|
|
||||||
|
@ -182,10 +182,13 @@ function Installation(props: singleInstallationProps) {
|
||||||
values={values}
|
values={values}
|
||||||
s3Credentials={s3Credentials}
|
s3Credentials={s3Credentials}
|
||||||
installationId={props.current_installation.id}
|
installationId={props.current_installation.id}
|
||||||
productNum={props.current_installation.product}
|
|
||||||
></BatteryView>
|
></BatteryView>
|
||||||
}
|
}
|
||||||
></Route>
|
></Route>
|
||||||
|
<Route
|
||||||
|
path={routes.overview}
|
||||||
|
element={<Overview s3Credentials={s3Credentials}></Overview>}
|
||||||
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path={'*'}
|
path={'*'}
|
||||||
|
|
|
@ -107,11 +107,11 @@ function InstallationSearch(props: installationSearchProps) {
|
||||||
{filteredData.map((installation) => {
|
{filteredData.map((installation) => {
|
||||||
return (
|
return (
|
||||||
<Route
|
<Route
|
||||||
key={installation.s3BucketId}
|
key={installation.id}
|
||||||
path={routes.installation + installation.s3BucketId + '*'}
|
path={routes.installation + installation.id + '*'}
|
||||||
element={
|
element={
|
||||||
<Installation
|
<Installation
|
||||||
key={installation.s3BucketId}
|
key={installation.id}
|
||||||
current_installation={installation}
|
current_installation={installation}
|
||||||
type="installation"
|
type="installation"
|
||||||
></Installation>
|
></Installation>
|
||||||
|
|
|
@ -23,20 +23,14 @@ function SalidomonstallationForm(props: SalidomoInstallationFormProps) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const [open, setOpen] = useState(true);
|
const [open, setOpen] = useState(true);
|
||||||
const [formValues, setFormValues] = useState<Partial<I_Installation>>({
|
const [formValues, setFormValues] = useState<Partial<I_Installation>>({
|
||||||
installationName: '',
|
name: '',
|
||||||
region: '',
|
region: '',
|
||||||
location: '',
|
location: '',
|
||||||
country: '',
|
country: '',
|
||||||
vpnIp: '',
|
vpnIp: '',
|
||||||
vrmLink: ''
|
vrmLink: ''
|
||||||
});
|
});
|
||||||
const requiredFields = [
|
const requiredFields = ['name', 'location', 'country', 'vpnIp', 'vrmLink'];
|
||||||
'installationName',
|
|
||||||
'location',
|
|
||||||
'country',
|
|
||||||
'vpnIp',
|
|
||||||
'vrmLink'
|
|
||||||
];
|
|
||||||
const installationContext = useContext(InstallationsContext);
|
const installationContext = useContext(InstallationsContext);
|
||||||
const { createInstallation, loading, setLoading, error, setError } =
|
const { createInstallation, loading, setLoading, error, setError } =
|
||||||
installationContext;
|
installationContext;
|
||||||
|
@ -114,11 +108,11 @@ function SalidomonstallationForm(props: SalidomoInstallationFormProps) {
|
||||||
defaultMessage="Installation Name"
|
defaultMessage="Installation Name"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
name="installationName"
|
name="name"
|
||||||
value={formValues.installationName}
|
value={formValues.name}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
required
|
required
|
||||||
error={formValues.installationName === ''}
|
error={formValues.name === ''}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -52,7 +52,7 @@ function CustomTreeItem(props: CustomTreeItemProps) {
|
||||||
routes.installations +
|
routes.installations +
|
||||||
routes.tree +
|
routes.tree +
|
||||||
routes.installation +
|
routes.installation +
|
||||||
installation.s3BucketId +
|
installation.id +
|
||||||
'/' +
|
'/' +
|
||||||
routes.live,
|
routes.live,
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,11 +28,7 @@ function InstallationTree() {
|
||||||
subnode != node &&
|
subnode != node &&
|
||||||
subnode.parentId == node.id && (
|
subnode.parentId == node.id && (
|
||||||
<TreeNode
|
<TreeNode
|
||||||
key={
|
key={subnode.id.toString() + subnode.type}
|
||||||
subnode.type == 'Installation'
|
|
||||||
? subnode.s3BucketId.toString() + subnode.type
|
|
||||||
: subnode.id.toString() + subnode.type
|
|
||||||
}
|
|
||||||
node={subnode}
|
node={subnode}
|
||||||
parent_id={node.id}
|
parent_id={node.id}
|
||||||
/>
|
/>
|
||||||
|
@ -62,11 +58,7 @@ function InstallationTree() {
|
||||||
{foldersAndInstallations.map((node, index) => {
|
{foldersAndInstallations.map((node, index) => {
|
||||||
return (
|
return (
|
||||||
<TreeNode
|
<TreeNode
|
||||||
key={
|
key={node.id.toString() + node.type}
|
||||||
node.type == 'Installation'
|
|
||||||
? node.s3BucketId.toString() + node.type
|
|
||||||
: node.id.toString() + node.type
|
|
||||||
}
|
|
||||||
node={node}
|
node={node}
|
||||||
parent_id={'0'}
|
parent_id={'0'}
|
||||||
/>
|
/>
|
||||||
|
@ -80,11 +72,11 @@ function InstallationTree() {
|
||||||
if (installation.type == 'Installation') {
|
if (installation.type == 'Installation') {
|
||||||
return (
|
return (
|
||||||
<Route
|
<Route
|
||||||
key={installation.s3BucketId}
|
key={installation.id}
|
||||||
path={routes.installation + installation.s3BucketId + '*'}
|
path={routes.installation + installation.id + '*'}
|
||||||
element={
|
element={
|
||||||
<Installation
|
<Installation
|
||||||
key={installation.s3BucketId}
|
key={installation.id}
|
||||||
current_installation={installation}
|
current_installation={installation}
|
||||||
type="installation"
|
type="installation"
|
||||||
></Installation>
|
></Installation>
|
||||||
|
|
|
@ -25,6 +25,5 @@ export interface I_Folder {
|
||||||
information: string;
|
information: string;
|
||||||
parentId: number;
|
parentId: number;
|
||||||
type: string;
|
type: string;
|
||||||
s3BucketId: number;
|
|
||||||
children?: (I_Installation | I_Folder)[];
|
children?: (I_Installation | I_Folder)[];
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,7 @@ export interface I_S3Credentials {
|
||||||
s3Provider: string;
|
s3Provider: string;
|
||||||
s3Key: string;
|
s3Key: string;
|
||||||
s3Secret: string;
|
s3Secret: string;
|
||||||
s3Bucket: string;
|
s3Bucket?: string;
|
||||||
s3BucketId: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ErrorMessage {
|
export interface ErrorMessage {
|
||||||
|
|
Loading…
Reference in New Issue