Skip to content

Commit

Permalink
[Security Solution][Endpoint] Generic hook to handle Response Actions…
Browse files Browse the repository at this point in the history
… API interactions (#141224)

- New general hook (`useConsoleActionSubmitter()`) for handling response console commands that need to generate an endpoint response action
- Refactored all Response Actions to use new hook
- Fixed bug in `useIsMounted()` hook
  • Loading branch information
paul-tavares authored Sep 27, 2022
1 parent 7af3f39 commit 504d8c4
Show file tree
Hide file tree
Showing 32 changed files with 806 additions and 672 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ export const NoParametersRequestSchema = {
body: schema.object({ ...BaseActionRequestSchema }),
};

export type BaseActionRequestBody = TypeOf<typeof NoParametersRequestSchema.body>;

export const KillOrSuspendProcessRequestSchema = {
body: schema.object({
...BaseActionRequestSchema,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ export interface PendingActionsResponse {
}

export type PendingActionsRequestQuery = TypeOf<typeof ActionStatusRequestSchema.query>;

export interface ActionDetails<TOutputContent extends object = object> {
/** The action id */
id: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { act, fireEvent, waitFor, waitForElementToBeRemoved } from '@testing-lib
import userEvent from '@testing-library/user-event';
import type { ArtifactListPageRenderingSetup } from './mocks';
import { getArtifactListPageRenderingSetup } from './mocks';
import { getDeferred } from '../mocks';
import { getDeferred } from '../../mocks/utils';

jest.mock('../../../common/components/user_privileges');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-t
import { EuiButton, EuiSpacer, EuiText } from '@elastic/eui';
import type { EuiFlyoutSize } from '@elastic/eui/src/components/flyout/flyout';
import { useLocation } from 'react-router-dom';
import { useIsMounted } from '@kbn/securitysolution-hook-utils';
import type { ServerApiError } from '../../../common/types';
import { AdministrationListPage } from '../administration_list_page';

Expand Down Expand Up @@ -45,7 +46,6 @@ import { useToasts } from '../../../common/lib/kibana';
import { useMemoizedRouteState } from '../../common/hooks';
import { BackToExternalAppSecondaryButton } from '../back_to_external_app_secondary_button';
import { BackToExternalAppButton } from '../back_to_external_app_button';
import { useIsMounted } from '../../hooks/use_is_mounted';

type ArtifactEntryCardType = typeof ArtifactEntryCard;

Expand Down Expand Up @@ -221,7 +221,7 @@ export const ArtifactListPage = memo<ArtifactListPageProps>(
);

const handleArtifactDeleteModalOnSuccess = useCallback(() => {
if (isMounted) {
if (isMounted()) {
setSelectedItemForDelete(undefined);
refetchListData();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type { ArtifactListPageRenderingSetup } from '../mocks';
import { getArtifactListPageRenderingSetup } from '../mocks';
import { act, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { getDeferred } from '../../mocks';
import { getDeferred } from '../../../mocks/utils';

describe('When displaying the Delete artifact modal in the Artifact List Page', () => {
let renderResult: ReturnType<AppContextTestRender['render']>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import type { trustedAppsAllHttpMocks } from '../../../mocks';
import { useUserPrivileges as _useUserPrivileges } from '../../../../common/components/user_privileges';
import { entriesToConditionEntries } from '../../../../common/utils/exception_list_items/mappers';
import type { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types';
import { getDeferred } from '../../mocks';
import { getDeferred } from '../../../mocks/utils';

jest.mock('../../../../common/components/user_privileges');
const useUserPrivileges = _useUserPrivileges as jest.Mock;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {

import type { EuiFlyoutSize } from '@elastic/eui/src/components/flyout/flyout';
import type { IHttpFetchError } from '@kbn/core-http-browser';
import { useIsMounted } from '@kbn/securitysolution-hook-utils';
import { useUrlParams } from '../../../hooks/use_url_params';
import { useIsFlyoutOpened } from '../hooks/use_is_flyout_opened';
import { useTestIdGenerator } from '../../../hooks/use_test_id_generator';
Expand All @@ -39,7 +40,6 @@ import { useKibana, useToasts } from '../../../../common/lib/kibana';
import { createExceptionListItemForCreate } from '../../../../../common/endpoint/service/artifacts/utils';
import { useWithArtifactSubmitData } from '../hooks/use_with_artifact_submit_data';
import { useIsArtifactAllowedPerPolicyUsage } from '../hooks/use_is_artifact_allowed_per_policy_usage';
import { useIsMounted } from '../../../hooks/use_is_mounted';
import { useGetArtifact } from '../../../hooks/artifacts';
import type { PolicyData } from '../../../../../common/endpoint/types';

Expand Down Expand Up @@ -271,7 +271,7 @@ export const ArtifactFlyout = memo<ArtifactFlyoutProps>(

const handleFormComponentOnChange: ArtifactFormComponentProps['onChange'] = useCallback(
({ item: updatedItem, isValid }) => {
if (isMounted) {
if (isMounted()) {
setFormState({
item: updatedItem,
isValid,
Expand All @@ -289,7 +289,7 @@ export const ArtifactFlyout = memo<ArtifactFlyoutProps>(
: labels.flyoutCreateSubmitSuccess(result)
);

if (isMounted) {
if (isMounted()) {
// Close the flyout
// `undefined` will cause params to be dropped from url
setUrlParams({ ...urlParams, itemId: undefined, show: undefined }, true);
Expand All @@ -307,12 +307,12 @@ export const ArtifactFlyout = memo<ArtifactFlyoutProps>(
submitHandler(formState.item, formMode)
.then(handleSuccess)
.catch((submitHandlerError) => {
if (isMounted) {
if (isMounted()) {
setExternalSubmitHandlerError(submitHandlerError);
}
})
.finally(() => {
if (isMounted) {
if (isMounted()) {
setExternalIsSubmittingData(false);
}
});
Expand All @@ -326,7 +326,7 @@ export const ArtifactFlyout = memo<ArtifactFlyoutProps>(
useEffect(() => {
if (isEditFlow && !hasItemDataForEdit && !error && isInitializing && !isLoadingItemForEdit) {
fetchItemForEdit().then(({ data: editItemData }) => {
if (editItemData && isMounted) {
if (editItemData && isMounted()) {
setFormState(createFormInitialState(apiClient.listId, editItemData));
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import { useEffect, useMemo, useState } from 'react';
import type { Pagination } from '@elastic/eui';
import { useQuery } from '@tanstack/react-query';
import { useIsMounted } from '@kbn/securitysolution-hook-utils';
import type { ServerApiError } from '../../../../common/types';
import { useIsMounted } from '../../../hooks/use_is_mounted';
import { MANAGEMENT_PAGE_SIZE_OPTIONS } from '../../../common/constants';
import { useUrlParams } from '../../../hooks/use_url_params';
import type { ExceptionsListApiClient } from '../../../services/exceptions_list/exceptions_list_api_client';
Expand Down Expand Up @@ -98,7 +98,7 @@ export const useWithArtifactListData = (
// Once we know if data exists, update the page initializing state.
// This should only ever happen at most once;
useEffect(() => {
if (isMounted) {
if (isMounted()) {
if (isPageInitializing && !isLoadingDataExists) {
setIsPageInitializing(false);
}
Expand All @@ -107,7 +107,7 @@ export const useWithArtifactListData = (

// Update the uiPagination once the query succeeds
useEffect(() => {
if (isMounted && listData && !isLoadingListData && isSuccessListData) {
if (isMounted() && listData && !isLoadingListData && isSuccessListData) {
setUiPagination((prevState) => {
return {
...prevState,
Expand All @@ -134,7 +134,7 @@ export const useWithArtifactListData = (
// >> Check if data exists again (which should return true
useEffect(() => {
if (
isMounted &&
isMounted() &&
!isLoadingListData &&
!isLoadingDataExists &&
!listDataError &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ export type CommandExecutionComponent<
/** The arguments that could have been entered by the user */
TArgs extends SupportedArguments = any,
/** Internal store for the Command execution */
TStore extends object = Record<string, unknown>,
TStore extends object = any,
/** The metadata defined on the Command Definition */
TMeta = any
> = ComponentType<CommandExecutionComponentProps<TArgs, TStore, TMeta>>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ describe('When using processes action from response actions console', () => {
enterConsoleCommand(renderResult, 'processes');

await waitFor(() => {
expect(renderResult.getByTestId('getProcessesErrorCallout').textContent).toMatch(
expect(renderResult.getByTestId('getProcesses-actionFailure').textContent).toMatch(
/error one \| error two/
);
});
Expand All @@ -145,7 +145,7 @@ describe('When using processes action from response actions console', () => {
enterConsoleCommand(renderResult, 'processes');

await waitFor(() => {
expect(renderResult.getByTestId('performGetProcessesErrorCallout').textContent).toMatch(
expect(renderResult.getByTestId('getProcesses-apiFailure').textContent).toMatch(
/this is an error/
);
});
Expand Down
Loading

0 comments on commit 504d8c4

Please sign in to comment.