Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,15 @@ interface ServerReturnedHostPolicyResponse {
payload: GetHostPolicyResponse;
}

interface ServerFailedToReturnHostPolicyResponse {
type: 'serverFailedToReturnHostPolicyResponse';
payload: ServerApiError;
}

export type HostAction =
| ServerReturnedHostList
| ServerFailedToReturnHostList
| ServerReturnedHostDetails
| ServerFailedToReturnHostDetails
| ServerReturnedHostPolicyResponse;
| ServerReturnedHostPolicyResponse
| ServerFailedToReturnHostPolicyResponse;
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ describe('HostList store concerns', () => {
details: undefined,
detailsLoading: false,
detailsError: undefined,
policyResponse: undefined,
policyResponseLoading: false,
policyResponseError: undefined,
location: undefined,
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { HostResultList, HostPolicyResponseActionStatus } from '../../../../../common/types';
import { HostResultList } from '../../../../../common/types';
import { isOnHostPage, hasSelectedHost, uiQueryParams, listData } from './selectors';
import { HostState } from '../../types';
import { ImmutableMiddlewareFactory } from '../../types';
import { HostPolicyResponse } from '../../../../../common/types';

export const hostMiddlewareFactory: ImmutableMiddlewareFactory<HostState> = coreStart => {
return ({ getState, dispatch }) => next => async action => {
Expand Down Expand Up @@ -70,47 +69,25 @@ export const hostMiddlewareFactory: ImmutableMiddlewareFactory<HostState> = core
type: 'serverReturnedHostDetails',
payload: response,
});
} catch (error) {
dispatch({
type: 'serverFailedToReturnHostDetails',
payload: error,
});
}

// call the policy response api
try {
const policyResponse = await coreStart.http.get(`/api/endpoint/policy_response`, {
query: { hostId: selectedHost },
});
dispatch({
type: 'serverReturnedHostPolicyResponse',
payload: {
policy_response: ({
endpoint: {
policy: {
applied: {
version: '1.0.0',
status: HostPolicyResponseActionStatus.success,
id: '17d4b81d-9940-4b64-9de5-3e03ef1fb5cf',
actions: {
download_model: {
status: 'success',
message: 'Model downloaded',
},
ingest_events_config: {
status: 'failure',
message: 'No action taken',
},
},
response: {
configurations: {
malware: {
status: 'success',
concerned_actions: ['download_model'],
},
events: {
status: 'failure',
concerned_actions: ['ingest_events_config'],
},
},
},
},
},
},
} as unknown) as HostPolicyResponse, // Temporary until we get API
},
payload: policyResponse,
});
} catch (error) {
dispatch({
type: 'serverFailedToReturnHostDetails',
type: 'serverFailedToReturnHostPolicyResponse',
payload: error,
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ const initialState = (): HostState => {
detailsLoading: false,
detailsError: undefined,
policyResponse: undefined,
policyResponseLoading: false,
policyResponseError: undefined,
location: undefined,
};
};
Expand Down Expand Up @@ -68,6 +70,14 @@ export const hostListReducer: ImmutableReducer<HostState, AppAction> = (
return {
...state,
policyResponse: action.payload.policy_response,
policyResponseLoading: false,
policyResponseError: undefined,
};
} else if (action.type === 'serverFailedToReturnHostPolicyResponse') {
return {
...state,
policyResponseError: action.payload,
policyResponseLoading: false,
};
} else if (action.type === 'userChangedUrl') {
const newState: Immutable<HostState> = {
Expand Down Expand Up @@ -97,8 +107,10 @@ export const hostListReducer: ImmutableReducer<HostState, AppAction> = (
...state,
location: action.payload,
detailsLoading: true,
policyResponseLoading: true,
error: undefined,
detailsError: undefined,
policyResponseError: undefined,
};
} else {
// if previous page was not host list or host details, load both list and details
Expand All @@ -107,8 +119,10 @@ export const hostListReducer: ImmutableReducer<HostState, AppAction> = (
location: action.payload,
loading: true,
detailsLoading: true,
policyResponseLoading: true,
error: undefined,
detailsError: undefined,
policyResponseError: undefined,
};
}
}
Expand All @@ -118,6 +132,7 @@ export const hostListReducer: ImmutableReducer<HostState, AppAction> = (
location: action.payload,
error: undefined,
detailsError: undefined,
policyResponseError: undefined,
};
}
return state;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,11 @@ export const policyResponseActions: (
}
);

export const policyResponseLoading = (state: Immutable<HostState>): boolean =>
state.policyResponseLoading;

export const policyResponseError = (state: Immutable<HostState>) => state.policyResponseError;

export const isOnHostPage = (state: Immutable<HostState>) =>
state.location ? state.location.pathname === '/hosts' : false;

Expand Down
4 changes: 4 additions & 0 deletions x-pack/plugins/endpoint/public/applications/endpoint/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ export interface HostState {
detailsError?: ServerApiError;
/** Holds the Policy Response for the Host currently being displayed in the details */
policyResponse?: HostPolicyResponse;
/** policyResponse is being retrieved */
policyResponseLoading: boolean;
/** api error from retrieving the policy response */
policyResponseError?: ServerApiError;
/** current location info */
location?: Immutable<EndpointAppLocation>;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { useHostSelector, useHostLogsUrl } from '../hooks';
import { urlFromQueryParams } from '../url_from_query_params';
import { policyResponseStatus, uiQueryParams } from '../../../store/hosts/selectors';
import { useNavigateByRouterEventHandler } from '../../hooks/use_navigate_by_router_event_handler';
import { POLICY_STATUS_TO_HEALTH_COLOR } from './host_constants';
import { POLICY_STATUS_TO_HEALTH_COLOR } from '../host_constants';

const HostIds = styled(EuiListGroupItem)`
margin-top: 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
EuiTitle,
EuiText,
EuiSpacer,
EuiEmptyPrompt,
} from '@elastic/eui';
import { useHistory } from 'react-router-dom';
import { FormattedMessage } from '@kbn/i18n/react';
Expand All @@ -29,6 +30,8 @@ import {
policyResponseConfigurations,
policyResponseActions,
policyResponseFailedOrWarningActionCount,
policyResponseError,
policyResponseLoading,
} from '../../../store/hosts/selectors';
import { HostDetails } from './host_details';
import { PolicyResponse } from './policy_response';
Expand Down Expand Up @@ -108,6 +111,8 @@ const PolicyResponseFlyoutPanel = memo<{
const responseConfig = useHostSelector(policyResponseConfigurations);
const responseActionStatus = useHostSelector(policyResponseActions);
const responseAttentionCount = useHostSelector(policyResponseFailedOrWarningActionCount);
const loading = useHostSelector(policyResponseLoading);
const error = useHostSelector(policyResponseError);
const detailsUri = useMemo(
() =>
urlFromQueryParams({
Expand Down Expand Up @@ -142,17 +147,24 @@ const PolicyResponseFlyoutPanel = memo<{
/>
</h4>
</EuiText>
{responseConfig !== undefined && responseActionStatus !== undefined ? (
{error && (
<EuiEmptyPrompt
title={
<FormattedMessage
id="xpack.endpoint.hostDetails.noPolicyResponse"
defaultMessage="No policy response available"
/>
}
/>
)}
{loading && <EuiLoadingContent lines={3} />}

{responseConfig !== undefined && responseActionStatus !== undefined && (
<PolicyResponse
responseConfig={responseConfig}
responseActionStatus={responseActionStatus}
responseAttentionCount={responseAttentionCount}
/>
) : (
<FormattedMessage
id="xpack.endpoint.hostDetails.noPolicyResponse"
defaultMessage="No Policy Response Available"
/>
)}
</EuiFlyoutBody>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
Immutable,
} from '../../../../../../common/types';
import { formatResponse } from './policy_response_friendly_names';
import { POLICY_STATUS_TO_HEALTH_COLOR } from './host_constants';
import { POLICY_STATUS_TO_HEALTH_COLOR } from '../host_constants';

/**
* Nested accordion in the policy response detailing any concerned
Expand Down Expand Up @@ -43,6 +43,17 @@ const PolicyResponseConfigAccordion = styled(EuiAccordion)`
:hover:not(.euiAccordion-isOpen) {
background-color: ${props => props.theme.eui.euiColorLightestShade};
}

.policyResponseActionsAccordion {
svg {
height: ${props => props.theme.eui.euiIconSizes.small};
width: ${props => props.theme.eui.euiIconSizes.small};
}
}

.policyResponseStatusHealth {
width: 100px;
}
`;

const ResponseActions = memo(
Expand All @@ -65,8 +76,13 @@ const ResponseActions = memo(
id={action + index}
key={action + index}
data-test-subj="hostDetailsPolicyResponseActionsAccordion"
className="policyResponseActionsAccordion"
buttonContent={
<EuiText size="xs" data-test-subj="policyResponseAction">
<EuiText
size="xs"
className="eui-textTruncate"
data-test-subj="policyResponseAction"
>
<h4>{formatResponse(action)}</h4>
</EuiText>
}
Expand All @@ -75,6 +91,7 @@ const ResponseActions = memo(
<EuiHealth
color={POLICY_STATUS_TO_HEALTH_COLOR[statuses.status]}
data-test-subj="policyResponseStatusHealth"
className="policyResponseStatusHealth"
>
<EuiText size="xs">
<p>{formatResponse(statuses.status)}</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ responseMap.set(
defaultMessage: 'Failed',
})
);
responseMap.set(
'logging',
i18n.translate('xpack.endpoint.hostDetails.policyResponse.logging', {
defaultMessage: 'Logging',
})
);
responseMap.set(
'streaming',
i18n.translate('xpack.endpoint.hostDetails.policyResponse.streaming', {
defaultMessage: 'Streaming',
})
);
responseMap.set(
'malware',
i18n.translate('xpack.endpoint.hostDetails.policyResponse.malware', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,17 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { HostPolicyResponseActionStatus } from '../../../../../../common/types';
import { HostPolicyResponseActionStatus, HostStatus } from '../../../../../common/types';

export const HOST_STATUS_TO_HEALTH_COLOR = Object.freeze<
{
[key in HostStatus]: string;
}
>({
[HostStatus.ERROR]: 'danger',
[HostStatus.ONLINE]: 'success',
[HostStatus.OFFLINE]: 'subdued',
});

export const POLICY_STATUS_TO_HEALTH_COLOR = Object.freeze<
{ [key in keyof typeof HostPolicyResponseActionStatus]: string }
Expand Down
Loading