fix: refactoring monitorsList and minor fixes based on feedback

This commit is contained in:
mannilakash committed 2026-03-17 15:01:30 -04:00
1 parent d3d00353a1
commit 622446c308
4 files changed
+109 -136

No files matched your search

+2 -17
View File
@@ -29,6 +29,7 @@ import type { StatusPageFormData } from "@/Validation/statusPage";
import { useGet, usePost, usePut, useDelete } from "@/Hooks/UseApi";
import type { Monitor } from "@/Types/Monitor";
import type { MonitorDisplayType, StatusPageResponse } from "@/Types/StatusPage";
import { getMonitorTypeLabel } from "@/Types/StatusPage";
import timezones from "@/Utils/timezones.json";
import { useNavigate, useParams } from "react-router-dom";
import axios from "axios";
@@ -39,22 +40,6 @@ interface TimezoneOption {
name: string;
}
const MONITOR_TYPE_KEYS: Record<string, string> = {
http: "pages.common.monitors.monitorTypes.optionHttp",
ping: "pages.common.monitors.monitorTypes.optionPing",
docker: "pages.common.monitors.monitorTypes.optionDocker",
port: "pages.common.monitors.monitorTypes.optionPort",
game: "pages.common.monitors.monitorTypes.optionGame",
grpc: "pages.common.monitors.monitorTypes.optionGrpc",
websocket: "pages.common.monitors.monitorTypes.optionWebSocket",
hardware: "pages.common.monitors.monitorTypes.optionHardware",
};
const getMonitorTypeLabel = (type: string, t: (key: string) => string): string => {
const i18nMonitorKey = MONITOR_TYPE_KEYS[type];
return i18nMonitorKey ? t(i18nMonitorKey) : type;
};
const CreateStatusPage = () => {
const theme = useTheme();
const { t } = useTranslation();
@@ -111,7 +96,7 @@ const CreateStatusPage = () => {
});
return typesSet.size ? Array.from(typesSet) : ["uptime"];
}, [JSON.stringify(watchedMonitorIds), monitors]);
}, [watchedMonitorIds, monitors]);
useEffect(() => {
form.setValue("type", computedTypes);
@@ -12,6 +12,7 @@ import { useSelector } from "react-redux";
import { useState } from "react";
import type { Monitor } from "@/Types/Monitor";
import type { StatusPage } from "@/Types/StatusPage";
import { getMonitorTypeLabel } from "@/Types/StatusPage";
import type { RootState } from "@/Types/state";
import { LAYOUT, SPACING } from "@/Utils/Theme/constants";
@@ -25,81 +26,98 @@ interface MonitorsListProps {
}
const getMonitorBadgeStyles = (monitorType: string, theme: Theme) => {
// for future: specific badge styles can be defined here based on monitor type
const badgeConfig: Record<string, { color: string; bg: string }> = {
hardware: {
color: theme.palette.background.paper,
bg: theme.palette.info.light,
},
http: {
color: theme.palette.background.paper,
bg: theme.palette.success.light,
},
ping: {
color: theme.palette.background.paper,
bg: theme.palette.success.light,
},
port: {
color: theme.palette.background.paper,
bg: theme.palette.success.light,
},
docker: {
color: theme.palette.background.paper,
bg: theme.palette.success.light,
},
pagespeed: {
color: theme.palette.background.paper,
bg: theme.palette.success.light,
},
game: {
color: theme.palette.background.paper,
bg: theme.palette.success.light,
},
};
const config = badgeConfig[monitorType] ?? badgeConfig.http;
const bg =
monitorType === "hardware" ? theme.palette.info.light : theme.palette.success.light;
return {
backgroundColor: config.bg,
color: config.color,
backgroundColor: bg,
color: theme.palette.background.paper,
padding: `${theme.spacing(SPACING.SM)} ${theme.spacing(SPACING.LG)}`,
borderRadius: theme.shape.borderRadius,
};
};
// Extracted component for monitor content below the header row
const MonitorHeader = ({
monitor,
showURL,
}: {
monitor: StatusPageMonitor;
showURL: boolean;
}) => {
const theme = useTheme();
const { t } = useTranslation();
return (
<Stack
direction="row"
alignItems="center"
justifyContent="space-between"
gap={theme.spacing(LAYOUT.XS)}
mb={theme.spacing(LAYOUT.XS)}
>
<Box sx={{ overflow: "hidden", minWidth: 0, flex: 1 }}>
<Stack
direction="row"
alignItems="center"
gap={theme.spacing(SPACING.LG)}
mb={theme.spacing(SPACING.SM)}
>
<Typography
variant="h6"
sx={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}
>
{monitor.name}
</Typography>
<Typography
variant="caption"
sx={getMonitorBadgeStyles(monitor.type ?? "", theme)}
>
{getMonitorTypeLabel(monitor.type, t)}
</Typography>
</Stack>
{showURL && monitor.url && (
<Typography
variant="body2"
color={theme.palette.text.secondary}
sx={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}
>
{monitor.url}
</Typography>
)}
</Box>
<StatusLabel status={monitor.status} />
</Stack>
);
};
const MonitorContent = ({
monitor,
statusPage,
chartType,
}: {
monitor: Monitor & { checks?: Monitor["recentChecks"] };
monitor: StatusPageMonitor;
statusPage: StatusPage;
chartType: string;
}) => {
const theme = useTheme();
const isInfrastructureMonitor = monitor?.type === "hardware";
if (isInfrastructureMonitor) {
if (statusPage.showInfrastructure === false) {
return null;
}
if (monitor.type === "hardware") {
if (statusPage.showInfrastructure === false) return null;
return <InfrastructureMetrics monitor={monitor} />;
}
if (statusPage.showCharts === false) {
return null;
}
if (statusPage.showCharts === false) return null;
const checks = monitor.checks?.slice().reverse() ?? [];
return (
<Box sx={{ overflow: "hidden", minWidth: 0, flex: 1, mb: theme.spacing(SPACING.LG) }}>
{chartType === "histogram" ? (
<HistogramResponseTime
height={{ xs: 50, md: 100 }}
gap={{ xs: theme.spacing(SPACING.SM), md: theme.spacing(LAYOUT.SM) }}
checks={monitor?.checks?.slice().reverse() ?? []}
checks={checks}
/>
) : (
<HeatmapResponseTime checks={monitor?.checks?.slice().reverse() ?? []} />
<HeatmapResponseTime checks={checks} />
)}
</Box>
);
@@ -108,17 +126,15 @@ const MonitorContent = ({
export const MonitorsList = ({ statusPage, monitors }: MonitorsListProps) => {
const theme = useTheme();
const { t } = useTranslation();
const showURL = useSelector((state: RootState) => state.ui?.showURL);
const [chartType, setChartType] = useState<"histogram" | "heatmap">("histogram");
return (
<Stack gap={theme.spacing(LAYOUT.MD)}>
{statusPage.showCharts && (
<Stack
direction={"row"}
alignItems={"center"}
direction="row"
alignItems="center"
gap={theme.spacing(LAYOUT.SM)}
>
<Typography>{t("pages.statusPages.monitorsList.chartTypeHeatmap")}</Typography>
@@ -126,9 +142,7 @@ export const MonitorsList = ({ statusPage, monitors }: MonitorsListProps) => {
dualOption
value={chartType}
checked={chartType === "histogram"}
onChange={(e) => {
setChartType(e.target.checked ? "histogram" : "heatmap");
}}
onChange={(e) => setChartType(e.target.checked ? "histogram" : "heatmap")}
/>
<Typography>
{t("pages.statusPages.monitorsList.chartTypeHistogram")}
@@ -136,69 +150,22 @@ export const MonitorsList = ({ statusPage, monitors }: MonitorsListProps) => {
</Stack>
)}
{monitors?.map((monitor) => {
return (
<BaseBox
key={monitor.id}
padding={theme.spacing(LAYOUT.MD)}
>
<Stack
direction="row"
alignItems="center"
justifyContent="space-between"
gap={theme.spacing(LAYOUT.XS)}
mb={theme.spacing(LAYOUT.XS)}
>
<Box sx={{ overflow: "hidden", minWidth: 0, flex: 1 }}>
<Stack
direction="row"
alignItems="center"
gap={theme.spacing(SPACING.LG)}
mb={theme.spacing(SPACING.SM)}
>
<Typography
variant="h6"
sx={{
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
}}
>
{monitor.name}
</Typography>
<Typography
variant="caption"
sx={getMonitorBadgeStyles(monitor?.type ?? "", theme)}
>
{t(
`pages.common.monitors.monitorTypes.option${monitor?.type.charAt(0).toUpperCase() + monitor?.type.slice(1)}`
)}
</Typography>
</Stack>
{showURL && monitor?.url && (
<Typography
variant="body2"
color={theme.palette.text.secondary}
sx={{
overflow: "hidden",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
}}
>
{monitor.url}
</Typography>
)}
</Box>
<StatusLabel status={monitor?.status} />
</Stack>
<MonitorContent
monitor={monitor}
statusPage={statusPage}
chartType={chartType}
/>
</BaseBox>
);
})}
{monitors.map((monitor) => (
<BaseBox
key={monitor.id}
padding={theme.spacing(LAYOUT.MD)}
>
<MonitorHeader
monitor={monitor}
showURL={showURL}
/>
<MonitorContent
monitor={monitor}
statusPage={statusPage}
chartType={chartType}
/>
</BaseBox>
))}
</Stack>
);
};
+21 -1
View File
@@ -1,6 +1,26 @@
import type { Monitor } from "@/Types/Monitor";
import type { Monitor, MonitorType } from "@/Types/Monitor";
export type MonitorDisplayType = "uptime" | "infrastructure";
export const MONITOR_TYPE_KEYS: Partial<Record<MonitorType, string>> = {
http: "pages.common.monitors.monitorTypes.optionHttp",
ping: "pages.common.monitors.monitorTypes.optionPing",
docker: "pages.common.monitors.monitorTypes.optionDocker",
port: "pages.common.monitors.monitorTypes.optionPort",
game: "pages.common.monitors.monitorTypes.optionGame",
grpc: "pages.common.monitors.monitorTypes.optionGrpc",
websocket: "pages.common.monitors.monitorTypes.optionWebSocket",
hardware: "pages.common.monitors.monitorTypes.optionHardware",
pagespeed: "pages.common.monitors.monitorTypes.optionPagespeed",
};
export const getMonitorTypeLabel = (
type: MonitorType,
t: (key: string) => string
): string => {
const key = MONITOR_TYPE_KEYS[type];
return key ? t(key) : type;
};
export interface StatusPage {
id: string;
userId: string;
+2 -1
View File
@@ -551,7 +551,8 @@
"optionWebSocketDescription": "Monitor WebSocket endpoints for connection health and response time.",
"optionHttpDescription": "Use HTTP(S) to monitor your website or API endpoint.",
"optionPingDescription": "Use ICMP Ping to monitor if a server is online.",
"optionPortDescription": "Monitor if a specific port on a server is open."
"optionPortDescription": "Monitor if a specific port on a server is open.",
"title": "Type"
},
"thresholds": {
"title": "Alert thresholds",