"use client"; import { useMemo, useState } from "react"; import { Box, Card, Group, ScrollArea, SegmentedControl, SimpleGrid, Stack, Text } from "@mantine/core"; import { clientApi } from "@homarr/api/client"; import { useI18n } from "@homarr/translation/client"; import type { WidgetComponentProps } from "../definition"; import { IntegrationErrorIndicator } from "../common/integration-error-indicator"; import { getUsableWidgetQueryData } from "../common/query-state"; import { WidgetEmptyState } from "../common/empty-state"; import { AveragesSection } from "./averages"; import { combineSpeedtestDashboards, getAvailableSpeedtestDashboards, getCompactSections } from "./helpers"; import { LatestResultSection } from "./latest-result"; import { RecentResultsSection } from "./recent-results"; const emptyDashboardData = [] as const; export default function SpeedtestTrackerWidget({ options, integrationIds, width, height, displayMode = "compact", }: WidgetComponentProps<"speedtestTracker">) { const t = useI18n("widget.speedtestTracker"); const dashboardQuery = clientApi.widget.speedtestTracker.getDashboard.useQuery({ integrationIds }); const dashboardData = getUsableWidgetQueryData(dashboardQuery) ?? emptyDashboardData; const [advancedRange, setAdvancedRange] = useState("24"); const isAdvanced = displayMode === "advanced"; const successfulDashboards = useMemo(() => getAvailableSpeedtestDashboards(dashboardData), [dashboardData]); const combined = useMemo( () => combineSpeedtestDashboards(successfulDashboards.map(({ dashboard }) => dashboard)), [successfulDashboards], ); const rangeHours = isAdvanced ? Number(advancedRange) : 12; const cutoff = rangeHours > 0 ? Date.now() - rangeHours * 60 * 60 * 1000 : 0; const recentFiltered = combined.recentResults.filter((result) => result.created_at.getTime() > cutoff); const showLatestResult = isAdvanced || options.showLatestResult; const showStats = isAdvanced || options.showStats; const showRecentResults = isAdvanced || options.showRecentResults; const showPingGraph = isAdvanced || options.showPingGraph; const hasStatSection = (showLatestResult && combined.latestResult !== null) || (showStats && combined.stats !== null); const hasChart = showRecentResults && recentFiltered.length > 0; const noSectionsEnabled = !isAdvanced && !options.showLatestResult && !options.showStats && !options.showRecentResults; const advancedSectionWidth = width >= 720 ? width / 2 : width; const latest = showLatestResult && combined.latestResult && ( ); const averages = showStats && combined.stats && ( ); const compactSections = getCompactSections(height, { latest: Boolean(latest), chart: hasChart, averages: Boolean(averages), }); if (displayMode === "advanced") { const sourceColumns = successfulDashboards.length > 1 && width >= 900 ? 2 : 1; const sourcePanelWidth = sourceColumns === 2 ? Math.max(0, (width - 48) / 2) : Math.max(0, width - 32); const sourceSectionWidth = sourcePanelWidth >= 720 ? sourcePanelWidth / 2 : sourcePanelWidth; return ( {successfulDashboards.length === 0 ? ( ) : ( {successfulDashboards.map(({ integrationId, integrationName, dashboard }) => { const sourceRecent = dashboard.recentResults.filter((result) => result.created_at.getTime() > cutoff); const sourceHasStats = dashboard.latestResult !== null || dashboard.stats !== null; const sourceHasChart = sourceRecent.length > 0; return ( {integrationName} {sourceHasStats && ( = 720 ? 2 : 1} spacing="md"> {dashboard.latestResult && ( )} {dashboard.stats && } )} {sourceHasChart && ( )} {!sourceHasStats && !sourceHasChart && } ); })} )} ); } return ( {dashboardData.length > 1 && ( {successfulDashboards.map(({ integrationName }) => integrationName).join(" ยท ")} )} {(compactSections.latest || compactSections.averages) && ( {compactSections.latest &&
{latest}
} {compactSections.averages &&
{averages}
}
)} {compactSections.chart && (
)} {noSectionsEnabled && ( {t("noSectionsEnabled")} )} {!noSectionsEnabled && !hasStatSection && !hasChart && }
); }