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:
gorkem-bwl committed 2026-02-20 08:20:25 -05:00
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>
);
+9
View File
@@ -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;
+5
View File
@@ -368,6 +368,11 @@
"dateTime": "Date & time",
"statusCode": "Status code"
}
},
"expandedRow": {
"location": "Location",
"responseTime": "Response time",
"statusCode": "Status code"
}
},
"common": {