diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/builders.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/builders.ts index 0ebef33d6a0c5a..3c0e463d424e4b 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/builders.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/builders.ts @@ -49,10 +49,6 @@ export const initialEndpointPageState = (): Immutable => { policyVersionInfo: undefined, hostStatus: undefined, isolationRequestState: createUninitialisedResourceState(), - /** - * Getting pending endpoint actions is "supplemental" data, so there is no need to show other Async - * states other than Loaded - */ endpointPendingActions: createLoadedResourceState(new Map()), }; }; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts index 352876788637b0..6e074cd6d57cd2 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/middleware.ts @@ -32,8 +32,9 @@ import { getIsIsolationRequestPending, getCurrentIsolationRequestState, getActivityLogData, + detailsData, } from './selectors'; -import { EndpointState, PolicyIds } from '../types'; +import { AgentIdsPendingActions, EndpointState, PolicyIds } from '../types'; import { sendGetEndpointSpecificPackagePolicies, sendGetEndpointSecurityPackage, @@ -57,6 +58,7 @@ import { isolateHost, unIsolateHost } from '../../../../common/lib/endpoint_isol import { AppAction } from '../../../../common/store/actions'; import { resolvePathVariables } from '../../../../common/utils/resolve_path_variables'; import { ServerReturnedEndpointPackageInfo } from './action'; +import { fetchPendingActionsByAgentId } from '../../../../common/lib/endpoint_pending_actions'; type EndpointPageStore = ImmutableMiddlewareAPI; @@ -111,6 +113,8 @@ export const endpointMiddlewareFactory: ImmutableMiddlewareFactory => { + const state = getState(); + const detailsEndpoint = detailsData(state); + const listEndpoints = listData(state); + const agentsIds = new Set(); + + // get all agent ids for the endpoints in the list + if (detailsEndpoint) { + agentsIds.add(detailsEndpoint.elastic.agent.id); + } + + for (const endpointInfo of listEndpoints) { + agentsIds.add(endpointInfo.metadata.elastic.agent.id); + } + + if (agentsIds.size === 0) { + return; + } + + try { + const { data: pendingActions } = await fetchPendingActionsByAgentId(Array.from(agentsIds)); + const agentIdToPendingActions: AgentIdsPendingActions = new Map(); + + for (const pendingAction of pendingActions) { + agentIdToPendingActions.set(pendingAction.agent_id, pendingAction.pending_actions); + } + + dispatch({ + type: 'endpointPendingActionsStateChanged', + payload: createLoadedResourceState(agentIdToPendingActions), + }); + } catch (error) { + logError(error); + } +}; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts index 19235b792b2702..d46e1a7c9eff6a 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/reducer.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { EndpointDetailsActivityLogChanged } from './action'; +import { EndpointDetailsActivityLogChanged, EndpointPendingActionsStateChanged } from './action'; import { isOnEndpointPage, hasSelectedEndpoint, @@ -38,6 +38,19 @@ const handleEndpointDetailsActivityLogChanged: CaseReducer = ( + state, + action +) => { + if (isOnEndpointPage(state)) { + return { + ...state, + endpointPendingActions: action.payload, + }; + } + return state; +}; + /* eslint-disable-next-line complexity */ export const endpointListReducer: StateReducer = (state = initialEndpointPageState(), action) => { if (action.type === 'serverReturnedEndpointList') { @@ -123,6 +136,8 @@ export const endpointListReducer: StateReducer = (state = initialEndpointPageSta }; } else if (action.type === 'endpointDetailsActivityLogChanged') { return handleEndpointDetailsActivityLogChanged(state, action); + } else if (action.type === 'endpointPendingActionsStateChanged') { + return handleEndpointPendingActionsStateChanged(state, action); } else if (action.type === 'serverReturnedPoliciesForOnboarding') { return { ...state, diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts index 68eb2d3b21830e..2bac4193a48990 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/selectors.ts @@ -412,8 +412,8 @@ export const getEndpointHostIsolationStatusPropsCallback: ( const endpointPendingActions = pendingActionsState.data.get(endpoint.elastic.agent.id); if (endpointPendingActions) { - pendingIsolate = endpointPendingActions.pending_actions?.isolate ?? 0; - pendingUnIsolate = endpointPendingActions.pending_actions?.unisolate ?? 0; + pendingIsolate = endpointPendingActions?.isolate ?? 0; + pendingUnIsolate = endpointPendingActions?.unisolate ?? 0; } } diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts index 0897af35a22363..875b2c16a5fd50 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/types.ts @@ -93,10 +93,16 @@ export interface EndpointState { hostStatus?: HostStatus; /** Host isolation request state for a single endpoint */ isolationRequestState: AsyncResourceState; - /** Holds a map of `agentId` to `EndpointPendingActions` that is used by both the list and details view. */ - endpointPendingActions: AsyncResourceState>; + /** + * Holds a map of `agentId` to `EndpointPendingActions` that is used by both the list and details view + * Getting pending endpoint actions is "supplemental" data, so there is no need to show other Async + * states other than Loaded + */ + endpointPendingActions: AsyncResourceState; } +export type AgentIdsPendingActions = Map; + /** * packagePolicy contains a list of Package Policy IDs (received via Endpoint metadata policy response) mapped to a boolean whether they exist or not. * agentPolicy contains a list of existing Package Policy Ids mapped to an associated Fleet parent Agent Config.