mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Security Solution][Endpoint] Display better success and failure messages for kill suspend process actions (#137353) (#137462)
* add map with endpoint action response code and associated i18n message
* Add component to handle getting a failure message from a completed action
* Add component to handle getting a failure message from a completed action
* Correct type definition for ActionResponseOutput
* New ActionSuccess component + use it in kill/suspend process
* Change default failure message
* add some jsdocs to the endpoint codes
(cherry picked from commit cb4d6aa8d5
)
Co-authored-by: Paul Tavares <56442535+paul-tavares@users.noreply.github.com>
This commit is contained in:
parent
3d6d405054
commit
10460c84c8
16 changed files with 304 additions and 71 deletions
|
@ -18,9 +18,7 @@ export type ISOLATION_ACTIONS = 'isolate' | 'unisolate';
|
|||
/** The output provided by some of the Endpoint responses */
|
||||
export interface ActionResponseOutput<TOutputContent extends object = object> {
|
||||
type: 'json' | 'text';
|
||||
content: {
|
||||
entries: TOutputContent[];
|
||||
};
|
||||
content: TOutputContent;
|
||||
}
|
||||
|
||||
export interface ProcessesEntry {
|
||||
|
@ -30,6 +28,24 @@ export interface ProcessesEntry {
|
|||
user: string;
|
||||
}
|
||||
|
||||
export interface GetProcessesActionOutputContent {
|
||||
entries: ProcessesEntry[];
|
||||
}
|
||||
|
||||
export interface SuspendProcessActionOutputContent {
|
||||
code: string;
|
||||
command?: string;
|
||||
pid?: number;
|
||||
entity_id?: string;
|
||||
}
|
||||
|
||||
export interface KillProcessActionOutputContent {
|
||||
code: string;
|
||||
command?: string;
|
||||
pid?: number;
|
||||
entity_id?: string;
|
||||
}
|
||||
|
||||
export const RESPONSE_ACTION_COMMANDS = [
|
||||
'isolate',
|
||||
'unisolate',
|
||||
|
@ -275,9 +291,7 @@ export interface ActionDetails<TOutputContent extends object = object> {
|
|||
startedAt: string;
|
||||
/** The date when the action was completed (a response by the endpoint (not fleet) was received) */
|
||||
completedAt: string | undefined;
|
||||
/**
|
||||
* The output data from an action
|
||||
*/
|
||||
/** The output data from an action stored in an object where the key is the agent id */
|
||||
outputs?: Record<string, ActionResponseOutput<TOutputContent>>;
|
||||
/** user that created the action */
|
||||
createdBy: string;
|
||||
|
|
|
@ -7,10 +7,19 @@
|
|||
|
||||
export { Console } from './console';
|
||||
export { ConsoleManager, useConsoleManager } from './components/console_manager';
|
||||
export type { CommandDefinition, Command, ConsoleProps } from './types';
|
||||
export type {
|
||||
CommandDefinition,
|
||||
Command,
|
||||
ConsoleProps,
|
||||
CommandExecutionComponentProps,
|
||||
} from './types';
|
||||
export type {
|
||||
ConsoleRegistrationInterface,
|
||||
ManagedConsoleExtensionComponentProps,
|
||||
RegisteredConsoleClient,
|
||||
ConsoleManagerClient,
|
||||
} from './components/console_manager/types';
|
||||
export type {
|
||||
CommandExecutionResultProps,
|
||||
CommandExecutionResultComponent,
|
||||
} from './components/command_execution_result';
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* 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 React, { memo, useMemo } from 'react';
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { endpointActionResponseCodes } from '../endpoint_responder/endpoint_action_response_codes';
|
||||
import type { ActionDetails, MaybeImmutable } from '../../../../common/endpoint/types';
|
||||
|
||||
interface EndpointActionFailureMessageProps {
|
||||
action: MaybeImmutable<ActionDetails<{ code?: string }>>;
|
||||
}
|
||||
|
||||
export const EndpointActionFailureMessage = memo<EndpointActionFailureMessageProps>(
|
||||
({ action }) => {
|
||||
return useMemo(() => {
|
||||
if (!action.isCompleted || action.wasSuccessful) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const errors: string[] = [];
|
||||
|
||||
// Determine if each endpoint returned a response code and if so,
|
||||
// see if we have a localized message for it
|
||||
if (action.outputs) {
|
||||
for (const agent of action.agents) {
|
||||
const endpointAgentOutput = action.outputs[agent];
|
||||
|
||||
if (
|
||||
endpointAgentOutput &&
|
||||
endpointAgentOutput.type === 'json' &&
|
||||
endpointAgentOutput.content.code &&
|
||||
endpointActionResponseCodes[endpointAgentOutput.content.code]
|
||||
) {
|
||||
errors.push(endpointActionResponseCodes[endpointAgentOutput.content.code]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!errors.length) {
|
||||
if (action.errors) {
|
||||
errors.push(...action.errors);
|
||||
} else {
|
||||
errors.push(
|
||||
i18n.translate('xpack.securitySolution.endpointActionFailureMessage.unknownFailure', {
|
||||
defaultMessage: 'Action failed',
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.endpointResponseActions.actionError.errorMessage"
|
||||
defaultMessage="The following { errorCount, plural, =1 {error was} other {errors were}} encountered:"
|
||||
values={{ errorCount: errors.length }}
|
||||
/>
|
||||
<EuiSpacer size="s" />
|
||||
<div>{errors.join(' | ')}</div>
|
||||
</>
|
||||
);
|
||||
}, [action]);
|
||||
}
|
||||
);
|
||||
EndpointActionFailureMessage.displayName = 'EndpointActionFailureMessage';
|
|
@ -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 { EndpointActionFailureMessage } from './endpoint_action_failure_message';
|
|
@ -6,25 +6,19 @@
|
|||
*/
|
||||
|
||||
import React, { memo } from 'react';
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import { EndpointActionFailureMessage } from '../endpoint_action_failure_message';
|
||||
import type { CommandExecutionResultComponent } from '../console/components/command_execution_result';
|
||||
import type { ImmutableArray } from '../../../../common/endpoint/types';
|
||||
import type { ActionDetails, MaybeImmutable } from '../../../../common/endpoint/types';
|
||||
|
||||
export const ActionError = memo<{
|
||||
errors: ImmutableArray<string>;
|
||||
title?: string;
|
||||
action: MaybeImmutable<ActionDetails>;
|
||||
ResultComponent: CommandExecutionResultComponent;
|
||||
title?: string;
|
||||
dataTestSubj?: string;
|
||||
}>(({ title, dataTestSubj, errors, ResultComponent }) => {
|
||||
}>(({ title, dataTestSubj, action, ResultComponent }) => {
|
||||
return (
|
||||
<ResultComponent showAs="failure" title={title} data-test-subj={dataTestSubj}>
|
||||
<FormattedMessage
|
||||
id="xpack.securitySolution.endpointResponseActions.actionError.errorMessage"
|
||||
defaultMessage="The following errors were encountered:"
|
||||
/>
|
||||
<EuiSpacer size="s" />
|
||||
<div>{errors.join(' | ')}</div>
|
||||
<EndpointActionFailureMessage action={action} />
|
||||
</ResultComponent>
|
||||
);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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 React, { memo, useMemo } from 'react';
|
||||
import { endpointActionResponseCodes } from './endpoint_action_response_codes';
|
||||
import type { ActionDetails, MaybeImmutable } from '../../../../common/endpoint/types';
|
||||
import type { CommandExecutionResultComponent, CommandExecutionResultProps } from '../console';
|
||||
|
||||
export interface ActionSuccessProps extends CommandExecutionResultProps {
|
||||
action: MaybeImmutable<ActionDetails<{ code?: string }>>;
|
||||
ResultComponent: CommandExecutionResultComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display generic success message for all actions
|
||||
*/
|
||||
export const ActionSuccess = memo<ActionSuccessProps>(
|
||||
({ action, ResultComponent, title: _title, ...props }) => {
|
||||
const title = useMemo(() => {
|
||||
if (_title) {
|
||||
return _title;
|
||||
}
|
||||
|
||||
const firstAgentId = action.agents[0];
|
||||
const actionOutputCode = action.outputs?.[firstAgentId]?.content?.code;
|
||||
|
||||
return actionOutputCode ? endpointActionResponseCodes[actionOutputCode] : undefined;
|
||||
}, [_title, action.agents, action.outputs]);
|
||||
|
||||
return <ResultComponent {...props} title={title} />;
|
||||
}
|
||||
);
|
||||
ActionSuccess.displayName = 'ActionSuccess';
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
|
||||
const CODES = Object.freeze({
|
||||
// -----------------------------------------------------------------
|
||||
// SUSPEND-PROCESS CODES
|
||||
// -----------------------------------------------------------------
|
||||
/**
|
||||
* Code will be used whenever you provide an entity_id or pid that isn't found.
|
||||
* suspend_process will always be an error because the process was not found to be suspended
|
||||
*/
|
||||
'ra_suspend-process_error_not-found': i18n.translate(
|
||||
'xpack.securitySolution.endpointActionResponseCodes.suspendProcess.notFoundError',
|
||||
{ defaultMessage: 'The provided process was not found' }
|
||||
),
|
||||
|
||||
/**
|
||||
* Code will be used when the provided process can not be killed (for stability reasons).
|
||||
* Example: This occurs if you try to kill Endpoint Security
|
||||
*/
|
||||
'ra_suspend-process_error_not-permitted': i18n.translate(
|
||||
'xpack.securitySolution.endpointActionResponseCodes.suspendProcess.notPermittedSuccess',
|
||||
{ defaultMessage: 'The provided process cannot be suspended' }
|
||||
),
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
// KILL-PROCESS CODES
|
||||
// -----------------------------------------------------------------
|
||||
/**
|
||||
* Code will be used whenever you provide an entity_id that isn't found. Since entity_id is
|
||||
* unique, we can guarantee that it was legitimately not found and not just that the process
|
||||
* was already killed.
|
||||
*/
|
||||
'ra_kill-process_error_not-found': i18n.translate(
|
||||
'xpack.securitySolution.endpointActionResponseCodes.killProcess.notFoundError',
|
||||
{ defaultMessage: 'The provided process was not found' }
|
||||
),
|
||||
|
||||
/**
|
||||
* Code will be used whenever you provide a pid that isn't found. Since pid is reused, we aren't
|
||||
* sure if the process was already killed or just wasn't found. In either case, a process with
|
||||
* that pid will no longer be running.
|
||||
*/
|
||||
'ra_kill-process_success_no-action': i18n.translate(
|
||||
'xpack.securitySolution.endpointActionResponseCodes.killProcess.noActionSuccess',
|
||||
{ defaultMessage: 'Action completed. The provided process was not found or already killed' }
|
||||
),
|
||||
|
||||
/**
|
||||
* Code will be used when the provided process can not be killed (for stability reasons).
|
||||
* Example: This occurs if you try to kill Endpoint Security
|
||||
*/
|
||||
'ra_kill-process_error_not-permitted': i18n.translate(
|
||||
'xpack.securitySolution.endpointActionResponseCodes.killProcess.notPermittedSuccess',
|
||||
{ defaultMessage: 'The provided process cannot be killed' }
|
||||
),
|
||||
});
|
||||
|
||||
/**
|
||||
* A map of possible code's that can be returned from the endpoint for response actions
|
||||
*/
|
||||
export const endpointActionResponseCodes: Readonly<Record<string | keyof typeof CODES, string>> =
|
||||
CODES;
|
|
@ -11,7 +11,10 @@ import { EuiBasicTable } from '@elastic/eui';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import type { IHttpFetchError } from '@kbn/core-http-browser';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import type { ActionDetails, ProcessesEntry } from '../../../../common/endpoint/types';
|
||||
import type {
|
||||
ActionDetails,
|
||||
GetProcessesActionOutputContent,
|
||||
} from '../../../../common/endpoint/types';
|
||||
import { useGetActionDetails } from '../../hooks/endpoint/use_get_action_details';
|
||||
import type { EndpointCommandDefinitionMeta } from './types';
|
||||
import type { CommandExecutionComponentProps } from '../console/types';
|
||||
|
@ -46,7 +49,7 @@ export const GetProcessesActionResult = memo<
|
|||
{
|
||||
actionId?: string;
|
||||
actionRequestSent?: boolean;
|
||||
completedActionDetails?: ActionDetails<ProcessesEntry>;
|
||||
completedActionDetails?: ActionDetails<GetProcessesActionOutputContent>;
|
||||
apiError?: IHttpFetchError;
|
||||
},
|
||||
EndpointCommandDefinitionMeta
|
||||
|
@ -66,10 +69,13 @@ export const GetProcessesActionResult = memo<
|
|||
error: processesActionRequestError,
|
||||
} = useSendGetEndpointProcessesRequest();
|
||||
|
||||
const { data: actionDetails } = useGetActionDetails<ProcessesEntry>(actionId ?? '-', {
|
||||
enabled: Boolean(actionId) && isPending,
|
||||
refetchInterval: isPending ? 3000 : false,
|
||||
});
|
||||
const { data: actionDetails } = useGetActionDetails<GetProcessesActionOutputContent>(
|
||||
actionId ?? '-',
|
||||
{
|
||||
enabled: Boolean(actionId) && isPending,
|
||||
refetchInterval: isPending ? 3000 : false,
|
||||
}
|
||||
);
|
||||
|
||||
// Send get processes request if not yet done
|
||||
useEffect(() => {
|
||||
|
@ -201,7 +207,7 @@ export const GetProcessesActionResult = memo<
|
|||
{ defaultMessage: 'Get processes action failed' }
|
||||
)}
|
||||
dataTestSubj={'getProcessesErrorCallout'}
|
||||
errors={completedActionDetails?.errors}
|
||||
action={completedActionDetails}
|
||||
ResultComponent={ResultComponent}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -38,7 +38,7 @@ export const IsolateActionResult = memo<ActionRequestComponentProps>(
|
|||
return (
|
||||
<ActionError
|
||||
dataTestSubj={'isolateErrorCallout'}
|
||||
errors={completedActionDetails?.errors}
|
||||
action={completedActionDetails}
|
||||
ResultComponent={ResultComponent}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -8,7 +8,11 @@
|
|||
import React, { memo, useEffect } from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import type { IHttpFetchError } from '@kbn/core-http-browser';
|
||||
import type { ActionDetails } from '../../../../common/endpoint/types';
|
||||
import { ActionSuccess } from './action_success';
|
||||
import type {
|
||||
ActionDetails,
|
||||
KillProcessActionOutputContent,
|
||||
} from '../../../../common/endpoint/types';
|
||||
import { useGetActionDetails } from '../../hooks/endpoint/use_get_action_details';
|
||||
import type { EndpointCommandDefinitionMeta } from './types';
|
||||
import { useSendKillProcessRequest } from '../../hooks/endpoint/use_send_kill_process_endpoint_request';
|
||||
|
@ -23,7 +27,7 @@ export const KillProcessActionResult = memo<
|
|||
{
|
||||
actionId?: string;
|
||||
actionRequestSent?: boolean;
|
||||
completedActionDetails?: ActionDetails;
|
||||
completedActionDetails?: ActionDetails<KillProcessActionOutputContent>;
|
||||
apiError?: IHttpFetchError;
|
||||
},
|
||||
EndpointCommandDefinitionMeta
|
||||
|
@ -37,10 +41,13 @@ export const KillProcessActionResult = memo<
|
|||
|
||||
const { mutate, data, isSuccess, error } = useSendKillProcessRequest();
|
||||
|
||||
const { data: actionDetails } = useGetActionDetails(actionId ?? '-', {
|
||||
enabled: Boolean(actionId) && isPending,
|
||||
refetchInterval: isPending ? ACTION_DETAILS_REFRESH_INTERVAL : false,
|
||||
});
|
||||
const { data: actionDetails } = useGetActionDetails<KillProcessActionOutputContent>(
|
||||
actionId ?? '-',
|
||||
{
|
||||
enabled: Boolean(actionId) && isPending,
|
||||
refetchInterval: isPending ? ACTION_DETAILS_REFRESH_INTERVAL : false,
|
||||
}
|
||||
);
|
||||
|
||||
// Send Kill request if not yet done
|
||||
useEffect(() => {
|
||||
|
@ -86,11 +93,6 @@ export const KillProcessActionResult = memo<
|
|||
}
|
||||
}, [actionDetails?.data, setStatus, setStore, isPending]);
|
||||
|
||||
// Show nothing if still pending
|
||||
if (isPending) {
|
||||
return <ResultComponent showAs="pending" />;
|
||||
}
|
||||
|
||||
// Show API errors if perform action fails
|
||||
if (isError && apiError) {
|
||||
return (
|
||||
|
@ -104,18 +106,29 @@ export const KillProcessActionResult = memo<
|
|||
);
|
||||
}
|
||||
|
||||
// Show nothing if still pending
|
||||
if (isPending || !completedActionDetails) {
|
||||
return <ResultComponent showAs="pending" />;
|
||||
}
|
||||
|
||||
// Show errors
|
||||
if (completedActionDetails?.errors) {
|
||||
return (
|
||||
<ActionError
|
||||
dataTestSubj={'killProcessErrorCallout'}
|
||||
errors={completedActionDetails?.errors}
|
||||
action={completedActionDetails}
|
||||
ResultComponent={ResultComponent}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Show Success
|
||||
return <ResultComponent showAs="success" data-test-subj="killProcessSuccessCallout" />;
|
||||
return (
|
||||
<ActionSuccess
|
||||
action={completedActionDetails}
|
||||
ResultComponent={ResultComponent}
|
||||
data-test-subj="killProcessSuccessCallout"
|
||||
/>
|
||||
);
|
||||
});
|
||||
KillProcessActionResult.displayName = 'KillProcessActionResult';
|
||||
|
|
|
@ -39,7 +39,7 @@ export const ReleaseActionResult = memo<ActionRequestComponentProps>(
|
|||
return (
|
||||
<ActionError
|
||||
dataTestSubj={'releaseErrorCallout'}
|
||||
errors={completedActionDetails?.errors}
|
||||
action={completedActionDetails}
|
||||
ResultComponent={ResultComponent}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -8,7 +8,11 @@
|
|||
import React, { memo, useEffect } from 'react';
|
||||
import { FormattedMessage } from '@kbn/i18n-react';
|
||||
import type { IHttpFetchError } from '@kbn/core-http-browser';
|
||||
import type { ActionDetails } from '../../../../common/endpoint/types';
|
||||
import { ActionSuccess } from './action_success';
|
||||
import type {
|
||||
ActionDetails,
|
||||
SuspendProcessActionOutputContent,
|
||||
} from '../../../../common/endpoint/types';
|
||||
import { useGetActionDetails } from '../../hooks/endpoint/use_get_action_details';
|
||||
import type { EndpointCommandDefinitionMeta } from './types';
|
||||
import { useSendSuspendProcessRequest } from '../../hooks/endpoint/use_send_suspend_process_endpoint_request';
|
||||
|
@ -23,7 +27,7 @@ export const SuspendProcessActionResult = memo<
|
|||
{
|
||||
actionId?: string;
|
||||
actionRequestSent?: boolean;
|
||||
completedActionDetails?: ActionDetails;
|
||||
completedActionDetails?: ActionDetails<SuspendProcessActionOutputContent>;
|
||||
apiError?: IHttpFetchError;
|
||||
},
|
||||
EndpointCommandDefinitionMeta
|
||||
|
@ -37,10 +41,13 @@ export const SuspendProcessActionResult = memo<
|
|||
|
||||
const { mutate, data, isSuccess, error } = useSendSuspendProcessRequest();
|
||||
|
||||
const { data: actionDetails } = useGetActionDetails(actionId ?? '-', {
|
||||
enabled: Boolean(actionId) && isPending,
|
||||
refetchInterval: isPending ? ACTION_DETAILS_REFRESH_INTERVAL : false,
|
||||
});
|
||||
const { data: actionDetails } = useGetActionDetails<SuspendProcessActionOutputContent>(
|
||||
actionId ?? '-',
|
||||
{
|
||||
enabled: Boolean(actionId) && isPending,
|
||||
refetchInterval: isPending ? ACTION_DETAILS_REFRESH_INTERVAL : false,
|
||||
}
|
||||
);
|
||||
|
||||
// Send Suspend request if not yet done
|
||||
useEffect(() => {
|
||||
|
@ -100,7 +107,7 @@ export const SuspendProcessActionResult = memo<
|
|||
}
|
||||
|
||||
// Show nothing if still pending
|
||||
if (isPending) {
|
||||
if (isPending || !completedActionDetails) {
|
||||
return <ResultComponent showAs="pending" />;
|
||||
}
|
||||
|
||||
|
@ -109,13 +116,19 @@ export const SuspendProcessActionResult = memo<
|
|||
return (
|
||||
<ActionError
|
||||
dataTestSubj={'suspendProcessErrorCallout'}
|
||||
errors={completedActionDetails?.errors}
|
||||
action={completedActionDetails}
|
||||
ResultComponent={ResultComponent}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// Show Success
|
||||
return <ResultComponent data-test-subj="suspendProcessSuccessCallout" />;
|
||||
return (
|
||||
<ActionSuccess
|
||||
action={completedActionDetails}
|
||||
ResultComponent={ResultComponent}
|
||||
data-test-subj="suspendProcessSuccessCallout"
|
||||
/>
|
||||
);
|
||||
});
|
||||
SuspendProcessActionResult.displayName = 'SuspendProcessActionResult';
|
||||
|
|
|
@ -11,19 +11,19 @@ import { useQuery } from 'react-query';
|
|||
import { useHttp } from '../../../common/lib/kibana';
|
||||
import { resolvePathVariables } from '../../../common/utils/resolve_path_variables';
|
||||
import { ACTION_DETAILS_ROUTE } from '../../../../common/endpoint/constants';
|
||||
import type { ActionDetailsApiResponse, ProcessesEntry } from '../../../../common/endpoint/types';
|
||||
import type { ActionDetailsApiResponse } from '../../../../common/endpoint/types';
|
||||
|
||||
export const useGetActionDetails = <TOutputType extends object = object>(
|
||||
actionId: string,
|
||||
options: UseQueryOptions<ActionDetailsApiResponse<ProcessesEntry>, IHttpFetchError> = {}
|
||||
): UseQueryResult<ActionDetailsApiResponse<ProcessesEntry>, IHttpFetchError> => {
|
||||
options: UseQueryOptions<ActionDetailsApiResponse<TOutputType>, IHttpFetchError> = {}
|
||||
): UseQueryResult<ActionDetailsApiResponse<TOutputType>, IHttpFetchError> => {
|
||||
const http = useHttp();
|
||||
|
||||
return useQuery<ActionDetailsApiResponse<ProcessesEntry>, IHttpFetchError>({
|
||||
return useQuery<ActionDetailsApiResponse<TOutputType>, IHttpFetchError>({
|
||||
queryKey: ['get-action-details', actionId],
|
||||
...options,
|
||||
queryFn: () => {
|
||||
return http.get<ActionDetailsApiResponse<ProcessesEntry>>(
|
||||
return http.get<ActionDetailsApiResponse<TOutputType>>(
|
||||
resolvePathVariables(ACTION_DETAILS_ROUTE, { action_id: actionId.trim() || 'undefined' })
|
||||
);
|
||||
},
|
||||
|
|
|
@ -11,7 +11,7 @@ import type { IHttpFetchError } from '@kbn/core-http-browser';
|
|||
import type {
|
||||
ProcessesRequestBody,
|
||||
ResponseActionApiResponse,
|
||||
ProcessesEntry,
|
||||
GetProcessesActionOutputContent,
|
||||
} from '../../../../common/endpoint/types/actions';
|
||||
import { GET_PROCESSES_ROUTE } from '../../../../common/endpoint/constants';
|
||||
import { KibanaServices } from '../../../common/lib/kibana';
|
||||
|
@ -22,25 +22,24 @@ import { KibanaServices } from '../../../common/lib/kibana';
|
|||
*/
|
||||
export const useSendGetEndpointProcessesRequest = (
|
||||
customOptions?: UseMutationOptions<
|
||||
ResponseActionApiResponse<ProcessesEntry>,
|
||||
ResponseActionApiResponse<GetProcessesActionOutputContent>,
|
||||
IHttpFetchError,
|
||||
ProcessesRequestBody
|
||||
>
|
||||
): UseMutationResult<
|
||||
ResponseActionApiResponse<ProcessesEntry>,
|
||||
ResponseActionApiResponse<GetProcessesActionOutputContent>,
|
||||
IHttpFetchError,
|
||||
ProcessesRequestBody
|
||||
> => {
|
||||
return useMutation<
|
||||
ResponseActionApiResponse<ProcessesEntry>,
|
||||
ResponseActionApiResponse<GetProcessesActionOutputContent>,
|
||||
IHttpFetchError,
|
||||
ProcessesRequestBody
|
||||
>((getRunningProcessesData: ProcessesRequestBody) => {
|
||||
return KibanaServices.get().http.post<ResponseActionApiResponse<ProcessesEntry>>(
|
||||
GET_PROCESSES_ROUTE,
|
||||
{
|
||||
body: JSON.stringify(getRunningProcessesData),
|
||||
}
|
||||
);
|
||||
return KibanaServices.get().http.post<
|
||||
ResponseActionApiResponse<GetProcessesActionOutputContent>
|
||||
>(GET_PROCESSES_ROUTE, {
|
||||
body: JSON.stringify(getRunningProcessesData),
|
||||
});
|
||||
}, customOptions);
|
||||
};
|
||||
|
|
|
@ -24,8 +24,8 @@ import type {
|
|||
ActionListApiResponse,
|
||||
ResponseActionApiResponse,
|
||||
PendingActionsResponse,
|
||||
ProcessesEntry,
|
||||
ActionDetails,
|
||||
GetProcessesActionOutputContent,
|
||||
} from '../../../common/endpoint/types';
|
||||
|
||||
export type ResponseActionsHttpMocksInterface = ResponseProvidersInterface<{
|
||||
|
@ -43,7 +43,7 @@ export type ResponseActionsHttpMocksInterface = ResponseProvidersInterface<{
|
|||
|
||||
agentPendingActionsSummary: (options: HttpFetchOptionsWithPath) => PendingActionsResponse;
|
||||
|
||||
processes: () => ActionDetailsApiResponse<ProcessesEntry>;
|
||||
processes: () => ActionDetailsApiResponse<GetProcessesActionOutputContent>;
|
||||
}>;
|
||||
|
||||
export const responseActionsHttpMocks = httpHandlerMockFactory<ResponseActionsHttpMocksInterface>([
|
||||
|
@ -134,7 +134,7 @@ export const responseActionsHttpMocks = httpHandlerMockFactory<ResponseActionsHt
|
|||
id: 'processes',
|
||||
path: GET_PROCESSES_ROUTE,
|
||||
method: 'post',
|
||||
handler: (): ActionDetailsApiResponse<ProcessesEntry> => {
|
||||
handler: (): ActionDetailsApiResponse<GetProcessesActionOutputContent> => {
|
||||
const generator = new EndpointActionGenerator('seed');
|
||||
const response = generator.generateActionDetails({
|
||||
outputs: {
|
||||
|
@ -145,7 +145,7 @@ export const responseActionsHttpMocks = httpHandlerMockFactory<ResponseActionsHt
|
|||
},
|
||||
},
|
||||
},
|
||||
}) as ActionDetails<ProcessesEntry>;
|
||||
}) as ActionDetails<GetProcessesActionOutputContent>;
|
||||
|
||||
return { data: response };
|
||||
},
|
||||
|
|
|
@ -21,7 +21,7 @@ import type {
|
|||
EndpointActionResponse,
|
||||
LogsEndpointActionResponse,
|
||||
ActionResponseOutput,
|
||||
ProcessesEntry,
|
||||
GetProcessesActionOutputContent,
|
||||
} from '../../../common/endpoint/types';
|
||||
import type { EndpointActionListRequestQuery } from '../../../common/endpoint/schema/actions';
|
||||
import { EndpointActionGenerator } from '../../../common/endpoint/data_generators/endpoint_action_generator';
|
||||
|
@ -158,6 +158,6 @@ const getOutputDataIfNeeded = (
|
|||
entries: endpointActionGenerator.randomResponseActionProcesses(100),
|
||||
},
|
||||
},
|
||||
} as { output: ActionResponseOutput<ProcessesEntry> })
|
||||
} as { output: ActionResponseOutput<GetProcessesActionOutputContent> })
|
||||
: {};
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue