remove dead code
This commit is contained in:
1 parent
edeed00be6
commit
d32ea7f8c3
4 files changed
+28
-677
No files matched your search
@@ -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 (
|
||||
<Stack
|
||||
direction="row"
|
||||
justifyContent="space-between"
|
||||
>
|
||||
<Typography
|
||||
variant="body2"
|
||||
color={theme.palette.text.secondary}
|
||||
>
|
||||
{label}
|
||||
</Typography>
|
||||
<Typography variant="body2">{value}</Typography>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
||||
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 (
|
||||
<Grid
|
||||
size={isSmall ? 12 : 4}
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
textAlign: "center",
|
||||
gap: theme.spacing(SPACING.LG),
|
||||
padding: theme.spacing(LAYOUT.XS),
|
||||
borderRight: isSmall ? "none" : `1px solid ${theme.palette.divider}`,
|
||||
borderBottom: isSmall ? `1px solid ${theme.palette.divider}` : "none",
|
||||
"&:last-child": {
|
||||
borderRight: "none",
|
||||
borderBottom: "none",
|
||||
paddingBottom: theme.spacing(SPACING.LG),
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
display="flex"
|
||||
flexDirection="column"
|
||||
alignItems="center"
|
||||
>
|
||||
<Gauge
|
||||
progress={progress}
|
||||
radius={GAUGE_RADIUS}
|
||||
strokeWidth={GAUGE_STROKE_WIDTH}
|
||||
/>
|
||||
<Typography variant="body2">{label}</Typography>
|
||||
</Box>
|
||||
{details && details.length > 0 && (
|
||||
<Box
|
||||
width="100%"
|
||||
paddingX={theme.spacing(LAYOUT.LG)}
|
||||
>
|
||||
{details.map((detail) => (
|
||||
<MetricDetailRow
|
||||
key={detail.label}
|
||||
label={detail.label}
|
||||
value={detail.value}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
)}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
|
||||
type LatestCheck = NonNullable<Monitor["recentChecks"]>[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 (
|
||||
<Typography
|
||||
variant="body2"
|
||||
color={theme.palette.text.secondary}
|
||||
>
|
||||
{t("pages.statusPages.monitorsList.noData")}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
const metrics: MetricConfig[] = [
|
||||
buildCpuMetric(latestCheck, t),
|
||||
buildMemoryMetric(latestCheck, t),
|
||||
buildDiskMetric(latestCheck, t),
|
||||
].filter((m): m is MetricConfig => m !== null);
|
||||
|
||||
if (metrics.length === 0) {
|
||||
return (
|
||||
<Typography
|
||||
variant="body2"
|
||||
color={theme.palette.text.secondary}
|
||||
>
|
||||
{t("pages.statusPages.monitorsList.noData")}
|
||||
</Typography>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Grid
|
||||
container
|
||||
alignItems="center"
|
||||
padding={theme.spacing(LAYOUT.XS)}
|
||||
>
|
||||
{metrics.map(({ key, label, progress, details }) => (
|
||||
<MetricItem
|
||||
key={key}
|
||||
label={label}
|
||||
progress={progress}
|
||||
details={details}
|
||||
/>
|
||||
))}
|
||||
</Grid>
|
||||
);
|
||||
};
|
||||
@@ -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 (
|
||||
<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"
|
||||
className="sp-heading"
|
||||
sx={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}
|
||||
>
|
||||
{monitor.name}
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="caption"
|
||||
className="sp-badge"
|
||||
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: StatusPageMonitor;
|
||||
statusPage: StatusPage;
|
||||
chartType: string;
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
|
||||
if (monitor.type === "hardware") {
|
||||
if (statusPage.showInfrastructure === false) return null;
|
||||
return <InfrastructureMetrics monitor={monitor} />;
|
||||
}
|
||||
|
||||
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={checks}
|
||||
/>
|
||||
) : (
|
||||
<HeatmapResponseTime checks={checks} />
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
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"
|
||||
gap={theme.spacing(LAYOUT.SM)}
|
||||
>
|
||||
<Typography>{t("pages.statusPages.monitorsList.chartTypeHeatmap")}</Typography>
|
||||
<SwitchComponent
|
||||
dualOption
|
||||
value={chartType}
|
||||
checked={chartType === "histogram"}
|
||||
onChange={(e) => setChartType(e.target.checked ? "histogram" : "heatmap")}
|
||||
/>
|
||||
<Typography>
|
||||
{t("pages.statusPages.monitorsList.chartTypeHistogram")}
|
||||
</Typography>
|
||||
</Stack>
|
||||
)}
|
||||
|
||||
{monitors.map((monitor) => (
|
||||
<BaseBox
|
||||
key={monitor.id}
|
||||
className="sp-card"
|
||||
padding={theme.spacing(LAYOUT.MD)}
|
||||
>
|
||||
<MonitorHeader
|
||||
monitor={monitor}
|
||||
showURL={showURL}
|
||||
/>
|
||||
<MonitorContent
|
||||
monitor={monitor}
|
||||
statusPage={statusPage}
|
||||
chartType={chartType}
|
||||
/>
|
||||
</BaseBox>
|
||||
))}
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
@@ -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: <CircleX size={24} />,
|
||||
};
|
||||
}
|
||||
|
||||
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: <CircleCheck size={24} />,
|
||||
};
|
||||
}
|
||||
if (allOf("breached")) {
|
||||
return {
|
||||
msg: t("pages.statusPages.statusBar.allBreached"),
|
||||
tone: "down",
|
||||
icon: <ShieldAlert size={24} />,
|
||||
};
|
||||
}
|
||||
if (allOf("maintenance")) {
|
||||
return {
|
||||
msg: t("pages.statusPages.statusBar.allMaintenance"),
|
||||
tone: "warn",
|
||||
icon: <Wrench size={24} />,
|
||||
};
|
||||
}
|
||||
if (allOf("down")) {
|
||||
return {
|
||||
msg: t("pages.statusPages.statusBar.allDown"),
|
||||
tone: "down",
|
||||
icon: <CircleX size={24} />,
|
||||
};
|
||||
}
|
||||
if (allOf("paused")) {
|
||||
return {
|
||||
msg: t("pages.statusPages.statusBar.allPaused"),
|
||||
tone: "warn",
|
||||
icon: <PauseCircle size={24} />,
|
||||
};
|
||||
}
|
||||
if (allOf("initializing")) {
|
||||
return {
|
||||
msg: t("pages.statusPages.statusBar.allInitializing"),
|
||||
tone: "warn",
|
||||
icon: <Loader size={24} />,
|
||||
};
|
||||
}
|
||||
|
||||
// Breached takes highest priority in mixed states
|
||||
if (someOf("breached") && someOf("down")) {
|
||||
return {
|
||||
msg: t("pages.statusPages.statusBar.breachedAndDown"),
|
||||
tone: "down",
|
||||
icon: <ShieldAlert size={24} />,
|
||||
};
|
||||
}
|
||||
if (someOf("breached")) {
|
||||
return {
|
||||
msg: t("pages.statusPages.statusBar.breached"),
|
||||
tone: "down",
|
||||
icon: <ShieldAlert size={24} />,
|
||||
};
|
||||
}
|
||||
if (someOf("maintenance") && someOf("down")) {
|
||||
return {
|
||||
msg: t("pages.statusPages.statusBar.maintenanceAndDown"),
|
||||
tone: "down",
|
||||
icon: <Wrench size={24} />,
|
||||
};
|
||||
}
|
||||
if (someOf("maintenance") && noneOf("down")) {
|
||||
return {
|
||||
msg: t("pages.statusPages.statusBar.maintenance"),
|
||||
tone: "warn",
|
||||
icon: <Wrench size={24} />,
|
||||
};
|
||||
}
|
||||
if (someOf("down")) {
|
||||
return {
|
||||
msg: t("pages.statusPages.statusBar.degraded"),
|
||||
tone: "warn",
|
||||
icon: <AlertTriangle size={24} />,
|
||||
};
|
||||
}
|
||||
if (someOf("paused")) {
|
||||
return {
|
||||
msg: t("pages.statusPages.statusBar.partiallyPaused"),
|
||||
tone: "warn",
|
||||
icon: <PauseCircle size={24} />,
|
||||
};
|
||||
}
|
||||
if (someOf("initializing")) {
|
||||
return {
|
||||
msg: t("pages.statusPages.statusBar.initializing"),
|
||||
tone: "info",
|
||||
icon: <Loader size={24} />,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
msg: t("pages.statusPages.statusBar.unknown"),
|
||||
tone: "warn",
|
||||
icon: <AlertTriangle size={24} />,
|
||||
};
|
||||
};
|
||||
|
||||
const toneToCssVar: Record<SemanticTone, string> = {
|
||||
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 (
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
gap={theme.spacing(2)}
|
||||
height={theme.spacing(30)}
|
||||
bgcolor={toneToCssVar[monitorsStatus.tone]}
|
||||
borderRadius={theme.shape.borderRadius}
|
||||
className="sp-hero"
|
||||
>
|
||||
{monitorsStatus.icon}
|
||||
<Typography className="sp-hero-title">{monitorsStatus.msg}</Typography>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
@@ -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 = (
|
||||
<ThemedRenderer
|
||||
@@ -107,82 +92,41 @@ const StatusPageView = () => {
|
||||
/>
|
||||
);
|
||||
|
||||
if (themedRenderer) {
|
||||
// Public route: render directly on the viewport, themed background covers everything.
|
||||
if (isPublic) {
|
||||
return (
|
||||
<StatusPageThemeProvider
|
||||
theme={statusPage.theme}
|
||||
themeMode={statusPage.themeMode}
|
||||
paintBody
|
||||
>
|
||||
{themedRenderer}
|
||||
</StatusPageThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
// 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 (
|
||||
<BasePage
|
||||
loading={isLoading}
|
||||
error={error}
|
||||
breadcrumbOverride={undefined}
|
||||
sx={{ flex: 1, minHeight: 0 }}
|
||||
<StatusPageThemeProvider
|
||||
theme={statusPage.theme}
|
||||
themeMode={statusPage.themeMode}
|
||||
paintBody
|
||||
>
|
||||
<HeaderStatusPageControls
|
||||
isAdmin={isAdmin}
|
||||
statusPage={statusPage}
|
||||
isPublic={false}
|
||||
/>
|
||||
<StatusPageThemeProvider
|
||||
theme={statusPage.theme}
|
||||
themeMode={statusPage.themeMode}
|
||||
transparent
|
||||
>
|
||||
<BrowserFrame url={publicUrl}>{themedRenderer}</BrowserFrame>
|
||||
</StatusPageThemeProvider>
|
||||
</BasePage>
|
||||
{themedRenderer}
|
||||
</StatusPageThemeProvider>
|
||||
);
|
||||
}
|
||||
|
||||
// Admin preview: wrap in a mock browser frame inside the admin shell.
|
||||
const publicUrl = `${window.location.origin}/status/public/${statusPage.url}`;
|
||||
return (
|
||||
<StatusPageThemeProvider
|
||||
theme={statusPage.theme}
|
||||
themeMode={statusPage.themeMode}
|
||||
<BasePage
|
||||
loading={isLoading}
|
||||
error={error}
|
||||
breadcrumbOverride={undefined}
|
||||
sx={{ flex: 1, minHeight: 0 }}
|
||||
>
|
||||
<BasePage
|
||||
loading={isLoading}
|
||||
error={error}
|
||||
sx={sx}
|
||||
breadcrumbOverride={isPublic ? [] : undefined}
|
||||
<HeaderStatusPageControls
|
||||
isAdmin={isAdmin}
|
||||
statusPage={statusPage}
|
||||
isPublic={false}
|
||||
/>
|
||||
<StatusPageThemeProvider
|
||||
theme={statusPage.theme}
|
||||
themeMode={statusPage.themeMode}
|
||||
transparent
|
||||
>
|
||||
<HeaderStatusPageControls
|
||||
isAdmin={isAdmin}
|
||||
statusPage={statusPage}
|
||||
isPublic={isPublic}
|
||||
/>
|
||||
{logoSrc && (
|
||||
<Box
|
||||
component="img"
|
||||
src={logoSrc}
|
||||
alignSelf={"flex-start"}
|
||||
alt={statusPage.companyName}
|
||||
sx={{
|
||||
maxHeight: 120,
|
||||
maxWidth: "100%",
|
||||
objectFit: "contain",
|
||||
mb: 2,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<StatusBar monitors={monitors} />
|
||||
<MonitorsList
|
||||
statusPage={statusPage}
|
||||
monitors={monitors}
|
||||
/>
|
||||
</BasePage>
|
||||
</StatusPageThemeProvider>
|
||||
<BrowserFrame url={publicUrl}>{themedRenderer}</BrowserFrame>
|
||||
</StatusPageThemeProvider>
|
||||
</BasePage>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user