Merge pull request #6713 from homarr-labs/fix/v2-system-resource-widget

fix(v2 system resources widget): overflow and initial chart render
This commit is contained in:
Bergasha authored and GitHub committed 2026-08-27 11:09:18 +10:00
commit 70e1b29913
3 files changed
+38 -17

No files matched your search

@@ -53,7 +53,7 @@ export const CommonChart = ({
ref={ref}
h={"100%"}
pos={"relative"}
style={{ overflow: "visible", border: `1px solid ${borderColor}` }}
style={{ overflow: "hidden", border: `1px solid ${borderColor}` }}
p={0}
bg={backgroundColor}
radius={board.itemRadius}
@@ -127,7 +127,12 @@ export const CommonChart = ({
},
}}
tooltipAnimationDuration={200}
tooltipProps={tooltipProps}
tooltipProps={{
// Render via portal so the tooltip isn't clipped by the card's overflow:hidden
// (needed to stop the chart line itself bleeding past its rounded corners).
portal: typeof document !== "undefined" ? document.body : undefined,
...tooltipProps,
}}
withTooltip={height >= 64}
yAxisProps={yAxisProps}
fillOpacity={chartType === "area" ? 0.3 : undefined}
@@ -19,6 +19,15 @@ const COMPACT_HISTORY_SIZE = 15;
const ADVANCED_HISTORY_SIZE = 60;
const ALL_SYSTEM_CHARTS = ["cpu", "memory", "gpu", "network"] as const;
const ADVANCED_CHART_COLUMN_BREAKPOINTS = [
{ minWidth: 1100, columns: 4 },
{ minWidth: 560, columns: 2 },
{ minWidth: 0, columns: 1 },
] as const;
const getAdvancedChartColumns = (width: number): number =>
ADVANCED_CHART_COLUMN_BREAKPOINTS.find(({ minWidth }) => width >= minWidth)?.columns ?? 1;
type SystemChart = WidgetComponentProps<"systemResources">["options"]["visibleCharts"][number];
type ChartItem = {
@@ -110,14 +119,13 @@ export default function SystemResources({
lastUpdatedAt.current = dataUpdatedAt;
setHistoryByIntegration((previous) =>
Object.fromEntries(
data.map((entry) => [
entry.integrationId,
appendBoundedHistory(
previous[entry.integrationId] ?? [],
toChartItem(entry.healthInfo),
ADVANCED_HISTORY_SIZE,
),
]),
data.map((entry) => {
const currentItem = toChartItem(entry.healthInfo);
// Seed with the current item when there's no history yet, so the first real
// update lands at 2 points instead of dropping back to the single-value fallback.
const seed = previous[entry.integrationId] ?? [currentItem];
return [entry.integrationId, appendBoundedHistory(seed, currentItem, ADVANCED_HISTORY_SIZE)];
}),
),
);
}, [dataUpdatedAt, data]);
@@ -126,7 +134,9 @@ export default function SystemResources({
const panelWidth = width / panelColumns;
const renderCharts = (entry: (typeof data)[number], availableWidth: number, availableHeight: number) => {
const currentItem = toChartItem(entry.healthInfo);
const fullHistory = historyByIntegration[entry.integrationId] ?? [currentItem];
// Duplicate the first point so the chart has two points to draw a line from
// immediately, instead of showing the single-value fallback until the next poll.
const fullHistory = historyByIntegration[entry.integrationId] ?? [currentItem, currentItem];
const history = isAdvanced ? fullHistory : fullHistory.slice(-COMPACT_HISTORY_SIZE);
return (
@@ -225,20 +235,27 @@ const SystemCharts = ({
const showNetwork = visibleCharts.includes("network");
const labelDisplayMode = isAdvanced ? "textWithIcon" : options.labelDisplayMode;
const chartCount = visibleCharts.length;
const chartColumns = isAdvanced && width >= 560 ? 2 : 1;
const chartColumns = useMemo(
() => (isAdvanced ? getAdvancedChartColumns(width) : 1),
[isAdvanced, width],
);
const compactChartGap = 8;
const compactRowHeight = 56;
const chartHeight = isAdvanced
? 180
: `calc((100% - ${Math.max(0, chartCount - 1) * compactChartGap}px) / ${Math.max(1, chartCount)})`;
? 110
: Math.max(
28,
Math.min(compactRowHeight, (height - Math.max(0, chartCount - 1) * compactChartGap) / Math.max(1, chartCount)),
);
return (
<Stack gap={isAdvanced ? "xs" : compactChartGap} h={isAdvanced ? "auto" : height} miw={0}>
<Stack gap={isAdvanced ? "xs" : compactChartGap} h="auto" miw={0}>
{showTitle && (
<Text size="sm" fw={600} truncate="end">
{integrationName}
</Text>
)}
<SimpleGrid cols={chartColumns} spacing={isAdvanced ? "xs" : compactChartGap} style={{ flex: 1, minHeight: 0 }}>
<SimpleGrid cols={chartColumns} spacing={isAdvanced ? "xs" : compactChartGap}>
{chartCount === 0 && (
<Center h="100%">
<Text size="sm" c="dimmed">
@@ -11,7 +11,6 @@ import type { BoardItemAdvancedOptions } from "@homarr/validation/shared";
import classes from "./widget-card-shell.module.css";
const getOverflow = (kind: WidgetKind, hasCustomCssClasses: boolean): CSSProperties => {
if (kind === "systemResources") return { overflowX: "visible", overflowY: "visible" };
if (kind === "iframe" || kind === "assistant") return { overflowX: "hidden", overflowY: "hidden" };
if (hasCustomCssClasses) return {};
return { overflowX: "hidden", overflowY: "auto" };