implement editing maintenance windows

This commit is contained in:
Alex Holliday committed 2024-10-09 14:10:38 +08:00
1 parent e3c0944062
commit ad9d735127
8 files changed
+148 -47

No files matched your search

@@ -51,12 +51,14 @@ const Search = ({
filteredBy,
secondaryLabel,
value,
inputValue,
handleInputChange,
handleChange,
sx,
multiple = false,
isAdorned = true,
error,
disabled,
}) => {
const theme = useTheme();
@@ -64,7 +66,8 @@ const Search = ({
<Autocomplete
multiple={multiple}
id={id}
inputValue={value}
value={value}
inputValue={inputValue}
onInputChange={(_, newValue) => {
handleInputChange(newValue);
}}
@@ -73,6 +76,7 @@ const Search = ({
}}
fullWidth
freeSolo
disabled={disabled}
disableClearable
options={options}
getOptionLabel={(option) => option[filteredBy]}
@@ -178,12 +182,14 @@ Search.propTypes = {
options: PropTypes.array.isRequired,
filteredBy: PropTypes.string.isRequired,
secondaryLabel: PropTypes.string,
value: PropTypes.string.isRequired,
value: PropTypes.array,
inputValue: PropTypes.string.isRequired,
handleInputChange: PropTypes.func.isRequired,
handleChange: PropTypes.func,
isAdorned: PropTypes.bool,
sx: PropTypes.object,
error: PropTypes.string,
disabled: PropTypes.bool,
};
export default Search;
@@ -1,4 +1,4 @@
import { Box, Button, Stack, Typography } from "@mui/material";
import { Box, Button, duration, Stack, Typography } from "@mui/material";
import { useSelector } from "react-redux";
import { useTheme } from "@emotion/react";
import { useEffect, useState } from "react";
@@ -9,6 +9,8 @@ import { DatePicker } from "@mui/x-date-pickers/DatePicker";
import { MobileTimePicker } from "@mui/x-date-pickers/MobileTimePicker";
import { maintenanceWindowValidation } from "../../../Validation/validation";
import { createToast } from "../../../Utils/toastUtils";
import LoadingButton from "@mui/lab/LoadingButton";
import dayjs from "dayjs";
import Select from "../../../Components/Inputs/Select";
import Field from "../../../Components/Inputs/Field";
@@ -23,14 +25,40 @@ import {
MS_PER_MINUTE,
MS_PER_HOUR,
MS_PER_DAY,
MS_PER_WEEK,
} from "../../../Utils/timeUtils";
import { useNavigate, useParams } from "react-router-dom";
const getDurationAndUnit = (durationInMs) => {
if (durationInMs % MS_PER_DAY === 0) {
return {
duration: (durationInMs / MS_PER_DAY).toString(),
durationUnit: "days",
};
} else if (durationInMs % MS_PER_HOUR === 0) {
return {
duration: (durationInMs / MS_PER_HOUR).toString(),
durationUnit: "hours",
};
} else if (durationInMs % MS_PER_MINUTE === 0) {
return {
duration: (durationInMs / MS_PER_MINUTE).toString(),
durationUnit: "minutes",
};
} else {
return {
duration: (durationInMs / MS_PER_SECOND).toString(),
durationUnit: "seconds",
};
}
};
const MS_LOOKUP = {
seconds: MS_PER_SECOND,
minutes: MS_PER_MINUTE,
hours: MS_PER_HOUR,
days: MS_PER_DAY,
weeks: MS_PER_WEEK,
};
const REPEAT_LOOKUP = {
@@ -39,6 +67,12 @@ const REPEAT_LOOKUP = {
weekly: MS_PER_DAY * 7,
};
const REVERSE_REPEAT_LOOKUP = {
0: "none",
[MS_PER_DAY]: "daily",
[MS_PER_WEEK]: "weekly",
};
const repeatConfig = [
{ _id: 0, name: "Don't repeat", value: "none" },
{
@@ -104,34 +138,34 @@ const CreateMaintenance = () => {
limit: -1,
types: ["http", "ping", "pagespeed"],
});
setMonitors(response.data.data.monitors);
const monitors = response.data.data.monitors;
setMonitors(monitors);
if (maintenanceWindowId === undefined) {
return;
}
const maintenanceWindow = await networkService.getMaintenanceWindowById(
{
authToken: authToken,
maintenanceWindowId: maintenanceWindowId,
}
);
logger.info(maintenanceWindow);
// const { name, start, end, repeat, monitors } =
// maintenanceWindow.data.data.maintenanceWindow;
// const startDate = dayjs(start);
// const startTime = dayjs(start);
// const duration = dayjs(end).diff(dayjs(start), "seconds");
// const durationUnit = "seconds";
// setForm({
// name,
// startDate,
// startTime,
// duration,
// durationUnit,
// repeat,
// monitors,
// });
const res = await networkService.getMaintenanceWindowById({
authToken: authToken,
maintenanceWindowId: maintenanceWindowId,
});
const maintenanceWindow = res.data.data;
const { name, start, end, repeat, monitorId } = maintenanceWindow;
const startTime = dayjs(start);
const endTime = dayjs(end);
const durationInMs = endTime.diff(startTime, "milliseconds").toString();
const { duration, durationUnit } = getDurationAndUnit(durationInMs);
const monitor = monitors.find((monitor) => monitor._id === monitorId);
setForm({
...form,
name,
repeat: REVERSE_REPEAT_LOOKUP[repeat],
startDate: startTime,
startTime,
duration,
durationUnit,
monitors: monitor ? [monitor] : [],
});
} catch (error) {
createToast({ body: "Failed to fetch data" });
logger.error("Failed to fetch monitors", error);
@@ -201,17 +235,13 @@ const CreateMaintenance = () => {
newErrors[err.path[0]] = err.message;
});
setErrors(newErrors);
console.log(error);
logger.error(error);
return;
}
// Build timestamp for maintenance window from startDate and startTime
const start = dayjs(form.startDate);
start
const start = dayjs(form.startDate)
.set("hour", form.startTime.hour())
.set("minute", form.startTime.minute())
.set("second", form.startTime.second())
.set("millisecond", form.startTime.millisecond());
.set("minute", form.startTime.minute());
// Build end timestamp for maintenance window
const MS_MULTIPLIER = MS_LOOKUP[form.durationUnit];
const durationInMs = form.duration * MS_MULTIPLIER;
@@ -232,18 +262,32 @@ const CreateMaintenance = () => {
submit.expiry = end;
}
try {
await networkService.createMaintenanceWindow({
authToken: authToken,
maintenanceWindow: submit,
});
const requestConfig = { authToken: authToken, maintenanceWindow: submit };
if (maintenanceWindowId !== undefined) {
requestConfig.maintenanceWindowId = maintenanceWindowId;
}
const request =
maintenanceWindowId === undefined
? networkService.createMaintenanceWindow(requestConfig)
: networkService.editMaintenanceWindow(requestConfig);
try {
setIsLoading(true);
await request;
createToast({
body: "Successfully created maintenance window",
});
navigate("/maintenance");
} catch (error) {
console.log(error);
createToast({
body: `Failed to ${
maintenanceWindowId === undefined ? "create" : "edit"
} maintenance window`,
});
logger.error(error);
} finally {
setIsLoading(false);
}
};
@@ -252,7 +296,10 @@ const CreateMaintenance = () => {
<Breadcrumbs
list={[
{ name: "maintenance", path: "/maintenance" },
{ name: "create", path: `/maintenance/create` },
{
name: maintenanceWindowId === undefined ? "create" : "edit",
path: `/maintenance/create`,
},
]}
/>
<Stack
@@ -265,7 +312,7 @@ const CreateMaintenance = () => {
<Box>
<Typography component="h1" variant="h1">
<Typography component="span" fontSize="inherit">
Create a{" "}
{`${maintenanceWindowId === undefined ? "Create a" : "Edit"}`}{" "}
</Typography>
<Typography
component="span"
@@ -481,10 +528,12 @@ const CreateMaintenance = () => {
options={monitors ? monitors : []}
filteredBy="name"
secondaryLabel={"type"}
value={search}
inputValue={search}
value={form.monitors}
handleInputChange={handleSearch}
handleChange={handleSelectMonitors}
error={errors["monitors"]}
disabled={maintenanceWindowId !== undefined}
/>
</Box>
</Stack>
@@ -499,14 +548,19 @@ const CreateMaintenance = () => {
>
Cancel
</Button>
<Button
<LoadingButton
loading={isLoading}
variant="contained"
color="primary"
onClick={handleSubmit}
disabled={false}
>
Create maintenance
</Button>
{`${
maintenanceWindowId === undefined
? "Create maintenance"
: "Edit maintenance"
}`}
</LoadingButton>
</Box>
</Stack>
</Box>
@@ -46,6 +46,10 @@ const ActionsMenu = ({ isAdmin, maintenanceWindow, updateCallback }) => {
setIsOpen(false);
};
const handleEdit = () => {
navigate(`/maintenance/create/${maintenanceWindow._id}`);
};
const openMenu = (event) => {
event.preventDefault();
event.stopPropagation();
@@ -106,7 +110,7 @@ const ActionsMenu = ({ isAdmin, maintenanceWindow, updateCallback }) => {
onClick={(e) => {
closeMenu(e);
e.stopPropagation();
console.log("Edit");
handleEdit();
}}
>
Edit
+27
View File
@@ -717,6 +717,33 @@ class NetworkService {
);
}
/**
* ************************************
* Edits a maintenance window
* ************************************
*
* @async
* @param {Object} config - The configuration object.
* @param {string} config.authToken - The authorization token to be used in the request header.
* @param {Object} config.maintenanceWindowId - The maintenance window id.
* @param {Object} config.maintenanceWindow - The maintenance window object to be sent in the request body.
* @returns {Promise<AxiosResponse>} The response from the axios POST request.
*
*/
async editMaintenanceWindow(config) {
return this.axiosInstance.put(
`/maintenance-window/${config.maintenanceWindowId}`,
config.maintenanceWindow,
{
headers: {
Authorization: `Bearer ${config.authToken}`,
"Content-Type": "application/json",
},
}
);
}
/**
* ************************************
* Get maintenance window by id
+1
View File
@@ -8,6 +8,7 @@ export const MS_PER_SECOND = 1000;
export const MS_PER_MINUTE = 60 * MS_PER_SECOND;
export const MS_PER_HOUR = 60 * MS_PER_MINUTE;
export const MS_PER_DAY = 24 * MS_PER_HOUR;
export const MS_PER_WEEK = MS_PER_DAY * 7;
export const formatDuration = (ms) => {
const seconds = Math.floor(ms / 1000);
@@ -1,5 +1,7 @@
const {
createMaintenanceWindowBodyValidation,
editMaintenanceWindowByIdParamValidation,
editMaintenanceByIdWindowBodyValidation,
getMaintenanceWindowByIdParamValidation,
getMaintenanceWindowsByMonitorIdParamValidation,
getMaintenanceWindowsByTeamIdQueryValidation,
@@ -186,7 +188,7 @@ const editMaintenanceWindow = async (req, res, next) => {
return;
}
try {
await req.db.editMaintenanceWindow(req.params.id, req.body);
await req.db.editMaintenanceWindowById(req.params.id, req.body);
return res.status(201).json({
success: true,
msg: successMessages.MAINTENANCE_WINDOW_EDIT,
@@ -206,6 +206,12 @@ const editMaintenanceWindowById = async (
maintenanceWindowData
) => {
try {
const editedMaintenanceWindow = MaintenanceWindow.findByIdAndUpdate(
maintenanceWindowId,
maintenanceWindowData,
{ new: true }
);
return editedMaintenanceWindow;
} catch (error) {
error.service = SERVICE_NAME;
error.method = "editMaintenanceWindowById";
+1
View File
@@ -405,6 +405,7 @@ const editMaintenanceByIdWindowBodyValidation = joi.object({
start: joi.date(),
end: joi.date(),
expiry: joi.date(),
monitors: joi.array(),
});
//****************************************