diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_action_failure_message/endpoint_action_failure_message.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_action_failure_message/endpoint_action_failure_message.tsx index 6a197890b4bf6..7e85a0d081ed6 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_action_failure_message/endpoint_action_failure_message.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_action_failure_message/endpoint_action_failure_message.tsx @@ -14,10 +14,11 @@ import type { ActionDetails, MaybeImmutable } from '../../../../common/endpoint/ interface EndpointActionFailureMessageProps { action: MaybeImmutable>; + 'data-test-subj'?: string; } export const EndpointActionFailureMessage = memo( - ({ action }) => { + ({ action, 'data-test-subj': dataTestSubj }) => { return useMemo(() => { if (!action.isCompleted || action.wasSuccessful) { return null; @@ -55,7 +56,7 @@ export const EndpointActionFailureMessage = memo +
{errors.join(' | ')}
- +
); - }, [action]); + }, [ + action.agents, + action.errors, + action.isCompleted, + action.outputs, + action.wasSuccessful, + dataTestSubj, + ]); } ); EndpointActionFailureMessage.displayName = 'EndpointActionFailureMessage'; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/upload_action.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/upload_action.tsx index ea119fe5583e0..97856800ada85 100644 --- a/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/upload_action.tsx +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_responder/command_render_components/upload_action.tsx @@ -6,6 +6,7 @@ */ import React, { memo, useMemo } from 'react'; +import { EndpointUploadActionResult } from '../../endpoint_upload_action_result'; import type { UploadActionUIRequestBody } from '../../../../../common/endpoint/schema/actions'; import { useConsoleActionSubmitter } from '../hooks/use_console_action_submitter'; import { useSendUploadEndpointRequest } from '../../../hooks/response_actions/use_send_upload_endpoint_request'; @@ -53,6 +54,14 @@ export const UploadActionResult = memo< dataTestSubj: 'upload', }); - return
{'UploadActionResult placeholder'}
; + if (actionDetails?.isCompleted && actionDetails.wasSuccessful) { + return ( + + + + ); + } + + return result; }); UploadActionResult.displayName = 'UploadActionResult'; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_upload_action_result/endpoint_upload_action_result.tsx b/x-pack/plugins/security_solution/public/management/components/endpoint_upload_action_result/endpoint_upload_action_result.tsx new file mode 100644 index 0000000000000..8b2c2b4eeeeb7 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_upload_action_result/endpoint_upload_action_result.tsx @@ -0,0 +1,108 @@ +/* + * 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 { FormattedMessage } from '@kbn/i18n-react'; +import React, { memo } from 'react'; +import { EuiText } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import numeral from '@elastic/numeral'; +import { EndpointActionFailureMessage } from '../endpoint_action_failure_message'; +import type { + ActionDetails, + ResponseActionUploadOutputContent, + ResponseActionUploadParameters, +} from '../../../../common/endpoint/types'; +import { useTestIdGenerator } from '../../hooks/use_test_id_generator'; + +interface EndpointUploadActionResultProps { + action: ActionDetails; + /** The agent id to display the result for. If undefined, the first agent will be used */ + agentId?: string; + 'data-test-subj'?: string; +} + +const LABELS = Object.freeze>({ + path: i18n.translate('xpack.securitySolution.uploadActionResult.savedTo', { + defaultMessage: 'File saved to', + }), + + disk_free_space: i18n.translate('xpack.securitySolution.uploadActionResult.freeDiskSpace', { + defaultMessage: 'Free disk space on drive', + }), + + noAgentResponse: i18n.translate('xpack.securitySolution.uploadActionResult.missingAgentResult', { + defaultMessage: 'Error: Agent result missing', + }), +}); + +export const EndpointUploadActionResult = memo( + ({ action, agentId, 'data-test-subj': dataTestSubj }) => { + const getTestId = useTestIdGenerator(dataTestSubj); + + const agentState = action?.agentState[agentId ?? action.agents[0]]; + const agentResult = action?.outputs?.[agentId ?? action.agents[0]]; + + if (action.command !== 'upload') { + return null; + } + + // Use case: action log + if (!agentState.isCompleted) { + return ( +
+ +
+ ); + } + + // if we don't have an agent result (for whatever reason) + if (!agentResult) { + return
{LABELS.noAgentResponse}
; + } + + // Error result + if (!agentState.wasSuccessful) { + return ( + + ); + } + + return ( +
+ + +
+ ); + } +); +EndpointUploadActionResult.displayName = 'EndpointUploadActionResult'; + +export interface KeyValueDisplayProps { + name: string; + value: string; +} +const KeyValueDisplay = memo(({ name, value }) => { + return ( + + + {name} + {': '} + + {value} + + ); +}); +KeyValueDisplay.displayName = 'KeyValueDisplay'; diff --git a/x-pack/plugins/security_solution/public/management/components/endpoint_upload_action_result/index.ts b/x-pack/plugins/security_solution/public/management/components/endpoint_upload_action_result/index.ts new file mode 100644 index 0000000000000..2b94f4ead1140 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/components/endpoint_upload_action_result/index.ts @@ -0,0 +1,8 @@ +/* + * 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. + */ + +export { EndpointUploadActionResult } from './endpoint_upload_action_result';