diff --git a/client/src/Pages/Incidents/Components/ActiveIncidentsPanel/index.jsx b/client/src/Pages/Incidents/Components/ActiveIncidentsPanel/index.jsx
deleted file mode 100644
index fda257695..000000000
--- a/client/src/Pages/Incidents/Components/ActiveIncidentsPanel/index.jsx
+++ /dev/null
@@ -1,134 +0,0 @@
-import PropTypes from "prop-types";
-import { Box, Stack, Typography } from "@mui/material";
-import { useTheme } from "@emotion/react";
-import { useTranslation } from "react-i18next";
-import PanelSkeleton from "../IncidentsSummaryPanel/skeleton.jsx";
-import Icon from "@/Components/v1/Icon";
-import SummaryCard from "../SummaryCard/index.jsx";
-
-/**
- * ActiveIncidentsPanel Component
- *
- * Displays a quick overview of currently active incidents.
- * Shows only essential information: monitor name, status badge, and duration.
- *
- * @param {Object} props
- * @param {Array} props.incidents - Array of active incidents
- * @param {number} props.totalCount - Total count of active incidents (for badge)
- * @param {boolean} props.isLoading - Loading state
- * @param {Object} props.error - Error object if any
- * @param {Function} props.onIncidentClick - Callback when incident is clicked (optional)
- */
-const ActiveIncidentsPanel = ({ totalCount = 0, isLoading = false, error = null }) => {
- const theme = useTheme();
- const { t } = useTranslation();
-
- if (isLoading) {
- return ;
- }
-
- if (error) {
- return (
-
-
- {t("incidentsPage.incidentsActivePanelError")}
-
-
- );
- }
-
- if (!totalCount || totalCount === 0) {
- return (
-
-
-
-
-
-
-
- {t("incidentsPage.allSystemsAreOperational")}
-
-
-
- );
- }
-
- return (
-
-
-
-
-
-
-
- {totalCount}
-
-
-
- );
-};
-
-ActiveIncidentsPanel.propTypes = {
- totalCount: PropTypes.number,
- isLoading: PropTypes.bool,
- error: PropTypes.object,
- onIncidentClick: PropTypes.func,
-};
-
-export default ActiveIncidentsPanel;
diff --git a/client/src/Pages/Incidents/Components/CardSummary.tsx b/client/src/Pages/Incidents/Components/CardSummary.tsx
index 12d1f87cb..60b13bde7 100644
--- a/client/src/Pages/Incidents/Components/CardSummary.tsx
+++ b/client/src/Pages/Incidents/Components/CardSummary.tsx
@@ -5,13 +5,45 @@ import Grid from "@mui/material/Grid";
import { BaseBox, ValueLabel } from "@/Components/v2/design-elements";
import { CircleCheck, TriangleAlert, Bell, Wrench, Globe } from "lucide-react";
import Box from "@mui/material/Box";
-import { SummaryItem } from "@/Pages/Incidents/Components/IncidentItem";
import { useTranslation } from "react-i18next";
import { useTheme } from "@mui/material";
import type { IncidentSummary, IncidentSummaryItem } from "@/Types/Incident";
import { getIncidentsDuration } from "@/Pages/Incidents/utils";
+interface SummaryItemProps {
+ icon: React.ReactNode;
+ label: string;
+ value: string | number;
+}
+
+const SummaryItem = ({ icon, label, value }: SummaryItemProps) => {
+ const theme = useTheme();
+ return (
+
+
+ {icon}
+ {label}
+
+
+ {value}
+
+
+ );
+};
+
interface SummaryCardProps {
title: string;
sx?: React.CSSProperties;
@@ -92,6 +124,7 @@ export const SummaryCardActiveIncidents = ({ summary }: SummaryCardActiveInciden
const SummaryIncidentItem = ({ incident }: { incident: IncidentSummaryItem }) => {
const theme = useTheme();
+ const { t } = useTranslation();
const duration = getIncidentsDuration(incident);
return (
fontWeight={500}
noWrap
>
- {incident.monitorName ?? "N/A"}
+ {incident.monitorName ?? t("common.labels.na")}
@@ -130,7 +163,7 @@ const SummaryIncidentItem = ({ incident }: { incident: IncidentSummaryItem }) =>
>
@@ -182,8 +215,8 @@ export const SummaryCardStats = ({ summary }: SummaryCardStatsProps) => {
if (!summary) return null;
const mostAffected =
!summary.total || summary.total === 0
- ? "N/A"
- : summary.topMonitor?.monitorName || t("N/A");
+ ? t("common.labels.na")
+ : summary.topMonitor?.monitorName || t("common.labels.na");
return (
{
}
label={t("pages.incidents.summaryCard.incidentStats.avgResolutionTime")}
- value={summary.total > 0 ? `${summary.avgResolutionTimeHours || 0} hours` : "N/A"}
+ value={summary.total > 0 ? `${summary.avgResolutionTimeHours || 0} hours` : t("common.labels.na")}
/>
);
diff --git a/client/src/Pages/Incidents/Components/HeaderIncidents.tsx b/client/src/Pages/Incidents/Components/HeaderIncidents.tsx
deleted file mode 100644
index e69de29bb..000000000
diff --git a/client/src/Pages/Incidents/Components/IncidentDetailsModal/index.jsx b/client/src/Pages/Incidents/Components/IncidentDetailsModal/index.jsx
deleted file mode 100644
index 34efd632e..000000000
--- a/client/src/Pages/Incidents/Components/IncidentDetailsModal/index.jsx
+++ /dev/null
@@ -1,413 +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 "../SummaryCard/index.jsx";
-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/timeUtilsLegacy.js";
-import { useSelector } from "react-redux";
-import PropTypes from "prop-types";
-
-// Hooks
-import useFetchIncidents from "../../hooks/useFetchIncidents.js";
-import useGetIncidentsDuration from "../../hooks/useGetIncidentsDuration.js";
-
-const IncidentDetailsModal = ({ open, incidentId, onClose, onResolved }) => {
- const theme = useTheme();
- const { t } = useTranslation();
- const { fetchIncidentById, resolveIncident } = useFetchIncidents();
- const [incidentData, setIncidentData] = useState(null);
- const [isLoading, setIsLoading] = useState(false);
- const [isResolveDialogOpen, setIsResolveDialogOpen] = useState(false);
- const uiTimezone = useSelector((state) => state.ui.timezone);
- const isActive = incidentData?.incident?.status === true;
- const duration = useGetIncidentsDuration(incidentData?.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) {
- setIncidentData(null);
- setIsLoading(false);
- return;
- }
-
- setIsLoading(true);
- try {
- const incidentData = await fetchIncidentById(incidentId);
- setIncidentData(incidentData);
- } catch (error) {
- console.error("Error fetching incident:", error);
- setIncidentData(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) {
- setIncidentData(updatedIncident);
- }
- };
-
- const renderContent = () => {
- if (isLoading) {
- return (
-
- );
- }
-
- if (!incidentData) {
- return (
-
- );
- }
-
- return (
-
-
-
-
-
-
-
- {isActive ? t("incidentsPage.active") : t("incidentsPage.resolved")}
-
-
-
-
-
- {t("incidentsPage.incidentItemMonitor")}
-
-
- {incidentData?.monitor?.name || t("incidentsPage.unknownMonitor")}
-
-
-
-
- {t("incidentsPage.URL")}
-
-
- {incidentData?.monitor?.url || "-"}
-
-
-
-
-
-
-
-
-
-
-
-
-
- {t("incidentsPage.timeline")}
-
-
-
-
- {!isActive && (
-
- )}
-
-
-
-
-
-
-
-
-
-
- {isActive
- ? t("incidentsPage.errorDetails")
- : t("incidentsPage.resolutionDetails")}
-
-
-
-
-
-
-
-
- {!isActive && (
- <>
-
- {incidentData?.incident?.resolutionType === "manual" && (
-
- )}
- >
- )}
-
-
-
-
-
-
-
- );
- };
-
- return (
-
-
- {renderContent()}
- {!isActive &&
- incidentData?.incident?.resolutionType === "manual" &&
- incidentData?.user?.email && (
-
- {t("incidentsPage.resolvedBy")}: {incidentData.user.email}
-
- )}
-
- {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/Incidents/Components/IncidentItem.tsx b/client/src/Pages/Incidents/Components/IncidentItem.tsx
deleted file mode 100644
index 13bff2a77..000000000
--- a/client/src/Pages/Incidents/Components/IncidentItem.tsx
+++ /dev/null
@@ -1,104 +0,0 @@
-import Stack from "@mui/material/Stack";
-import Box from "@mui/material/Box";
-import Divider from "@mui/material/Divider";
-import Grid from "@mui/material/Grid";
-import Typography from "@mui/material/Typography";
-import { ValueLabel } from "@/Components/v2/design-elements";
-import { Globe } from "lucide-react";
-
-import type { Incident } from "@/Types/Incident";
-import type { Monitor } from "@/Types/Monitor";
-import { useTheme } from "@mui/material";
-import { getIncidentsDuration } from "@/Pages/Incidents/utils";
-
-export const IncidentItem = ({
- incident,
- monitor,
-}: {
- incident: Incident;
- monitor?: Monitor | null;
-}) => {
- const theme = useTheme();
- const duration = getIncidentsDuration(incident);
- return (
-
-
-
-
- {monitor ? monitor.name : "N/A"}
-
-
-
-
-
-
-
-
- {duration}
-
-
- );
-};
-
-interface SummaryItemProps {
- icon: React.ReactNode;
- label: string;
- value: string | number;
-}
-
-export const SummaryItem = ({ icon, label, value }: SummaryItemProps) => {
- const theme = useTheme();
- return (
-
-
- {icon}
-
- {label}: {value}
-
-
-
-
- );
-};
diff --git a/client/src/Pages/Incidents/Components/IncidentTable/IncidentActionsMenu.jsx b/client/src/Pages/Incidents/Components/IncidentTable/IncidentActionsMenu.jsx
deleted file mode 100644
index d125a9fdb..000000000
--- a/client/src/Pages/Incidents/Components/IncidentTable/IncidentActionsMenu.jsx
+++ /dev/null
@@ -1,156 +0,0 @@
-// Components
-import IconButton from "@mui/material/IconButton";
-import Menu from "@mui/material/Menu";
-import MenuItem from "@mui/material/MenuItem";
-import Icon from "@/Components/v1/Icon/index.jsx";
-import ResolveIncidentDialog from "../ResolveIncidentDialog/index.jsx";
-
-// Utils
-import { useState } from "react";
-import { useTheme } from "@emotion/react";
-import { useTranslation } from "react-i18next";
-import { TypeToPathMap } from "@/Utils/monitorUtilsLegacy.js";
-import { useNavigate } from "react-router-dom";
-import PropTypes from "prop-types";
-
-const IncidentActionsMenu = ({ incident, monitor, onResolve, onOpenDetails }) => {
- const [anchorEl, setAnchorEl] = useState(null);
- const [isDialogOpen, setIsDialogOpen] = useState(false);
- const theme = useTheme();
- const { t } = useTranslation();
- 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 {
- if (monitor) {
- const path = TypeToPathMap[monitor.type];
- if (path && monitor.id) {
- navigate(`/${path}/${monitor.id}`);
- } 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,
- },
- }}
- >
-
-
-
-
-
- >
- );
-};
-
-IncidentActionsMenu.propTypes = {
- incident: PropTypes.shape({
- id: PropTypes.string.isRequired,
- status: PropTypes.bool.isRequired,
- }).isRequired,
- monitor: PropTypes.shape({
- id: PropTypes.string.isRequired,
- type: PropTypes.string.isRequired,
- }).isRequired,
- onResolve: PropTypes.func.isRequired,
- onOpenDetails: PropTypes.func,
-};
-
-export default IncidentActionsMenu;
diff --git a/client/src/Pages/Incidents/Components/IncidentTable/index.jsx b/client/src/Pages/Incidents/Components/IncidentTable/index.jsx
deleted file mode 100644
index 2a03a8822..000000000
--- a/client/src/Pages/Incidents/Components/IncidentTable/index.jsx
+++ /dev/null
@@ -1,193 +0,0 @@
-//Components
-import DataTable from "@/Components/v1/Table/index.jsx";
-import TableSkeleton from "@/Components/v1/Table/skeleton.jsx";
-import Pagination from "@/Components/v1/Table/TablePagination/index.jsx";
-import { StatusLabel } from "@/Components/v1/Label/index.jsx";
-import { HttpStatusLabel } from "@/Components/v1/HttpStatusLabel/index.jsx";
-import GenericFallback from "@/Components/v1/GenericFallback/index.jsx";
-import NetworkError from "@/Components/v1/GenericFallback/NetworkError.jsx";
-import IncidentActionsMenu from "./IncidentActionsMenu.jsx";
-
-//Utils
-import { formatDateWithTz } from "../../../../Utils/timeUtilsLegacy.js";
-import { useSelector } from "react-redux";
-import PropTypes from "prop-types";
-import { useTranslation } from "react-i18next";
-import { Typography, useTheme } from "@mui/material";
-
-const IncidentTable = ({
- monitors = [],
- incidents = [],
- incidentsCount = 0,
- isLoading = false,
- networkError = false,
- page = 0,
- rowsPerPage = 10,
- handleChangePage,
- handleChangeRowsPerPage,
- resolveIncident,
- handleUpdateTrigger,
- onOpenDetails,
-}) => {
- const uiTimezone = useSelector((state) => state.ui.timezone);
-
- const { t } = useTranslation();
- const theme = useTheme();
-
- const handleResolveIncident = async (incidentId, options = {}) => {
- try {
- await resolveIncident(incidentId, options);
- handleUpdateTrigger();
- } catch (error) {
- console.error(t("incidentsPage.errorResolvingIncident"), error);
- }
- };
-
- const headers = [
- {
- id: "monitorName",
- content: t("incidentsTableMonitorName"),
- render: (row) => {
- const monitor = monitors.find((monitor) => monitor.id === row.monitorId);
- return monitor ? monitor.name : "N/A";
- },
- },
- {
- id: "status",
- content: t("incidentsTableStatus"),
- render: (row) => {
- const status = row.status === true ? "down" : "up";
- const statusText =
- row.status === true ? t("incidentsPage.active") : t("incidentsPage.resolved");
- return (
-
- );
- },
- },
- {
- id: "startTime",
- content: t("incidentsPage.startTime"),
- render: (row) => {
- const formattedDate = formatDateWithTz(
- row.startTime || row.createdAt,
- "YYYY-MM-DD HH:mm:ss A",
- uiTimezone
- );
- return formattedDate;
- },
- },
- {
- id: "endTime",
- content: t("incidentsPage.endTime"),
- render: (row) => {
- if (row.endTime) {
- return formatDateWithTz(row.endTime, "YYYY-MM-DD HH:mm:ss A", uiTimezone);
- }
- return "-";
- },
- },
- {
- id: "resolutionType",
- content: t("incidentsPage.resolutionType"),
- render: (row) => {
- if (row.resolutionType) {
- return (
-
- {row.resolutionType}
-
- );
- }
- return "-";
- },
- },
- {
- id: "statusCode",
- content: t("incidentsTableStatusCode"),
- render: (row) => ,
- },
- {
- id: "message",
- content: t("incidentsTableMessage"),
- render: (row) => row.message || "-",
- },
- {
- id: "action",
- content: t("actions"),
- render: (row) => {
- return (
- monitor.id === row.monitorId)}
- onResolve={handleResolveIncident}
- onOpenDetails={onOpenDetails}
- />
- );
- },
- },
- ];
-
- if (isLoading) return ;
-
- if (networkError) {
- return (
-
-
-
- );
- }
-
- if (!isLoading && !networkError && incidents?.length === 0) {
- return (
-
- {t("incidentsTableNoIncidents", "No incidents found")}
-
- );
- }
-
- const incidentsData = Array.isArray(incidents) ? incidents : [];
-
- return (
- <>
-
-
- >
- );
-};
-
-IncidentTable.propTypes = {
- incidents: PropTypes.array.isRequired, // Array of incident objects
- incidentsCount: PropTypes.number.isRequired, // Total count for pagination
- isLoading: PropTypes.bool.isRequired, // Loading state
- networkError: PropTypes.bool, // Network error object
- page: PropTypes.number.isRequired, // Current page number
- rowsPerPage: PropTypes.number.isRequired, // Number of rows per page
- handleChangePage: PropTypes.func.isRequired, // Handler for page change
- handleChangeRowsPerPage: PropTypes.func.isRequired, // Handler for rows per page change
- resolveIncident: PropTypes.func.isRequired,
- handleUpdateTrigger: PropTypes.func.isRequired,
- onOpenDetails: PropTypes.func,
-};
-
-export default IncidentTable;
diff --git a/client/src/Pages/Incidents/Components/IncidentsSummaryPanel/index.jsx b/client/src/Pages/Incidents/Components/IncidentsSummaryPanel/index.jsx
deleted file mode 100644
index 33ba21cd1..000000000
--- a/client/src/Pages/Incidents/Components/IncidentsSummaryPanel/index.jsx
+++ /dev/null
@@ -1,100 +0,0 @@
-import { useEffect, useState } from "react";
-// Hooks
-import useFetchIncidents from "../../hooks/useFetchIncidents.js";
-import PropTypes from "prop-types";
-// Components
-import { Grid } from "@mui/material";
-import ActiveIncidentsPanel from "../ActiveIncidentsPanel/index.jsx";
-import LatestIncidentsPanel from "../LatestIncidentsPanel/index.jsx";
-import StatisticsPanel from "../StatisticsPanel/index.jsx";
-
-const IncidentsSummaryPanel = ({ updateTrigger }) => {
- const { fetchIncidentSummary } = useFetchIncidents();
- const [summary, setSummary] = useState({
- totalActive: 0,
- avgResolutionTimeHours: 0,
- total: 0,
- topMonitor: null,
- totalManualResolutions: 0,
- totalAutomaticResolutions: 0,
- latestIncidents: [],
- });
-
- const [isLoadingSummary, setIsLoadingSummary] = useState(false);
- const [summaryError, setSummaryError] = useState(null);
-
- useEffect(() => {
- const fetchSummary = async () => {
- setIsLoadingSummary(true);
- setSummaryError(null);
-
- try {
- const summaryData = await fetchIncidentSummary({
- limit: 3,
- });
-
- if (summaryData) {
- setSummary(summaryData);
- } else {
- setSummaryError(new Error("Failed to fetch summary"));
- }
- } catch (error) {
- console.error("Error fetching incident summary:", error);
- setSummaryError(error);
- } finally {
- setIsLoadingSummary(false);
- }
- };
-
- fetchSummary();
- }, [fetchIncidentSummary, updateTrigger]);
-
- return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
- >
- );
-};
-
-IncidentsSummaryPanel.propTypes = {
- updateTrigger: PropTypes.bool.isRequired,
-};
-export default IncidentsSummaryPanel;
diff --git a/client/src/Pages/Incidents/Components/IncidentsSummaryPanel/skeleton.jsx b/client/src/Pages/Incidents/Components/IncidentsSummaryPanel/skeleton.jsx
deleted file mode 100644
index 153cd7c25..000000000
--- a/client/src/Pages/Incidents/Components/IncidentsSummaryPanel/skeleton.jsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import { Skeleton } from "@mui/material";
-import SummaryCard from "../SummaryCard/index.jsx";
-
-/**
- * Simple skeleton loader for summary panels
- * Reusable for ActiveIncidentsPanel, LatestIncidentsPanel, and StatisticsPanel
- */
-const PanelSkeleton = () => {
- return (
-
-
-
- );
-};
-
-export default PanelSkeleton;
diff --git a/client/src/Pages/Incidents/Components/LatestIncidentsPanel/IncidentItem.jsx b/client/src/Pages/Incidents/Components/LatestIncidentsPanel/IncidentItem.jsx
deleted file mode 100644
index e8001087b..000000000
--- a/client/src/Pages/Incidents/Components/LatestIncidentsPanel/IncidentItem.jsx
+++ /dev/null
@@ -1,115 +0,0 @@
-import PropTypes from "prop-types";
-import { Box, Stack, Typography } from "@mui/material";
-import { useTheme } from "@emotion/react";
-import { StatusLabel } from "@/Components/v1/Label/index.jsx";
-import { getHumanReadableDuration } from "@/Utils/timeUtilsLegacy.js";
-import Icon from "@/Components/v1/Icon";
-import { useTranslation } from "react-i18next";
-import useGetIncidentsDuration from "../../hooks/useGetIncidentsDuration";
-import { Grid } from "@mui/material";
-
-const IncidentItem = ({ incident }) => {
- const { t } = useTranslation();
- const theme = useTheme();
- const isActive = incident.status === true;
- const duration = useGetIncidentsDuration(incident, isActive);
- const iconWrapperStyle = {
- display: "flex",
- justifyContent: "center",
- mx: theme.spacing(2),
- color: theme.palette.primary.contrastTextTertiary,
- "& svg": {
- width: 18,
- height: 18,
- },
- "& svg path": {
- stroke: "currentColor",
- strokeWidth: 1.5,
- },
- };
-
- return (
-
-
-
-
-
-
- {incident.monitorName || t("incidentsPage.unknownMonitor")}
-
-
-
-
-
-
-
-
- {duration}
-
-
- );
-};
-
-IncidentItem.propTypes = {
- incident: PropTypes.shape({
- _id: PropTypes.string,
- id: PropTypes.string,
- monitorId: PropTypes.string,
- monitorName: PropTypes.string,
- status: PropTypes.bool,
- startTime: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]),
- endTime: PropTypes.oneOfType([PropTypes.string, PropTypes.instanceOf(Date)]),
- resolutionType: PropTypes.oneOf(["automatic", "manual"]),
- }),
- onClick: PropTypes.func,
-};
-
-export default IncidentItem;
diff --git a/client/src/Pages/Incidents/Components/LatestIncidentsPanel/index.jsx b/client/src/Pages/Incidents/Components/LatestIncidentsPanel/index.jsx
deleted file mode 100644
index ff1ef9417..000000000
--- a/client/src/Pages/Incidents/Components/LatestIncidentsPanel/index.jsx
+++ /dev/null
@@ -1,114 +0,0 @@
-import PropTypes from "prop-types";
-import { Box, Stack, Typography, Divider } from "@mui/material";
-import { useTheme } from "@emotion/react";
-import { useTranslation } from "react-i18next";
-import PanelSkeleton from "../IncidentsSummaryPanel/skeleton.jsx";
-import IncidentItem from "./IncidentItem.jsx";
-import SummaryCard from "../SummaryCard/index.jsx";
-import Icon from "@/Components/v1/Icon";
-
-/**
- * LatestIncidentsPanel Component
- *
- * Displays a quick overview of recent incidents (both active and resolved).
- * Shows only essential information: monitor name, status, duration, and resolution type.
- *
- * @param {Object} props
- * @param {Array} props.incidents - Array of recent incidents
- * @param {boolean} props.isLoading - Loading state
- * @param {Object} props.error - Error object if any
- */
-const LatestIncidentsPanel = ({ incidents = [], isLoading = false, error = null }) => {
- const theme = useTheme();
- const { t } = useTranslation();
-
- if (isLoading) {
- return ;
- }
-
- if (error) {
- return (
-
-
-
- {t("incidentsPage.incidentsLatestPanelError")}
-
-
-
- );
- }
-
- return (
-
- {!incidents || incidents.length === 0 ? (
-
-
-
-
-
-
- {t("incidentsPage.incidentsLatestPanelEmpty")}
-
-
- ) : (
-
- {incidents.map((incident, index) => (
-
-
- {index < incidents.length - 1 && }
-
- ))}
-
- )}
-
- );
-};
-
-LatestIncidentsPanel.propTypes = {
- incidents: PropTypes.arrayOf(
- PropTypes.shape({
- _id: PropTypes.string,
- monitorId: PropTypes.string,
- monitorName: PropTypes.string,
- status: PropTypes.bool,
- duration: PropTypes.string,
- resolutionType: PropTypes.oneOf(["automatic", "manual"]),
- })
- ),
- isLoading: PropTypes.bool,
- error: PropTypes.object,
- onIncidentClick: PropTypes.func,
-};
-
-export default LatestIncidentsPanel;
diff --git a/client/src/Pages/Incidents/Components/OptionsHeader/index.jsx b/client/src/Pages/Incidents/Components/OptionsHeader/index.jsx
deleted file mode 100644
index 8d7439576..000000000
--- a/client/src/Pages/Incidents/Components/OptionsHeader/index.jsx
+++ /dev/null
@@ -1,139 +0,0 @@
-// Components
-import { Stack, Typography, Button, ButtonGroup } from "@mui/material";
-import Select from "@/Components/v1/Inputs/Select/index.jsx";
-import PropTypes from "prop-types";
-
-//Utils
-import { useTheme } from "@emotion/react";
-import { useTranslation } from "react-i18next";
-
-const OptionsHeader = ({
- shouldRender,
- selectedMonitor = 0,
- setSelectedMonitor,
- monitors,
- filter = "all",
- setFilter,
- dateRange = "all",
- setDateRange,
-}) => {
- const theme = useTheme();
- const { t } = useTranslation();
- const monitorNames = typeof monitors !== "undefined" ? Object.values(monitors) : [];
-
- const filterOptions = [
- { _id: "all", name: t("incidentsPage.incidentsOptionsHeaderFilterAll") },
- { _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 = {
- direction: "row",
- alignItems: "center",
- gap: theme.spacing(6),
- };
-
- if (!shouldRender) return;
-
- return (
-
-
-
- {t("incidentsOptionsHeader")}
-
-
-
-
- {t("incidentsOptionsHeaderFilterBy")}
-
-
-
-
- {t("incidentsOptionsHeaderShow")}
-
-
-
-
-
-
-
-
-
- );
-};
-
-OptionsHeader.propTypes = {
- shouldRender: PropTypes.bool,
- selectedMonitor: PropTypes.string,
- setSelectedMonitor: PropTypes.func,
- monitors: PropTypes.object,
- filter: PropTypes.string,
- setFilter: PropTypes.func,
- dateRange: PropTypes.string,
- setDateRange: PropTypes.func,
-};
-
-export default OptionsHeader;
diff --git a/client/src/Pages/Incidents/Components/ResolveIncidentDialog/index.jsx b/client/src/Pages/Incidents/Components/ResolveIncidentDialog/index.jsx
deleted file mode 100644
index 3e868b2dc..000000000
--- a/client/src/Pages/Incidents/Components/ResolveIncidentDialog/index.jsx
+++ /dev/null
@@ -1,101 +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 = false,
-}) => {
- 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,
- onClose: PropTypes.func.isRequired,
- onResolve: PropTypes.func.isRequired,
- onAfterResolve: PropTypes.func,
- isLoading: PropTypes.bool,
- onResolved: PropTypes.func,
-};
-
-export default ResolveIncidentDialog;
diff --git a/client/src/Pages/Incidents/Components/StatisticsPanel/index.jsx b/client/src/Pages/Incidents/Components/StatisticsPanel/index.jsx
deleted file mode 100644
index 7f07f688f..000000000
--- a/client/src/Pages/Incidents/Components/StatisticsPanel/index.jsx
+++ /dev/null
@@ -1,168 +0,0 @@
-import PropTypes from "prop-types";
-import { Box, Stack, Typography, Divider } from "@mui/material";
-import { useTheme } from "@emotion/react";
-import PanelSkeleton from "../IncidentsSummaryPanel/skeleton.jsx";
-import { useTranslation } from "react-i18next";
-import Icon from "@/Components/v1/Icon";
-import SummaryCard from "../SummaryCard/index.jsx";
-
-/**
- * StatisticsPanel Component
- *
- * Displays key metrics and statistics about incidents.
- *
- * @param {Object} props
- * @param {Object} props.statistics - Statistics data object
- * @param {number} props.statistics.total - Total incidents count
- * @param {number} props.statistics.totalTrend - Trend percentage for total (optional)
- * @param {string} props.statistics.mttr - Mean Time To Resolve (formatted string, e.g., "2h 15m")
- * @param {number} props.statistics.mttrTrend - Trend percentage for MTTR (optional)
- * @param {Object} props.statistics.topMonitor - Top monitor with most incidents
- * @param {string} props.statistics.topMonitor.name - Monitor name
- * @param {number} props.statistics.topMonitor.count - Incident count
- * @param {number} props.statistics.topMonitor.percentage - Percentage of total
- * @param {string} props.statistics.uptimeAffected - Total downtime (formatted string, e.g., "12h 45m")
- * @param {number} props.statistics.availability - Availability percentage
- * @param {boolean} props.isLoading - Loading state
- * @param {Object} props.error - Error object if any
- */
-const StatisticsPanel = ({ isLoading = false, error = null, summary = {} }) => {
- const theme = useTheme();
- const { t } = useTranslation();
- const totalResolutions =
- (summary?.totalManualResolutions || 0) + (summary?.totalAutomaticResolutions || 0);
-
- const iconWrapperStyle = {
- display: "flex",
- justifyContent: "center",
- mx: theme.spacing(2),
- color: theme.palette.primary.contrastTextTertiary,
- "& svg": {
- width: 18,
- height: 18,
- },
- "& svg path": {
- stroke: "currentColor",
- strokeWidth: 1.5,
- },
- };
- if (isLoading) {
- return ;
- }
-
- if (error) {
- return (
-
-
-
- {t("incidentsPage.incidentsStatisticsPanelError")}
-
-
-
- );
- }
-
- const getMostAffectedMonitor = () => {
- if (!summary.total || summary.total === 0) {
- return t("incidentsPage.none");
- }
- return summary.topMonitor?.monitorName || t("incidentsPage.none");
- };
-
- const rowStyle = {
- py: theme.spacing(0.5),
- minHeight: 32,
- };
-
- return (
-
-
-
-
-
-
-
-
- {t("incidentsPage.totalIncidents")}: {summary.total || 0}
-
-
-
-
-
-
-
-
-
-
- {t("incidentsPage.mostAffectedMonitor")}: {getMostAffectedMonitor()}
-
-
-
-
-
-
-
-
-
- {t("incidentsPage.avgResolutionTime")}:{" "}
- {summary.total > 0
- ? `${summary.avgResolutionTimeHours || 0} ${t("incidentsPage.hours")}`
- : "N/A"}
-
-
-
-
- );
-};
-
-StatisticsPanel.propTypes = {
- summary: PropTypes.object,
- isLoading: PropTypes.bool,
- error: PropTypes.object,
-};
-
-export default StatisticsPanel;
diff --git a/client/src/Pages/Incidents/Components/SummaryCard/index.jsx b/client/src/Pages/Incidents/Components/SummaryCard/index.jsx
deleted file mode 100644
index 3a8589dc1..000000000
--- a/client/src/Pages/Incidents/Components/SummaryCard/index.jsx
+++ /dev/null
@@ -1,64 +0,0 @@
-import { Paper } from "@mui/material";
-import { useTheme } from "@mui/material/styles";
-import PropTypes from "prop-types";
-import { Box, Stack, Typography, Divider } from "@mui/material";
-const SummaryCard = ({ children, isHighPriority = false, sx = {}, title = null }) => {
- const theme = useTheme();
- return (
-
- {title && (
-
-
-
- {title}
-
-
-
-
- )}
-
- {children}
-
-
- );
-};
-SummaryCard.propTypes = {
- children: PropTypes.node,
- isHighPriority: PropTypes.bool,
- sx: PropTypes.object,
- title: PropTypes.string,
-};
-export default SummaryCard;
diff --git a/client/src/Pages/Incidents/hooks/useFetchIncidents.js b/client/src/Pages/Incidents/hooks/useFetchIncidents.js
deleted file mode 100644
index e308c9319..000000000
--- a/client/src/Pages/Incidents/hooks/useFetchIncidents.js
+++ /dev/null
@@ -1,215 +0,0 @@
-import { useState, useCallback } from "react";
-import { networkService } from "../../../main.jsx";
-import { createToast } from "../../../Utils/toastUtils.jsx";
-import { useTranslation } from "react-i18next";
-/**
- * Hook to fetch and manage incidents
- *
- * Provides multiple functions to fetch incidents with different filters.
- *
- * @returns {Object} {
- * incidents,
- * incidentsCount,
- * isLoading,
- * networkError,
- * fetchIncidents,
- * fetchActiveIncidents,
- * fetchResolvedIncidents,
- * fetchIncidentsByTeam,
- * fetchIncidentById,
- * resolveIncident,
- * fetchIncidentSummary
- * }
- */
-const useFetchIncidents = () => {
- const [incidents, setIncidents] = useState(null);
- const [incidentsCount, setIncidentsCount] = useState(null);
- const [isLoading, setIsLoading] = useState(false);
- const [networkError, setNetworkError] = useState(false);
- const { t } = useTranslation();
- /**
- * Generic function to fetch incidents by team with custom config
- *
- * @param {Object} config - Configuration object
- * @param {string} [config.monitorId] - Filter by monitor ID
- * @param {boolean} [config.status] - Filter by status (true=active, false=resolved)
- * @param {string} [config.resolutionType] - Filter by resolution type (automatic/manual)
- * @param {string} [config.sortOrder] - Sort order (asc/desc)
- * @param {string} [config.dateRange] - Date range filter
- * @param {number} [config.page] - Page number
- * @param {number} [config.rowsPerPage] - Rows per page
- */
- const fetchIncidentsByTeam = useCallback(async (config = {}) => {
- try {
- setIsLoading(true);
- setNetworkError(false);
-
- const res = await networkService.getIncidentsByTeam(config);
- setIncidents(res.data?.data?.incidents || []);
- setIncidentsCount(res.data?.data?.count || 0);
- } catch (error) {
- setNetworkError(true);
- console.error(t("incidentsPage.errorFetchingIncidents"), error);
- createToast({ body: error.message || t("incidentsPage.errorFetchingIncidents") });
- } finally {
- setIsLoading(false);
- }
- }, []);
-
- /**
- * Fetch active (open) incidents - Default function
- *
- * @param {Object} config - Additional configuration
- */
- const fetchActiveIncidents = useCallback(
- async (config = {}) => {
- await fetchIncidentsByTeam({
- status: true,
- sortOrder: "desc",
- ...config,
- });
- },
- [fetchIncidentsByTeam]
- );
-
- const fetchIncidentsByResolutionType = useCallback(
- async (resolutionType, config = {}) => {
- await fetchIncidentsByTeam({
- resolutionType,
- sortOrder: "desc",
- ...config,
- });
- },
- [fetchIncidentsByTeam]
- );
- /**
- * Fetch resolved incidents
- *
- * @param {Object} config - Additional configuration
- */
- const fetchResolvedIncidents = useCallback(
- async (config = {}) => {
- await fetchIncidentsByTeam({
- status: false,
- sortOrder: "desc",
- ...config,
- });
- },
- [fetchIncidentsByTeam]
- );
-
- /**
- * Fetch incidents with custom filters (alias for fetchIncidentsByTeam)
- *
- * @param {Object} config - Configuration object
- */
- const fetchIncidents = useCallback(
- async (config = {}) => {
- await fetchIncidentsByTeam(config);
- },
- [fetchIncidentsByTeam]
- );
-
- /**
- * Fetch a single incident by ID
- *
- * @param {string} incidentId - The ID of the incident to fetch
- * @returns {Promise