Fixed exoscale keys
This commit is contained in:
parent
6a18e56cf7
commit
ac8f874255
|
@ -101,6 +101,23 @@ public class Controller : ControllerBase
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet(nameof(GetAllWarningsForInstallation))]
|
||||||
|
public ActionResult<IEnumerable<Warning>> GetAllWarningsForInstallation(Int64 id, Token authToken)
|
||||||
|
{
|
||||||
|
var user = Db.GetSession(authToken)?.User;
|
||||||
|
if (user == null)
|
||||||
|
return Unauthorized();
|
||||||
|
|
||||||
|
var installation = Db.GetInstallationById(id);
|
||||||
|
|
||||||
|
if (installation is null || !user.HasAccessTo(installation))
|
||||||
|
return Unauthorized();
|
||||||
|
|
||||||
|
return Db.Warnings
|
||||||
|
.Where(error => error.InstallationId == id)
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet(nameof(GetUserById))]
|
[HttpGet(nameof(GetUserById))]
|
||||||
public ActionResult<User> GetUserById(Int64 id, Token authToken)
|
public ActionResult<User> GetUserById(Int64 id, Token authToken)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,13 +2,22 @@ using SQLite;
|
||||||
|
|
||||||
namespace InnovEnergy.App.Backend.DataTypes;
|
namespace InnovEnergy.App.Backend.DataTypes;
|
||||||
|
|
||||||
public class Error
|
public abstract class LogEntry
|
||||||
{
|
{
|
||||||
[PrimaryKey, AutoIncrement]
|
[PrimaryKey, AutoIncrement]
|
||||||
public Int64 Id { get; set; }
|
public Int64 Id { get; set; }
|
||||||
public Int64 InstallationId { get; set; }
|
public Int64 InstallationId { get; set; }
|
||||||
public String ErrorDescription { get; set; } = null!;
|
public String Description { get; set; } = null!;
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
public String DeviceCreatedTheError { get; set; } = null!;
|
public String DeviceCreatedTheMessage { get; set; } = null!;
|
||||||
public Boolean Seen { get; set; }
|
public Boolean Seen { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Derived class for errors
|
||||||
|
public class Error : LogEntry
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Warning : LogEntry
|
||||||
|
{
|
||||||
|
}
|
|
@ -13,11 +13,8 @@ namespace InnovEnergy.App.Backend.DataTypes.Methods;
|
||||||
public static class ExoCmd
|
public static class ExoCmd
|
||||||
{
|
{
|
||||||
|
|
||||||
private const String Key = "EXOea18f5a82bd358896154c783";
|
|
||||||
private const String Secret = "lYtzU7R5e0L6XKOgBaLVPFr41nEBDxDdXU47zBAEI6M";
|
|
||||||
|
|
||||||
[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "<Pending>")]
|
[UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code", Justification = "<Pending>")]
|
||||||
public static readonly S3Credentials? S3Creds = JsonSerializer.Deserialize<S3Credentials>(File.OpenRead("./Resources/exoscaleS3.json"));
|
public static readonly S3Credentials S3Credentials = JsonSerializer.Deserialize<S3Credentials>(File.OpenRead("./Resources/exoscaleS3.json"))!;
|
||||||
|
|
||||||
private static Byte[] HmacSha256Digest(String message, String secret)
|
private static Byte[] HmacSha256Digest(String message, String secret)
|
||||||
{
|
{
|
||||||
|
@ -47,7 +44,7 @@ public static class ExoCmd
|
||||||
//Console.WriteLine("Message to sign:\n" + messageToSign);
|
//Console.WriteLine("Message to sign:\n" + messageToSign);
|
||||||
|
|
||||||
|
|
||||||
var hmac = HmacSha256Digest(messageToSign, Secret);
|
var hmac = HmacSha256Digest(messageToSign, S3Credentials.Secret);
|
||||||
return Convert.ToBase64String(hmac);
|
return Convert.ToBase64String(hmac);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +73,7 @@ public static class ExoCmd
|
||||||
|
|
||||||
var unixtime = DateTimeOffset.UtcNow.ToUnixTimeSeconds()+60;
|
var unixtime = DateTimeOffset.UtcNow.ToUnixTimeSeconds()+60;
|
||||||
|
|
||||||
var authheader = "credential="+Key+",signed-query-args="+",expires="+unixtime+",signature="+BuildSignature("GET", method, unixtime);
|
var authheader = "credential="+S3Credentials.Key+",signed-query-args="+",expires="+unixtime+",signature="+BuildSignature("GET", method, unixtime);
|
||||||
|
|
||||||
var client = new HttpClient();
|
var client = new HttpClient();
|
||||||
|
|
||||||
|
@ -92,10 +89,12 @@ public static class ExoCmd
|
||||||
{
|
{
|
||||||
var url = "https://api-ch-dk-2.exoscale.com/v2/api-key";
|
var url = "https://api-ch-dk-2.exoscale.com/v2/api-key";
|
||||||
var method = "api-key";
|
var method = "api-key";
|
||||||
var contentString = $$"""{"role-id": "{{roleName}}", "name":"{{installation.BucketName()}}v2"}""";
|
var contentString = $$"""{"role-id": "{{roleName}}", "name":"{{installation.BucketName()}}"}""";
|
||||||
var unixtime = DateTimeOffset.UtcNow.ToUnixTimeSeconds() + 60;
|
var unixtime = DateTimeOffset.UtcNow.ToUnixTimeSeconds() + 60;
|
||||||
|
|
||||||
var authheader = "credential=" + Key + ",expires=" + unixtime + ",signature=" +
|
|
||||||
|
|
||||||
|
var authheader = "credential=" + S3Credentials.Key + ",expires=" + unixtime + ",signature=" +
|
||||||
BuildSignature("POST", method, contentString, unixtime);
|
BuildSignature("POST", method, contentString, unixtime);
|
||||||
|
|
||||||
var client = new HttpClient();
|
var client = new HttpClient();
|
||||||
|
@ -143,7 +142,7 @@ public static class ExoCmd
|
||||||
|
|
||||||
var unixtime = DateTimeOffset.UtcNow.ToUnixTimeSeconds()+60;
|
var unixtime = DateTimeOffset.UtcNow.ToUnixTimeSeconds()+60;
|
||||||
|
|
||||||
var authheader = "credential="+Key+",signed-query-args="+",expires="+unixtime+",signature="+BuildSignature("POST", method, contentString, unixtime);
|
var authheader = "credential="+S3Credentials.Key+",signed-query-args="+",expires="+unixtime+",signature="+BuildSignature("POST", method, contentString, unixtime);
|
||||||
|
|
||||||
var client = new HttpClient();
|
var client = new HttpClient();
|
||||||
|
|
||||||
|
@ -171,7 +170,7 @@ public static class ExoCmd
|
||||||
|
|
||||||
var unixtime = DateTimeOffset.UtcNow.ToUnixTimeSeconds()+60;
|
var unixtime = DateTimeOffset.UtcNow.ToUnixTimeSeconds()+60;
|
||||||
|
|
||||||
var authheader = "credential="+Key+",expires="+unixtime+",signature="+BuildSignature("DELETE", method, unixtime);
|
var authheader = "credential="+S3Credentials.Key+",expires="+unixtime+",signature="+BuildSignature("DELETE", method, unixtime);
|
||||||
|
|
||||||
var client = new HttpClient();
|
var client = new HttpClient();
|
||||||
|
|
||||||
|
@ -220,7 +219,7 @@ public static class ExoCmd
|
||||||
|
|
||||||
var unixtime = DateTimeOffset.UtcNow.ToUnixTimeSeconds()+60;
|
var unixtime = DateTimeOffset.UtcNow.ToUnixTimeSeconds()+60;
|
||||||
|
|
||||||
var authheader = "credential="+Key+",signed-query-args="+",expires="+unixtime+",signature="+BuildSignature("POST", method, contentString, unixtime);
|
var authheader = "credential="+S3Credentials.Key+",signed-query-args="+",expires="+unixtime+",signature="+BuildSignature("POST", method, contentString, unixtime);
|
||||||
|
|
||||||
var client = new HttpClient();
|
var client = new HttpClient();
|
||||||
|
|
||||||
|
@ -245,7 +244,7 @@ public static class ExoCmd
|
||||||
|
|
||||||
public static async Task<Boolean> CreateBucket(this Installation installation)
|
public static async Task<Boolean> CreateBucket(this Installation installation)
|
||||||
{
|
{
|
||||||
var s3Region = new S3Region($"https://{installation.S3Region}.{installation.S3Provider}", S3Creds!);
|
var s3Region = new S3Region($"https://{installation.S3Region}.{installation.S3Provider}", S3Credentials!);
|
||||||
return await s3Region.PutBucket(installation.BucketName()) != null;
|
return await s3Region.PutBucket(installation.BucketName()) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,7 +271,7 @@ public static class ExoCmd
|
||||||
// return result.ExitCode == 200;
|
// return result.ExitCode == 200;
|
||||||
|
|
||||||
|
|
||||||
var s3Region = new S3Region($"https://{installation.S3Region}.{installation.S3Provider}", S3Creds!);
|
var s3Region = new S3Region($"https://{installation.S3Region}.{installation.S3Provider}", S3Credentials!);
|
||||||
var url = s3Region.Bucket(installation.BucketName()).Path("config.json");
|
var url = s3Region.Bucket(installation.BucketName()).Path("config.json");
|
||||||
return await url.PutObject(config);
|
return await url.PutObject(config);
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,8 @@ public static class InstallationMethods
|
||||||
|
|
||||||
public static async Task<Boolean> RenewS3Credentials(this Installation installation)
|
public static async Task<Boolean> RenewS3Credentials(this Installation installation)
|
||||||
{
|
{
|
||||||
if(installation.S3Key != "") await installation.RevokeReadKey();
|
if(!installation.S3Key.IsNullOrEmpty())
|
||||||
|
await installation.RevokeReadKey();
|
||||||
|
|
||||||
var (key,secret) = await installation.CreateReadKey();
|
var (key,secret) = await installation.CreateReadKey();
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,11 @@ public static partial class Db
|
||||||
return Insert(error);
|
return Insert(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Boolean Create(Warning warning)
|
||||||
|
{
|
||||||
|
return Insert(warning);
|
||||||
|
}
|
||||||
|
|
||||||
public static Boolean Create(Folder folder)
|
public static Boolean Create(Folder folder)
|
||||||
{
|
{
|
||||||
return Insert(folder);
|
return Insert(folder);
|
||||||
|
@ -80,4 +85,30 @@ public static partial class Db
|
||||||
Create(newError);
|
Create(newError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void HandleWarning(Warning newWarning,int installationId)
|
||||||
|
{
|
||||||
|
//Find the total number of warnings for this installation
|
||||||
|
var totalWarnings = Warnings.Count(warning => warning.InstallationId == installationId);
|
||||||
|
|
||||||
|
//If there are 100 warnings, remove the one with the oldest timestamp
|
||||||
|
if (totalWarnings == 100)
|
||||||
|
{
|
||||||
|
var oldestWarning =
|
||||||
|
Warnings.Where(warning => warning.InstallationId == installationId)
|
||||||
|
.OrderBy(warning => warning.CreatedAt)
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
//Remove the old error
|
||||||
|
Delete(oldestWarning);
|
||||||
|
|
||||||
|
//Add the new error
|
||||||
|
Create(newWarning);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("---------------Added the new Error to the database-----------------");
|
||||||
|
Create(newWarning);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -12,7 +12,6 @@ using SQLiteConnection = SQLite.SQLiteConnection;
|
||||||
|
|
||||||
namespace InnovEnergy.App.Backend.Database;
|
namespace InnovEnergy.App.Backend.Database;
|
||||||
|
|
||||||
|
|
||||||
public static partial class Db
|
public static partial class Db
|
||||||
{
|
{
|
||||||
private static SQLiteConnection Connection { get; } = InitConnection();
|
private static SQLiteConnection Connection { get; } = InitConnection();
|
||||||
|
@ -20,9 +19,9 @@ public static partial class Db
|
||||||
private static SQLiteConnection InitConnection()
|
private static SQLiteConnection InitConnection()
|
||||||
{
|
{
|
||||||
var latestDb = new DirectoryInfo("DbBackups")
|
var latestDb = new DirectoryInfo("DbBackups")
|
||||||
.GetFiles()
|
.GetFiles()
|
||||||
.OrderBy(f => f.LastWriteTime)
|
.OrderBy(f => f.LastWriteTime)
|
||||||
.Last().Name;
|
.Last().Name;
|
||||||
|
|
||||||
//This is the file connection from the DbBackups folder
|
//This is the file connection from the DbBackups folder
|
||||||
var fileConnection = new SQLiteConnection("DbBackups/" + latestDb);
|
var fileConnection = new SQLiteConnection("DbBackups/" + latestDb);
|
||||||
|
@ -36,6 +35,7 @@ public static partial class Db
|
||||||
fileConnection.CreateTable<Session>();
|
fileConnection.CreateTable<Session>();
|
||||||
fileConnection.CreateTable<OrderNumber2Installation>();
|
fileConnection.CreateTable<OrderNumber2Installation>();
|
||||||
fileConnection.CreateTable<Error>();
|
fileConnection.CreateTable<Error>();
|
||||||
|
fileConnection.CreateTable<Warning>();
|
||||||
|
|
||||||
return CopyDbToMemory(fileConnection);
|
return CopyDbToMemory(fileConnection);
|
||||||
}
|
}
|
||||||
|
@ -53,6 +53,7 @@ public static partial class Db
|
||||||
memoryConnection.CreateTable<Session>();
|
memoryConnection.CreateTable<Session>();
|
||||||
memoryConnection.CreateTable<OrderNumber2Installation>();
|
memoryConnection.CreateTable<OrderNumber2Installation>();
|
||||||
memoryConnection.CreateTable<Error>();
|
memoryConnection.CreateTable<Error>();
|
||||||
|
memoryConnection.CreateTable<Warning>();
|
||||||
|
|
||||||
//Copy all the existing tables from the disk to main memory
|
//Copy all the existing tables from the disk to main memory
|
||||||
fileConnection.Table<Session>().ForEach(memoryConnection.Insert);
|
fileConnection.Table<Session>().ForEach(memoryConnection.Insert);
|
||||||
|
@ -63,6 +64,7 @@ public static partial class Db
|
||||||
fileConnection.Table<InstallationAccess>().ForEach(memoryConnection.Insert);
|
fileConnection.Table<InstallationAccess>().ForEach(memoryConnection.Insert);
|
||||||
fileConnection.Table<OrderNumber2Installation>().ForEach(memoryConnection.Insert);
|
fileConnection.Table<OrderNumber2Installation>().ForEach(memoryConnection.Insert);
|
||||||
fileConnection.Table<Error>().ForEach(memoryConnection.Insert);
|
fileConnection.Table<Error>().ForEach(memoryConnection.Insert);
|
||||||
|
fileConnection.Table<Warning>().ForEach(memoryConnection.Insert);
|
||||||
|
|
||||||
return memoryConnection;
|
return memoryConnection;
|
||||||
}
|
}
|
||||||
|
@ -73,16 +75,18 @@ public static partial class Db
|
||||||
Connection.Backup("DbBackups/" + filename);
|
Connection.Backup("DbBackups/" + filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TableQuery<Session> Sessions => Connection.Table<Session>();
|
public static TableQuery<Session> Sessions => Connection.Table<Session>();
|
||||||
public static TableQuery<Folder> Folders => Connection.Table<Folder>();
|
public static TableQuery<Folder> Folders => Connection.Table<Folder>();
|
||||||
public static TableQuery<Installation> Installations => Connection.Table<Installation>();
|
public static TableQuery<Installation> Installations => Connection.Table<Installation>();
|
||||||
public static TableQuery<User> Users => Connection.Table<User>();
|
public static TableQuery<User> Users => Connection.Table<User>();
|
||||||
public static TableQuery<FolderAccess> FolderAccess => Connection.Table<FolderAccess>();
|
public static TableQuery<FolderAccess> FolderAccess => Connection.Table<FolderAccess>();
|
||||||
public static TableQuery<InstallationAccess> InstallationAccess => Connection.Table<InstallationAccess>();
|
public static TableQuery<InstallationAccess> InstallationAccess => Connection.Table<InstallationAccess>();
|
||||||
public static TableQuery<OrderNumber2Installation> OrderNumber2Installation => Connection.Table<OrderNumber2Installation>();
|
public static TableQuery<OrderNumber2Installation> OrderNumber2Installation => Connection.Table<OrderNumber2Installation>();
|
||||||
public static TableQuery<Error> Errors => Connection.Table<Error>();
|
public static TableQuery<Error> Errors => Connection.Table<Error>();
|
||||||
|
public static TableQuery<Warning> Warnings => Connection.Table<Warning>();
|
||||||
|
|
||||||
public static void Init(){
|
public static void Init()
|
||||||
|
{
|
||||||
// used to force static constructor
|
// used to force static constructor
|
||||||
//Since this class is static, we call Init method from the Program.cs to initialize all the fields of the class
|
//Since this class is static, we call Init method from the Program.cs to initialize all the fields of the class
|
||||||
}
|
}
|
||||||
|
@ -100,16 +104,46 @@ public static partial class Db
|
||||||
Connection.CreateTable<Session>();
|
Connection.CreateTable<Session>();
|
||||||
Connection.CreateTable<OrderNumber2Installation>();
|
Connection.CreateTable<OrderNumber2Installation>();
|
||||||
Connection.CreateTable<Error>();
|
Connection.CreateTable<Error>();
|
||||||
|
Connection.CreateTable<Warning>();
|
||||||
});
|
});
|
||||||
|
|
||||||
Observable.Interval(TimeSpan.FromHours(0.5))
|
UpdateKeys().SupressAwaitWarning();
|
||||||
.StartWith(0) // Do it right away (on startup)
|
CleanupSessions().SupressAwaitWarning();
|
||||||
.ObserveOn(TaskPoolScheduler.Default)
|
|
||||||
.SubscribeOn(TaskPoolScheduler.Default)
|
|
||||||
.SelectMany(Cleanup)
|
|
||||||
.Subscribe();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task CleanupSessions()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DeleteStaleSessions();
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine("An error has occured when cleaning stale sessions, exception is:\n"+e);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(TimeSpan.FromHours(0.5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task UpdateKeys()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await UpdateS3Urls();
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine("An error has occured when updating S3 keys, exception is:\n"+e);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Delay(TimeSpan.FromHours(24));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static Boolean RunTransaction(Func<Boolean> func)
|
private static Boolean RunTransaction(Func<Boolean> func)
|
||||||
|
@ -133,37 +167,30 @@ public static partial class Db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static async Task<Boolean> Cleanup(Int64 _)
|
|
||||||
{
|
|
||||||
await UpdateS3Urls();
|
|
||||||
DeleteStaleSessions();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void DeleteStaleSessions()
|
private static void DeleteStaleSessions()
|
||||||
{
|
{
|
||||||
var deadline = DateTime.Now.AddDays((-1)*Session.MaxAge.Days);
|
var deadline = DateTime.Now.AddDays((-1) * Session.MaxAge.Days);
|
||||||
Sessions.Delete(s => s.LastSeen < deadline);
|
Sessions.Delete(s => s.LastSeen < deadline);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static async Task UpdateS3Urls()
|
private static async Task UpdateS3Urls()
|
||||||
{
|
{
|
||||||
var regions = Installations
|
var regions = Installations
|
||||||
.Select(i => i.S3Region)
|
.Select(i => i.S3Region)
|
||||||
.Distinct()
|
.Distinct()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
const String provider = "exo.io";
|
const String provider = "exo.io";
|
||||||
|
|
||||||
foreach (var region in regions)
|
foreach (var region in regions)
|
||||||
{
|
{
|
||||||
var s3Region = new S3Region($"https://{region}.{provider}", ExoCmd.S3Creds!);
|
var s3Region = new S3Region($"https://{region}.{provider}", ExoCmd.S3Credentials!);
|
||||||
var bucketList = await s3Region.ListAllBuckets();
|
var bucketList = await s3Region.ListAllBuckets();
|
||||||
|
|
||||||
var installations = from bucket in bucketList.Buckets
|
var installations = from bucket in bucketList.Buckets
|
||||||
from installation in Installations
|
from installation in Installations
|
||||||
where installation.BucketName() == bucket.BucketName
|
where installation.BucketName() == bucket.BucketName
|
||||||
select installation;
|
select installation;
|
||||||
|
|
||||||
foreach (var installation in installations)
|
foreach (var installation in installations)
|
||||||
{
|
{
|
||||||
|
|
|
@ -49,6 +49,20 @@ public static partial class Db
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Boolean Delete(Warning warningToDelete)
|
||||||
|
{
|
||||||
|
var deleteSuccess = RunTransaction(DeleteWarning);
|
||||||
|
if (deleteSuccess)
|
||||||
|
BackupDatabase();
|
||||||
|
return deleteSuccess;
|
||||||
|
|
||||||
|
|
||||||
|
Boolean DeleteWarning()
|
||||||
|
{
|
||||||
|
return Warnings.Delete(error => error.Id == warningToDelete.Id) >0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Boolean Delete(Installation installation)
|
public static Boolean Delete(Installation installation)
|
||||||
{
|
{
|
||||||
var deleteSuccess = RunTransaction(DeleteInstallationAndItsDependencies);
|
var deleteSuccess = RunTransaction(DeleteInstallationAndItsDependencies);
|
||||||
|
|
|
@ -4,6 +4,6 @@ public class StatusMessage
|
||||||
public required int InstallationId { get; init; }
|
public required int InstallationId { get; init; }
|
||||||
public required int Status { get; init; }
|
public required int Status { get; init; }
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
public String Error { get; init; } = null!;
|
public String Description { get; init; } = null!;
|
||||||
public String DeviceCreatedTheError { get; init; } = null!;
|
public String CreatedBy { get; init; } = null!;
|
||||||
}
|
}
|
|
@ -99,15 +99,30 @@ public static class WebsocketManager
|
||||||
Error newError = new Error
|
Error newError = new Error
|
||||||
{
|
{
|
||||||
InstallationId = receivedStatusMessage.InstallationId,
|
InstallationId = receivedStatusMessage.InstallationId,
|
||||||
ErrorDescription = receivedStatusMessage.Error,
|
Description = receivedStatusMessage.Description,
|
||||||
CreatedAt = receivedStatusMessage.CreatedAt,
|
CreatedAt = receivedStatusMessage.CreatedAt,
|
||||||
DeviceCreatedTheError = receivedStatusMessage.DeviceCreatedTheError,
|
DeviceCreatedTheMessage = receivedStatusMessage.CreatedBy,
|
||||||
Seen = false
|
Seen = false
|
||||||
};
|
};
|
||||||
//Create a new error and add it to the database
|
//Create a new error and add it to the database
|
||||||
Db.HandleError(newError,receivedStatusMessage.InstallationId);
|
Db.HandleError(newError,receivedStatusMessage.InstallationId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else if (receivedStatusMessage.Status==1)
|
||||||
|
{
|
||||||
|
Console.WriteLine("-----------------------New warning-----------------------");
|
||||||
|
|
||||||
|
Warning newWarning = new Warning
|
||||||
|
{
|
||||||
|
InstallationId = receivedStatusMessage.InstallationId,
|
||||||
|
Description = receivedStatusMessage.Description,
|
||||||
|
CreatedAt = receivedStatusMessage.CreatedAt,
|
||||||
|
DeviceCreatedTheMessage = receivedStatusMessage.CreatedBy,
|
||||||
|
Seen = false
|
||||||
|
};
|
||||||
|
//Create a new error and add it to the database
|
||||||
|
Db.HandleWarning(newWarning,receivedStatusMessage.InstallationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!InstallationConnections.ContainsKey(installationId))
|
if (!InstallationConnections.ContainsKey(installationId))
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,9 +4,9 @@ namespace InnovEnergy.App.SaliMax.MiddlewareClasses;
|
||||||
public class StatusMessage
|
public class StatusMessage
|
||||||
{
|
{
|
||||||
|
|
||||||
public required int InstallationId { get; init; }
|
public required int InstallationId { get; set; }
|
||||||
public required int Status { get; init; }
|
public required int Status { get; set; }
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
public String Error { get; set; } = null!;
|
public String Description { get; set; } = null!;
|
||||||
public String DeviceCreatedTheError { get; set; } = null!;
|
public String CreatedBy { get; set; } = null!;
|
||||||
}
|
}
|
|
@ -357,8 +357,14 @@ internal static class Program
|
||||||
if (status == 2)
|
if (status == 2)
|
||||||
{
|
{
|
||||||
jsonObject.CreatedAt = DateTime.Now;
|
jsonObject.CreatedAt = DateTime.Now;
|
||||||
jsonObject.Error = "Battery Temperature High";
|
jsonObject.Description = "Battery Temperature High";
|
||||||
jsonObject.DeviceCreatedTheError = "Battery/1";
|
jsonObject.CreatedBy = "Battery/1";
|
||||||
|
}
|
||||||
|
else if (status == 1)
|
||||||
|
{
|
||||||
|
jsonObject.CreatedAt = DateTime.Now;
|
||||||
|
jsonObject.Description = "Temp warning message";
|
||||||
|
jsonObject.CreatedBy = "Battery/4";
|
||||||
}
|
}
|
||||||
|
|
||||||
var message = JsonSerializer.Serialize(jsonObject);
|
var message = JsonSerializer.Serialize(jsonObject);
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
export const axiosConfigWithoutToken = axios.create({
|
export const axiosConfigWithoutToken = axios.create({
|
||||||
//baseURL: 'https://monitor.innov.energy/api'
|
baseURL: 'https://monitor.innov.energy/api'
|
||||||
baseURL: 'http://127.0.0.1:7087/api'
|
//baseURL: 'http://127.0.0.1:7087/api'
|
||||||
});
|
});
|
||||||
|
|
||||||
const axiosConfig = axios.create({
|
const axiosConfig = axios.create({
|
||||||
//baseURL: 'https://monitor.innov.energy/api'
|
baseURL: 'https://monitor.innov.energy/api'
|
||||||
baseURL: 'http://127.0.0.1:7087/api'
|
//baseURL: 'http://127.0.0.1:7087/api'
|
||||||
});
|
});
|
||||||
|
|
||||||
axiosConfig.defaults.params = {};
|
axiosConfig.defaults.params = {};
|
||||||
|
|
|
@ -17,12 +17,14 @@ import {
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import ErrorIcon from '@mui/icons-material/Error';
|
import ErrorIcon from '@mui/icons-material/Error';
|
||||||
|
import WarningIcon from '@mui/icons-material/Warning';
|
||||||
import axiosConfig from '../../../Resources/axiosConfig';
|
import axiosConfig from '../../../Resources/axiosConfig';
|
||||||
import { AxiosError, AxiosResponse } from 'axios/index';
|
import { AxiosError, AxiosResponse } from 'axios/index';
|
||||||
import routes from '../../../Resources/routes.json';
|
import routes from '../../../Resources/routes.json';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { TokenContext } from '../../../contexts/tokenContext';
|
import { TokenContext } from '../../../contexts/tokenContext';
|
||||||
import { ErrorMessage } from '../../../interfaces/S3Types';
|
import { ErrorMessage } from '../../../interfaces/S3Types';
|
||||||
|
import Button from '@mui/material/Button';
|
||||||
|
|
||||||
interface LogProps {
|
interface LogProps {
|
||||||
errorLoadingS3Data: boolean;
|
errorLoadingS3Data: boolean;
|
||||||
|
@ -31,8 +33,11 @@ interface LogProps {
|
||||||
|
|
||||||
function Log(props: LogProps) {
|
function Log(props: LogProps) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
//const [warnings, setWarnings] = useState<Notification[]>([]);
|
const [warnings, setWarnings] = useState<ErrorMessage[]>([]);
|
||||||
const [errors, setErrors] = useState<ErrorMessage[]>([]);
|
const [errors, setErrors] = useState<ErrorMessage[]>([]);
|
||||||
|
const [errorButtonPressed, setErrorButtonPressed] = useState(false);
|
||||||
|
const [warningButtonPressed, setWarningButtonPressed] = useState(false);
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const tokencontext = useContext(TokenContext);
|
const tokencontext = useContext(TokenContext);
|
||||||
const { removeToken } = tokencontext;
|
const { removeToken } = tokencontext;
|
||||||
|
@ -49,14 +54,41 @@ function Log(props: LogProps) {
|
||||||
navigate(routes.login);
|
navigate(routes.login);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
axiosConfig
|
||||||
|
.get(`/GetAllWarningsForInstallation?id=${props.id}`)
|
||||||
|
.then((res: AxiosResponse<ErrorMessage[]>) => {
|
||||||
|
setWarnings(res.data);
|
||||||
|
})
|
||||||
|
.catch((err: AxiosError) => {
|
||||||
|
if (err.response && err.response.status == 401) {
|
||||||
|
removeToken();
|
||||||
|
navigate(routes.login);
|
||||||
|
}
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const handleErrorButtonPressed = () => {
|
||||||
|
setErrorButtonPressed(!errorButtonPressed);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleWarningButtonPressed = () => {
|
||||||
|
setWarningButtonPressed(!warningButtonPressed);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="xl">
|
<Container maxWidth="xl">
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid item xs={12} md={12}>
|
<Grid item xs={12} md={12}>
|
||||||
{/* IT SHOULD BE {(errors.length > 0 || props.warnings.length > 0) && (*/}
|
<Button
|
||||||
{errors.length > 0 && (
|
variant="contained"
|
||||||
|
onClick={handleErrorButtonPressed}
|
||||||
|
sx={{ marginTop: '20px' }}
|
||||||
|
>
|
||||||
|
<FormattedMessage id="Show Errors" defaultMessage="Show Errors" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
{errorButtonPressed && errors.length > 0 && (
|
||||||
<Card sx={{ marginTop: '10px' }}>
|
<Card sx={{ marginTop: '10px' }}>
|
||||||
<Divider />
|
<Divider />
|
||||||
<TableContainer>
|
<TableContainer>
|
||||||
|
@ -66,7 +98,6 @@ function Log(props: LogProps) {
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<FormattedMessage id="type" defaultMessage="Type" />
|
<FormattedMessage id="type" defaultMessage="Type" />
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="description"
|
id="description"
|
||||||
|
@ -85,13 +116,146 @@ function Log(props: LogProps) {
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{errors.map((error, index) => {
|
{errors.map((error, index) => (
|
||||||
|
<TableRow hover key={index}>
|
||||||
|
<TableCell>
|
||||||
|
<ErrorIcon
|
||||||
|
sx={{
|
||||||
|
color: 'red',
|
||||||
|
width: 25,
|
||||||
|
height: 25,
|
||||||
|
marginLeft: '5px',
|
||||||
|
marginTop: '8px'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
fontWeight="bold"
|
||||||
|
color="text.primary"
|
||||||
|
gutterBottom
|
||||||
|
noWrap
|
||||||
|
sx={{ marginTop: '5px', verticalAlign: 'middle' }}
|
||||||
|
>
|
||||||
|
{error.description}
|
||||||
|
</Typography>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
fontWeight="bold"
|
||||||
|
color="text.primary"
|
||||||
|
gutterBottom
|
||||||
|
noWrap
|
||||||
|
sx={{ marginTop: '5px', verticalAlign: 'middle' }}
|
||||||
|
>
|
||||||
|
{error.deviceCreatedTheMessage}
|
||||||
|
</Typography>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
fontWeight="bold"
|
||||||
|
color="text.primary"
|
||||||
|
gutterBottom
|
||||||
|
noWrap
|
||||||
|
sx={{ marginTop: '5px', verticalAlign: 'middle' }}
|
||||||
|
>
|
||||||
|
{error.createdAt}
|
||||||
|
</Typography>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
fontWeight="bold"
|
||||||
|
color="text.primary"
|
||||||
|
gutterBottom
|
||||||
|
noWrap
|
||||||
|
sx={{ marginTop: '5px', verticalAlign: 'middle' }}
|
||||||
|
>
|
||||||
|
{error.seen == false ? 'No' : 'Yes'}
|
||||||
|
</Typography>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!props.errorLoadingS3Data &&
|
||||||
|
errorButtonPressed &&
|
||||||
|
errors.length == 0 && (
|
||||||
|
<Alert
|
||||||
|
severity="error"
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginTop: '20px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id="noerrors"
|
||||||
|
defaultMessage="There are no errors"
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
color="inherit"
|
||||||
|
size="small"
|
||||||
|
sx={{ marginLeft: '4px' }}
|
||||||
|
></IconButton>
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} md={12}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
onClick={handleWarningButtonPressed}
|
||||||
|
sx={{ marginTop: '20px' }}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id="Show Warnings"
|
||||||
|
defaultMessage="Show Warnings"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
{warningButtonPressed && warnings.length > 0 && (
|
||||||
|
<Card sx={{ marginTop: '10px' }}>
|
||||||
|
<Divider />
|
||||||
|
<TableContainer>
|
||||||
|
<Table>
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell>
|
||||||
|
<FormattedMessage id="type" defaultMessage="Type" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<FormattedMessage
|
||||||
|
id="description"
|
||||||
|
defaultMessage="Description"
|
||||||
|
/>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<FormattedMessage id="device" defaultMessage="Device" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<FormattedMessage id="date" defaultMessage="Date" />
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<FormattedMessage id="seen" defaultMessage="Seen" />
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{warnings.map((warning, index) => {
|
||||||
return (
|
return (
|
||||||
<TableRow hover key={index}>
|
<TableRow hover key={index}>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<ErrorIcon
|
<WarningIcon
|
||||||
sx={{
|
sx={{
|
||||||
color: 'red',
|
color: 'orange',
|
||||||
width: 25,
|
width: 25,
|
||||||
height: 25,
|
height: 25,
|
||||||
marginLeft: '5px',
|
marginLeft: '5px',
|
||||||
|
@ -106,9 +270,9 @@ function Log(props: LogProps) {
|
||||||
color="text.primary"
|
color="text.primary"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
noWrap
|
noWrap
|
||||||
sx={{ marginTop: '5px', marginLeft: '-40px' }}
|
sx={{ marginTop: '5px', verticalAlign: 'middle' }}
|
||||||
>
|
>
|
||||||
{error.errorDescription}
|
{warning.description}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
|
@ -120,7 +284,7 @@ function Log(props: LogProps) {
|
||||||
noWrap
|
noWrap
|
||||||
sx={{ marginTop: '5px' }}
|
sx={{ marginTop: '5px' }}
|
||||||
>
|
>
|
||||||
{error.deviceCreatedTheError}
|
{warning.deviceCreatedTheMessage}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
|
@ -130,9 +294,9 @@ function Log(props: LogProps) {
|
||||||
color="text.primary"
|
color="text.primary"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
noWrap
|
noWrap
|
||||||
sx={{ marginTop: '5px', marginLeft: '-40px' }}
|
sx={{ marginTop: '5px', verticalAlign: 'middle' }}
|
||||||
>
|
>
|
||||||
{error.createdAt}
|
{warning.createdAt}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
|
@ -142,106 +306,43 @@ function Log(props: LogProps) {
|
||||||
color="text.primary"
|
color="text.primary"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
noWrap
|
noWrap
|
||||||
sx={{ marginTop: '5px', marginLeft: '10px' }}
|
sx={{ marginTop: '5px', verticalAlign: 'middle' }}
|
||||||
>
|
>
|
||||||
{error.seen == false ? 'No' : 'Yes'}
|
{warning.seen == false ? 'No' : 'Yes'}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
|
||||||
{/*{props.warnings.map((warning, index) => {*/}
|
|
||||||
{/* return (*/}
|
|
||||||
{/* <TableRow hover key={index}>*/}
|
|
||||||
{/* <TableCell>*/}
|
|
||||||
{/* <WarningIcon*/}
|
|
||||||
{/* sx={{*/}
|
|
||||||
{/* color: '#ffc04d',*/}
|
|
||||||
{/* width: 25,*/}
|
|
||||||
{/* height: 25,*/}
|
|
||||||
{/* marginLeft: '5px',*/}
|
|
||||||
{/* marginTop: '8px'*/}
|
|
||||||
{/* }}*/}
|
|
||||||
{/* />*/}
|
|
||||||
{/* </TableCell>*/}
|
|
||||||
{/* <TableCell>*/}
|
|
||||||
{/* <Typography*/}
|
|
||||||
{/* variant="body1"*/}
|
|
||||||
{/* fontWeight="bold"*/}
|
|
||||||
{/* color="text.primary"*/}
|
|
||||||
{/* gutterBottom*/}
|
|
||||||
{/* noWrap*/}
|
|
||||||
{/* sx={{ marginTop: '10px' }}*/}
|
|
||||||
{/* >*/}
|
|
||||||
{/* {warning.device}*/}
|
|
||||||
{/* </Typography>*/}
|
|
||||||
{/* </TableCell>*/}
|
|
||||||
{/* <TableCell>*/}
|
|
||||||
{/* <Typography*/}
|
|
||||||
{/* variant="body1"*/}
|
|
||||||
{/* fontWeight="bold"*/}
|
|
||||||
{/* color="text.primary"*/}
|
|
||||||
{/* gutterBottom*/}
|
|
||||||
{/* noWrap*/}
|
|
||||||
{/* sx={{ marginTop: '10px' }}*/}
|
|
||||||
{/* >*/}
|
|
||||||
{/* {warning.description}*/}
|
|
||||||
{/* </Typography>*/}
|
|
||||||
{/* </TableCell>*/}
|
|
||||||
{/* <TableCell>*/}
|
|
||||||
{/* <Typography*/}
|
|
||||||
{/* variant="body1"*/}
|
|
||||||
{/* fontWeight="bold"*/}
|
|
||||||
{/* color="text.primary"*/}
|
|
||||||
{/* gutterBottom*/}
|
|
||||||
{/* noWrap*/}
|
|
||||||
{/* sx={{ marginTop: '10px' }}*/}
|
|
||||||
{/* >*/}
|
|
||||||
{/* {warning.date}*/}
|
|
||||||
{/* </Typography>*/}
|
|
||||||
{/* </TableCell>*/}
|
|
||||||
{/* <TableCell>*/}
|
|
||||||
{/* <Typography*/}
|
|
||||||
{/* variant="body1"*/}
|
|
||||||
{/* fontWeight="bold"*/}
|
|
||||||
{/* color="text.primary"*/}
|
|
||||||
{/* gutterBottom*/}
|
|
||||||
{/* noWrap*/}
|
|
||||||
{/* sx={{ marginTop: '10px' }}*/}
|
|
||||||
{/* >*/}
|
|
||||||
{/* {warning.time}*/}
|
|
||||||
{/* </Typography>*/}
|
|
||||||
{/* </TableCell>*/}
|
|
||||||
{/* </TableRow>*/}
|
|
||||||
{/* );*/}
|
|
||||||
{/*})}*/}
|
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</TableContainer>
|
</TableContainer>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!props.errorLoadingS3Data && errors.length == 0 && (
|
{!props.errorLoadingS3Data &&
|
||||||
<Alert
|
warningButtonPressed &&
|
||||||
severity="error"
|
warnings.length == 0 && (
|
||||||
sx={{
|
<Alert
|
||||||
display: 'flex',
|
severity="error"
|
||||||
alignItems: 'center',
|
sx={{
|
||||||
marginTop: '20px'
|
display: 'flex',
|
||||||
}}
|
alignItems: 'center',
|
||||||
>
|
//marginBottom: '20px'
|
||||||
<FormattedMessage
|
marginTop: '20px'
|
||||||
id="noerrors"
|
}}
|
||||||
defaultMessage="There are no errors"
|
>
|
||||||
/>
|
<FormattedMessage
|
||||||
<IconButton
|
id="nowarnings"
|
||||||
color="inherit"
|
defaultMessage="There are no warnings"
|
||||||
size="small"
|
/>
|
||||||
sx={{ marginLeft: '4px' }}
|
<IconButton
|
||||||
></IconButton>
|
color="inherit"
|
||||||
</Alert>
|
size="small"
|
||||||
)}
|
sx={{ marginLeft: '4px' }}
|
||||||
|
></IconButton>
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Grid item xs={12} md={12} style={{ marginBottom: '20px' }}>
|
<Grid item xs={12} md={12} style={{ marginBottom: '20px' }}>
|
||||||
|
@ -265,28 +366,6 @@ function Log(props: LogProps) {
|
||||||
></IconButton>
|
></IconButton>
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/*{!props.errorLoadingS3Data && props.warnings.length == 0 && (*/}
|
|
||||||
{/* <Alert*/}
|
|
||||||
{/* severity="error"*/}
|
|
||||||
{/* sx={{*/}
|
|
||||||
{/* display: 'flex',*/}
|
|
||||||
{/* alignItems: 'center',*/}
|
|
||||||
{/* //marginBottom: '20px'*/}
|
|
||||||
{/* marginTop: '20px'*/}
|
|
||||||
{/* }}*/}
|
|
||||||
{/* >*/}
|
|
||||||
{/* <FormattedMessage*/}
|
|
||||||
{/* id="nowarnings"*/}
|
|
||||||
{/* defaultMessage="There are no warnings"*/}
|
|
||||||
{/* />*/}
|
|
||||||
{/* <IconButton*/}
|
|
||||||
{/* color="inherit"*/}
|
|
||||||
{/* size="small"*/}
|
|
||||||
{/* sx={{ marginLeft: '4px' }}*/}
|
|
||||||
{/* ></IconButton>*/}
|
|
||||||
{/* </Alert>*/}
|
|
||||||
{/*)}*/}
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Container>
|
</Container>
|
||||||
|
|
|
@ -8,8 +8,8 @@ export interface I_S3Credentials {
|
||||||
|
|
||||||
export interface ErrorMessage {
|
export interface ErrorMessage {
|
||||||
installationId: number;
|
installationId: number;
|
||||||
|
description: string;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
errorDescription: string;
|
deviceCreatedTheMessage: string;
|
||||||
deviceCreatedTheError: string;
|
|
||||||
seen: boolean;
|
seen: boolean;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue