From 427e5a18eab629713ba93ea4b1187bc5a0976845 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Tue, 20 Jan 2026 19:12:05 +0000 Subject: [PATCH] incidents -> checks --- .../Checks/Components/IncidentTable/index.jsx | 264 ++++++++++++++++ .../Components/OptionsHeader/index.jsx | 15 +- .../Components/OptionsHeader/skeleton.jsx | 0 .../Components/StatusBoxes/StatusBox.jsx | 0 .../Components/StatusBoxes/index.jsx | 0 .../Components/StatusBoxes/skeleton.jsx | 0 client/src/Pages/Checks/index.jsx | 120 +++++++ .../Components/ActiveIncidentsPanel/index.jsx | 0 .../Components/IncidentTable/index.jsx | 293 +++++++----------- .../IncidentsSummaryPanel/index.jsx | 0 .../IncidentsSummaryPanel/skeleton.jsx | 0 .../LatestIncidentsPanel/IncidentItem.jsx | 0 .../Components/LatestIncidentsPanel/index.jsx | 0 .../Components/OptionsHeader/index.jsx | 15 +- .../Components/StatisticsPanel/index.jsx | 0 .../Components/SummaryCard/index.jsx | 0 .../hooks/useFetchIncidents.js | 0 client/src/Pages/Incidents/index.jsx | 153 +++++---- .../Components/IncidentTable/index.jsx | 209 ------------- client/src/Pages/Incidents2/index.jsx | 151 --------- client/src/Routes/index.jsx | 8 +- 21 files changed, 615 insertions(+), 613 deletions(-) create mode 100644 client/src/Pages/Checks/Components/IncidentTable/index.jsx rename client/src/Pages/{Incidents2 => Checks}/Components/OptionsHeader/index.jsx (87%) rename client/src/Pages/{Incidents => Checks}/Components/OptionsHeader/skeleton.jsx (100%) rename client/src/Pages/{Incidents => Checks}/Components/StatusBoxes/StatusBox.jsx (100%) rename client/src/Pages/{Incidents => Checks}/Components/StatusBoxes/index.jsx (100%) rename client/src/Pages/{Incidents => Checks}/Components/StatusBoxes/skeleton.jsx (100%) create mode 100644 client/src/Pages/Checks/index.jsx rename client/src/Pages/{Incidents2 => Incidents}/Components/ActiveIncidentsPanel/index.jsx (100%) rename client/src/Pages/{Incidents2 => Incidents}/Components/IncidentsSummaryPanel/index.jsx (100%) rename client/src/Pages/{Incidents2 => Incidents}/Components/IncidentsSummaryPanel/skeleton.jsx (100%) rename client/src/Pages/{Incidents2 => Incidents}/Components/LatestIncidentsPanel/IncidentItem.jsx (100%) rename client/src/Pages/{Incidents2 => Incidents}/Components/LatestIncidentsPanel/index.jsx (100%) rename client/src/Pages/{Incidents2 => Incidents}/Components/StatisticsPanel/index.jsx (100%) rename client/src/Pages/{Incidents2 => Incidents}/Components/SummaryCard/index.jsx (100%) rename client/src/Pages/{Incidents2 => Incidents}/hooks/useFetchIncidents.js (100%) delete mode 100644 client/src/Pages/Incidents2/Components/IncidentTable/index.jsx delete mode 100644 client/src/Pages/Incidents2/index.jsx diff --git a/client/src/Pages/Checks/Components/IncidentTable/index.jsx b/client/src/Pages/Checks/Components/IncidentTable/index.jsx new file mode 100644 index 000000000..e066049e6 --- /dev/null +++ b/client/src/Pages/Checks/Components/IncidentTable/index.jsx @@ -0,0 +1,264 @@ +//Components +import Stack from "@mui/material/Stack"; +import DataTable from "@/Components/v1/Table/index.jsx"; +import Table from "@mui/material/Table"; +import TableBody from "@mui/material/TableBody"; +import TableRow from "@mui/material/TableRow"; +import TableCell from "@mui/material/TableCell"; +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"; + +//Utils +import { formatDateWithTz } from "@/Utils/timeUtils.js"; +import { useSelector } from "react-redux"; +import { useState } from "react"; +import PropTypes from "prop-types"; +import { useTranslation } from "react-i18next"; +import { + useFetchChecksTeam, + useFetchChecksByMonitor, + useResolveIncident, +} from "@/Hooks/checkHooks.js"; +import { Button, Typography, useTheme } from "@mui/material"; +import { lighten } from "@mui/material/styles"; + +const GetTooltip = (row) => { + const theme = useTheme(); + const phases = row?.timings?.phases; + + const phaseKeyFormattingMap = { + firstByte: "first byte", + }; + return ( + + {`Status code: ${row?.statusCode}`} + {`Response time: ${row?.responseTime} ms`} + {phases && ( + <> + {`Request timing: `} + + + {Object.keys(phases)?.map((phaseKey) => ( + + + + {`${phaseKeyFormattingMap[phaseKey] || phaseKey}:`} + + + + {`${phases[phaseKey]} ms`} + + + ))} + +
+ + )} +
+ ); +}; + +const IncidentTable = ({ + isLoading, + monitors, + selectedMonitor, + filter, + dateRange, + updateTrigger, + setUpdateTrigger, +}) => { + //Redux state + const uiTimezone = useSelector((state) => state.ui.timezone); + + //Local state + const [page, setPage] = useState(0); + const [rowsPerPage, setRowsPerPage] = useState(10); + const selectedMonitorDetails = monitors?.[selectedMonitor]; + const selectedMonitorType = selectedMonitorDetails?.type; + + //Hooks + const [resolveIncident, resolveLoading] = useResolveIncident(); + + const [checksMonitor, checksCountMonitor, isLoadingMonitor, networkErrorMonitor] = + useFetchChecksByMonitor({ + monitorId: selectedMonitor === "0" ? undefined : selectedMonitor, + type: selectedMonitorType, + status: false, + sortOrder: "desc", + limit: null, + dateRange, + filter: filter === "resolved" ? "all" : filter, + ack: filter === "resolved" ? true : false, + page: page, + rowsPerPage: rowsPerPage, + enabled: selectedMonitor !== "0", + updateTrigger, + }); + + const [checksTeam, checksCountTeam, isLoadingTeam, networkErrorTeam] = + useFetchChecksTeam({ + status: false, + sortOrder: "desc", + limit: null, + dateRange, + filter: filter === "resolved" ? "all" : filter, + ack: filter === "resolved" ? true : false, + page: page, + rowsPerPage: rowsPerPage, + enabled: selectedMonitor === "0", + updateTrigger, + }); + + const checks = selectedMonitor === "0" ? checksTeam : checksMonitor; + const checksCount = selectedMonitor === "0" ? checksCountTeam : checksCountMonitor; + isLoading = isLoadingTeam || isLoadingMonitor; + const networkError = selectedMonitor === "0" ? networkErrorTeam : networkErrorMonitor; + + const { t } = useTranslation(); + + //Handlers + const handleChangePage = (_, newPage) => { + setPage(newPage); + }; + + const handleChangeRowsPerPage = (event) => { + setRowsPerPage(event.target.value); + }; + + const handleResolveIncident = (checkId) => { + resolveIncident(checkId, setUpdateTrigger); + }; + + const headers = [ + { + id: "monitorName", + content: t("incidentsTableMonitorName"), + render: (row) => monitors[row.monitorId]?.name ?? "N/A", + }, + { + id: "status", + content: t("incidentsTableStatus"), + render: (row) => { + const status = row.status === true ? "up" : "down"; + return ( + + ); + }, + }, + { + id: "dateTime", + content: t("incidentsTableDateTime"), + render: (row) => { + const formattedDate = formatDateWithTz( + row.createdAt, + "YYYY-MM-DD HH:mm:ss A", + uiTimezone + ); + return formattedDate; + }, + }, + { + id: "statusCode", + content: t("incidentsTableStatusCode"), + render: (row) => , + }, + { id: "message", content: t("incidentsTableMessage"), render: (row) => row.message }, + { + id: "action", + content: t("actions"), + render: (row) => { + return row.ack === false ? ( + + ) : ( + + {t("incidentsTableResolvedAt")}{" "} + {formatDateWithTz(row.ackAt, "YYYY-MM-DD HH:mm:ss A", uiTimezone)} + + ); + }, + }, + ]; + + if (isLoading || resolveLoading) return ; + + if (networkError) { + return ( + + + + ); + } + + if (!isLoading && typeof checksCount === "undefined") { + return {t("incidentsTableNoIncidents")}; + } + + return ( + <> + + + + ); +}; + +IncidentTable.propTypes = { + isLoading: PropTypes.bool, + monitors: PropTypes.object, + selectedMonitor: PropTypes.string, + filter: PropTypes.string, + dateRange: PropTypes.string, + updateTrigger: PropTypes.bool, + setUpdateTrigger: PropTypes.func, +}; +export default IncidentTable; diff --git a/client/src/Pages/Incidents2/Components/OptionsHeader/index.jsx b/client/src/Pages/Checks/Components/OptionsHeader/index.jsx similarity index 87% rename from client/src/Pages/Incidents2/Components/OptionsHeader/index.jsx rename to client/src/Pages/Checks/Components/OptionsHeader/index.jsx index 3a0ca1985..c16f54f18 100644 --- a/client/src/Pages/Incidents2/Components/OptionsHeader/index.jsx +++ b/client/src/Pages/Checks/Components/OptionsHeader/index.jsx @@ -5,6 +5,7 @@ import PropTypes from "prop-types"; //Utils import { useTheme } from "@emotion/react"; +import SkeletonLayout from "./skeleton.jsx"; import { useTranslation } from "react-i18next"; const OptionsHeader = ({ @@ -14,27 +15,27 @@ const OptionsHeader = ({ monitors, filter = "all", setFilter, - dateRange = "all", + dateRange = "hour", 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: "all", name: t("incidentsOptionsHeaderFilterAll") }, + { _id: "down", name: t("incidentsOptionsHeaderFilterDown") }, + { _id: "resolve", name: t("incidentsOptionsHeaderFilterCannotResolve") }, + { _id: "resolved", name: t("incidentsOptionsHeaderFilterResolved") }, ]; + // The stacks below which are three in number have the same style so const stackStyles = { direction: "row", alignItems: "center", gap: theme.spacing(6), }; - if (!shouldRender) return; + if (!shouldRender) return ; return ( { + // Redux state + const { t } = useTranslation(); + + const BREADCRUMBS = [{ name: t("checksPageTitle"), path: "/checks" }]; + + // Local state + const [selectedMonitor, setSelectedMonitor] = useState("0"); + const [filter, setFilter] = useState(undefined); + const [dateRange, setDateRange] = useState(undefined); + const [monitorLookup, setMonitorLookup] = useState(undefined); + const [updateTrigger, setUpdateTrigger] = useState(false); + + //Hooks + const { acknowledge, isLoadingAcknowledge } = useAcknowledgeChecks(); + + //Utils + const theme = useTheme(); + const [monitors, , isLoading, networkError] = useFetchMonitorsByTeamId({}); + const [summary, isLoadingSummary, networkErrorSummary] = useFetchChecksSummaryByTeamId({ + updateTrigger, + }); + const { monitorId } = useParams(); + + useEffect(() => { + if (monitorId) { + setSelectedMonitor(monitorId); + } + }, [monitorId]); + + useEffect(() => { + const monitorLookup = monitors?.reduce((acc, monitor) => { + acc[monitor._id] = { + _id: monitor._id, + name: monitor.name, + type: monitor.type, + }; + return acc; + }, {}); + setMonitorLookup(monitorLookup); + }, [monitors]); + + const handleAcknowledge = () => { + const monitorId = selectedMonitor === "0" ? null : selectedMonitor; + acknowledge(setUpdateTrigger, monitorId); + }; + + if (networkError || networkErrorSummary) { + return ( + + + + ); + } + + return ( + + + + + + + + + + ); +}; + +export default Checks; diff --git a/client/src/Pages/Incidents2/Components/ActiveIncidentsPanel/index.jsx b/client/src/Pages/Incidents/Components/ActiveIncidentsPanel/index.jsx similarity index 100% rename from client/src/Pages/Incidents2/Components/ActiveIncidentsPanel/index.jsx rename to client/src/Pages/Incidents/Components/ActiveIncidentsPanel/index.jsx diff --git a/client/src/Pages/Incidents/Components/IncidentTable/index.jsx b/client/src/Pages/Incidents/Components/IncidentTable/index.jsx index e066049e6..670da4a81 100644 --- a/client/src/Pages/Incidents/Components/IncidentTable/index.jsx +++ b/client/src/Pages/Incidents/Components/IncidentTable/index.jsx @@ -1,10 +1,5 @@ //Components -import Stack from "@mui/material/Stack"; import DataTable from "@/Components/v1/Table/index.jsx"; -import Table from "@mui/material/Table"; -import TableBody from "@mui/material/TableBody"; -import TableRow from "@mui/material/TableRow"; -import TableCell from "@mui/material/TableCell"; 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"; @@ -13,213 +8,154 @@ import GenericFallback from "@/Components/v1/GenericFallback/index.jsx"; import NetworkError from "@/Components/v1/GenericFallback/NetworkError.jsx"; //Utils -import { formatDateWithTz } from "@/Utils/timeUtils.js"; +import { formatDateWithTz } from "../../../../Utils/timeUtils.js"; import { useSelector } from "react-redux"; -import { useState } from "react"; import PropTypes from "prop-types"; import { useTranslation } from "react-i18next"; -import { - useFetchChecksTeam, - useFetchChecksByMonitor, - useResolveIncident, -} from "@/Hooks/checkHooks.js"; import { Button, Typography, useTheme } from "@mui/material"; -import { lighten } from "@mui/material/styles"; - -const GetTooltip = (row) => { - const theme = useTheme(); - const phases = row?.timings?.phases; - - const phaseKeyFormattingMap = { - firstByte: "first byte", - }; - return ( - - {`Status code: ${row?.statusCode}`} - {`Response time: ${row?.responseTime} ms`} - {phases && ( - <> - {`Request timing: `} - - - {Object.keys(phases)?.map((phaseKey) => ( - - - - {`${phaseKeyFormattingMap[phaseKey] || phaseKey}:`} - - - - {`${phases[phaseKey]} ms`} - - - ))} - -
- - )} -
- ); -}; const IncidentTable = ({ - isLoading, - monitors, - selectedMonitor, - filter, - dateRange, - updateTrigger, - setUpdateTrigger, + monitors = [], + incidents = [], + incidentsCount = 0, + isLoading = false, + networkError = false, + page = 0, + rowsPerPage = 10, + handleChangePage, + handleChangeRowsPerPage, + resolveIncident, + handleUpdateTrigger, }) => { - //Redux state const uiTimezone = useSelector((state) => state.ui.timezone); - //Local state - const [page, setPage] = useState(0); - const [rowsPerPage, setRowsPerPage] = useState(10); - const selectedMonitorDetails = monitors?.[selectedMonitor]; - const selectedMonitorType = selectedMonitorDetails?.type; - - //Hooks - const [resolveIncident, resolveLoading] = useResolveIncident(); - - const [checksMonitor, checksCountMonitor, isLoadingMonitor, networkErrorMonitor] = - useFetchChecksByMonitor({ - monitorId: selectedMonitor === "0" ? undefined : selectedMonitor, - type: selectedMonitorType, - status: false, - sortOrder: "desc", - limit: null, - dateRange, - filter: filter === "resolved" ? "all" : filter, - ack: filter === "resolved" ? true : false, - page: page, - rowsPerPage: rowsPerPage, - enabled: selectedMonitor !== "0", - updateTrigger, - }); - - const [checksTeam, checksCountTeam, isLoadingTeam, networkErrorTeam] = - useFetchChecksTeam({ - status: false, - sortOrder: "desc", - limit: null, - dateRange, - filter: filter === "resolved" ? "all" : filter, - ack: filter === "resolved" ? true : false, - page: page, - rowsPerPage: rowsPerPage, - enabled: selectedMonitor === "0", - updateTrigger, - }); - - const checks = selectedMonitor === "0" ? checksTeam : checksMonitor; - const checksCount = selectedMonitor === "0" ? checksCountTeam : checksCountMonitor; - isLoading = isLoadingTeam || isLoadingMonitor; - const networkError = selectedMonitor === "0" ? networkErrorTeam : networkErrorMonitor; - const { t } = useTranslation(); + const theme = useTheme(); - //Handlers - const handleChangePage = (_, newPage) => { - setPage(newPage); - }; - - const handleChangeRowsPerPage = (event) => { - setRowsPerPage(event.target.value); - }; - - const handleResolveIncident = (checkId) => { - resolveIncident(checkId, setUpdateTrigger); + const handleResolveIncident = async (incidentId) => { + try { + await resolveIncident(incidentId); + handleUpdateTrigger(); + } catch (error) { + console.error(t("incidentsPage.errorResolvingIncident"), error); + } }; const headers = [ { id: "monitorName", content: t("incidentsTableMonitorName"), - render: (row) => monitors[row.monitorId]?.name ?? "N/A", + render: (row) => { + console.log(monitors, 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 ? "up" : "down"; + const status = row.status === true ? "down" : "up"; + const statusText = + row.status === true ? t("incidentsPage.active") : t("incidentsPage.resolved"); return ( ); }, }, { - id: "dateTime", - content: t("incidentsTableDateTime"), + id: "startTime", + content: t("incidentsPage.startTime"), render: (row) => { const formattedDate = formatDateWithTz( - row.createdAt, + 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: "message", + content: t("incidentsTableMessage"), + render: (row) => row.message || "-", + }, { id: "action", content: t("actions"), render: (row) => { - return row.ack === false ? ( - - ) : ( - - {t("incidentsTableResolvedAt")}{" "} - {formatDateWithTz(row.ackAt, "YYYY-MM-DD HH:mm:ss A", uiTimezone)} - - ); + if (row.status === true) { + return ( + + ); + } else { + return ( + + {t("incidentsPage.incidentsTableResolved")} + + ); + } }, }, ]; - if (isLoading || resolveLoading) return ; + if (isLoading) return ; if (networkError) { return ( @@ -229,20 +165,25 @@ const IncidentTable = ({ ); } - if (!isLoading && typeof checksCount === "undefined") { - return {t("incidentsTableNoIncidents")}; + if (!isLoading && !networkError && incidents?.length === 0) { + return ( + + {t("incidentsTableNoIncidents", "No incidents found")} + + ); } + const incidentsData = Array.isArray(incidents) ? incidents : []; + return ( <> { const theme = useTheme(); const { t } = useTranslation(); const monitorNames = typeof monitors !== "undefined" ? Object.values(monitors) : []; + const filterOptions = [ - { _id: "all", name: t("incidentsOptionsHeaderFilterAll") }, - { _id: "down", name: t("incidentsOptionsHeaderFilterDown") }, - { _id: "resolve", name: t("incidentsOptionsHeaderFilterCannotResolve") }, - { _id: "resolved", name: t("incidentsOptionsHeaderFilterResolved") }, + { _id: "all", name: t("incidentsPage.incidentsOptionsHeaderFilterAll") }, + { _id: "active", name: t("incidentsPage.incidentsOptionsHeaderFilterActive") }, + { _id: "resolved", name: t("incidentsPage.incidentsOptionsHeaderFilterResolved") }, + { _id: "manual", name: t("incidentsPage.incidentsOptionsHeaderFilterManual") }, ]; - // The stacks below which are three in number have the same style so const stackStyles = { direction: "row", alignItems: "center", gap: theme.spacing(6), }; - if (!shouldRender) return ; + if (!shouldRender) return; return ( { - // Redux state +// Hooks +import useFetchIncidents from "./hooks/useFetchIncidents.js"; +import { useFetchMonitorsByTeamId } from "../../Hooks/monitorHooks.js"; + +const Incidents2 = () => { const { t } = useTranslation(); - const BREADCRUMBS = [{ name: t("checksPageTitle"), path: "/checks" }]; + const BREADCRUMBS = [ + { name: t("incidentsPageTitle", "Incidents"), path: "/incidents" }, + ]; - // Local state const [selectedMonitor, setSelectedMonitor] = useState("0"); - const [filter, setFilter] = useState(undefined); - const [dateRange, setDateRange] = useState(undefined); + const [filter, setFilter] = useState("all"); + const [dateRange, setDateRange] = useState("all"); + const [page, setPage] = useState(0); + const [rowsPerPage, setRowsPerPage] = useState(10); const [monitorLookup, setMonitorLookup] = useState(undefined); const [updateTrigger, setUpdateTrigger] = useState(false); + const handleUpdateTrigger = () => { + setUpdateTrigger((prev) => !prev); + }; - //Hooks - const { acknowledge, isLoadingAcknowledge } = useAcknowledgeChecks(); + const [monitors, isLoadingMonitors, monitorsNetworkError] = useFetchMonitorsByTeamId( + {} + ); + + const { + incidents, + incidentsCount, + isLoading: isLoadingIncidents, + networkError: incidentsNetworkError, + fetchIncidents, + fetchActiveIncidents, + fetchResolvedIncidents, + resolveIncident, + } = useFetchIncidents(); + + const networkError = monitorsNetworkError || incidentsNetworkError; - //Utils const theme = useTheme(); - const [monitors, , isLoading, networkError] = useFetchMonitorsByTeamId({}); - const [summary, isLoadingSummary, networkErrorSummary] = useFetchChecksSummaryByTeamId({ - updateTrigger, - }); - const { monitorId } = useParams(); useEffect(() => { - if (monitorId) { - setSelectedMonitor(monitorId); + setPage(0); + }, [selectedMonitor, filter, dateRange]); + + useEffect(() => { + const config = { + monitorId: selectedMonitor !== "0" ? selectedMonitor : undefined, + sortOrder: "desc", + dateRange, + page, + rowsPerPage, + }; + + if (filter === "active") { + fetchActiveIncidents(config); + } else if (filter === "resolved") { + fetchResolvedIncidents(config); + } else { + fetchIncidents(config); } - }, [monitorId]); + }, [ + selectedMonitor, + filter, + dateRange, + page, + rowsPerPage, + updateTrigger, + fetchActiveIncidents, + fetchResolvedIncidents, + fetchIncidents, + ]); useEffect(() => { - const monitorLookup = monitors?.reduce((acc, monitor) => { - acc[monitor._id] = { - _id: monitor._id, + const lookup = monitors?.reduce((acc, monitor) => { + acc[monitor.id] = { + id: monitor.id, name: monitor.name, type: monitor.type, }; return acc; }, {}); - setMonitorLookup(monitorLookup); + setMonitorLookup(lookup); }, [monitors]); - const handleAcknowledge = () => { - const monitorId = selectedMonitor === "0" ? null : selectedMonitor; - acknowledge(setUpdateTrigger, monitorId); - }; - - if (networkError || networkErrorSummary) { + if (networkError) { return ( @@ -75,27 +105,23 @@ const Checks = () => { ); } + const handleChangePage = (_, newPage) => { + setPage(newPage); + }; + + const handleChangeRowsPerPage = (event) => { + setRowsPerPage(parseInt(event.target.value, 10)); + setPage(0); + }; + return ( - - - - + + + { dateRange={dateRange} setDateRange={setDateRange} /> + ); }; -export default Checks; +export default Incidents2; diff --git a/client/src/Pages/Incidents2/Components/IncidentTable/index.jsx b/client/src/Pages/Incidents2/Components/IncidentTable/index.jsx deleted file mode 100644 index 670da4a81..000000000 --- a/client/src/Pages/Incidents2/Components/IncidentTable/index.jsx +++ /dev/null @@ -1,209 +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"; - -//Utils -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"; - -const IncidentTable = ({ - monitors = [], - incidents = [], - incidentsCount = 0, - isLoading = false, - networkError = false, - page = 0, - rowsPerPage = 10, - handleChangePage, - handleChangeRowsPerPage, - resolveIncident, - handleUpdateTrigger, -}) => { - const uiTimezone = useSelector((state) => state.ui.timezone); - - const { t } = useTranslation(); - const theme = useTheme(); - - const handleResolveIncident = async (incidentId) => { - try { - await resolveIncident(incidentId); - handleUpdateTrigger(); - } catch (error) { - console.error(t("incidentsPage.errorResolvingIncident"), error); - } - }; - - const headers = [ - { - 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"; - }, - }, - { - 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) => { - if (row.status === true) { - return ( - - ); - } else { - return ( - - {t("incidentsPage.incidentsTableResolved")} - - ); - } - }, - }, - ]; - - 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, -}; - -export default IncidentTable; diff --git a/client/src/Pages/Incidents2/index.jsx b/client/src/Pages/Incidents2/index.jsx deleted file mode 100644 index 4e68279c5..000000000 --- a/client/src/Pages/Incidents2/index.jsx +++ /dev/null @@ -1,151 +0,0 @@ -// Components -import { Stack } from "@mui/material"; -import Breadcrumbs from "@/Components/v1/Breadcrumbs/index.jsx"; -import GenericFallback from "@/Components/v1/GenericFallback/index.jsx"; -import IncidentTable from "./Components/IncidentTable/index.jsx"; -import OptionsHeader from "./Components/OptionsHeader/index.jsx"; -import IncidentsSummaryPanel from "./Components/IncidentsSummaryPanel/index.jsx"; - -//Utils -import { useTheme } from "@emotion/react"; -import { useState, useEffect } from "react"; -import NetworkError from "@/Components/v1/GenericFallback/NetworkError.jsx"; -import { useTranslation } from "react-i18next"; - -// Hooks -import useFetchIncidents from "./hooks/useFetchIncidents.js"; -import { useFetchMonitorsByTeamId } from "../../Hooks/monitorHooks.js"; - -const Incidents2 = () => { - const { t } = useTranslation(); - - const BREADCRUMBS = [ - { name: t("incidentsPageTitle", "Incidents"), path: "/incidents" }, - ]; - - const [selectedMonitor, setSelectedMonitor] = useState("0"); - const [filter, setFilter] = useState("all"); - const [dateRange, setDateRange] = useState("all"); - const [page, setPage] = useState(0); - const [rowsPerPage, setRowsPerPage] = useState(10); - const [monitorLookup, setMonitorLookup] = useState(undefined); - const [updateTrigger, setUpdateTrigger] = useState(false); - const handleUpdateTrigger = () => { - setUpdateTrigger((prev) => !prev); - }; - - const [monitors, isLoadingMonitors, monitorsNetworkError] = useFetchMonitorsByTeamId( - {} - ); - - const { - incidents, - incidentsCount, - isLoading: isLoadingIncidents, - networkError: incidentsNetworkError, - fetchIncidents, - fetchActiveIncidents, - fetchResolvedIncidents, - resolveIncident, - } = useFetchIncidents(); - - const networkError = monitorsNetworkError || incidentsNetworkError; - - const theme = useTheme(); - - useEffect(() => { - setPage(0); - }, [selectedMonitor, filter, dateRange]); - - useEffect(() => { - const config = { - monitorId: selectedMonitor !== "0" ? selectedMonitor : undefined, - sortOrder: "desc", - dateRange, - page, - rowsPerPage, - }; - - if (filter === "active") { - fetchActiveIncidents(config); - } else if (filter === "resolved") { - fetchResolvedIncidents(config); - } else { - fetchIncidents(config); - } - }, [ - selectedMonitor, - filter, - dateRange, - page, - rowsPerPage, - updateTrigger, - fetchActiveIncidents, - fetchResolvedIncidents, - fetchIncidents, - ]); - - useEffect(() => { - const lookup = monitors?.reduce((acc, monitor) => { - acc[monitor.id] = { - id: monitor.id, - name: monitor.name, - type: monitor.type, - }; - return acc; - }, {}); - setMonitorLookup(lookup); - }, [monitors]); - - if (networkError) { - return ( - - - - ); - } - - const handleChangePage = (_, newPage) => { - setPage(newPage); - }; - - const handleChangeRowsPerPage = (event) => { - setRowsPerPage(parseInt(event.target.value, 10)); - setPage(0); - }; - - return ( - - - - - - - - - - ); -}; - -export default Incidents2; diff --git a/client/src/Routes/index.jsx b/client/src/Routes/index.jsx index d9f6d58cb..878b17b09 100644 --- a/client/src/Routes/index.jsx +++ b/client/src/Routes/index.jsx @@ -28,9 +28,11 @@ import InfrastructureDetails from "../Pages/Infrastructure/Details/index.jsx"; // Server Status import ServerUnreachable from "../Pages/ServerUnreachable.jsx"; +// Checks +import Checks from "../Pages/Checks/index.jsx"; + // Incidents -import Checks from "../Pages/Incidents"; -import Incidents2 from "../Pages/Incidents2/index.jsx"; +import Incidents from "../Pages/Incidents/index.jsx"; // Status pages import CreateStatus from "../Pages/StatusPage/Create/index.jsx"; @@ -136,7 +138,7 @@ const Routes = () => { /> } + element={} />