Enabled set date button in front end
Use s3cmd in backend to search the corresponding timestamps
This commit is contained in:
parent
b499d01473
commit
cce3a6f9bd
|
@ -1,4 +1,6 @@
|
|||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using InnovEnergy.App.Backend.Database;
|
||||
using InnovEnergy.App.Backend.DataTypes;
|
||||
using InnovEnergy.App.Backend.DataTypes.Methods;
|
||||
|
@ -144,9 +146,11 @@ public class Controller : ControllerBase
|
|||
.ThenByDescending(error => error.Time)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
||||
|
||||
[HttpGet(nameof(GetCsvTimestampsForInstallation))]
|
||||
public ActionResult<IEnumerable<CsvTimestamp>> GetCsvTimestampsForInstallation(Int64 id, Int32 start, Int32 end, Token authToken)
|
||||
public ActionResult<IEnumerable<Int64>> GetCsvTimestampsForInstallation(Int64 id, Int32 start, Int32 end, Token authToken)
|
||||
{
|
||||
var user = Db.GetSession(authToken)?.User;
|
||||
if (user == null)
|
||||
|
@ -158,21 +162,84 @@ public class Controller : ControllerBase
|
|||
return Unauthorized();
|
||||
|
||||
var sampleSize = 100;
|
||||
var allTimestamps = new List<CsvTimestamp>();
|
||||
var allTimestamps = new List<Int64>();
|
||||
|
||||
if (start != 0 && end != 0)
|
||||
static string FindCommonPrefix(string str1, string str2)
|
||||
{
|
||||
allTimestamps = Db.CsvTimestamps
|
||||
.Where(csvTimestamp => csvTimestamp.InstallationId == id && csvTimestamp.Timestamp > start && csvTimestamp.Timestamp < end)
|
||||
.OrderBy(csvTimestamp => csvTimestamp.Timestamp).ToList();
|
||||
int minLength = Math.Min(str1.Length, str2.Length);
|
||||
int i = 0;
|
||||
while (i < minLength && str1[i] == str2[i])
|
||||
{
|
||||
i++;
|
||||
}
|
||||
return str1.Substring(0, i);
|
||||
}
|
||||
else
|
||||
|
||||
string commonPrefix = FindCommonPrefix(start.ToString(), end.ToString());
|
||||
|
||||
string bucketPath = "s3://"+installation.S3BucketId + "-3e5b3069-214a-43ee-8d85-57d72000c19d/"+commonPrefix;
|
||||
string configPath = "/home/ubuntu/.s3cfg";
|
||||
|
||||
try
|
||||
{
|
||||
allTimestamps = Db.CsvTimestamps
|
||||
.Where(csvTimestamp => csvTimestamp.InstallationId == id)
|
||||
.OrderBy(csvTimestamp => csvTimestamp.Timestamp).ToList();
|
||||
|
||||
// Set up process start info
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "s3cmd",
|
||||
Arguments = $"--config {configPath} ls {bucketPath}",
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
// Start the process
|
||||
Process process = new Process
|
||||
{
|
||||
StartInfo = startInfo
|
||||
};
|
||||
|
||||
process.Start();
|
||||
|
||||
// Read the output
|
||||
string output = process.StandardOutput.ReadToEnd();
|
||||
string error = process.StandardError.ReadToEnd();
|
||||
|
||||
process.WaitForExit();
|
||||
|
||||
// Check for errors
|
||||
if (process.ExitCode != 0)
|
||||
{
|
||||
Console.WriteLine("Error executing command:");
|
||||
Console.WriteLine(error);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Command output:");
|
||||
//Console.WriteLine(output);
|
||||
// Define a regex pattern to match the filenames without .csv extension
|
||||
var pattern = @"/([^/]+)\.csv$";
|
||||
var regex = new Regex(pattern);
|
||||
|
||||
// Process each line of the output
|
||||
foreach (var line in output.Split('\n'))
|
||||
{
|
||||
var match = regex.Match(line);
|
||||
if (match.Success && long.Parse(match.Groups[1].Value)>=start && long.Parse(match.Groups[1].Value)<=end)
|
||||
{
|
||||
allTimestamps.Add(long.Parse(match.Groups[1].Value));
|
||||
//Console.WriteLine(match.Groups[1].Value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"Exception: {e.Message}");
|
||||
}
|
||||
|
||||
|
||||
|
||||
int totalRecords = allTimestamps.Count;
|
||||
if (totalRecords <= sampleSize)
|
||||
|
@ -186,7 +253,7 @@ public class Controller : ControllerBase
|
|||
|
||||
|
||||
int interval = totalRecords / sampleSize;
|
||||
var sampledTimestamps = new List<CsvTimestamp>();
|
||||
var sampledTimestamps = new List<Int64>();
|
||||
|
||||
for (int i = 0; i < totalRecords; i += interval)
|
||||
{
|
||||
|
@ -204,11 +271,6 @@ public class Controller : ControllerBase
|
|||
Console.WriteLine("SampledTimestamps = " + sampledTimestamps.Count);
|
||||
|
||||
return sampledTimestamps;
|
||||
|
||||
// return Db.CsvTimestamps
|
||||
// .Where(csvTimestamp => csvTimestamp.InstallationId == id)
|
||||
// .OrderByDescending(csvTimestamp => csvTimestamp.Timestamp)
|
||||
// .ToList();
|
||||
}
|
||||
|
||||
[HttpGet(nameof(GetUserById))]
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
using SQLite;
|
||||
|
||||
namespace InnovEnergy.App.Backend.DataTypes;
|
||||
|
||||
public class CsvTimestamp{
|
||||
[PrimaryKey, AutoIncrement]
|
||||
public Int64 Id { get; set; }
|
||||
public Int64 InstallationId { get; set; }
|
||||
public Int32 Timestamp { get; set; }
|
||||
|
||||
}
|
|
@ -105,7 +105,7 @@ public static class InstallationMethods
|
|||
|
||||
public static Installation HideWriteKeyIfUserIsNotAdmin(this Installation installation, int userIsAdmin)
|
||||
{
|
||||
if(userIsAdmin!=2)
|
||||
if(userIsAdmin==2)
|
||||
return installation;
|
||||
|
||||
installation.S3WriteKey = "";
|
||||
|
|
|
@ -289,7 +289,7 @@ public static class SessionMethods
|
|||
{
|
||||
var sessionUser = session?.User;
|
||||
var userAlreadyExists = Db.GetUserByEmail(newUser.Email);
|
||||
|
||||
|
||||
return sessionUser is not null
|
||||
&& userAlreadyExists is null
|
||||
&& sessionUser.UserType !=0
|
||||
|
|
|
@ -42,11 +42,6 @@ public static partial class Db
|
|||
return Insert(warning);
|
||||
}
|
||||
|
||||
public static Boolean Create(CsvTimestamp csvTimestamp)
|
||||
{
|
||||
return Insert(csvTimestamp);
|
||||
}
|
||||
|
||||
public static Boolean Create(Folder folder)
|
||||
{
|
||||
return Insert(folder);
|
||||
|
@ -176,34 +171,4 @@ public static partial class Db
|
|||
}
|
||||
}
|
||||
|
||||
public static void AddCsvTimestamp(CsvTimestamp newCsvTimestamp,int installationId)
|
||||
{
|
||||
var maxCSvPerInstallation = 60 * 24;
|
||||
//Find the total number of warnings for this installation
|
||||
var totalCsvNames = CsvTimestamps.Count(csvTimestamp => csvTimestamp.InstallationId == installationId);
|
||||
|
||||
//If there are 100 warnings, remove the one with the oldest timestamp
|
||||
if (totalCsvNames == maxCSvPerInstallation)
|
||||
{
|
||||
var oldestCSvTimestamp =
|
||||
CsvTimestamps.Where(csvTimestamp => csvTimestamp.InstallationId == installationId)
|
||||
.OrderBy(csvTimestamp => csvTimestamp.Timestamp)
|
||||
.FirstOrDefault();
|
||||
|
||||
//Remove the old error
|
||||
Delete(oldestCSvTimestamp);
|
||||
|
||||
//Add the new error
|
||||
Create(newCsvTimestamp);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Console.WriteLine("---------------Added the new Csv Timestamp to the database-----------------");
|
||||
Create(newCsvTimestamp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -37,7 +37,6 @@ public static partial class Db
|
|||
fileConnection.CreateTable<Error>();
|
||||
fileConnection.CreateTable<Warning>();
|
||||
fileConnection.CreateTable<UserAction>();
|
||||
fileConnection.CreateTable<CsvTimestamp>();
|
||||
|
||||
return fileConnection;
|
||||
//return CopyDbToMemory(fileConnection);
|
||||
|
@ -58,7 +57,6 @@ public static partial class Db
|
|||
memoryConnection.CreateTable<Error>();
|
||||
memoryConnection.CreateTable<Warning>();
|
||||
fileConnection.CreateTable<UserAction>();
|
||||
fileConnection.CreateTable<CsvTimestamp>();
|
||||
|
||||
//Copy all the existing tables from the disk to main memory
|
||||
fileConnection.Table<Session>().ForEach(memoryConnection.Insert);
|
||||
|
@ -71,7 +69,6 @@ public static partial class Db
|
|||
fileConnection.Table<Error>().ForEach(memoryConnection.Insert);
|
||||
fileConnection.Table<Warning>().ForEach(memoryConnection.Insert);
|
||||
fileConnection.Table<UserAction>().ForEach(memoryConnection.Insert);
|
||||
fileConnection.Table<CsvTimestamp>().ForEach(memoryConnection.Insert);
|
||||
|
||||
return memoryConnection;
|
||||
}
|
||||
|
@ -92,7 +89,6 @@ public static partial class Db
|
|||
public static TableQuery<Error> Errors => Connection.Table<Error>();
|
||||
public static TableQuery<Warning> Warnings => Connection.Table<Warning>();
|
||||
public static TableQuery<UserAction> UserActions => Connection.Table<UserAction>();
|
||||
public static TableQuery<CsvTimestamp> CsvTimestamps => Connection.Table<CsvTimestamp>();
|
||||
|
||||
public static void Init()
|
||||
{
|
||||
|
@ -115,7 +111,6 @@ public static partial class Db
|
|||
Connection.CreateTable<Error>();
|
||||
Connection.CreateTable<Warning>();
|
||||
Connection.CreateTable<UserAction>();
|
||||
Connection.CreateTable<CsvTimestamp>();
|
||||
});
|
||||
|
||||
//UpdateKeys();
|
||||
|
|
|
@ -90,20 +90,6 @@ public static partial class Db
|
|||
}
|
||||
}
|
||||
|
||||
public static Boolean Delete(CsvTimestamp csvTimestampToDelete)
|
||||
{
|
||||
var deleteSuccess = RunTransaction(DeleteCsvTimestampToDelete);
|
||||
if (deleteSuccess)
|
||||
Backup();
|
||||
return deleteSuccess;
|
||||
|
||||
|
||||
Boolean DeleteCsvTimestampToDelete()
|
||||
{
|
||||
return CsvTimestamps.Delete(csvTimestamp => csvTimestamp.Id == csvTimestampToDelete.Id) >0;
|
||||
}
|
||||
}
|
||||
|
||||
public static Boolean Delete(Installation installation)
|
||||
{
|
||||
var deleteSuccess = RunTransaction(DeleteInstallationAndItsDependencies);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
using System.Diagnostics;
|
||||
using Flurl.Http;
|
||||
using Hellang.Middleware.ProblemDetails;
|
||||
using InnovEnergy.App.Backend.Database;
|
||||
|
@ -22,6 +23,7 @@ public static class Program
|
|||
RabbitMqManager.StartRabbitMqConsumer();
|
||||
WebsocketManager.MonitorInstallationTable();
|
||||
|
||||
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddProblemDetails(setup =>
|
||||
{
|
||||
|
|
|
@ -52,8 +52,6 @@ public static class RabbitMqManager
|
|||
//A message can be an alarm, a warning or a heartbit
|
||||
StatusMessage? receivedStatusMessage = JsonSerializer.Deserialize<StatusMessage>(message);
|
||||
|
||||
|
||||
|
||||
lock (WebsocketManager.InstallationConnections)
|
||||
{
|
||||
//Consumer received a message
|
||||
|
@ -69,17 +67,6 @@ public static class RabbitMqManager
|
|||
if (receivedStatusMessage.Type == MessageType.Heartbit)
|
||||
{
|
||||
//Console.WriteLine("This is a heartbit message from installation: " + installationId + " Name of the file is "+ receivedStatusMessage.Timestamp);
|
||||
|
||||
if (receivedStatusMessage.Timestamp != 0)
|
||||
{
|
||||
CsvTimestamp newCsvTimestamp = new CsvTimestamp
|
||||
{
|
||||
InstallationId = installationId,
|
||||
Timestamp = receivedStatusMessage.Timestamp
|
||||
};
|
||||
|
||||
Db.AddCsvTimestamp(newCsvTimestamp, installationId);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -133,7 +120,7 @@ public static class RabbitMqManager
|
|||
Seen = false
|
||||
};
|
||||
|
||||
Console.WriteLine("Add an alarm for installation "+installationId);
|
||||
//Console.WriteLine("Add an alarm for installation "+installationId);
|
||||
|
||||
// Send replace battery email to support team if this alarm is "NeedToReplaceBattery"
|
||||
if (alarm.Description == "2 or more string are disabled")
|
||||
|
@ -187,9 +174,7 @@ public static class RabbitMqManager
|
|||
{
|
||||
WebsocketManager.InformWebsocketsForInstallation(installationId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
Channel.BasicConsume(queue: "statusQueue", autoAck: true, consumer: consumer);
|
||||
|
|
|
@ -19,7 +19,6 @@ public static class WebsocketManager
|
|||
lock (InstallationConnections){
|
||||
foreach (var installationConnection in InstallationConnections){
|
||||
if ((DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(1)){
|
||||
Console.WriteLine("Installation "+installationConnection.Key+" is offline, latest timestamp was "+installationConnection.Value.Timestamp);
|
||||
installationConnection.Value.Status = -1;
|
||||
if (installationConnection.Value.Connections.Count > 0){InformWebsocketsForInstallation(installationConnection.Key);}
|
||||
}
|
||||
|
@ -94,7 +93,7 @@ public static class WebsocketManager
|
|||
continue;
|
||||
}
|
||||
|
||||
Console.WriteLine("Received a new message from websocket");
|
||||
//Console.WriteLine("Received a new message from websocket");
|
||||
lock (InstallationConnections)
|
||||
{
|
||||
//Each front-end will send the list of the installations it wants to access
|
||||
|
@ -102,6 +101,7 @@ public static class WebsocketManager
|
|||
//Then, report the status of each requested installation to the front-end that created the websocket connection
|
||||
foreach (var installationId in installationIds)
|
||||
{
|
||||
//Console.WriteLine("New id is "+installationId);
|
||||
var installation = Db.GetInstallationById(installationId);
|
||||
if (!InstallationConnections.ContainsKey(installationId))
|
||||
{
|
||||
|
|
|
@ -9,5 +9,5 @@ Salimax0005 ie-entwicklung@10.2.4.36 Schreinerei Schönthal (Thu
|
|||
Salimax0006 ie-entwicklung@10.2.4.35 Steakhouse Mettmenstetten
|
||||
Salimax0007 ie-entwicklung@10.2.4.154 LerchenhofHerr Twannberg
|
||||
Salimax0008 ie-entwicklung@10.2.4.113 Wittmann Kottingbrunn
|
||||
Salimax0010 ie-entwicklung@10.2.4.211 Mohatech 1
|
||||
Salimax0010 ie-entwicklung@10.2.4.211 Mohatech 1 (Beat Moser)
|
||||
SalidomoServer ig@134.209.238.170
|
|
@ -54,6 +54,6 @@ INNOVENERGY_PROTOCOL_VERSION = '48TL200V3'
|
|||
|
||||
|
||||
# S3 Credentials
|
||||
S3BUCKET = "10-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e"
|
||||
S3KEY = "EXOa8cc58d2e51e389fed9ccbfa"
|
||||
S3SECRET = "hofDGMmSSN1OACYXHWRUGdG61mFjBxKC18sF0VpMQgY"
|
||||
S3BUCKET = "35-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e"
|
||||
S3KEY = "EXO2a70f415b6b387b5628020bd"
|
||||
S3SECRET = "qdlYoXDZyME8LEB8BFTuCmJoTzkP2Nebr2jVmlXUzgY"
|
||||
|
|
|
@ -448,22 +448,25 @@ function Configuration(props: ConfigurationProps) {
|
|||
fullWidth
|
||||
/>
|
||||
</div>
|
||||
<div style={{ marginBottom: '5px' }}>
|
||||
<TextField
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="Maximum_Discharge_Power"
|
||||
defaultMessage="Maximum Discharge Power (W)"
|
||||
/>
|
||||
}
|
||||
value={
|
||||
(props.values.maximumDischargePower[0].value as number) *
|
||||
48 *
|
||||
(props.values.DcDcNum[0].value as number)
|
||||
}
|
||||
fullWidth
|
||||
/>
|
||||
</div>
|
||||
|
||||
{props.values.maximumDischargePower && (
|
||||
<div style={{ marginBottom: '5px' }}>
|
||||
<TextField
|
||||
label={
|
||||
<FormattedMessage
|
||||
id="Maximum_Discharge_Power"
|
||||
defaultMessage="Maximum Discharge Power (W)"
|
||||
/>
|
||||
}
|
||||
value={
|
||||
(props.values.maximumDischargePower[0].value as number) *
|
||||
48 *
|
||||
(props.values.DcDcNum[0].value as number)
|
||||
}
|
||||
fullWidth
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<TextField
|
||||
label={
|
||||
|
|
|
@ -387,6 +387,26 @@ function HistoryOfActions(props: HistoryProps) {
|
|||
/>
|
||||
</Typography>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
marginTop: '15px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="body1"
|
||||
color="dimgrey"
|
||||
fontWeight="bold"
|
||||
fontSize="1rem"
|
||||
gutterBottom
|
||||
noWrap
|
||||
>
|
||||
<FormattedMessage id="edit" defaultMessage="Edit" />
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<Divider />
|
||||
<div style={{ maxHeight: '600px', overflowY: 'auto' }}>
|
||||
|
|
|
@ -282,30 +282,10 @@ function Information(props: InformationProps) {
|
|||
/>
|
||||
</div>
|
||||
|
||||
{/*<div>*/}
|
||||
{/* <TextField*/}
|
||||
{/* label="S3 Write Key"*/}
|
||||
{/* name="s3writekey"*/}
|
||||
{/* value={formValues.s3WriteKey}*/}
|
||||
{/* variant="outlined"*/}
|
||||
{/* fullWidth*/}
|
||||
{/* />*/}
|
||||
{/*</div>*/}
|
||||
|
||||
{/*<div>*/}
|
||||
{/* <TextField*/}
|
||||
{/* label="S3 Write Secret Key"*/}
|
||||
{/* name="s3writesecretkey"*/}
|
||||
{/* value={formValues.s3WriteSecret}*/}
|
||||
{/* variant="outlined"*/}
|
||||
{/* fullWidth*/}
|
||||
{/* />*/}
|
||||
{/*</div>*/}
|
||||
|
||||
<div>
|
||||
<TextField
|
||||
label="S3 Bucket Name"
|
||||
name="s3writesecretkey"
|
||||
name="s3bucketname"
|
||||
value={
|
||||
formValues.s3BucketId +
|
||||
'-3e5b3069-214a-43ee-8d85-57d72000c19d'
|
||||
|
@ -314,6 +294,25 @@ function Information(props: InformationProps) {
|
|||
fullWidth
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<TextField
|
||||
label="S3 Write Key"
|
||||
name="s3writekey"
|
||||
value={formValues.s3WriteKey}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<TextField
|
||||
label="S3 Write Secret Key"
|
||||
name="s3writesecretkey"
|
||||
value={formValues.s3WriteSecret}
|
||||
variant="outlined"
|
||||
fullWidth
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
|
|
@ -117,11 +117,11 @@ function Installation(props: singleInstallationProps) {
|
|||
};
|
||||
|
||||
const fetchDataPeriodically = async () => {
|
||||
var timeperiodToSearch = 70;
|
||||
var timeperiodToSearch = 90;
|
||||
let res;
|
||||
let timestampToFetch;
|
||||
|
||||
for (var i = timeperiodToSearch; i > 0; i -= 2) {
|
||||
for (var i = 0; i < timeperiodToSearch; i += 2) {
|
||||
if (!continueFetching.current) {
|
||||
return false;
|
||||
}
|
||||
|
@ -379,6 +379,7 @@ function Installation(props: singleInstallationProps) {
|
|||
{loading &&
|
||||
currentTab != 'information' &&
|
||||
currentTab != 'history' &&
|
||||
currentTab != 'overview' &&
|
||||
currentTab != 'log' && (
|
||||
<Container
|
||||
maxWidth="xl"
|
||||
|
|
|
@ -85,7 +85,14 @@ function Overview(props: OverviewProps) {
|
|||
const resultPromise: Promise<{
|
||||
chartData: chartDataInterface;
|
||||
chartOverview: overviewInterface;
|
||||
}> = transformInputToDailyData(props.s3Credentials, props.id);
|
||||
}> = transformInputToDailyData(
|
||||
props.s3Credentials,
|
||||
props.id,
|
||||
UnixTime.fromTicks(new Date().getTime() / 1000).earlier(
|
||||
TimeSpan.fromDays(1)
|
||||
),
|
||||
UnixTime.fromTicks(new Date().getTime() / 1000)
|
||||
);
|
||||
|
||||
resultPromise
|
||||
.then((result) => {
|
||||
|
@ -169,6 +176,7 @@ function Overview(props: OverviewProps) {
|
|||
const resultPromise: Promise<{
|
||||
chartAggregatedData: chartAggregatedDataInterface;
|
||||
chartOverview: overviewInterface;
|
||||
dateList: string[];
|
||||
}> = transformInputToAggregatedData(
|
||||
props.s3Credentials,
|
||||
dayjs().subtract(1, 'week'),
|
||||
|
@ -193,7 +201,7 @@ function Overview(props: OverviewProps) {
|
|||
prevData.concat({
|
||||
chartData: result.chartAggregatedData,
|
||||
chartOverview: result.chartOverview,
|
||||
datelist: computeLast7Days(),
|
||||
datelist: result.dateList,
|
||||
netbalance: powerDifference
|
||||
})
|
||||
);
|
||||
|
@ -482,22 +490,22 @@ function Overview(props: OverviewProps) {
|
|||
<FormattedMessage id="lastweek" defaultMessage="Last week" />
|
||||
</Button>
|
||||
|
||||
{aggregatedData && (
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleSetDate}
|
||||
disabled={loading}
|
||||
sx={{
|
||||
marginTop: '20px',
|
||||
marginLeft: '10px',
|
||||
backgroundColor: dateOpen ? '#808080' : '#ffc04d',
|
||||
color: '#000000',
|
||||
'&:hover': { bgcolor: '#f7b34d' }
|
||||
}}
|
||||
>
|
||||
<FormattedMessage id="set_date" defaultMessage="Set Date" />
|
||||
</Button>
|
||||
)}
|
||||
{/*{aggregatedData && (*/}
|
||||
<Button
|
||||
variant="contained"
|
||||
onClick={handleSetDate}
|
||||
disabled={loading}
|
||||
sx={{
|
||||
marginTop: '20px',
|
||||
marginLeft: '10px',
|
||||
backgroundColor: dateOpen ? '#808080' : '#ffc04d',
|
||||
color: '#000000',
|
||||
'&:hover': { bgcolor: '#f7b34d' }
|
||||
}}
|
||||
>
|
||||
<FormattedMessage id="set_date" defaultMessage="Set Date" />
|
||||
</Button>
|
||||
{/*)}*/}
|
||||
</Grid>
|
||||
|
||||
<Grid
|
||||
|
|
|
@ -78,6 +78,7 @@ function SalidomoOverview(props: salidomoOverviewProps) {
|
|||
const resultPromise: Promise<{
|
||||
chartAggregatedData: chartAggregatedDataInterface;
|
||||
chartOverview: overviewInterface;
|
||||
dateList: string[];
|
||||
}> = transformInputToAggregatedData(
|
||||
props.s3Credentials,
|
||||
dayjs().subtract(1, 'week'),
|
||||
|
@ -102,7 +103,7 @@ function SalidomoOverview(props: salidomoOverviewProps) {
|
|||
prevData.concat({
|
||||
chartData: result.chartAggregatedData,
|
||||
chartOverview: result.chartOverview,
|
||||
datelist: computeLast7Days(),
|
||||
datelist: result.dateList,
|
||||
netbalance: powerDifference
|
||||
})
|
||||
);
|
||||
|
|
|
@ -18,6 +18,7 @@ import { FormattedMessage } from 'react-intl';
|
|||
import { useLocation, useNavigate } from 'react-router-dom';
|
||||
import routes from '../../../Resources/routes.json';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import BuildIcon from '@mui/icons-material/Build';
|
||||
|
||||
interface FlatInstallationViewProps {
|
||||
installations: I_Installation[];
|
||||
|
@ -26,7 +27,7 @@ interface FlatInstallationViewProps {
|
|||
const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
||||
const [isRowHovered, setHoveredRow] = useState(-1);
|
||||
const webSocketContext = useContext(WebSocketContext);
|
||||
const { getStatus } = webSocketContext;
|
||||
const { getStatus, getTestingMode } = webSocketContext;
|
||||
const navigate = useNavigate();
|
||||
const [selectedInstallation, setSelectedInstallation] = useState<number>(-1);
|
||||
const currentLocation = useLocation();
|
||||
|
@ -320,6 +321,19 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
|||
: 'green'
|
||||
}}
|
||||
/>
|
||||
{getTestingMode(installation.id) && (
|
||||
<BuildIcon
|
||||
style={{
|
||||
width: '23px',
|
||||
height: '23px',
|
||||
color: 'purple',
|
||||
borderRadius: '50%',
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
marginLeft: '15px'
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
|
|
@ -24,6 +24,9 @@ import BatteryView from '../BatteryView/BatteryView';
|
|||
import Log from '../Log/Log';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import SalidomoOverview from '../Overview/salidomoOverview';
|
||||
import { UserType } from '../../../interfaces/UserTypes';
|
||||
import HistoryOfActions from '../History/History';
|
||||
import BuildIcon from '@mui/icons-material/Build';
|
||||
|
||||
interface singleInstallationProps {
|
||||
current_installation?: I_Installation;
|
||||
|
@ -36,7 +39,7 @@ function Installation(props: singleInstallationProps) {
|
|||
const location = useLocation().pathname;
|
||||
const [errorLoadingS3Data, setErrorLoadingS3Data] = useState(false);
|
||||
const webSocketsContext = useContext(WebSocketContext);
|
||||
const { getStatus } = webSocketsContext;
|
||||
const { getStatus, getTestingMode } = webSocketsContext;
|
||||
const [currentTab, setCurrentTab] = useState<string>(undefined);
|
||||
const [values, setValues] = useState<TopologyValues | null>(null);
|
||||
const status = getStatus(props.current_installation.id);
|
||||
|
@ -74,11 +77,11 @@ function Installation(props: singleInstallationProps) {
|
|||
const continueFetching = useRef(false);
|
||||
|
||||
const fetchDataPeriodically = async () => {
|
||||
var timeperiodToSearch = 70;
|
||||
var timeperiodToSearch = 90;
|
||||
let res;
|
||||
let timestampToFetch;
|
||||
|
||||
for (var i = timeperiodToSearch; i > 0; i -= 2) {
|
||||
for (var i = 0; i < timeperiodToSearch; i += 2) {
|
||||
if (!continueFetching.current) {
|
||||
return false;
|
||||
}
|
||||
|
@ -274,11 +277,26 @@ function Installation(props: singleInstallationProps) {
|
|||
: 'green'
|
||||
}}
|
||||
/>
|
||||
|
||||
{getTestingMode(props.current_installation.id) && (
|
||||
<BuildIcon
|
||||
style={{
|
||||
width: '23px',
|
||||
height: '23px',
|
||||
color: 'purple',
|
||||
borderRadius: '50%',
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
marginLeft: '15px'
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{loading &&
|
||||
currentTab != 'information' &&
|
||||
currentTab != 'overview' &&
|
||||
currentTab != 'history' &&
|
||||
currentTab != 'log' && (
|
||||
<Container
|
||||
maxWidth="xl"
|
||||
|
@ -354,6 +372,18 @@ function Installation(props: singleInstallationProps) {
|
|||
}
|
||||
></Route>
|
||||
|
||||
{currentUser.userType == UserType.admin && (
|
||||
<Route
|
||||
path={routes.history}
|
||||
element={
|
||||
<HistoryOfActions
|
||||
errorLoadingS3Data={errorLoadingS3Data}
|
||||
id={props.current_installation.id}
|
||||
></HistoryOfActions>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Route
|
||||
path={'*'}
|
||||
element={<Navigate to={routes.information}></Navigate>}
|
||||
|
|
|
@ -14,7 +14,7 @@ function SalidomoInstallationTabs() {
|
|||
const location = useLocation();
|
||||
const context = useContext(UserContext);
|
||||
const { currentUser } = context;
|
||||
const tabList = ['batteryview', 'information', 'overview', 'log'];
|
||||
const tabList = ['batteryview', 'information', 'overview', 'log', 'history'];
|
||||
|
||||
const [currentTab, setCurrentTab] = useState<string>(undefined);
|
||||
const [fetchedInstallations, setFetchedInstallations] =
|
||||
|
@ -106,6 +106,15 @@ function SalidomoInstallationTabs() {
|
|||
label: (
|
||||
<FormattedMessage id="information" defaultMessage="Information" />
|
||||
)
|
||||
},
|
||||
{
|
||||
value: 'history',
|
||||
label: (
|
||||
<FormattedMessage
|
||||
id="history"
|
||||
defaultMessage="History Of Actions"
|
||||
/>
|
||||
)
|
||||
}
|
||||
]
|
||||
: [
|
||||
|
|
|
@ -380,47 +380,30 @@ export const transformInputToDailyData = async (
|
|||
};
|
||||
});
|
||||
|
||||
let timestampArray: CsvTimestamp[] = [];
|
||||
let timestampArray: number[] = [];
|
||||
let adjustedTimestampArray = [];
|
||||
const timestampPromises = [];
|
||||
|
||||
if (start_time && end_time) {
|
||||
await axiosConfig
|
||||
.get(
|
||||
`/GetCsvTimestampsForInstallation?id=${id}&start=${start_time.ticks}&end=${end_time.ticks}`
|
||||
)
|
||||
.then((res: AxiosResponse<CsvTimestamp[]>) => {
|
||||
timestampArray = res.data;
|
||||
})
|
||||
.catch((err: AxiosError) => {
|
||||
if (err.response && err.response.status == 401) {
|
||||
//removeToken();
|
||||
//navigate(routes.login);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
await axiosConfig
|
||||
.get(`/GetCsvTimestampsForInstallation?id=${id}&start=${0}&end=${0}`)
|
||||
.then((res: AxiosResponse<CsvTimestamp[]>) => {
|
||||
timestampArray = res.data;
|
||||
})
|
||||
.catch((err: AxiosError) => {
|
||||
if (err.response && err.response.status == 401) {
|
||||
//removeToken();
|
||||
//navigate(routes.login);
|
||||
}
|
||||
});
|
||||
}
|
||||
await axiosConfig
|
||||
.get(
|
||||
`/GetCsvTimestampsForInstallation?id=${id}&start=${start_time.ticks}&end=${end_time.ticks}`
|
||||
)
|
||||
.then((res: AxiosResponse<number[]>) => {
|
||||
timestampArray = res.data;
|
||||
})
|
||||
.catch((err: AxiosError) => {
|
||||
if (err.response && err.response.status == 401) {
|
||||
//removeToken();
|
||||
//navigate(routes.login);
|
||||
}
|
||||
});
|
||||
|
||||
for (var i = 0; i < timestampArray.length; i++) {
|
||||
timestampPromises.push(
|
||||
fetchDataForOneTime(
|
||||
UnixTime.fromTicks(timestampArray[i].timestamp),
|
||||
s3Credentials
|
||||
)
|
||||
fetchDataForOneTime(UnixTime.fromTicks(timestampArray[i]), s3Credentials)
|
||||
);
|
||||
|
||||
const adjustedTimestamp = new Date(timestampArray[i].timestamp * 1000);
|
||||
const adjustedTimestamp = new Date(timestampArray[i] * 1000);
|
||||
//Timezone offset is negative, so we convert the timestamp to the current zone by subtracting the corresponding offset
|
||||
adjustedTimestamp.setHours(
|
||||
adjustedTimestamp.getHours() - adjustedTimestamp.getTimezoneOffset() / 60
|
||||
|
@ -619,7 +602,6 @@ export const transformInputToAggregatedData = async (
|
|||
if (result[path].value < overviewData[path].min) {
|
||||
overviewData[path].min = result[path].value;
|
||||
}
|
||||
|
||||
if (result[path].value > overviewData[path].max) {
|
||||
overviewData[path].max = result[path].value;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue