Skip to content

Commit

Permalink
[Fleet] Fix agents count in agent list table and add tooltip with cor…
Browse files Browse the repository at this point in the history
…rect info (elastic#197834)

Fixes elastic#195441

## Summary
Selection agent count on agent list table gets incorrect when there are
multiple hosted agents, especially if they are on inactive state. In
fact to calculate the selected number of agents we were getting hosted
agents, but without taking into account the filtering applied on the
page, i.e. we were always getting all the hosted agent (inactive too).
This caused the final calculation to be off.

In this PR I'm fixing [the
query](https://github.com/elastic/kibana/pull/197834/files#diff-9707a4b93a96749876e4cf173a0b39cd5a620e311e2652c5ed4b8670ca7e6becR309-R320)
used to get those agents to take in account the filters and I'm also
adding a small tooltip that breaks up the number of agents (selected,
total, hosted)

### Testing
- Make sure to have many agents, hosted and not in different states
(inactive, unenrolled)
- To make a hosted agent inactive follow the steps explained
[here](elastic#195441)
- Verify that the selection numbers are correct: select agents on all
pages and hover on the new tooltip shown besides the "selected agents".
This number should match the number shown on the actions dropdown

### Screenshots
<img width="2376" alt="Screenshot 2024-10-25 at 17 00 44"
src="https://github.com/user-attachments/assets/81d2836a-f997-4ccb-a23c-3d2cfbfa62d3">
<img width="2409" alt="Screenshot 2024-10-25 at 17 00 59"
src="https://github.com/user-attachments/assets/ba21933a-f1e6-457e-8059-e87b3e29a7d1">

https://github.com/user-attachments/assets/c153c491-29a1-481c-a3e3-25bab6412963

### Checklist

- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [ ]
[Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html)
was added for features that require explanation or tutorials
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

---------

Co-authored-by: Elastic Machine <[email protected]>
(cherry picked from commit 079e929)
  • Loading branch information
criamico committed Oct 28, 2024
1 parent 3027eb1 commit f08eb8a
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import React from 'react';
import styled from 'styled-components';
import { EuiFlexGroup, EuiFlexItem, EuiText, EuiButtonEmpty } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem, EuiText, EuiButtonEmpty, EuiIconTip } from '@elastic/eui';
import { FormattedMessage, FormattedNumber } from '@kbn/i18n-react';

import { SO_SEARCH_LIMIT } from '../../../../constants';
Expand All @@ -33,6 +33,7 @@ const Button = styled(EuiButtonEmpty)`

export const AgentsSelectionStatus: React.FunctionComponent<{
totalAgents: number;
totalManagedAgents: number;
selectableAgents: number;
managedAgentsOnCurrentPage: number;
selectionMode: SelectionMode;
Expand All @@ -41,6 +42,7 @@ export const AgentsSelectionStatus: React.FunctionComponent<{
setSelectedAgents: (agents: Agent[]) => void;
}> = ({
totalAgents,
totalManagedAgents,
selectableAgents,
managedAgentsOnCurrentPage,
selectionMode,
Expand Down Expand Up @@ -71,11 +73,28 @@ export const AgentsSelectionStatus: React.FunctionComponent<{
}}
/>
) : (
<FormattedMessage
id="xpack.fleet.agentBulkActions.totalAgents"
defaultMessage="Showing {count, plural, one {# agent} other {# agents}}"
values={{ count: totalAgents }}
/>
<>
<FormattedMessage
id="xpack.fleet.agentBulkActions.totalAgents"
defaultMessage="Showing {count, plural, one {# agent} other {# agents}}"
values={{ count: totalAgents }}
/>{' '}
<EuiIconTip
type="iInCircle"
content={
<FormattedMessage
data-test-subj="selectedAgentCountTooltip"
id="xpack.fleet.agentBulkActions.agentsBreakDownTooltip"
defaultMessage=" {totalAgents} total agents: {totalSelected} user-managed agents, {totalManagedAgents} on hosted policies"
values={{
totalAgents,
totalManagedAgents,
totalSelected: totalAgents - totalManagedAgents,
}}
/>
}
/>
</>
)}
</EuiText>
</EuiFlexItem>
Expand All @@ -96,7 +115,24 @@ export const AgentsSelectionStatus: React.FunctionComponent<{
selectionMode,
count: selectedAgents.length,
}}
/>
/>{' '}
{selectionMode === 'query' && (
<EuiIconTip
type="iInCircle"
content={
<FormattedMessage
data-test-subj="selectedAgentCountTooltip"
id="xpack.fleet.agentBulkActions.agentsSelectedTooltip"
defaultMessage="{totalSelected} user-managed agents selected: {totalAgents} total agents, {totalManagedAgents} on hosted policies. Most actions are only available to user-managed agents."
values={{
totalAgents,
totalManagedAgents,
totalSelected: totalAgents - totalManagedAgents,
}}
/>
}
/>
)}
</EuiText>
</EuiFlexItem>
{showSelectEverything ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export const AgentBulkActions: React.FunctionComponent<Props> = ({
const [isRequestDiagnosticsModalOpen, setIsRequestDiagnosticsModalOpen] =
useState<boolean>(false);

// update the query removing the "managed" agents
// update the query removing the "managed" agents in any state (unenrolled, offline, etc)
const selectionQuery = useMemo(() => {
if (totalManagedAgentIds.length) {
const excludedKuery = `${AGENTS_PREFIX}.agent.id : (${totalManagedAgentIds
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const AgentTableHeader: React.FunctionComponent<{
agentStatus?: { [k in SimplifiedAgentStatus]: number };
totalAgents: number;
selectableAgents: number;
totalManagedAgents: number;
managedAgentsOnCurrentPage: number;
selectionMode: SelectionMode;
setSelectionMode: (mode: SelectionMode) => void;
Expand All @@ -31,6 +32,7 @@ export const AgentTableHeader: React.FunctionComponent<{
}> = ({
agentStatus,
totalAgents,
totalManagedAgents,
selectableAgents,
managedAgentsOnCurrentPage,
selectionMode,
Expand All @@ -47,6 +49,7 @@ export const AgentTableHeader: React.FunctionComponent<{
<EuiFlexItem grow={false}>
<AgentsSelectionStatus
totalAgents={totalAgents}
totalManagedAgents={totalManagedAgents}
selectableAgents={selectableAgents}
managedAgentsOnCurrentPage={managedAgentsOnCurrentPage}
selectionMode={selectionMode}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,14 +306,18 @@ export function useFetchAgentsData() {
setTotalManagedAgentIds([]);
setManagedAgentsOnCurrentPage(0);
} else {
// Find all the agents that have managed policies and are not unenrolled
const policiesKuery = managedAgentPolicies
.map((policy) => `policy_id:"${policy.id}"`)
.join(' or ');
// Find all the agents that have managed policies
// to the correct ids we need to build the kuery applying the same filters as the global ones
const managedPoliciesKuery = getKuery({
search,
selectedAgentPolicies: managedAgentPolicies.map((policy) => policy.id),
selectedTags,
selectedStatus,
});
const response = await sendGetAgents({
kuery: `NOT (status:unenrolled) and ${policiesKuery}`,
kuery: `${managedPoliciesKuery}`,
perPage: SO_SEARCH_LIMIT,
showInactive: true,
showInactive,
});
if (response.error) {
throw new Error(response.error.message);
Expand Down Expand Up @@ -350,7 +354,6 @@ export function useFetchAgentsData() {
fetchDataAsync();
},
[
fullAgentPolicyFecher,
pagination.currentPage,
pagination.pageSize,
kuery,
Expand All @@ -359,8 +362,12 @@ export function useFetchAgentsData() {
showInactive,
showUpgradeable,
displayAgentMetrics,
fullAgentPolicyFecher,
allTags,
latestAgentActionErrors,
search,
selectedTags,
selectedStatus,
notifications.toasts,
]
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ export const AgentListPage: React.FunctionComponent<{}> = () => {
{/* Agent total, bulk actions and status bar */}
<AgentTableHeader
totalAgents={nAgentsInTable}
totalManagedAgents={totalManagedAgentIds.length || 0}
agentStatus={agentsStatus}
selectableAgents={agentsOnCurrentPage?.filter(isAgentSelectable).length || 0}
managedAgentsOnCurrentPage={managedAgentsOnCurrentPage}
Expand Down

0 comments on commit f08eb8a

Please sign in to comment.