fix(proxmox): restore standalone PBS host details

Change-source: pulse-maintainer
This commit is contained in:
pulse-triage[bot]
2026-08-27 01:30:03 +01:00
parent 479cce1d73
commit 325ff793c8
3 changed files with 134 additions and 34 deletions
@@ -28,6 +28,10 @@ vi.mock('@/components/Discovery/DiscoveryTab', () => ({
DiscoveryTab: () => <div data-testid="discovery-tab" />,
}));
vi.mock('@/components/Workloads/StackedDiskBar', () => ({
StackedDiskBar: () => <div data-testid="stacked-disk-bar" />,
}));
vi.mock('@/api/resources', () => ({
ResourceAPI: {
getFacetBundle: vi.fn().mockResolvedValue({
@@ -40,6 +44,7 @@ vi.mock('@/api/resources', () => ({
vi.mock('@/api/ai', () => ({
AIAPI: {
getSettings: vi.fn().mockResolvedValue({ discovery_enabled: false }),
getResourceIntelligence: vi.fn().mockResolvedValue({
resource_id: 'resource-1',
health: {
@@ -206,6 +211,55 @@ describe('ResourceDetailDrawer service cards', () => {
expect(activeTasks.getByText('Queued')).toBeInTheDocument();
});
it('renders merged agent hardware for a standalone PBS host', () => {
const resource = baseResource({
id: 'pbs-agent-1',
type: 'pbs',
name: 'pbs-bare-metal',
displayName: 'PBS Bare Metal',
platformId: 'pbs-bare-metal',
platformType: 'proxmox-pbs',
sourceType: 'hybrid',
memory: { current: 50, total: 16_000, used: 8_000, free: 8_000 },
platformData: {
sources: ['pbs', 'agent'],
pbs: {
hostname: 'pbs-bare-metal',
connectionHealth: 'online',
datastoreCount: 1,
},
agent: {
agentId: 'agent-pbs-1',
agentVersion: '6.4.0',
hostname: 'pbs-bare-metal',
osName: 'Debian GNU/Linux',
osVersion: '13',
kernelVersion: '6.12.0-pve',
architecture: 'amd64',
cpuCount: 8,
networkInterfaces: [{ name: 'eno1', addresses: ['192.0.2.10'] }],
disks: [{ mountpoint: '/', total: 10_000, used: 4_000, free: 6_000 }],
sensors: { temperatureCelsius: { cpu_package: 61 } },
},
},
});
const { getByTestId } = render(() => (
<ResourceDetailDrawer resource={resource} initialShowHostDetails />
));
expandPlatformDetails(getByTestId);
const hostDetails = within(getByTestId('resource-host-details-section'));
expect(hostDetails.getByText('System')).toBeInTheDocument();
expect(hostDetails.getByText('Hardware')).toBeInTheDocument();
expect(hostDetails.getByText('Network')).toBeInTheDocument();
expect(hostDetails.getByText('Disks')).toBeInTheDocument();
expect(hostDetails.getByText('Thermals')).toBeInTheDocument();
expect(hostDetails.getByText('Debian GNU/Linux 13')).toBeInTheDocument();
expect(hostDetails.getByText('eno1')).toBeInTheDocument();
expect(hostDetails.getByText('192.0.2.10')).toBeInTheDocument();
});
it('renders PMG card with compact summary and queue/mail breakdown sections', () => {
const resource = baseResource({
id: 'pmg-1',
@@ -1,6 +1,5 @@
import { For, Show, createMemo, type Accessor, type JSX } from 'solid-js';
import { InlineDetailTableRow } from '@/components/shared/InlineDetailTableRow';
import { StatusDot } from '@/components/shared/StatusDot';
import { TableCell, TableHead, TableRow } from '@/components/shared/Table';
import {
@@ -19,6 +18,7 @@ import {
import {
createPlatformResourceDetailState,
getPlatformResourceDetailRowInteractionProps,
PlatformResourceDetailTableRow,
PlatformResourceDetailToggleButton,
} from '@/features/platformPage/PlatformResourceDetailTableRow';
import type { PBSBackup } from '@/types/api';
@@ -44,6 +44,7 @@ import {
interface BackupServerRow {
key: string;
resource: Resource;
serverName: string;
online: boolean;
connectionLabel: string;
@@ -124,6 +125,7 @@ export function buildBackupServerRows(
const datastores = server.pbs?.datastores ?? [];
const memoryTotal = server.memory?.total ?? 0;
const host = {
resource: server,
serverName: server.name,
online: serverIsOnline(server),
connectionLabel: connectionLabel(server),
@@ -413,39 +415,14 @@ export function ProxmoxBackupServersTable(props: {
</TableCell>
</Show>
</TableRow>
<Show when={isExpanded()}>
<InlineDetailTableRow
cellId={detailRowId()}
colspan={visibleColumns().length}
class="bg-surface-alt/40"
cellClass="px-3 py-2 whitespace-normal"
contentClass="min-w-0 whitespace-normal"
data-inline-detail-for={row.key}
>
<div class="grid grid-cols-2 gap-x-3 gap-y-1 text-[11px] sm:grid-cols-4">
<span>
<span class="font-medium text-base-content">Server:</span>{' '}
<span class="text-muted">{row.serverName}</span>
</span>
<span>
<span class="font-medium text-base-content">Datastore:</span>{' '}
<span class="font-mono text-muted">{row.datastore?.name || '—'}</span>
</span>
<span>
<span class="font-medium text-base-content">Version:</span>{' '}
<span class="text-muted">{row.version || '—'}</span>
</span>
<span>
<span class="font-medium text-base-content">Memory:</span>{' '}
<span class="text-muted">
{row.memoryTotal
? `${formatPlatformTableBytesValue(row.memoryUsed, '0 B')} / ${formatPlatformTableBytesValue(row.memoryTotal)}`
: '—'}
</span>
</span>
</div>
</InlineDetailTableRow>
</Show>
<PlatformResourceDetailTableRow
resource={row.resource}
open={isExpanded()}
detailRowId={detailRowId()}
colSpan={visibleColumns().length}
initialShowHostDetails
onClose={() => detail.close(rowIdentity)}
/>
</>
);
}}
@@ -0,0 +1,69 @@
import { fireEvent, render, screen } from '@solidjs/testing-library';
import { describe, expect, it, vi } from 'vitest';
import type { Resource } from '@/types/resource';
import { ProxmoxBackupServersTable } from '../ProxmoxBackupServersTable';
vi.mock('@/components/Infrastructure/ResourceDetailDrawer', () => ({
ResourceDetailDrawer: (props: {
resource: Resource;
initialShowHostDetails?: boolean;
onClose?: () => void;
}) => (
<div
data-testid="pbs-resource-detail"
data-resource-id={props.resource.id}
data-host-details-open={String(props.initialShowHostDetails === true)}
>
<button type="button" onClick={props.onClose}>
Close details
</button>
</div>
),
}));
const makePbsResource = (): Resource =>
({
id: 'pbs-1',
type: 'pbs',
name: 'pbs-main',
displayName: 'PBS Main',
platformId: 'pbs-main',
platformType: 'proxmox-pbs',
sourceType: 'hybrid',
status: 'online',
lastSeen: 1_700_000_000_000,
cpu: { current: 12.4 },
memory: { current: 40, total: 8_000, used: 3_200, free: 4_800 },
pbs: {
instanceId: 'pbs-main',
version: '3.2.1',
connectionHealth: 'healthy',
datastores: [{ name: 'tank', total: 1_000, used: 400, available: 600, usagePercent: 40 }],
},
platformData: {
sources: ['pbs', 'agent'],
agent: {
agentId: 'agent-pbs-1',
hostname: 'pbs-main',
osName: 'Debian GNU/Linux',
disks: [{ mountpoint: '/', total: 10_000, used: 4_000 }],
},
pbs: { instanceId: 'pbs-main', hostname: 'pbs-main', datastoreCount: 1 },
},
}) as Resource;
describe('ProxmoxBackupServersTable details', () => {
it('opens the canonical resource drawer with merged host details expanded', () => {
render(() => <ProxmoxBackupServersTable servers={[makePbsResource()]} />);
fireEvent.click(screen.getByRole('button', { name: 'Expand details for pbs-main' }));
const detail = screen.getByTestId('pbs-resource-detail');
expect(detail).toHaveAttribute('data-resource-id', 'pbs-1');
expect(detail).toHaveAttribute('data-host-details-open', 'true');
fireEvent.click(screen.getByRole('button', { name: 'Close details' }));
expect(screen.queryByTestId('pbs-resource-detail')).not.toBeInTheDocument();
});
});