From 2abbd808c743f797363fb1f1d44912d7f376b437 Mon Sep 17 00:00:00 2001 From: Frank Hassanabad Date: Sun, 17 Jan 2021 09:18:34 -0700 Subject: [PATCH] [Security Solutions][Detection Engine] Removes duplicate API calls (#88420) ## Summary This removes some duplicate API calls to reduce pressure on the backend and speed up querying times within the application for the front end. This fixes some of the issues of https://github.com/elastic/kibana/issues/82327, but there are several performance improvements that are going to be needed to help reduce the slowness when you have a system under a lot of pressure. So far this removes duplication for these API calls when you are on the manage detection rules page: ```ts api/detection_engine/rules/_find api/detection_engine/rules/_find_statuses api/detection_engine/tags ``` Screen Shot 2021-01-14 at 3 53 21 PM * This hides the tags and searches while the page is loading to avoid duplicate calls when the pre-packaged rules counts come back * This untangles the refetchRules from the refetchPrePackagedRulesStatus as two separate calls to avoid issues we have with re-rendering and re-calling the backend. ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios --- .../detection_engine/alerts/use_query.tsx | 2 +- .../alerts/use_signal_index.tsx | 2 +- .../containers/detection_engine/rules/api.ts | 6 +- .../detection_engine/rules/types.ts | 6 +- .../rules/use_pre_packaged_rules.tsx | 2 +- .../rules/use_rule_status.tsx | 4 +- .../detection_engine/rules/use_rules.test.tsx | 15 +++++ .../detection_engine/rules/use_rules.tsx | 25 ++------ .../rules/all/batch_actions.tsx | 14 +++-- .../rules/all/columns.test.tsx | 3 + .../detection_engine/rules/all/columns.tsx | 14 +++-- .../rules/all/exceptions/exceptions_table.tsx | 2 +- .../detection_engine/rules/all/index.tsx | 4 +- .../rules/all/reducer.test.ts | 6 ++ .../rules/all/rules_tables.tsx | 61 +++++++++++-------- .../pages/detection_engine/rules/index.tsx | 10 +-- 16 files changed, 105 insertions(+), 71 deletions(-) diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_query.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_query.tsx index 9c992fa87270..3bef1d8edd04 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_query.tsx +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_query.tsx @@ -9,7 +9,7 @@ import React, { SetStateAction, useEffect, useState } from 'react'; import { fetchQueryAlerts } from './api'; import { AlertSearchResponse } from './types'; -type Func = () => void; +type Func = () => Promise; export interface ReturnQueryAlerts { loading: boolean; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_signal_index.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_signal_index.tsx index 1233456359b7..5ebdb38b8dd5 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_signal_index.tsx +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/alerts/use_signal_index.tsx @@ -11,7 +11,7 @@ import { createSignalIndex, getSignalIndex } from './api'; import * as i18n from './translations'; import { isSecurityAppError } from '../../../../common/utils/api'; -type Func = () => void; +type Func = () => Promise; export interface ReturnSignalIndex { loading: boolean; diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts index da33b7841c7a..f602a0a9523c 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/api.ts @@ -120,9 +120,9 @@ export const fetchRules = async ({ ...showElasticRuleFilter, ].join(' AND '); - const tags = [ - ...(filterOptions.tags?.map((t) => `alert.attributes.tags: "${t.replace(/"/g, '\\"')}"`) ?? []), - ].join(' AND '); + const tags = filterOptions.tags + .map((t) => `alert.attributes.tags: "${t.replace(/"/g, '\\"')}"`) + .join(' AND '); const filterString = filtersWithoutTags !== '' && tags !== '' diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts index b930212610ae..6eefa7f732be 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/types.ts @@ -177,9 +177,9 @@ export interface FilterOptions { filter: string; sortField: RulesSortingFields; sortOrder: SortOrder; - showCustomRules?: boolean; - showElasticRules?: boolean; - tags?: string[]; + showCustomRules: boolean; + showElasticRules: boolean; + tags: string[]; } export interface FetchRulesResponse { diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules.tsx index 48530ddeb181..d83d4e0caa97 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules.tsx +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_pre_packaged_rules.tsx @@ -20,7 +20,7 @@ import { getPrePackagedTimelineStatus, } from '../../../pages/detection_engine/rules/helpers'; -type Func = () => void; +type Func = () => Promise; export type CreatePreBuiltRules = () => Promise; interface ReturnPrePackagedTimelines { diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_status.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_status.tsx index 0e96f58ee687..ddf50e9edae5 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_status.tsx +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rule_status.tsx @@ -113,9 +113,11 @@ export const useRulesStatuses = (rules: Rules): ReturnRulesStatuses => { setLoading(false); } }; - if (rules != null && rules.length > 0) { + + if (rules.length > 0) { fetchData(rules.map((r) => r.id)); } + return () => { isSubscribed = false; abortCtrl.abort(); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rules.test.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rules.test.tsx index 76f2a5b58754..a874acf36c52 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rules.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rules.test.tsx @@ -27,6 +27,9 @@ describe('useRules', () => { filter: '', sortField: 'created_at', sortOrder: 'desc', + tags: [], + showCustomRules: false, + showElasticRules: false, }, }) ); @@ -48,6 +51,9 @@ describe('useRules', () => { filter: '', sortField: 'created_at', sortOrder: 'desc', + tags: [], + showCustomRules: false, + showElasticRules: false, }, }) ); @@ -153,6 +159,9 @@ describe('useRules', () => { filter: '', sortField: 'created_at', sortOrder: 'desc', + tags: [], + showCustomRules: false, + showElasticRules: false, }, }) ); @@ -182,6 +191,9 @@ describe('useRules', () => { filter: '', sortField: 'created_at', sortOrder: 'desc', + tags: [], + showCustomRules: false, + showElasticRules: false, }, }, } @@ -198,6 +210,9 @@ describe('useRules', () => { filter: 'hello world', sortField: 'created_at', sortOrder: 'desc', + tags: [], + showCustomRules: false, + showElasticRules: false, }, }); await waitForNextUpdate(); diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rules.tsx b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rules.tsx index 2ada6d8426ce..9b4a5ce8c23c 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rules.tsx +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/use_rules.tsx @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { noop } from 'lodash/fp'; import { useEffect, useState, useRef } from 'react'; import { FetchRulesResponse, FilterOptions, PaginationOptions, Rule } from './types'; @@ -12,16 +11,11 @@ import { errorToToaster, useStateToaster } from '../../../../common/components/t import { fetchRules } from './api'; import * as i18n from './translations'; -export type ReturnRules = [ - boolean, - FetchRulesResponse | null, - (refreshPrePackagedRule?: boolean) => void -]; +export type ReturnRules = [boolean, FetchRulesResponse | null, () => Promise]; export interface UseRules { pagination: PaginationOptions; filterOptions: FilterOptions; - refetchPrePackagedRulesStatus?: () => void; dispatchRulesInReducer?: (rules: Rule[], pagination: Partial) => void; } @@ -34,20 +28,19 @@ export interface UseRules { export const useRules = ({ pagination, filterOptions, - refetchPrePackagedRulesStatus, dispatchRulesInReducer, }: UseRules): ReturnRules => { const [rules, setRules] = useState(null); - const reFetchRules = useRef<(refreshPrePackagedRule?: boolean) => void>(noop); + const reFetchRules = useRef<() => Promise>(() => Promise.resolve()); const [loading, setLoading] = useState(true); const [, dispatchToaster] = useStateToaster(); - const filterTags = filterOptions.tags?.sort().join(); + const filterTags = filterOptions.tags.sort().join(); useEffect(() => { let isSubscribed = true; const abortCtrl = new AbortController(); - async function fetchData() { + const fetchData = async () => { try { setLoading(true); const fetchRulesResult = await fetchRules({ @@ -77,15 +70,10 @@ export const useRules = ({ if (isSubscribed) { setLoading(false); } - } + }; fetchData(); - reFetchRules.current = (refreshPrePackagedRule: boolean = false) => { - fetchData(); - if (refreshPrePackagedRule && refetchPrePackagedRulesStatus != null) { - refetchPrePackagedRulesStatus(); - } - }; + reFetchRules.current = (): Promise => fetchData(); return () => { isSubscribed = false; abortCtrl.abort(); @@ -100,7 +88,6 @@ export const useRules = ({ filterTags, filterOptions.showCustomRules, filterOptions.showElasticRules, - refetchPrePackagedRulesStatus, ]); return [loading, rules, reFetchRules.current]; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/batch_actions.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/batch_actions.tsx index f911fbddd81c..1ed534069470 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/batch_actions.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/batch_actions.tsx @@ -27,7 +27,8 @@ interface GetBatchItems { hasMlPermissions: boolean; hasActionsPrivileges: boolean; loadingRuleIds: string[]; - reFetchRules: (refreshPrePackagedRule?: boolean) => void; + reFetchRules: () => Promise; + refetchPrePackagedRulesStatus: () => Promise; rules: Rule[]; selectedRuleIds: string[]; } @@ -39,17 +40,18 @@ export const getBatchItems = ({ hasMlPermissions, loadingRuleIds, reFetchRules, + refetchPrePackagedRulesStatus, rules, selectedRuleIds, hasActionsPrivileges, }: GetBatchItems) => { - const selectedRules = selectedRuleIds.reduce((acc, id) => { + const selectedRules = selectedRuleIds.reduce>((acc, id) => { const found = rules.find((r) => r.id === id); if (found != null) { return { [id]: found, ...acc }; } return acc; - }, {} as Record); + }, {}); const containsEnabled = selectedRuleIds.some((id) => selectedRules[id]?.enabled ?? false); const containsDisabled = selectedRuleIds.some((id) => !selectedRules[id]?.enabled ?? false); @@ -139,7 +141,8 @@ export const getBatchItems = ({ dispatch, dispatchToaster ); - reFetchRules(true); + await reFetchRules(); + await refetchPrePackagedRulesStatus(); }} > { closePopover(); await deleteRulesAction(selectedRuleIds, dispatch, dispatchToaster); - reFetchRules(true); + await reFetchRules(); + await refetchPrePackagedRulesStatus(); }} > {i18n.BATCH_ACTION_DELETE_SELECTED} diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.test.tsx index 564b382b7b29..c48ba49e8db2 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.test.tsx @@ -27,6 +27,7 @@ describe('AllRulesTable Columns', () => { const dispatch = jest.fn(); const dispatchToaster = jest.fn(); const reFetchRules = jest.fn(); + const refetchPrePackagedRulesStatus = jest.fn(); beforeEach(() => { results = []; @@ -53,6 +54,7 @@ describe('AllRulesTable Columns', () => { dispatchToaster, history, reFetchRules, + refetchPrePackagedRulesStatus, true )[1]; await duplicateRulesActionObject.onClick(rule); @@ -75,6 +77,7 @@ describe('AllRulesTable Columns', () => { dispatchToaster, history, reFetchRules, + refetchPrePackagedRulesStatus, true )[3]; await deleteRulesActionObject.onClick(rule); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.tsx index 2b03d6dd4de3..0d585b446381 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/columns.tsx @@ -43,7 +43,8 @@ export const getActions = ( dispatch: React.Dispatch, dispatchToaster: Dispatch, history: H.History, - reFetchRules: (refreshPrePackagedRule?: boolean) => void, + reFetchRules: () => Promise, + refetchPrePackagedRulesStatus: () => Promise, actionsPrivileges: | boolean | Readonly<{ @@ -77,7 +78,8 @@ export const getActions = ( enabled: (rowItem: Rule) => canEditRuleWithActions(rowItem, actionsPrivileges), onClick: async (rowItem: Rule) => { await duplicateRulesAction([rowItem], [rowItem.id], dispatch, dispatchToaster); - await reFetchRules(true); + await reFetchRules(); + await refetchPrePackagedRulesStatus(); }, }, { @@ -95,7 +97,8 @@ export const getActions = ( name: i18n.DELETE_RULE, onClick: async (rowItem: Rule) => { await deleteRulesAction([rowItem.id], dispatch, dispatchToaster); - await reFetchRules(true); + await reFetchRules(); + await refetchPrePackagedRulesStatus(); }, }, ]; @@ -115,7 +118,8 @@ interface GetColumns { hasMlPermissions: boolean; hasNoPermissions: boolean; loadingRuleIds: string[]; - reFetchRules: (refreshPrePackagedRule?: boolean) => void; + reFetchRules: () => Promise; + refetchPrePackagedRulesStatus: () => Promise; hasReadActionsPrivileges: | boolean | Readonly<{ @@ -132,6 +136,7 @@ export const getColumns = ({ hasNoPermissions, loadingRuleIds, reFetchRules, + refetchPrePackagedRulesStatus, hasReadActionsPrivileges, }: GetColumns): RulesColumns[] => { const cols: RulesColumns[] = [ @@ -279,6 +284,7 @@ export const getColumns = ({ dispatchToaster, history, reFetchRules, + refetchPrePackagedRulesStatus, hasReadActionsPrivileges ), width: '40px', diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.tsx index ccd00daf5e5a..cc04c205abce 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/exceptions/exceptions_table.tsx @@ -36,7 +36,7 @@ import { patchRule } from '../../../../../containers/detection_engine/rules/api' // eslint-disable-next-line @typescript-eslint/no-explicit-any const MyEuiBasicTable = styled(EuiBasicTable as any)`` as any; -export type Func = () => void; +export type Func = () => Promise; export interface ExceptionListFilter { name?: string | null; list_id?: string | null; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.tsx index 4c4095ee6f74..381f104855bf 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/index.tsx @@ -20,12 +20,12 @@ interface AllRulesProps { hasNoPermissions: boolean; loading: boolean; loadingCreatePrePackagedRules: boolean; - refetchPrePackagedRulesStatus: () => void; + refetchPrePackagedRulesStatus: () => Promise; rulesCustomInstalled: number | null; rulesInstalled: number | null; rulesNotInstalled: number | null; rulesNotUpdated: number | null; - setRefreshRulesData: (refreshRule: (refreshPrePackagedRule?: boolean) => void) => void; + setRefreshRulesData: (refreshRule: () => Promise) => void; } export enum AllRulesTabs { diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/reducer.test.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/reducer.test.ts index 0456111074b6..7501f4377740 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/reducer.test.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/reducer.test.ts @@ -14,6 +14,9 @@ const initialState: State = { filter: '', sortField: 'enabled', sortOrder: 'desc', + tags: [], + showCustomRules: false, + showElasticRules: false, }, loadingRuleIds: [], loadingRulesAction: null, @@ -193,6 +196,9 @@ describe('allRulesReducer', () => { filter: 'host.name:*', sortField: 'enabled', sortOrder: 'desc', + tags: [], + showCustomRules: false, + showElasticRules: false, }; const { filterOptions, pagination } = reducer(initialState, { type: 'updateFilterOptions', diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx index 232fb118fb2f..2ae124dc8610 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/all/rules_tables.tsx @@ -60,6 +60,9 @@ const initialState: State = { filter: '', sortField: INITIAL_SORT_FIELD, sortOrder: 'desc', + tags: [], + showCustomRules: false, + showElasticRules: false, }, loadingRuleIds: [], loadingRulesAction: null, @@ -82,12 +85,12 @@ interface RulesTableProps { hasNoPermissions: boolean; loading: boolean; loadingCreatePrePackagedRules: boolean; - refetchPrePackagedRulesStatus: () => void; + refetchPrePackagedRulesStatus: () => Promise; rulesCustomInstalled: number | null; rulesInstalled: number | null; rulesNotInstalled: number | null; rulesNotUpdated: number | null; - setRefreshRulesData: (refreshRule: (refreshPrePackagedRule?: boolean) => void) => void; + setRefreshRulesData: (refreshRule: () => Promise) => void; selectedTab: AllRulesTabs; } @@ -183,10 +186,9 @@ export const RulesTables = React.memo( }); }, []); - const [isLoadingRules, , reFetchRulesData] = useRules({ + const [isLoadingRules, , reFetchRules] = useRules({ pagination, filterOptions, - refetchPrePackagedRulesStatus, dispatchRulesInReducer: setRules, }); @@ -220,7 +222,8 @@ export const RulesTables = React.memo( hasActionsPrivileges, loadingRuleIds, selectedRuleIds, - reFetchRules: reFetchRulesData, + reFetchRules, + refetchPrePackagedRulesStatus, rules, }); }, @@ -229,7 +232,8 @@ export const RulesTables = React.memo( dispatchToaster, hasMlPermissions, loadingRuleIds, - reFetchRulesData, + reFetchRules, + refetchPrePackagedRulesStatus, rules, selectedRuleIds, hasActionsPrivileges, @@ -273,19 +277,22 @@ export const RulesTables = React.memo( (loadingRulesAction === 'enable' || loadingRulesAction === 'disable') ? loadingRuleIds : [], - reFetchRules: reFetchRulesData, + reFetchRules, + refetchPrePackagedRulesStatus, hasReadActionsPrivileges: hasActionsPrivileges, }); - // eslint-disable-next-line react-hooks/exhaustive-deps }, [ dispatch, dispatchToaster, formatUrl, + refetchPrePackagedRulesStatus, + hasActionsPrivileges, + hasNoPermissions, hasMlPermissions, history, loadingRuleIds, loadingRulesAction, - reFetchRulesData, + reFetchRules, ]); const monitoringColumns = useMemo(() => getMonitoringColumns(history, formatUrl), [ @@ -294,10 +301,8 @@ export const RulesTables = React.memo( ]); useEffect(() => { - if (reFetchRulesData != null) { - setRefreshRulesData(reFetchRulesData); - } - }, [reFetchRulesData, setRefreshRulesData]); + setRefreshRulesData(reFetchRules); + }, [reFetchRules, setRefreshRulesData]); useEffect(() => { if (initLoading && !loading && !isLoadingRules && !isLoadingRulesStatuses) { @@ -306,11 +311,12 @@ export const RulesTables = React.memo( }, [initLoading, loading, isLoadingRules, isLoadingRulesStatuses]); const handleCreatePrePackagedRules = useCallback(async () => { - if (createPrePackagedRules != null && reFetchRulesData != null) { + if (createPrePackagedRules != null) { await createPrePackagedRules(); - reFetchRulesData(true); + await reFetchRules(); + await refetchPrePackagedRulesStatus(); } - }, [createPrePackagedRules, reFetchRulesData]); + }, [createPrePackagedRules, reFetchRules, refetchPrePackagedRulesStatus]); const euiBasicTableSelectionProps = useMemo( () => ({ @@ -343,12 +349,13 @@ export const RulesTables = React.memo( return false; }, [loadingRuleIds, loadingRulesAction]); - const handleRefreshData = useCallback((): void => { - if (reFetchRulesData != null && !isLoadingAnActionOnRule) { - reFetchRulesData(true); + const handleRefreshData = useCallback(async (): Promise => { + if (!isLoadingAnActionOnRule) { + await reFetchRules(); + await refetchPrePackagedRulesStatus(); setLastRefreshDate(); } - }, [reFetchRulesData, isLoadingAnActionOnRule, setLastRefreshDate]); + }, [reFetchRules, isLoadingAnActionOnRule, setLastRefreshDate, refetchPrePackagedRulesStatus]); const handleResetIdleTimer = useCallback((): void => { if (isRefreshOn) { @@ -458,12 +465,14 @@ export const RulesTables = React.memo( /> } > - + {shouldShowRulesTable && ( + + )} {isLoadingAnActionOnRule && !initLoading && ( diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/index.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/index.tsx index dc2e99b90da4..9423604e546e 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/index.tsx @@ -35,7 +35,7 @@ import { SecurityPageName } from '../../../../app/types'; import { LinkButton } from '../../../../common/components/links'; import { useFormatUrl } from '../../../../common/components/link_to'; -type Func = (refreshPrePackagedRule?: boolean) => void; +type Func = () => Promise; const RulesPageComponent: React.FC = () => { const history = useHistory(); @@ -94,20 +94,22 @@ const RulesPageComponent: React.FC = () => { const handleRefreshRules = useCallback(async () => { if (refreshRulesData.current != null) { - refreshRulesData.current(true); + await refreshRulesData.current(); } }, [refreshRulesData]); const handleCreatePrePackagedRules = useCallback(async () => { if (createPrePackagedRules != null) { await createPrePackagedRules(); - handleRefreshRules(); + return handleRefreshRules(); } }, [createPrePackagedRules, handleRefreshRules]); const handleRefetchPrePackagedRulesStatus = useCallback(() => { if (refetchPrePackagedRulesStatus != null) { - refetchPrePackagedRulesStatus(); + return refetchPrePackagedRulesStatus(); + } else { + return Promise.resolve(); } }, [refetchPrePackagedRulesStatus]);