mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 02:25:56 +00:00
Sync Proxmox node table with workload search
This commit is contained in:
@@ -1613,6 +1613,11 @@ Agent`), with the plain-language source phrase available through accessible
|
||||
and responsive/mobile rows must present the same preferred label while
|
||||
retaining native diagnostics; page-local formatting such as
|
||||
`cluster (node)` must not replace the backend-authored presentation.
|
||||
On the Proxmox overview, the committed Workloads search is shared state for
|
||||
both the guest table and the node table: guest matches retain their owning
|
||||
node, direct node matches retain that node, and unrelated nodes are hidden.
|
||||
The node table must use the same provider-scoped search vocabulary rather
|
||||
than receiving an unfiltered copy of the estate.
|
||||
8. Keep summary chart interaction identity on one shared helper. Summary surfaces that expose row-hover, group-hover, chart-hover, or route-focus-driven chart emphasis must derive page/group/entity scope through `frontend-modern/src/components/shared/summaryCardInteraction.ts` and pass that same resolved scope into card-state, sparkline, and density-map primitives, rather than letting cards read `hovered || focused` while charts listen to a different page-local ID source. Hovering one summary chart must promote that series into the shared active entity so sibling cards highlight the same object instead of keeping chart-local hover islands, and hovering or pinning a workload group header, infrastructure cluster header, or storage pool-group header must scope the matching summary cards through that same shared contract instead of forking a page-local summary filter path. Sibling cards should surface that synchronized hover as one compact header readout through the shared summary-card contract, while the chart under the pointer keeps the only floating tooltip. Recovery is explicitly outside this interaction dialect: its retired posture-card strip must not return with row/group/chart hover behavior without a separate governed product decision.
|
||||
9. Keep page summaries page-scoped when table rows enter contextual focus. Route-backed row selection may add a focused label and shared series emphasis, but infrastructure, workloads, and storage summary cards must continue to render the page-level series set instead of collapsing the summary down to the selected row or replacing the global trend view with row-local empty states.
|
||||
10. Keep contextual row focus on the shared summary primitive. Summary surfaces and same-route table drill-ins must reuse `frontend-modern/src/components/shared/contextualFocus.ts` for interactive-series filtering, focused-name lookup, active-series derivation, local scroll preservation, and deliberate inline-detail reveal instead of rebuilding page-local `Set` filters, focused-label scans, drawer-aware scroll math, or ad hoc scroll restoration in each surface.
|
||||
|
||||
@@ -437,10 +437,13 @@ That bounded node preview remains before the virtual guest inventory at every
|
||||
viewport; narrow layouts must not move it after the full guest list's virtual
|
||||
scroll extent, where the node estate would become effectively undiscoverable.
|
||||
The workload filter belongs immediately before the workload table it controls,
|
||||
after the node preview; it must not filter the node table. The nodes table must
|
||||
always receive the real already-loaded PVE node collection, so committed or
|
||||
draft workload terms can never manufacture the estate-empty `No Proxmox VE
|
||||
nodes` state. That empty state is reserved for genuinely absent node inventory.
|
||||
after the node preview, and its committed search term must also flow into the
|
||||
node table. The node table must use the shared Proxmox search model so a
|
||||
matching guest retains its owning node while unrelated nodes disappear; a
|
||||
node search must likewise retain the directly matching node. The table still
|
||||
receives the real already-loaded PVE node collection as its source, so the
|
||||
estate-empty `No Proxmox VE nodes` state remains reserved for genuinely absent
|
||||
node inventory, while a narrowed result uses the distinct no-match state.
|
||||
Those counts and layout controls must not imply
|
||||
protection, verification, or restore readiness beyond the evidence held by the
|
||||
workflow-owned Storage, Backups, Ceph, and Mail surfaces.
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
{
|
||||
"version": 1,
|
||||
"base_sha": "ae9cfb1da87235e81359e251ec5f0a6670398ad9",
|
||||
"verified_at": "2026-08-23T18:06:00Z",
|
||||
"base_sha": "35b8c0a4c2ccbc11a1bb67116cb2d1e8f6d72391",
|
||||
"verified_at": "2026-08-23T18:28:00Z",
|
||||
"result": "passed",
|
||||
"changed_paths": [
|
||||
"frontend-modern/src/features/proxmox/ProxmoxBackupsTable.tsx",
|
||||
"frontend-modern/src/features/proxmox/proxmoxPageModel.ts",
|
||||
"frontend-modern/src/routing/resourceLinks.ts"
|
||||
"frontend-modern/src/features/proxmox/ProxmoxPageSurface.tsx"
|
||||
],
|
||||
"content_sha256": {
|
||||
"frontend-modern/src/features/proxmox/ProxmoxBackupsTable.tsx": "050b7e4336a467a71376b471f3e53cbcf65f11de088cd076efe0afe0943ecf31",
|
||||
"frontend-modern/src/features/proxmox/proxmoxPageModel.ts": "09cebaf862d67def8e560b49acf50bdbcdc13f814fec15ad7fc8b1ae412a7fc1",
|
||||
"frontend-modern/src/routing/resourceLinks.ts": "8a22520911eb1b84cee0ab4ef4388ec8dbfd40380db93dbac451d26f8031db3c"
|
||||
"frontend-modern/src/features/proxmox/ProxmoxPageSurface.tsx": "5fbcb11d536ff657dcbffbe25c3b749bcf8bd4ff545dbdd0c02d3414c703c759"
|
||||
},
|
||||
"routes": [
|
||||
"/proxmox/backups/date",
|
||||
"/proxmox/backups/coverage"
|
||||
"/proxmox/overview"
|
||||
],
|
||||
"viewports": [
|
||||
{
|
||||
@@ -28,15 +23,13 @@
|
||||
}
|
||||
],
|
||||
"states": [
|
||||
"Desktop direct navigation to /proxmox/backups/date renders the By date section with its chronological backup table and Coverage link",
|
||||
"Desktop navigation to /proxmox/backups/coverage selects Coverage and renders posture filters and coverage rows",
|
||||
"Narrow Coverage renders the route-backed section rail, responsive columns, and no horizontal overflow",
|
||||
"The running app reported no console errors during direct navigation and section switching"
|
||||
"Desktop direct navigation to /proxmox/overview rendered the connected Proxmox app shell and its overview loading state while the large mock estate hydrated",
|
||||
"The running app reported a connected backend/live data stream and no browser console errors during the overview navigation",
|
||||
"The large-estate narrowed node result is covered by the focused Proxmox page-surface and node-table tests"
|
||||
],
|
||||
"interactions": [
|
||||
"Loaded /proxmox/backups/date at the desktop viewport and inspected the active section rail and date table",
|
||||
"Selected Coverage through the canonical section link and verified /proxmox/backups/coverage with active navigation",
|
||||
"Loaded Coverage at 390x844 and verified responsive section navigation, posture table content, and overflow state",
|
||||
"Reset the temporary narrow viewport after verification"
|
||||
"Loaded /proxmox/overview at the desktop viewport and inspected the connected overview shell",
|
||||
"Confirmed the page exposes the Proxmox overview route used by the shared workload search",
|
||||
"Verified the guest-aware node narrowing contract through the focused page-surface and node-table test suites"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -333,6 +333,7 @@ function ProxmoxOverview(props: ProxmoxOverviewProps) {
|
||||
<ProxmoxNodesTable
|
||||
nodes={currentModel().pveNodes}
|
||||
guests={currentModel().guests}
|
||||
search={workloadsState.search}
|
||||
metricDisplayMode={props.metricDisplayMode}
|
||||
metricHistoryRange={props.metricHistoryRange}
|
||||
layoutWidth={overviewWidth.width}
|
||||
|
||||
+21
-9
@@ -122,9 +122,15 @@ vi.mock('../ProxmoxMailGatewayTable', () => ({
|
||||
}));
|
||||
|
||||
vi.mock('../ProxmoxNodesTable', () => ({
|
||||
ProxmoxNodesTable: (props: { nodes: Resource[]; topology?: unknown }) => {
|
||||
ProxmoxNodesTable: (props: { nodes: Resource[]; search?: () => string; topology?: unknown }) => {
|
||||
mockNodesTableProps(props);
|
||||
return <div data-testid="nodes-table" data-rows={props.nodes.length} />;
|
||||
return (
|
||||
<div
|
||||
data-testid="nodes-table"
|
||||
data-rows={props.nodes.length}
|
||||
data-search={props.search?.() ?? ''}
|
||||
/>
|
||||
);
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -212,7 +218,7 @@ describe('ProxmoxPageSurface contract', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps the node inventory independent from committed workload search terms', () => {
|
||||
it('passes committed workload search terms to the node table', () => {
|
||||
mockWorkloadSearch.mockReturnValue('reporting-api-01, wireguard-edge-01');
|
||||
setResources([
|
||||
makeResource({
|
||||
@@ -242,11 +248,17 @@ describe('ProxmoxPageSurface contract', () => {
|
||||
renderSurface();
|
||||
|
||||
expect(screen.getByTestId('nodes-table')).toHaveAttribute('data-rows', '2');
|
||||
expect(mockNodesTableProps).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ nodes: expect.arrayContaining([expect.any(Object)]) }),
|
||||
expect(screen.getByTestId('nodes-table')).toHaveAttribute(
|
||||
'data-search',
|
||||
'reporting-api-01, wireguard-edge-01',
|
||||
);
|
||||
expect(proxmoxPageSurfaceSource).toContain('nodes={currentModel().pveNodes}');
|
||||
expect(proxmoxPageSurfaceSource).not.toContain('filterProxmoxNodesForSearch');
|
||||
expect(mockNodesTableProps).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
nodes: expect.arrayContaining([expect.any(Object)]),
|
||||
search: mockWorkloadSearch,
|
||||
}),
|
||||
);
|
||||
expect(proxmoxPageSurfaceSource).toContain('search={workloadsState.search}');
|
||||
});
|
||||
|
||||
it('does not call a retained version from a stopped Proxmox agent currently running', () => {
|
||||
@@ -312,7 +324,7 @@ describe('ProxmoxPageSurface contract', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('keeps workload search scoped to guests instead of hiding the node inventory', () => {
|
||||
it('shares workload search with the node inventory', () => {
|
||||
mockWorkloadSearch.mockReturnValue('pve-1');
|
||||
setResources([
|
||||
makeResource({
|
||||
@@ -325,7 +337,7 @@ describe('ProxmoxPageSurface contract', () => {
|
||||
renderSurface();
|
||||
|
||||
expect(mockNodesTableProps).toHaveBeenLastCalledWith(
|
||||
expect.not.objectContaining({ search: expect.anything() }),
|
||||
expect.objectContaining({ search: mockWorkloadSearch }),
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user