diff --git a/Client/src/Components/GenericFallback/NetworkError.jsx b/Client/src/Components/GenericFallback/NetworkError.jsx new file mode 100644 index 000000000..b26037a57 --- /dev/null +++ b/Client/src/Components/GenericFallback/NetworkError.jsx @@ -0,0 +1,20 @@ +import { Typography } from "@mui/material"; +import { useTheme } from "@emotion/react"; + +const NetworkError = () => { + const theme = useTheme(); + return ( + <> + + Network error + + Please check your connection + + ); +}; + +export default NetworkError; diff --git a/Client/src/Components/NetworkErrorFallback/index.jsx b/Client/src/Components/GenericFallback/index.jsx similarity index 81% rename from Client/src/Components/NetworkErrorFallback/index.jsx rename to Client/src/Components/GenericFallback/index.jsx index 1039b256b..af9ed2ea4 100644 --- a/Client/src/Components/NetworkErrorFallback/index.jsx +++ b/Client/src/Components/GenericFallback/index.jsx @@ -1,5 +1,5 @@ import { useTheme } from "@emotion/react"; -import { Box, Stack, Typography } from "@mui/material"; +import { Box, Stack } from "@mui/material"; import Skeleton from "../../assets/Images/create-placeholder.svg?react"; import SkeletonDark from "../../assets/Images/create-placeholder-dark.svg?react"; import Background from "../../assets/Images/background-grid.svg?react"; @@ -11,13 +11,13 @@ import { useSelector } from "react-redux"; * @returns {JSX.Element} The rendered fallback UI. */ -const NetworkErrorFallback = () => { +const GenericFallback = ({ children }) => { const theme = useTheme(); const mode = useSelector((state) => state.ui.mode); return ( { maxWidth={"300px"} zIndex={1} > - - Network error - - Please check your connection + {children} ); }; -export default NetworkErrorFallback; +export default GenericFallback; diff --git a/Client/src/Components/Table/TablePagination/index.jsx b/Client/src/Components/Table/TablePagination/index.jsx index 014e2405f..8427f4270 100644 --- a/Client/src/Components/Table/TablePagination/index.jsx +++ b/Client/src/Components/Table/TablePagination/index.jsx @@ -8,7 +8,7 @@ Pagination.propTypes = { paginationLabel: PropTypes.string, // Label for the pagination. itemCount: PropTypes.number, // Total number of items for pagination. page: PropTypes.number, // Current page index. - rowsPerPage: PropTypes.number.isRequired, // Number of rows displayed per page. + rowsPerPage: PropTypes.number, // Number of rows displayed per page. handleChangePage: PropTypes.func.isRequired, // Function to handle page changes. handleChangeRowsPerPage: PropTypes.func, // Function to handle changes in rows per page. }; diff --git a/Client/src/Pages/Uptime/Monitors/Components/UptimeDataTable/skeleton.jsx b/Client/src/Components/Table/skeleton.jsx similarity index 56% rename from Client/src/Pages/Uptime/Monitors/Components/UptimeDataTable/skeleton.jsx rename to Client/src/Components/Table/skeleton.jsx index e3c4fa2e2..062d39156 100644 --- a/Client/src/Pages/Uptime/Monitors/Components/UptimeDataTable/skeleton.jsx +++ b/Client/src/Components/Table/skeleton.jsx @@ -1,14 +1,14 @@ import { Skeleton } from "@mui/material"; -const UptimeDataTableSkeleton = () => { +const TableSkeleton = () => { return ( ); }; -export default UptimeDataTableSkeleton; +export default TableSkeleton; diff --git a/Client/src/Pages/Incidents/Components/IncidentTable/index.jsx b/Client/src/Pages/Incidents/Components/IncidentTable/index.jsx new file mode 100644 index 000000000..ba7a03e05 --- /dev/null +++ b/Client/src/Pages/Incidents/Components/IncidentTable/index.jsx @@ -0,0 +1,126 @@ +//Components +import Table from "../../../../Components/Table"; +import TableSkeleton from "../../../../Components/Table/skeleton"; +import Pagination from "../../../../Components/Table/TablePagination"; +import { StatusLabel } from "../../../../Components/Label"; +import { HttpStatusLabel } from "../../../../Components/HttpStatusLabel"; +import GenericFallback from "../../../../Components/GenericFallback"; +import NetworkError from "../../../../Components/GenericFallback/NetworkError"; + +//Utils +import { formatDateWithTz } from "../../../../Utils/timeUtils"; +import { useSelector } from "react-redux"; +import { useState } from "react"; +import useChecksFetch from "../../Hooks/useChecksFetch"; +import PropTypes from "prop-types"; + +const IncidentTable = ({ + shouldRender, + monitors, + selectedMonitor, + filter, + dateRange, +}) => { + //Redux state + const uiTimezone = useSelector((state) => state.ui.timezone); + + //Local state + const [page, setPage] = useState(0); + const [rowsPerPage, setRowsPerPage] = useState(10); + const { isLoading, networkError, checks, checksCount } = useChecksFetch({ + selectedMonitor, + filter, + dateRange, + page, + rowsPerPage, + }); + + //Handlers + const handleChangePage = (_, newPage) => { + setPage(newPage); + }; + + const handleChangeRowsPerPage = (event) => { + setRowsPerPage(event.target.value); + }; + + const headers = [ + { + id: "monitorName", + content: "Monitor Name", + render: (row) => monitors[row.monitorId]?.name ?? "N/A", + }, + { + id: "status", + content: "Status", + render: (row) => { + const status = row.status === true ? "up" : "down"; + return ( + + ); + }, + }, + { + id: "dateTime", + content: "Date & Time", + render: (row) => { + const formattedDate = formatDateWithTz( + row.createdAt, + "YYYY-MM-DD HH:mm:ss A", + uiTimezone + ); + return formattedDate; + }, + }, + { + id: "statusCode", + content: "Status Code", + render: (row) => , + }, + { id: "message", content: "Message", render: (row) => row.message }, + ]; + + if (!shouldRender || isLoading) return ; + + if (networkError) { + return ( + + + + ); + } + + if (!isLoading && typeof checksCount === "undefined") { + return No incidents recorded; + } + + return ( + <> + + + + ); +}; + +IncidentTable.propTypes = { + shouldRender: PropTypes.bool, + monitors: PropTypes.object, + selectedMonitor: PropTypes.string, + filter: PropTypes.string, + dateRange: PropTypes.string, +}; +export default IncidentTable; diff --git a/Client/src/Pages/Incidents/Components/OptionsHeader/index.jsx b/Client/src/Pages/Incidents/Components/OptionsHeader/index.jsx new file mode 100644 index 000000000..967acfed5 --- /dev/null +++ b/Client/src/Pages/Incidents/Components/OptionsHeader/index.jsx @@ -0,0 +1,162 @@ +// Components +import { Stack, Typography, Button, ButtonGroup } from "@mui/material"; +import Select from "../../../../Components/Inputs/Select"; +import PropTypes from "prop-types"; + +//Utils +import { useTheme } from "@emotion/react"; +import SkeletonLayout from "./skeleton"; + +const OptionsHeader = ({ + shouldRender, + selectedMonitor = 0, + setSelectedMonitor, + monitors, + filter = "all", + setFilter, + dateRange = "hour", + setDateRange, +}) => { + const theme = useTheme(); + const monitorNames = typeof monitors !== "undefined" ? Object.values(monitors) : []; + + if (!shouldRender) return ; + + return ( + + + + Incidents for + + - - - - Filter by: - - - - - - - - - - Show: - - - - - - - - - - - - )} + + + + ); }; diff --git a/Client/src/Pages/Incidents/skeleton.jsx b/Client/src/Pages/Incidents/skeleton.jsx deleted file mode 100644 index 51848a108..000000000 --- a/Client/src/Pages/Incidents/skeleton.jsx +++ /dev/null @@ -1,50 +0,0 @@ -import { Stack, Skeleton } from "@mui/material"; -import { useTheme } from "@emotion/react"; - -/** - * Renders a skeleton layout. - * - * @returns {JSX.Element} - */ -const SkeletonLayout = () => { - const theme = useTheme(); - - return ( - <> - - - - - - - - - ); -}; - -export default SkeletonLayout; diff --git a/Client/src/Pages/PageSpeed/Monitors/index.jsx b/Client/src/Pages/PageSpeed/Monitors/index.jsx index a0c24d48e..470a33f18 100644 --- a/Client/src/Pages/PageSpeed/Monitors/index.jsx +++ b/Client/src/Pages/PageSpeed/Monitors/index.jsx @@ -1,6 +1,6 @@ // Components import Breadcrumbs from "../../../Components/Breadcrumbs"; -import { Stack } from "@mui/material"; +import { Stack, Typography } from "@mui/material"; import CreateMonitorHeader from "../../../Components/CreateMonitorHeader"; import MonitorCountHeader from "../../../Components/MonitorCountHeader"; import MonitorGrid from "./Components/MonitorGrid"; @@ -11,7 +11,7 @@ import { useTheme } from "@emotion/react"; import { useSelector } from "react-redux"; import { useIsAdmin } from "../../../Hooks/useIsAdmin"; import useMonitorsFetch from "./Hooks/useMonitorsFetch"; -import NetworkErrorFallback from "../../../Components/NetworkErrorFallback"; +import GenericFallback from "../../../Components/GenericFallback"; // Constants const BREADCRUMBS = [{ name: `pagespeed`, path: "/pagespeed" }]; @@ -27,7 +27,18 @@ const PageSpeed = () => { }); if (networkError === true) { - return ; + return ( + + + Network error + + Please check your connection + + ); } if (!isLoading && monitors?.length === 0) { diff --git a/Client/src/Pages/Uptime/Monitors/Components/UptimeDataTable/index.jsx b/Client/src/Pages/Uptime/Monitors/Components/UptimeDataTable/index.jsx index 8a9fdcbe9..2824f80d6 100644 --- a/Client/src/Pages/Uptime/Monitors/Components/UptimeDataTable/index.jsx +++ b/Client/src/Pages/Uptime/Monitors/Components/UptimeDataTable/index.jsx @@ -9,7 +9,7 @@ import BarChart from "../../../../../Components/Charts/BarChart"; import ActionsMenu from "../ActionsMenu"; import LoadingSpinner from "../LoadingSpinner"; -import UptimeDataTableSkeleton from "./skeleton"; +import TableSkeleton from "../../../../../Components/Table/skeleton"; // Utils import { useTheme } from "@emotion/react"; @@ -175,7 +175,7 @@ const UptimeDataTable = ({ ]; if (monitorsAreLoading) { - return ; + return ; } return ( diff --git a/Client/src/Pages/Uptime/Monitors/index.jsx b/Client/src/Pages/Uptime/Monitors/index.jsx index 1356d9e7c..31dcc93be 100644 --- a/Client/src/Pages/Uptime/Monitors/index.jsx +++ b/Client/src/Pages/Uptime/Monitors/index.jsx @@ -6,13 +6,13 @@ import UptimeDataTable from "./Components/UptimeDataTable"; import Pagination from "../../../Components/Table/TablePagination"; import CreateMonitorHeader from "../../../Components/CreateMonitorHeader"; import Fallback from "../../../Components/Fallback"; -import NetworkErrorFallback from "../../../Components/NetworkErrorFallback"; +import GenericFallback from "../../../Components/GenericFallback"; import SearchComponent from "./Components/SearchComponent"; import MonitorCountHeader from "../../../Components/MonitorCountHeader"; // MUI Components -import { Stack, Box, Button } from "@mui/material"; +import { Stack, Box, Button, Typography } from "@mui/material"; // Utils import { useState, useCallback } from "react"; @@ -109,8 +109,21 @@ const UptimeMonitors = () => { }); const totalMonitors = monitorsSummary?.totalMonitors ?? 0; - if (networkError) return ; - + if (networkError) { + return ( + + {" "} + + Network error + + Please check your connection + + ); + } if (!isLoading && !monitorsAreLoading && totalMonitors === 0) { return (