From 5ca05949b857ca0417eaa8a9cf435c64b41c1b44 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Sat, 16 May 2026 14:56:57 +0100 Subject: [PATCH] workloads(drawer): seed guest history charts with current values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GuestDrawer.tsx mounted GuestDrawerHistory without a fallbackMetrics prop, so mergeFallbackHistoryMetrics never fired and any guest with <2 stored samples in the selected range showed "Collecting history" indefinitely — even though the row already carries live cpu/memory/ disk/net/diskio values. Add getGuestDrawerHistoryFallbackMetrics (mirrors the node helper), project cpu/memory/disk/netin/netout/diskread/diskwrite from the current Guest snapshot (multiplying the 0-1 cpu fraction up to a percent so it matches the chart's % scale), and pass it through. Flat 2-point sparkline now renders immediately and gets replaced by real history as samples accumulate. --- .../src/components/Workloads/GuestDrawer.tsx | 13 ++++++-- .../components/Workloads/guestDrawerModel.ts | 32 +++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/frontend-modern/src/components/Workloads/GuestDrawer.tsx b/frontend-modern/src/components/Workloads/GuestDrawer.tsx index 5054bf765..1e6e191ef 100644 --- a/frontend-modern/src/components/Workloads/GuestDrawer.tsx +++ b/frontend-modern/src/components/Workloads/GuestDrawer.tsx @@ -1,6 +1,6 @@ -import { Component, Show, Suspense } from 'solid-js'; +import { Component, Show, Suspense, createMemo } from 'solid-js'; import { DiscoveryTab } from '../Discovery/DiscoveryTab'; -import type { GuestDrawerProps } from './guestDrawerModel'; +import { getGuestDrawerHistoryFallbackMetrics, type GuestDrawerProps } from './guestDrawerModel'; import { useGuestDrawerState } from './useGuestDrawerState'; import { GuestDrawerHistory, GuestDrawerHistoryRangeSelect } from './GuestDrawerHistory'; import { GuestDrawerOverview } from './GuestDrawerOverview'; @@ -35,6 +35,9 @@ export const GuestDrawer: Component = (props) => { webInterfaceTargetLabel, } = useGuestDrawerState(props); const headingId = () => `guest-drawer-heading-${guestId()}`; + const historyFallbackMetrics = createMemo(() => + getGuestDrawerHistoryFallbackMetrics(props.guest), + ); return (
@@ -118,7 +121,11 @@ export const GuestDrawer: Component = (props) => { {hasHistorySupport() && activeTab() === 'history' && (
- +
)} diff --git a/frontend-modern/src/components/Workloads/guestDrawerModel.ts b/frontend-modern/src/components/Workloads/guestDrawerModel.ts index 2a42e3f26..344f3e3de 100644 --- a/frontend-modern/src/components/Workloads/guestDrawerModel.ts +++ b/frontend-modern/src/components/Workloads/guestDrawerModel.ts @@ -52,6 +52,38 @@ export interface GuestDrawerBackupPresentation { export const isGuestDrawerVM = (guest: Guest): boolean => resolveWorkloadType(guest) === 'vm'; +// Fallback current-value metrics for the guest drawer's history charts. +// Mirrors `getNodeDrawerHistoryFallbackMetrics` — supplies a single +// finite value per metric so `mergeFallbackHistoryMetrics` can synthesize +// a flat 2-point line, replacing the "Collecting history" placeholder +// when the metrics-store hasn't yet accumulated 2+ samples for that +// resource within the selected range. Keys must match the `metric` +// strings declared in `GUEST_DRAWER_HISTORY_GROUPS`. +export const getGuestDrawerHistoryFallbackMetrics = ( + guest: Guest, +): Record => { + const cpuRaw = typeof guest.cpu === 'number' ? guest.cpu : undefined; + const cpuPercent = + cpuRaw === undefined || !Number.isFinite(cpuRaw) + ? undefined + : cpuRaw <= 1.5 + ? cpuRaw * 100 + : cpuRaw; + const memUsage = guest.memory?.usage; + const diskUsage = guest.disk?.usage; + const finite = (value: number | undefined): number | undefined => + typeof value === 'number' && Number.isFinite(value) ? value : undefined; + return { + cpu: finite(cpuPercent), + memory: finite(memUsage), + disk: finite(diskUsage), + netin: finite(guest.networkIn), + netout: finite(guest.networkOut), + diskread: finite(guest.diskRead), + diskwrite: finite(guest.diskWrite), + }; +}; + export const GUEST_DRAWER_HISTORY_DEFAULT_RANGE: HistoryTimeRange = '24h'; export const GUEST_DRAWER_HISTORY_GROUPS: GuestDrawerHistoryGroupConfig[] = [