import { useEffect, useState } from "react"; import { Wifi } from "lucide-react"; import { useTranslation } from "react-i18next"; import { registerWidget } from "./WidgetRegistry"; import type { PingStatusConfig, WidgetComponentProps, } from "@/types/homepage-types"; import { GRID_SIZE } from "@/types/homepage-types"; import { homepageApi } from "@/main-axios"; import { WidgetTitle } from "./WidgetTitle"; interface PingResult { ok: boolean; statusCode: number | null; latencyMs: number; } async function pingUrl(url: string): Promise { const res = await homepageApi.get("/ping", { params: { url } }); return res.data as PingResult; } function StatusDot({ ok, pending }: { ok: boolean | null; pending: boolean }) { if (pending) return ( ); return ( ); } function PingStatusWidget({ widget, config, }: WidgetComponentProps) { const { t } = useTranslation(); const { urls, refreshInterval, showLatency } = config; const [results, setResults] = useState>({}); const [pending, setPending] = useState>({}); const fetchAll = async () => { if (urls.length === 0) return; const newPending: Record = {}; urls.forEach((u) => { newPending[u.url] = true; }); setPending(newPending); await Promise.all( urls.map(async (u) => { try { const r = await pingUrl(u.url); setResults((prev) => ({ ...prev, [u.url]: r })); } catch { setResults((prev) => ({ ...prev, [u.url]: { ok: false, statusCode: null, latencyMs: 0 }, })); } finally { setPending((prev) => ({ ...prev, [u.url]: false })); } }), ); }; const interval = Math.max(10, refreshInterval || 30); useEffect(() => { fetchAll(); const iv = setInterval(fetchAll, interval * 1000); return () => clearInterval(iv); }, [JSON.stringify(urls), interval]); if (urls.length === 0) { return (
{t("homepage.noPingUrls")}
); } return (
} />
{urls.map((u) => { const r = results[u.url]; const isPending = pending[u.url] ?? false; return (
{u.label || u.url} {r && ( {r.statusCode ?? (r.ok ? "OK" : "ERR")} )}
{showLatency && r && r.latencyMs > 0 && ( {r.latencyMs}ms )}
); })}
); } registerWidget({ id: "ping_status", name: "Ping Status", description: "Check if URLs or services are reachable", category: "monitoring", icon: , defaultConfig: { urls: [], refreshInterval: 30, showLatency: true }, defaultSize: { w: GRID_SIZE * 9, h: GRID_SIZE * 7 }, minSize: { w: GRID_SIZE * 3, h: GRID_SIZE * 2 }, component: PingStatusWidget, }); export { PingStatusWidget };