feat: add expandable location rows to ChecksTable
## Changes - Add LocationResult type and locationResults field to client Check type - Add expandable rows to ChecksTable showing per-location Globalping results (location name, status, response time, status code) - Pass globalpingEnabled and locationLabels props from Details page to ChecksTable - Add translation keys for expanded row columns ## Benefits Users can now click a check row to see how each Globalping location performed for that specific monitoring cycle, providing at-a-glance multi-location visibility.
This commit is contained in:
1 parent
a23e4de1d3
commit
249e109b7b
4 files changed
+107
No files matched your search
@@ -1,5 +1,7 @@
|
||||
import { Table, Pagination, StatusLabel } from "@/Components/v2/design-elements";
|
||||
import Box from "@mui/material/Box";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import type { Header } from "@/Components/v2/design-elements/";
|
||||
import type { Check } from "@/Types/Check";
|
||||
|
||||
@@ -8,6 +10,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { formatDateWithTz } from "@/Utils/TimeUtils";
|
||||
import type { RootState } from "@/Types/state";
|
||||
import { useSelector } from "react-redux";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
|
||||
const getHeaders = (t: Function, uiTimezone: string) => {
|
||||
const headers: Header<Check>[] = [
|
||||
@@ -50,6 +53,8 @@ export const ChecksTable = ({
|
||||
setPage,
|
||||
rowsPerPage,
|
||||
setRowsPerPage,
|
||||
globalpingEnabled = false,
|
||||
locationLabels = {},
|
||||
}: {
|
||||
checks: Check[];
|
||||
count: number;
|
||||
@@ -57,9 +62,12 @@ export const ChecksTable = ({
|
||||
setPage: (page: number) => void;
|
||||
rowsPerPage: number;
|
||||
setRowsPerPage: (rowsPerPage: number) => void;
|
||||
globalpingEnabled?: boolean;
|
||||
locationLabels?: Record<string, string>;
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const uiTimezone = useSelector((state: RootState) => state.ui.timezone);
|
||||
const headers = getHeaders(t, uiTimezone);
|
||||
|
||||
@@ -78,6 +86,87 @@ export const ChecksTable = ({
|
||||
setRowsPerPage(value);
|
||||
};
|
||||
|
||||
const renderExpandedContent = (row: Check) => {
|
||||
if (!row.locationResults || row.locationResults.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Stack gap={theme.spacing(2)}>
|
||||
<Stack
|
||||
direction="row"
|
||||
sx={{
|
||||
px: theme.spacing(4),
|
||||
py: theme.spacing(2),
|
||||
borderBottom: `1px solid ${theme.palette.divider}`,
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight={600}
|
||||
sx={{ flex: 2 }}
|
||||
>
|
||||
{t("pages.checks.expandedRow.location")}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight={600}
|
||||
sx={{ flex: 1 }}
|
||||
>
|
||||
{t("common.table.headers.status")}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight={600}
|
||||
sx={{ flex: 1 }}
|
||||
>
|
||||
{t("pages.checks.expandedRow.responseTime")}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight={600}
|
||||
sx={{ flex: 1 }}
|
||||
>
|
||||
{t("pages.checks.expandedRow.statusCode")}
|
||||
</Typography>
|
||||
</Stack>
|
||||
{row.locationResults.map((lr) => (
|
||||
<Stack
|
||||
key={lr.location}
|
||||
direction="row"
|
||||
sx={{
|
||||
px: theme.spacing(4),
|
||||
py: theme.spacing(1),
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{ flex: 2 }}
|
||||
>
|
||||
{locationLabels[lr.location] ?? lr.location}
|
||||
</Typography>
|
||||
<Box sx={{ flex: 1 }}>
|
||||
<StatusLabel status={lr.status ? "up" : "down"} />
|
||||
</Box>
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{ flex: 1 }}
|
||||
>
|
||||
{Math.round(lr.responseTime)} ms
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
sx={{ flex: 1 }}
|
||||
>
|
||||
{lr.statusCode || "N/A"}
|
||||
</Typography>
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Table
|
||||
@@ -86,6 +175,8 @@ export const ChecksTable = ({
|
||||
onRowClick={(row) => {
|
||||
navigate(`/checks/${row.id}`);
|
||||
}}
|
||||
expandableRows={globalpingEnabled}
|
||||
renderExpandedContent={globalpingEnabled ? renderExpandedContent : undefined}
|
||||
/>
|
||||
<Pagination
|
||||
component="div"
|
||||
|
||||
@@ -245,6 +245,8 @@ const UptimeDetailsPage = () => {
|
||||
setPage={setPage}
|
||||
rowsPerPage={rowsPerPage}
|
||||
setRowsPerPage={setRowsPerPage}
|
||||
globalpingEnabled={monitor?.globalpingEnabled ?? false}
|
||||
locationLabels={locationLabels}
|
||||
/>
|
||||
</BasePage>
|
||||
);
|
||||
|
||||
@@ -117,6 +117,14 @@ export interface CheckTimings {
|
||||
};
|
||||
}
|
||||
|
||||
export interface LocationResult {
|
||||
location: string;
|
||||
status: boolean;
|
||||
responseTime: number;
|
||||
statusCode: number;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface Check {
|
||||
id: string;
|
||||
metadata: CheckMetadata;
|
||||
@@ -140,6 +148,7 @@ export interface Check {
|
||||
seo?: number;
|
||||
performance?: number;
|
||||
audits?: CheckAudits;
|
||||
locationResults?: LocationResult[];
|
||||
__v: number;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
|
||||
@@ -368,6 +368,11 @@
|
||||
"dateTime": "Date & time",
|
||||
"statusCode": "Status code"
|
||||
}
|
||||
},
|
||||
"expandedRow": {
|
||||
"location": "Location",
|
||||
"responseTime": "Response time",
|
||||
"statusCode": "Status code"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
|
||||
Reference in new issue
Block a user