implement editing maintenance windows
This commit is contained in:
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -405,6 +405,7 @@ const editMaintenanceByIdWindowBodyValidation = joi.object({
|
||||
start: joi.date(),
|
||||
end: joi.date(),
|
||||
expiry: joi.date(),
|
||||
monitors: joi.array(),
|
||||
});
|
||||
|
||||
//****************************************
|
||||
|
||||
Reference in new issue
Block a user