"use client"; import type { CSSProperties } from "react"; import { DonutChart } from "@mantine/charts"; import { Group, Progress, ScrollArea, Stack, Text } from "@mantine/core"; import type { PatchMonOsDistributionEntry } from "@homarr/integrations"; import { useScopedI18n } from "@homarr/translation/client"; import classes from "./component.module.css"; const OS_COLORS = ["blue.6", "orange.6", "green.6", "grape.6", "cyan.6", "pink.6", "yellow.6", "teal.6"] as const; interface OsDistributionSectionProps { entries: PatchMonOsDistributionEntry[]; limit: number; showOsVersion: boolean; displayMode: "bars" | "donut"; width: number; height: number; showLegend: boolean; compact?: boolean; } export const formatOsLabel = (entry: PatchMonOsDistributionEntry, showVersion: boolean) => showVersion && entry.osVersion ? `${entry.name} ${entry.osVersion}` : entry.name; const getMantineColorVariable = (color: string) => `var(--mantine-color-${color.replace(".", "-")})`; export function OsDistributionSection({ entries, limit, showOsVersion, displayMode, width, height, showLegend, compact = false, }: OsDistributionSectionProps) { const t = useScopedI18n("widget.patchmon"); if (entries.length === 0) { return null; } const visibleEntries = limit > 0 ? entries.slice(0, limit) : entries; if (displayMode === "donut") { const chartData = visibleEntries.map((entry, i) => ({ name: formatOsLabel(entry, showOsVersion), value: entry.count, color: OS_COLORS[i % OS_COLORS.length] as string, })); const donutSize = compact ? Math.max(36, Math.min(width - 18, height - 10, 96)) : Math.max(48, Math.min(width - 24, height * 0.55, showLegend ? 140 : 180)); return ( {!compact && ( {t("osDistribution")} )}
{showLegend && (
{chartData.map((entry) => (
{entry.name} {entry.value}
))}
)}
); } const maxCount = Math.max(...visibleEntries.map((entry) => entry.count), 1); if (compact) { const maxRows = Math.max(2, Math.min(visibleEntries.length, Math.floor(height / 28), width < 160 ? 2 : 4)); const compactEntries = visibleEntries.slice(0, maxRows); if (compactEntries.length === 0) return null; return (
{compactEntries.map((entry, i) => (
{formatOsLabel(entry, showOsVersion)} {entry.count}
))}
); } return ( {t("osDistribution")} {visibleEntries.map((entry, i) => { const barValue = (entry.count / maxCount) * 100; const barColor = OS_COLORS[i % OS_COLORS.length] as string; return (
{formatOsLabel(entry, showOsVersion)} {entry.count}
); })}
); }