diff --git a/Client/src/Features/UI/uiSlice.js b/Client/src/Features/UI/uiSlice.js index 2b6a08e8d..a70c31041 100644 --- a/Client/src/Features/UI/uiSlice.js +++ b/Client/src/Features/UI/uiSlice.js @@ -9,6 +9,9 @@ const initialState = { team: { rowsPerPage: 5, }, + maintenance: { + rowsPerPage: 5, + }, sidebar: { collapsed: false, }, diff --git a/Client/src/Pages/Maintenance/CreateMaintenance/index.jsx b/Client/src/Pages/Maintenance/CreateMaintenance/index.jsx index 057df1c74..48b1cbc07 100644 --- a/Client/src/Pages/Maintenance/CreateMaintenance/index.jsx +++ b/Client/src/Pages/Maintenance/CreateMaintenance/index.jsx @@ -190,6 +190,7 @@ const CreateMaintenance = () => { repeat, }; + console.log(submit); if (repeat === 0) { submit.expiry = end; } diff --git a/Client/src/Pages/Maintenance/MaintenanceTable/ActionsMenu/index.jsx b/Client/src/Pages/Maintenance/MaintenanceTable/ActionsMenu/index.jsx new file mode 100644 index 000000000..22f864c51 --- /dev/null +++ b/Client/src/Pages/Maintenance/MaintenanceTable/ActionsMenu/index.jsx @@ -0,0 +1,182 @@ +import { useState } from "react"; +import { useTheme } from "@emotion/react"; +import { useNavigate } from "react-router-dom"; +import { + Button, + IconButton, + Menu, + MenuItem, + Modal, + Stack, + Typography, +} from "@mui/material"; +import Settings from "../../../../assets/icons/settings-bold.svg?react"; +import PropTypes from "prop-types"; + +const ActionsMenu = ({ isAdmin, maintenanceWindow }) => { + const [anchorEl, setAnchorEl] = useState(null); + const [isOpen, setIsOpen] = useState(false); + const theme = useTheme(); + + const handleRemove = async (event) => { + event.preventDefault(); + event.stopPropagation(); + console.log("remove"); + setIsOpen(false); // close modal + }; + + const openMenu = (event) => { + event.preventDefault(); + event.stopPropagation(); + setAnchorEl(event.currentTarget); + }; + + const openRemove = (e) => { + closeMenu(e); + setIsOpen(true); + }; + + const closeMenu = (e) => { + e.stopPropagation(); + setAnchorEl(null); + }; + + const navigate = useNavigate(); + + return ( + <> + { + event.stopPropagation(); + openMenu(event); + }} + sx={{ + "&:focus": { + outline: "none", + }, + "& svg path": { + stroke: theme.palette.other.icon, + }, + }} + > + + + + closeMenu(e)} + disableScrollLock + slotProps={{ + paper: { + sx: { + "& ul": { p: theme.spacing(2.5) }, + "& li": { m: 0 }, + "& li:last-of-type": { + color: theme.palette.error.text, + }, + }, + }, + }} + > + { + closeMenu(e); + e.stopPropagation(); + console.log("Edit"); + }} + > + Edit + + { + closeMenu(e); + e.stopPropagation(); + console.log("Pause"); + }} + > + Pause + + + { + e.stopPropagation(); + openRemove(e); + }} + > + Remove + + + { + e.stopPropagation(); + setIsOpen(false); + }} + > + + + Do you really want to remove this maintenance window? + + + + + + + + + ); +}; + +ActionsMenu.propTypes = { + maintenanceWindow: PropTypes.object, + isAdmin: PropTypes.bool, + updateCallback: PropTypes.func, +}; + +export default ActionsMenu; diff --git a/Client/src/Pages/Maintenance/MaintenanceTable/index.jsx b/Client/src/Pages/Maintenance/MaintenanceTable/index.jsx index 29c651add..6cccfa06a 100644 --- a/Client/src/Pages/Maintenance/MaintenanceTable/index.jsx +++ b/Client/src/Pages/Maintenance/MaintenanceTable/index.jsx @@ -15,16 +15,18 @@ import { } from "@mui/material"; import ArrowDownwardRoundedIcon from "@mui/icons-material/ArrowDownwardRounded"; import ArrowUpwardRoundedIcon from "@mui/icons-material/ArrowUpwardRounded"; - +import ActionsMenu from "./ActionsMenu"; import { useState, useEffect, memo, useCallback, useRef } from "react"; -import { useDispatch } from "react-redux"; +import { useDispatch, useSelector } from "react-redux"; import { useTheme } from "@emotion/react"; import LeftArrowDouble from "../../../assets/icons/left-arrow-double.svg?react"; import RightArrowDouble from "../../../assets/icons/right-arrow-double.svg?react"; import LeftArrow from "../../../assets/icons/left-arrow.svg?react"; import RightArrow from "../../../assets/icons/right-arrow.svg?react"; import SelectorVertical from "../../../assets/icons/selector-vertical.svg?react"; -// import ActionsMenu from "../actionsMenu"; +import { formatDurationRounded } from "../../../Utils/timeUtils"; +import { StatusLabel } from "../../../Components/Label"; +import { setRowsPerPage } from "../../../Features/UI/uiSlice"; /** * Component for pagination actions (first, previous, next, last). @@ -101,16 +103,15 @@ TablePaginationActions.propTypes = { const MaintenanceTable = ({ page, setPage, - rowsPerPage, - setRowsPerPage, sort, setSort, maintenanceWindows, maintenanceWindowCount, }) => { + const { rowsPerPage } = useSelector((state) => state.ui.maintenance); + const theme = useTheme(); const dispatch = useDispatch(); - const handleChangePage = (event, newPage) => { setPage(newPage); }; @@ -119,7 +120,7 @@ const MaintenanceTable = ({ dispatch( setRowsPerPage({ value: parseInt(event.target.value, 10), - table: "monitors", + table: "maintenance", }) ); setPage(0); @@ -159,7 +160,7 @@ const MaintenanceTable = ({ onClick={() => handleSort("name")} > - Host + Maintenance Window Name {sort.order === "asc" ? ( @@ -195,12 +196,38 @@ const MaintenanceTable = ({ - Response Time - Type + Next Window + Repeat Actions - + + {maintenanceWindows.map((maintenanceWindow) => { + const text = maintenanceWindow.active ? "active" : "paused"; + const status = maintenanceWindow.active ? "up" : "paused"; + return ( + + {maintenanceWindow.name} + + + + {maintenanceWindow.start} + + {maintenanceWindow.repeat === 0 + ? "N/A" + : formatDurationRounded(maintenanceWindow.repeat)} + + + + + + ); + })} + { const theme = useTheme(); - const authState = useSelector((state) => state.auth); + const navigate = useNavigate(); + const { authToken } = useSelector((state) => state.auth); + const { rowsPerPage } = useSelector((state) => state.ui.maintenance); const [maintenanceWindows, setMaintenanceWindows] = useState([]); const [maintenanceWindowCount, setMaintenanceWindowCount] = useState(0); const [page, setPage] = useState(0); - const [rowsPerPage, setRowsPerPage] = useState(5); const [sort, setSort] = useState({}); - useEffect(() => {}); + useEffect(() => { + const fetchMaintenanceWindows = async () => { + try { + const response = await networkService.getMaintenanceWindowsByTeamId({ + authToken: authToken, + page: page, + rowsPerPage: rowsPerPage, + }); + const { maintenanceWindows, maintenanceWindowCount } = + response.data.data; + setMaintenanceWindows(maintenanceWindows); + setMaintenanceWindowCount(maintenanceWindowCount); + } catch (error) { + console.log(error); + } + }; + fetchMaintenanceWindows(); + }, [authToken, page, rowsPerPage]); return ( { }} > {maintenanceWindows.length > 0 && ( - + + + + + + + )} {isAdmin && maintenanceWindows.length === 0 && ( } The response from the axios POST request. + * + */ + + async getMaintenanceWindowsByTeamId(config) { + const { authToken, active, page, rowsPerPage, field, order } = config; + + const params = new URLSearchParams(); + + if (active) params.append("status", active); + if (page) params.append("page", page); + if (rowsPerPage) params.append("rowsPerPage", rowsPerPage); + if (field) params.append("field", field); + if (order) params.append("order", order); + + return this.axiosInstance.get( + `/maintenance-window/team?${params.toString()}`, + { + headers: { + Authorization: `Bearer ${authToken}`, + "Content-Type": "application/json", + }, + } + ); + } } export default NetworkService; diff --git a/Server/controllers/maintenanceWindowController.js b/Server/controllers/maintenanceWindowController.js index 09dd177a9..bd92b4dc1 100644 --- a/Server/controllers/maintenanceWindowController.js +++ b/Server/controllers/maintenanceWindowController.js @@ -28,6 +28,7 @@ const createMaintenanceWindows = async (req, res, next) => { return req.db.createMaintenanceWindow({ teamId, monitorId, + name: req.body.name, active: req.body.active ? req.body.active : true, repeat: req.body.repeat, start: req.body.start, diff --git a/Server/db/models/MaintenanceWindow.js b/Server/db/models/MaintenanceWindow.js index 06141cc60..3727d3b40 100644 --- a/Server/db/models/MaintenanceWindow.js +++ b/Server/db/models/MaintenanceWindow.js @@ -43,6 +43,9 @@ const MaintenanceWindow = mongoose.Schema( type: Boolean, default: true, }, + name: { + type: String, + }, repeat: { type: Number, }, diff --git a/Server/db/mongo/modules/maintenanceWindowModule.js b/Server/db/mongo/modules/maintenanceWindowModule.js index 57b1eb05f..7e328e27c 100644 --- a/Server/db/mongo/modules/maintenanceWindowModule.js +++ b/Server/db/mongo/modules/maintenanceWindowModule.js @@ -36,7 +36,7 @@ const createMaintenanceWindow = async (maintenanceWindowData) => { if (maintenanceWindowData.oneTime) { maintenanceWindow.expiry = maintenanceWindowData.end; } - const result = maintenanceWindow.save(); + const result = await maintenanceWindow.save(); return result; } catch (error) { error.service = SERVICE_NAME;