diff --git a/surfsense_web/app/(home)/uptime/page.tsx b/surfsense_web/app/(home)/uptime/page.tsx deleted file mode 100644 index b3aaeb848..000000000 --- a/surfsense_web/app/(home)/uptime/page.tsx +++ /dev/null @@ -1,262 +0,0 @@ -import Link from "next/link"; -import { UPTIME_REPORT_URL } from "@/lib/env-config"; - -type UptimeStatus = "up" | "down"; - -interface LocationStat { - uptime_status: UptimeStatus; - response_time: number | null; - last_check: number; -} - -interface UptimeMonitor { - id: string; - name: string; - type: string; - target: string; - last_check: number; - uptime_status: UptimeStatus; - monitor_status: string; - uptime: number; - locations?: Record; -} - -interface UptimeMonitorsApiResponse { - monitors?: unknown[]; -} - -const HETRIXTOOLS_API_BASE = "https://api.hetrixtools.com/v3"; - -function formatTimestamp(timestamp: number) { - if (!Number.isFinite(timestamp) || timestamp <= 0) return "n/a"; - return new Date(timestamp * 1000).toLocaleString(); -} - -function formatLocationName(location: string) { - return location - .replaceAll("_", " ") - .split(" ") - .map((part) => part.charAt(0).toUpperCase() + part.slice(1)) - .join(" "); -} - -function toNumber(value: unknown, fallback = 0) { - if (typeof value === "number" && Number.isFinite(value)) return value; - if (typeof value === "string") { - const parsed = Number.parseFloat(value); - if (Number.isFinite(parsed)) return parsed; - } - return fallback; -} - -function normalizeUptimeStatus(value: unknown): UptimeStatus { - return value === "down" ? "down" : "up"; -} - -function normalizeMonitor(rawMonitor: unknown): UptimeMonitor | null { - if (!rawMonitor || typeof rawMonitor !== "object") return null; - - const monitor = rawMonitor as Record; - const rawLocations = - monitor.locations && typeof monitor.locations === "object" - ? (monitor.locations as Record) - : {}; - - const locations: Record = {}; - for (const [locationName, rawLocation] of Object.entries(rawLocations)) { - if (!rawLocation || typeof rawLocation !== "object") continue; - const location = rawLocation as Record; - locations[locationName] = { - uptime_status: normalizeUptimeStatus(location.uptime_status), - response_time: - location.response_time === null ? null : toNumber(location.response_time, 0), - last_check: toNumber(location.last_check, 0), - }; - } - - return { - id: String(monitor.id ?? ""), - name: String(monitor.name ?? "Unnamed monitor"), - type: String(monitor.type ?? ""), - target: String(monitor.target ?? ""), - last_check: toNumber(monitor.last_check, 0), - uptime_status: normalizeUptimeStatus(monitor.uptime_status), - monitor_status: String(monitor.monitor_status ?? "unknown"), - uptime: toNumber(monitor.uptime, 0), - locations, - }; -} - -async function fetchUptimeMonitors(): Promise<{ - monitors: UptimeMonitor[]; - error?: string; -}> { - const apiKey = process.env.HETRIXTOOLS_API_KEY; - const monitorId = process.env.HETRIXTOOLS_MONITOR_ID; - - if (!apiKey) { - return { - monitors: [], - error: - "Missing HETRIXTOOLS_API_KEY. Add it to your server environment to enable custom uptime UI.", - }; - } - - const query = monitorId - ? `id=${encodeURIComponent(monitorId)}` - : "per_page=20&page=1&order_by=last_check&order=desc"; - - try { - const response = await fetch(`${HETRIXTOOLS_API_BASE}/uptime-monitors?${query}`, { - method: "GET", - headers: { - Authorization: `Bearer ${apiKey}`, - }, - next: { revalidate: 60 }, - }); - - if (!response.ok) { - return { - monitors: [], - error: `HetrixTools API request failed (${response.status}).`, - }; - } - - const data = (await response.json()) as UptimeMonitorsApiResponse; - const monitors = (data.monitors ?? []) - .map((monitor) => normalizeMonitor(monitor)) - .filter((monitor): monitor is UptimeMonitor => monitor !== null); - return { monitors }; - } catch { - return { - monitors: [], - error: "Could not reach HetrixTools API from the server.", - }; - } -} - -export default async function UptimePage() { - const { monitors, error } = await fetchUptimeMonitors(); - - return ( -
-
-
-

- System Status -

-

- SurfSense uptime dashboard -

-
- - Open original report - - - Source: HetrixTools v3 API (`/uptime-monitors`). - -
-
- - {error ? ( -
-

Unable to load custom uptime data

-

{error}

-
- ) : monitors.length === 0 ? ( -
- No uptime monitors returned by HetrixTools API. -
- ) : ( -
- {monitors.map((monitor) => { - const locations = Object.entries(monitor.locations ?? {}); - const isUp = monitor.uptime_status === "up"; - - return ( -
-
-
-

- {monitor.name} -

-

- {monitor.target || "No target shown"} -

-
-
- {isUp ? "Operational" : "Outage"} -
-
- -
-
-

Uptime

-

- {monitor.uptime.toFixed(4)}% -

-
-
-

- Last check -

-

- {formatTimestamp(monitor.last_check)} -

-
-
-

- Monitor status -

-

- {monitor.monitor_status.replaceAll("_", " ")} -

-
-
- - {locations.length > 0 && ( -
-

- Locations -

-
- {locations.map(([locationName, locationData]) => ( -
-

- {formatLocationName(locationName)} -

-

- {locationData.uptime_status === "up" ? "Up" : "Down"} ยท{" "} - {locationData.response_time ?? "n/a"} ms -

-
- ))} -
-
- )} -
- ); - })} -
- )} -
-
- ); -}