Persistent logging (erros and warning)
This commit is contained in:
parent
ac8f874255
commit
1204a28ab5
|
@ -446,6 +446,41 @@ public class Controller : ControllerBase
|
||||||
return installation.FillOrderNumbers().HideParentIfUserHasNoAccessToParent(session!.User).HideWriteKeyIfUserIsNotAdmin(session.User.HasWriteAccess);
|
return installation.FillOrderNumbers().HideParentIfUserHasNoAccessToParent(session!.User).HideWriteKeyIfUserIsNotAdmin(session.User.HasWriteAccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost(nameof(AcknowledgeError))]
|
||||||
|
public ActionResult AcknowledgeError(Int64 id, Token authToken)
|
||||||
|
{
|
||||||
|
var session = Db.GetSession(authToken);
|
||||||
|
|
||||||
|
if (session == null)
|
||||||
|
return Unauthorized();
|
||||||
|
|
||||||
|
var error=Db.Errors
|
||||||
|
.FirstOrDefault(error => error.Id == id);
|
||||||
|
|
||||||
|
error.Seen = true;
|
||||||
|
|
||||||
|
return Db.Update(error)
|
||||||
|
? Ok()
|
||||||
|
: Unauthorized();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost(nameof(AcknowledgeWarning))]
|
||||||
|
public ActionResult AcknowledgeWarning(Int64 id, Token authToken)
|
||||||
|
{
|
||||||
|
var session = Db.GetSession(authToken);
|
||||||
|
|
||||||
|
if (session == null)
|
||||||
|
return Unauthorized();
|
||||||
|
|
||||||
|
var warning=Db.Warnings
|
||||||
|
.FirstOrDefault(warning => warning.Id == id);
|
||||||
|
|
||||||
|
warning.Seen = true;
|
||||||
|
|
||||||
|
return Db.Update(warning)
|
||||||
|
? Ok()
|
||||||
|
: Unauthorized();
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPut(nameof(UpdateFolder))]
|
[HttpPut(nameof(UpdateFolder))]
|
||||||
public ActionResult<Folder> UpdateFolder([FromBody] Folder folder, Token authToken)
|
public ActionResult<Folder> UpdateFolder([FromBody] Folder folder, Token authToken)
|
||||||
|
|
|
@ -8,8 +8,9 @@ public abstract class LogEntry
|
||||||
public Int64 Id { get; set; }
|
public Int64 Id { get; set; }
|
||||||
public Int64 InstallationId { get; set; }
|
public Int64 InstallationId { get; set; }
|
||||||
public String Description { get; set; } = null!;
|
public String Description { get; set; } = null!;
|
||||||
public DateTime CreatedAt { get; set; }
|
public String Date { get; set; } = null!;
|
||||||
public String DeviceCreatedTheMessage { get; set; } = null!;
|
public String Time { get; set; } = null!;
|
||||||
|
public String DeviceCreatedTheMessage{ get; set; } = null!;
|
||||||
public Boolean Seen { get; set; }
|
public Boolean Seen { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,7 @@ public static partial class Db
|
||||||
{
|
{
|
||||||
var oldestError =
|
var oldestError =
|
||||||
Errors.Where(error => error.InstallationId == installationId)
|
Errors.Where(error => error.InstallationId == installationId)
|
||||||
.OrderBy(error => error.CreatedAt)
|
.OrderBy(error => error.Date)
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
//Remove the old error
|
//Remove the old error
|
||||||
|
@ -96,7 +96,7 @@ public static partial class Db
|
||||||
{
|
{
|
||||||
var oldestWarning =
|
var oldestWarning =
|
||||||
Warnings.Where(warning => warning.InstallationId == installationId)
|
Warnings.Where(warning => warning.InstallationId == installationId)
|
||||||
.OrderBy(warning => warning.CreatedAt)
|
.OrderBy(warning => warning.Date)
|
||||||
.FirstOrDefault();
|
.FirstOrDefault();
|
||||||
|
|
||||||
//Remove the old error
|
//Remove the old error
|
||||||
|
|
|
@ -17,6 +17,17 @@ public static partial class Db
|
||||||
return Update(obj: folder);
|
return Update(obj: folder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Boolean Update(Error error)
|
||||||
|
{
|
||||||
|
return Update(obj: error);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Boolean Update(Warning warning)
|
||||||
|
{
|
||||||
|
return Update(obj: warning);
|
||||||
|
}
|
||||||
|
|
||||||
public static Boolean Update(Installation installation)
|
public static Boolean Update(Installation installation)
|
||||||
{
|
{
|
||||||
return Update(obj: installation);
|
return Update(obj: installation);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"Key": "EXOea18f5a82bd358896154c783",
|
"Key": "EXO4d838d1360ba9fb7d51648b0",
|
||||||
"Secret": "lYtzU7R5e0L6XKOgBaLVPFr41nEBDxDdXU47zBAEI6M"
|
"Secret": "_bmrp6ewWAvNwdAQoeJuC-9y02Lsx7NV6zD-WjljzCU"
|
||||||
}
|
}
|
|
@ -3,7 +3,8 @@ public class StatusMessage
|
||||||
{
|
{
|
||||||
public required int InstallationId { get; init; }
|
public required int InstallationId { get; init; }
|
||||||
public required int Status { get; init; }
|
public required int Status { get; init; }
|
||||||
public DateTime CreatedAt { get; set; }
|
public String Date { get; set; } = null!;
|
||||||
|
public String Time { get; set; } = null!;
|
||||||
public String Description { get; init; } = null!;
|
public String Description { get; init; } = null!;
|
||||||
public String CreatedBy { get; init; } = null!;
|
public String CreatedBy { get; init; } = null!;
|
||||||
}
|
}
|
|
@ -100,7 +100,8 @@ public static class WebsocketManager
|
||||||
{
|
{
|
||||||
InstallationId = receivedStatusMessage.InstallationId,
|
InstallationId = receivedStatusMessage.InstallationId,
|
||||||
Description = receivedStatusMessage.Description,
|
Description = receivedStatusMessage.Description,
|
||||||
CreatedAt = receivedStatusMessage.CreatedAt,
|
Date = receivedStatusMessage.Date,
|
||||||
|
Time = receivedStatusMessage.Time,
|
||||||
DeviceCreatedTheMessage = receivedStatusMessage.CreatedBy,
|
DeviceCreatedTheMessage = receivedStatusMessage.CreatedBy,
|
||||||
Seen = false
|
Seen = false
|
||||||
};
|
};
|
||||||
|
@ -115,7 +116,8 @@ public static class WebsocketManager
|
||||||
{
|
{
|
||||||
InstallationId = receivedStatusMessage.InstallationId,
|
InstallationId = receivedStatusMessage.InstallationId,
|
||||||
Description = receivedStatusMessage.Description,
|
Description = receivedStatusMessage.Description,
|
||||||
CreatedAt = receivedStatusMessage.CreatedAt,
|
Date = receivedStatusMessage.Date,
|
||||||
|
Time = receivedStatusMessage.Time,
|
||||||
DeviceCreatedTheMessage = receivedStatusMessage.CreatedBy,
|
DeviceCreatedTheMessage = receivedStatusMessage.CreatedBy,
|
||||||
Seen = false
|
Seen = false
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,7 +6,8 @@ public class StatusMessage
|
||||||
|
|
||||||
public required int InstallationId { get; set; }
|
public required int InstallationId { get; set; }
|
||||||
public required int Status { get; set; }
|
public required int Status { get; set; }
|
||||||
public DateTime CreatedAt { get; set; }
|
public String Date { get; set; } = null!;
|
||||||
|
public String Time { get; set; } = null!;
|
||||||
public String Description { get; set; } = null!;
|
public String Description { get; set; } = null!;
|
||||||
public String CreatedBy { get; set; } = null!;
|
public String CreatedBy { get; set; } = null!;
|
||||||
}
|
}
|
|
@ -356,13 +356,15 @@ internal static class Program
|
||||||
|
|
||||||
if (status == 2)
|
if (status == 2)
|
||||||
{
|
{
|
||||||
jsonObject.CreatedAt = DateTime.Now;
|
jsonObject.Date = DateTime.Now.ToString("yyyy-MM-dd");
|
||||||
jsonObject.Description = "Battery Temperature High";
|
jsonObject.Time = DateTime.Now.ToString("HH:mm:ss");
|
||||||
jsonObject.CreatedBy = "Battery/1";
|
jsonObject.Description = "Battery Overvoltage";
|
||||||
|
jsonObject.CreatedBy = "Battery/4";
|
||||||
}
|
}
|
||||||
else if (status == 1)
|
else if (status == 1)
|
||||||
{
|
{
|
||||||
jsonObject.CreatedAt = DateTime.Now;
|
jsonObject.Date = DateTime.Now.ToString("yyyy-MM-dd");
|
||||||
|
jsonObject.Time = DateTime.Now.ToString("HH:mm:ss");
|
||||||
jsonObject.Description = "Temp warning message";
|
jsonObject.Description = "Temp warning message";
|
||||||
jsonObject.CreatedBy = "Battery/4";
|
jsonObject.CreatedBy = "Battery/4";
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,16 @@ public static class TaskUtils
|
||||||
return await task; // await the task to bubble up any errors etc
|
return await task; // await the task to bubble up any errors etc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void SupressAwaitWarning(this Task task)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void SupressAwaitWarning<T>(this Task<T> task)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static Task WhenAny(this IEnumerable<Task> tasks)
|
public static Task WhenAny(this IEnumerable<Task> tasks)
|
||||||
|
|
|
@ -6,12 +6,6 @@ import {
|
||||||
Divider,
|
Divider,
|
||||||
Grid,
|
Grid,
|
||||||
IconButton,
|
IconButton,
|
||||||
Table,
|
|
||||||
TableBody,
|
|
||||||
TableCell,
|
|
||||||
TableContainer,
|
|
||||||
TableHead,
|
|
||||||
TableRow,
|
|
||||||
useTheme
|
useTheme
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
|
@ -25,6 +19,8 @@ import { useNavigate } from 'react-router-dom';
|
||||||
import { TokenContext } from '../../../contexts/tokenContext';
|
import { TokenContext } from '../../../contexts/tokenContext';
|
||||||
import { ErrorMessage } from '../../../interfaces/S3Types';
|
import { ErrorMessage } from '../../../interfaces/S3Types';
|
||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
|
import FormControlLabel from '@mui/material/FormControlLabel';
|
||||||
|
import Checkbox from '@mui/material/Checkbox';
|
||||||
|
|
||||||
interface LogProps {
|
interface LogProps {
|
||||||
errorLoadingS3Data: boolean;
|
errorLoadingS3Data: boolean;
|
||||||
|
@ -37,7 +33,7 @@ function Log(props: LogProps) {
|
||||||
const [errors, setErrors] = useState<ErrorMessage[]>([]);
|
const [errors, setErrors] = useState<ErrorMessage[]>([]);
|
||||||
const [errorButtonPressed, setErrorButtonPressed] = useState(false);
|
const [errorButtonPressed, setErrorButtonPressed] = useState(false);
|
||||||
const [warningButtonPressed, setWarningButtonPressed] = useState(false);
|
const [warningButtonPressed, setWarningButtonPressed] = useState(false);
|
||||||
|
const [updateCount, setUpdateCount] = useState(0);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const tokencontext = useContext(TokenContext);
|
const tokencontext = useContext(TokenContext);
|
||||||
const { removeToken } = tokencontext;
|
const { removeToken } = tokencontext;
|
||||||
|
@ -66,7 +62,7 @@ function Log(props: LogProps) {
|
||||||
navigate(routes.login);
|
navigate(routes.login);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, []);
|
}, [updateCount]);
|
||||||
|
|
||||||
const handleErrorButtonPressed = () => {
|
const handleErrorButtonPressed = () => {
|
||||||
setErrorButtonPressed(!errorButtonPressed);
|
setErrorButtonPressed(!errorButtonPressed);
|
||||||
|
@ -76,6 +72,34 @@ function Log(props: LogProps) {
|
||||||
setWarningButtonPressed(!warningButtonPressed);
|
setWarningButtonPressed(!warningButtonPressed);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleErrorAcknowledgeButtonPressed = (errorId: number) => {
|
||||||
|
axiosConfig
|
||||||
|
.post(`/AcknowledgeError?id=${errorId}`)
|
||||||
|
.then((res: AxiosResponse<ErrorMessage[]>) => {
|
||||||
|
setUpdateCount(updateCount + 1);
|
||||||
|
})
|
||||||
|
.catch((err: AxiosError) => {
|
||||||
|
if (err.response && err.response.status == 401) {
|
||||||
|
removeToken();
|
||||||
|
navigate(routes.login);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleWarningAcknowledgeButtonPressed = (warningId: number) => {
|
||||||
|
axiosConfig
|
||||||
|
.post(`/AcknowledgeWarning?id=${warningId}`)
|
||||||
|
.then((res: AxiosResponse<ErrorMessage[]>) => {
|
||||||
|
setUpdateCount(updateCount + 1);
|
||||||
|
})
|
||||||
|
.catch((err: AxiosError) => {
|
||||||
|
if (err.response && err.response.status == 401) {
|
||||||
|
removeToken();
|
||||||
|
navigate(routes.login);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="xl">
|
<Container maxWidth="xl">
|
||||||
<Grid container>
|
<Grid container>
|
||||||
|
@ -91,97 +115,278 @@ function Log(props: LogProps) {
|
||||||
{errorButtonPressed && errors.length > 0 && (
|
{errorButtonPressed && errors.length > 0 && (
|
||||||
<Card sx={{ marginTop: '10px' }}>
|
<Card sx={{ marginTop: '10px' }}>
|
||||||
<Divider />
|
<Divider />
|
||||||
<TableContainer>
|
<div>
|
||||||
<Table>
|
<div
|
||||||
<TableHead>
|
style={{
|
||||||
<TableRow>
|
height: '40px',
|
||||||
<TableCell>
|
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="type" defaultMessage="Type" />
|
<FormattedMessage id="type" defaultMessage="Type" />
|
||||||
</TableCell>
|
</Typography>
|
||||||
<TableCell>
|
</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
|
<FormattedMessage
|
||||||
id="description"
|
id="description"
|
||||||
defaultMessage="Description"
|
defaultMessage="Description"
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</Typography>
|
||||||
<TableCell>
|
</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="device" defaultMessage="Device" />
|
<FormattedMessage id="device" defaultMessage="Device" />
|
||||||
</TableCell>
|
</Typography>
|
||||||
<TableCell>
|
</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" />
|
<FormattedMessage id="date" defaultMessage="Date" />
|
||||||
</TableCell>
|
</Typography>
|
||||||
<TableCell>
|
</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: 1,
|
||||||
|
marginTop: '15px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
color="dimgrey"
|
||||||
|
fontWeight="bold"
|
||||||
|
fontSize="1rem"
|
||||||
|
gutterBottom
|
||||||
|
noWrap
|
||||||
|
>
|
||||||
<FormattedMessage id="seen" defaultMessage="Seen" />
|
<FormattedMessage id="seen" defaultMessage="Seen" />
|
||||||
</TableCell>
|
</Typography>
|
||||||
</TableRow>
|
</div>
|
||||||
</TableHead>
|
</div>
|
||||||
<TableBody>
|
<Divider />
|
||||||
|
<div style={{ maxHeight: '400px', overflowY: 'auto' }}>
|
||||||
{errors.map((error, index) => (
|
{errors.map((error, index) => (
|
||||||
<TableRow hover key={index}>
|
<>
|
||||||
<TableCell>
|
<Divider />
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
style={{
|
||||||
|
height: '40px',
|
||||||
|
marginBottom: '10px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
marginTop: '10px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ErrorIcon
|
<ErrorIcon
|
||||||
sx={{
|
sx={{
|
||||||
color: 'red',
|
color: 'red',
|
||||||
width: 25,
|
width: 25,
|
||||||
height: 25,
|
height: 25
|
||||||
marginLeft: '5px',
|
|
||||||
marginTop: '8px'
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</div>
|
||||||
<TableCell>
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
marginTop: '15px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Typography
|
<Typography
|
||||||
variant="body1"
|
variant="body1"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
color="text.primary"
|
color="text.primary"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
noWrap
|
noWrap
|
||||||
sx={{ marginTop: '5px', verticalAlign: 'middle' }}
|
|
||||||
>
|
>
|
||||||
{error.description}
|
{error.description}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</div>
|
||||||
<TableCell>
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
marginTop: '15px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Typography
|
<Typography
|
||||||
variant="body1"
|
variant="body1"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
color="text.primary"
|
color="text.primary"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
noWrap
|
noWrap
|
||||||
sx={{ marginTop: '5px', verticalAlign: 'middle' }}
|
|
||||||
>
|
>
|
||||||
{error.deviceCreatedTheMessage}
|
{error.deviceCreatedTheMessage}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</div>
|
||||||
<TableCell>
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
marginTop: '15px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Typography
|
<Typography
|
||||||
variant="body1"
|
variant="body1"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
color="text.primary"
|
color="text.primary"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
noWrap
|
noWrap
|
||||||
sx={{ marginTop: '5px', verticalAlign: 'middle' }}
|
|
||||||
>
|
>
|
||||||
{error.createdAt}
|
{error.date}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</div>
|
||||||
<TableCell>
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
marginTop: '15px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Typography
|
<Typography
|
||||||
variant="body1"
|
variant="body1"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
color="text.primary"
|
color="text.primary"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
noWrap
|
noWrap
|
||||||
sx={{ marginTop: '5px', verticalAlign: 'middle' }}
|
|
||||||
>
|
>
|
||||||
{error.seen == false ? 'No' : 'Yes'}
|
{error.time}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</div>
|
||||||
</TableRow>
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={error.seen}
|
||||||
|
onChange={() =>
|
||||||
|
error.seen === false &&
|
||||||
|
handleErrorAcknowledgeButtonPressed(error.id)
|
||||||
|
}
|
||||||
|
sx={{
|
||||||
|
marginLeft: '25px'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label=""
|
||||||
|
sx={{ marginTop: 1 }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
))}
|
))}
|
||||||
</TableBody>
|
</div>
|
||||||
</Table>
|
</div>
|
||||||
</TableContainer>
|
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -224,99 +429,280 @@ function Log(props: LogProps) {
|
||||||
{warningButtonPressed && warnings.length > 0 && (
|
{warningButtonPressed && warnings.length > 0 && (
|
||||||
<Card sx={{ marginTop: '10px' }}>
|
<Card sx={{ marginTop: '10px' }}>
|
||||||
<Divider />
|
<Divider />
|
||||||
<TableContainer>
|
<div>
|
||||||
<Table>
|
<div
|
||||||
<TableHead>
|
style={{
|
||||||
<TableRow>
|
height: '40px',
|
||||||
<TableCell>
|
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="type" defaultMessage="Type" />
|
<FormattedMessage id="type" defaultMessage="Type" />
|
||||||
</TableCell>
|
</Typography>
|
||||||
<TableCell>
|
</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
|
<FormattedMessage
|
||||||
id="description"
|
id="description"
|
||||||
defaultMessage="Description"
|
defaultMessage="Description"
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</Typography>
|
||||||
<TableCell>
|
</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="device" defaultMessage="Device" />
|
<FormattedMessage id="device" defaultMessage="Device" />
|
||||||
</TableCell>
|
</Typography>
|
||||||
<TableCell>
|
</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" />
|
<FormattedMessage id="date" defaultMessage="Date" />
|
||||||
</TableCell>
|
</Typography>
|
||||||
<TableCell>
|
</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: 1,
|
||||||
|
marginTop: '15px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
color="dimgrey"
|
||||||
|
fontWeight="bold"
|
||||||
|
fontSize="1rem"
|
||||||
|
gutterBottom
|
||||||
|
noWrap
|
||||||
|
>
|
||||||
<FormattedMessage id="seen" defaultMessage="Seen" />
|
<FormattedMessage id="seen" defaultMessage="Seen" />
|
||||||
</TableCell>
|
</Typography>
|
||||||
</TableRow>
|
</div>
|
||||||
</TableHead>
|
</div>
|
||||||
<TableBody>
|
<Divider />
|
||||||
{warnings.map((warning, index) => {
|
<div style={{ maxHeight: '400px', overflowY: 'auto' }}>
|
||||||
return (
|
{warnings.map((warning, index) => (
|
||||||
<TableRow hover key={index}>
|
<>
|
||||||
<TableCell>
|
<Divider />
|
||||||
|
<div
|
||||||
|
key={index}
|
||||||
|
style={{
|
||||||
|
height: '40px',
|
||||||
|
marginBottom: '10px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
marginTop: '10px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<WarningIcon
|
<WarningIcon
|
||||||
sx={{
|
sx={{
|
||||||
color: 'orange',
|
color: 'orange',
|
||||||
width: 25,
|
width: 25,
|
||||||
height: 25,
|
height: 25
|
||||||
marginLeft: '5px',
|
|
||||||
marginTop: '8px'
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</div>
|
||||||
<TableCell>
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
marginTop: '15px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Typography
|
<Typography
|
||||||
variant="body1"
|
variant="body1"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
color="text.primary"
|
color="text.primary"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
noWrap
|
noWrap
|
||||||
sx={{ marginTop: '5px', verticalAlign: 'middle' }}
|
|
||||||
>
|
>
|
||||||
{warning.description}
|
{warning.description}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</div>
|
||||||
<TableCell>
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
marginTop: '15px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Typography
|
<Typography
|
||||||
variant="body1"
|
variant="body1"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
color="text.primary"
|
color="text.primary"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
noWrap
|
noWrap
|
||||||
sx={{ marginTop: '5px' }}
|
|
||||||
>
|
>
|
||||||
{warning.deviceCreatedTheMessage}
|
{warning.deviceCreatedTheMessage}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</div>
|
||||||
<TableCell>
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
marginTop: '15px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Typography
|
<Typography
|
||||||
variant="body1"
|
variant="body1"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
color="text.primary"
|
color="text.primary"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
noWrap
|
noWrap
|
||||||
sx={{ marginTop: '5px', verticalAlign: 'middle' }}
|
|
||||||
>
|
>
|
||||||
{warning.createdAt}
|
{warning.date}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</div>
|
||||||
<TableCell>
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
marginTop: '15px',
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Typography
|
<Typography
|
||||||
variant="body1"
|
variant="body1"
|
||||||
fontWeight="bold"
|
fontWeight="bold"
|
||||||
color="text.primary"
|
color="text.primary"
|
||||||
gutterBottom
|
gutterBottom
|
||||||
noWrap
|
noWrap
|
||||||
sx={{ marginTop: '5px', verticalAlign: 'middle' }}
|
|
||||||
>
|
>
|
||||||
{warning.seen == false ? 'No' : 'Yes'}
|
{warning.time}
|
||||||
</Typography>
|
</Typography>
|
||||||
</TableCell>
|
</div>
|
||||||
</TableRow>
|
<div
|
||||||
);
|
style={{
|
||||||
})}
|
flex: 1,
|
||||||
</TableBody>
|
display: 'flex',
|
||||||
</Table>
|
alignItems: 'center',
|
||||||
</TableContainer>
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormControlLabel
|
||||||
|
control={
|
||||||
|
<Checkbox
|
||||||
|
checked={warning.seen}
|
||||||
|
onChange={() =>
|
||||||
|
warning.seen === false &&
|
||||||
|
handleWarningAcknowledgeButtonPressed(
|
||||||
|
warning.id
|
||||||
|
)
|
||||||
|
}
|
||||||
|
sx={{
|
||||||
|
marginLeft: '25px'
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label=""
|
||||||
|
sx={{ marginTop: 1 }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import React, { useContext, useEffect, useState } from 'react';
|
import React, { useContext, useEffect, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
|
Alert,
|
||||||
FormControl,
|
FormControl,
|
||||||
Grid,
|
Grid,
|
||||||
|
IconButton,
|
||||||
InputAdornment,
|
InputAdornment,
|
||||||
TextField,
|
TextField,
|
||||||
useTheme
|
useTheme
|
||||||
|
@ -13,6 +15,7 @@ import Button from '@mui/material/Button';
|
||||||
import UserForm from './userForm';
|
import UserForm from './userForm';
|
||||||
import { UserContext } from '../../../contexts/userContext';
|
import { UserContext } from '../../../contexts/userContext';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
import { Close as CloseIcon } from '@mui/icons-material';
|
||||||
|
|
||||||
function UsersSearch() {
|
function UsersSearch() {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
@ -21,6 +24,8 @@ function UsersSearch() {
|
||||||
const [filteredData, setFilteredData] = useState(availableUsers);
|
const [filteredData, setFilteredData] = useState(availableUsers);
|
||||||
const [openModal, setOpenModal] = useState(false);
|
const [openModal, setOpenModal] = useState(false);
|
||||||
const context = useContext(UserContext);
|
const context = useContext(UserContext);
|
||||||
|
const [userCreated, setUserCreated] = useState(false);
|
||||||
|
const [errorOccured, setErrorOccured] = useState(false);
|
||||||
const { currentUser, setUser } = context;
|
const { currentUser, setUser } = context;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -43,13 +48,27 @@ function UsersSearch() {
|
||||||
};
|
};
|
||||||
const handleUserFormSubmit = () => {
|
const handleUserFormSubmit = () => {
|
||||||
setOpenModal(false);
|
setOpenModal(false);
|
||||||
|
setUserCreated(true);
|
||||||
|
|
||||||
fetchAvailableUsers();
|
fetchAvailableUsers();
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
setUserCreated(false);
|
||||||
|
}, 8000);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUserFormCancel = () => {
|
const handleUserFormCancel = () => {
|
||||||
setOpenModal(false);
|
setOpenModal(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleUserError = () => {
|
||||||
|
setOpenModal(false);
|
||||||
|
setErrorOccured(true);
|
||||||
|
setTimeout(() => {
|
||||||
|
setErrorOccured(false);
|
||||||
|
}, 3000);
|
||||||
|
};
|
||||||
|
|
||||||
const isMobile = window.innerWidth <= 1490;
|
const isMobile = window.innerWidth <= 1490;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -63,8 +82,67 @@ function UsersSearch() {
|
||||||
)}
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
{userCreated && (
|
||||||
|
<Grid container spacing={1}>
|
||||||
|
<Grid item xs={12} md={3}>
|
||||||
|
<Alert
|
||||||
|
severity="success"
|
||||||
|
sx={{
|
||||||
|
mt: 1,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id="successfullyCreatedUser"
|
||||||
|
defaultMessage="Successfully Updated User"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<IconButton
|
||||||
|
color="inherit"
|
||||||
|
size="small"
|
||||||
|
onClick={() => setUserCreated(false)}
|
||||||
|
sx={{ marginLeft: '4px' }}
|
||||||
|
>
|
||||||
|
<CloseIcon fontSize="small" />
|
||||||
|
</IconButton>
|
||||||
|
</Alert>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
|
{errorOccured && (
|
||||||
|
<Grid container spacing={1}>
|
||||||
|
<Grid item xs={12} md={3}>
|
||||||
|
<Alert
|
||||||
|
severity="error"
|
||||||
|
sx={{
|
||||||
|
mt: 1,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormattedMessage
|
||||||
|
id="errorOccured"
|
||||||
|
defaultMessage="An error has occurred"
|
||||||
|
/>
|
||||||
|
<IconButton
|
||||||
|
color="inherit"
|
||||||
|
size="small"
|
||||||
|
onClick={() => setErrorOccured(false)}
|
||||||
|
sx={{ marginLeft: '4px' }}
|
||||||
|
>
|
||||||
|
<CloseIcon fontSize="small" />
|
||||||
|
</IconButton>
|
||||||
|
</Alert>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
)}
|
||||||
{openModal && (
|
{openModal && (
|
||||||
<UserForm cancel={handleUserFormCancel} submit={handleUserFormSubmit} />
|
<UserForm
|
||||||
|
cancel={handleUserFormCancel}
|
||||||
|
submit={handleUserFormSubmit}
|
||||||
|
error={handleUserError}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
<Grid container spacing={1} sx={{ marginTop: '1px' }}>
|
<Grid container spacing={1} sx={{ marginTop: '1px' }}>
|
||||||
<Grid item xs={12} md={isMobile ? 5 : 3}>
|
<Grid item xs={12} md={isMobile ? 5 : 3}>
|
||||||
|
|
|
@ -25,6 +25,7 @@ import { FormattedMessage } from 'react-intl';
|
||||||
interface userFormProps {
|
interface userFormProps {
|
||||||
cancel: () => void;
|
cancel: () => void;
|
||||||
submit: () => void;
|
submit: () => void;
|
||||||
|
error: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function userForm(props: userFormProps) {
|
function userForm(props: userFormProps) {
|
||||||
|
@ -106,19 +107,34 @@ function userForm(props: userFormProps) {
|
||||||
const isMobile = window.innerWidth <= 1490;
|
const isMobile = window.innerWidth <= 1490;
|
||||||
|
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
const res = await axiosConfig.post('/CreateUser', {
|
const res = await axiosConfig
|
||||||
|
.post('/CreateUser', {
|
||||||
...formValues,
|
...formValues,
|
||||||
password: '',
|
password: '',
|
||||||
language: 'english'
|
language: 'english'
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
setLoading(false);
|
||||||
|
if (err.response) {
|
||||||
|
props.error();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (res) {
|
||||||
try {
|
try {
|
||||||
for (const folderName of selectedFolderNames) {
|
for (const folderName of selectedFolderNames) {
|
||||||
const folder = folders.find((folder) => folder.name === folderName);
|
const folder = folders.find((folder) => folder.name === folderName);
|
||||||
|
|
||||||
await axiosConfig.post(
|
await axiosConfig
|
||||||
|
.post(
|
||||||
`/GrantUserAccessToFolder?UserId=${res.data.id}&FolderId=${folder.id}`
|
`/GrantUserAccessToFolder?UserId=${res.data.id}&FolderId=${folder.id}`
|
||||||
);
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
setLoading(false);
|
||||||
|
if (err.response) {
|
||||||
|
props.error();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const installationName of selectedInstallationNames) {
|
for (const installationName of selectedInstallationNames) {
|
||||||
|
@ -126,9 +142,16 @@ function userForm(props: userFormProps) {
|
||||||
(installation) => installation.name === installationName
|
(installation) => installation.name === installationName
|
||||||
);
|
);
|
||||||
|
|
||||||
await axiosConfig.post(
|
await axiosConfig
|
||||||
|
.post(
|
||||||
`/GrantUserAccessToInstallation?UserId=${res.data.id}&InstallationId=${installation.id}`
|
`/GrantUserAccessToInstallation?UserId=${res.data.id}&InstallationId=${installation.id}`
|
||||||
);
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
setLoading(false);
|
||||||
|
if (err.response) {
|
||||||
|
props.error();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
@ -145,6 +168,7 @@ function userForm(props: userFormProps) {
|
||||||
}, 2000);
|
}, 2000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancelSubmit = (e) => {
|
const handleCancelSubmit = (e) => {
|
||||||
|
|
|
@ -7,9 +7,11 @@ export interface I_S3Credentials {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ErrorMessage {
|
export interface ErrorMessage {
|
||||||
|
id: number;
|
||||||
installationId: number;
|
installationId: number;
|
||||||
description: string;
|
description: string;
|
||||||
createdAt: Date;
|
date: string;
|
||||||
|
time: string;
|
||||||
deviceCreatedTheMessage: string;
|
deviceCreatedTheMessage: string;
|
||||||
seen: boolean;
|
seen: boolean;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue