mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2025-12-22 10:47:08 +00:00
pagination
This commit is contained in:
@@ -47,14 +47,6 @@
|
||||
"vite-plugin-svgr": "^4.2.0",
|
||||
"zod": "4.1.11"
|
||||
},
|
||||
"unusedDepencies": {
|
||||
"@solana/wallet-adapter-base": "0.9.25",
|
||||
"@solana/wallet-adapter-material-ui": "0.16.35",
|
||||
"@solana/wallet-adapter-react": "0.15.37",
|
||||
"@solana/wallet-adapter-react-ui": "0.9.37",
|
||||
"@solana/wallet-adapter-wallets": "0.19.34",
|
||||
"@solana/web3.js": "1.98.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "24.5.2",
|
||||
"@types/react": "^18.2.66",
|
||||
|
||||
@@ -9,7 +9,6 @@ import { CssBaseline, GlobalStyles } from "@mui/material";
|
||||
import { logger } from "./Utils/Logger"; // Import the logger
|
||||
import { networkService } from "./main";
|
||||
import { Routes } from "./Routes";
|
||||
import WalletProvider from "./Components/WalletProvider";
|
||||
import AppLayout from "@/Components/v1/Layouts/AppLayout";
|
||||
|
||||
function App() {
|
||||
@@ -24,16 +23,12 @@ function App() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
/* Extract Themeprovider, baseline and global styles to Styles */
|
||||
<ThemeProvider theme={mode === "light" ? lightTheme : darkTheme}>
|
||||
<WalletProvider>
|
||||
<CssBaseline />
|
||||
|
||||
<AppLayout>
|
||||
<Routes />
|
||||
</AppLayout>
|
||||
<ToastContainer />
|
||||
</WalletProvider>
|
||||
<CssBaseline />
|
||||
<AppLayout>
|
||||
<Routes />
|
||||
</AppLayout>
|
||||
<ToastContainer />
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Box from "@mui/material/Box";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useMediaQuery } from "@mui/material";
|
||||
import type { PaletteKey } from "@/Utils/Theme/v2/theme";
|
||||
|
||||
35
client/src/Components/v2/DesignElements/StatusLabel.tsx
Normal file
35
client/src/Components/v2/DesignElements/StatusLabel.tsx
Normal file
@@ -0,0 +1,35 @@
|
||||
import Box from "@mui/material/Box";
|
||||
import { BaseBox } from "@/Components/v2/DesignElements";
|
||||
import type { MonitorStatus } from "@/Types/Monitor";
|
||||
|
||||
import { getStatusPalette } from "@/Utils/MonitorUtils";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
|
||||
export const StatusLabel = ({ status }: { status: MonitorStatus }) => {
|
||||
const theme = useTheme();
|
||||
const palette = getStatusPalette(status);
|
||||
const transformedText = status.charAt(0).toUpperCase() + status.slice(1).toLowerCase();
|
||||
|
||||
return (
|
||||
<BaseBox
|
||||
sx={{
|
||||
display: "inline-flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
padding: theme.spacing(3, 5),
|
||||
color: theme.palette[palette].main,
|
||||
borderColor: theme.palette[palette].lowContrast,
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
width={7}
|
||||
height={7}
|
||||
bgcolor={theme.palette[palette].lowContrast}
|
||||
borderRadius="50%"
|
||||
marginRight="5px"
|
||||
/>
|
||||
{transformedText}
|
||||
</BaseBox>
|
||||
);
|
||||
};
|
||||
@@ -5,7 +5,19 @@ import TableCell from "@mui/material/TableCell";
|
||||
import TableContainer from "@mui/material/TableContainer";
|
||||
import TableHead from "@mui/material/TableHead";
|
||||
import TableRow from "@mui/material/TableRow";
|
||||
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import LastPageIcon from "@mui/icons-material/LastPage";
|
||||
import FirstPageIcon from "@mui/icons-material/FirstPage";
|
||||
import KeyboardArrowLeft from "@mui/icons-material/KeyboardArrowLeft";
|
||||
import KeyboardArrowRight from "@mui/icons-material/KeyboardArrowRight";
|
||||
|
||||
import Box from "@mui/material/Box";
|
||||
import TablePagination from "@mui/material/TablePagination";
|
||||
import type { TablePaginationProps } from "@mui/material/TablePagination";
|
||||
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useMediaQuery } from "@mui/material";
|
||||
export type Header<T> = {
|
||||
id: number | string;
|
||||
content: React.ReactNode;
|
||||
@@ -87,3 +99,109 @@ export function DataTable<T extends { id?: string | number; _id?: string | numbe
|
||||
</TableContainer>
|
||||
);
|
||||
}
|
||||
|
||||
interface TablePaginationActionsProps {
|
||||
count: number;
|
||||
page: number;
|
||||
rowsPerPage: number;
|
||||
onPageChange: (event: React.MouseEvent<HTMLButtonElement>, newPage: number) => void;
|
||||
}
|
||||
|
||||
function TablePaginationActions(props: TablePaginationActionsProps) {
|
||||
const theme = useTheme();
|
||||
const { count, page, rowsPerPage, onPageChange } = props;
|
||||
|
||||
const handleFirstPageButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
onPageChange(event, 0);
|
||||
};
|
||||
|
||||
const handleBackButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
onPageChange(event, page - 1);
|
||||
};
|
||||
|
||||
const handleNextButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
onPageChange(event, page + 1);
|
||||
};
|
||||
|
||||
const handleLastPageButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
onPageChange(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1));
|
||||
};
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{ flexShrink: 0, ml: 2.5 }}
|
||||
className="table-pagination-actions"
|
||||
>
|
||||
<IconButton
|
||||
onClick={handleFirstPageButtonClick}
|
||||
disabled={page === 0}
|
||||
aria-label="first page"
|
||||
>
|
||||
{theme.direction === "rtl" ? <LastPageIcon /> : <FirstPageIcon />}
|
||||
</IconButton>
|
||||
<IconButton
|
||||
onClick={handleBackButtonClick}
|
||||
disabled={page === 0}
|
||||
aria-label="previous page"
|
||||
>
|
||||
{theme.direction === "rtl" ? <KeyboardArrowRight /> : <KeyboardArrowLeft />}
|
||||
</IconButton>
|
||||
<IconButton
|
||||
onClick={handleNextButtonClick}
|
||||
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
|
||||
aria-label="next page"
|
||||
>
|
||||
{theme.direction === "rtl" ? <KeyboardArrowLeft /> : <KeyboardArrowRight />}
|
||||
</IconButton>
|
||||
<IconButton
|
||||
onClick={handleLastPageButtonClick}
|
||||
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
|
||||
aria-label="last page"
|
||||
>
|
||||
{theme.direction === "rtl" ? <FirstPageIcon /> : <LastPageIcon />}
|
||||
</IconButton>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export const Pagination: React.FC<TablePaginationProps> = ({ ...props }) => {
|
||||
const isSmall = useMediaQuery((theme: any) => theme.breakpoints.down("sm"));
|
||||
const theme = useTheme();
|
||||
return (
|
||||
<TablePagination
|
||||
ActionsComponent={TablePaginationActions}
|
||||
rowsPerPageOptions={[5, 10, 25]}
|
||||
{...props}
|
||||
sx={{
|
||||
"& .MuiTablePagination-toolbar": {
|
||||
display: isSmall ? "grid" : "flex",
|
||||
},
|
||||
"& .MuiTablePagination-selectLabel": {
|
||||
gridColumn: "1",
|
||||
gridRow: "1",
|
||||
justifySelf: "center",
|
||||
},
|
||||
"& .MuiTablePagination-select": {
|
||||
gridColumn: "2",
|
||||
gridRow: "1",
|
||||
justifySelf: "center",
|
||||
},
|
||||
"& .MuiTablePagination-displayedRows": {
|
||||
gridColumn: "2",
|
||||
gridRow: "2",
|
||||
justifySelf: "center ",
|
||||
},
|
||||
"& .table-pagination-actions": {
|
||||
gridColumn: "1",
|
||||
gridRow: "2",
|
||||
justifySelf: "center",
|
||||
},
|
||||
"& .MuiSelect-select": {
|
||||
border: 1,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export { SplitBox as HorizontalSplitBox, ConfigBox } from "./SplitBox";
|
||||
export { BasePage } from "./BasePage";
|
||||
export { BGBox, UpStatusBox, DownStatusBox, PausedStatusBox } from "./StatusBox";
|
||||
export { DataTable as Table } from "./Table";
|
||||
export { DataTable as Table, Pagination } from "./Table";
|
||||
export { GradientBox, StatBox } from "./StatBox";
|
||||
export { BaseBox } from "./BaseBox";
|
||||
export { StatusLabel } from "./StatusLabel";
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import Button from "@mui/material/Button";
|
||||
import type { ButtonProps } from "@mui/material/Button";
|
||||
|
||||
export const ButtonInput: React.FC<ButtonProps> = ({ filled, sx, ...props }) => {
|
||||
export const ButtonInput: React.FC<ButtonProps> = ({ sx, ...props }) => {
|
||||
return (
|
||||
<Button
|
||||
filled={filled}
|
||||
{...props}
|
||||
sx={{ textTransform: "none", height: 34, fontWeight: 400, borderRadius: 2, ...sx }}
|
||||
/>
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import ButtonGroup from "@mui/material/ButtonGroup";
|
||||
import type { ButtonGroupProps } from "@mui/material/ButtonGroup";
|
||||
export const ButtonGroupInput: React.FC<ButtonGroupProps> = ({
|
||||
orientation,
|
||||
...props
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<ButtonGroup
|
||||
orientation={orientation}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { BaseChart } from "./HistogramStatus";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import Box from "@mui/material/Box";
|
||||
import AverageResponseIcon from "@/assets/icons/average-response-icon.svg?react";
|
||||
import { Cell, RadialBarChart, RadialBar, ResponsiveContainer } from "recharts";
|
||||
|
||||
@@ -23,7 +22,10 @@ export const ChartAvgResponse = ({ avg, max }: { avg: number; max: number }) =>
|
||||
};
|
||||
|
||||
return (
|
||||
<BaseChart icon={<AverageResponseIcon />}>
|
||||
<BaseChart
|
||||
icon={<AverageResponseIcon />}
|
||||
title={"Average response time"}
|
||||
>
|
||||
<Stack
|
||||
height="100%"
|
||||
position={"relative"}
|
||||
@@ -31,7 +33,6 @@ export const ChartAvgResponse = ({ avg, max }: { avg: number; max: number }) =>
|
||||
>
|
||||
<ResponsiveContainer
|
||||
width="100%"
|
||||
minWidth={210}
|
||||
height={155}
|
||||
>
|
||||
<RadialBarChart
|
||||
|
||||
@@ -4,7 +4,6 @@ import ResponseTimeIcon from "@/assets/icons/response-time-icon.svg?react";
|
||||
import {
|
||||
AreaChart,
|
||||
Area,
|
||||
YAxis,
|
||||
XAxis,
|
||||
Tooltip,
|
||||
CartesianGrid,
|
||||
@@ -52,6 +51,8 @@ type ResponseTimeToolTipProps = {
|
||||
payload?: any[];
|
||||
label?: string;
|
||||
range: string;
|
||||
theme: any;
|
||||
uiTimezone: string;
|
||||
};
|
||||
|
||||
const ResponseTimeToolTip: React.FC<ResponseTimeToolTipProps> = ({
|
||||
@@ -59,13 +60,14 @@ const ResponseTimeToolTip: React.FC<ResponseTimeToolTipProps> = ({
|
||||
payload,
|
||||
label,
|
||||
range,
|
||||
theme,
|
||||
uiTimezone,
|
||||
}) => {
|
||||
if (!label) return null;
|
||||
if (!payload) return null;
|
||||
if (!active) return null;
|
||||
|
||||
const theme = useTheme();
|
||||
const format = tooltipDateFormatLookup(range);
|
||||
const uiTimezone = useSelector((state: any) => state.ui.timezone);
|
||||
const responseTime = Math.floor(payload?.[0]?.value || 0);
|
||||
return (
|
||||
<BaseBox sx={{ py: theme.spacing(2), px: theme.spacing(4) }}>
|
||||
@@ -83,6 +85,8 @@ export const ChartResponseTime = ({
|
||||
range: string;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const uiTimezone = useSelector((state: any) => state.ui.timezone);
|
||||
|
||||
return (
|
||||
<BaseChart
|
||||
icon={<ResponseTimeIcon />}
|
||||
@@ -137,6 +141,8 @@ export const ChartResponseTime = ({
|
||||
<ResponseTimeToolTip
|
||||
{...props}
|
||||
range={range}
|
||||
theme={theme}
|
||||
uiTimezone={uiTimezone}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -41,6 +41,7 @@ export const HeaderControls = ({
|
||||
>
|
||||
<ButtonGroup
|
||||
orientation={isSmall ? "vertical" : "horizontal"}
|
||||
fullWidth={isSmall}
|
||||
variant="contained"
|
||||
color="secondary"
|
||||
>
|
||||
|
||||
@@ -2,8 +2,7 @@ import Stack from "@mui/material/Stack";
|
||||
import { ButtonGroup, Button } from "@/Components/v2/Inputs";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { theme } from "@/Utils/Theme/v2/theme";
|
||||
|
||||
import { useMediaQuery } from "@mui/material";
|
||||
export const HeaderRange = ({
|
||||
range,
|
||||
setRange,
|
||||
@@ -14,15 +13,18 @@ export const HeaderRange = ({
|
||||
loading: boolean;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const isSmall = useMediaQuery(theme.breakpoints.down("md"));
|
||||
return (
|
||||
<Stack
|
||||
gap={theme.spacing(9)}
|
||||
direction="row"
|
||||
direction={isSmall ? "column" : "row"}
|
||||
alignItems={"center"}
|
||||
justifyContent="flex-end"
|
||||
>
|
||||
<Typography variant="body2">{`Showing statistics for past ${range}`}</Typography>
|
||||
<ButtonGroup
|
||||
orientation={isSmall ? "vertical" : "horizontal"}
|
||||
fullWidth={isSmall}
|
||||
variant="contained"
|
||||
color={"primary"}
|
||||
>
|
||||
|
||||
@@ -65,7 +65,6 @@ export const BaseChart: React.FC<BaseChartProps> = ({ children, icon, title }) =
|
||||
<BaseBox
|
||||
sx={{
|
||||
padding: theme.spacing(8),
|
||||
minWidth: 250,
|
||||
display: "flex",
|
||||
flex: 1,
|
||||
}}
|
||||
|
||||
@@ -20,7 +20,7 @@ export const useGet = <T,>(
|
||||
axiosConfig?: AxiosRequestConfig,
|
||||
swrConfig?: SWRConfiguration<T, Error>
|
||||
) => {
|
||||
const { data, error, isLoading, mutate } = useSWR<T>(
|
||||
const { data, error, isLoading, isValidating, mutate } = useSWR<T>(
|
||||
url,
|
||||
(url) => fetcher<T>(url, axiosConfig),
|
||||
swrConfig
|
||||
@@ -29,6 +29,7 @@ export const useGet = <T,>(
|
||||
return {
|
||||
response: data ?? null,
|
||||
loading: isLoading,
|
||||
isValidating,
|
||||
error: error?.message ?? null,
|
||||
refetch: mutate,
|
||||
};
|
||||
|
||||
93
client/src/Pages/v2/Uptime/CheckTable.tsx
Normal file
93
client/src/Pages/v2/Uptime/CheckTable.tsx
Normal file
@@ -0,0 +1,93 @@
|
||||
import { Table, Pagination } from "@/Components/v2/DesignElements";
|
||||
import { StatusLabel } from "@/Components/v2/DesignElements";
|
||||
import Box from "@mui/material/Box";
|
||||
|
||||
import type { Header } from "@/Components/v2/DesignElements/Table";
|
||||
import type { Check } from "@/Types/Check";
|
||||
import type { ApiResponse } from "@/Hooks/v2/UseApi";
|
||||
import type { MonitorStatus } from "@/Types/Monitor";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useGet } from "@/Hooks/v2/UseApi";
|
||||
import { formatDateWithTz } from "@/Utils/TimeUtils";
|
||||
import { useSelector } from "react-redux";
|
||||
const getHeaders = (t: Function, uiTimezone: string) => {
|
||||
const headers: Header<Check>[] = [
|
||||
{
|
||||
id: "status",
|
||||
content: t("status"),
|
||||
render: (row) => {
|
||||
return <StatusLabel status={row.status as MonitorStatus} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "date",
|
||||
content: t("date&Time"),
|
||||
render: (row) => {
|
||||
return formatDateWithTz(row.createdAt, "ddd, MMMM D, YYYY, HH:mm A", uiTimezone);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "statusCode",
|
||||
content: t("statusCode"),
|
||||
render: (row) => {
|
||||
return row.httpStatusCode || "N/A";
|
||||
},
|
||||
},
|
||||
];
|
||||
return headers;
|
||||
};
|
||||
|
||||
export const CheckTable = ({ monitorId }: { monitorId: string }) => {
|
||||
const [page, setPage] = useState(0);
|
||||
const [rowsPerPage, setRowsPerPage] = useState(5);
|
||||
const { t } = useTranslation();
|
||||
const uiTimezone = useSelector((state: any) => state.ui.timezone);
|
||||
const headers = getHeaders(t, uiTimezone);
|
||||
|
||||
const { response, error } = useGet<ApiResponse>(
|
||||
`/monitors/${monitorId}/checks?page=${page}&rowsPerPage=${rowsPerPage}`,
|
||||
{},
|
||||
{ keepPreviousData: true }
|
||||
);
|
||||
|
||||
const checks = response?.data?.checks || [];
|
||||
const count = response?.data?.count || 0;
|
||||
|
||||
const handlePageChange = (
|
||||
_e: React.MouseEvent<HTMLButtonElement> | null,
|
||||
newPage: number
|
||||
) => {
|
||||
setPage(newPage);
|
||||
};
|
||||
|
||||
const handleRowsPerPageChange = (
|
||||
e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>
|
||||
) => {
|
||||
const value = Number(e.target.value);
|
||||
setPage(0);
|
||||
setRowsPerPage(value);
|
||||
};
|
||||
|
||||
if (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Table
|
||||
headers={headers}
|
||||
data={checks}
|
||||
/>
|
||||
<Pagination
|
||||
component="div"
|
||||
count={count}
|
||||
page={page}
|
||||
rowsPerPage={rowsPerPage}
|
||||
onPageChange={handlePageChange}
|
||||
onRowsPerPageChange={handleRowsPerPageChange}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
@@ -4,7 +4,11 @@ import Stack from "@mui/material/Stack";
|
||||
import { StatBox } from "@/Components/v2/DesignElements";
|
||||
import { HistogramStatus } from "@/Components/v2/Monitors/HistogramStatus";
|
||||
import { ChartAvgResponse } from "@/Components/v2/Monitors/ChartAvgResponse";
|
||||
import { ChartResponseTime } from "@/Components/v2/Monitors/ChartResponseTime";
|
||||
import { HeaderRange } from "@/Components/v2/Monitors/HeaderRange";
|
||||
import { CheckTable } from "@/Pages/v2/Uptime/CheckTable";
|
||||
|
||||
import type { IMonitor } from "@/Types/Monitor";
|
||||
import { useMediaQuery } from "@mui/material";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useParams } from "react-router";
|
||||
@@ -12,8 +16,6 @@ import { useGet, usePatch, type ApiResponse } from "@/Hooks/v2/UseApi";
|
||||
import { useState } from "react";
|
||||
import { getStatusPalette } from "@/Utils/MonitorUtils";
|
||||
import prettyMilliseconds from "pretty-ms";
|
||||
import { ChartResponseTime } from "@/Components/v2/Monitors/ChartResponseTime";
|
||||
import { HeaderRange } from "@/Components/v2/Monitors/HeaderRange";
|
||||
|
||||
const UptimeDetailsPage = () => {
|
||||
const { id } = useParams();
|
||||
@@ -23,7 +25,7 @@ const UptimeDetailsPage = () => {
|
||||
// Local state
|
||||
const [range, setRange] = useState("2h");
|
||||
|
||||
const { response, loading, error, refetch } = useGet<ApiResponse>(
|
||||
const { response, isValidating, error, refetch } = useGet<ApiResponse>(
|
||||
`/monitors/${id}?embedChecks=true&range=${range}`,
|
||||
|
||||
{},
|
||||
@@ -32,8 +34,8 @@ const UptimeDetailsPage = () => {
|
||||
|
||||
const {
|
||||
response: upResponse,
|
||||
isValidating: upIsValidating,
|
||||
error: upError,
|
||||
loading: upLoading,
|
||||
} = useGet<ApiResponse>(
|
||||
`/monitors/${id}?embedChecks=true&range=${range}&status=up`,
|
||||
{},
|
||||
@@ -43,7 +45,7 @@ const UptimeDetailsPage = () => {
|
||||
const {
|
||||
response: downResponse,
|
||||
error: downError,
|
||||
loading: downLoading,
|
||||
isValidating: downIsValidating,
|
||||
} = useGet<ApiResponse>(
|
||||
`/monitors/${id}?embedChecks=true&range=${range}&status=down`,
|
||||
{},
|
||||
@@ -56,7 +58,8 @@ const UptimeDetailsPage = () => {
|
||||
error: postError,
|
||||
} = usePatch<ApiResponse>(`/monitors/${id}/active`);
|
||||
|
||||
const monitor = response?.data?.monitor || null;
|
||||
const monitor: IMonitor = response?.data?.monitor;
|
||||
|
||||
if (!monitor) {
|
||||
return null;
|
||||
}
|
||||
@@ -79,12 +82,17 @@ const UptimeDetailsPage = () => {
|
||||
? [...downResponse.data.checks].reverse()
|
||||
: [];
|
||||
|
||||
// TODO something with these
|
||||
|
||||
console.log(loading, error, postError, checks, setRange);
|
||||
|
||||
const palette = getStatusPalette(monitor.status);
|
||||
|
||||
if (error || upError || downError || postError) {
|
||||
console.error("Error fetching monitor data:", {
|
||||
error,
|
||||
upError,
|
||||
downError,
|
||||
postError,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<BasePage>
|
||||
<HeaderControls
|
||||
@@ -116,6 +124,7 @@ const UptimeDetailsPage = () => {
|
||||
/>
|
||||
</Stack>
|
||||
<HeaderRange
|
||||
loading={isValidating || upIsValidating || downIsValidating}
|
||||
range={range}
|
||||
setRange={setRange}
|
||||
/>
|
||||
@@ -144,6 +153,7 @@ const UptimeDetailsPage = () => {
|
||||
checks={checks}
|
||||
range={range}
|
||||
/>
|
||||
<CheckTable monitorId={monitor._id} />
|
||||
</BasePage>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Table } from "@/Components/v2/DesignElements";
|
||||
import { HistogramResponseTime } from "@/Components/v2/Monitors/HistogramResponseTime";
|
||||
import type { Header } from "@/Components/v2/DesignElements/Table";
|
||||
import { ActionsMenu } from "@/Components/v2/ActionsMenu";
|
||||
import { StatusLabel } from "@/Components/v2/DesignElements";
|
||||
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useMediaQuery } from "@mui/material";
|
||||
@@ -86,7 +87,7 @@ const getHeaders = (theme: any, t: Function, navigate: Function) => {
|
||||
id: "status",
|
||||
content: t("status"),
|
||||
render: (row) => {
|
||||
return row.status;
|
||||
return <StatusLabel status={row.status} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,8 +1,38 @@
|
||||
export interface CheckTimingPhases {
|
||||
wait: number;
|
||||
dns: number;
|
||||
tcp: number;
|
||||
tls: number;
|
||||
request: number;
|
||||
firstByte: number;
|
||||
download: number;
|
||||
total: number;
|
||||
}
|
||||
|
||||
export interface CheckTimings {
|
||||
start: string;
|
||||
socket: string;
|
||||
lookup: string;
|
||||
connect: string;
|
||||
secureConnect: string;
|
||||
response: string;
|
||||
end: string;
|
||||
phases: CheckTimingPhases;
|
||||
}
|
||||
|
||||
export interface Check {
|
||||
_id: string;
|
||||
monitorId: string;
|
||||
type: string;
|
||||
status: string;
|
||||
message: string;
|
||||
responseTime: number;
|
||||
httpStatusCode: number;
|
||||
ack: boolean;
|
||||
expiry: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
timings: CheckTimings;
|
||||
}
|
||||
|
||||
export interface GroupedCheck {
|
||||
|
||||
Reference in New Issue
Block a user