status bar

This commit is contained in:
Alex Holliday
2026-02-02 20:39:16 +00:00
parent 75d3644b36
commit 0fd4173816
8 changed files with 234 additions and 31 deletions
@@ -95,7 +95,7 @@ export const HeaderMonitorControls = ({
await refetch();
}}
>
{monitor?.isActive ? t("pause") : t("resume")}
{monitor?.isActive ? t("common.buttons.pause") : t("common.buttons.resume")}
</Button>
)}
{isAdmin && (
@@ -105,7 +105,7 @@ export const HeaderMonitorControls = ({
startIcon={<Icon icon={Settings} />}
onClick={() => navigate(`/${path}/configure/${monitor.id}`)}
>
Configure
{t("common.buttons.configure")}
</Button>
)}
</Stack>
@@ -155,7 +155,7 @@ export const HeaderDeleteControls = ({
await refetch();
}}
>
{monitor?.isActive ? t("pause") : t("resume")}
{monitor?.isActive ? t("common.buttons.pause") : t("common.buttons.resume")}
</Button>
)}
{isAdmin && (
@@ -0,0 +1,87 @@
import Stack from "@mui/material/Stack";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import { Icon } from "@/Components/v2/design-elements";
import { Button } from "@/Components/v2/inputs";
import { Settings, ExternalLink } from "lucide-react";
import { useTheme } from "@mui/material";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import type { StatusPage } from "@/Types/StatusPage";
interface HeaderStatusPageControlsProps {
isAdmin: boolean;
statusPage: StatusPage;
isPublic?: boolean;
}
export const HeaderStatusPageControls = ({
isAdmin,
statusPage,
isPublic = false,
}: HeaderStatusPageControlsProps) => {
const theme = useTheme();
const navigate = useNavigate();
const { t } = useTranslation();
return (
<Stack
direction={"row"}
alignItems={"center"}
justifyContent={"space-between"}
mb={4}
>
<Stack
direction="row"
gap={theme.spacing(4)}
alignItems="baseline"
>
<Typography
variant="h1"
overflow="hidden"
textOverflow="ellipsis"
sx={{
maxWidth: { xs: "200px", sm: "100%" },
}}
>
{statusPage?.companyName}
</Typography>
{statusPage?.isPublished && !isPublic && (
<>
<Typography
onClick={() => {
window.open(
`/status/uptime/public/${statusPage.url}`,
"_blank",
"noopener,noreferrer"
);
}}
sx={{
borderBottom: 1,
borderColor: "transparent",
":hover": {
cursor: "pointer",
borderBottom: 1,
},
}}
>
{t("publicLink")}
</Typography>
<Box>
<ExternalLink size={14} />
</Box>
</>
)}
</Stack>
{isAdmin && (
<Button
variant="contained"
color="secondary"
startIcon={<Icon icon={Settings} />}
onClick={() => navigate(`status/uptime/configure/${statusPage.url}`)}
>
{t("common.buttons.configure")}
</Button>
)}
</Stack>
);
};
@@ -0,0 +1,62 @@
import { AlertTriangle, CircleCheck } from "lucide-react";
import Stack from "@mui/material/Stack";
import Typography from "@mui/material/Typography";
import { useTranslation } from "react-i18next";
import type { Theme } from "@mui/material";
import { useTheme } from "@mui/material";
import type { Monitor } from "@/Types/Monitor";
const getMonitorStatus = (monitors: Monitor[], theme: Theme, t: Function) => {
const monitorsStatus: Record<string, any> = {
icon: <AlertTriangle size={24} />,
};
if (monitors.every((monitor) => monitor.status === true)) {
monitorsStatus.msg = t("pages.statusPages.statusBar.allUp");
monitorsStatus.color = theme.palette.success.main;
monitorsStatus.icon = <CircleCheck size={24} />;
}
if (monitors.every((monitor) => monitor.status === false)) {
monitorsStatus.msg = t("pages.statusPages.statusBar.allDown");
monitorsStatus.color = theme.palette.error.main;
}
if (monitors.some((monitor) => monitor.status === false)) {
monitorsStatus.msg = t("pages.statusPages.statusBar.degraded");
monitorsStatus.color = theme.palette.warning.main;
}
// Paused or unknown
if (monitors.some((monitor) => typeof monitor.status === "undefined")) {
monitorsStatus.msg = t("pages.statusPages.statusBar.unknown");
monitorsStatus.color = theme.palette.warning.main;
}
return monitorsStatus;
};
interface StatusBarProps {
monitors: Monitor[];
}
export const StatusBar = ({ monitors }: StatusBarProps) => {
const theme = useTheme();
const { t } = useTranslation();
const monitorsStatus = getMonitorStatus(monitors, theme, t);
return (
<Stack
direction="row"
alignItems="center"
justifyContent="center"
gap={theme.spacing(2)}
height={theme.spacing(30)}
bgcolor={monitorsStatus.color}
borderRadius={theme.shape.borderRadius}
>
{monitorsStatus.icon}
<Typography>{monitorsStatus.msg}</Typography>
</Stack>
);
};
@@ -0,0 +1,51 @@
import { BasePage } from "@/Components/v2/design-elements";
import { StatusBar } from "@/Pages/StatusPage/Status/Components/StatusBar";
import Typography from "@mui/material/Typography";
import { useTranslation } from "react-i18next";
import { useIsAdmin } from "@/Hooks/useIsAdmin";
import { useLocation, useParams } from "react-router-dom";
import { useGet } from "@/Hooks/UseApi";
import type { StatusPageResponse } from "@/Types/StatusPage";
import { HeaderStatusPageControls } from "./Components/HeaderStatusPageControls";
const StatusPageView = () => {
const { t } = useTranslation();
const { url } = useParams();
const isAdmin = useIsAdmin();
const location = useLocation();
const isPublic = location.pathname.startsWith("/status/uptime/public");
const apiUrl = url ? `/status-page/${url}?type=uptime` : null;
const { data, isLoading, error } = useGet<StatusPageResponse>(apiUrl);
const statusPage = data?.statusPage;
const monitors = data?.monitors ?? [];
if (!statusPage || !monitors) {
return null;
}
if (monitors.length === 0) {
return "poo";
}
return (
<BasePage
loading={isLoading}
error={error}
>
<HeaderStatusPageControls
isAdmin={isAdmin}
statusPage={statusPage}
isPublic={isPublic}
/>
<Typography variant="h2">{t("statusPageStatusServiceStatus")}</Typography>
<StatusBar monitors={monitors} />
<pre> {JSON.stringify(data, null, 2)}</pre>
</BasePage>
);
};
export default StatusPageView;
+15 -3
View File
@@ -38,7 +38,7 @@ import Incidents from "../Pages/Incidents/";
// Status pages
import CreateStatus from "../Pages/StatusPage/Create/index.jsx";
import StatusPages from "../Pages/StatusPage/StatusPages";
import Status from "../Pages/StatusPage/Status/index.jsx";
import Status from "../Pages/StatusPage/Status";
import Notifications from "../Pages/Notifications";
import CreateNotifications from "../Pages/Notifications/create";
@@ -238,7 +238,13 @@ const Routes = () => {
<Route
path="status/uptime/:url"
element={<Status />}
element={
<>
<ThemeProvider theme={v2theme}>
<Status />
</ThemeProvider>
</>
}
/>
<Route
@@ -360,7 +366,13 @@ const Routes = () => {
/>
<Route
path="/status/uptime/public/:url"
element={<Status />}
element={
<>
<ThemeProvider theme={v2theme}>
<Status />
</ThemeProvider>
</>
}
/>
<Route
+7
View File
@@ -1,3 +1,5 @@
import type { Monitor } from "@/Types/Monitor";
export interface StatusPage {
id: string;
userId: string;
@@ -22,3 +24,8 @@ export interface StatusPage {
createdAt: string;
updatedAt: string;
}
export interface StatusPageResponse {
statusPage: StatusPage;
monitors: Monitor[];
}
+9 -25
View File
@@ -22,7 +22,8 @@
"cancel": "Cancel",
"confirm": "Confirm",
"save": "Save",
"test": "Test"
"test": "Test",
"configure": "Configure"
},
"alerts": {
@@ -201,10 +202,6 @@
},
"uptime": {
"table": {
"headers": {
"name": "Status page name",
"url": "Public URL"
},
"headers": {
"responseTime": "Response time"
}
@@ -217,10 +214,6 @@
},
"checks": {
"table": {
"headers": {
"name": "Status page name",
"url": "Public URL"
},
"headers": {
"dateTime": "Date & time",
"statusCode": "Status code"
@@ -249,10 +242,6 @@
"actionButton": "Let's create your first PageSpeed monitor!"
},
"table": {
"headers": {
"name": "Status page name",
"url": "Public URL"
},
"headers": {
"pageSpeedScore": "PageSpeed score"
}
@@ -285,10 +274,6 @@
"actionButton": "Let's create your first infrastructure monitor!"
},
"table": {
"headers": {
"name": "Status page name",
"url": "Public URL"
},
"headers": {
"cpu": "CPU",
"disk": "Disk",
@@ -349,10 +334,6 @@
"title": "Notification channles are used to:"
},
"table": {
"headers": {
"name": "Status page name",
"url": "Public URL"
},
"headers": {
"destination": "Destination"
}
@@ -417,10 +398,6 @@
},
"table": {
"headers": {
"name": "Status page name",
"url": "Public URL"
},
"activeIncidents": "Active Incidents",
"resolvedIncidents": "Resolved Incidents",
"headers": {
@@ -495,6 +472,13 @@
"Keep users informed about outages and performance"
],
"title": "A status page is used to:"
},
"serviceStauts": "Service stauts",
"statusBar": {
"allUp": "All systems operational",
"allDown": "All systems down",
"degraded": "Degraded performance",
"unknown": "Unknown status"
}
}
},