diff --git a/client/src/Pages/StatusPage/Status/Components/InfrastructureMetrics.tsx b/client/src/Pages/StatusPage/Status/Components/InfrastructureMetrics.tsx
deleted file mode 100644
index 32a15d64b..000000000
--- a/client/src/Pages/StatusPage/Status/Components/InfrastructureMetrics.tsx
+++ /dev/null
@@ -1,246 +0,0 @@
-import Stack from "@mui/material/Stack";
-import Typography from "@mui/material/Typography";
-import { Gauge } from "@/Components/design-elements";
-import { useTheme } from "@mui/material/styles";
-import { useTranslation } from "react-i18next";
-import prettyBytes from "pretty-bytes";
-import type { Monitor } from "@/Types/Monitor";
-import Grid from "@mui/material/Grid";
-import useMediaQuery from "@mui/material/useMediaQuery";
-import Box from "@mui/material/Box";
-import { LAYOUT, SPACING } from "@/Utils/Theme/constants";
-
-const GAUGE_RADIUS = 60;
-const GAUGE_STROKE_WIDTH = 12;
-const PERCENTAGE_MULTIPLIER = 100;
-
-interface StatusPageMonitor extends Monitor {
- checks?: Monitor["recentChecks"];
-}
-
-interface MetricDetail {
- label: string;
- value: string;
-}
-
-interface MetricConfig {
- key: string;
- label: string;
- hasData: boolean;
- progress: number;
- details: MetricDetail[];
-}
-
-const MetricDetailRow = ({ label, value }: MetricDetail) => {
- const theme = useTheme();
- return (
-
-
- {label}
-
- {value}
-
- );
-};
-
-interface MetricItemProps {
- label: string;
- progress: number;
- details?: MetricDetail[];
-}
-
-const MetricItem = ({ label, progress, details }: MetricItemProps) => {
- const theme = useTheme();
- const isSmall = useMediaQuery(theme.breakpoints.down("md"));
- return (
-
-
-
- {label}
-
- {details && details.length > 0 && (
-
- {details.map((detail) => (
-
- ))}
-
- )}
-
- );
-};
-
-type LatestCheck = NonNullable[number];
-
-const buildCpuMetric = (
- check: LatestCheck,
- t: (key: string) => string
-): MetricConfig | null => {
- if (!check.cpu || typeof check.cpu.usage_percent !== "number") {
- return null;
- }
- const usagePercent = (check.cpu.usage_percent ?? 0) * PERCENTAGE_MULTIPLIER;
- return {
- key: "cpu",
- label: t("pages.statusPages.monitorsList.infrastructure.cpu"),
- hasData: true,
- progress: usagePercent,
- details: [
- {
- label: t("pages.statusPages.monitorsList.infrastructure.usage"),
- value: `${usagePercent.toFixed(2)}%`,
- },
- ],
- };
-};
-
-const buildMemoryMetric = (
- check: LatestCheck,
- t: (key: string) => string
-): MetricConfig | null => {
- if (
- !check.memory ||
- typeof check.memory.usage_percent !== "number" ||
- typeof check.memory.used_bytes !== "number" ||
- typeof check.memory.total_bytes !== "number"
- ) {
- return null;
- }
- return {
- key: "memory",
- label: t("pages.statusPages.monitorsList.infrastructure.memory"),
- hasData: true,
- progress: (check.memory.usage_percent ?? 0) * PERCENTAGE_MULTIPLIER,
- details: [
- {
- label: t("pages.statusPages.monitorsList.infrastructure.used"),
- value: prettyBytes(check.memory.used_bytes ?? 0),
- },
- {
- label: t("pages.statusPages.monitorsList.infrastructure.total"),
- value: prettyBytes(check.memory.total_bytes ?? 0),
- },
- ],
- };
-};
-
-const buildDiskMetric = (
- check: LatestCheck,
- t: (key: string) => string
-): MetricConfig | null => {
- if (!check.disk || check.disk.length === 0) {
- return null;
- }
- const disks = check.disk;
- const avgUsagePercent =
- (disks.reduce((acc, disk) => acc + (disk?.usage_percent ?? 0), 0) / disks.length) *
- PERCENTAGE_MULTIPLIER;
- const totalUsedBytes = disks.reduce((acc, disk) => acc + (disk?.used_bytes ?? 0), 0);
- const totalTotalBytes = disks.reduce((acc, disk) => acc + (disk?.total_bytes ?? 0), 0);
-
- return {
- key: "disk",
- label: t("pages.statusPages.monitorsList.infrastructure.disk"),
- hasData: true,
- progress: avgUsagePercent,
- details: [
- {
- label: t("pages.statusPages.monitorsList.infrastructure.used"),
- value: prettyBytes(totalUsedBytes),
- },
- {
- label: t("pages.statusPages.monitorsList.infrastructure.total"),
- value: prettyBytes(totalTotalBytes),
- },
- ],
- };
-};
-
-export const InfrastructureMetrics = ({ monitor }: { monitor: StatusPageMonitor }) => {
- const theme = useTheme();
- const { t } = useTranslation();
-
- const latestCheck = monitor.recentChecks?.[0] ?? monitor.checks?.[0];
-
- if (!latestCheck) {
- return (
-
- {t("pages.statusPages.monitorsList.noData")}
-
- );
- }
-
- const metrics: MetricConfig[] = [
- buildCpuMetric(latestCheck, t),
- buildMemoryMetric(latestCheck, t),
- buildDiskMetric(latestCheck, t),
- ].filter((m): m is MetricConfig => m !== null);
-
- if (metrics.length === 0) {
- return (
-
- {t("pages.statusPages.monitorsList.noData")}
-
- );
- }
-
- return (
-
- {metrics.map(({ key, label, progress, details }) => (
-
- ))}
-
- );
-};
diff --git a/client/src/Pages/StatusPage/Status/Components/MonitorsList.tsx b/client/src/Pages/StatusPage/Status/Components/MonitorsList.tsx
deleted file mode 100644
index 01e7d1975..000000000
--- a/client/src/Pages/StatusPage/Status/Components/MonitorsList.tsx
+++ /dev/null
@@ -1,174 +0,0 @@
-import Stack from "@mui/material/Stack";
-import { useTranslation } from "react-i18next";
-import Box from "@mui/material/Box";
-import Typography from "@mui/material/Typography";
-import { HistogramResponseTime, HeatmapResponseTime } from "@/Components/common";
-import { StatusLabel, BaseBox } from "@/Components/design-elements";
-import { SwitchComponent } from "@/Components/inputs";
-import { InfrastructureMetrics } from "@/Pages/StatusPage/Status/Components/InfrastructureMetrics";
-
-import { useTheme, type Theme } from "@mui/material/styles";
-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";
-
-interface StatusPageMonitor extends Monitor {
- checks?: Monitor["recentChecks"];
-}
-
-interface MonitorsListProps {
- statusPage: StatusPage;
- monitors: StatusPageMonitor[];
-}
-
-const getMonitorBadgeStyles = (monitorType: string, theme: Theme) => {
- const bg =
- monitorType === "hardware" ? theme.palette.info.light : theme.palette.success.light;
- return {
- backgroundColor: bg,
- color: theme.palette.background.paper,
- padding: `${theme.spacing(SPACING.SM)} ${theme.spacing(SPACING.LG)}`,
- borderRadius: theme.shape.borderRadius,
- };
-};
-
-const MonitorHeader = ({
- monitor,
- showURL,
-}: {
- monitor: StatusPageMonitor;
- showURL: boolean;
-}) => {
- const theme = useTheme();
- const { t } = useTranslation();
-
- return (
-
-
-
-
- {monitor.name}
-
-
- {getMonitorTypeLabel(monitor.type, t)}
-
-
- {showURL && monitor.url && (
-
- {monitor.url}
-
- )}
-
-
-
- );
-};
-
-const MonitorContent = ({
- monitor,
- statusPage,
- chartType,
-}: {
- monitor: StatusPageMonitor;
- statusPage: StatusPage;
- chartType: string;
-}) => {
- const theme = useTheme();
-
- if (monitor.type === "hardware") {
- if (statusPage.showInfrastructure === false) return null;
- return ;
- }
-
- if (statusPage.showCharts === false) return null;
-
- const checks = monitor.checks?.slice().reverse() ?? [];
- return (
-
- {chartType === "histogram" ? (
-
- ) : (
-
- )}
-
- );
-};
-
-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 (
-
- {statusPage.showCharts && (
-
- {t("pages.statusPages.monitorsList.chartTypeHeatmap")}
- setChartType(e.target.checked ? "histogram" : "heatmap")}
- />
-
- {t("pages.statusPages.monitorsList.chartTypeHistogram")}
-
-
- )}
-
- {monitors.map((monitor) => (
-
-
-
-
- ))}
-
- );
-};
diff --git a/client/src/Pages/StatusPage/Status/Components/StatusBar.tsx b/client/src/Pages/StatusPage/Status/Components/StatusBar.tsx
deleted file mode 100644
index 49f70d952..000000000
--- a/client/src/Pages/StatusPage/Status/Components/StatusBar.tsx
+++ /dev/null
@@ -1,173 +0,0 @@
-import {
- AlertTriangle,
- CircleCheck,
- CircleX,
- Loader,
- PauseCircle,
- ShieldAlert,
- Wrench,
-} from "lucide-react";
-import Stack from "@mui/material/Stack";
-import Typography from "@mui/material/Typography";
-
-import { useTranslation } from "react-i18next";
-import { useTheme } from "@mui/material";
-import type { Monitor, MonitorStatus } from "@/Types/Monitor";
-
-type SemanticTone = "up" | "down" | "warn" | "info";
-
-interface StatusDisplay {
- icon: JSX.Element;
- msg?: string;
- tone: SemanticTone;
-}
-
-const getMonitorStatus = (monitors: Monitor[], t: Function): StatusDisplay => {
- if (monitors.length === 0) {
- return {
- msg: t("pages.statusPages.statusBar.noMonitors"),
- tone: "warn",
- icon: ,
- };
- }
-
- const allOf = (...statuses: MonitorStatus[]) =>
- monitors.every((m) => statuses.includes(m.status));
- const someOf = (...statuses: MonitorStatus[]) =>
- monitors.some((m) => statuses.includes(m.status));
- const noneOf = (...statuses: MonitorStatus[]) =>
- monitors.every((m) => !statuses.includes(m.status));
-
- if (allOf("up")) {
- return {
- msg: t("pages.statusPages.statusBar.allUp"),
- tone: "up",
- icon: ,
- };
- }
- if (allOf("breached")) {
- return {
- msg: t("pages.statusPages.statusBar.allBreached"),
- tone: "down",
- icon: ,
- };
- }
- if (allOf("maintenance")) {
- return {
- msg: t("pages.statusPages.statusBar.allMaintenance"),
- tone: "warn",
- icon: ,
- };
- }
- if (allOf("down")) {
- return {
- msg: t("pages.statusPages.statusBar.allDown"),
- tone: "down",
- icon: ,
- };
- }
- if (allOf("paused")) {
- return {
- msg: t("pages.statusPages.statusBar.allPaused"),
- tone: "warn",
- icon: ,
- };
- }
- if (allOf("initializing")) {
- return {
- msg: t("pages.statusPages.statusBar.allInitializing"),
- tone: "warn",
- icon: ,
- };
- }
-
- // Breached takes highest priority in mixed states
- if (someOf("breached") && someOf("down")) {
- return {
- msg: t("pages.statusPages.statusBar.breachedAndDown"),
- tone: "down",
- icon: ,
- };
- }
- if (someOf("breached")) {
- return {
- msg: t("pages.statusPages.statusBar.breached"),
- tone: "down",
- icon: ,
- };
- }
- if (someOf("maintenance") && someOf("down")) {
- return {
- msg: t("pages.statusPages.statusBar.maintenanceAndDown"),
- tone: "down",
- icon: ,
- };
- }
- if (someOf("maintenance") && noneOf("down")) {
- return {
- msg: t("pages.statusPages.statusBar.maintenance"),
- tone: "warn",
- icon: ,
- };
- }
- if (someOf("down")) {
- return {
- msg: t("pages.statusPages.statusBar.degraded"),
- tone: "warn",
- icon: ,
- };
- }
- if (someOf("paused")) {
- return {
- msg: t("pages.statusPages.statusBar.partiallyPaused"),
- tone: "warn",
- icon: ,
- };
- }
- if (someOf("initializing")) {
- return {
- msg: t("pages.statusPages.statusBar.initializing"),
- tone: "info",
- icon: ,
- };
- }
-
- return {
- msg: t("pages.statusPages.statusBar.unknown"),
- tone: "warn",
- icon: ,
- };
-};
-
-const toneToCssVar: Record = {
- up: "var(--sp-up)",
- down: "var(--sp-down)",
- warn: "var(--sp-warn)",
- info: "var(--sp-up)",
-};
-
-interface StatusBarProps {
- monitors: Monitor[];
-}
-
-export const StatusBar = ({ monitors }: StatusBarProps) => {
- const theme = useTheme();
- const { t } = useTranslation();
- const monitorsStatus = getMonitorStatus(monitors, t);
-
- return (
-
- {monitorsStatus.icon}
- {monitorsStatus.msg}
-
- );
-};
diff --git a/client/src/Pages/StatusPage/Status/index.tsx b/client/src/Pages/StatusPage/Status/index.tsx
index 86b9d90ad..1f9cca9ee 100644
--- a/client/src/Pages/StatusPage/Status/index.tsx
+++ b/client/src/Pages/StatusPage/Status/index.tsx
@@ -1,12 +1,9 @@
import { BasePage, BaseFallback } from "@/Components/design-elements";
-import { StatusBar } from "@/Pages/StatusPage/Status/Components/StatusBar";
-import { MonitorsList } from "@/Pages/StatusPage/Status/Components/MonitorsList";
import Typography from "@mui/material/Typography";
import { Link } from "react-router-dom";
import Stack from "@mui/material/Stack";
-import Box from "@mui/material/Box";
-import { useMediaQuery, useTheme } from "@mui/material";
+import { useTheme } from "@mui/material";
import { useTranslation } from "react-i18next";
import { useIsAdmin } from "@/Hooks/useIsAdmin";
import { useLocation, useParams } from "react-router-dom";
@@ -43,7 +40,6 @@ const StatusPageView = () => {
const { url } = useParams();
const isAdmin = useIsAdmin();
const location = useLocation();
- const isSmall = useMediaQuery(theme.breakpoints.down("md"));
const isPublic = location.pathname.startsWith("/status/public");
const apiUrl = url ? `/status-page/${url}?type=uptime&type=infrastructure` : null;
@@ -88,17 +84,6 @@ const StatusPageView = () => {
);
}
- let sx: React.CSSProperties = {};
- if (isPublic) {
- sx.paddingTop = theme.spacing(20);
- sx.paddingLeft = isSmall ? "5vw" : "20vw";
- sx.paddingRight = isSmall ? "5vw" : "20vw";
- }
-
- const logoSrc = statusPage.logo?.data
- ? `data:${statusPage.logo.contentType};base64,${statusPage.logo.data}`
- : null;
-
const ThemedRenderer = THEMED_RENDERERS[resolveStatusPageTheme(statusPage.theme)];
const themedRenderer = (
{
/>
);
- if (themedRenderer) {
- // Public route: render directly on the viewport, themed background covers everything.
- if (isPublic) {
- return (
-
- {themedRenderer}
-
- );
- }
-
- // Admin preview: wrap in a mock browser frame inside the admin shell.
- const publicUrl = `${window.location.origin}/status/public/${statusPage.url}`;
+ // Public route: render directly on the viewport, themed background covers everything.
+ if (isPublic) {
return (
-
-
-
- {themedRenderer}
-
-
+ {themedRenderer}
+
);
}
+ // Admin preview: wrap in a mock browser frame inside the admin shell.
+ const publicUrl = `${window.location.origin}/status/public/${statusPage.url}`;
return (
-
-
+
-
- {logoSrc && (
-
- )}
-
-
-
-
+ {themedRenderer}
+
+
);
};