Inserted folder view in backend-frontend
Clients can have access to both products Apply 20min chunk logic for Salidomo installations
This commit is contained in:
parent
2d3af976c1
commit
7db44785be
|
@ -41,10 +41,14 @@ public class Controller : ControllerBase
|
||||||
throw new Exceptions(401, "Wrong Password Exception", "Please try again.", Request.Path.Value!);
|
throw new Exceptions(401, "Wrong Password Exception", "Please try again.", Request.Path.Value!);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var session = new Session(user.HidePassword().HideParentIfUserHasNoAccessToParent(user));
|
var session = new Session(user.HidePassword().HideParentIfUserHasNoAccessToParent(user));
|
||||||
|
|
||||||
//TODO The Frontend should check for the MustResetPassword Flag
|
//TODO The Frontend should check for the MustResetPassword Flag
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return Db.Create(session)
|
return Db.Create(session)
|
||||||
? session
|
? session
|
||||||
: throw new Exceptions(401,"Session Creation Exception", "Not allowed to log in.", Request.Path.Value!);
|
: throw new Exceptions(401,"Session Creation Exception", "Not allowed to log in.", Request.Path.Value!);
|
||||||
|
@ -472,15 +476,16 @@ public class Controller : ControllerBase
|
||||||
|
|
||||||
|
|
||||||
[HttpGet(nameof(GetAllFoldersAndInstallations))]
|
[HttpGet(nameof(GetAllFoldersAndInstallations))]
|
||||||
public ActionResult<IEnumerable<Object>> GetAllFoldersAndInstallations(Token authToken)
|
public ActionResult<IEnumerable<Object>> GetAllFoldersAndInstallations(int productId, Token authToken)
|
||||||
{
|
{
|
||||||
var user = Db.GetSession(authToken)?.User;
|
var user = Db.GetSession(authToken)?.User;
|
||||||
|
|
||||||
if (user is null)
|
if (user is null)
|
||||||
return Unauthorized();
|
return Unauthorized();
|
||||||
|
|
||||||
|
|
||||||
var foldersAndInstallations = user
|
var foldersAndInstallations = user
|
||||||
.AccessibleFoldersAndInstallations(product:0)
|
.AccessibleFoldersAndInstallations(product:productId)
|
||||||
.Do(o => o.FillOrderNumbers())
|
.Do(o => o.FillOrderNumbers())
|
||||||
.Select(o => o.HideParentIfUserHasNoAccessToParent(user))
|
.Select(o => o.HideParentIfUserHasNoAccessToParent(user))
|
||||||
.OfType<Object>(); // Important! JSON serializer must see Objects otherwise
|
.OfType<Object>(); // Important! JSON serializer must see Objects otherwise
|
||||||
|
|
|
@ -143,7 +143,7 @@ public static class ExoCmd
|
||||||
{
|
{
|
||||||
const String url = "https://api-ch-dk-2.exoscale.com/v2/iam-role";
|
const String url = "https://api-ch-dk-2.exoscale.com/v2/iam-role";
|
||||||
const String method = "iam-role";
|
const String method = "iam-role";
|
||||||
String rolename = installation.Product==0?Db.Installations.Count(f => f.Product == 0) + installation.InstallationName:Db.Installations.Count(f => f.Product == 1) + installation.InstallationName;
|
String rolename = installation.Product==0?Db.Installations.Count(f => f.Product == 0) + installation.Name:Db.Installations.Count(f => f.Product == 1) + installation.Name;
|
||||||
|
|
||||||
|
|
||||||
var contentString = $$"""
|
var contentString = $$"""
|
||||||
|
@ -245,7 +245,7 @@ public static class ExoCmd
|
||||||
{
|
{
|
||||||
const String url = "https://api-ch-dk-2.exoscale.com/v2/iam-role";
|
const String url = "https://api-ch-dk-2.exoscale.com/v2/iam-role";
|
||||||
const String method = "iam-role";
|
const String method = "iam-role";
|
||||||
String rolename = installation.Product==0?Db.Installations.Count(f => f.Product == 0) + installation.InstallationName:Db.Installations.Count(f => f.Product == 1) + installation.InstallationName;
|
String rolename = installation.Product==0?Db.Installations.Count(f => f.Product == 0) + installation.Name:Db.Installations.Count(f => f.Product == 1) + installation.Name;
|
||||||
|
|
||||||
var contentString = $$"""
|
var contentString = $$"""
|
||||||
{
|
{
|
||||||
|
|
|
@ -41,9 +41,9 @@ public static class FolderMethods
|
||||||
public static IEnumerable<Folder> UniqueChildFolders(this Folder parent)
|
public static IEnumerable<Folder> UniqueChildFolders(this Folder parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
var set = new HashSet<Folder>(Db.Folders, EqualityComparer<Folder>.Default);
|
//var set = new HashSet<Folder>(Db.Folders, EqualityComparer<Folder>.Default);
|
||||||
|
|
||||||
return ChildFolders(parent).Where(set.Add);
|
return ChildFolders(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<Installation> ChildInstallations(this Folder parent)
|
public static IEnumerable<Installation> ChildInstallations(this Folder parent)
|
||||||
|
@ -56,6 +56,8 @@ public static class FolderMethods
|
||||||
|
|
||||||
public static IEnumerable<Folder> DescendantFolders(this Folder parent)
|
public static IEnumerable<Folder> DescendantFolders(this Folder parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
Console.WriteLine("Parent is "+parent.Id+" looking for descendant folders");
|
||||||
return parent
|
return parent
|
||||||
.TraverseDepthFirstPreOrder(UniqueChildFolders)
|
.TraverseDepthFirstPreOrder(UniqueChildFolders)
|
||||||
.Skip(1); // skip self
|
.Skip(1); // skip self
|
||||||
|
|
|
@ -56,6 +56,7 @@ public static class UserMethods
|
||||||
|
|
||||||
public static IEnumerable<Folder> DirectlyAccessibleFolders(this User user)
|
public static IEnumerable<Folder> DirectlyAccessibleFolders(this User user)
|
||||||
{
|
{
|
||||||
|
|
||||||
return Db
|
return Db
|
||||||
.FolderAccess
|
.FolderAccess
|
||||||
.Where(r => r.UserId == user.Id)
|
.Where(r => r.UserId == user.Id)
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
namespace InnovEnergy.App.Backend.DataTypes;
|
||||||
|
|
||||||
|
public class WebsocketMessage
|
||||||
|
{
|
||||||
|
|
||||||
|
public int id { get; set; }
|
||||||
|
public int status { get; set; }
|
||||||
|
public Boolean testingMode { get; set; }
|
||||||
|
|
||||||
|
}
|
|
@ -21,7 +21,8 @@ public static class Program
|
||||||
|
|
||||||
RabbitMqManager.InitializeEnvironment();
|
RabbitMqManager.InitializeEnvironment();
|
||||||
RabbitMqManager.StartRabbitMqConsumer();
|
RabbitMqManager.StartRabbitMqConsumer();
|
||||||
WebsocketManager.MonitorInstallationTable();
|
WebsocketManager.MonitorSalimaxInstallationTable();
|
||||||
|
WebsocketManager.MonitorSalidomoInstallationTable();
|
||||||
|
|
||||||
|
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using InnovEnergy.App.Backend.Database;
|
using InnovEnergy.App.Backend.Database;
|
||||||
using InnovEnergy.App.Backend.DataTypes;
|
using InnovEnergy.App.Backend.DataTypes;
|
||||||
|
using InnovEnergy.App.Backend.DataTypes.Methods;
|
||||||
using SQLite;
|
using SQLite;
|
||||||
|
|
||||||
namespace InnovEnergy.App.Backend.Relations;
|
namespace InnovEnergy.App.Backend.Relations;
|
||||||
|
@ -11,7 +12,8 @@ public class Session : Relation<String, Int64>
|
||||||
[Unique ] public String Token { get => Left ; init => Left = value;}
|
[Unique ] public String Token { get => Left ; init => Left = value;}
|
||||||
[Indexed] public Int64 UserId { get => Right; init => Right = value;}
|
[Indexed] public Int64 UserId { get => Right; init => Right = value;}
|
||||||
[Indexed] public DateTime LastSeen { get; set; }
|
[Indexed] public DateTime LastSeen { get; set; }
|
||||||
|
public Boolean AccessToSalimax { get; set; } = false;
|
||||||
|
public Boolean AccessToSalidomo { get; set; } = false;
|
||||||
[Ignore] public Boolean Valid => DateTime.Now - LastSeen < MaxAge
|
[Ignore] public Boolean Valid => DateTime.Now - LastSeen < MaxAge
|
||||||
&& (User) is not null;
|
&& (User) is not null;
|
||||||
|
|
||||||
|
@ -30,6 +32,9 @@ public class Session : Relation<String, Int64>
|
||||||
Token = CreateToken();
|
Token = CreateToken();
|
||||||
UserId = user.Id;
|
UserId = user.Id;
|
||||||
LastSeen = DateTime.Now;
|
LastSeen = DateTime.Now;
|
||||||
|
AccessToSalimax = user.AccessibleInstallations(product: 0).ToList().Count > 0;
|
||||||
|
AccessToSalidomo = user.AccessibleInstallations(product: 1).ToList().Count > 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String CreateToken()
|
private static String CreateToken()
|
||||||
|
|
|
@ -5,5 +5,6 @@ public class InstallationInfo
|
||||||
{
|
{
|
||||||
public int Status { get; set; }
|
public int Status { get; set; }
|
||||||
public DateTime Timestamp { get; set; }
|
public DateTime Timestamp { get; set; }
|
||||||
|
public int Product { get; set; }
|
||||||
public List<WebSocket> Connections { get; } = new List<WebSocket>();
|
public List<WebSocket> Connections { get; } = new List<WebSocket>();
|
||||||
}
|
}
|
|
@ -158,7 +158,8 @@ public static class RabbitMqManager
|
||||||
WebsocketManager.InstallationConnections[installationId] = new InstallationInfo
|
WebsocketManager.InstallationConnections[installationId] = new InstallationInfo
|
||||||
{
|
{
|
||||||
Status = receivedStatusMessage.Status,
|
Status = receivedStatusMessage.Status,
|
||||||
Timestamp = DateTime.Now
|
Timestamp = DateTime.Now,
|
||||||
|
Product = installation.Product
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.Net.WebSockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using InnovEnergy.App.Backend.Database;
|
using InnovEnergy.App.Backend.Database;
|
||||||
|
using InnovEnergy.App.Backend.DataTypes;
|
||||||
|
|
||||||
namespace InnovEnergy.App.Backend.Websockets;
|
namespace InnovEnergy.App.Backend.Websockets;
|
||||||
|
|
||||||
|
@ -13,12 +14,12 @@ public static class WebsocketManager
|
||||||
|
|
||||||
//Every 2 minutes, check the timestamp of the latest received message for every installation.
|
//Every 2 minutes, check the timestamp of the latest received message for every installation.
|
||||||
//If the difference between the two timestamps is more than two minutes, we consider this installation unavailable.
|
//If the difference between the two timestamps is more than two minutes, we consider this installation unavailable.
|
||||||
public static async Task MonitorInstallationTable()
|
public static async Task MonitorSalimaxInstallationTable()
|
||||||
{
|
{
|
||||||
while (true){
|
while (true){
|
||||||
lock (InstallationConnections){
|
lock (InstallationConnections){
|
||||||
foreach (var installationConnection in InstallationConnections){
|
foreach (var installationConnection in InstallationConnections){
|
||||||
if ((DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(1)){
|
if (installationConnection.Value.Product==0 && (DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(1)){
|
||||||
installationConnection.Value.Status = -1;
|
installationConnection.Value.Status = -1;
|
||||||
if (installationConnection.Value.Connections.Count > 0){InformWebsocketsForInstallation(installationConnection.Key);}
|
if (installationConnection.Value.Connections.Count > 0){InformWebsocketsForInstallation(installationConnection.Key);}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +29,21 @@ public static class WebsocketManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task MonitorSalidomoInstallationTable()
|
||||||
|
{
|
||||||
|
while (true){
|
||||||
|
lock (InstallationConnections){
|
||||||
|
foreach (var installationConnection in InstallationConnections){
|
||||||
|
if (installationConnection.Value.Product==1 && (DateTime.Now - installationConnection.Value.Timestamp) > TimeSpan.FromMinutes(20)){
|
||||||
|
installationConnection.Value.Status = -1;
|
||||||
|
if (installationConnection.Value.Connections.Count > 0){InformWebsocketsForInstallation(installationConnection.Key);}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Task.Delay(TimeSpan.FromMinutes(30));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Inform all the connected websockets regarding installation "installationId"
|
//Inform all the connected websockets regarding installation "installationId"
|
||||||
public static void InformWebsocketsForInstallation(Int64 installationId)
|
public static void InformWebsocketsForInstallation(Int64 installationId)
|
||||||
{
|
{
|
||||||
|
@ -35,7 +51,6 @@ public static class WebsocketManager
|
||||||
var installationConnection = InstallationConnections[installationId];
|
var installationConnection = InstallationConnections[installationId];
|
||||||
Console.WriteLine("Update all the connected websockets for installation " + installationId);
|
Console.WriteLine("Update all the connected websockets for installation " + installationId);
|
||||||
|
|
||||||
|
|
||||||
var jsonObject = new
|
var jsonObject = new
|
||||||
{
|
{
|
||||||
id = installationId,
|
id = installationId,
|
||||||
|
@ -96,6 +111,9 @@ public static class WebsocketManager
|
||||||
//Console.WriteLine("Received a new message from websocket");
|
//Console.WriteLine("Received a new message from websocket");
|
||||||
lock (InstallationConnections)
|
lock (InstallationConnections)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
List<WebsocketMessage> dataToSend = new List<WebsocketMessage>();
|
||||||
|
|
||||||
//Each front-end will send the list of the installations it wants to access
|
//Each front-end will send the list of the installations it wants to access
|
||||||
//If this is a new key (installation id), initialize the list for this key and then add the websocket object for this client
|
//If this is a new key (installation id), initialize the list for this key and then add the websocket object for this client
|
||||||
//Then, report the status of each requested installation to the front-end that created the websocket connection
|
//Then, report the status of each requested installation to the front-end that created the websocket connection
|
||||||
|
@ -108,29 +126,42 @@ public static class WebsocketManager
|
||||||
//Console.WriteLine("Create new empty list for installation id " + installationId);
|
//Console.WriteLine("Create new empty list for installation id " + installationId);
|
||||||
InstallationConnections[installationId] = new InstallationInfo
|
InstallationConnections[installationId] = new InstallationInfo
|
||||||
{
|
{
|
||||||
Status = -1
|
Status = -1,
|
||||||
|
Product = installation.Product
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
InstallationConnections[installationId].Connections.Add(currentWebSocket);
|
InstallationConnections[installationId].Connections.Add(currentWebSocket);
|
||||||
|
|
||||||
var jsonObject = new
|
var jsonObject = new WebsocketMessage
|
||||||
{
|
{
|
||||||
id = installationId,
|
id = installationId,
|
||||||
status = InstallationConnections[installationId].Status,
|
status = InstallationConnections[installationId].Status,
|
||||||
testingMode = installation.TestingMode
|
testingMode = installation.TestingMode
|
||||||
};
|
};
|
||||||
|
|
||||||
var jsonString = JsonSerializer.Serialize(jsonObject);
|
dataToSend.Add(jsonObject);
|
||||||
var dataToSend = Encoding.UTF8.GetBytes(jsonString);
|
|
||||||
|
//var jsonString = JsonSerializer.Serialize(jsonObject);
|
||||||
|
//var dataToSend = Encoding.UTF8.GetBytes(jsonString);
|
||||||
|
|
||||||
|
|
||||||
currentWebSocket.SendAsync(dataToSend,
|
// currentWebSocket.SendAsync(dataToSend,
|
||||||
|
// WebSocketMessageType.Text,
|
||||||
|
// true, // Indicates that this is the end of the message
|
||||||
|
// CancellationToken.None
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
var jsonString = JsonSerializer.Serialize(dataToSend);
|
||||||
|
var encodedDataToSend = Encoding.UTF8.GetBytes(jsonString);
|
||||||
|
|
||||||
|
|
||||||
|
currentWebSocket.SendAsync(encodedDataToSend,
|
||||||
WebSocketMessageType.Text,
|
WebSocketMessageType.Text,
|
||||||
true, // Indicates that this is the end of the message
|
true, // Indicates that this is the end of the message
|
||||||
CancellationToken.None
|
CancellationToken.None
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
Console.WriteLine("Printing installation connection list");
|
Console.WriteLine("Printing installation connection list");
|
||||||
Console.WriteLine("----------------------------------------------");
|
Console.WriteLine("----------------------------------------------");
|
||||||
|
|
|
@ -10,4 +10,5 @@ Salimax0006 ie-entwicklung@10.2.4.35 Steakhouse Mettmenstetten
|
||||||
Salimax0007 ie-entwicklung@10.2.4.154 LerchenhofHerr Twannberg
|
Salimax0007 ie-entwicklung@10.2.4.154 LerchenhofHerr Twannberg
|
||||||
Salimax0008 ie-entwicklung@10.2.4.113 Wittmann Kottingbrunn
|
Salimax0008 ie-entwicklung@10.2.4.113 Wittmann Kottingbrunn
|
||||||
Salimax0010 ie-entwicklung@10.2.4.211 Mohatech 1 (Beat Moser)
|
Salimax0010 ie-entwicklung@10.2.4.211 Mohatech 1 (Beat Moser)
|
||||||
|
Salimax0011 ie-entwicklung@10.2.4.239 Thomas Tschirren (Enggistein)
|
||||||
SalidomoServer ig@134.209.238.170
|
SalidomoServer ig@134.209.238.170
|
|
@ -54,6 +54,6 @@ INNOVENERGY_PROTOCOL_VERSION = '48TL200V3'
|
||||||
|
|
||||||
|
|
||||||
# S3 Credentials
|
# S3 Credentials
|
||||||
S3BUCKET = "114-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e"
|
S3BUCKET = "91-c0436b6a-d276-4cd8-9c44-1eae86cf5d0e"
|
||||||
S3KEY = "EXO5b9198dc11544f42b44e1180"
|
S3KEY = "EXOe6dce12288f11a676c2025a1"
|
||||||
S3SECRET = "ga-mD3SYZMJUfjksmXPKAHQhVkxPZYv57jC1oD_mkC0"
|
S3SECRET = "xpqM4Eh0Gg1HaYVkzlR9X6PwYa-QNb-mVk0XUkwW3cc"
|
||||||
|
|
|
@ -24,6 +24,7 @@ import { useNavigate } from 'react-router-dom';
|
||||||
import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank';
|
import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank';
|
||||||
import CheckBoxIcon from '@mui/icons-material/CheckBox';
|
import CheckBoxIcon from '@mui/icons-material/CheckBox';
|
||||||
import routes from 'src/Resources/routes.json';
|
import routes from 'src/Resources/routes.json';
|
||||||
|
import { ProductIdContext } from '../contexts/ProductIdContextProvider';
|
||||||
|
|
||||||
function Login() {
|
function Login() {
|
||||||
const [username, setUsername] = useState('');
|
const [username, setUsername] = useState('');
|
||||||
|
@ -35,6 +36,8 @@ function Login() {
|
||||||
|
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const context = useContext(UserContext);
|
const context = useContext(UserContext);
|
||||||
|
const { setAccessToSalimax, setAccessToSalidomo } =
|
||||||
|
useContext(ProductIdContext);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
if (!context) {
|
if (!context) {
|
||||||
|
@ -73,11 +76,18 @@ function Login() {
|
||||||
setNewToken(response.data.token);
|
setNewToken(response.data.token);
|
||||||
setUser(response.data.user);
|
setUser(response.data.user);
|
||||||
|
|
||||||
|
setAccessToSalimax(response.data.accessToSalimax);
|
||||||
|
setAccessToSalidomo(response.data.accessToSalidomo);
|
||||||
|
|
||||||
if (rememberMe) {
|
if (rememberMe) {
|
||||||
cookies.set('rememberedUsername', username, { path: '/' });
|
cookies.set('rememberedUsername', username, { path: '/' });
|
||||||
cookies.set('rememberedPassword', password, { path: '/' });
|
cookies.set('rememberedPassword', password, { path: '/' });
|
||||||
}
|
}
|
||||||
|
if (response.data.accessToSalimax) {
|
||||||
navigate(routes.installations);
|
navigate(routes.installations);
|
||||||
|
} else {
|
||||||
|
navigate(routes.salidomo_installations);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
|
|
@ -582,6 +582,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
||||||
<MenuItem disabled value="">
|
<MenuItem disabled value="">
|
||||||
Select Firmware Version
|
Select Firmware Version
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
<MenuItem value="AF09">AF09</MenuItem>
|
||||||
<MenuItem value="AF11">AF11</MenuItem>
|
<MenuItem value="AF11">AF11</MenuItem>
|
||||||
<MenuItem value="AF0A">AF0A</MenuItem>
|
<MenuItem value="AF0A">AF0A</MenuItem>
|
||||||
</Select>
|
</Select>
|
||||||
|
|
|
@ -200,7 +200,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
|
||||||
|
|
|
@ -379,6 +379,7 @@ function Installation(props: singleInstallationProps) {
|
||||||
{loading &&
|
{loading &&
|
||||||
currentTab != 'information' &&
|
currentTab != 'information' &&
|
||||||
currentTab != 'history' &&
|
currentTab != 'history' &&
|
||||||
|
currentTab != 'manage' &&
|
||||||
currentTab != 'overview' &&
|
currentTab != 'overview' &&
|
||||||
currentTab != 'log' && (
|
currentTab != 'log' && (
|
||||||
<Container
|
<Container
|
||||||
|
|
|
@ -53,9 +53,12 @@ export const fetchAggregatedData = (
|
||||||
|
|
||||||
export const fetchData = (
|
export const fetchData = (
|
||||||
timestamp: UnixTime,
|
timestamp: UnixTime,
|
||||||
s3Credentials?: I_S3Credentials
|
s3Credentials?: I_S3Credentials,
|
||||||
|
cutdigits?: boolean
|
||||||
): Promise<FetchResult<Record<string, DataRecord>>> => {
|
): Promise<FetchResult<Record<string, DataRecord>>> => {
|
||||||
const s3Path = `${timestamp.ticks}.csv`;
|
const s3Path = cutdigits
|
||||||
|
? `${timestamp.ticks.toString().slice(0, -2)}.csv`
|
||||||
|
: `${timestamp.ticks}.csv`;
|
||||||
if (s3Credentials && s3Credentials.s3Bucket) {
|
if (s3Credentials && s3Credentials.s3Bucket) {
|
||||||
const s3Access = new S3Access(
|
const s3Access = new S3Access(
|
||||||
s3Credentials.s3Bucket,
|
s3Credentials.s3Bucket,
|
||||||
|
@ -71,10 +74,14 @@ export const fetchData = (
|
||||||
if (r.status === 404) {
|
if (r.status === 404) {
|
||||||
return Promise.resolve(FetchResult.notAvailable);
|
return Promise.resolve(FetchResult.notAvailable);
|
||||||
} else if (r.status === 200) {
|
} else if (r.status === 200) {
|
||||||
|
console.log('FOUND ITTTTTTTTTTTT');
|
||||||
const csvtext = await r.text(); // Assuming the server returns the Base64 encoded ZIP file as text
|
const csvtext = await r.text(); // Assuming the server returns the Base64 encoded ZIP file as text
|
||||||
const contentEncoding = r.headers.get('content-type');
|
const contentEncoding = r.headers.get('content-type');
|
||||||
|
|
||||||
|
console.log(contentEncoding);
|
||||||
|
|
||||||
if (contentEncoding != 'application/base64; charset=utf-8') {
|
if (contentEncoding != 'application/base64; charset=utf-8') {
|
||||||
|
console.log('uncompressed');
|
||||||
return parseChunk(csvtext);
|
return parseChunk(csvtext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,6 +94,8 @@ export const fetchData = (
|
||||||
// Assuming the CSV file is named "data.csv" inside the ZIP archive
|
// Assuming the CSV file is named "data.csv" inside the ZIP archive
|
||||||
const csvContent = await zip.file('data.csv').async('text');
|
const csvContent = await zip.file('data.csv').async('text');
|
||||||
|
|
||||||
|
console.log(csvContent);
|
||||||
|
|
||||||
return parseChunk(csvContent);
|
return parseChunk(csvContent);
|
||||||
} else {
|
} else {
|
||||||
return Promise.resolve(FetchResult.notAvailable);
|
return Promise.resolve(FetchResult.notAvailable);
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { InstallationsContext } from '../../../contexts/InstallationsContextProv
|
||||||
import Installation from './Installation';
|
import Installation from './Installation';
|
||||||
import { WebSocketContext } from '../../../contexts/WebSocketContextProvider';
|
import { WebSocketContext } from '../../../contexts/WebSocketContextProvider';
|
||||||
import { UserType } from '../../../interfaces/UserTypes';
|
import { UserType } from '../../../interfaces/UserTypes';
|
||||||
|
import { ProductIdContext } from '../../../contexts/ProductIdContextProvider';
|
||||||
|
|
||||||
function InstallationTabs() {
|
function InstallationTabs() {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
@ -35,6 +36,8 @@ function InstallationTabs() {
|
||||||
const { salimaxInstallations, fetchAllInstallations } =
|
const { salimaxInstallations, fetchAllInstallations } =
|
||||||
useContext(InstallationsContext);
|
useContext(InstallationsContext);
|
||||||
|
|
||||||
|
const { product, setProduct } = useContext(ProductIdContext);
|
||||||
|
|
||||||
const webSocketsContext = useContext(WebSocketContext);
|
const webSocketsContext = useContext(WebSocketContext);
|
||||||
const { socket, openSocket, closeSocket } = webSocketsContext;
|
const { socket, openSocket, closeSocket } = webSocketsContext;
|
||||||
|
|
||||||
|
@ -67,6 +70,10 @@ function InstallationTabs() {
|
||||||
}
|
}
|
||||||
}, [salimaxInstallations]);
|
}, [salimaxInstallations]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setProduct(0);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleTabsChange = (_event: ChangeEvent<{}>, value: string): void => {
|
const handleTabsChange = (_event: ChangeEvent<{}>, value: string): void => {
|
||||||
setCurrentTab(value);
|
setCurrentTab(value);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1291,6 +1291,140 @@ function Overview(props: OverviewProps) {
|
||||||
</Card>
|
</Card>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
direction="row"
|
||||||
|
justifyContent="center"
|
||||||
|
alignItems="stretch"
|
||||||
|
spacing={3}
|
||||||
|
>
|
||||||
|
<Grid item md={6} xs={12}>
|
||||||
|
<Card
|
||||||
|
sx={{
|
||||||
|
overflow: 'visible',
|
||||||
|
marginTop: '30px',
|
||||||
|
marginBottom: '30px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
marginLeft: '20px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box display="flex" alignItems="center">
|
||||||
|
<Box>
|
||||||
|
<Typography variant="subtitle1" noWrap>
|
||||||
|
<FormattedMessage
|
||||||
|
id="ac_load"
|
||||||
|
defaultMessage="AC Load"
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'flex-start',
|
||||||
|
pt: 3
|
||||||
|
}}
|
||||||
|
></Box>
|
||||||
|
</Box>
|
||||||
|
|
||||||
|
{dailyData && (
|
||||||
|
<ReactApexChart
|
||||||
|
options={{
|
||||||
|
...getChartOptions(
|
||||||
|
dailyDataArray[chartState].chartOverview.ACLoad,
|
||||||
|
'daily',
|
||||||
|
[],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
chart: {
|
||||||
|
events: {
|
||||||
|
beforeZoom: (chartContext, options) => {
|
||||||
|
startZoom();
|
||||||
|
handleBeforeZoom(chartContext, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
series={[
|
||||||
|
{
|
||||||
|
...dailyDataArray[chartState].chartData.ACLoad,
|
||||||
|
color: '#ff9900'
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
type="line"
|
||||||
|
height={400}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
<Grid item md={6} xs={12}>
|
||||||
|
<Card
|
||||||
|
sx={{
|
||||||
|
overflow: 'visible',
|
||||||
|
marginTop: '30px',
|
||||||
|
marginBottom: '30px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
marginLeft: '20px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box display="flex" alignItems="center">
|
||||||
|
<Box>
|
||||||
|
<Typography variant="subtitle1" noWrap>
|
||||||
|
<FormattedMessage
|
||||||
|
id="dc_load"
|
||||||
|
defaultMessage="DC Load"
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'flex-start',
|
||||||
|
pt: 3
|
||||||
|
}}
|
||||||
|
></Box>
|
||||||
|
</Box>
|
||||||
|
{dailyData && (
|
||||||
|
<ReactApexChart
|
||||||
|
options={{
|
||||||
|
...getChartOptions(
|
||||||
|
dailyDataArray[chartState].chartOverview.DCLoad,
|
||||||
|
'daily',
|
||||||
|
[],
|
||||||
|
true
|
||||||
|
),
|
||||||
|
chart: {
|
||||||
|
events: {
|
||||||
|
beforeZoom: (chartContext, options) => {
|
||||||
|
startZoom();
|
||||||
|
handleBeforeZoom(chartContext, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
series={[
|
||||||
|
{
|
||||||
|
...dailyDataArray[chartState].chartData.DCLoad,
|
||||||
|
color: '#ff3333'
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
type="line"
|
||||||
|
height={400}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
)}
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
@ -157,7 +157,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>
|
||||||
|
|
||||||
|
|
|
@ -27,13 +27,15 @@ import SalidomoOverview from '../Overview/salidomoOverview';
|
||||||
import { UserType } from '../../../interfaces/UserTypes';
|
import { UserType } from '../../../interfaces/UserTypes';
|
||||||
import HistoryOfActions from '../History/History';
|
import HistoryOfActions from '../History/History';
|
||||||
import BuildIcon from '@mui/icons-material/Build';
|
import BuildIcon from '@mui/icons-material/Build';
|
||||||
|
import AccessContextProvider from '../../../contexts/AccessContextProvider';
|
||||||
|
import Access from '../ManageAccess/Access';
|
||||||
|
|
||||||
interface singleInstallationProps {
|
interface singleInstallationProps {
|
||||||
current_installation?: I_Installation;
|
current_installation?: I_Installation;
|
||||||
type?: string;
|
type?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function Installation(props: singleInstallationProps) {
|
function SalidomoInstallation(props: singleInstallationProps) {
|
||||||
const context = useContext(UserContext);
|
const context = useContext(UserContext);
|
||||||
const { currentUser } = context;
|
const { currentUser } = context;
|
||||||
const location = useLocation().pathname;
|
const location = useLocation().pathname;
|
||||||
|
@ -77,18 +79,19 @@ function Installation(props: singleInstallationProps) {
|
||||||
const continueFetching = useRef(false);
|
const continueFetching = useRef(false);
|
||||||
|
|
||||||
const fetchDataPeriodically = async () => {
|
const fetchDataPeriodically = async () => {
|
||||||
var timeperiodToSearch = 90;
|
var timeperiodToSearch = 30;
|
||||||
let res;
|
let res;
|
||||||
let timestampToFetch;
|
let timestampToFetch;
|
||||||
|
|
||||||
for (var i = 0; i < timeperiodToSearch; i += 2) {
|
for (var i = 0; i < timeperiodToSearch; i += 1) {
|
||||||
if (!continueFetching.current) {
|
if (!continueFetching.current) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
timestampToFetch = UnixTime.now().earlier(TimeSpan.fromSeconds(i));
|
timestampToFetch = UnixTime.now().earlier(TimeSpan.fromMinutes(i));
|
||||||
|
console.log('timestamp to fetch is ' + timestampToFetch);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
res = await fetchData(timestampToFetch, s3Credentials);
|
res = await fetchData(timestampToFetch, s3Credentials, true);
|
||||||
if (res !== FetchResult.notAvailable && res !== FetchResult.tryLater) {
|
if (res !== FetchResult.notAvailable && res !== FetchResult.tryLater) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -127,7 +130,7 @@ function Installation(props: singleInstallationProps) {
|
||||||
await timeout(2000);
|
await timeout(2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
timestampToFetch = timestampToFetch.later(TimeSpan.fromSeconds(60));
|
timestampToFetch = timestampToFetch.later(TimeSpan.fromMinutes(20));
|
||||||
console.log('NEW TIMESTAMP TO FETCH IS ' + timestampToFetch);
|
console.log('NEW TIMESTAMP TO FETCH IS ' + timestampToFetch);
|
||||||
|
|
||||||
for (i = 0; i < 10; i++) {
|
for (i = 0; i < 10; i++) {
|
||||||
|
@ -137,7 +140,7 @@ function Installation(props: singleInstallationProps) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('Trying to fetch timestamp ' + timestampToFetch);
|
console.log('Trying to fetch timestamp ' + timestampToFetch);
|
||||||
res = await fetchData(timestampToFetch, s3Credentials);
|
res = await fetchData(timestampToFetch, s3Credentials, true);
|
||||||
if (
|
if (
|
||||||
res !== FetchResult.notAvailable &&
|
res !== FetchResult.notAvailable &&
|
||||||
res !== FetchResult.tryLater
|
res !== FetchResult.tryLater
|
||||||
|
@ -148,7 +151,7 @@ function Installation(props: singleInstallationProps) {
|
||||||
console.error('Error fetching data:', err);
|
console.error('Error fetching data:', err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
timestampToFetch = timestampToFetch.later(TimeSpan.fromSeconds(1));
|
timestampToFetch = timestampToFetch.later(TimeSpan.fromMinutes(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -213,7 +216,7 @@ function Installation(props: singleInstallationProps) {
|
||||||
fontSize: '14px'
|
fontSize: '14px'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.current_installation.installationName}
|
{props.current_installation.name}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||||
|
@ -296,6 +299,7 @@ function Installation(props: singleInstallationProps) {
|
||||||
{loading &&
|
{loading &&
|
||||||
currentTab != 'information' &&
|
currentTab != 'information' &&
|
||||||
currentTab != 'overview' &&
|
currentTab != 'overview' &&
|
||||||
|
currentTab != 'manage' &&
|
||||||
currentTab != 'history' &&
|
currentTab != 'history' &&
|
||||||
currentTab != 'log' && (
|
currentTab != 'log' && (
|
||||||
<Container
|
<Container
|
||||||
|
@ -384,9 +388,23 @@ function Installation(props: singleInstallationProps) {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{currentUser.userType == UserType.admin && (
|
||||||
|
<Route
|
||||||
|
path={routes.manage}
|
||||||
|
element={
|
||||||
|
<AccessContextProvider>
|
||||||
|
<Access
|
||||||
|
currentResource={props.current_installation}
|
||||||
|
resourceType={props.type}
|
||||||
|
></Access>
|
||||||
|
</AccessContextProvider>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path={'*'}
|
path={'*'}
|
||||||
element={<Navigate to={routes.information}></Navigate>}
|
element={<Navigate to={routes.batteryview}></Navigate>}
|
||||||
/>
|
/>
|
||||||
</Routes>
|
</Routes>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -396,4 +414,4 @@ function Installation(props: singleInstallationProps) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Installation;
|
export default SalidomoInstallation;
|
||||||
|
|
|
@ -5,10 +5,7 @@ import FlatInstallationView from './FlatInstallationView';
|
||||||
import { I_Installation } from '../../../interfaces/InstallationTypes';
|
import { I_Installation } from '../../../interfaces/InstallationTypes';
|
||||||
import { Route, Routes, useLocation } from 'react-router-dom';
|
import { Route, Routes, useLocation } from 'react-router-dom';
|
||||||
import routes from '../../../Resources/routes.json';
|
import routes from '../../../Resources/routes.json';
|
||||||
import Installation from './Installation';
|
import SalidomoInstallation from './Installation';
|
||||||
import { FormattedMessage } from 'react-intl';
|
|
||||||
import Button from '@mui/material/Button';
|
|
||||||
import SalidomonstallationForm from './SalidomoInstallationForm';
|
|
||||||
|
|
||||||
interface installationSearchProps {
|
interface installationSearchProps {
|
||||||
installations: I_Installation[];
|
installations: I_Installation[];
|
||||||
|
@ -18,26 +15,11 @@ function InstallationSearch(props: installationSearchProps) {
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
const currentLocation = useLocation();
|
const currentLocation = useLocation();
|
||||||
const [filteredData, setFilteredData] = useState(props.installations);
|
const [filteredData, setFilteredData] = useState(props.installations);
|
||||||
const [openModalInstallation, setOpenModalInstallation] = useState(false);
|
|
||||||
|
|
||||||
const handleNewInstallationInsertion = () => {
|
|
||||||
setOpenModalInstallation(true);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleInstallationFormSubmit = () => {
|
|
||||||
setOpenModalInstallation(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleFormCancel = () => {
|
|
||||||
setOpenModalInstallation(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const filtered = props.installations.filter(
|
const filtered = props.installations.filter(
|
||||||
(item) =>
|
(item) =>
|
||||||
item.installationName
|
item.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||||
.toLowerCase()
|
|
||||||
.includes(searchTerm.toLowerCase()) ||
|
|
||||||
item.location.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
item.location.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||||
item.region.toLowerCase().includes(searchTerm.toLowerCase())
|
item.region.toLowerCase().includes(searchTerm.toLowerCase())
|
||||||
);
|
);
|
||||||
|
@ -46,12 +28,6 @@ function InstallationSearch(props: installationSearchProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{openModalInstallation && (
|
|
||||||
<SalidomonstallationForm
|
|
||||||
cancel={handleFormCancel}
|
|
||||||
submit={handleInstallationFormSubmit}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<Grid container>
|
<Grid container>
|
||||||
<Grid
|
<Grid
|
||||||
item
|
item
|
||||||
|
@ -74,17 +50,6 @@ function InstallationSearch(props: installationSearchProps) {
|
||||||
alignItems: 'flex-start'
|
alignItems: 'flex-start'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
onClick={handleNewInstallationInsertion}
|
|
||||||
sx={{ marginBottom: '8px' }}
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id="addNewInstallation"
|
|
||||||
defaultMessage="Add new installation"
|
|
||||||
/>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<FormControl variant="outlined">
|
<FormControl variant="outlined">
|
||||||
<TextField
|
<TextField
|
||||||
placeholder="Search"
|
placeholder="Search"
|
||||||
|
@ -112,11 +77,11 @@ function InstallationSearch(props: installationSearchProps) {
|
||||||
key={installation.s3BucketId}
|
key={installation.s3BucketId}
|
||||||
path={routes.installation + installation.s3BucketId + '*'}
|
path={routes.installation + installation.s3BucketId + '*'}
|
||||||
element={
|
element={
|
||||||
<Installation
|
<SalidomoInstallation
|
||||||
key={installation.s3BucketId}
|
key={installation.s3BucketId}
|
||||||
current_installation={installation}
|
current_installation={installation}
|
||||||
type="installation"
|
type="installation"
|
||||||
></Installation>
|
></SalidomoInstallation>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -21,26 +21,21 @@ import { FormattedMessage } from 'react-intl';
|
||||||
interface SalidomoInstallationFormProps {
|
interface SalidomoInstallationFormProps {
|
||||||
cancel: () => void;
|
cancel: () => void;
|
||||||
submit: () => void;
|
submit: () => void;
|
||||||
|
parentid: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function SalidomonstallationForm(props: SalidomoInstallationFormProps) {
|
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 DeviceTypes = ['Cerbo', 'Venus'];
|
const DeviceTypes = ['Cerbo', 'Venus'];
|
||||||
const installationContext = useContext(InstallationsContext);
|
const installationContext = useContext(InstallationsContext);
|
||||||
|
@ -57,7 +52,7 @@ function SalidomonstallationForm(props: SalidomoInstallationFormProps) {
|
||||||
};
|
};
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
formValues.parentId = 1;
|
formValues.parentId = props.parentid;
|
||||||
formValues.product = 1;
|
formValues.product = 1;
|
||||||
const responseData = await createInstallation(formValues);
|
const responseData = await createInstallation(formValues);
|
||||||
props.submit();
|
props.submit();
|
||||||
|
@ -120,11 +115,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>
|
||||||
|
|
|
@ -9,12 +9,24 @@ import { UserContext } from '../../../contexts/userContext';
|
||||||
import { InstallationsContext } from '../../../contexts/InstallationsContextProvider';
|
import { InstallationsContext } from '../../../contexts/InstallationsContextProvider';
|
||||||
import { WebSocketContext } from '../../../contexts/WebSocketContextProvider';
|
import { WebSocketContext } from '../../../contexts/WebSocketContextProvider';
|
||||||
import ListIcon from '@mui/icons-material/List';
|
import ListIcon from '@mui/icons-material/List';
|
||||||
|
import AccountTreeIcon from '@mui/icons-material/AccountTree';
|
||||||
|
import TreeView from '../Tree/treeView';
|
||||||
|
import { ProductIdContext } from '../../../contexts/ProductIdContextProvider';
|
||||||
|
import { UserType } from '../../../interfaces/UserTypes';
|
||||||
|
import SalidomoInstallation from './Installation';
|
||||||
|
|
||||||
function SalidomoInstallationTabs() {
|
function SalidomoInstallationTabs() {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const context = useContext(UserContext);
|
const context = useContext(UserContext);
|
||||||
const { currentUser } = context;
|
const { currentUser } = context;
|
||||||
const tabList = ['batteryview', 'information', 'overview', 'log', 'history'];
|
const tabList = [
|
||||||
|
'batteryview',
|
||||||
|
'information',
|
||||||
|
'manage',
|
||||||
|
'overview',
|
||||||
|
'log',
|
||||||
|
'history'
|
||||||
|
];
|
||||||
|
|
||||||
const [currentTab, setCurrentTab] = useState<string>(undefined);
|
const [currentTab, setCurrentTab] = useState<string>(undefined);
|
||||||
const [fetchedInstallations, setFetchedInstallations] =
|
const [fetchedInstallations, setFetchedInstallations] =
|
||||||
|
@ -22,6 +34,8 @@ function SalidomoInstallationTabs() {
|
||||||
const { salidomoInstallations, fetchAllSalidomoInstallations } =
|
const { salidomoInstallations, fetchAllSalidomoInstallations } =
|
||||||
useContext(InstallationsContext);
|
useContext(InstallationsContext);
|
||||||
|
|
||||||
|
const { product, setProduct } = useContext(ProductIdContext);
|
||||||
|
|
||||||
const webSocketsContext = useContext(WebSocketContext);
|
const webSocketsContext = useContext(WebSocketContext);
|
||||||
const { socket, openSocket, closeSocket } = webSocketsContext;
|
const { socket, openSocket, closeSocket } = webSocketsContext;
|
||||||
|
|
||||||
|
@ -30,6 +44,8 @@ function SalidomoInstallationTabs() {
|
||||||
|
|
||||||
if (path[path.length - 2] === 'list') {
|
if (path[path.length - 2] === 'list') {
|
||||||
setCurrentTab('list');
|
setCurrentTab('list');
|
||||||
|
} else if (path[path.length - 2] === 'tree') {
|
||||||
|
setCurrentTab('tree');
|
||||||
} else {
|
} else {
|
||||||
//Even if we are located at path: /batteryview/mainstats, we want the BatteryView tab to be bold
|
//Even if we are located at path: /batteryview/mainstats, we want the BatteryView tab to be bold
|
||||||
setCurrentTab(path.find((pathElement) => tabList.includes(pathElement)));
|
setCurrentTab(path.find((pathElement) => tabList.includes(pathElement)));
|
||||||
|
@ -52,6 +68,10 @@ function SalidomoInstallationTabs() {
|
||||||
}
|
}
|
||||||
}, [salidomoInstallations]);
|
}, [salidomoInstallations]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setProduct(1);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleTabsChange = (_event: ChangeEvent<{}>, value: string): void => {
|
const handleTabsChange = (_event: ChangeEvent<{}>, value: string): void => {
|
||||||
setCurrentTab(value);
|
setCurrentTab(value);
|
||||||
};
|
};
|
||||||
|
@ -75,14 +95,9 @@ function SalidomoInstallationTabs() {
|
||||||
return ret_path;
|
return ret_path;
|
||||||
};
|
};
|
||||||
|
|
||||||
const tabs =
|
const singleInstallationTabs =
|
||||||
currentTab != 'list' && !location.pathname.includes('folder')
|
currentUser.userType == UserType.admin
|
||||||
? [
|
? [
|
||||||
{
|
|
||||||
value: 'list',
|
|
||||||
icon: <ListIcon id="mode-toggle-button-list-icon" />
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
{
|
||||||
value: 'batteryview',
|
value: 'batteryview',
|
||||||
label: (
|
label: (
|
||||||
|
@ -101,6 +116,16 @@ function SalidomoInstallationTabs() {
|
||||||
label: <FormattedMessage id="log" defaultMessage="Log" />
|
label: <FormattedMessage id="log" defaultMessage="Log" />
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
value: 'manage',
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id="manage"
|
||||||
|
defaultMessage="Access Management"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
value: 'information',
|
value: 'information',
|
||||||
label: (
|
label: (
|
||||||
|
@ -119,12 +144,132 @@ function SalidomoInstallationTabs() {
|
||||||
]
|
]
|
||||||
: [
|
: [
|
||||||
{
|
{
|
||||||
value: 'list',
|
value: 'batteryview',
|
||||||
icon: <ListIcon id="mode-toggle-button-list-icon" />
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id="batteryview"
|
||||||
|
defaultMessage="Battery View"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'overview',
|
||||||
|
label: <FormattedMessage id="overview" defaultMessage="Overview" />
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
value: 'information',
|
||||||
|
label: (
|
||||||
|
<FormattedMessage id="information" defaultMessage="Information" />
|
||||||
|
)
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
const tabs =
|
||||||
|
currentTab != 'list' &&
|
||||||
|
currentTab != 'tree' &&
|
||||||
|
!location.pathname.includes('folder') &&
|
||||||
|
currentUser.userType == UserType.admin
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
value: 'list',
|
||||||
|
icon: <ListIcon id="mode-toggle-button-list-icon" />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'tree',
|
||||||
|
icon: <AccountTreeIcon id="mode-toggle-button-tree-icon" />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'batteryview',
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id="batteryview"
|
||||||
|
defaultMessage="Battery View"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'overview',
|
||||||
|
label: <FormattedMessage id="overview" defaultMessage="Overview" />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'log',
|
||||||
|
label: <FormattedMessage id="log" defaultMessage="Log" />
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
value: 'manage',
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id="manage"
|
||||||
|
defaultMessage="Access Management"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
value: 'information',
|
||||||
|
label: (
|
||||||
|
<FormattedMessage id="information" defaultMessage="Information" />
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'history',
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id="history"
|
||||||
|
defaultMessage="History Of Actions"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
: currentTab != 'list' &&
|
||||||
|
currentTab != 'tree' &&
|
||||||
|
!location.pathname.includes('folder') &&
|
||||||
|
currentUser.userType == UserType.client
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
value: 'list',
|
||||||
|
icon: <ListIcon id="mode-toggle-button-list-icon" />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'tree',
|
||||||
|
icon: <AccountTreeIcon id="mode-toggle-button-tree-icon" />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'batteryview',
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id="batteryview"
|
||||||
|
defaultMessage="Battery View"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'overview',
|
||||||
|
label: <FormattedMessage id="overview" defaultMessage="Overview" />
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
value: 'information',
|
||||||
|
label: (
|
||||||
|
<FormattedMessage id="information" defaultMessage="Information" />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
{
|
||||||
|
value: 'list',
|
||||||
|
icon: <ListIcon id="mode-toggle-button-list-icon" />
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'tree',
|
||||||
|
icon: <AccountTreeIcon id="mode-toggle-button-tree-icon" />
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
return salidomoInstallations.length > 1 ? (
|
||||||
|
<>
|
||||||
<Container maxWidth="xl" sx={{ marginTop: '20px' }} className="mainframe">
|
<Container maxWidth="xl" sx={{ marginTop: '20px' }} className="mainframe">
|
||||||
<TabsContainerWrapper>
|
<TabsContainerWrapper>
|
||||||
<Tabs
|
<Tabs
|
||||||
|
@ -143,7 +288,7 @@ function SalidomoInstallationTabs() {
|
||||||
component={Link}
|
component={Link}
|
||||||
label={tab.label}
|
label={tab.label}
|
||||||
to={
|
to={
|
||||||
tab.value === 'list'
|
tab.value === 'list' || tab.value === 'tree'
|
||||||
? routes[tab.value]
|
? routes[tab.value]
|
||||||
: navigateToTabPath(location.pathname, routes[tab.value])
|
: navigateToTabPath(location.pathname, routes[tab.value])
|
||||||
}
|
}
|
||||||
|
@ -165,12 +310,16 @@ function SalidomoInstallationTabs() {
|
||||||
element={
|
element={
|
||||||
<Grid item xs={12}>
|
<Grid item xs={12}>
|
||||||
<Box p={4}>
|
<Box p={4}>
|
||||||
<InstallationSearch installations={salidomoInstallations} />
|
<InstallationSearch
|
||||||
|
installations={salidomoInstallations}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Grid>
|
</Grid>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Route path={routes.tree + '*'} element={<TreeView />} />
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path={'*'}
|
path={'*'}
|
||||||
element={
|
element={
|
||||||
|
@ -183,7 +332,59 @@ function SalidomoInstallationTabs() {
|
||||||
</Grid>
|
</Grid>
|
||||||
</Card>
|
</Card>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
</>
|
||||||
|
) : salidomoInstallations.length === 1 ? (
|
||||||
|
<>
|
||||||
|
{' '}
|
||||||
|
<Container maxWidth="xl" sx={{ marginTop: '20px' }} className="mainframe">
|
||||||
|
<TabsContainerWrapper>
|
||||||
|
<Tabs
|
||||||
|
onChange={handleTabsChange}
|
||||||
|
value={currentTab}
|
||||||
|
variant="scrollable"
|
||||||
|
scrollButtons="auto"
|
||||||
|
textColor="primary"
|
||||||
|
indicatorColor="primary"
|
||||||
|
>
|
||||||
|
{singleInstallationTabs.map((tab) => (
|
||||||
|
<Tab
|
||||||
|
key={tab.value}
|
||||||
|
value={tab.value}
|
||||||
|
component={Link}
|
||||||
|
label={tab.label}
|
||||||
|
to={routes[tab.value]}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</Tabs>
|
||||||
|
</TabsContainerWrapper>
|
||||||
|
<Card variant="outlined">
|
||||||
|
<Grid
|
||||||
|
container
|
||||||
|
direction="row"
|
||||||
|
justifyContent="center"
|
||||||
|
alignItems="stretch"
|
||||||
|
spacing={0}
|
||||||
|
>
|
||||||
|
<Routes>
|
||||||
|
<Route
|
||||||
|
path={'*'}
|
||||||
|
element={
|
||||||
|
<Grid item xs={12}>
|
||||||
|
<Box p={4}>
|
||||||
|
<SalidomoInstallation
|
||||||
|
current_installation={salidomoInstallations[0]}
|
||||||
|
type="installation"
|
||||||
|
></SalidomoInstallation>
|
||||||
|
</Box>
|
||||||
|
</Grid>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Routes>
|
||||||
|
</Grid>
|
||||||
|
</Card>
|
||||||
|
</Container>
|
||||||
|
</>
|
||||||
|
) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SalidomoInstallationTabs;
|
export default SalidomoInstallationTabs;
|
||||||
|
|
|
@ -10,6 +10,7 @@ import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
import { WebSocketContext } from 'src/contexts/WebSocketContextProvider';
|
import { WebSocketContext } from 'src/contexts/WebSocketContextProvider';
|
||||||
import routes from 'src/Resources/routes.json';
|
import routes from 'src/Resources/routes.json';
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
import { ProductIdContext } from '../../../contexts/ProductIdContextProvider';
|
||||||
|
|
||||||
interface CustomTreeItemProps {
|
interface CustomTreeItemProps {
|
||||||
node: I_Installation | I_Folder;
|
node: I_Installation | I_Folder;
|
||||||
|
@ -44,12 +45,15 @@ function CustomTreeItem(props: CustomTreeItemProps) {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [selected, setSelected] = useState(false);
|
const [selected, setSelected] = useState(false);
|
||||||
const currentLocation = useLocation();
|
const currentLocation = useLocation();
|
||||||
|
const { product, setProduct } = useContext(ProductIdContext);
|
||||||
|
|
||||||
const handleSelectOneInstallation = (): void => {
|
const handleSelectOneInstallation = (): void => {
|
||||||
let installation = props.node;
|
let installation = props.node;
|
||||||
|
let path =
|
||||||
|
product == 0 ? routes.installations : routes.salidomo_installations;
|
||||||
if (installation.type != 'Folder') {
|
if (installation.type != 'Folder') {
|
||||||
navigate(
|
navigate(
|
||||||
routes.installations +
|
path +
|
||||||
routes.tree +
|
routes.tree +
|
||||||
routes.installation +
|
routes.installation +
|
||||||
installation.s3BucketId +
|
installation.s3BucketId +
|
||||||
|
@ -62,7 +66,7 @@ function CustomTreeItem(props: CustomTreeItemProps) {
|
||||||
setSelected(!selected);
|
setSelected(!selected);
|
||||||
} else {
|
} else {
|
||||||
navigate(
|
navigate(
|
||||||
routes.installations +
|
path +
|
||||||
routes.tree +
|
routes.tree +
|
||||||
routes.folder +
|
routes.folder +
|
||||||
installation.id +
|
installation.id +
|
||||||
|
@ -156,7 +160,8 @@ function CustomTreeItem(props: CustomTreeItemProps) {
|
||||||
}
|
}
|
||||||
sx={{
|
sx={{
|
||||||
display:
|
display:
|
||||||
currentLocation.pathname === routes.installations + 'tree' ||
|
currentLocation.pathname ===
|
||||||
|
routes.salidomo_installations + routes.tree ||
|
||||||
currentLocation.pathname === routes.installations + routes.tree ||
|
currentLocation.pathname === routes.installations + routes.tree ||
|
||||||
currentLocation.pathname.includes('folder')
|
currentLocation.pathname.includes('folder')
|
||||||
? 'block'
|
? 'block'
|
||||||
|
|
|
@ -21,6 +21,8 @@ import FolderForm from './folderForm';
|
||||||
import InstallationForm from '../Installations/installationForm';
|
import InstallationForm from '../Installations/installationForm';
|
||||||
import { InstallationsContext } from '../../../contexts/InstallationsContextProvider';
|
import { InstallationsContext } from '../../../contexts/InstallationsContextProvider';
|
||||||
import { UserType } from '../../../interfaces/UserTypes';
|
import { UserType } from '../../../interfaces/UserTypes';
|
||||||
|
import SalidomoInstallationForm from '../SalidomoInstallations/SalidomoInstallationForm';
|
||||||
|
import { ProductIdContext } from '../../../contexts/ProductIdContextProvider';
|
||||||
|
|
||||||
interface TreeInformationProps {
|
interface TreeInformationProps {
|
||||||
folder: I_Folder;
|
folder: I_Folder;
|
||||||
|
@ -50,6 +52,8 @@ function TreeInformation(props: TreeInformationProps) {
|
||||||
deleteFolder
|
deleteFolder
|
||||||
} = installationContext;
|
} = installationContext;
|
||||||
|
|
||||||
|
const { product, setProduct } = useContext(ProductIdContext);
|
||||||
|
|
||||||
const handleChange = (e) => {
|
const handleChange = (e) => {
|
||||||
const { name, value } = e.target;
|
const { name, value } = e.target;
|
||||||
setFormValues({
|
setFormValues({
|
||||||
|
@ -61,7 +65,7 @@ function TreeInformation(props: TreeInformationProps) {
|
||||||
const handleFolderInformationUpdate = () => {
|
const handleFolderInformationUpdate = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(false);
|
setError(false);
|
||||||
updateFolder(formValues);
|
updateFolder(formValues, product);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleNewInstallationInsertion = () => {
|
const handleNewInstallationInsertion = () => {
|
||||||
|
@ -80,7 +84,7 @@ function TreeInformation(props: TreeInformationProps) {
|
||||||
|
|
||||||
const deleteFolderModalHandle = () => {
|
const deleteFolderModalHandle = () => {
|
||||||
setOpenModalDeleteFolder(false);
|
setOpenModalDeleteFolder(false);
|
||||||
deleteFolder(formValues);
|
deleteFolder(formValues, product);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -195,13 +199,20 @@ function TreeInformation(props: TreeInformationProps) {
|
||||||
parentid={props.folder.id}
|
parentid={props.folder.id}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{openModalInstallation && (
|
{openModalInstallation && product == 0 && (
|
||||||
<InstallationForm
|
<InstallationForm
|
||||||
cancel={handleFormCancel}
|
cancel={handleFormCancel}
|
||||||
submit={handleInstallationFormSubmit}
|
submit={handleInstallationFormSubmit}
|
||||||
parentid={props.folder.id}
|
parentid={props.folder.id}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{openModalInstallation && product == 1 && (
|
||||||
|
<SalidomoInstallationForm
|
||||||
|
cancel={handleFormCancel}
|
||||||
|
submit={handleInstallationFormSubmit}
|
||||||
|
parentid={props.folder.id}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Container maxWidth="xl">
|
<Container maxWidth="xl">
|
||||||
<Grid
|
<Grid
|
||||||
container
|
container
|
||||||
|
|
|
@ -8,19 +8,27 @@ import Installation from '../Installations/Installation';
|
||||||
import { InstallationsContext } from 'src/contexts/InstallationsContextProvider';
|
import { InstallationsContext } from 'src/contexts/InstallationsContextProvider';
|
||||||
import { Route, Routes } from 'react-router-dom';
|
import { Route, Routes } from 'react-router-dom';
|
||||||
import routes from '../../../Resources/routes.json';
|
import routes from '../../../Resources/routes.json';
|
||||||
import Folder from './Folder';
|
|
||||||
import { WebSocketContext } from '../../../contexts/WebSocketContextProvider';
|
import { WebSocketContext } from '../../../contexts/WebSocketContextProvider';
|
||||||
|
import SalidomoInstallation from '../SalidomoInstallations/Installation';
|
||||||
|
import { ProductIdContext } from '../../../contexts/ProductIdContextProvider';
|
||||||
|
import Folder from './Folder';
|
||||||
|
|
||||||
function InstallationTree() {
|
function InstallationTree() {
|
||||||
const { foldersAndInstallations, fetchAllFoldersAndInstallations } =
|
const { foldersAndInstallations, fetchAllFoldersAndInstallations } =
|
||||||
useContext(InstallationsContext);
|
useContext(InstallationsContext);
|
||||||
|
|
||||||
|
const { product, setProduct } = useContext(ProductIdContext);
|
||||||
|
|
||||||
const webSocketContext = useContext(WebSocketContext);
|
const webSocketContext = useContext(WebSocketContext);
|
||||||
const { getStatus } = webSocketContext;
|
const { getStatus } = webSocketContext;
|
||||||
|
|
||||||
const sortedInstallations = [...foldersAndInstallations].sort((a, b) => {
|
const sortedInstallations = [...foldersAndInstallations].sort((a, b) => {
|
||||||
// Compare the status field of each installation and sort them based on the status.
|
// Compare the status field of each installation and sort them based on the status.
|
||||||
//Installations with alarms go first
|
//Installations with alarms go first
|
||||||
|
|
||||||
|
if (a.type == 'Folder') {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
let a_status = getStatus(a.id);
|
let a_status = getStatus(a.id);
|
||||||
let b_status = getStatus(b.id);
|
let b_status = getStatus(b.id);
|
||||||
|
|
||||||
|
@ -34,7 +42,7 @@ function InstallationTree() {
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchAllFoldersAndInstallations();
|
fetchAllFoldersAndInstallations(product);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const TreeNode = ({ node, parent_id }) => {
|
const TreeNode = ({ node, parent_id }) => {
|
||||||
|
@ -61,17 +69,59 @@ function InstallationTree() {
|
||||||
</CustomTreeItem>
|
</CustomTreeItem>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else if (node.type == 'Installation') {
|
||||||
return (
|
return (
|
||||||
node.parentId == parent_id && (
|
node.parentId == parent_id && (
|
||||||
<CustomTreeItem node={node} parent_id={parent_id} />
|
<CustomTreeItem node={node} parent_id={parent_id} />
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Grid container spacing={1} sx={{ marginTop: 0.1 }}>
|
<Grid container spacing={1} sx={{ marginTop: 0.1 }}>
|
||||||
|
<Routes>
|
||||||
|
{foldersAndInstallations.map((installation) => {
|
||||||
|
if (installation.type == 'Installation') {
|
||||||
|
return (
|
||||||
|
<Route
|
||||||
|
key={installation.s3BucketId}
|
||||||
|
path={routes.installation + installation.s3BucketId + '*'}
|
||||||
|
element={
|
||||||
|
product == 0 ? (
|
||||||
|
<Installation
|
||||||
|
key={installation.s3BucketId}
|
||||||
|
current_installation={installation}
|
||||||
|
type="installation"
|
||||||
|
></Installation>
|
||||||
|
) : (
|
||||||
|
<SalidomoInstallation
|
||||||
|
key={installation.s3BucketId}
|
||||||
|
current_installation={installation}
|
||||||
|
type="installation"
|
||||||
|
></SalidomoInstallation>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return (
|
||||||
|
<Route
|
||||||
|
key={installation.id}
|
||||||
|
path={routes.folder + installation.id + '*'}
|
||||||
|
element={
|
||||||
|
<Folder
|
||||||
|
key={installation.id + installation.type}
|
||||||
|
current_folder={installation}
|
||||||
|
></Folder>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</Routes>
|
||||||
<Grid item xs={12} md={12}>
|
<Grid item xs={12} md={12}>
|
||||||
<TreeView
|
<TreeView
|
||||||
defaultCollapseIcon={<ExpandMoreIcon />}
|
defaultCollapseIcon={<ExpandMoreIcon />}
|
||||||
|
@ -93,39 +143,6 @@ function InstallationTree() {
|
||||||
})}
|
})}
|
||||||
</TreeView>
|
</TreeView>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Routes>
|
|
||||||
{foldersAndInstallations.map((installation) => {
|
|
||||||
if (installation.type == 'Installation') {
|
|
||||||
return (
|
|
||||||
<Route
|
|
||||||
key={installation.s3BucketId}
|
|
||||||
path={routes.installation + installation.s3BucketId + '*'}
|
|
||||||
element={
|
|
||||||
<Installation
|
|
||||||
key={installation.s3BucketId}
|
|
||||||
current_installation={installation}
|
|
||||||
type="installation"
|
|
||||||
></Installation>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return (
|
|
||||||
<Route
|
|
||||||
key={installation.id}
|
|
||||||
path={routes.folder + installation.id + '*'}
|
|
||||||
element={
|
|
||||||
<Folder
|
|
||||||
key={installation.id + installation.type}
|
|
||||||
current_folder={installation}
|
|
||||||
></Folder>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})}
|
|
||||||
</Routes>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { I_Folder } from 'src/interfaces/InstallationTypes';
|
||||||
import { TokenContext } from 'src/contexts/tokenContext';
|
import { TokenContext } from 'src/contexts/tokenContext';
|
||||||
import { InstallationsContext } from 'src/contexts/InstallationsContextProvider';
|
import { InstallationsContext } from 'src/contexts/InstallationsContextProvider';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
import { ProductIdContext } from '../../../contexts/ProductIdContextProvider';
|
||||||
|
|
||||||
interface folderFormProps {
|
interface folderFormProps {
|
||||||
cancel: () => void;
|
cancel: () => void;
|
||||||
|
@ -29,7 +30,7 @@ function folderForm(props: folderFormProps) {
|
||||||
information: ''
|
information: ''
|
||||||
});
|
});
|
||||||
const requiredFields = ['name'];
|
const requiredFields = ['name'];
|
||||||
|
const { product, setProduct } = useContext(ProductIdContext);
|
||||||
const tokencontext = useContext(TokenContext);
|
const tokencontext = useContext(TokenContext);
|
||||||
const { removeToken } = tokencontext;
|
const { removeToken } = tokencontext;
|
||||||
|
|
||||||
|
@ -47,7 +48,7 @@ function folderForm(props: folderFormProps) {
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
formValues.parentId = props.parentid;
|
formValues.parentId = props.parentid;
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const responseData = await createFolder(formValues);
|
const responseData = await createFolder(formValues, product);
|
||||||
|
|
||||||
props.submit();
|
props.submit();
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,7 +18,7 @@ interface I_InstallationContextProviderProps {
|
||||||
foldersAndInstallations: I_Installation[];
|
foldersAndInstallations: I_Installation[];
|
||||||
fetchAllInstallations: () => Promise<void>;
|
fetchAllInstallations: () => Promise<void>;
|
||||||
fetchAllSalidomoInstallations: () => Promise<void>;
|
fetchAllSalidomoInstallations: () => Promise<void>;
|
||||||
fetchAllFoldersAndInstallations: () => Promise<void>;
|
fetchAllFoldersAndInstallations: (product: number) => Promise<void>;
|
||||||
createInstallation: (value: Partial<I_Installation>) => Promise<void>;
|
createInstallation: (value: Partial<I_Installation>) => Promise<void>;
|
||||||
updateInstallation: (value: I_Installation, view: string) => Promise<void>;
|
updateInstallation: (value: I_Installation, view: string) => Promise<void>;
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
@ -28,9 +28,9 @@ interface I_InstallationContextProviderProps {
|
||||||
updated: boolean;
|
updated: boolean;
|
||||||
setUpdated: (value: boolean) => void;
|
setUpdated: (value: boolean) => void;
|
||||||
deleteInstallation: (value: I_Installation, view: string) => Promise<void>;
|
deleteInstallation: (value: I_Installation, view: string) => Promise<void>;
|
||||||
createFolder: (value: Partial<I_Folder>) => Promise<void>;
|
createFolder: (value: Partial<I_Folder>, product: number) => Promise<void>;
|
||||||
updateFolder: (value: I_Folder) => Promise<void>;
|
updateFolder: (value: I_Folder, product: number) => Promise<void>;
|
||||||
deleteFolder: (value: I_Folder) => Promise<void>;
|
deleteFolder: (value: I_Folder, product: number) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const InstallationsContext =
|
export const InstallationsContext =
|
||||||
|
@ -40,7 +40,7 @@ export const InstallationsContext =
|
||||||
foldersAndInstallations: [],
|
foldersAndInstallations: [],
|
||||||
fetchAllInstallations: () => Promise.resolve(),
|
fetchAllInstallations: () => Promise.resolve(),
|
||||||
fetchAllSalidomoInstallations: () => Promise.resolve(),
|
fetchAllSalidomoInstallations: () => Promise.resolve(),
|
||||||
fetchAllFoldersAndInstallations: () => Promise.resolve(),
|
fetchAllFoldersAndInstallations: (product: number) => Promise.resolve(),
|
||||||
createInstallation: () => Promise.resolve(),
|
createInstallation: () => Promise.resolve(),
|
||||||
updateInstallation: () => Promise.resolve(),
|
updateInstallation: () => Promise.resolve(),
|
||||||
loading: false,
|
loading: false,
|
||||||
|
@ -104,9 +104,10 @@ const InstallationsContextProvider = ({
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const fetchAllFoldersAndInstallations = useCallback(async () => {
|
const fetchAllFoldersAndInstallations = useCallback(
|
||||||
|
async (product: number) => {
|
||||||
return axiosConfig
|
return axiosConfig
|
||||||
.get('/GetAllFoldersAndInstallations')
|
.get(`/GetAllFoldersAndInstallations?productId=${product}`)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
setFoldersAndInstallations(res.data);
|
setFoldersAndInstallations(res.data);
|
||||||
})
|
})
|
||||||
|
@ -116,7 +117,9 @@ const InstallationsContextProvider = ({
|
||||||
navigate(routes.login);
|
navigate(routes.login);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, []);
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
const createInstallation = useCallback(
|
const createInstallation = useCallback(
|
||||||
async (formValues: Partial<I_Installation>) => {
|
async (formValues: Partial<I_Installation>) => {
|
||||||
|
@ -124,11 +127,12 @@ const InstallationsContextProvider = ({
|
||||||
.post('/CreateInstallation', formValues)
|
.post('/CreateInstallation', formValues)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
if (formValues.product == 0) {
|
fetchAllFoldersAndInstallations(formValues.product);
|
||||||
fetchAllFoldersAndInstallations();
|
// if (formValues.product == 0) {
|
||||||
} else {
|
// fetchAllFoldersAndInstallations();
|
||||||
fetchAllSalidomoInstallations();
|
// } else {
|
||||||
}
|
// fetchAllSalidomoInstallations();
|
||||||
|
// }
|
||||||
})
|
})
|
||||||
|
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
@ -151,14 +155,12 @@ const InstallationsContextProvider = ({
|
||||||
if (response) {
|
if (response) {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setUpdated(true);
|
setUpdated(true);
|
||||||
if (formValues.product == 0) {
|
if (formValues.product == 0 && view == 'installation') {
|
||||||
if (view == 'installation') {
|
|
||||||
fetchAllInstallations();
|
fetchAllInstallations();
|
||||||
} else {
|
} else if (formValues.product == 1 && view == 'installation') {
|
||||||
fetchAllFoldersAndInstallations();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fetchAllSalidomoInstallations();
|
fetchAllSalidomoInstallations();
|
||||||
|
} else {
|
||||||
|
fetchAllFoldersAndInstallations(formValues.product);
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -186,14 +188,12 @@ const InstallationsContextProvider = ({
|
||||||
if (response) {
|
if (response) {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setUpdated(true);
|
setUpdated(true);
|
||||||
if (formValues.product == 0) {
|
if (formValues.product == 0 && view == 'installation') {
|
||||||
if (view == 'installation') {
|
|
||||||
fetchAllInstallations();
|
fetchAllInstallations();
|
||||||
} else {
|
} else if (formValues.product == 1 && view == 'installation') {
|
||||||
fetchAllFoldersAndInstallations();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fetchAllSalidomoInstallations();
|
fetchAllSalidomoInstallations();
|
||||||
|
} else {
|
||||||
|
fetchAllFoldersAndInstallations(formValues.product);
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
@ -213,12 +213,13 @@ const InstallationsContextProvider = ({
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
const createFolder = useCallback(async (formValues: Partial<I_Folder>) => {
|
const createFolder = useCallback(
|
||||||
|
async (formValues: Partial<I_Folder>, product: number) => {
|
||||||
axiosConfig
|
axiosConfig
|
||||||
.post('/CreateFolder', formValues)
|
.post('/CreateFolder', formValues)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
fetchAllFoldersAndInstallations();
|
fetchAllFoldersAndInstallations(product);
|
||||||
})
|
})
|
||||||
|
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
@ -229,16 +230,19 @@ const InstallationsContextProvider = ({
|
||||||
navigate(routes.login);
|
navigate(routes.login);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, []);
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
const updateFolder = useCallback(async (formValues: I_Folder) => {
|
const updateFolder = useCallback(
|
||||||
|
async (formValues: I_Folder, product: number) => {
|
||||||
axiosConfig
|
axiosConfig
|
||||||
.put('/UpdateFolder', formValues)
|
.put('/UpdateFolder', formValues)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response) {
|
if (response) {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setUpdated(true);
|
setUpdated(true);
|
||||||
fetchAllFoldersAndInstallations();
|
fetchAllFoldersAndInstallations(product);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setUpdated(false);
|
setUpdated(false);
|
||||||
|
@ -253,16 +257,19 @@ const InstallationsContextProvider = ({
|
||||||
navigate(routes.login);
|
navigate(routes.login);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, []);
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
const deleteFolder = useCallback(async (formValues: I_Folder) => {
|
const deleteFolder = useCallback(
|
||||||
|
async (formValues: I_Folder, product: number) => {
|
||||||
axiosConfig
|
axiosConfig
|
||||||
.delete(`/DeleteFolder?folderId=${formValues.id}`)
|
.delete(`/DeleteFolder?folderId=${formValues.id}`)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response) {
|
if (response) {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setUpdated(true);
|
setUpdated(true);
|
||||||
fetchAllFoldersAndInstallations();
|
fetchAllFoldersAndInstallations(product);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setUpdated(false);
|
setUpdated(false);
|
||||||
|
@ -277,7 +284,9 @@ const InstallationsContextProvider = ({
|
||||||
navigate(routes.login);
|
navigate(routes.login);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, []);
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstallationsContext.Provider
|
<InstallationsContext.Provider
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
import { createContext, ReactNode, useState } from 'react';
|
||||||
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
|
// Define the shape of the context
|
||||||
|
interface ProductIdContextType {
|
||||||
|
product?: number;
|
||||||
|
setProduct: (new_product: number) => void;
|
||||||
|
accessToSalimax: boolean;
|
||||||
|
accessToSalidomo: boolean;
|
||||||
|
setAccessToSalimax: (access: boolean) => void;
|
||||||
|
setAccessToSalidomo: (access: boolean) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the context.
|
||||||
|
export const ProductIdContext = createContext<ProductIdContextType | undefined>(
|
||||||
|
undefined
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create a UserContextProvider component
|
||||||
|
export const ProductIdContextProvider = ({
|
||||||
|
children
|
||||||
|
}: {
|
||||||
|
children: ReactNode;
|
||||||
|
}) => {
|
||||||
|
const location = useLocation().pathname;
|
||||||
|
const [accessToSalimax, setAccessToSalimax] = useState(() => {
|
||||||
|
const storedValue = localStorage.getItem('accessToSalimax');
|
||||||
|
return storedValue === 'true';
|
||||||
|
});
|
||||||
|
const [accessToSalidomo, setAccessToSalidomo] = useState(() => {
|
||||||
|
const storedValue = localStorage.getItem('accessToSalidomo');
|
||||||
|
return storedValue === 'true';
|
||||||
|
});
|
||||||
|
const [product, setProduct] = useState(location.includes('salidomo') ? 1 : 0);
|
||||||
|
|
||||||
|
const changeProductId = (new_product: number) => {
|
||||||
|
setProduct(new_product);
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeAccessSalimax = (access: boolean) => {
|
||||||
|
setAccessToSalimax(access);
|
||||||
|
localStorage.setItem('accessToSalimax', JSON.stringify(access));
|
||||||
|
};
|
||||||
|
|
||||||
|
const changeAccessSalidomo = (access: boolean) => {
|
||||||
|
setAccessToSalidomo(access);
|
||||||
|
localStorage.setItem('accessToSalidomo', JSON.stringify(access));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ProductIdContext.Provider
|
||||||
|
value={{
|
||||||
|
product,
|
||||||
|
setProduct: changeProductId,
|
||||||
|
accessToSalimax,
|
||||||
|
accessToSalidomo,
|
||||||
|
setAccessToSalimax: changeAccessSalimax,
|
||||||
|
setAccessToSalidomo: changeAccessSalidomo
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</ProductIdContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProductIdContextProvider;
|
|
@ -18,12 +18,8 @@ export const WebSocketContext = createContext<
|
||||||
const WebSocketContextProvider = ({ children }: { children: ReactNode }) => {
|
const WebSocketContextProvider = ({ children }: { children: ReactNode }) => {
|
||||||
const [socket, setSocket] = useState<WebSocket>(null);
|
const [socket, setSocket] = useState<WebSocket>(null);
|
||||||
const [installations, setInstallations] = useState<I_Installation[]>(null);
|
const [installations, setInstallations] = useState<I_Installation[]>(null);
|
||||||
const [installationStatus, setInstallationStatus] = useState<
|
const [installationStatus, setInstallationStatus] = useState(new Map());
|
||||||
Record<number, number>
|
const [installationMode, setInstallationMode] = useState(new Map());
|
||||||
>({});
|
|
||||||
const [installationMode, setInstallatioMode] = useState<
|
|
||||||
Record<number, boolean>
|
|
||||||
>({});
|
|
||||||
const BUFFER_LENGTH = 5;
|
const BUFFER_LENGTH = 5;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -53,22 +49,33 @@ const WebSocketContextProvider = ({ children }: { children: ReactNode }) => {
|
||||||
// Listen for messages
|
// Listen for messages
|
||||||
socket.addEventListener('message', (event) => {
|
socket.addEventListener('message', (event) => {
|
||||||
const message = JSON.parse(event.data); // Parse the JSON data
|
const message = JSON.parse(event.data); // Parse the JSON data
|
||||||
|
if (Array.isArray(message)) {
|
||||||
if (message.id != -1) {
|
setInstallationMode((prevMode) => {
|
||||||
const installation_id = message.id;
|
const newMode = new Map(prevMode);
|
||||||
|
message.forEach((item) => {
|
||||||
//console.log('Message from server ', installation_id, status);
|
newMode.set(item.id, item.testingMode);
|
||||||
setInstallatioMode((prevMode) => {
|
});
|
||||||
// Create a new object by spreading the previous state
|
|
||||||
const newMode = { ...prevMode };
|
|
||||||
newMode[installation_id] = message.testingMode;
|
|
||||||
return newMode;
|
return newMode;
|
||||||
});
|
});
|
||||||
|
|
||||||
setInstallationStatus((prevStatus) => {
|
setInstallationStatus((prevStatus) => {
|
||||||
// Create a new object by spreading the previous state
|
const newStatus = new Map(prevStatus);
|
||||||
const newStatus = { ...prevStatus };
|
message.forEach((item) => {
|
||||||
newStatus[installation_id] = message.status;
|
newStatus.set(item.id, item.status);
|
||||||
|
});
|
||||||
|
return newStatus;
|
||||||
|
});
|
||||||
|
} else if (message.id != -1) {
|
||||||
|
const installation_id = message.id;
|
||||||
|
|
||||||
|
setInstallationMode((prevMode) => {
|
||||||
|
const newMode = new Map(prevMode);
|
||||||
|
newMode.set(message.id, message.testingMode);
|
||||||
|
return newMode;
|
||||||
|
});
|
||||||
|
setInstallationStatus((prevStatus) => {
|
||||||
|
const newStatus = new Map(prevStatus);
|
||||||
|
newStatus.set(message.id, message.status);
|
||||||
return newStatus;
|
return newStatus;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -86,17 +93,16 @@ const WebSocketContextProvider = ({ children }: { children: ReactNode }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const getStatus = (installationId: number) => {
|
const getStatus = (installationId: number) => {
|
||||||
let status;
|
return installationStatus.get(installationId);
|
||||||
if (!installationStatus.hasOwnProperty(installationId)) {
|
// if (installationStatus.has(installationId)) {
|
||||||
status = -2;
|
// installationStatus.get(installationId);
|
||||||
} else {
|
// } else {
|
||||||
status = installationStatus[installationId];
|
// return -2;
|
||||||
}
|
// }
|
||||||
return status;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTestingMode = (installationId: number) => {
|
const getTestingMode = (installationId: number) => {
|
||||||
return installationMode[installationId];
|
return installationMode.get(installationId);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { SidebarProvider } from 'src/contexts/SidebarContext';
|
||||||
import * as serviceWorker from 'src/serviceWorker';
|
import * as serviceWorker from 'src/serviceWorker';
|
||||||
import UserContextProvider from './contexts/userContext';
|
import UserContextProvider from './contexts/userContext';
|
||||||
import TokenContextProvider from './contexts/tokenContext';
|
import TokenContextProvider from './contexts/tokenContext';
|
||||||
|
import ProductIdContextProvider from './contexts/ProductIdContextProvider';
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<HelmetProvider>
|
<HelmetProvider>
|
||||||
|
@ -15,7 +16,9 @@ ReactDOM.render(
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<UserContextProvider>
|
<UserContextProvider>
|
||||||
<TokenContextProvider>
|
<TokenContextProvider>
|
||||||
|
<ProductIdContextProvider>
|
||||||
<App />
|
<App />
|
||||||
|
</ProductIdContextProvider>
|
||||||
</TokenContextProvider>
|
</TokenContextProvider>
|
||||||
</UserContextProvider>
|
</UserContextProvider>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
|
|
|
@ -26,6 +26,8 @@ export interface overviewInterface {
|
||||||
pvProduction: chartInfoInterface;
|
pvProduction: chartInfoInterface;
|
||||||
dcBusVoltage: chartInfoInterface;
|
dcBusVoltage: chartInfoInterface;
|
||||||
overview: chartInfoInterface;
|
overview: chartInfoInterface;
|
||||||
|
ACLoad: chartInfoInterface;
|
||||||
|
DCLoad: chartInfoInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface chartAggregatedDataInterface {
|
export interface chartAggregatedDataInterface {
|
||||||
|
@ -46,6 +48,8 @@ export interface chartDataInterface {
|
||||||
gridPower: { name: string; data: number[] };
|
gridPower: { name: string; data: number[] };
|
||||||
pvProduction: { name: string; data: number[] };
|
pvProduction: { name: string; data: number[] };
|
||||||
dcBusVoltage: { name: string; data: number[] };
|
dcBusVoltage: { name: string; data: number[] };
|
||||||
|
ACLoad: { name: string; data: number[] };
|
||||||
|
DCLoad: { name: string; data: number[] };
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BatteryDataInterface {
|
export interface BatteryDataInterface {
|
||||||
|
@ -339,7 +343,9 @@ export const transformInputToDailyData = async (
|
||||||
'/Battery/Dc/Power',
|
'/Battery/Dc/Power',
|
||||||
'/GridMeter/Ac/Power/Active',
|
'/GridMeter/Ac/Power/Active',
|
||||||
'/PvOnDc/Dc/Power',
|
'/PvOnDc/Dc/Power',
|
||||||
'/DcDc/Dc/Link/Voltage'
|
'/DcDc/Dc/Link/Voltage',
|
||||||
|
'/LoadOnAcGrid/Power/Active',
|
||||||
|
'/LoadOnDc/Power'
|
||||||
];
|
];
|
||||||
const categories = [
|
const categories = [
|
||||||
'soc',
|
'soc',
|
||||||
|
@ -347,7 +353,9 @@ export const transformInputToDailyData = async (
|
||||||
'dcPower',
|
'dcPower',
|
||||||
'gridPower',
|
'gridPower',
|
||||||
'pvProduction',
|
'pvProduction',
|
||||||
'dcBusVoltage'
|
'dcBusVoltage',
|
||||||
|
'ACLoad',
|
||||||
|
'DCLoad'
|
||||||
];
|
];
|
||||||
|
|
||||||
const chartData: chartDataInterface = {
|
const chartData: chartDataInterface = {
|
||||||
|
@ -356,7 +364,9 @@ export const transformInputToDailyData = async (
|
||||||
dcPower: { name: 'Battery Power', data: [] },
|
dcPower: { name: 'Battery Power', data: [] },
|
||||||
gridPower: { name: 'Grid Power', data: [] },
|
gridPower: { name: 'Grid Power', data: [] },
|
||||||
pvProduction: { name: 'Pv Production', data: [] },
|
pvProduction: { name: 'Pv Production', data: [] },
|
||||||
dcBusVoltage: { name: 'DC Bus Voltage', data: [] }
|
dcBusVoltage: { name: 'DC Bus Voltage', data: [] },
|
||||||
|
ACLoad: { name: 'AC Load', data: [] },
|
||||||
|
DCLoad: { name: 'DC Load', data: [] }
|
||||||
};
|
};
|
||||||
|
|
||||||
const chartOverview: overviewInterface = {
|
const chartOverview: overviewInterface = {
|
||||||
|
@ -367,7 +377,9 @@ export const transformInputToDailyData = async (
|
||||||
gridPower: { magnitude: 0, unit: '', min: 0, max: 0 },
|
gridPower: { magnitude: 0, unit: '', min: 0, max: 0 },
|
||||||
pvProduction: { magnitude: 0, unit: '', min: 0, max: 0 },
|
pvProduction: { magnitude: 0, unit: '', min: 0, max: 0 },
|
||||||
dcBusVoltage: { magnitude: 0, unit: '', min: 0, max: 0 },
|
dcBusVoltage: { magnitude: 0, unit: '', min: 0, max: 0 },
|
||||||
overview: { magnitude: 0, unit: '', min: 0, max: 0 }
|
overview: { magnitude: 0, unit: '', min: 0, max: 0 },
|
||||||
|
ACLoad: { magnitude: 0, unit: '', min: 0, max: 0 },
|
||||||
|
DCLoad: { magnitude: 0, unit: '', min: 0, max: 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
categories.forEach((category) => {
|
categories.forEach((category) => {
|
||||||
|
@ -560,7 +572,9 @@ export const transformInputToAggregatedData = async (
|
||||||
gridPower: { magnitude: 0, unit: '', min: 0, max: 0 },
|
gridPower: { magnitude: 0, unit: '', min: 0, max: 0 },
|
||||||
pvProduction: { magnitude: 0, unit: '', min: 0, max: 0 },
|
pvProduction: { magnitude: 0, unit: '', min: 0, max: 0 },
|
||||||
dcBusVoltage: { magnitude: 0, unit: '', min: 0, max: 0 },
|
dcBusVoltage: { magnitude: 0, unit: '', min: 0, max: 0 },
|
||||||
overview: { magnitude: 0, unit: '', min: 0, max: 0 }
|
overview: { magnitude: 0, unit: '', min: 0, max: 0 },
|
||||||
|
ACLoad: { magnitude: 0, unit: '', min: 0, max: 0 },
|
||||||
|
DCLoad: { magnitude: 0, unit: '', min: 0, max: 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
pathsToSearch.forEach((path) => {
|
pathsToSearch.forEach((path) => {
|
||||||
|
|
|
@ -16,6 +16,7 @@ import TableChartTwoToneIcon from '@mui/icons-material/TableChartTwoTone';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { UserContext } from '../../../../contexts/userContext';
|
import { UserContext } from '../../../../contexts/userContext';
|
||||||
import { UserType } from '../../../../interfaces/UserTypes';
|
import { UserType } from '../../../../interfaces/UserTypes';
|
||||||
|
import { ProductIdContext } from '../../../../contexts/ProductIdContextProvider';
|
||||||
|
|
||||||
const MenuWrapper = styled(Box)(
|
const MenuWrapper = styled(Box)(
|
||||||
({ theme }) => `
|
({ theme }) => `
|
||||||
|
@ -163,6 +164,7 @@ function SidebarMenu() {
|
||||||
const { closeSidebar } = useContext(SidebarContext);
|
const { closeSidebar } = useContext(SidebarContext);
|
||||||
const context = useContext(UserContext);
|
const context = useContext(UserContext);
|
||||||
const { currentUser, setUser } = context;
|
const { currentUser, setUser } = context;
|
||||||
|
const { accessToSalimax, accessToSalidomo } = useContext(ProductIdContext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -176,6 +178,7 @@ function SidebarMenu() {
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<SubMenuWrapper>
|
<SubMenuWrapper>
|
||||||
|
{accessToSalimax && (
|
||||||
<List component="div">
|
<List component="div">
|
||||||
<ListItem component="div">
|
<ListItem component="div">
|
||||||
<Button
|
<Button
|
||||||
|
@ -191,8 +194,9 @@ function SidebarMenu() {
|
||||||
</Button>
|
</Button>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
</List>
|
</List>
|
||||||
|
)}
|
||||||
|
|
||||||
{currentUser.userType == UserType.admin && (
|
{accessToSalidomo && (
|
||||||
<List component="div">
|
<List component="div">
|
||||||
<ListItem component="div">
|
<ListItem component="div">
|
||||||
<Button
|
<Button
|
||||||
|
|
Loading…
Reference in New Issue