From deb2950d28b659d65b836c3ed4223d0621c6035b Mon Sep 17 00:00:00 2001 From: rcourtman Date: Sat, 9 May 2026 14:49:37 +0100 Subject: [PATCH] Move Install agent attention from global callout to row-level chips The 'Install agents' recommendation rendered above the table as a secondary button + paragraph: 'Install Pulse Agent on pbs-docker when you want node-local telemetry...'. The user had to read the paragraph and then map the named system back to the table row. Surface the same attention directly on the affected row instead. For systems with API coverage but no Pulse Agent, render a small '+ Install agent' chip in the actions column above the Manage button. The chip routes to the same agent-install picker the global button used. Hide the global recommendation card when its kind is 'agent' so the two affordances don't duplicate each other. Other recommendation states (discovery scan, coverage coherent, add infrastructure on empty) still render as before. --- .../Settings/InfrastructureSourceManager.tsx | 54 +++++++++++++++---- .../InfrastructureWorkspace.test.tsx | 24 +++++---- 2 files changed, 60 insertions(+), 18 deletions(-) diff --git a/frontend-modern/src/components/Settings/InfrastructureSourceManager.tsx b/frontend-modern/src/components/Settings/InfrastructureSourceManager.tsx index 2216a9591..5f15794b3 100644 --- a/frontend-modern/src/components/Settings/InfrastructureSourceManager.tsx +++ b/frontend-modern/src/components/Settings/InfrastructureSourceManager.tsx @@ -610,7 +610,17 @@ export const InfrastructureSourceManager: Component - + {/* Recommendation button hides for the apiOnly install-agents case + because row-level install-agent chips now surface the same + attention per-system. Other recommendations (discovery scan, + coverage coherent, add infrastructure) still render here. */} + +
+ {/* Row-level install-agent shortcut: the + apiOnly attention state lands directly on + the affected system instead of the user + reading a global callout and figuring out + which row it referred to. */} + + + + +
diff --git a/frontend-modern/src/components/Settings/__tests__/InfrastructureWorkspace.test.tsx b/frontend-modern/src/components/Settings/__tests__/InfrastructureWorkspace.test.tsx index 01338de57..b450688f8 100644 --- a/frontend-modern/src/components/Settings/__tests__/InfrastructureWorkspace.test.tsx +++ b/frontend-modern/src/components/Settings/__tests__/InfrastructureWorkspace.test.tsx @@ -289,7 +289,12 @@ describe('InfrastructureWorkspace', () => { expect(screen.getByRole('button', { name: /Discovery settings/i })).toBeInTheDocument(); expect(screen.getByRole('button', { name: /^Add infrastructure$/i })).toBeInTheDocument(); expect(screen.queryByRole('button', { name: /^Detect address$/i })).toBeNull(); - expect(screen.queryByRole('button', { name: /^Install agent$/i })).toBeNull(); + // Row-level 'Install agent' surfaces per system that has API coverage + // but no Pulse Agent yet. The fixture has one such system, so at least + // one of these buttons should exist. + expect( + screen.getAllByRole('button', { name: /^Install agent$/i }).length, + ).toBeGreaterThan(0); const readiness = screen.getByRole('region', { name: /Infrastructure setup summary/i, }); @@ -304,7 +309,12 @@ describe('InfrastructureWorkspace', () => { expect(within(readiness).getAllByText('1 system').length).toBeGreaterThan(0); expect(within(readiness).getAllByText('0 systems').length).toBeGreaterThan(0); expect(within(readiness).getByText('Discovery off')).toBeInTheDocument(); - expect(within(readiness).getByRole('button', { name: /Install agents/i })).toBeInTheDocument(); + // Global 'Install agents' recommendation button is hidden when + // row-level 'Install agent' chips already surface the apiOnly state + // per-system. + expect( + within(readiness).queryByRole('button', { name: /Install agents/i }), + ).not.toBeInTheDocument(); expect(screen.getByText('Proxmox VE')).toBeInTheDocument(); expect(screen.getByText('Proxmox VE').closest('tr')?.className).toContain('grouped-table-row'); expect(screen.queryByText('VMware vCenter')).toBeNull(); @@ -322,13 +332,9 @@ describe('InfrastructureWorkspace', () => { await waitFor(() => expect(screen.getByText('Infrastructure systems')).toBeInTheDocument()); - fireEvent.click( - within( - screen.getByRole('region', { - name: /Infrastructure setup summary/i, - }), - ).getByRole('button', { name: /Install agents/i }), - ); + // Row-level 'Install agent' replaced the global 'Install agents' + // recommendation button; same routing target. + fireEvent.click(screen.getAllByRole('button', { name: /^Install agent$/i })[0]); expect(navigateSpy).toHaveBeenLastCalledWith('/settings/infrastructure?add=agent', { scroll: false, });