"use client"; import { Badge, Card, Center, Group, List, ScrollArea, SimpleGrid, Stack, Text, useMantineTheme } from "@mantine/core"; import { IconCircleCheckFilled, IconCircleXFilled } from "@tabler/icons-react"; import dayjs from "dayjs"; import duration from "dayjs/plugin/duration"; import objectSupport from "dayjs/plugin/objectSupport"; import relativeTime from "dayjs/plugin/relativeTime"; import { clientApi } from "@homarr/api/client"; import type { TranslationFunction } from "@homarr/translation"; import { useCurrentIntlLocale, useI18n } from "@homarr/translation/client"; import type { WidgetComponentProps } from "../../definition"; import { IntegrationErrorIndicator } from "../../common/integration-error-indicator"; import { getBinaryStatusKey } from "../../common/locale"; import { getUsableWidgetQueryData } from "../../common/query-state"; import { WidgetQueryErrorIndicator } from "../../common/query-state-indicator"; import type { NetworkControllerMatrixMetricKey, NetworkControllerMatrixSectionKey } from "./display"; import { getNetworkControllerMatrix } from "./display"; dayjs.extend(objectSupport); dayjs.extend(relativeTime); dayjs.extend(duration); export default function NetworkControllerSummaryWidget({ integrationIds, width, height, displayMode, }: WidgetComponentProps<"networkControllerSummary">) { const summaryQuery = clientApi.widget.networkController.summary.useQuery({ integrationIds, }); const results = getUsableWidgetQueryData(summaryQuery) ?? []; const summaries = results.filter( (result): result is typeof result & { summary: NonNullable; updatedAt: Date } => result.summary !== null && result.updatedAt !== undefined, ); const { isPending } = summaryQuery; const t = useI18n(); const locale = useCurrentIntlLocale(); const statusLabels = { enabled: t("widget.dnsHoleSummary.status.enabled"), disabled: t("widget.dnsHoleSummary.status.disabled"), unknown: t("widget.dnsHoleSummary.status.unknown"), }; const isDense = height < 160; const showDetails = height >= 180 && width >= 240; const columns = width >= 720 ? 2 : 1; const isAdvanced = displayMode === "advanced"; const queryIndicators = ( ); if (isPending || summaries.length === 0) { return ( {queryIndicators}
{isPending ? t("common.action.loading") : t("widget.networkControllerSummary.error.integrationsDisconnected")}
); } if (isAdvanced) { const controllerColumns = width >= 960 ? 2 : 1; const matrixColumns = width >= 720 ? 3 : width >= 440 ? 2 : 1; return ( {queryIndicators} {summaries.map(({ integration, summary, updatedAt }) => ( {integration.name} {integration.kind} {t("widget.networkControllerSummary.advanced.updated")} {new Date(updatedAt).toLocaleString(locale)} {getNetworkControllerMatrix(summary).map((section) => ( {getMatrixSectionLabel(section.key, t)} {statusLabels[getBinaryStatusKey(section.status)]} {section.metrics.length > 0 && ( {section.metrics.map((metric) => ( {getMatrixMetricLabel(metric.key, t)} {formatMatrixMetric(metric.key, metric.value)} ))} )} ))} ))} ); } return ( {queryIndicators} {summaries.map(({ integration, summary }) => ( 1}> {summaries.length > 1 && ( {integration.name} {integration.kind} )} } > {t("widget.networkControllerSummary.card.wan")} } > {t("widget.networkControllerSummary.card.web")} {summary.www.latency}ms{showDetails ? ` · ${summary.www.ping}ms` : ""} } > {t("widget.networkControllerSummary.card.wifi")} {showDetails ? ` · ${summary.wifi.users + summary.wifi.guests}` : ""} {showDetails && ( } > {t("widget.networkControllerSummary.card.lan")} · {summary.lan.users + summary.lan.guests} )} } > {t("widget.networkControllerSummary.card.vpn.label")} {t("widget.networkControllerSummary.card.vpn.countConnected", { count: summary.vpn.users })} ))} ); } const getMatrixMetricLabel = (key: NetworkControllerMatrixMetricKey, t: TranslationFunction) => t(`widget.networkControllerSummary.advanced.metric.${key}`); const formatMatrixMetric = (key: NetworkControllerMatrixMetricKey, value: number) => { if (key === "latency" || key === "ping") return `${value}ms`; if (key === "uptime") return dayjs.duration(value, "seconds").humanize(); return String(value); }; const getMatrixSectionLabel = (key: NetworkControllerMatrixSectionKey, t: TranslationFunction) => { if (key === "vpn") return t("widget.networkControllerSummary.card.vpn.label"); return t(`widget.networkControllerSummary.card.${key}`); }; const StatusIcon = ({ status, label, size }: { status?: "enabled" | "disabled"; label: string; size: number }) => { const mantineTheme = useMantineTheme(); if (status === "enabled") { return ; } if (status === "disabled") { return ; } return ; };