From 6d87f12f63490693f726368f4331457dea90c1fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20S=C3=A1nchez?= Date: Mon, 14 Mar 2022 16:28:32 +0100 Subject: [PATCH] [Security Solution] [Endpoint] Add blocklist tab in policy view (#127458) * Adds blocklists tab in policy detail view * Fixes wrong .id on normalize function Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../public/management/common/constants.ts | 1 + .../public/management/common/routing.ts | 47 ++++++ .../management/pages/blocklist/constants.ts | 9 ++ .../public/management/pages/policy/index.tsx | 2 + .../selectors/policy_common_selectors.ts | 14 ++ .../selectors/policy_settings_selectors.ts | 6 +- .../pages/policy/view/policy_hooks.ts | 7 + .../view/tabs/blocklists_translations.ts | 153 ++++++++++++++++++ .../pages/policy/view/tabs/policy_tabs.tsx | 58 ++++++- 9 files changed, 295 insertions(+), 2 deletions(-) create mode 100644 x-pack/plugins/security_solution/public/management/pages/policy/view/tabs/blocklists_translations.ts diff --git a/x-pack/plugins/security_solution/public/management/common/constants.ts b/x-pack/plugins/security_solution/public/management/common/constants.ts index dd3db8f3352a7..ea38414b0cb96 100644 --- a/x-pack/plugins/security_solution/public/management/common/constants.ts +++ b/x-pack/plugins/security_solution/public/management/common/constants.ts @@ -15,6 +15,7 @@ export const MANAGEMENT_ROUTING_POLICY_DETAILS_FORM_PATH = `${MANAGEMENT_PATH}/: export const MANAGEMENT_ROUTING_POLICY_DETAILS_TRUSTED_APPS_PATH = `${MANAGEMENT_PATH}/:tabName(${AdministrationSubTab.policies})/:policyId/trustedApps`; export const MANAGEMENT_ROUTING_POLICY_DETAILS_EVENT_FILTERS_PATH = `${MANAGEMENT_PATH}/:tabName(${AdministrationSubTab.policies})/:policyId/eventFilters`; export const MANAGEMENT_ROUTING_POLICY_DETAILS_HOST_ISOLATION_EXCEPTIONS_PATH = `${MANAGEMENT_PATH}/:tabName(${AdministrationSubTab.policies})/:policyId/hostIsolationExceptions`; +export const MANAGEMENT_ROUTING_POLICY_DETAILS_BLOCKLISTS_PATH = `${MANAGEMENT_PATH}/:tabName(${AdministrationSubTab.policies})/:policyId/blocklists`; /** @deprecated use the paths defined above instead */ export const MANAGEMENT_ROUTING_POLICY_DETAILS_PATH_OLD = `${MANAGEMENT_PATH}/:tabName(${AdministrationSubTab.policies})/:policyId`; export const MANAGEMENT_ROUTING_TRUSTED_APPS_PATH = `${MANAGEMENT_PATH}/:tabName(${AdministrationSubTab.trustedApps})`; diff --git a/x-pack/plugins/security_solution/public/management/common/routing.ts b/x-pack/plugins/security_solution/public/management/common/routing.ts index 2f5dbc762b5d7..d031e50152a66 100644 --- a/x-pack/plugins/security_solution/public/management/common/routing.ts +++ b/x-pack/plugins/security_solution/public/management/common/routing.ts @@ -10,6 +10,7 @@ import { isEmpty } from 'lodash/fp'; import querystring from 'querystring'; import { generatePath } from 'react-router-dom'; import { appendSearch } from '../../common/components/link_to/helpers'; +import { ArtifactListPageUrlParams } from '../components/artifact_list_page'; import { EndpointIndexUIQueryParams } from '../pages/endpoint_hosts/types'; import { EventFiltersPageLocation } from '../pages/event_filters/types'; import { HostIsolationExceptionsPageLocation } from '../pages/host_isolation_exceptions/types'; @@ -29,6 +30,8 @@ import { MANAGEMENT_ROUTING_POLICY_DETAILS_TRUSTED_APPS_PATH, MANAGEMENT_ROUTING_POLICY_DETAILS_EVENT_FILTERS_PATH, MANAGEMENT_ROUTING_TRUSTED_APPS_PATH, + MANAGEMENT_ROUTING_BLOCKLIST_PATH, + MANAGEMENT_ROUTING_POLICY_DETAILS_BLOCKLISTS_PATH, } from './constants'; // Taken from: https://github.com/microsoft/TypeScript/issues/12936#issuecomment-559034150 @@ -215,6 +218,29 @@ const normalizeEventFiltersPageLocation = ( } }; +const normalizBlocklistsPageLocation = ( + location?: Partial +): Partial => { + if (location) { + return { + ...(!isDefaultOrMissing(location.page, MANAGEMENT_DEFAULT_PAGE) + ? { page: location.page } + : {}), + ...(!isDefaultOrMissing(location.pageSize, MANAGEMENT_DEFAULT_PAGE_SIZE) + ? { pageSize: location.pageSize } + : {}), + ...(!isDefaultOrMissing(location.show, undefined) ? { show: location.show } : {}), + ...(!isDefaultOrMissing(location.itemId, undefined) ? { id: location.itemId } : {}), + ...(!isDefaultOrMissing(location.filter, '') ? { filter: location.filter } : ''), + ...(!isDefaultOrMissing(location.includedPolicies, '') + ? { includedPolicies: location.includedPolicies } + : ''), + }; + } else { + return {}; + } +}; + const normalizeHostIsolationExceptionsPageLocation = ( location?: Partial ): Partial => { @@ -407,3 +433,24 @@ export const getPolicyHostIsolationExceptionsPath = ( querystring.stringify(normalizePolicyDetailsArtifactsListPageLocation(location)) )}`; }; + +export const getBlocklistsListPath = (location?: Partial): string => { + const path = generatePath(MANAGEMENT_ROUTING_BLOCKLIST_PATH, { + tabName: AdministrationSubTab.blocklist, + }); + + return `${path}${appendSearch(querystring.stringify(normalizBlocklistsPageLocation(location)))}`; +}; + +export const getPolicyBlocklistsPath = ( + policyId: string, + location?: Partial +) => { + const path = generatePath(MANAGEMENT_ROUTING_POLICY_DETAILS_BLOCKLISTS_PATH, { + tabName: AdministrationSubTab.policies, + policyId, + }); + return `${path}${appendSearch( + querystring.stringify(normalizePolicyDetailsArtifactsListPageLocation(location)) + )}`; +}; diff --git a/x-pack/plugins/security_solution/public/management/pages/blocklist/constants.ts b/x-pack/plugins/security_solution/public/management/pages/blocklist/constants.ts index 3fb68e4171597..0ecdeae1fe6e2 100644 --- a/x-pack/plugins/security_solution/public/management/pages/blocklist/constants.ts +++ b/x-pack/plugins/security_solution/public/management/pages/blocklist/constants.ts @@ -24,3 +24,12 @@ export const BLOCKLISTS_LIST_DEFINITION: CreateExceptionListSchema = { list_id: ENDPOINT_BLOCKLISTS_LIST_ID, type: BLOCKLISTS_LIST_TYPE, }; + +export const SEARCHABLE_FIELDS: Readonly = [ + `name`, + `description`, + 'item_id', + `entries.value`, + `entries.entries.value`, + `comments.comment`, +]; diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/index.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/index.tsx index 48356808a5043..e6680af5c7daf 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/index.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/index.tsx @@ -15,6 +15,7 @@ import { MANAGEMENT_ROUTING_POLICY_DETAILS_PATH_OLD, MANAGEMENT_ROUTING_POLICY_DETAILS_HOST_ISOLATION_EXCEPTIONS_PATH, MANAGEMENT_ROUTING_POLICIES_PATH, + MANAGEMENT_ROUTING_POLICY_DETAILS_BLOCKLISTS_PATH, } from '../../common/constants'; import { NotFoundPage } from '../../../app/404'; import { getPolicyDetailPath } from '../../common/routing'; @@ -30,6 +31,7 @@ export const PolicyContainer = memo(() => { MANAGEMENT_ROUTING_POLICY_DETAILS_TRUSTED_APPS_PATH, MANAGEMENT_ROUTING_POLICY_DETAILS_EVENT_FILTERS_PATH, MANAGEMENT_ROUTING_POLICY_DETAILS_HOST_ISOLATION_EXCEPTIONS_PATH, + MANAGEMENT_ROUTING_POLICY_DETAILS_BLOCKLISTS_PATH, ]} exact component={PolicyDetails} diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/policy_common_selectors.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/policy_common_selectors.ts index 40953b927e935..ef753e75a8391 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/policy_common_selectors.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/policy_common_selectors.ts @@ -12,6 +12,7 @@ import { MANAGEMENT_ROUTING_POLICY_DETAILS_HOST_ISOLATION_EXCEPTIONS_PATH, MANAGEMENT_ROUTING_POLICY_DETAILS_TRUSTED_APPS_PATH, MANAGEMENT_ROUTING_POLICY_DETAILS_EVENT_FILTERS_PATH, + MANAGEMENT_ROUTING_POLICY_DETAILS_BLOCKLISTS_PATH, } from '../../../../../common/constants'; import { PolicyDetailsSelector, PolicyDetailsState } from '../../../types'; @@ -76,3 +77,16 @@ export const isOnHostIsolationExceptionsView: PolicyDetailsSelector = c ); } ); + +/** Returns a boolean of whether the user is on the blocklists page or not */ +export const isOnBlocklistsView: PolicyDetailsSelector = createSelector( + getUrlLocationPathname, + (pathname) => { + return ( + matchPath(pathname ?? '', { + path: MANAGEMENT_ROUTING_POLICY_DETAILS_BLOCKLISTS_PATH, + exact: true, + }) !== null + ); + } +); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/policy_settings_selectors.ts b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/policy_settings_selectors.ts index a1a4c62d70734..eda993be89848 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/policy_settings_selectors.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/store/policy_details/selectors/policy_settings_selectors.ts @@ -23,6 +23,7 @@ import { MANAGEMENT_ROUTING_POLICY_DETAILS_HOST_ISOLATION_EXCEPTIONS_PATH, MANAGEMENT_ROUTING_POLICY_DETAILS_TRUSTED_APPS_PATH, MANAGEMENT_ROUTING_POLICY_DETAILS_EVENT_FILTERS_PATH, + MANAGEMENT_ROUTING_POLICY_DETAILS_BLOCKLISTS_PATH, } from '../../../../../common/constants'; import { ManagementRoutePolicyDetailsParams } from '../../../../../types'; import { getPolicyDataForUpdate } from '../../../../../../../common/endpoint/service/policy'; @@ -31,6 +32,7 @@ import { isOnPolicyEventFiltersView, isOnHostIsolationExceptionsView, isOnPolicyFormView, + isOnBlocklistsView, } from './policy_common_selectors'; /** Returns the policy details */ @@ -93,7 +95,8 @@ export const isOnPolicyDetailsPage = (state: Immutable) => isOnPolicyFormView(state) || isOnPolicyTrustedAppsView(state) || isOnPolicyEventFiltersView(state) || - isOnHostIsolationExceptionsView(state); + isOnHostIsolationExceptionsView(state) || + isOnBlocklistsView(state); /** Returns the license info fetched from the license service */ export const license = (state: Immutable) => { @@ -111,6 +114,7 @@ export const policyIdFromParams: (state: Immutable) => strin MANAGEMENT_ROUTING_POLICY_DETAILS_TRUSTED_APPS_PATH, MANAGEMENT_ROUTING_POLICY_DETAILS_EVENT_FILTERS_PATH, MANAGEMENT_ROUTING_POLICY_DETAILS_HOST_ISOLATION_EXCEPTIONS_PATH, + MANAGEMENT_ROUTING_POLICY_DETAILS_BLOCKLISTS_PATH, ], exact: true, })?.params?.policyId ?? '' diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_hooks.ts b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_hooks.ts index e8f3f97c6e0c1..2716f81d3230f 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_hooks.ts +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/policy_hooks.ts @@ -9,6 +9,7 @@ import { useCallback } from 'react'; import { useHistory } from 'react-router-dom'; import { useSelector } from 'react-redux'; import { + ENDPOINT_BLOCKLISTS_LIST_ID, ENDPOINT_EVENT_FILTERS_LIST_ID, ENDPOINT_TRUSTED_APPS_LIST_ID, } from '@kbn/securitysolution-list-constants'; @@ -19,6 +20,7 @@ import { MANAGEMENT_STORE_POLICY_DETAILS_NAMESPACE, } from '../../../common/constants'; import { + getPolicyBlocklistsPath, getPolicyDetailsArtifactsListPath, getPolicyEventFiltersPath, getPolicyHostIsolationExceptionsPath, @@ -79,6 +81,11 @@ export function usePolicyDetailsArtifactsNavigateCallback(listId: string) { ...location, ...args, }); + } else if (listId === ENDPOINT_BLOCKLISTS_LIST_ID) { + return getPolicyBlocklistsPath(policyId, { + ...location, + ...args, + }); } else { return getPolicyHostIsolationExceptionsPath(policyId, { ...location, diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/tabs/blocklists_translations.ts b/x-pack/plugins/security_solution/public/management/pages/policy/view/tabs/blocklists_translations.ts new file mode 100644 index 0000000000000..9eb2d57a506b3 --- /dev/null +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/tabs/blocklists_translations.ts @@ -0,0 +1,153 @@ +/* + * 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'; +import { ExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; + +export const POLICY_ARTIFACT_BLOCKLISTS_LABELS = Object.freeze({ + deleteModalTitle: i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.list.removeDialog.title', + { + defaultMessage: 'Remove blocklist from policy', + } + ), + deleteModalImpactInfo: i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.list.removeDialog.messageCallout', + { + defaultMessage: + 'This blocklist will be removed only from this policy and can still be found and managed from the artifact page.', + } + ), + deleteModalErrorMessage: i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.list.removeDialog.errorToastTitle', + { + defaultMessage: 'Error while attempting to remove blocklist', + } + ), + flyoutWarningCalloutMessage: (maxNumber: number) => + i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.layout.flyout.searchWarning.text', + { + defaultMessage: + 'Only the first {maxNumber} blocklists are displayed. Please use the search bar to refine the results.', + values: { maxNumber }, + } + ), + flyoutNoArtifactsToBeAssignedMessage: i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.layout.flyout.noAssignable', + { + defaultMessage: 'There are no blocklists that can be assigned to this policy.', + } + ), + flyoutTitle: i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.layout.flyout.title', + { + defaultMessage: 'Assign blocklists', + } + ), + flyoutSubtitle: (policyName: string): string => + i18n.translate('xpack.securitySolution.endpoint.policy.blocklists.layout.flyout.subtitle', { + defaultMessage: 'Select blocklists to add to {policyName}', + values: { policyName }, + }), + flyoutSearchPlaceholder: i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.layout.search.label', + { + defaultMessage: 'Search blocklists', + } + ), + flyoutErrorMessage: i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.layout.flyout.toastError.text', + { + defaultMessage: `An error occurred updating blocklists`, + } + ), + flyoutSuccessMessageText: (updatedExceptions: ExceptionListItemSchema[]): string => + updatedExceptions.length > 1 + ? i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.layout.flyout.toastSuccess.textMultiples', + { + defaultMessage: '{count} blocklists have been added to your list.', + values: { count: updatedExceptions.length }, + } + ) + : i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.layout.flyout.toastSuccess.textSingle', + { + defaultMessage: '"{name}" has been added to your blocklist list.', + values: { name: updatedExceptions[0].name }, + } + ), + emptyUnassignedTitle: i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.empty.unassigned.title', + { defaultMessage: 'No assigned blocklists' } + ), + emptyUnassignedMessage: (policyName: string): string => + i18n.translate('xpack.securitySolution.endpoint.policy.blocklists.empty.unassigned.content', { + defaultMessage: + 'There are currently no blocklists assigned to {policyName}. Assign blocklists now or add and manage them on the blocklists page.', + values: { policyName }, + }), + emptyUnassignedPrimaryActionButtonTitle: i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.empty.unassigned.primaryAction', + { + defaultMessage: 'Assign blocklists', + } + ), + emptyUnassignedSecondaryActionButtonTitle: i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.empty.unassigned.secondaryAction', + { + defaultMessage: 'Manage blocklists', + } + ), + emptyUnexistingTitle: i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.empty.unexisting.title', + { defaultMessage: 'No blocklists exist' } + ), + emptyUnexistingMessage: i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.empty.unexisting.content', + { + defaultMessage: 'There are currently no blocklists applied to your endpoints.', + } + ), + emptyUnexistingPrimaryActionButtonTitle: i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.empty.unexisting.action', + { defaultMessage: 'Add blocklists' } + ), + listTotalItemCountMessage: (totalItemsCount: number): string => + i18n.translate('xpack.securitySolution.endpoint.policy.blocklists.list.totalItemCount', { + defaultMessage: 'Showing {totalItemsCount, plural, one {# blocklist} other {# blocklists}}', + values: { totalItemsCount }, + }), + listRemoveActionNotAllowedMessage: i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.list.removeActionNotAllowed', + { + defaultMessage: 'Globally applied blocklist cannot be removed from policy.', + } + ), + listSearchPlaceholderMessage: i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.list.search.placeholder', + { + defaultMessage: `Search on the fields below: name, description, IP`, + } + ), + layoutTitle: i18n.translate('xpack.securitySolution.endpoint.policy.blocklists.layout.title', { + defaultMessage: 'Assigned blocklists', + }), + layoutAssignButtonTitle: i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.layout.assignToPolicy', + { + defaultMessage: 'Assign blocklists to policy', + } + ), + layoutViewAllLinkMessage: i18n.translate( + 'xpack.securitySolution.endpoint.policy.blocklists.layout.about.viewAllLinkLabel', + { + defaultMessage: 'view all blocklists', + } + ), +}); diff --git a/x-pack/plugins/security_solution/public/management/pages/policy/view/tabs/policy_tabs.tsx b/x-pack/plugins/security_solution/public/management/pages/policy/view/tabs/policy_tabs.tsx index 706995974fcbc..17c880ffa6261 100644 --- a/x-pack/plugins/security_solution/public/management/pages/policy/view/tabs/policy_tabs.tsx +++ b/x-pack/plugins/security_solution/public/management/pages/policy/view/tabs/policy_tabs.tsx @@ -20,6 +20,8 @@ import { getHostIsolationExceptionsListPath, getTrustedAppsListPath, getPolicyDetailsArtifactsListPath, + getBlocklistsListPath, + getPolicyBlocklistsPath, } from '../../../../common/routing'; import { useHttp } from '../../../../../common/lib/kibana'; import { ManagementPageLoader } from '../../../../components/management_page_loader'; @@ -29,6 +31,7 @@ import { isOnPolicyEventFiltersView, isOnPolicyFormView, isOnPolicyTrustedAppsView, + isOnBlocklistsView, policyDetails, policyIdFromParams, } from '../../store/policy_details/selectors'; @@ -38,18 +41,22 @@ import { usePolicyDetailsSelector } from '../policy_hooks'; import { POLICY_ARTIFACT_EVENT_FILTERS_LABELS } from './event_filters_translations'; import { POLICY_ARTIFACT_TRUSTED_APPS_LABELS } from './trusted_apps_translations'; import { POLICY_ARTIFACT_HOST_ISOLATION_EXCEPTIONS_LABELS } from './host_isolation_exceptions_translations'; +import { POLICY_ARTIFACT_BLOCKLISTS_LABELS } from './blocklists_translations'; import { TrustedAppsApiClient } from '../../../trusted_apps/service/trusted_apps_api_client'; import { EventFiltersApiClient } from '../../../event_filters/service/event_filters_api_client'; +import { BlocklistsApiClient } from '../../../blocklist/services/blocklists_api_client'; import { HostIsolationExceptionsApiClient } from '../../../host_isolation_exceptions/host_isolation_exceptions_api_client'; import { SEARCHABLE_FIELDS as TRUSTED_APPS_SEARCHABLE_FIELDS } from '../../../trusted_apps/constants'; import { SEARCHABLE_FIELDS as EVENT_FILTERS_SEARCHABLE_FIELDS } from '../../../event_filters/constants'; import { SEARCHABLE_FIELDS as HOST_ISOLATION_EXCEPTIONS_SEARCHABLE_FIELDS } from '../../../host_isolation_exceptions/constants'; +import { SEARCHABLE_FIELDS as BLOCKLISTS_SEARCHABLE_FIELDS } from '../../../blocklist/constants'; const enum PolicyTabKeys { SETTINGS = 'settings', TRUSTED_APPS = 'trustedApps', EVENT_FILTERS = 'eventFilters', HOST_ISOLATION_EXCEPTIONS = 'hostIsolationExceptions', + BLOCKLISTS = 'blocklists', } interface PolicyTab { @@ -65,6 +72,7 @@ export const PolicyTabs = React.memo(() => { const isInTrustedAppsTab = usePolicyDetailsSelector(isOnPolicyTrustedAppsView); const isInEventFilters = usePolicyDetailsSelector(isOnPolicyEventFiltersView); const isInHostIsolationExceptionsTab = usePolicyDetailsSelector(isOnHostIsolationExceptionsView); + const isInBlocklistsTab = usePolicyDetailsSelector(isOnBlocklistsView); const policyId = usePolicyDetailsSelector(policyIdFromParams); const policyItem = usePolicyDetailsSelector(policyDetails); const privileges = useUserPrivileges().endpointPrivileges; @@ -104,6 +112,11 @@ export const PolicyTabs = React.memo(() => { [http] ); + const getBlocklistsApiClientInstance = useCallback( + () => BlocklistsApiClient.getInstance(http), + [http] + ); + const tabs: Record = useMemo(() => { const trustedAppsLabels = { ...POLICY_ARTIFACT_TRUSTED_APPS_LABELS, @@ -138,6 +151,17 @@ export const PolicyTabs = React.memo(() => { ), }; + const blocklistsLabels = { + ...POLICY_ARTIFACT_BLOCKLISTS_LABELS, + layoutAboutMessage: (count: number, link: React.ReactElement): React.ReactNode => ( + + ), + }; + return { [PolicyTabKeys.SETTINGS]: { id: PolicyTabKeys.SETTINGS, @@ -214,11 +238,31 @@ export const PolicyTabs = React.memo(() => { ), } : undefined, + [PolicyTabKeys.BLOCKLISTS]: { + id: PolicyTabKeys.BLOCKLISTS, + name: i18n.translate('xpack.securitySolution.endpoint.policy.details.tabs.blocklists', { + defaultMessage: 'Blocklists', + }), + content: ( + <> + + + + ), + }, }; }, [ canSeeHostIsolationExceptions, getEventFiltersApiClientInstance, getHostIsolationExceptionsApiClientInstance, + getBlocklistsApiClientInstance, getTrustedAppsApiClientInstance, policyItem, privileges.canIsolateHost, @@ -242,10 +286,19 @@ export const PolicyTabs = React.memo(() => { selectedTab = tabs[PolicyTabKeys.EVENT_FILTERS]; } else if (isInHostIsolationExceptionsTab) { selectedTab = tabs[PolicyTabKeys.HOST_ISOLATION_EXCEPTIONS]; + } else if (isInBlocklistsTab) { + selectedTab = tabs[PolicyTabKeys.BLOCKLISTS]; } return selectedTab || defaultTab; - }, [tabs, isInSettingsTab, isInTrustedAppsTab, isInEventFilters, isInHostIsolationExceptionsTab]); + }, [ + tabs, + isInSettingsTab, + isInTrustedAppsTab, + isInEventFilters, + isInHostIsolationExceptionsTab, + isInBlocklistsTab, + ]); const onTabClickHandler = useCallback( (selectedTab: EuiTabbedContentTab) => { @@ -263,6 +316,9 @@ export const PolicyTabs = React.memo(() => { case PolicyTabKeys.HOST_ISOLATION_EXCEPTIONS: path = getPolicyHostIsolationExceptionsPath(policyId); break; + case PolicyTabKeys.BLOCKLISTS: + path = getPolicyBlocklistsPath(policyId); + break; } history.push(path); },