diff --git a/packages/widgets/src/unifi-os/component.tsx b/packages/widgets/src/unifi-os/component.tsx index c5daafe3b..de808a7e8 100644 --- a/packages/widgets/src/unifi-os/component.tsx +++ b/packages/widgets/src/unifi-os/component.tsx @@ -11,7 +11,7 @@ import { useIntegrationConnected } from "@homarr/common"; import { useI18n } from "@homarr/translation/client"; import type { WidgetComponentProps } from "../definition"; -import { ThroughputChart } from "./throughput-chart"; +import { ThroughputChart, ThroughputLegend } from "./throughput-chart"; import type { ThroughputPoint } from "./throughput-history"; import { appendThroughputPoint } from "./throughput-history"; @@ -94,8 +94,11 @@ export default function UnifiOsWidget({ integrationIds, options }: WidgetCompone const wanColor = summary.wan.state === "online" ? "green" : summary.wan.state === "offline" ? "red" : "gray"; const isp = summary.wan.isp; + // No `justify="space-between"` on the outer stack: the Internet card flexes to + // take the leftover height, so there is no slack left to distribute — + // distributing it is exactly what piled empty space between the bottom rows. return ( - + {/* The site name is not decorative: a console can host several sites and the widget only shows one. Naming it makes that choice visible. */} @@ -116,11 +119,23 @@ export default function UnifiOsWidget({ integrationIds, options }: WidgetCompone )} + {/* The one block that grows; the header, the stats rows and the footer keep + their natural size. No `minHeight: 0` here on purpose: a flex item's + automatic minimum is its content, so on a tile too short for everything + the card stops shrinking at its own content and the tile scrolls, as it + already did, rather than the card being squeezed and spilling the graph + over the rows below it. */} + {/* The rates ride the header row, right-aligned opposite the title, so + they read as a heading and detach from the area below them. */} @@ -128,10 +143,15 @@ export default function UnifiOsWidget({ integrationIds, options }: WidgetCompone {t("widget.unifiOs.card.internet")} - {summary.wan.throughput === null && ( + {summary.wan.throughput === null ? ( {EMPTY_VALUE} + ) : ( + )} @@ -141,8 +161,6 @@ export default function UnifiOsWidget({ integrationIds, options }: WidgetCompone {summary.wan.throughput !== null && ( ( + + + + +); + +export interface ThroughputChartProps { + history: ThroughputPoint[]; /** Formats a raw bits-per-second value for the tooltip. */ formatRate: (bitsPerSecond: number) => string; upName: string; downName: string; } -export const ThroughputChart = ({ - history, - upLabel, - downLabel, - formatRate, - upName, - downName, -}: ThroughputChartProps) => ( - - - - - - +/** + * The wrapper is the flex child that claims the card's leftover height, and the + * chart fills it with `h="100%"`. Mantine turns that into an inline + * `height: 100%` on the chart root, which recharts' `ResponsiveContainer` then + * measures; a percentage resolves here because flex layout gives this wrapper a + * definite used height, the card above it being a flex item of a `h="100%"` + * stack inside a tile of fixed height. + */ +export const ThroughputChart = ({ history, formatRate, upName, downName }: ThroughputChartProps) => ( + , }} /> - + );