diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts index f54e7d4774128..ba07cd3c9d461 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/store/action.ts @@ -166,6 +166,13 @@ export interface EndpointDetailsActivityLogUpdatePaging { }; } +export interface EndpointDetailsLoad { + type: 'endpointDetailsLoad'; + payload: { + endpointId: string; + }; +} + export interface EndpointDetailsActivityLogUpdateIsInvalidDateRange { type: 'endpointDetailsActivityLogUpdateIsInvalidDateRange'; payload: { @@ -187,6 +194,7 @@ export type EndpointAction = | EndpointDetailsActivityLogUpdatePaging | EndpointDetailsActivityLogUpdateIsInvalidDateRange | EndpointDetailsActivityLogChanged + | EndpointDetailsLoad | ServerReturnedEndpointPolicyResponse | ServerFailedToReturnEndpointPolicyResponse | ServerReturnedPoliciesForOnboarding 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 19658631e6cf2..063dcc44df2e8 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 @@ -115,6 +115,10 @@ export const endpointMiddlewareFactory: ImmutableMiddlewareFactory; coreStart: CoreStart; + selectedEndpoint: string; }) { const { getState, dispatch } = store; - dispatch({ - type: 'serverCancelledPolicyItemsLoading', - }); - - // If user navigated directly to a endpoint details page, load the endpoint list - if (listData(getState()).length === 0) { - const { page_index: pageIndex, page_size: pageSize } = uiQueryParams(getState()); - try { - const response = await coreStart.http.post(HOST_METADATA_LIST_ROUTE, { - body: JSON.stringify({ - paging_properties: [{ page_index: pageIndex }, { page_size: pageSize }], - }), - }); - response.request_page_index = Number(pageIndex); - dispatch({ - type: 'serverReturnedEndpointList', - payload: response, - }); - - try { - const ingestPolicies = await getAgentAndPoliciesForEndpointsList( - coreStart.http, - response.hosts, - nonExistingPolicies(getState()) - ); - if (ingestPolicies?.packagePolicy !== undefined) { - dispatch({ - type: 'serverReturnedEndpointNonExistingPolicies', - payload: ingestPolicies.packagePolicy, - }); - } - if (ingestPolicies?.agentPolicy !== undefined) { - dispatch({ - type: 'serverReturnedEndpointAgentPolicies', - payload: ingestPolicies.agentPolicy, - }); - } - } catch (error) { - // TODO should handle the error instead of logging it to the browser - // Also this is an anti-pattern we shouldn't use - // Ignore Errors, since this should not hinder the user's ability to use the UI - logError(error); - } - } catch (error) { - dispatch({ - type: 'serverFailedToReturnEndpointList', - payload: error, - }); - } - } else { - dispatch({ - type: 'serverCancelledEndpointListLoading', - }); - } - // call the endpoint details api - const { selected_endpoint: selectedEndpoint } = uiQueryParams(getState()); try { const response = await coreStart.http.get( resolvePathVariables(HOST_METADATA_GET_ROUTE, { id: selectedEndpoint as string }) @@ -736,6 +663,51 @@ async function endpointDetailsMiddleware({ }); } } + +async function endpointDetailsMiddleware({ + store, + coreStart, +}: { + store: ImmutableMiddlewareAPI; + coreStart: CoreStart; +}) { + const { getState, dispatch } = store; + dispatch({ + type: 'serverCancelledPolicyItemsLoading', + }); + + // If user navigated directly to a endpoint details page, load the endpoint list + if (listData(getState()).length === 0) { + const { page_index: pageIndex, page_size: pageSize } = uiQueryParams(getState()); + try { + const response = await coreStart.http.post(HOST_METADATA_LIST_ROUTE, { + body: JSON.stringify({ + paging_properties: [{ page_index: pageIndex }, { page_size: pageSize }], + }), + }); + response.request_page_index = Number(pageIndex); + dispatch({ + type: 'serverReturnedEndpointList', + payload: response, + }); + + dispatchIngestPolicies({ http: coreStart.http, hosts: response.hosts, store }); + } catch (error) { + dispatch({ + type: 'serverFailedToReturnEndpointList', + payload: error, + }); + } + } else { + dispatch({ + type: 'serverCancelledEndpointListLoading', + }); + } + const { selected_endpoint: selectedEndpoint } = uiQueryParams(getState()); + if (selectedEndpoint !== undefined) { + loadEndpointDetails({ store, coreStart, selectedEndpoint }); + } +} async function endpointDetailsActivityLogChangedMiddleware({ store, coreStart, @@ -803,3 +775,39 @@ export async function handleLoadMetadataTransformStats(http: HttpStart, store: E }); } } + +async function dispatchIngestPolicies({ + store, + hosts, + http, +}: { + store: EndpointPageStore; + hosts: HostResultList['hosts']; + http: HttpStart; +}) { + const { getState, dispatch } = store; + try { + const ingestPolicies = await getAgentAndPoliciesForEndpointsList( + http, + hosts, + nonExistingPolicies(getState()) + ); + if (ingestPolicies?.packagePolicy !== undefined) { + dispatch({ + type: 'serverReturnedEndpointNonExistingPolicies', + payload: ingestPolicies.packagePolicy, + }); + } + if (ingestPolicies?.agentPolicy !== undefined) { + dispatch({ + type: 'serverReturnedEndpointAgentPolicies', + payload: ingestPolicies.agentPolicy, + }); + } + } catch (error) { + // TODO should handle the error instead of logging it to the browser + // Also this is an anti-pattern we shouldn't use + // Ignore Errors, since this should not hinder the user's ability to use the UI + logError(error); + } +} diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details.tsx index 369b4c128e052..635a6ba6cf193 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details.tsx @@ -4,207 +4,223 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import styled from 'styled-components'; import { - EuiDescriptionList, - EuiListGroup, - EuiListGroupItem, - EuiText, - EuiFlexGroup, - EuiFlexItem, - EuiBadge, + EuiEmptyPrompt, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiLoadingContent, EuiSpacer, + EuiText, } from '@elastic/eui'; -import React, { memo, useMemo } from 'react'; -import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { isPolicyOutOfDate } from '../../utils'; -import { HostInfo, HostMetadata, HostStatus } from '../../../../../../common/endpoint/types'; -import { useEndpointSelector } from '../hooks'; -import { policyResponseStatus, uiQueryParams } from '../../store/selectors'; -import { POLICY_STATUS_TO_BADGE_COLOR } from '../host_constants'; -import { FormattedDateAndTime } from '../../../../../common/components/endpoint/formatted_date_time'; -import { useNavigateByRouterEventHandler } from '../../../../../common/hooks/endpoint/use_navigate_by_router_event_handler'; +import { FormattedMessage } from '@kbn/i18n/react'; +import React, { memo, useCallback, useEffect, useMemo } from 'react'; +import { HostMetadata } from '../../../../../../common/endpoint/types'; +import { PreferenceFormattedDateFromPrimitive } from '../../../../../common/components/formatted_date'; +import { useToasts } from '../../../../../common/lib/kibana'; import { getEndpointDetailsPath } from '../../../../common/routing'; -import { EndpointPolicyLink } from '../components/endpoint_policy_link'; -import { OutOfDate } from '../components/out_of_date'; -import { EndpointAgentStatus } from '../components/endpoint_agent_status'; -import { useAppUrl } from '../../../../../common/lib/kibana/hooks'; - -const HostIds = styled(EuiListGroupItem)` - margin-top: 0; - .euiListGroupItem__text { - padding: 0; - } -`; +import { + detailsData, + detailsError, + getActivityLogData, + hostStatusInfo, + policyResponseActions, + policyResponseAppliedRevision, + policyResponseConfigurations, + policyResponseError, + policyResponseFailedOrWarningActionCount, + policyResponseLoading, + policyResponseTimestamp, + policyVersionInfo, + showView, + uiQueryParams, +} from '../../store/selectors'; +import { useEndpointSelector } from '../hooks'; +import * as i18 from '../translations'; +import { ActionsMenu } from './components/actions_menu'; +import { BackToEndpointDetailsFlyoutSubHeader } from './components/back_to_endpoint_details_flyout_subheader'; +import { + EndpointDetailsFlyoutTabs, + EndpointDetailsTabsTypes, +} from './components/endpoint_details_tabs'; +import { EndpointIsolationFlyoutPanel } from './components/endpoint_isolate_flyout_panel'; +import { FlyoutBodyNoTopPadding } from './components/flyout_body_no_top_padding'; +import { EndpointDetailsFlyoutHeader } from './components/flyout_header'; +import { EndpointActivityLog } from './endpoint_activity_log'; +import { EndpointDetailsContent } from './endpoint_details_content'; +import { PolicyResponse } from './policy_response'; -export const EndpointDetails = memo( - ({ - details, - policyInfo, - hostStatus, - }: { - details: HostMetadata; - policyInfo?: HostInfo['policy_info']; - hostStatus: HostStatus; - }) => { - const queryParams = useEndpointSelector(uiQueryParams); - const policyStatus = useEndpointSelector( - policyResponseStatus - ) as keyof typeof POLICY_STATUS_TO_BADGE_COLOR; - const { getAppUrl } = useAppUrl(); +export const EndpointDetails = memo(() => { + const toasts = useToasts(); + const queryParams = useEndpointSelector(uiQueryParams); - const [policyResponseUri, policyResponseRoutePath] = useMemo(() => { - // eslint-disable-next-line @typescript-eslint/naming-convention - const { selected_endpoint, show, ...currentUrlParams } = queryParams; - const path = getEndpointDetailsPath({ - name: 'endpointPolicyResponse', - ...currentUrlParams, - selected_endpoint: details.agent.id, - }); - return [getAppUrl({ path }), path]; - }, [details.agent.id, getAppUrl, queryParams]); + const activityLog = useEndpointSelector(getActivityLogData); + const hostDetails = useEndpointSelector(detailsData); + const hostDetailsError = useEndpointSelector(detailsError); - const policyStatusClickHandler = useNavigateByRouterEventHandler(policyResponseRoutePath); - - const detailsResults = useMemo(() => { - return [ - { - title: i18n.translate('xpack.securitySolution.endpoint.details.os', { - defaultMessage: 'OS', - }), - description: {details.host.os.full}, - }, - { - title: i18n.translate('xpack.securitySolution.endpoint.details.agentStatus', { - defaultMessage: 'Agent Status', - }), - description: , - }, - { - title: i18n.translate('xpack.securitySolution.endpoint.details.lastSeen', { - defaultMessage: 'Last Seen', - }), - description: ( - - {' '} - - - ), - }, - { - title: i18n.translate('xpack.securitySolution.endpoint.details.policy', { - defaultMessage: 'Policy', - }), - description: ( - - - - - {details.Endpoint.policy.applied.name} - - - - - {details.Endpoint.policy.applied.endpoint_policy_version && ( - - - - - - )} - {isPolicyOutOfDate(details.Endpoint.policy.applied, policyInfo) && ( - - - - )} - - - ), - }, - { - title: i18n.translate('xpack.securitySolution.endpoint.details.policyStatus', { - defaultMessage: 'Policy Status', - }), - description: ( - // https://github.com/elastic/eui/issues/4530 - // @ts-ignore - - - - - - ), - }, - { - title: i18n.translate('xpack.securitySolution.endpoint.details.endpointVersion', { - defaultMessage: 'Endpoint Version', - }), - description: {details.agent.version}, - }, - { - title: i18n.translate('xpack.securitySolution.endpoint.details.ipAddress', { - defaultMessage: 'IP Address', - }), - description: ( - - - {details.host.ip.map((ip: string, index: number) => ( - - ))} - - - ), - }, - ]; - }, [ - details, - hostStatus, - policyResponseUri, - policyStatus, - policyStatusClickHandler, - policyInfo, - ]); + const policyInfo = useEndpointSelector(policyVersionInfo); + const hostStatus = useEndpointSelector(hostStatusInfo); + const show = useEndpointSelector(showView); - return ( + const ContentLoadingMarkup = useMemo( + () => ( <> + - + - ); - } -); + ), + [] + ); + + const getTabs = useCallback( + (id: string) => [ + { + id: EndpointDetailsTabsTypes.overview, + name: i18.OVERVIEW, + route: getEndpointDetailsPath({ + ...queryParams, + name: 'endpointDetails', + selected_endpoint: id, + }), + content: + hostDetails === undefined ? ( + ContentLoadingMarkup + ) : ( + + ), + }, + { + id: EndpointDetailsTabsTypes.activityLog, + name: i18.ACTIVITY_LOG.tabTitle, + route: getEndpointDetailsPath({ + ...queryParams, + name: 'endpointActivityLog', + selected_endpoint: id, + }), + content: , + }, + ], + [ContentLoadingMarkup, hostDetails, policyInfo, hostStatus, activityLog, queryParams] + ); + + const showFlyoutFooter = + show === 'details' || show === 'policy_response' || show === 'activity_log'; + + useEffect(() => { + if (hostDetailsError !== undefined) { + toasts.addDanger({ + title: i18n.translate('xpack.securitySolution.endpoint.details.errorTitle', { + defaultMessage: 'Could not find host', + }), + text: i18n.translate('xpack.securitySolution.endpoint.details.errorBody', { + defaultMessage: 'Please exit the flyout and select an available host.', + }), + }); + } + }, [hostDetailsError, show, toasts]); + return ( + <> + {(show === 'policy_response' || show === 'isolate' || show === 'unisolate') && ( + + )} + {hostDetails === undefined ? ( + + + + ) : ( + <> + {(show === 'details' || show === 'activity_log') && ( + + )} + + {show === 'policy_response' && } + + {(show === 'isolate' || show === 'unisolate') && ( + + )} + + {showFlyoutFooter && ( + + + + )} + + )} + + ); +}); EndpointDetails.displayName = 'EndpointDetails'; + +const PolicyResponseFlyoutPanel = memo<{ + hostMeta: HostMetadata; +}>(({ hostMeta }) => { + const responseConfig = useEndpointSelector(policyResponseConfigurations); + const responseActions = useEndpointSelector(policyResponseActions); + const responseAttentionCount = useEndpointSelector(policyResponseFailedOrWarningActionCount); + const loading = useEndpointSelector(policyResponseLoading); + const error = useEndpointSelector(policyResponseError); + const responseTimestamp = useEndpointSelector(policyResponseTimestamp); + const responsePolicyRevisionNumber = useEndpointSelector(policyResponseAppliedRevision); + + return ( + <> + + + + +

+ +

+
+ + + , + }} + /> + + + {error && ( + + } + /> + )} + {loading && } + {responseConfig !== undefined && responseActions !== undefined && ( + + )} +
+ + ); +}); + +PolicyResponseFlyoutPanel.displayName = 'PolicyResponseFlyoutPanel'; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details_content.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details_content.tsx new file mode 100644 index 0000000000000..cc1cad52eb21c --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/endpoint_details_content.tsx @@ -0,0 +1,210 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import styled from 'styled-components'; +import { + EuiDescriptionList, + EuiListGroup, + EuiListGroupItem, + EuiText, + EuiFlexGroup, + EuiFlexItem, + EuiBadge, + EuiSpacer, +} from '@elastic/eui'; +import React, { memo, useMemo } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { isPolicyOutOfDate } from '../../utils'; +import { HostInfo, HostMetadata, HostStatus } from '../../../../../../common/endpoint/types'; +import { useEndpointSelector } from '../hooks'; +import { policyResponseStatus, uiQueryParams } from '../../store/selectors'; +import { POLICY_STATUS_TO_BADGE_COLOR } from '../host_constants'; +import { FormattedDateAndTime } from '../../../../../common/components/endpoint/formatted_date_time'; +import { useNavigateByRouterEventHandler } from '../../../../../common/hooks/endpoint/use_navigate_by_router_event_handler'; +import { getEndpointDetailsPath } from '../../../../common/routing'; +import { EndpointPolicyLink } from '../components/endpoint_policy_link'; +import { OutOfDate } from '../components/out_of_date'; +import { EndpointAgentStatus } from '../components/endpoint_agent_status'; +import { useAppUrl } from '../../../../../common/lib/kibana/hooks'; + +const HostIds = styled(EuiListGroupItem)` + margin-top: 0; + .euiListGroupItem__text { + padding: 0; + } +`; + +export const EndpointDetailsContent = memo( + ({ + details, + policyInfo, + hostStatus, + }: { + details: HostMetadata; + policyInfo?: HostInfo['policy_info']; + hostStatus: HostStatus; + }) => { + const queryParams = useEndpointSelector(uiQueryParams); + const policyStatus = useEndpointSelector( + policyResponseStatus + ) as keyof typeof POLICY_STATUS_TO_BADGE_COLOR; + const { getAppUrl } = useAppUrl(); + + const [policyResponseUri, policyResponseRoutePath] = useMemo(() => { + // eslint-disable-next-line @typescript-eslint/naming-convention + const { selected_endpoint, show, ...currentUrlParams } = queryParams; + const path = getEndpointDetailsPath({ + name: 'endpointPolicyResponse', + ...currentUrlParams, + selected_endpoint: details.agent.id, + }); + return [getAppUrl({ path }), path]; + }, [details.agent.id, getAppUrl, queryParams]); + + const policyStatusClickHandler = useNavigateByRouterEventHandler(policyResponseRoutePath); + + const detailsResults = useMemo(() => { + return [ + { + title: i18n.translate('xpack.securitySolution.endpoint.details.os', { + defaultMessage: 'OS', + }), + description: {details.host.os.full}, + }, + { + title: i18n.translate('xpack.securitySolution.endpoint.details.agentStatus', { + defaultMessage: 'Agent Status', + }), + description: , + }, + { + title: i18n.translate('xpack.securitySolution.endpoint.details.lastSeen', { + defaultMessage: 'Last Seen', + }), + description: ( + + {' '} + + + ), + }, + { + title: i18n.translate('xpack.securitySolution.endpoint.details.policy', { + defaultMessage: 'Policy', + }), + description: ( + + + + + {details.Endpoint.policy.applied.name} + + + + + {details.Endpoint.policy.applied.endpoint_policy_version && ( + + + + + + )} + {isPolicyOutOfDate(details.Endpoint.policy.applied, policyInfo) && ( + + + + )} + + + ), + }, + { + title: i18n.translate('xpack.securitySolution.endpoint.details.policyStatus', { + defaultMessage: 'Policy Status', + }), + description: ( + // https://github.com/elastic/eui/issues/4530 + // @ts-ignore + + + + + + ), + }, + { + title: i18n.translate('xpack.securitySolution.endpoint.details.endpointVersion', { + defaultMessage: 'Endpoint Version', + }), + description: {details.agent.version}, + }, + { + title: i18n.translate('xpack.securitySolution.endpoint.details.ipAddress', { + defaultMessage: 'IP Address', + }), + description: ( + + + {details.host.ip.map((ip: string, index: number) => ( + + ))} + + + ), + }, + ]; + }, [ + details, + hostStatus, + policyResponseUri, + policyStatus, + policyStatusClickHandler, + policyInfo, + ]); + + return ( + <> + + + + ); + } +); + +EndpointDetailsContent.displayName = 'EndpointDetailsContent'; diff --git a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/index.tsx b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/index.tsx index d3fc812f6317b..84b0bdad4d6eb 100644 --- a/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/endpoint_hosts/view/details/index.tsx @@ -4,122 +4,23 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import React, { useCallback, useEffect, useMemo, memo } from 'react'; -import { - EuiFlyout, - EuiFlyoutBody, - EuiFlyoutFooter, - EuiLoadingContent, - EuiText, - EuiSpacer, - EuiEmptyPrompt, -} from '@elastic/eui'; +import React, { useCallback, memo } from 'react'; +import { EuiFlyout } from '@elastic/eui'; import { useHistory } from 'react-router-dom'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { i18n } from '@kbn/i18n'; -import { useToasts } from '../../../../../common/lib/kibana'; import { useEndpointSelector } from '../hooks'; -import { - uiQueryParams, - detailsData, - detailsError, - getActivityLogData, - showView, - policyResponseConfigurations, - policyResponseActions, - policyResponseFailedOrWarningActionCount, - policyResponseError, - policyResponseLoading, - policyResponseTimestamp, - policyVersionInfo, - hostStatusInfo, - policyResponseAppliedRevision, -} from '../../store/selectors'; -import { EndpointDetails } from './endpoint_details'; -import { EndpointActivityLog } from './endpoint_activity_log'; -import { PolicyResponse } from './policy_response'; -import * as i18 from '../translations'; -import { HostMetadata } from '../../../../../../common/endpoint/types'; -import { - EndpointDetailsFlyoutTabs, - EndpointDetailsTabsTypes, -} from './components/endpoint_details_tabs'; +import { uiQueryParams } from '../../store/selectors'; -import { PreferenceFormattedDateFromPrimitive } from '../../../../../common/components/formatted_date'; -import { EndpointIsolationFlyoutPanel } from './components/endpoint_isolate_flyout_panel'; -import { BackToEndpointDetailsFlyoutSubHeader } from './components/back_to_endpoint_details_flyout_subheader'; -import { FlyoutBodyNoTopPadding } from './components/flyout_body_no_top_padding'; -import { getEndpointListPath, getEndpointDetailsPath } from '../../../../common/routing'; -import { ActionsMenu } from './components/actions_menu'; -import { EndpointDetailsFlyoutHeader } from './components/flyout_header'; +import { getEndpointListPath } from '../../../../common/routing'; +import { EndpointDetails } from './endpoint_details'; export const EndpointDetailsFlyout = memo(() => { const history = useHistory(); - const toasts = useToasts(); const queryParams = useEndpointSelector(uiQueryParams); const { selected_endpoint: selectedEndpoint, ...queryParamsWithoutSelectedEndpoint } = queryParams; - const activityLog = useEndpointSelector(getActivityLogData); - const hostDetails = useEndpointSelector(detailsData); - const hostDetailsError = useEndpointSelector(detailsError); - - const policyInfo = useEndpointSelector(policyVersionInfo); - const hostStatus = useEndpointSelector(hostStatusInfo); - const show = useEndpointSelector(showView); - - const ContentLoadingMarkup = useMemo( - () => ( - <> - - - - - ), - [] - ); - - const getTabs = useCallback( - (id: string) => [ - { - id: EndpointDetailsTabsTypes.overview, - name: i18.OVERVIEW, - route: getEndpointDetailsPath({ - ...queryParams, - name: 'endpointDetails', - selected_endpoint: id, - }), - content: - hostDetails === undefined ? ( - ContentLoadingMarkup - ) : ( - - ), - }, - { - id: EndpointDetailsTabsTypes.activityLog, - name: i18.ACTIVITY_LOG.tabTitle, - route: getEndpointDetailsPath({ - ...queryParams, - name: 'endpointActivityLog', - selected_endpoint: id, - }), - content: , - }, - ], - [ContentLoadingMarkup, hostDetails, policyInfo, hostStatus, activityLog, queryParams] - ); - - const showFlyoutFooter = - show === 'details' || show === 'policy_response' || show === 'activity_log'; - const handleFlyoutClose = useCallback(() => { const { show: _show, ...urlSearchParams } = queryParamsWithoutSelectedEndpoint; history.push( @@ -129,20 +30,6 @@ export const EndpointDetailsFlyout = memo(() => { }) ); }, [history, queryParamsWithoutSelectedEndpoint]); - - useEffect(() => { - if (hostDetailsError !== undefined) { - toasts.addDanger({ - title: i18n.translate('xpack.securitySolution.endpoint.details.errorTitle', { - defaultMessage: 'Could not find host', - }), - text: i18n.translate('xpack.securitySolution.endpoint.details.errorBody', { - defaultMessage: 'Please exit the flyout and select an available host.', - }), - }); - } - }, [hostDetailsError, show, toasts]); - return ( { paddingSize="l" ownFocus={false} > - {(show === 'policy_response' || show === 'isolate' || show === 'unisolate') && ( - - )} - {hostDetails === undefined ? ( - - - - ) : ( - <> - {(show === 'details' || show === 'activity_log') && ( - - )} - - {show === 'policy_response' && } - - {(show === 'isolate' || show === 'unisolate') && ( - - )} - - {showFlyoutFooter && ( - - - - )} - - )} + ); }); EndpointDetailsFlyout.displayName = 'EndpointDetailsFlyout'; - -const PolicyResponseFlyoutPanel = memo<{ - hostMeta: HostMetadata; -}>(({ hostMeta }) => { - const responseConfig = useEndpointSelector(policyResponseConfigurations); - const responseActions = useEndpointSelector(policyResponseActions); - const responseAttentionCount = useEndpointSelector(policyResponseFailedOrWarningActionCount); - const loading = useEndpointSelector(policyResponseLoading); - const error = useEndpointSelector(policyResponseError); - const responseTimestamp = useEndpointSelector(policyResponseTimestamp); - const responsePolicyRevisionNumber = useEndpointSelector(policyResponseAppliedRevision); - - return ( - <> - - - - -

- -

-
- - - , - }} - /> - - - {error && ( - - } - /> - )} - {loading && } - {responseConfig !== undefined && responseActions !== undefined && ( - - )} -
- - ); -}); - -PolicyResponseFlyoutPanel.displayName = 'PolicyResponseFlyoutPanel';