From 09513696ee585dd11e44939d5fe17dc20c314502 Mon Sep 17 00:00:00 2001 From: karenvicent Date: Wed, 21 Jan 2026 15:33:00 -0500 Subject: [PATCH] detail modal fixes and filters options --- .../Components/IncidentDetailsModal/index.jsx | 2 - .../IncidentTable/IncidentActionsMenu.jsx | 16 +- .../Components/IncidentTable/index.jsx | 5 +- .../Components/LatestIncidentsPanel/index.jsx | 2 +- .../Components/OptionsHeader/index.jsx | 1 + .../ResolveIncidentDialog/index.jsx | 8 +- .../Incidents/hooks/useFetchIncidents.js | 26 +- client/src/Pages/Incidents/index.jsx | 8 + .../Components/IncidentDetailsModal/index.jsx | 406 ------------------ .../IncidentTable/IncidentActionsMenu.jsx | 154 ------- .../ResolveIncidentDialog/index.jsx | 105 ----- client/src/locales/en.json | 1 + 12 files changed, 49 insertions(+), 685 deletions(-) delete mode 100644 client/src/Pages/Incidents2/Components/IncidentDetailsModal/index.jsx delete mode 100644 client/src/Pages/Incidents2/Components/IncidentTable/IncidentActionsMenu.jsx delete mode 100644 client/src/Pages/Incidents2/Components/ResolveIncidentDialog/index.jsx diff --git a/client/src/Pages/Incidents/Components/IncidentDetailsModal/index.jsx b/client/src/Pages/Incidents/Components/IncidentDetailsModal/index.jsx index 1290c69ff..e4dad7c3e 100644 --- a/client/src/Pages/Incidents/Components/IncidentDetailsModal/index.jsx +++ b/client/src/Pages/Incidents/Components/IncidentDetailsModal/index.jsx @@ -168,7 +168,6 @@ const IncidentDetailsModal = ({ open, incidentId, onClose, onResolved }) => { > @@ -188,7 +187,6 @@ const IncidentDetailsModal = ({ open, incidentId, onClose, onResolved }) => { > diff --git a/client/src/Pages/Incidents/Components/IncidentTable/IncidentActionsMenu.jsx b/client/src/Pages/Incidents/Components/IncidentTable/IncidentActionsMenu.jsx index 1e9a3be85..28b3a4f52 100644 --- a/client/src/Pages/Incidents/Components/IncidentTable/IncidentActionsMenu.jsx +++ b/client/src/Pages/Incidents/Components/IncidentTable/IncidentActionsMenu.jsx @@ -2,7 +2,7 @@ import IconButton from "@mui/material/IconButton"; import Menu from "@mui/material/Menu"; import MenuItem from "@mui/material/MenuItem"; -//import Settings from "../../../../assets/icons/settings-bold.svg?react"; +import Icon from "@/Components/v1/Icon/index.jsx"; import ResolveIncidentDialog from "../ResolveIncidentDialog/index.jsx"; import useFetchIncidents from "../../hooks/useFetchIncidents"; @@ -51,7 +51,7 @@ const IncidentActionsMenu = ({ incident, onResolve, onOpenDetails }) => { e.stopPropagation(); closeMenu(e); if (onOpenDetails) { - onOpenDetails(incident._id); + onOpenDetails(incident.id); } }; @@ -59,8 +59,7 @@ const IncidentActionsMenu = ({ incident, onResolve, onOpenDetails }) => { e.stopPropagation(); closeMenu(e); try { - const incidentData = await fetchIncidentById(incident._id); - console.log(incidentData); + const incidentData = await fetchIncidentById(incident.id); if (incidentData) { const { type, _id: monitorId } = incidentData.monitorId; const path = TypeToPathMap[type]; @@ -94,7 +93,10 @@ const IncidentActionsMenu = ({ incident, onResolve, onOpenDetails }) => { }, }} > - {/* */}M + { @@ -144,7 +146,7 @@ const IncidentActionsMenu = ({ incident, onResolve, onOpenDetails }) => { IncidentActionsMenu.propTypes = { incident: PropTypes.shape({ - _id: PropTypes.string.isRequired, + id: PropTypes.string.isRequired, status: PropTypes.bool.isRequired, }).isRequired, onResolve: PropTypes.func.isRequired, diff --git a/client/src/Pages/Incidents/Components/IncidentTable/index.jsx b/client/src/Pages/Incidents/Components/IncidentTable/index.jsx index 699ae59c4..7d23d8ebd 100644 --- a/client/src/Pages/Incidents/Components/IncidentTable/index.jsx +++ b/client/src/Pages/Incidents/Components/IncidentTable/index.jsx @@ -13,7 +13,7 @@ import { formatDateWithTz } from "../../../../Utils/timeUtils.js"; import { useSelector } from "react-redux"; import PropTypes from "prop-types"; import { useTranslation } from "react-i18next"; -import { Button, Typography, useTheme } from "@mui/material"; +import { Typography, useTheme } from "@mui/material"; const IncidentTable = ({ monitors = [], @@ -36,7 +36,7 @@ const IncidentTable = ({ const handleResolveIncident = async (incidentId, options = {}) => { try { - await resolveIncident(incidentId); + await resolveIncident(incidentId, options); handleUpdateTrigger(); } catch (error) { console.error(t("incidentsPage.errorResolvingIncident"), error); @@ -48,7 +48,6 @@ const IncidentTable = ({ id: "monitorName", content: t("incidentsTableMonitorName"), render: (row) => { - console.log(monitors, row); const monitor = monitors.find((monitor) => monitor.id === row.monitorId); return monitor ? monitor.name : "N/A"; }, diff --git a/client/src/Pages/Incidents/Components/LatestIncidentsPanel/index.jsx b/client/src/Pages/Incidents/Components/LatestIncidentsPanel/index.jsx index d24bcd0ef..ff1ef9417 100644 --- a/client/src/Pages/Incidents/Components/LatestIncidentsPanel/index.jsx +++ b/client/src/Pages/Incidents/Components/LatestIncidentsPanel/index.jsx @@ -84,7 +84,7 @@ const LatestIncidentsPanel = ({ incidents = [], isLoading = false, error = null ) : ( {incidents.map((incident, index) => ( - + {index < incidents.length - 1 && } diff --git a/client/src/Pages/Incidents/Components/OptionsHeader/index.jsx b/client/src/Pages/Incidents/Components/OptionsHeader/index.jsx index 3a0ca1985..8d7439576 100644 --- a/client/src/Pages/Incidents/Components/OptionsHeader/index.jsx +++ b/client/src/Pages/Incidents/Components/OptionsHeader/index.jsx @@ -26,6 +26,7 @@ const OptionsHeader = ({ { _id: "active", name: t("incidentsPage.incidentsOptionsHeaderFilterActive") }, { _id: "resolved", name: t("incidentsPage.incidentsOptionsHeaderFilterResolved") }, { _id: "manual", name: t("incidentsPage.incidentsOptionsHeaderFilterManual") }, + { _id: "automatic", name: t("incidentsPage.incidentsOptionsHeaderFilterAutomatic") }, ]; const stackStyles = { diff --git a/client/src/Pages/Incidents/Components/ResolveIncidentDialog/index.jsx b/client/src/Pages/Incidents/Components/ResolveIncidentDialog/index.jsx index e2be5fed2..3e868b2dc 100644 --- a/client/src/Pages/Incidents/Components/ResolveIncidentDialog/index.jsx +++ b/client/src/Pages/Incidents/Components/ResolveIncidentDialog/index.jsx @@ -13,7 +13,7 @@ const ResolveIncidentDialog = ({ onResolve, onAfterResolve, onResolved, - isLoading, + isLoading = false, }) => { const { t } = useTranslation(); const theme = useTheme(); @@ -90,7 +90,7 @@ const ResolveIncidentDialog = ({ ResolveIncidentDialog.propTypes = { open: PropTypes.bool.isRequired, - incidentId: PropTypes.string.isRequired, + incidentId: PropTypes.string, onClose: PropTypes.func.isRequired, onResolve: PropTypes.func.isRequired, onAfterResolve: PropTypes.func, @@ -98,8 +98,4 @@ ResolveIncidentDialog.propTypes = { onResolved: PropTypes.func, }; -ResolveIncidentDialog.defaultProps = { - isLoading: false, -}; - export default ResolveIncidentDialog; diff --git a/client/src/Pages/Incidents/hooks/useFetchIncidents.js b/client/src/Pages/Incidents/hooks/useFetchIncidents.js index 54874bae7..3de495f8a 100644 --- a/client/src/Pages/Incidents/hooks/useFetchIncidents.js +++ b/client/src/Pages/Incidents/hooks/useFetchIncidents.js @@ -71,7 +71,28 @@ const useFetchIncidents = () => { }, [fetchIncidentsByTeam] ); - + const fetchManualResolvedIncidents = useCallback( + async (config = {}) => { + await fetchIncidentsByTeam({ + status: false, + resolutionType: "manual", + sortOrder: "desc", + ...config, + }); + }, + [fetchIncidentsByTeam] + ); + const fetchAutomaticResolvedIncidents = useCallback( + async (config = {}) => { + await fetchIncidentsByTeam({ + status: false, + resolutionType: "automatic", + sortOrder: "desc", + ...config, + }); + }, + [fetchIncidentsByTeam] + ); /** * Fetch resolved incidents * @@ -154,6 +175,7 @@ const useFetchIncidents = () => { createToast({ body: t("incidentsPage.errorResolvingIncident") }); } } catch (error) { + console.log("cayo a error"); setNetworkError(true); console.error(t("incidentsPage.errorResolvingIncident"), error); const errorMessage = @@ -198,6 +220,8 @@ const useFetchIncidents = () => { fetchIncidentById, resolveIncident, fetchIncidentSummary, + fetchManualResolvedIncidents, + fetchAutomaticResolvedIncidents, }; }; diff --git a/client/src/Pages/Incidents/index.jsx b/client/src/Pages/Incidents/index.jsx index abf24989b..179002e18 100644 --- a/client/src/Pages/Incidents/index.jsx +++ b/client/src/Pages/Incidents/index.jsx @@ -49,6 +49,8 @@ const Incidents2 = () => { fetchActiveIncidents, fetchResolvedIncidents, resolveIncident, + fetchManualResolvedIncidents, + fetchAutomaticResolvedIncidents, } = useFetchIncidents(); const networkError = monitorsNetworkError || incidentsNetworkError; @@ -72,6 +74,10 @@ const Incidents2 = () => { fetchActiveIncidents(config); } else if (filter === "resolved") { fetchResolvedIncidents(config); + } else if (filter === "manual") { + fetchManualResolvedIncidents(config); + } else if (filter === "automatic") { + fetchAutomaticResolvedIncidents(config); } else { fetchIncidents(config); } @@ -85,6 +91,8 @@ const Incidents2 = () => { fetchActiveIncidents, fetchResolvedIncidents, fetchIncidents, + fetchManualResolvedIncidents, + fetchAutomaticResolvedIncidents, ]); useEffect(() => { diff --git a/client/src/Pages/Incidents2/Components/IncidentDetailsModal/index.jsx b/client/src/Pages/Incidents2/Components/IncidentDetailsModal/index.jsx deleted file mode 100644 index 25af835b9..000000000 --- a/client/src/Pages/Incidents2/Components/IncidentDetailsModal/index.jsx +++ /dev/null @@ -1,406 +0,0 @@ -// Components -import { Stack, Typography, Grid, Box, Button, Divider } from "@mui/material"; -import { GenericDialog } from "@/Components/v1/Dialog/genericDialog.jsx"; -import GenericFallback from "@/Components/v1/GenericFallback/index.jsx"; -import SummaryCard from "@/Pages/Incidents2/Components/SummaryCard"; -import ResolveIncidentDialog from "../ResolveIncidentDialog/index.jsx"; - -// Utils -import { useEffect, useState } from "react"; -import { useTheme } from "@emotion/react"; -import { useTranslation } from "react-i18next"; -import { formatDateWithTz } from "@/Utils/timeUtils"; -import { useSelector } from "react-redux"; -import PropTypes from "prop-types"; - -// Hooks -import useFetchIncidents from "@/Pages/Incidents2/hooks/useFetchIncidents"; -import useGetIncidentsDuration from "@/Pages/Incidents2/hooks/useGetIncidentsDuration"; - -const IncidentDetailsModal = ({ open, incidentId, onClose, onResolved }) => { - const theme = useTheme(); - const { t } = useTranslation(); - const { fetchIncidentById, resolveIncident } = useFetchIncidents(); - const [incident, setIncident] = useState(null); - const [isLoading, setIsLoading] = useState(false); - const [isResolveDialogOpen, setIsResolveDialogOpen] = useState(false); - const uiTimezone = useSelector((state) => state.ui.timezone); - const isActive = incident?.status === true; - const duration = useGetIncidentsDuration(incident || null, isActive); - - const statusColor = isActive ? theme.palette.error.main : theme.palette.success.main; - const toCapitalLetter = (text) => - typeof text === "string" && text.length > 0 - ? text.charAt(0).toUpperCase() + text.slice(1) - : text; - - const KeyValueRow = ({ label, value, sx = {} }) => ( - - - {label} - - - - {value ?? "-"} - - - - ); - - useEffect(() => { - const loadIncident = async () => { - if (!incidentId || !open) { - setIncident(null); - setIsLoading(false); - return; - } - - setIsLoading(true); - try { - const incidentData = await fetchIncidentById(incidentId); - setIncident(incidentData); - } catch (error) { - console.error("Error fetching incident:", error); - setIncident(null); - } finally { - setIsLoading(false); - } - }; - - loadIncident(); - }, [incidentId, open, fetchIncidentById]); - - const openResolveDialog = () => { - setIsResolveDialogOpen(true); - }; - - const closeResolveDialog = () => { - setIsResolveDialogOpen(false); - }; - - const handleAfterResolve = async () => { - if (!incidentId) return; - const updatedIncident = await fetchIncidentById(incidentId); - if (updatedIncident) { - setIncident(updatedIncident); - } - }; - - const renderContent = () => { - if (isLoading) { - return ( - - ); - } - - if (!incident) { - return ( - - ); - } - - return ( - - - - - - - - {isActive ? t("incidentsPage.active") : t("incidentsPage.resolved")} - - - - - - {t("incidentsPage.incidentItemMonitor")}: - - - {incident?.monitorId?.name || t("incidentsPage.unknownMonitor")} - - - - - {t("incidentsPage.URL")}: - - - {incident?.monitorId?.url || "-"} - - - - - - - - - - - - - - {t("incidentsPage.timeline")} - - - - - {!isActive && ( - - )} - - - - - - - - - - - {isActive - ? t("incidentsPage.errorDetails") - : t("incidentsPage.resolutionDetails")} - - - - - - - - {incident?.message || "-"} - - - {!isActive && ( - <> - - - - {incident?.resolutionType === "manual" && ( - <> - - - - - )} - - )} - - - - - - - - ); - }; - - return ( - - - {renderContent()} - - {isActive && ( - - )} - - - - - - - ); -}; - -IncidentDetailsModal.propTypes = { - open: PropTypes.bool.isRequired, - incidentId: PropTypes.string, - onClose: PropTypes.func.isRequired, - onResolved: PropTypes.func, -}; - -export default IncidentDetailsModal; diff --git a/client/src/Pages/Incidents2/Components/IncidentTable/IncidentActionsMenu.jsx b/client/src/Pages/Incidents2/Components/IncidentTable/IncidentActionsMenu.jsx deleted file mode 100644 index 2902da049..000000000 --- a/client/src/Pages/Incidents2/Components/IncidentTable/IncidentActionsMenu.jsx +++ /dev/null @@ -1,154 +0,0 @@ -// Components -import IconButton from "@mui/material/IconButton"; -import Menu from "@mui/material/Menu"; -import MenuItem from "@mui/material/MenuItem"; -import Settings from "../../../../assets/icons/settings-bold.svg?react"; -import ResolveIncidentDialog from "../ResolveIncidentDialog/index.jsx"; -import useFetchIncidents from "../../hooks/useFetchIncidents"; - -// Utils -import { useState } from "react"; -import { useTheme } from "@emotion/react"; -import { useTranslation } from "react-i18next"; -import { TypeToPathMap } from "@/Utils/monitorUtils.js"; -import { useNavigate } from "react-router-dom"; -import PropTypes from "prop-types"; - -const IncidentActionsMenu = ({ incident, onResolve, onOpenDetails }) => { - const [anchorEl, setAnchorEl] = useState(null); - const [isDialogOpen, setIsDialogOpen] = useState(false); - const theme = useTheme(); - const { t } = useTranslation(); - const { fetchIncidentById } = useFetchIncidents(); - const navigate = useNavigate(); - const openMenu = (event) => { - event.preventDefault(); - event.stopPropagation(); - setAnchorEl(event.currentTarget); - }; - - const closeMenu = (e) => { - if (e) { - e.stopPropagation(); - } - setAnchorEl(null); - }; - - const openResolveDialog = (e) => { - closeMenu(e); - setIsDialogOpen(true); - }; - - const closeDialog = (e) => { - if (e) { - e.stopPropagation(); - } - setIsDialogOpen(false); - }; - - const isActive = incident.status === true; - const handleGoToDetails = (e) => { - e.stopPropagation(); - closeMenu(e); - if (onOpenDetails) { - onOpenDetails(incident._id); - } - }; - - const handleGoToMonitor = async (e) => { - e.stopPropagation(); - closeMenu(e); - try { - const incidentData = await fetchIncidentById(incident._id); - console.log(incidentData); - if (incidentData) { - const { type, _id: monitorId } = incidentData.monitorId; - const path = TypeToPathMap[type]; - if (path && monitorId) { - navigate(`/${path}/${monitorId}`); - } else { - console.error(`Monitor type not found`); - } - } else { - console.error("Monitor information not found in incident data"); - } - } catch (error) { - console.error("Error fetching incident details:", error); - } - }; - - return ( - <> - { - event.stopPropagation(); - openMenu(event); - }} - sx={{ - "&:focus": { - outline: "none", - }, - "& svg path": { - stroke: theme.palette.primary.contrastTextTertiary, - }, - }} - > - - - - - - {t("incidentsPage.incidentsTableActionDetails", "Details")} - - - {t("incidentsPage.incidentsTableActionGoToMonitor", "Go to monitor")} - - {isActive && ( - { - e.stopPropagation(); - openResolveDialog(e); - }} - > - {t("incidentsPage.incidentsTableActionResolveManually")} - - )} - - - - ); -}; - -IncidentActionsMenu.propTypes = { - incident: PropTypes.shape({ - _id: PropTypes.string.isRequired, - status: PropTypes.bool.isRequired, - }).isRequired, - onResolve: PropTypes.func.isRequired, - onOpenDetails: PropTypes.func, -}; - -export default IncidentActionsMenu; diff --git a/client/src/Pages/Incidents2/Components/ResolveIncidentDialog/index.jsx b/client/src/Pages/Incidents2/Components/ResolveIncidentDialog/index.jsx deleted file mode 100644 index e2be5fed2..000000000 --- a/client/src/Pages/Incidents2/Components/ResolveIncidentDialog/index.jsx +++ /dev/null @@ -1,105 +0,0 @@ -import { useEffect, useState } from "react"; -import PropTypes from "prop-types"; -import { Button, Stack } from "@mui/material"; -import { useTranslation } from "react-i18next"; -import { useTheme } from "@emotion/react"; -import { GenericDialog } from "@/Components/v1/Dialog/genericDialog.jsx"; -import TextInput from "@/Components/v1/Inputs/TextInput/index.jsx"; - -const ResolveIncidentDialog = ({ - open, - incidentId, - onClose, - onResolve, - onAfterResolve, - onResolved, - isLoading, -}) => { - const { t } = useTranslation(); - const theme = useTheme(); - const [comment, setComment] = useState(""); - const [isSubmitting, setIsSubmitting] = useState(false); - - useEffect(() => { - if (open) { - setComment(""); - } - }, [open]); - - const handleConfirm = async () => { - if (!incidentId) return; - const trimmed = comment.trim(); - try { - setIsSubmitting(true); - await onResolve(incidentId, trimmed ? { comment: trimmed } : {}); - if (onAfterResolve) { - await onAfterResolve(); - } - onResolved?.(); - onClose(); - } catch (error) { - console.error("Error resolving incident:", error); - } finally { - setIsSubmitting(false); - } - }; - - return ( - - - setComment(e.target.value)} - maxWidth="100%" - /> - - - - - - - ); -}; - -ResolveIncidentDialog.propTypes = { - open: PropTypes.bool.isRequired, - incidentId: PropTypes.string.isRequired, - onClose: PropTypes.func.isRequired, - onResolve: PropTypes.func.isRequired, - onAfterResolve: PropTypes.func, - isLoading: PropTypes.bool, - onResolved: PropTypes.func, -}; - -ResolveIncidentDialog.defaultProps = { - isLoading: false, -}; - -export default ResolveIncidentDialog; diff --git a/client/src/locales/en.json b/client/src/locales/en.json index 9b5ac626f..cc5789e7f 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -1202,6 +1202,7 @@ "noIncidentIdProvided": "No incident ID provided", "errorFetchingIncidentSummary": "Error fetching incident summary", "incidentsOptionsHeaderFilterManual": "Manual", + "incidentsOptionsHeaderFilterAutomatic": "Automatic", "incidentsOptionsHeaderFilterAll": "All", "incidentsOptionsHeaderFilterActive": "Active", "incidentsOptionsHeaderFilterResolved": "Resolved",