feat: adding delete and detail actions

This commit is contained in:
Caio Cabral committed 2024-11-29 13:48:29 -05:00
1 parent 55e3c674b6
commit 91f608a62a
3 files changed
+274 -10

No files matched your search

+11
View File
@@ -0,0 +1,11 @@
import { useSelector } from "react-redux";
const useIsAdmin = () => {
const { user } = useSelector((state) => state.auth);
const isAdmin =
(user?.role?.includes("admin") ?? false) ||
(user?.role?.includes("superadmin") ?? false);
return isAdmin;
};
export { useIsAdmin };
@@ -0,0 +1,235 @@
/* TODO I basically copied and pasted this component from the actionsMenu. Check how we can make it reusable */
import { useRef, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { useTheme } from "@emotion/react";
import { useNavigate } from "react-router-dom";
import { createToast } from "../../../../Utils/toastUtils";
/* import { logger } from "../../../Utils/Logger"; */
import { IconButton, Menu, MenuItem } from "@mui/material";
import {
deleteUptimeMonitor,
/* pauseUptimeMonitor, */
getUptimeMonitorsByTeamId,
} from "../../../../Features/UptimeMonitors/uptimeMonitorsSlice";
import Settings from "../../../../assets/icons/settings-bold.svg?react";
import PropTypes from "prop-types";
import Dialog from "../../../../Components/Dialog";
import { networkService } from "../../../../Utils/NetworkService.js";
const InfrastructureMenu = ({ monitor, isAdmin, updateCallback }) => {
/* const [anchorEl, setAnchorEl] = useState(null);
const [actions, setActions] = useState({}); */
const actions = { id: monitor.id, url: monitor.url };
const anchor = useRef(null);
const [isOpen, setIsOpen] = useState(false);
const [isDialogOpen, setIsDialogOpen] = useState(false);
const dispatch = useDispatch();
const theme = useTheme();
const authState = useSelector((state) => state.auth);
const authToken = authState.authToken;
const { isLoading } = useSelector((state) => state.uptimeMonitors);
/* const handlePause = async () => {
try {
const action = await dispatch(
pauseUptimeMonitor({ authToken, monitorId: monitor._id })
);
if (pauseUptimeMonitor.fulfilled.match(action)) {
updateCallback();
const state = action?.payload?.data.isActive === false ? "paused" : "resumed";
createToast({ body: `Monitor ${state} successfully.` });
} else {
throw new Error(action?.error?.message ?? "Failed to pause monitor.");
}
} catch (error) {
logger.error("Error pausing monitor:", monitor._id, error);
createToast({ body: "Failed to pause monitor." });
}
}; */
/* TODO
1) Clean component
2) Rerender after removing
3) Add padding to inputs (I took of their height)
*/
const openMenu = (e) => {
e.stopPropagation();
setIsOpen(true);
};
const closeMenu = (e) => {
e.stopPropagation();
setIsOpen(false);
};
const openRemove = (e) => {
closeMenu(e);
setIsDialogOpen(true);
};
const cancelRemove = () => {
setIsDialogOpen(false);
};
const navigate = useNavigate();
function openDetails(id) {
navigate(`/infrastructure/${id}`);
}
const handleRemove = async () => {
try {
/* TODO not working, dont know why */
const result = await networkService.deleteMonitorById({
authToken,
monitorId: actions.id,
});
console.log(result);
/* Toast success */
} catch (error) {
console.log(error);
/* Toast error */
} finally {
setIsDialogOpen(false);
updateCallback();
}
/* let monitor = { _id: actions.id };
const action = await dispatch(
deleteUptimeMonitor({ authToken: authState.authToken, monitor })
);
if (action.meta.requestStatus === "fulfilled") {
setIsOpen(false); // close modal
dispatch(getUptimeMonitorsByTeamId(authState.authToken));
updateCallback();
createToast({ body: "Monitor deleted successfully." });
} else {
createToast({ body: "Failed to delete monitor." });
} */
};
return (
<>
<IconButton
aria-label="monitor actions"
onClick={openMenu}
sx={{
"&:focus": {
outline: "none",
},
"& svg path": {
stroke: theme.palette.other.icon,
},
}}
ref={anchor}
>
<Settings />
</IconButton>
<Menu
className="actions-menu"
anchorEl={anchor.current}
open={isOpen}
onClose={closeMenu}
disableScrollLock
slotProps={{
paper: {
sx: {
"& ul": { p: theme.spacing(2.5) },
"& li": { m: 0 },
"& li:last-of-type": {
color: theme.palette.error.contrastText,
},
},
},
}}
>
{/*
Open sit action. Not necessary for infrastructure?
{actions.url !== null ? (
<MenuItem
onClick={(e) => {
closeMenu(e);
e.stopPropagation();
window.open(actions.url, "_blank", "noreferrer");
}}
>
Open site
</MenuItem>
) : (
""
)}
*/}
<MenuItem onClick={() => openDetails(actions.id)}>Details</MenuItem>
{/* TODO - pass monitor id to Incidents page */}
{/* <MenuItem
onClick={(e) => {
e.stopPropagation();
navigate(`/incidents/${actions.id}`);
}}
>
Incidents
</MenuItem> */}
{/* {isAdmin && (
<MenuItem
onClick={(e) => {
e.stopPropagation();
navigate(`/monitors/configure/${actions.id}`);
}}
>
Configure
</MenuItem>
)} */}
{/* {isAdmin && (
<MenuItem
onClick={(e) => {
e.stopPropagation();
navigate(`/monitors/create/${actions.id}`);
}}
>
Clone
</MenuItem>
)} */}
{/* {isAdmin && (
<MenuItem
onClick={(e) => {
e.stopPropagation();
handlePause(e);
}}
>
{monitor?.isActive === true ? "Pause" : "Resume"}
</MenuItem>
)} */}
{isAdmin && <MenuItem onClick={openRemove}>Remove</MenuItem>}
</Menu>
<Dialog
open={isDialogOpen}
theme={theme}
title="Do you really want to delete this monitor?"
description="Once deleted, this monitor cannot be retrieved."
onCancel={cancelRemove}
confirmationButtonLabel="Delete"
/* Do we need stop propagation? */
onConfirm={handleRemove}
isLoading={isLoading}
modelTitle="modal-delete-monitor"
modelDescription="delete-monitor-confirmation"
/>
</>
);
};
InfrastructureMenu.propTypes = {
monitor: PropTypes.shape({
_id: PropTypes.string,
url: PropTypes.string,
type: PropTypes.string,
isActive: PropTypes.bool,
}).isRequired,
isAdmin: PropTypes.bool,
updateCallback: PropTypes.func,
};
export { InfrastructureMenu };
+28 -10
View File
@@ -4,7 +4,7 @@ import { /* useDispatch, */ useSelector } from "react-redux";
import { useTheme } from "@emotion/react";
import useUtils from "../Monitors/utils";
import { jwtDecode } from "jwt-decode";
import GearIcon from "../../Assets/icons/settings-bold.svg?react";
// import GearIcon from "../../Assets/icons/settings-bold.svg?react";
import CPUChipIcon from "../../Assets/icons/cpu-chip.svg?react";
import {
Box,
@@ -27,6 +27,9 @@ import { Pagination } from "./components/TablePagination";
import { networkService } from "../../Utils/NetworkService.js";
import CustomGauge from "../../Components/Charts/CustomGauge/index.jsx";
import Host from "../Monitors/Home/host.jsx";
import ActionsMenu from "../Monitors/Home/actionsMenu.jsx";
import { useIsAdmin } from "../../Hooks/useIsAdmin.js";
import { InfrastructureMenu } from "./components/Menu";
const columns = [
{ label: "Host" },
@@ -71,7 +74,9 @@ Analyze existing BasicTable
* @returns {JSX.Element} The infrastructure monitoring page.
*/
function Infrastructure(/* {isAdmin} */) {
function Infrastructure() {
/* Adding this custom hook so we can avoid using the HOC approach that can lower performance (we are calling the admin logic N times on initializing the project. using a custom hook will cal it ass needed ) */
const isAdmin = useIsAdmin();
const theme = useTheme();
const navigate = useNavigate();
@@ -93,7 +98,7 @@ function Infrastructure(/* {isAdmin} */) {
const { authToken } = useSelector((state) => state.auth);
const user = jwtDecode(authToken);
const fetchMonitors = useCallback(async () => {
const fetchMonitors = async () => {
try {
const response = await networkService.getMonitorsByTeamId({
authToken,
@@ -106,6 +111,7 @@ function Infrastructure(/* {isAdmin} */) {
page: page,
rowsPerPage: rowsPerPage,
});
console.log({ response });
setMonitorState({
monitors: response?.data?.data?.monitors ?? [],
total: response?.data?.data?.monitorCount ?? 0,
@@ -113,7 +119,7 @@ function Infrastructure(/* {isAdmin} */) {
} catch (error) {
console.error(error);
}
}, [page, rowsPerPage, authToken]);
};
useEffect(() => {
fetchMonitors();
@@ -121,8 +127,6 @@ function Infrastructure(/* {isAdmin} */) {
const { determineState } = useUtils();
const { monitors, total: totalMonitors } = monitorState;
console.log({ monitors });
console.log(monitors[0]?.checks[0]?.memory.usage_percent);
const monitorsAsRows = monitors.map((monitor) => ({
id: monitor._id,
url: monitor.url,
@@ -133,12 +137,21 @@ function Infrastructure(/* {isAdmin} */) {
mem: monitor?.checks[0]?.memory.usage_percent * 100,
disk: monitor?.checks[0]?.disk[0]?.usage_percent * 100,
}));
/* Adding click on row action */
/* Adding actions to the table */
/*
TODO
Clean component (actions component)
Add padding to inputs (I took of their height)
Add toast
*/
function openDetails(id) {
navigate(`/infrastructure/${id}`);
}
function handleActionMenuDelete() {
fetchMonitors();
}
return (
<Stack
@@ -273,10 +286,15 @@ function Infrastructure(/* {isAdmin} */) {
},
}}
>
<GearIcon
<InfrastructureMenu
monitor={row}
isAdmin={isAdmin}
updateCallback={handleActionMenuDelete}
/>
{/* <GearIcon
width={20}
height={20}
/>
/> */}
</IconButton>
</TableCell>
</TableRow>