mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 18:45:53 +00:00
fix(workloads): show RAM usage in guest drawer Memory card
The guest drawer Overview card titled Memory only rendered supplementary balloon/swap lines, never the primary RAM used/total, so an expanded guest showed a Memory card containing just a swap figure. It now leads with Usage/Total/Free (mirroring the node drawer Memory card) and keeps balloon and swap as trailing rows. Replaces the string-only getGuestDrawerMemoryExtraLines with a structured getGuestDrawerMemoryRows and removes the now-dead memoryExtraLines prop from the guest drawer chain.
This commit is contained in:
@@ -31,7 +31,6 @@ export const GuestDrawer: Component<GuestDrawerProps> = (props) => {
|
||||
historyTarget,
|
||||
ipAddresses,
|
||||
guestOsSummary,
|
||||
memoryExtraLines,
|
||||
networkInterfaces,
|
||||
normalizedTags,
|
||||
setHistoryRange,
|
||||
@@ -88,7 +87,6 @@ export const GuestDrawer: Component<GuestDrawerProps> = (props) => {
|
||||
hasNetworkInterfaces={hasNetworkInterfaces()}
|
||||
hasOsInfo={hasOsInfo()}
|
||||
ipAddresses={ipAddresses()}
|
||||
memoryExtraLines={memoryExtraLines()}
|
||||
networkInterfaces={networkInterfaces()}
|
||||
normalizedTags={normalizedTags()}
|
||||
onCustomUrlChange={props.onCustomUrlChange}
|
||||
|
||||
@@ -8,7 +8,7 @@ import { formatBytes, formatUptime } from '@/utils/format';
|
||||
import type { MetricDisplayThresholds } from '@/utils/metricThresholds';
|
||||
|
||||
import { DiskList } from './DiskList';
|
||||
import { isGuestDrawerVM } from './guestDrawerModel';
|
||||
import { getGuestDrawerMemoryRows, isGuestDrawerVM } from './guestDrawerModel';
|
||||
|
||||
import type { GuestDrawerProps } from './guestDrawerModel';
|
||||
|
||||
@@ -23,7 +23,6 @@ interface GuestDrawerOverviewProps {
|
||||
hasNetworkInterfaces: boolean;
|
||||
hasOsInfo: boolean;
|
||||
ipAddresses: string[];
|
||||
memoryExtraLines?: string[];
|
||||
networkInterfaces: NonNullable<GuestDrawerProps['guest']['networkInterfaces']>;
|
||||
normalizedTags: string[];
|
||||
onCustomUrlChange?: GuestDrawerProps['onCustomUrlChange'];
|
||||
@@ -255,13 +254,22 @@ export function GuestDrawerOverview(props: GuestDrawerOverviewProps) {
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
<Show when={props.memoryExtraLines && props.memoryExtraLines.length > 0}>
|
||||
<Show when={getGuestDrawerMemoryRows(props.guest).length > 0}>
|
||||
<div class="rounded border border-border bg-surface p-3 shadow-sm">
|
||||
<h3 class="text-[11px] font-medium uppercase tracking-wide text-base-content mb-2">
|
||||
Memory
|
||||
</h3>
|
||||
<div class="space-y-1 text-[11px] text-muted">
|
||||
<For each={props.memoryExtraLines}>{(line) => <div>{line}</div>}</For>
|
||||
<div class="space-y-1.5 text-[11px]">
|
||||
<For each={getGuestDrawerMemoryRows(props.guest)}>
|
||||
{(row) => (
|
||||
<div class="flex items-center justify-between gap-2 min-w-0">
|
||||
<span class="shrink-0 text-muted">{row.label}</span>
|
||||
<span class="truncate text-right font-medium text-base-content" title={row.value}>
|
||||
{row.value}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</For>
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
@@ -6,7 +6,7 @@ import type {
|
||||
} from '@/api/charts';
|
||||
|
||||
import { formatHistoryChartTooltipValue } from '@/components/shared/historyChartModel';
|
||||
import { formatBytes } from '@/utils/format';
|
||||
import { formatBytes, formatPercent } from '@/utils/format';
|
||||
import { getCanonicalWorkloadId, resolveWorkloadType } from '@/utils/workloads';
|
||||
|
||||
type Guest = WorkloadGuest;
|
||||
@@ -280,19 +280,44 @@ export const getGuestDrawerAgentTitle = (guest: Guest): string => {
|
||||
return isGuestDrawerVM(guest) ? `QEMU guest agent ${version}` : version;
|
||||
};
|
||||
|
||||
export const getGuestDrawerMemoryExtraLines = (guest: Guest): string[] | undefined => {
|
||||
if (!guest.memory) return undefined;
|
||||
export interface GuestDrawerMemoryRow {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
const lines: string[] = [];
|
||||
const total = guest.memory.total ?? 0;
|
||||
if (guest.memory.balloon && guest.memory.balloon > 0 && guest.memory.balloon !== total) {
|
||||
lines.push(`Balloon: ${formatBytes(guest.memory.balloon)}`);
|
||||
// Memory rows for the guest drawer Overview card. Leads with the primary
|
||||
// RAM usage (Usage / Total / Free) so the "Memory" card lives up to its title
|
||||
// and matches the node drawer's memory card, then appends balloon/swap when
|
||||
// present. The collapsed row only shows the RAM gauge; the drawer is where the
|
||||
// breakdown belongs.
|
||||
export const getGuestDrawerMemoryRows = (guest: Guest): GuestDrawerMemoryRow[] => {
|
||||
const memory = guest.memory;
|
||||
if (!memory) return [];
|
||||
|
||||
const rows: GuestDrawerMemoryRow[] = [];
|
||||
const total = memory.total ?? 0;
|
||||
const used = memory.used ?? 0;
|
||||
|
||||
if (total > 0) {
|
||||
rows.push({ label: 'Usage', value: `${formatPercent((used / total) * 100)} · ${formatBytes(used)}` });
|
||||
rows.push({ label: 'Total', value: formatBytes(total) });
|
||||
if (typeof memory.free === 'number') {
|
||||
rows.push({ label: 'Free', value: formatBytes(memory.free) });
|
||||
}
|
||||
}
|
||||
if (guest.memory.swapTotal && guest.memory.swapTotal > 0) {
|
||||
const swapUsed = guest.memory.swapUsed ?? 0;
|
||||
lines.push(`Swap: ${formatBytes(swapUsed)} / ${formatBytes(guest.memory.swapTotal)}`);
|
||||
|
||||
if (memory.balloon && memory.balloon > 0 && memory.balloon !== total) {
|
||||
rows.push({ label: 'Balloon', value: formatBytes(memory.balloon) });
|
||||
}
|
||||
return lines.length > 0 ? lines : undefined;
|
||||
|
||||
if (memory.swapTotal && memory.swapTotal > 0) {
|
||||
rows.push({
|
||||
label: 'Swap',
|
||||
value: `${formatBytes(memory.swapUsed ?? 0)} / ${formatBytes(memory.swapTotal)}`,
|
||||
});
|
||||
}
|
||||
|
||||
return rows;
|
||||
};
|
||||
|
||||
export const hasGuestDrawerFilesystemDetails = (guest: Guest): boolean =>
|
||||
|
||||
@@ -29,7 +29,6 @@ import {
|
||||
getGuestDrawerBackupPresentation,
|
||||
GUEST_DRAWER_HISTORY_DEFAULT_RANGE,
|
||||
getGuestDrawerHistoryTarget,
|
||||
getGuestDrawerMemoryExtraLines,
|
||||
getGuestDrawerNetworkInterfaces,
|
||||
hasGuestDrawerFilesystemDetails,
|
||||
hasGuestDrawerOsInfo,
|
||||
@@ -78,7 +77,6 @@ export function useGuestDrawerState(props: GuestDrawerProps) {
|
||||
const agentTitle = createMemo(() => getGuestDrawerAgentTitle(props.guest));
|
||||
const hasAgentInfo = createMemo(() => agentLabel().length > 0);
|
||||
const ipAddresses = createMemo(() => props.guest.ipAddresses || []);
|
||||
const memoryExtraLines = createMemo(() => getGuestDrawerMemoryExtraLines(props.guest));
|
||||
const hasFilesystemDetails = createMemo(() => hasGuestDrawerFilesystemDetails(props.guest));
|
||||
const networkInterfaces = createMemo(() => getGuestDrawerNetworkInterfaces(props.guest));
|
||||
const hasNetworkInterfaces = createMemo(() => networkInterfaces().length > 0);
|
||||
@@ -158,7 +156,6 @@ export function useGuestDrawerState(props: GuestDrawerProps) {
|
||||
historyTarget,
|
||||
historyRange,
|
||||
ipAddresses,
|
||||
memoryExtraLines,
|
||||
networkInterfaces,
|
||||
normalizedTags,
|
||||
osName,
|
||||
|
||||
Reference in New Issue
Block a user