Persistent logging (erros and warning)

This commit is contained in:
Noe 2023-11-22 09:35:29 +01:00
parent ac8f874255
commit 1204a28ab5
14 changed files with 757 additions and 204 deletions

View File

@ -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)

View File

@ -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; }
} }

View File

@ -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

View File

@ -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);

View File

@ -1,4 +1,4 @@
{ {
"Key": "EXOea18f5a82bd358896154c783", "Key": "EXO4d838d1360ba9fb7d51648b0",
"Secret": "lYtzU7R5e0L6XKOgBaLVPFr41nEBDxDdXU47zBAEI6M" "Secret": "_bmrp6ewWAvNwdAQoeJuC-9y02Lsx7NV6zD-WjljzCU"
} }

View File

@ -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!;
} }

View File

@ -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
}; };

View File

@ -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!;
} }

View File

@ -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";
} }

View File

@ -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)

View File

@ -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>
)} )}

View File

@ -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}>

View File

@ -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) => {

View File

@ -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;
} }