Add history button
This commit is contained in:
parent
5fdc7de448
commit
48de0805b9
|
@ -564,12 +564,20 @@ public class Controller : ControllerBase
|
|||
return Ok();
|
||||
}
|
||||
|
||||
|
||||
[HttpPost(nameof(EditInstallationConfig))]
|
||||
public async Task<ActionResult<IEnumerable<Object>>> EditInstallationConfig([FromBody] Configuration config, Int64 installationId, Token authToken)
|
||||
[HttpPost(nameof(InsertNewAction))]
|
||||
public async Task<ActionResult<IEnumerable<Object>>> 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<ActionResult<IEnumerable<Object>>> 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();
|
||||
}
|
||||
|
||||
|
|
|
@ -102,22 +102,14 @@ public static class SessionMethods
|
|||
&& 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 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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
@ -113,17 +98,32 @@ public static class RabbitMqManager
|
|||
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"+
|
||||
|
|
|
@ -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<Action[]>([]);
|
||||
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<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(() => {
|
||||
axiosConfig
|
||||
|
@ -43,265 +104,378 @@ function HistoryOfActions(props: HistoryProps) {
|
|||
navigate(routes.login);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
}, [openModalAddAction]);
|
||||
|
||||
return (
|
||||
<Container maxWidth="xl">
|
||||
<Grid container>
|
||||
<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"
|
||||
<>
|
||||
{openModalAddAction && (
|
||||
<Modal
|
||||
open={openModalAddAction}
|
||||
aria-labelledby="error-modal"
|
||||
aria-describedby="error-modal-description"
|
||||
>
|
||||
<LocalizationProvider dateAdapter={AdapterDayjs}>
|
||||
<Box
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
width: 500,
|
||||
bgcolor: 'background.paper',
|
||||
borderRadius: 4,
|
||||
boxShadow: 24,
|
||||
p: 4,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginTop: '20px'
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center'
|
||||
}}
|
||||
>
|
||||
<FormattedMessage
|
||||
id="nohistory"
|
||||
defaultMessage="There is no history of actions"
|
||||
/>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
sx={{ marginLeft: '4px' }}
|
||||
></IconButton>
|
||||
</Alert>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
<div>
|
||||
<DateTimePicker
|
||||
label="Select Action Date"
|
||||
name="timestamp"
|
||||
value={actionDate}
|
||||
onChange={(newDate) => handleDateChange(newDate.toDate())}
|
||||
sx={{
|
||||
width: 450,
|
||||
marginTop: 2
|
||||
}}
|
||||
/>
|
||||
|
||||
<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>
|
||||
<TextField
|
||||
label="Description"
|
||||
variant="outlined"
|
||||
name="description"
|
||||
value={newAction.description}
|
||||
onChange={handleChange}
|
||||
fullWidth
|
||||
multiline
|
||||
rows={4} // Adding rows prop to make it a multiline field with more space
|
||||
sx={{
|
||||
marginBottom: 2,
|
||||
marginTop: 2,
|
||||
height: 'auto'
|
||||
}} // 'auto' height works better with multiline fields
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center'
|
||||
}}
|
||||
>
|
||||
<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;
|
||||
userName: string;
|
||||
installationId: number;
|
||||
timestamp: string;
|
||||
description: String;
|
||||
timestamp: Date;
|
||||
description: string;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue