mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 10:35:51 +00:00
fix(proxmox): restore standalone PBS host details
Change-source: pulse-maintainer
This commit is contained in:
+54
@@ -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)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}}
|
||||
|
||||
+69
@@ -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();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user