diff --git a/csharp/App/Backend/Controller.cs b/csharp/App/Backend/Controller.cs index b4dabe8cc..220f63c3c 100644 --- a/csharp/App/Backend/Controller.cs +++ b/csharp/App/Backend/Controller.cs @@ -564,12 +564,20 @@ public class Controller : ControllerBase return Ok(); } - - [HttpPost(nameof(EditInstallationConfig))] - public async Task>> EditInstallationConfig([FromBody] Configuration config, Int64 installationId, Token authToken) + [HttpPost(nameof(InsertNewAction))] + public async Task>> InsertNewAction([FromBody] UserAction action, Token authToken) + { + var session = Db.GetSession(authToken); + var actionSuccess = await session.RecordUserAction(action); + return actionSuccess ? Ok() : Unauthorized(); + + } + + + [HttpPost(nameof(EditInstallationConfig))] + public async Task>> EditInstallationConfig([FromBody] Configuration config, Int64 installationId,Token authToken) { var session = Db.GetSession(authToken); - //Console.WriteLine(config.GridSetPoint); // Send configuration changes var success = await session.SendInstallationConfig(installationId, config); @@ -577,7 +585,15 @@ public class Controller : ControllerBase // Record configuration change if (success) { - var actionSuccess = await session.RecordUserAction(installationId, config); + // Create a new UserAction object + var action = new UserAction + { + InstallationId = installationId, + Timestamp = DateTime.Now, + Description = config.GetConfigurationString() + }; + + var actionSuccess = await session.RecordUserAction(action); return actionSuccess?Ok():Unauthorized(); } diff --git a/csharp/App/Backend/DataTypes/Methods/Session.cs b/csharp/App/Backend/DataTypes/Methods/Session.cs index 7fe7a23fa..5824c9602 100644 --- a/csharp/App/Backend/DataTypes/Methods/Session.cs +++ b/csharp/App/Backend/DataTypes/Methods/Session.cs @@ -102,23 +102,15 @@ public static class SessionMethods && await installation.SendConfig(configuration); } - public static async Task RecordUserAction(this Session? session, Int64 installationId, Configuration newConfiguration) + public static async Task RecordUserAction(this Session? session, UserAction action) { var user = session?.User; - var timestamp = DateTime.Now; if (user is null || user.UserType == 0) return false; - // Create a new UserAction object - var action = new UserAction - { - UserName = user.Name, - InstallationId = installationId, - Timestamp = timestamp, - Description = newConfiguration.GetConfigurationString() - }; - + action.UserName = user.Name; + // Save the configuration change to the database Db.HandleAction(action); return true; diff --git a/csharp/App/Backend/Database/Create.cs b/csharp/App/Backend/Database/Create.cs index b25cc089f..2c8c7aa2e 100644 --- a/csharp/App/Backend/Database/Create.cs +++ b/csharp/App/Backend/Database/Create.cs @@ -88,7 +88,7 @@ public static partial class Db } else { - Console.WriteLine("---------------Added the new Error to the database-----------------"); + Console.WriteLine("---------------Added the new Action to the database-----------------"); Create(newAction); } } diff --git a/csharp/App/Backend/Websockets/RabbitMQManager.cs b/csharp/App/Backend/Websockets/RabbitMQManager.cs index 6402eb671..8d8ee4194 100644 --- a/csharp/App/Backend/Websockets/RabbitMQManager.cs +++ b/csharp/App/Backend/Websockets/RabbitMQManager.cs @@ -59,23 +59,8 @@ public static class RabbitMqManager //Consumer received a message if (receivedStatusMessage != null) { - Console.WriteLine("----------------------------------------------"); - - int installationId = (int)Db.Installations.Where(f => f.Product == receivedStatusMessage.Product && f.S3BucketId == receivedStatusMessage.InstallationId).Select(f => f.Id).FirstOrDefault(); - string installationName = (string)Db.Installations.Where(f => f.Product == receivedStatusMessage.Product && f.S3BucketId == receivedStatusMessage.InstallationId).Select(f => f.InstallationName).FirstOrDefault(); - int bucketId = (int)Db.Installations.Where(f => f.Product == receivedStatusMessage.Product && f.S3BucketId == receivedStatusMessage.InstallationId).Select(f => f.S3BucketId).FirstOrDefault(); - int productId = (int)Db.Installations.Where(f => f.Product == receivedStatusMessage.Product && f.S3BucketId == receivedStatusMessage.InstallationId).Select(f => f.Product).FirstOrDefault(); - string monitorLink = ""; - if (productId == 0) - { - monitorLink = - $"https://monitor.innov.energy/installations/list/installation/{bucketId}/batteryview"; - } - else - { - monitorLink = - $"https://monitor.innov.energy/salidomo_installations/list/installation/{bucketId}/batteryview"; - } + Installation installation = Db.Installations.FirstOrDefault(f => f.Product == receivedStatusMessage.Product && f.S3BucketId == receivedStatusMessage.InstallationId); + int installationId = (int )installation.Id; Console.WriteLine("Received a message from installation: " + installationId + " , product is: "+receivedStatusMessage.Product+ " and status is: " + receivedStatusMessage.Status); //This is a heartbit message, just update the timestamp for this installation. @@ -112,18 +97,33 @@ public static class RabbitMqManager //Traverse the Alarm list, and store each of them to the database if (receivedStatusMessage.Alarms != null) { + + string monitorLink; + if (installation.Product == 0) + { + monitorLink = + $"https://monitor.innov.energy/installations/list/installation/{installation.S3BucketId}/batteryview"; + } + else + { + monitorLink = + $"https://monitor.innov.energy/salidomo_installations/list/installation/{installation.S3BucketId}/batteryview"; + } foreach (var alarm in receivedStatusMessage.Alarms) { Error newError = new Error { - InstallationId = installationId, + InstallationId = installation.Id, Description = alarm.Description, Date = alarm.Date, Time = alarm.Time, DeviceCreatedTheMessage = alarm.CreatedBy, Seen = false - }; Console.WriteLine("Add an alarm for installation "+installationId); + }; + + Console.WriteLine("Add an alarm for installation "+installationId); + // Send replace battery email to support team if this alarm is "NeedToReplaceBattery" if (alarm.Description == "NeedToReplaceBattery" || alarm.Description == "2 or more string are disabled") { @@ -132,7 +132,7 @@ public static class RabbitMqManager string subject = "Battery Alarm: 2 or more strings broken"; string text = $"Dear InnovEnergy Support Team,\n" + $"\n"+ - $"Installation Name: {installationName}\n"+ + $"Installation Name: {installation.InstallationName}\n"+ $"\n"+ $"Installation Monitor Link: {monitorLink}\n"+ $"\n"+ diff --git a/typescript/frontend-marios2/src/content/dashboards/History/History.tsx b/typescript/frontend-marios2/src/content/dashboards/History/History.tsx index 25de1adce..8d519f3dc 100644 --- a/typescript/frontend-marios2/src/content/dashboards/History/History.tsx +++ b/typescript/frontend-marios2/src/content/dashboards/History/History.tsx @@ -1,11 +1,14 @@ import React, { useContext, useEffect, useState } from 'react'; import { Alert, + Box, Card, Container, Divider, Grid, IconButton, + Modal, + TextField, useTheme } from '@mui/material'; import Typography from '@mui/material/Typography'; @@ -16,6 +19,10 @@ import routes from '../../../Resources/routes.json'; import { useNavigate } from 'react-router-dom'; import { TokenContext } from '../../../contexts/tokenContext'; import { Action } from '../../../interfaces/S3Types'; +import Button from '@mui/material/Button'; +import { DateTimePicker, LocalizationProvider } from '@mui/x-date-pickers'; +import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; +import dayjs from 'dayjs'; interface HistoryProps { errorLoadingS3Data: boolean; @@ -29,7 +36,61 @@ function HistoryOfActions(props: HistoryProps) { const [history, setHistory] = useState([]); const navigate = useNavigate(); const tokencontext = useContext(TokenContext); + const [actionDate, setActionDate] = useState(dayjs()); const { removeToken } = tokencontext; + const [openModalAddAction, setOpenModalAddAction] = useState(false); + const requiredFields = ['description', 'timestamp']; + const [newAction, setNewAction] = useState>({ + installationId: props.id, + timestamp: actionDate.toDate(), + description: '' + }); + + const handleDateChange = (newdate) => { + setActionDate(newdate); + setNewAction({ + ...newAction, + ['timestamp']: newdate + }); + }; + + const handleChange = (e) => { + const { name, value } = e.target; + setNewAction({ + ...newAction, + [name]: value + }); + }; + + const handleAddActionButton = () => { + setOpenModalAddAction(!openModalAddAction); + }; + + const SumbitNewAction = () => { + const res = axiosConfig.post(`/InsertNewAction`, newAction).catch((err) => { + if (err.response) { + // setError(true); + // setLoading(false); + } + }); + + if (res) { + setOpenModalAddAction(!openModalAddAction); + } + }; + + const deleteUserModalHandleCancel = (e) => { + setOpenModalAddAction(false); + }; + + const areRequiredFieldsFilled = () => { + for (const field of requiredFields) { + if (!newAction[field]) { + return false; + } + } + return true; + }; useEffect(() => { axiosConfig @@ -43,265 +104,378 @@ function HistoryOfActions(props: HistoryProps) { navigate(routes.login); } }); - }, []); + }, [openModalAddAction]); return ( - - - - {history.length > 0 && ( - - -
-
-
- - - -
- -
- - - -
-
- - - -
-
- - - -
-
- -
- {history.map((action, index) => { - // Parse the timestamp string to a Date object - const date = new Date(action.timestamp); - - // Extract the date part (e.g., "2023-05-31") - const datePart = date.toLocaleDateString(); - - // Extract the time part (e.g., "12:34:56") - const timePart = date.toLocaleTimeString(); - - return ( - - -
-
- - {action.userName} - -
- -
- - {datePart} - -
-
- - {timePart} - -
- -
- - {action.description} - -
-
-
- ); - })} -
-
-
- )} - - {!props.errorLoadingS3Data && history.length == 0 && ( - + {openModalAddAction && ( + + + - - - - )} -
-
+
+ handleDateChange(newDate.toDate())} + sx={{ + width: 450, + marginTop: 2 + }} + /> - - {props.errorLoadingS3Data && ( - - - - - )} - - + +
+ +
+ + + +
+ + + + )} + + {!openModalAddAction && ( + + + + + + + + + + {history.length > 0 && ( + + +
+
+
+ + + +
+ +
+ + + +
+
+ + + +
+
+ + + +
+
+ +
+ {history.map((action, index) => { + // Parse the timestamp string to a Date object + const date = new Date(action.timestamp); + + // Extract the date part (e.g., "2023-05-31") + const datePart = date.toLocaleDateString(); + + // Extract the time part (e.g., "12:34:56") + const timePart = date.toLocaleTimeString(); + + return ( + + +
+
+ + {action.userName} + +
+ +
+ + {datePart} + +
+
+ + {timePart} + +
+ +
+ + {action.description} + +
+
+
+ ); + })} +
+
+
+ )} + + {!props.errorLoadingS3Data && history.length == 0 && ( + + + + + )} +
+
+ + + {props.errorLoadingS3Data && ( + + + + + )} + +
+ )} + ); } diff --git a/typescript/frontend-marios2/src/interfaces/S3Types.tsx b/typescript/frontend-marios2/src/interfaces/S3Types.tsx index 6d7c56db0..7da146cc4 100644 --- a/typescript/frontend-marios2/src/interfaces/S3Types.tsx +++ b/typescript/frontend-marios2/src/interfaces/S3Types.tsx @@ -21,6 +21,6 @@ export interface Action { id: number; userName: string; installationId: number; - timestamp: string; - description: String; + timestamp: Date; + description: string; }