Add history button
This commit is contained in:
parent
5fdc7de448
commit
48de0805b9
|
@ -564,12 +564,20 @@ public class Controller : ControllerBase
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost(nameof(InsertNewAction))]
|
||||||
[HttpPost(nameof(EditInstallationConfig))]
|
public async Task<ActionResult<IEnumerable<Object>>> InsertNewAction([FromBody] UserAction action, Token authToken)
|
||||||
public async Task<ActionResult<IEnumerable<Object>>> EditInstallationConfig([FromBody] Configuration config, Int64 installationId, Token authToken)
|
{
|
||||||
|
var session = Db.GetSession(authToken);
|
||||||
|
var actionSuccess = await session.RecordUserAction(action);
|
||||||
|
return actionSuccess ? Ok() : Unauthorized();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[HttpPost(nameof(EditInstallationConfig))]
|
||||||
|
public async Task<ActionResult<IEnumerable<Object>>> EditInstallationConfig([FromBody] Configuration config, Int64 installationId,Token authToken)
|
||||||
{
|
{
|
||||||
var session = Db.GetSession(authToken);
|
var session = Db.GetSession(authToken);
|
||||||
//Console.WriteLine(config.GridSetPoint);
|
|
||||||
|
|
||||||
// Send configuration changes
|
// Send configuration changes
|
||||||
var success = await session.SendInstallationConfig(installationId, config);
|
var success = await session.SendInstallationConfig(installationId, config);
|
||||||
|
@ -577,7 +585,15 @@ public class Controller : ControllerBase
|
||||||
// Record configuration change
|
// Record configuration change
|
||||||
if (success)
|
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();
|
return actionSuccess?Ok():Unauthorized();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -102,22 +102,14 @@ public static class SessionMethods
|
||||||
&& await installation.SendConfig(configuration);
|
&& await installation.SendConfig(configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<Boolean> RecordUserAction(this Session? session, Int64 installationId, Configuration newConfiguration)
|
public static async Task<Boolean> RecordUserAction(this Session? session, UserAction action)
|
||||||
{
|
{
|
||||||
var user = session?.User;
|
var user = session?.User;
|
||||||
var timestamp = DateTime.Now;
|
|
||||||
|
|
||||||
if (user is null || user.UserType == 0)
|
if (user is null || user.UserType == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Create a new UserAction object
|
action.UserName = user.Name;
|
||||||
var action = new UserAction
|
|
||||||
{
|
|
||||||
UserName = user.Name,
|
|
||||||
InstallationId = installationId,
|
|
||||||
Timestamp = timestamp,
|
|
||||||
Description = newConfiguration.GetConfigurationString()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Save the configuration change to the database
|
// Save the configuration change to the database
|
||||||
Db.HandleAction(action);
|
Db.HandleAction(action);
|
||||||
|
|
|
@ -88,7 +88,7 @@ public static partial class Db
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine("---------------Added the new Error to the database-----------------");
|
Console.WriteLine("---------------Added the new Action to the database-----------------");
|
||||||
Create(newAction);
|
Create(newAction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,23 +59,8 @@ public static class RabbitMqManager
|
||||||
//Consumer received a message
|
//Consumer received a message
|
||||||
if (receivedStatusMessage != null)
|
if (receivedStatusMessage != null)
|
||||||
{
|
{
|
||||||
Console.WriteLine("----------------------------------------------");
|
Installation installation = Db.Installations.FirstOrDefault(f => f.Product == receivedStatusMessage.Product && f.S3BucketId == receivedStatusMessage.InstallationId);
|
||||||
|
int installationId = (int )installation.Id;
|
||||||
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";
|
|
||||||
}
|
|
||||||
Console.WriteLine("Received a message from installation: " + installationId + " , product is: "+receivedStatusMessage.Product+ " and status is: " + receivedStatusMessage.Status);
|
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.
|
//This is a heartbit message, just update the timestamp for this installation.
|
||||||
|
@ -113,17 +98,32 @@ public static class RabbitMqManager
|
||||||
if (receivedStatusMessage.Alarms != null)
|
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)
|
foreach (var alarm in receivedStatusMessage.Alarms)
|
||||||
{
|
{
|
||||||
Error newError = new Error
|
Error newError = new Error
|
||||||
{
|
{
|
||||||
InstallationId = installationId,
|
InstallationId = installation.Id,
|
||||||
Description = alarm.Description,
|
Description = alarm.Description,
|
||||||
Date = alarm.Date,
|
Date = alarm.Date,
|
||||||
Time = alarm.Time,
|
Time = alarm.Time,
|
||||||
DeviceCreatedTheMessage = alarm.CreatedBy,
|
DeviceCreatedTheMessage = alarm.CreatedBy,
|
||||||
Seen = false
|
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"
|
// Send replace battery email to support team if this alarm is "NeedToReplaceBattery"
|
||||||
if (alarm.Description == "NeedToReplaceBattery" || alarm.Description == "2 or more string are disabled")
|
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 subject = "Battery Alarm: 2 or more strings broken";
|
||||||
string text = $"Dear InnovEnergy Support Team,\n" +
|
string text = $"Dear InnovEnergy Support Team,\n" +
|
||||||
$"\n"+
|
$"\n"+
|
||||||
$"Installation Name: {installationName}\n"+
|
$"Installation Name: {installation.InstallationName}\n"+
|
||||||
$"\n"+
|
$"\n"+
|
||||||
$"Installation Monitor Link: {monitorLink}\n"+
|
$"Installation Monitor Link: {monitorLink}\n"+
|
||||||
$"\n"+
|
$"\n"+
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
import React, { useContext, useEffect, useState } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
|
Box,
|
||||||
Card,
|
Card,
|
||||||
Container,
|
Container,
|
||||||
Divider,
|
Divider,
|
||||||
Grid,
|
Grid,
|
||||||
IconButton,
|
IconButton,
|
||||||
|
Modal,
|
||||||
|
TextField,
|
||||||
useTheme
|
useTheme
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
|
@ -16,6 +19,10 @@ import routes from '../../../Resources/routes.json';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { TokenContext } from '../../../contexts/tokenContext';
|
import { TokenContext } from '../../../contexts/tokenContext';
|
||||||
import { Action } from '../../../interfaces/S3Types';
|
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 {
|
interface HistoryProps {
|
||||||
errorLoadingS3Data: boolean;
|
errorLoadingS3Data: boolean;
|
||||||
|
@ -29,7 +36,61 @@ function HistoryOfActions(props: HistoryProps) {
|
||||||
const [history, setHistory] = useState<Action[]>([]);
|
const [history, setHistory] = useState<Action[]>([]);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const tokencontext = useContext(TokenContext);
|
const tokencontext = useContext(TokenContext);
|
||||||
|
const [actionDate, setActionDate] = useState(dayjs());
|
||||||
const { removeToken } = tokencontext;
|
const { removeToken } = tokencontext;
|
||||||
|
const [openModalAddAction, setOpenModalAddAction] = useState(false);
|
||||||
|
const requiredFields = ['description', 'timestamp'];
|
||||||
|
const [newAction, setNewAction] = useState<Partial<Action>>({
|
||||||
|
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(() => {
|
useEffect(() => {
|
||||||
axiosConfig
|
axiosConfig
|
||||||
|
@ -43,265 +104,378 @@ function HistoryOfActions(props: HistoryProps) {
|
||||||
navigate(routes.login);
|
navigate(routes.login);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, []);
|
}, [openModalAddAction]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="xl">
|
<>
|
||||||
<Grid container>
|
{openModalAddAction && (
|
||||||
<Grid item xs={12} md={12}>
|
<Modal
|
||||||
{history.length > 0 && (
|
open={openModalAddAction}
|
||||||
<Card sx={{ marginTop: '10px' }}>
|
aria-labelledby="error-modal"
|
||||||
<Divider />
|
aria-describedby="error-modal-description"
|
||||||
<div>
|
>
|
||||||
<div
|
<LocalizationProvider dateAdapter={AdapterDayjs}>
|
||||||
style={{
|
<Box
|
||||||
height: '40px',
|
|
||||||
marginBottom: '10px',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
marginTop: '15px',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography
|
|
||||||
variant="body1"
|
|
||||||
color="dimgrey"
|
|
||||||
fontWeight="bold"
|
|
||||||
fontSize="1rem"
|
|
||||||
gutterBottom
|
|
||||||
noWrap
|
|
||||||
>
|
|
||||||
<FormattedMessage id="user" defaultMessage="User" />
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
marginTop: '15px',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography
|
|
||||||
variant="body1"
|
|
||||||
color="dimgrey"
|
|
||||||
fontWeight="bold"
|
|
||||||
fontSize="1rem"
|
|
||||||
gutterBottom
|
|
||||||
noWrap
|
|
||||||
>
|
|
||||||
<FormattedMessage id="date" defaultMessage="Date" />
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
marginTop: '15px',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography
|
|
||||||
variant="body1"
|
|
||||||
color="dimgrey"
|
|
||||||
fontWeight="bold"
|
|
||||||
fontSize="1rem"
|
|
||||||
gutterBottom
|
|
||||||
noWrap
|
|
||||||
>
|
|
||||||
<FormattedMessage id="time" defaultMessage="Time" />
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
flex: 6,
|
|
||||||
marginTop: '15px',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography
|
|
||||||
variant="body1"
|
|
||||||
color="dimgrey"
|
|
||||||
fontWeight="bold"
|
|
||||||
fontSize="1rem"
|
|
||||||
gutterBottom
|
|
||||||
noWrap
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
id="description"
|
|
||||||
defaultMessage="Description"
|
|
||||||
/>
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Divider />
|
|
||||||
<div style={{ maxHeight: '400px', overflowY: 'auto' }}>
|
|
||||||
{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 (
|
|
||||||
<React.Fragment key={index}>
|
|
||||||
<Divider />
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
minHeight: '40px',
|
|
||||||
marginBottom: '10px',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
marginTop: '15px',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography
|
|
||||||
variant="body1"
|
|
||||||
fontWeight="bold"
|
|
||||||
color="text.primary"
|
|
||||||
gutterBottom
|
|
||||||
>
|
|
||||||
{action.userName}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
marginTop: '15px',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography
|
|
||||||
variant="body1"
|
|
||||||
fontWeight="bold"
|
|
||||||
color="text.primary"
|
|
||||||
gutterBottom
|
|
||||||
>
|
|
||||||
{datePart}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
marginTop: '15px',
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography
|
|
||||||
variant="body1"
|
|
||||||
fontWeight="bold"
|
|
||||||
color="text.primary"
|
|
||||||
gutterBottom
|
|
||||||
>
|
|
||||||
{timePart}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
flex: 6,
|
|
||||||
display: 'flex',
|
|
||||||
marginTop: '15px',
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Typography
|
|
||||||
variant="body1"
|
|
||||||
fontWeight="bold"
|
|
||||||
color="text.primary"
|
|
||||||
gutterBottom
|
|
||||||
style={{
|
|
||||||
whiteSpace: 'normal',
|
|
||||||
wordBreak: 'break-word'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{action.description}
|
|
||||||
</Typography>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</React.Fragment>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Card>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!props.errorLoadingS3Data && history.length == 0 && (
|
|
||||||
<Alert
|
|
||||||
severity="error"
|
|
||||||
sx={{
|
sx={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '50%',
|
||||||
|
left: '50%',
|
||||||
|
transform: 'translate(-50%, -50%)',
|
||||||
|
width: 500,
|
||||||
|
bgcolor: 'background.paper',
|
||||||
|
borderRadius: 4,
|
||||||
|
boxShadow: 24,
|
||||||
|
p: 4,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
flexDirection: 'column',
|
||||||
marginTop: '20px'
|
alignItems: 'center'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FormattedMessage
|
<div>
|
||||||
id="nohistory"
|
<DateTimePicker
|
||||||
defaultMessage="There is no history of actions"
|
label="Select Action Date"
|
||||||
/>
|
name="timestamp"
|
||||||
<IconButton
|
value={actionDate}
|
||||||
color="inherit"
|
onChange={(newDate) => handleDateChange(newDate.toDate())}
|
||||||
size="small"
|
sx={{
|
||||||
sx={{ marginLeft: '4px' }}
|
width: 450,
|
||||||
></IconButton>
|
marginTop: 2
|
||||||
</Alert>
|
}}
|
||||||
)}
|
/>
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Grid item xs={12} md={12} style={{ marginBottom: '20px' }}>
|
<TextField
|
||||||
{props.errorLoadingS3Data && (
|
label="Description"
|
||||||
<Alert
|
variant="outlined"
|
||||||
severity="error"
|
name="description"
|
||||||
sx={{
|
value={newAction.description}
|
||||||
display: 'flex',
|
onChange={handleChange}
|
||||||
alignItems: 'center',
|
fullWidth
|
||||||
marginTop: '20px'
|
multiline
|
||||||
}}
|
rows={4} // Adding rows prop to make it a multiline field with more space
|
||||||
>
|
sx={{
|
||||||
<FormattedMessage
|
marginBottom: 2,
|
||||||
id="cannotloadloggingdata"
|
marginTop: 2,
|
||||||
defaultMessage="Cannot load logging data"
|
height: 'auto'
|
||||||
/>
|
}} // 'auto' height works better with multiline fields
|
||||||
<IconButton
|
/>
|
||||||
color="inherit"
|
</div>
|
||||||
size="small"
|
|
||||||
sx={{ marginLeft: '4px' }}
|
<div
|
||||||
></IconButton>
|
style={{
|
||||||
</Alert>
|
display: 'flex',
|
||||||
)}
|
alignItems: 'center'
|
||||||
</Grid>
|
}}
|
||||||
</Container>
|
>
|
||||||
|
<Button
|
||||||
|
sx={{
|
||||||
|
textTransform: 'none',
|
||||||
|
bgcolor: '#ffc04d',
|
||||||
|
color: '#111111',
|
||||||
|
'&:hover': { bgcolor: '#f7b34d' }
|
||||||
|
}}
|
||||||
|
onClick={SumbitNewAction}
|
||||||
|
disabled={!areRequiredFieldsFilled()}
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
sx={{
|
||||||
|
marginLeft: 2,
|
||||||
|
textTransform: 'none',
|
||||||
|
bgcolor: '#ffc04d',
|
||||||
|
color: '#111111',
|
||||||
|
'&:hover': { bgcolor: '#f7b34d' }
|
||||||
|
}}
|
||||||
|
onClick={deleteUserModalHandleCancel}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Box>
|
||||||
|
</LocalizationProvider>
|
||||||
|
</Modal>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!openModalAddAction && (
|
||||||
|
<Container maxWidth="xl">
|
||||||
|
<Grid container>
|
||||||
|
<Grid container>
|
||||||
|
<Grid item xs={6} md={6}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
onClick={handleAddActionButton}
|
||||||
|
sx={{
|
||||||
|
marginTop: '20px',
|
||||||
|
backgroundColor: '#ffc04d',
|
||||||
|
color: '#000000',
|
||||||
|
'&:hover': { bgcolor: '#f7b34d' }
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id="add_action"
|
||||||
|
defaultMessage="Add New Action"
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} md={12}>
|
||||||
|
{history.length > 0 && (
|
||||||
|
<Card sx={{ marginTop: '10px' }}>
|
||||||
|
<Divider />
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
height: '40px',
|
||||||
|
marginBottom: '10px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
marginTop: '15px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
color="dimgrey"
|
||||||
|
fontWeight="bold"
|
||||||
|
fontSize="1rem"
|
||||||
|
gutterBottom
|
||||||
|
noWrap
|
||||||
|
>
|
||||||
|
<FormattedMessage id="user" defaultMessage="User" />
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
marginTop: '15px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
color="dimgrey"
|
||||||
|
fontWeight="bold"
|
||||||
|
fontSize="1rem"
|
||||||
|
gutterBottom
|
||||||
|
noWrap
|
||||||
|
>
|
||||||
|
<FormattedMessage id="date" defaultMessage="Date" />
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
marginTop: '15px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
color="dimgrey"
|
||||||
|
fontWeight="bold"
|
||||||
|
fontSize="1rem"
|
||||||
|
gutterBottom
|
||||||
|
noWrap
|
||||||
|
>
|
||||||
|
<FormattedMessage id="time" defaultMessage="Time" />
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 6,
|
||||||
|
marginTop: '15px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
color="dimgrey"
|
||||||
|
fontWeight="bold"
|
||||||
|
fontSize="1rem"
|
||||||
|
gutterBottom
|
||||||
|
noWrap
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id="description"
|
||||||
|
defaultMessage="Description"
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Divider />
|
||||||
|
<div style={{ maxHeight: '400px', overflowY: 'auto' }}>
|
||||||
|
{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 (
|
||||||
|
<React.Fragment key={index}>
|
||||||
|
<Divider />
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
minHeight: '40px',
|
||||||
|
marginBottom: '10px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
marginTop: '15px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
fontWeight="bold"
|
||||||
|
color="text.primary"
|
||||||
|
gutterBottom
|
||||||
|
>
|
||||||
|
{action.userName}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
marginTop: '15px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
fontWeight="bold"
|
||||||
|
color="text.primary"
|
||||||
|
gutterBottom
|
||||||
|
>
|
||||||
|
{datePart}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
marginTop: '15px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
fontWeight="bold"
|
||||||
|
color="text.primary"
|
||||||
|
gutterBottom
|
||||||
|
>
|
||||||
|
{timePart}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 6,
|
||||||
|
display: 'flex',
|
||||||
|
marginTop: '15px',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
fontWeight="bold"
|
||||||
|
color="text.primary"
|
||||||
|
gutterBottom
|
||||||
|
style={{
|
||||||
|
whiteSpace: 'normal',
|
||||||
|
wordBreak: 'break-word'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{action.description}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!props.errorLoadingS3Data && history.length == 0 && (
|
||||||
|
<Alert
|
||||||
|
severity="error"
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginTop: '20px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id="nohistory"
|
||||||
|
defaultMessage="There is no history of actions"
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
color="inherit"
|
||||||
|
size="small"
|
||||||
|
sx={{ marginLeft: '4px' }}
|
||||||
|
></IconButton>
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} md={12} style={{ marginBottom: '20px' }}>
|
||||||
|
{props.errorLoadingS3Data && (
|
||||||
|
<Alert
|
||||||
|
severity="error"
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginTop: '20px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id="cannotloadloggingdata"
|
||||||
|
defaultMessage="Cannot load logging data"
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
color="inherit"
|
||||||
|
size="small"
|
||||||
|
sx={{ marginLeft: '4px' }}
|
||||||
|
></IconButton>
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
</Grid>
|
||||||
|
</Container>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,6 @@ export interface Action {
|
||||||
id: number;
|
id: number;
|
||||||
userName: string;
|
userName: string;
|
||||||
installationId: number;
|
installationId: number;
|
||||||
timestamp: string;
|
timestamp: Date;
|
||||||
description: String;
|
description: string;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue