import { useEffect, useState } from "react";
import { Server } from "lucide-react";
import { useTranslation } from "@termix/plugin-sdk/frontend";
import { registerWidget } from "./WidgetRegistry";
import type { SystemOverviewConfig, WidgetComponentProps } from "../types.js";
import { GRID_SIZE } from "../types.js";
import {
WidgetTitle,
getDatabaseHealth,
getUptime,
getVersionInfo,
runVisibleInterval,
} from "@termix/plugin-sdk/ui";
interface InfoRowProps {
label: string;
value: string | null | undefined;
valueColor?: string;
}
function InfoRow({ label, value, valueColor }: InfoRowProps) {
if (!value) return null;
return (
{label}
{value}
);
}
function SystemOverviewWidget({
widget,
config,
}: WidgetComponentProps) {
const { t } = useTranslation();
const { showVersion, showDbHealth, showUptime } = config;
const [version, setVersion] = useState(null);
const [updateAvailable, setUpdateAvailable] = useState(false);
const [dbStatus, setDbStatus] = useState(null);
const [uptimeFormatted, setUptimeFormatted] = useState(null);
const fetchData = async () => {
try {
if (showVersion) {
// `checkRemote=false` makes /version return early with just
// {localVersion, status: "update_check_disabled"}, and the response has
// no `updateAvailable` field in either mode -- so the previous read was
// false twice over. `status` is what the endpoint actually answers with,
// and what the dashboard and profile badges already read.
const info = await getVersionInfo();
setVersion((info?.localVersion as string) ?? null);
setUpdateAvailable(info?.status === "requires_update");
}
if (showDbHealth) {
const health = await getDatabaseHealth();
setDbStatus((health?.status as string) ?? "unknown");
}
if (showUptime) {
const up = await getUptime();
setUptimeFormatted(up.formatted);
}
} catch {
/* ignore */
}
};
useEffect(() => {
fetchData();
return runVisibleInterval(() => {
void fetchData();
}, 300_000);
}, [showVersion, showDbHealth, showUptime]);
const accent =
getComputedStyle(document.documentElement)
.getPropertyValue("--accent-brand")
.trim() || "#f59145";
return (
}
fallback="Termix"
/>
{showVersion && (
)}
{showVersion && updateAvailable && (
)}
{showDbHealth && (
)}
{showUptime && (
)}
);
}
registerWidget({
id: "system_overview",
name: "System Overview",
description: "Termix version, database health, and uptime at a glance",
category: "system",
icon: ,
defaultConfig: { showVersion: true, showDbHealth: true, showUptime: true },
defaultSize: { w: GRID_SIZE * 10, h: GRID_SIZE * 6 },
minSize: { w: GRID_SIZE * 4, h: GRID_SIZE * 3 },
component: SystemOverviewWidget,
});
export { SystemOverviewWidget };