Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: incidents refactor #1664

Merged
merged 5 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions Client/src/Components/GenericFallback/NetworkError.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Typography } from "@mui/material";
import { useTheme } from "@emotion/react";

const NetworkError = () => {
const theme = useTheme();
return (
<>
<Typography
variant="h1"
marginY={theme.spacing(4)}
color={theme.palette.primary.contrastTextTertiary}
>
Network error
</Typography>
<Typography>Please check your connection</Typography>
</>
);
};

export default NetworkError;
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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 (
<Box
className="page-speed"
padding={theme.spacing(16)}
position="relative"
border={1}
borderColor={theme.palette.primary.lowContrast}
Expand Down Expand Up @@ -68,18 +68,11 @@ const NetworkErrorFallback = () => {
maxWidth={"300px"}
zIndex={1}
>
<Typography
variant="h1"
marginY={theme.spacing(4)}
color={theme.palette.primary.contrastTextTertiary}
>
Network error
</Typography>
<Typography>Please check your connection</Typography>
{children}
</Stack>
</Stack>
</Box>
);
};

export default NetworkErrorFallback;
export default GenericFallback;
2 changes: 1 addition & 1 deletion Client/src/Components/Table/TablePagination/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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.
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { Skeleton } from "@mui/material";

const UptimeDataTableSkeleton = () => {
const TableSkeleton = () => {
return (
<Skeleton
variant="rounded"
width="100%"
height="100%"
height="80%"
flex={1}
/>
);
};

export default UptimeDataTableSkeleton;
export default TableSkeleton;
126 changes: 126 additions & 0 deletions Client/src/Pages/Incidents/Components/IncidentTable/index.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<StatusLabel
status={status}
text={status}
customStyles={{ textTransform: "capitalize" }}
/>
);
},
},
{
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) => <HttpStatusLabel status={row.statusCode} />,
},
{ id: "message", content: "Message", render: (row) => row.message },
];

if (!shouldRender || isLoading) return <TableSkeleton />;

if (networkError) {
return (
<GenericFallback>
<NetworkError />
</GenericFallback>
);
}

if (!isLoading && typeof checksCount === "undefined") {
return <GenericFallback>No incidents recorded</GenericFallback>;
}

return (
<>
<Table
headers={headers}
data={checks}
/>
<Pagination
paginationLabel="incidents"
itemCount={checksCount}
page={page}
rowsPerPage={rowsPerPage}
handleChangePage={handleChangePage}
handleChangeRowsPerPage={handleChangeRowsPerPage}
/>
</>
);
};

IncidentTable.propTypes = {
shouldRender: PropTypes.bool,
monitors: PropTypes.object,
selectedMonitor: PropTypes.string,
filter: PropTypes.string,
dateRange: PropTypes.string,
};
export default IncidentTable;
162 changes: 162 additions & 0 deletions Client/src/Pages/Incidents/Components/OptionsHeader/index.jsx
Original file line number Diff line number Diff line change
@@ -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 <SkeletonLayout />;

return (
<Stack
direction="row"
justifyContent="space-between"
>
<Stack
direction="row"
alignItems="center"
gap={theme.spacing(6)}
>
<Typography
display="inline-block"
component="h1"
color={theme.palette.primary.contrastTextSecondary}
>
Incidents for
</Typography>
<Select
id="incidents-select-monitor"
placeholder="All servers"
value={selectedMonitor}
onChange={(e) => setSelectedMonitor(e.target.value)}
items={monitorNames}
sx={{
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastTextSecondary,
}}
/>
</Stack>
<Stack
direction="row"
alignItems="center"
gap={theme.spacing(6)}
>
<Typography
display="inline-block"
component="h1"
color={theme.palette.primary.contrastTextSecondary}
>
Filter by:
</Typography>
<ButtonGroup
sx={{
ml: "auto",
"& .MuiButtonBase-root, & .MuiButtonBase-root:hover": {
borderColor: theme.palette.primary.lowContrast,
},
}}
>
<Button
variant="group"
filled={(filter === "all").toString()}
onClick={() => setFilter("all")}
>
All
</Button>
<Button
variant="group"
filled={(filter === "down").toString()}
onClick={() => setFilter("down")}
>
Down
</Button>
<Button
variant="group"
filled={(filter === "resolve").toString()}
onClick={() => setFilter("resolve")}
>
Cannot resolve
</Button>
</ButtonGroup>
</Stack>
<Stack
direction="row"
alignItems="center"
gap={theme.spacing(6)}
>
<Typography
display="inline-block"
component="h1"
color={theme.palette.primary.contrastTextSecondary}
>
Show:
</Typography>
<ButtonGroup
sx={{
ml: "auto",
"& .MuiButtonBase-root, & .MuiButtonBase-root:hover": {
borderColor: theme.palette.primary.lowContrast,
},
}}
>
<Button
variant="group"
filled={(dateRange === "hour").toString()}
onClick={() => setDateRange("hour")}
>
Last hour
</Button>
<Button
variant="group"
filled={(dateRange === "day").toString()}
onClick={() => setDateRange("day")}
>
Last day
</Button>
<Button
variant="group"
filled={(dateRange === "week").toString()}
onClick={() => setDateRange("week")}
>
Last week
</Button>
<Button
variant="group"
filled={(dateRange === "all").toString()}
onClick={() => setDateRange("all")}
>
All
</Button>
</ButtonGroup>
</Stack>
</Stack>
);
};

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;
11 changes: 11 additions & 0 deletions Client/src/Pages/Incidents/Components/OptionsHeader/skeleton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Stack, Skeleton } from "@mui/material";

const SkeletonLayout = () => {
return (
<Stack>
<Skeleton height={40} />
</Stack>
);
};

export default SkeletonLayout;
Loading