diff --git a/apps/web/src/app/status-page/[domain]/page.tsx b/apps/web/src/app/status-page/[domain]/page.tsx index 3569ea1a3..c2542fd81 100644 --- a/apps/web/src/app/status-page/[domain]/page.tsx +++ b/apps/web/src/app/status-page/[domain]/page.tsx @@ -13,6 +13,9 @@ import { EmptyState } from "@/components/dashboard/empty-state"; import { Header } from "@/components/dashboard/header"; import { IncidentList } from "@/components/status-page/incident-list"; import { MonitorList } from "@/components/status-page/monitor-list"; +import { StatusCheck } from "@/components/status-page/status-check"; +import { getMonitorListData } from "@/lib/tb"; +import { notEmpty } from "@/lib/utils"; import { api } from "@/trpc/server"; const url = @@ -58,6 +61,7 @@ export default async function Page({ params }: Props) { /> ) : ( <> + ( ; + monitors: z.infer[]; +}) { + const isIncident = incidents.some( + (incident) => !["monitoring", "resolved"].includes(incident.status), + ); + + const monitorsData = ( + await Promise.all( + monitors.map((monitor) => { + return getResponseListData({ + monitorId: String(monitor.id), + limit: 10, + }); + }), + ) + ).filter(notEmpty); + + function calcStatus() { + const { count, ok } = monitorsData.flat(1).reduce( + (prev, curr) => { + const isOk = curr.statusCode <= 299 && curr.statusCode >= 200; + return { count: prev.count + 1, ok: prev.ok + (isOk ? 1 : 0) }; + }, + { count: 0, ok: 0 }, + ); + const status = getStatus(ok / count); + return status; + } + + const status = calcStatus(); + const incident = { + label: "Incident", + variant: "incident", + twColor: "text-yellow-500", + twBgColor: "bg-yellow-500", + } as const; + + const { label, variant, twBgColor } = isIncident ? incident : status; + + return ( +
+
+

{label}

+ + + +
+

Status Check

+
+ ); +} + +interface StatusIconProps { + variant: StatusVariant | "incident"; + className?: string; +} + +function StatusIcon({ variant, className }: StatusIconProps) { + const rootClassName = cn("h-5 w-5 text-background", className); + const MinusIcon = Icons["minus"]; + const CheckIcon = Icons["check"]; + const AlertTriangleIcon = Icons["alert-triangle"]; + if (variant === "incident") { + return ; + } + if (variant === "degraded") { + return ; + } + if (variant === "down") { + return ; + } + return ; +} diff --git a/apps/web/src/lib/tracker.ts b/apps/web/src/lib/tracker.ts index 680e80912..81e92e1de 100644 --- a/apps/web/src/lib/tracker.ts +++ b/apps/web/src/lib/tracker.ts @@ -1,17 +1,47 @@ import type { Monitor } from "@openstatus/tinybird"; +export type StatusVariant = "up" | "degraded" | "down" | "empty"; + +type GetStatusReturnType = { + label: string; + variant: StatusVariant; + twColor: string; + twBgColor: string; +}; + /** * Get the status of a monitor based on its ratio * @param ratio * @returns */ -export const getStatus = ( - ratio: number, -): { label: string; variant: "up" | "degraded" | "down" | "empty" } => { - if (isNaN(ratio)) return { label: "Missing", variant: "empty" }; - if (ratio >= 0.98) return { label: "Operational", variant: "up" }; - if (ratio >= 0.5) return { label: "Degraded", variant: "degraded" }; - return { label: "Downtime", variant: "down" }; +export const getStatus = (ratio: number): GetStatusReturnType => { + if (isNaN(ratio)) + return { + label: "Missing", + variant: "empty", + twColor: "text-gray-500", + twBgColor: "bg-gray-500", + }; + if (ratio >= 0.98) + return { + label: "Operational", + variant: "up", + twColor: "text-green-500", + twBgColor: "bg-green-500", + }; + if (ratio >= 0.5) + return { + label: "Degraded", + variant: "degraded", + twColor: "text-yellow-500", + twBgColor: "bg-yellow-500", + }; + return { + label: "Downtime", + variant: "down", + twColor: "text-red-500", + twBgColor: "bg-red-500", + }; }; /**