mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 02:25:56 +00:00
fix(proxmox): keep backup details on backups tab
This commit is contained in:
@@ -181,13 +181,9 @@ focus restoration, and responsive drawer behavior on one primitive. Proxmox
|
||||
Backup Server rows follow this rule and request the shared host-details
|
||||
disclosure open initially so a merged agent's system, hardware, network, disk,
|
||||
and thermal facts remain discoverable from the PBS surface.
|
||||
`ProxmoxBackupServersTable` is the single PBS host-health composition on both
|
||||
Proxmox Overview and Backups. Overview places it between PVE nodes and guests
|
||||
so a standalone PBS host remains part of the estate scan; Backups places the
|
||||
same table beside recovery evidence. Overview must omit the backup-artifact
|
||||
count column because it does not own the PBS artifact request, while both
|
||||
placements retain the same responsive columns, row interaction, and canonical
|
||||
resource drawer rather than introducing an overview-only PBS row variant.
|
||||
`ProxmoxBackupServersTable` belongs to the Proxmox Backups tab. Proxmox
|
||||
Overview must not duplicate that domain table between its node and guest
|
||||
regions; the tab boundary owns PBS server, datastore, and artifact detail.
|
||||
When that surface receives the provider-owned PBS resource and its host Agent
|
||||
as separate canonical resources, `ProxmoxBackupServersTable` may assemble a
|
||||
presentation-only drawer resource only after one unique normalized host
|
||||
|
||||
@@ -42,12 +42,12 @@ backup artifact, recovery point, protection posture, or restore operation, and
|
||||
storage/recovery consumers must continue to use the canonical resource and
|
||||
provider identities for all domain authority.
|
||||
The Proxmox overview is also a large-estate read-side consumer: it owns one
|
||||
canonical unified-resource snapshot for its PVE node, PBS host-health, and guest
|
||||
regions, and its shared workloads adapter must consume that snapshot without
|
||||
starting a second workload or infrastructure inventory request. Backup and
|
||||
recovery tables keep their domain-specific evidence requests, while an overview
|
||||
refresh must update all overview regions from the same owner snapshot rather
|
||||
than mixing reads from different inventory generations.
|
||||
canonical unified-resource snapshot for its node and guest regions, and its
|
||||
shared workloads adapter must consume that snapshot without starting a second
|
||||
workload or infrastructure inventory request. Backup and recovery tables keep
|
||||
their domain-specific evidence requests, while an overview refresh must update
|
||||
all overview regions from the same owner snapshot rather than mixing reads
|
||||
from different inventory generations.
|
||||
The physical-disks surface consumes every page in the server-declared unified
|
||||
resource result, scopes same-named Proxmox nodes by instance, and never hides a
|
||||
disk behind a client-side page ceiling. Search includes vendor, WWN, transport,
|
||||
@@ -486,18 +486,17 @@ summary row. Compact layouts must not stack those secondary facts beneath the
|
||||
resource name and make the row taller: keep essential identity inline when no
|
||||
detail disclosure exists, and otherwise preserve supporting context in its
|
||||
existing column, the row's accessible title, or the expanded detail content.
|
||||
The Backup servers summary owns PBS reachability and datastore capacity and is
|
||||
shared by Proxmox Overview and Backups, but its row expansion is the canonical
|
||||
unified-resource drawer, not a second storage-local detail model. Overview
|
||||
places this health summary after PVE nodes and before guests so bare-metal PBS
|
||||
hosts remain in the estate scan. Because Overview consumes only the canonical
|
||||
resource snapshot, it omits the artifact-count column rather than rendering
|
||||
zero from an unrequested PBS backup feed; the Backups placement supplies that
|
||||
domain API evidence and retains the count. A PBS resource merged with a Pulse
|
||||
Agent keeps the PBS service evidence and exposes the agent's system, hardware,
|
||||
network, disk, thermal, history, and management context through that shared
|
||||
drawer. Storage/recovery does not duplicate agent telemetry or invent a
|
||||
competing provider drawer hierarchy.
|
||||
The Backup servers summary on the Proxmox Backups tab owns PBS reachability and
|
||||
datastore capacity, but its row expansion is the canonical unified-resource
|
||||
drawer, not a second storage-local detail model. A PBS resource merged with a
|
||||
Pulse Agent keeps the
|
||||
PBS service evidence and exposes the agent's system, hardware, network, disk,
|
||||
thermal, history, and management context through that shared drawer. Bare-metal
|
||||
PBS hosts therefore remain fully inspectable after leaving the standalone
|
||||
Machines surface, while storage/recovery does not duplicate agent telemetry or
|
||||
invent a competing provider drawer hierarchy.
|
||||
Proxmox Overview must not duplicate this domain table; its route-scoped
|
||||
snapshot remains limited to the node and guest regions it owns.
|
||||
The product-family projection may still deliver the PBS service and its Agent
|
||||
host as separate resources. In that case the Backup servers table correlates
|
||||
only a unique normalized host-identity match for drawer presentation, preserves
|
||||
@@ -590,17 +589,15 @@ complete client-side result set; windowing must not become pagination, a partial
|
||||
count, or a recovery-local `Next` / `Load more` control. Expanded coverage
|
||||
evidence remains owned by the visible workload row.
|
||||
The Proxmox shell hydrates Overview, Storage, Replication, Backups, Ceph, and
|
||||
Mail from route-scoped resource families. Overview includes PBS service rows
|
||||
and Agent facets in its bounded snapshot so host health and the canonical PBS
|
||||
drawer do not depend on background hydration of Backups or Storage. Only the
|
||||
visible tab consumes realtime reconciliation. Desktop background hydration may
|
||||
prefetch the other route families, while phone background hydration is bounded
|
||||
to Storage because the phone shell retains at most the two most-recent tab
|
||||
trees. Storage reuses the shell's bounded agent/PBS/storage/physical-disk/Ceph
|
||||
source instead of opening a duplicate page query or an all-estate subscription,
|
||||
and is prewarmed for the common Overview/Storage transition; hidden route-state
|
||||
effects remain dormant and a forced Proxmox storage scope is not serialized as
|
||||
redundant URL state.
|
||||
Mail from route-scoped resource families. Only the visible tab consumes
|
||||
realtime reconciliation. Desktop background hydration may prefetch the other
|
||||
route families, while phone background hydration is bounded to Storage because
|
||||
the phone shell retains at most the two most-recent tab trees. Storage reuses
|
||||
the shell's bounded agent/PBS/storage/physical-disk/Ceph source instead of
|
||||
opening a duplicate page query or an all-estate subscription, and is prewarmed
|
||||
for the common Overview/Storage transition; hidden route-state effects remain
|
||||
dormant and a forced Proxmox storage scope is not serialized as redundant URL
|
||||
state.
|
||||
PBS server/datastore rows may display backup counts, but the
|
||||
counts must come from the PBS backup API artifact identity, not from a
|
||||
datastore-capacity approximation. The table owns which PBS artifact count is
|
||||
|
||||
@@ -426,14 +426,6 @@ inventory: operator-visible guest names, VMIDs, node identities, status, and
|
||||
provider scope may retain a parent node, but opaque unified-resource `id`
|
||||
hashes must not create node matches that the normalized workload table cannot
|
||||
show.
|
||||
That Overview snapshot also includes PBS service resources and their Agent
|
||||
facets. The page composes the same `ProxmoxBackupServersTable` used by Backups
|
||||
between PVE nodes and guests, so standalone PBS health and the canonical
|
||||
resource drawer remain discoverable without returning the Agent to Machines or
|
||||
building a second host projection. Overview does not own PBS artifact evidence
|
||||
and therefore suppresses that table's backup-count column; service identity,
|
||||
datastore capacity, current Agent telemetry, and History continue to use the
|
||||
same fail-closed correlation boundary as the Backups placement.
|
||||
Large platform inventories may bound their initial row projection through the
|
||||
shared platform-table preview primitive so the next canonical surface remains
|
||||
in the initial reading flow. Proxmox node consumers retain the page model's
|
||||
@@ -832,10 +824,9 @@ container inventory table.
|
||||
10. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.ts` shared with `performance-and-scalability`: unified resource table state, grouping, and windowing are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
11. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts` shared with `performance-and-scalability`: unified resource table viewport sync and selected-row reveal are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary.
|
||||
12. `frontend-modern/src/features/proxmox/ProxmoxBackupServersTable.tsx` shared with `storage-recovery`: Proxmox backup server table rows are both a storage/recovery backup-health surface and a unified-resource platform-table consumer boundary.
|
||||
The same table is composed on Proxmox Overview and Backups. Overview reads
|
||||
PBS and Agent facets from its owner snapshot and suppresses artifact counts;
|
||||
Backups may add counts from its PBS artifact request. Both placements keep
|
||||
the canonical PBS row and drawer contract below.
|
||||
The table is composed on the Proxmox Backups tab and must not be duplicated
|
||||
on Overview. The Backups placement keeps the canonical PBS row and drawer
|
||||
contract below while owning the domain-specific artifact request.
|
||||
Each row carries the canonical PBS `Resource` into the shared platform
|
||||
resource-detail row. When coalescence has attached an agent facet, or when
|
||||
the product-family projection contains exactly one separate Agent resource
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
{
|
||||
"version": 1,
|
||||
"base_sha": "aea8d3497b0474d985602c81fe17be228446c954",
|
||||
"verified_at": "2026-08-28T14:52:18Z",
|
||||
"base_sha": "0dc2c8c16d9612f981a29055cc703f6100cdf8cb",
|
||||
"verified_at": "2026-08-28T19:44:59Z",
|
||||
"result": "passed",
|
||||
"changed_paths": [
|
||||
"frontend-modern/src/components/Workloads/NodeDrawerOverview.tsx",
|
||||
"frontend-modern/src/components/shared/DrawerAttentionSection.tsx"
|
||||
"frontend-modern/src/features/proxmox/ProxmoxBackupServersTable.tsx",
|
||||
"frontend-modern/src/features/proxmox/ProxmoxPageSurface.tsx"
|
||||
],
|
||||
"content_sha256": {
|
||||
"frontend-modern/src/components/Workloads/NodeDrawerOverview.tsx": "ec60044cf9b250c9d049230ee7252bf73a389956b3ab611929520ad6c70dac40",
|
||||
"frontend-modern/src/components/shared/DrawerAttentionSection.tsx": "6f1b0d01ef1e3bdcb21faff305e2c2d7763cc226cb92c0f4c4daca7f1fbf04c0"
|
||||
"frontend-modern/src/features/proxmox/ProxmoxBackupServersTable.tsx": "58e4c06e98108a69f1e62f631bb248eec626b3c6fc204e60507e377cd1633d8c",
|
||||
"frontend-modern/src/features/proxmox/ProxmoxPageSurface.tsx": "1e6daf19456ff79e7181e8117bbb2064feb53b852438294a58dd2fa5197b3817"
|
||||
},
|
||||
"routes": [
|
||||
"/attention-verification.html"
|
||||
],
|
||||
"routes": ["/proxmox/overview", "/proxmox/backups/date"],
|
||||
"viewports": [
|
||||
{
|
||||
"width": 1440,
|
||||
"height": 900
|
||||
"width": 1280,
|
||||
"height": 800
|
||||
},
|
||||
{
|
||||
"width": 390,
|
||||
@@ -25,15 +23,15 @@
|
||||
}
|
||||
],
|
||||
"states": [
|
||||
"collapsed five-alert node summary showing the first three resource-specific alerts",
|
||||
"expanded node summary showing warning, critical, info, and acknowledged severity badges",
|
||||
"desktop summary bounded to 768 pixels with no horizontal page overflow",
|
||||
"390 pixel summary contained within the viewport with no horizontal page overflow"
|
||||
"mock-backed Proxmox Overview with the bounded node preview flowing directly into Guests and no PBS server table",
|
||||
"Proxmox Backups By date view retaining the PBS server and datastore table with artifact counts",
|
||||
"expanded PBS server row retaining canonical resource details on the Backups tab",
|
||||
"desktop and narrow layouts contained within the viewport without horizontal document overflow"
|
||||
],
|
||||
"interactions": [
|
||||
"confirmed node and child VM resource names plus Memory, Disk, and Backup Age metrics remain visible beside their problem text",
|
||||
"selected Show 2 more alerts and confirmed both hidden alerts appeared with aria-expanded=true",
|
||||
"selected Show fewer alerts and confirmed the summary returned to three visible alerts with aria-expanded=false",
|
||||
"repeated collapsed and expanded disclosure states at 1440x900 and 390x844 and confirmed no horizontal overflow"
|
||||
"opened Proxmox Overview at 1280x800 and confirmed Nodes precede Guests with a 16 pixel section gap and no backup-server table",
|
||||
"opened Proxmox Backups at 1280x800 and confirmed three PBS server/datastore rows remain visible",
|
||||
"repeated Overview at 390x844 and confirmed Nodes and Guests remain visible without a duplicated PBS table or horizontal overflow",
|
||||
"opened Proxmox Backups at 390x844, expanded the first PBS row, and confirmed canonical resource details remain usable without horizontal overflow"
|
||||
]
|
||||
}
|
||||
|
||||
+1
-1
@@ -444,7 +444,7 @@ describe('platform overview layout guardrails', () => {
|
||||
}
|
||||
|
||||
expect(proxmoxPageSurfaceSource).toContain('<ProxmoxNodesTable');
|
||||
expect(proxmoxPageSurfaceSource).toContain('<ProxmoxBackupServersTable');
|
||||
expect(proxmoxPageSurfaceSource).not.toContain('<ProxmoxBackupServersTable');
|
||||
expect(proxmoxPageSurfaceSource).toContain('<WorkloadsSurface');
|
||||
expect(proxmoxPageSurfaceSource).toContain(
|
||||
"const PROXMOX_WORKLOAD_EXCLUDED_TYPES = ['app-container'] as const",
|
||||
|
||||
@@ -40,9 +40,8 @@ import {
|
||||
// so it lives here on the Backups page, not buried on the platform Storage tab
|
||||
// where the rows read as generic "PVE" storage. One row per datastore, labelled
|
||||
// by its server; a server with no datastore data still gets a reachability row.
|
||||
// Host CPU/memory/uptime ride along on each of the server's rows. The shared
|
||||
// table appears on Overview for estate health and on Backups beside recovery
|
||||
// evidence, so both paths open the same canonical PBS/agent detail drawer.
|
||||
// Host CPU/memory/uptime ride along on each of the server's rows: PBS hosts
|
||||
// left the v5 nodes table in the v6 IA, so this is where their health lives.
|
||||
|
||||
interface BackupServerRow {
|
||||
key: string;
|
||||
@@ -245,7 +244,6 @@ export function buildBackupServerRows(
|
||||
export function ProxmoxBackupServersTable(props: {
|
||||
servers: readonly Resource[];
|
||||
backups?: readonly PBSBackup[];
|
||||
showBackupCounts?: boolean;
|
||||
emptyIcon?: JSX.Element;
|
||||
layoutWidth?: Accessor<number | null | undefined>;
|
||||
}) {
|
||||
@@ -257,11 +255,7 @@ export function ProxmoxBackupServersTable(props: {
|
||||
? getBackupServerLayoutForContainer(width)
|
||||
: 'full';
|
||||
});
|
||||
const visibleColumns = createMemo(() =>
|
||||
getBackupServerColumns(layoutMode()).filter(
|
||||
(column) => props.showBackupCounts !== false || column.id !== 'backups',
|
||||
),
|
||||
);
|
||||
const visibleColumns = createMemo(() => getBackupServerColumns(layoutMode()));
|
||||
const detail = createPlatformResourceDetailState({ idPrefix: 'proxmox-backup-server-detail' });
|
||||
const columnVisible = (column: BackupServerColumnId) =>
|
||||
visibleColumns().some((candidate) => candidate.id === column);
|
||||
|
||||
@@ -51,7 +51,6 @@ import {
|
||||
PlatformTableLoadingState,
|
||||
} from '@/features/platformPage/sharedPlatformPage';
|
||||
import { ProxmoxBackupsTable } from './ProxmoxBackupsTable';
|
||||
import { ProxmoxBackupServersTable } from './ProxmoxBackupServersTable';
|
||||
import { ProxmoxCephTable } from './ProxmoxCephTable';
|
||||
import { ProxmoxMailGatewayTable } from './ProxmoxMailGatewayTable';
|
||||
import { ProxmoxNodesTable } from './ProxmoxNodesTable';
|
||||
@@ -71,7 +70,7 @@ import {
|
||||
// REST page also carries global type aggregations, so evidence-gated tabs do
|
||||
// not require the old 1,000+ row workspace request.
|
||||
const PROXMOX_RESOURCE_QUERY_BY_TAB: Record<ProxmoxPageTabId, string> = {
|
||||
overview: 'type=agent,vm,system-container,oci-container,pbs',
|
||||
overview: 'type=agent,vm,system-container,oci-container',
|
||||
storage: 'type=agent,pbs,storage,physical_disk,ceph',
|
||||
replication: 'type=agent',
|
||||
backups: 'type=agent,vm,system-container,pbs',
|
||||
@@ -531,11 +530,6 @@ function ProxmoxOverview(props: ProxmoxOverviewProps) {
|
||||
inventoryCountsVisible={props.inventoryCountsVisible}
|
||||
/>
|
||||
</section>
|
||||
<ProxmoxBackupServersTable
|
||||
servers={currentModel().pbs}
|
||||
showBackupCounts={false}
|
||||
layoutWidth={overviewWidth.width}
|
||||
/>
|
||||
<section
|
||||
id="proxmox-guests-section"
|
||||
aria-label="Guests"
|
||||
|
||||
-9
@@ -56,15 +56,6 @@ const makePbsResource = (): Resource =>
|
||||
}) as Resource;
|
||||
|
||||
describe('ProxmoxBackupServersTable details', () => {
|
||||
it('omits artifact counts when composed as overview health', () => {
|
||||
render(() => (
|
||||
<ProxmoxBackupServersTable servers={[makePbsResource()]} showBackupCounts={false} />
|
||||
));
|
||||
|
||||
expect(screen.queryByRole('columnheader', { name: 'Backups' })).not.toBeInTheDocument();
|
||||
expect(screen.getByRole('columnheader', { name: /Backup server/ })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('opens the canonical resource drawer with merged host details expanded', () => {
|
||||
render(() => <ProxmoxBackupServersTable servers={[makePbsResource()]} />);
|
||||
|
||||
|
||||
+2
-47
@@ -14,7 +14,6 @@ const mockVersionInfo = vi.hoisted(() => vi.fn());
|
||||
const mockStorageProps = vi.hoisted(() => vi.fn());
|
||||
const mockTotalStats = vi.hoisted(() => vi.fn());
|
||||
const mockNodesTableProps = vi.hoisted(() => vi.fn());
|
||||
const mockBackupServersTableProps = vi.hoisted(() => vi.fn());
|
||||
const mockWorkloadSearch = vi.hoisted(() => vi.fn(() => ''));
|
||||
|
||||
const makeResource = (resource: Partial<Resource> & Pick<Resource, 'id' | 'type'>): Resource =>
|
||||
@@ -116,13 +115,6 @@ vi.mock('../ProxmoxBackupsTable', () => ({
|
||||
ProxmoxBackupsTable: () => <div data-testid="backups-table" />,
|
||||
}));
|
||||
|
||||
vi.mock('../ProxmoxBackupServersTable', () => ({
|
||||
ProxmoxBackupServersTable: (props: { servers: Resource[] }) => {
|
||||
mockBackupServersTableProps(props);
|
||||
return <div data-testid="backup-servers-table" data-rows={props.servers.length} />;
|
||||
},
|
||||
}));
|
||||
|
||||
vi.mock('../ProxmoxCephTable', () => ({
|
||||
ProxmoxCephTable: () => <div data-testid="ceph-table" />,
|
||||
}));
|
||||
@@ -334,36 +326,6 @@ describe('ProxmoxPageSurface contract', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps standalone PBS host health on the Proxmox overview', () => {
|
||||
const pbsServer = makeResource({
|
||||
id: 'pbs:standalone',
|
||||
type: 'pbs',
|
||||
name: 'pbs-standalone',
|
||||
platformType: 'proxmox-pbs',
|
||||
sources: ['pbs'],
|
||||
pbs: { instanceId: 'pbs-standalone', connectionHealth: 'healthy' },
|
||||
});
|
||||
const pbsAgent = makeResource({
|
||||
id: 'agent:pbs-standalone',
|
||||
type: 'agent',
|
||||
name: 'pbs-standalone',
|
||||
platformType: 'proxmox-pbs',
|
||||
sources: ['agent', 'pbs'],
|
||||
agent: { agentId: 'agent-pbs-standalone', hostname: 'pbs-standalone' },
|
||||
});
|
||||
setResources([pbsServer, pbsAgent]);
|
||||
|
||||
renderSurface();
|
||||
|
||||
expect(screen.getByTestId('backup-servers-table')).toHaveAttribute('data-rows', '2');
|
||||
expect(mockBackupServersTableProps).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
servers: [pbsServer, pbsAgent],
|
||||
showBackupCounts: false,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('shares workload search with the node inventory', () => {
|
||||
mockWorkloadSearch.mockReturnValue('pve-1');
|
||||
setResources([
|
||||
@@ -430,7 +392,7 @@ describe('ProxmoxPageSurface contract', () => {
|
||||
'proxmox-mail',
|
||||
]);
|
||||
expect(options.map((value) => value.query)).toEqual([
|
||||
'type=agent,vm,system-container,oci-container,pbs',
|
||||
'type=agent,vm,system-container,oci-container',
|
||||
'type=agent,pbs,storage,physical_disk,ceph',
|
||||
'type=agent',
|
||||
'type=agent,vm,system-container,pbs',
|
||||
@@ -442,8 +404,6 @@ describe('ProxmoxPageSurface contract', () => {
|
||||
expect(proxmoxPageSurfaceSource).toContain('requestIdleCallback');
|
||||
expect(proxmoxPageSurfaceSource).toContain("phoneViewport\n ? ['storage']");
|
||||
expect(proxmoxPageSurfaceSource).toContain('resourceSource={storageResources}');
|
||||
expect(proxmoxPageSurfaceSource).toContain('servers={currentModel().pbs}');
|
||||
expect(proxmoxPageSurfaceSource).toContain('showBackupCounts={false}');
|
||||
});
|
||||
|
||||
it('places workload controls beside the workload table they affect', () => {
|
||||
@@ -454,12 +414,7 @@ describe('ProxmoxPageSurface contract', () => {
|
||||
expect(nodesTableIndex).toBeGreaterThan(-1);
|
||||
expect(workloadFilterIndex).toBeGreaterThan(nodesTableIndex);
|
||||
expect(workloadsSurfaceIndex).toBeGreaterThan(workloadFilterIndex);
|
||||
expect(proxmoxPageSurfaceSource.indexOf('<ProxmoxBackupServersTable')).toBeGreaterThan(
|
||||
nodesTableIndex,
|
||||
);
|
||||
expect(proxmoxPageSurfaceSource.indexOf('<ProxmoxBackupServersTable')).toBeLessThan(
|
||||
workloadFilterIndex,
|
||||
);
|
||||
expect(proxmoxPageSurfaceSource).not.toContain('<ProxmoxBackupServersTable');
|
||||
});
|
||||
|
||||
it('keeps the bounded node preview before guests at every viewport', () => {
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
import { expect, test } from "@playwright/test";
|
||||
|
||||
import { ensureAuthenticated, getMockMode, setMockMode } from "./helpers";
|
||||
|
||||
test.describe("Proxmox PBS overview", () => {
|
||||
test.setTimeout(180_000);
|
||||
|
||||
test("keeps standalone PBS health and details in the estate scan", async ({
|
||||
page,
|
||||
}) => {
|
||||
await ensureAuthenticated(page);
|
||||
const initialMockMode = await getMockMode(page);
|
||||
|
||||
try {
|
||||
if (!initialMockMode.enabled) {
|
||||
await setMockMode(page, true);
|
||||
}
|
||||
|
||||
await page.setViewportSize({ width: 1280, height: 800 });
|
||||
await page.goto("/proxmox/overview", { waitUntil: "domcontentloaded" });
|
||||
|
||||
const overview = page.getByTestId("proxmox-page");
|
||||
const nodes = overview.locator(".proxmox-nodes-card");
|
||||
const servers = overview.locator(
|
||||
'[data-proxmox-backups-table="servers"]',
|
||||
);
|
||||
const guests = overview.locator("#proxmox-guests-section");
|
||||
|
||||
await expect(nodes).toBeVisible({ timeout: 60_000 });
|
||||
await expect(servers).toBeVisible({ timeout: 60_000 });
|
||||
const desktopRow = servers.locator("tbody tr[aria-expanded]").first();
|
||||
await expect(desktopRow).toBeVisible();
|
||||
await expect(desktopRow.locator("td").first()).not.toHaveText("");
|
||||
await expect(
|
||||
servers.getByRole("columnheader", { name: "Backups" }),
|
||||
).toHaveCount(0);
|
||||
await expect(guests).toBeVisible();
|
||||
|
||||
const placement = await overview.evaluate((root) => {
|
||||
const nodesElement = root.querySelector(".proxmox-nodes-card");
|
||||
const serversElement = root.querySelector(
|
||||
'[data-proxmox-backups-table="servers"]',
|
||||
);
|
||||
const guestsElement = root.querySelector("#proxmox-guests-section");
|
||||
if (!nodesElement || !serversElement || !guestsElement) return null;
|
||||
return {
|
||||
nodesBeforeServers: Boolean(
|
||||
nodesElement.compareDocumentPosition(serversElement) &
|
||||
Node.DOCUMENT_POSITION_FOLLOWING,
|
||||
),
|
||||
serversBeforeGuests: Boolean(
|
||||
serversElement.compareDocumentPosition(guestsElement) &
|
||||
Node.DOCUMENT_POSITION_FOLLOWING,
|
||||
),
|
||||
};
|
||||
});
|
||||
expect(placement).toEqual({
|
||||
nodesBeforeServers: true,
|
||||
serversBeforeGuests: true,
|
||||
});
|
||||
|
||||
const desktopToggle = desktopRow.getByRole("button", {
|
||||
name: /details for/,
|
||||
});
|
||||
await desktopToggle.click();
|
||||
await expect(desktopRow).toHaveAttribute("aria-expanded", "true");
|
||||
await expect(
|
||||
servers.getByRole("tab", { name: "History" }).first(),
|
||||
).toBeVisible();
|
||||
await desktopToggle.click();
|
||||
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
await page.reload({ waitUntil: "domcontentloaded" });
|
||||
await expect(servers).toBeVisible({ timeout: 60_000 });
|
||||
|
||||
const narrowRow = servers.locator("tbody tr[aria-expanded]").first();
|
||||
await narrowRow.click();
|
||||
await expect(narrowRow).toHaveAttribute("aria-expanded", "true");
|
||||
await expect(
|
||||
servers.getByRole("tab", { name: "History" }).first(),
|
||||
).toBeVisible();
|
||||
|
||||
const pageWidth = await page.evaluate(() => ({
|
||||
clientWidth: document.documentElement.clientWidth,
|
||||
scrollWidth: document.documentElement.scrollWidth,
|
||||
}));
|
||||
expect(pageWidth.scrollWidth).toBeLessThanOrEqual(
|
||||
pageWidth.clientWidth + 1,
|
||||
);
|
||||
} finally {
|
||||
if (!initialMockMode.enabled) {
|
||||
await setMockMode(page, false);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user