diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/bulk_actions.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/bulk_actions.test.tsx index 20fb4bb83dac8..5834c776a6dce 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/bulk_actions.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/bulk_actions.test.tsx @@ -30,6 +30,7 @@ const defaultProps = { shownAgents: 10, inactiveShownAgents: 0, totalManagedAgentIds: [], + inactiveManagedAgentIds: [], selectionMode: 'manual', currentQuery: '', selectedAgents: [], @@ -126,6 +127,10 @@ describe('AgentBulkActions', () => { }); describe('When in query mode', () => { + mockedExperimentalFeaturesService.get.mockReturnValue({ + diagnosticFileUploadEnabled: true, + } as any); + it('should show correct actions for active agents when no managed policies exist', async () => { const results = render({ ...defaultProps, @@ -162,15 +167,57 @@ describe('AgentBulkActions', () => { expect(results.getByText('Add / remove tags').closest('button')!).toBeEnabled(); expect(results.getByText('Assign to new policy').closest('button')!).toBeEnabled(); - expect(results.getByText('Unenroll 8 agents').closest('button')!).toBeEnabled(); - expect(results.getByText('Upgrade 8 agents').closest('button')!).toBeEnabled(); - expect(results.getByText('Schedule upgrade for 8 agents').closest('button')!).toBeDisabled(); expect( results.getByText('Request diagnostics for 8 agents').closest('button')! ).toBeEnabled(); + expect(results.getByText('Unenroll 8 agents').closest('button')!).toBeEnabled(); + expect(results.getByText('Upgrade 8 agents').closest('button')!).toBeEnabled(); + expect(results.getByText('Schedule upgrade for 8 agents').closest('button')!).toBeDisabled(); expect(results.getByText('Restart upgrade 8 agents').closest('button')!).toBeEnabled(); }); + it('should show correct actions also when there are inactive managed agents', async () => { + const results = render({ + ...defaultProps, + inactiveManagedAgentIds: ['agentId1', 'agentId2'], + totalManagedAgentIds: ['agentId1', 'agentId2', 'agentId3'], + selectionMode: 'query', + }); + + const bulkActionsButton = results.getByTestId('agentBulkActionsButton'); + await act(async () => { + fireEvent.click(bulkActionsButton); + }); + + expect(results.getByText('Add / remove tags').closest('button')!).toBeEnabled(); + expect(results.getByText('Assign to new policy').closest('button')!).toBeEnabled(); + expect(results.getByText('Unenroll 9 agents').closest('button')!).toBeEnabled(); + expect(results.getByText('Upgrade 9 agents').closest('button')!).toBeEnabled(); + expect(results.getByText('Schedule upgrade for 9 agents').closest('button')!).toBeDisabled(); + expect(results.getByText('Restart upgrade 9 agents').closest('button')!).toBeEnabled(); + }); + + it('should show disabled actions when only inactive agents are selected', async () => { + const results = render({ + ...defaultProps, + inactiveShownAgents: 10, + selectedAgents: [{ id: 'agent1' }, { id: 'agent2' }] as Agent[], + selectionMode: 'query', + }); + + const bulkActionsButton = results.getByTestId('agentBulkActionsButton'); + await act(async () => { + fireEvent.click(bulkActionsButton); + }); + + expect(results.getByText('Add / remove tags').closest('button')!).toBeDisabled(); + expect(results.getByText('Assign to new policy').closest('button')!).toBeDisabled(); + expect(results.getByText('Unenroll 0 agents').closest('button')!).toBeDisabled(); + expect(results.getByText('Upgrade 0 agents').closest('button')!).toBeDisabled(); + expect(results.getByText('Schedule upgrade for 0 agents').closest('button')!).toBeDisabled(); + expect(results.getByText('Restart upgrade 0 agents').closest('button')!).toBeDisabled(); + }); + it('should generate a correct kuery to select agents', async () => { const results = render({ ...defaultProps, diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/bulk_actions.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/bulk_actions.tsx index 6ae366f1dbb98..cd00c194a6c11 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/bulk_actions.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/bulk_actions.tsx @@ -38,6 +38,7 @@ export interface Props { shownAgents: number; inactiveShownAgents: number; totalManagedAgentIds: string[]; + inactiveManagedAgentIds: string[]; selectionMode: SelectionMode; currentQuery: string; selectedAgents: Agent[]; @@ -51,6 +52,7 @@ export const AgentBulkActions: React.FunctionComponent = ({ shownAgents, inactiveShownAgents, totalManagedAgentIds, + inactiveManagedAgentIds, selectionMode, currentQuery, selectedAgents, @@ -91,18 +93,19 @@ export const AgentBulkActions: React.FunctionComponent = ({ } }, [currentQuery, totalManagedAgentIds]); - // Check if user is working with only inactive agents - const atLeastOneActiveAgentSelected = - selectionMode === 'manual' - ? !!selectedAgents.find((agent) => agent.active) - : shownAgents > inactiveShownAgents; const totalActiveAgents = shownAgents - inactiveShownAgents; + // exclude inactive agents from the count const agentCount = selectionMode === 'manual' ? selectedAgents.length - : totalActiveAgents - totalManagedAgentIds?.length; + : totalActiveAgents - (totalManagedAgentIds?.length - inactiveManagedAgentIds?.length); + // Check if user is working with only inactive agents + const atLeastOneActiveAgentSelected = + selectionMode === 'manual' + ? !!selectedAgents.find((agent) => agent.active) + : agentCount > 0 && shownAgents > inactiveShownAgents; const agents = selectionMode === 'manual' ? selectedAgents : selectionQuery; const [tagsPopoverButton, setTagsPopoverButton] = useState(); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/search_and_filter_bar.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/search_and_filter_bar.tsx index 3ecc5e6545795..8013a490103af 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/search_and_filter_bar.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/search_and_filter_bar.tsx @@ -49,6 +49,7 @@ export interface SearchAndFilterBarProps { inactiveShownAgents: number; totalInactiveAgents: number; totalManagedAgentIds: string[]; + inactiveManagedAgentIds: string[]; selectionMode: SelectionMode; currentQuery: string; selectedAgents: Agent[]; @@ -78,6 +79,7 @@ export const SearchAndFilterBar: React.FunctionComponent = () => { const [inactiveShownAgents, setInactiveShownAgents] = useState(0); const [totalInactiveAgents, setTotalInactiveAgents] = useState(0); const [totalManagedAgentIds, setTotalManagedAgentIds] = useState([]); + const [inactiveManagedAgentIds, setInactiveManagedAgentIds] = useState([]); const [managedAgentsOnCurrentPage, setManagedAgentsOnCurrentPage] = useState(0); const [showAgentActivityTour, setShowAgentActivityTour] = useState({ isOpen: false }); const getSortFieldForAPI = (field: keyof Agent): string => { @@ -335,7 +336,11 @@ export const AgentListPage: React.FunctionComponent<{}> = () => { } const allManagedAgents = response.data?.items ?? []; const allManagedAgentIds = allManagedAgents?.map((agent) => agent.id); + const inactiveManagedIds = allManagedAgents + ?.filter((agent) => agent.status === 'inactive') + .map((agent) => agent.id); setTotalManagedAgentIds(allManagedAgentIds); + setInactiveManagedAgentIds(inactiveManagedIds); setManagedAgentsOnCurrentPage( agentsResponse.data.items @@ -606,6 +611,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => { inactiveShownAgents={inactiveShownAgents} totalInactiveAgents={totalInactiveAgents} totalManagedAgentIds={totalManagedAgentIds} + inactiveManagedAgentIds={inactiveManagedAgentIds} selectionMode={selectionMode} currentQuery={kuery} selectedAgents={selectedAgents}