diff --git a/x-pack/plugins/security_solution/public/app/translations.ts b/x-pack/plugins/security_solution/public/app/translations.ts index aa7eaa83685dbaf..e9a45c0397316e9 100644 --- a/x-pack/plugins/security_solution/public/app/translations.ts +++ b/x-pack/plugins/security_solution/public/app/translations.ts @@ -43,7 +43,7 @@ export const USERS = i18n.translate('xpack.securitySolution.navigation.users', { }); export const RULES = i18n.translate('xpack.securitySolution.navigation.rules', { - defaultMessage: 'Rules', + defaultMessage: 'SIEM rules', }); export const EXCEPTIONS = i18n.translate('xpack.securitySolution.navigation.exceptions', { @@ -71,7 +71,7 @@ export const ENDPOINTS = i18n.translate('xpack.securitySolution.search.administr export const POLICIES = i18n.translate( 'xpack.securitySolution.navigation.administration.policies', { - defaultMessage: 'Policies', + defaultMessage: 'Endpoint policies', } ); export const TRUSTED_APPLICATIONS = i18n.translate( @@ -90,7 +90,7 @@ export const EVENT_FILTERS = i18n.translate( export const HOST_ISOLATION_EXCEPTIONS = i18n.translate( 'xpack.securitySolution.search.administration.hostIsolationExceptions', { - defaultMessage: 'Host isolation exceptions', + defaultMessage: 'Host isolation IP exceptions', } ); export const DETECT = i18n.translate('xpack.securitySolution.navigation.detect', { diff --git a/x-pack/plugins/security_solution/public/common/hooks/use_experimental_features.ts b/x-pack/plugins/security_solution/public/common/hooks/use_experimental_features.ts index 3132ae70381a299..1cc2506ec399686 100644 --- a/x-pack/plugins/security_solution/public/common/hooks/use_experimental_features.ts +++ b/x-pack/plugins/security_solution/public/common/hooks/use_experimental_features.ts @@ -14,14 +14,16 @@ import { const allowedExperimentalValues = getExperimentalAllowedValues(); -export const useIsExperimentalFeatureEnabled = (feature: keyof ExperimentalFeatures): boolean => - useSelector(({ app: { enableExperimental } }: State) => { - if (!enableExperimental || !(feature in enableExperimental)) { - throw new Error( - `Invalid enable value ${feature}. Allowed values are: ${allowedExperimentalValues.join( - ', ' - )}` - ); - } - return enableExperimental[feature]; - }); +export const useIsExperimentalFeatureEnabled = (feature: keyof ExperimentalFeatures): boolean => { + const enableExperimental = useEnableExperimental(); + + if (!enableExperimental || !(feature in enableExperimental)) { + throw new Error( + `Invalid enable value ${feature}. Allowed values are: ${allowedExperimentalValues.join(', ')}` + ); + } + return enableExperimental[feature]; +}; + +export const useEnableExperimental = (): ExperimentalFeatures => + useSelector(({ app: { enableExperimental } }: State) => enableExperimental); diff --git a/x-pack/plugins/security_solution/public/common/images/detection_response_page.png b/x-pack/plugins/security_solution/public/common/images/detection_response_page.png new file mode 100644 index 000000000000000..630cd555598432d Binary files /dev/null and b/x-pack/plugins/security_solution/public/common/images/detection_response_page.png differ diff --git a/x-pack/plugins/security_solution/public/common/links/links.ts b/x-pack/plugins/security_solution/public/common/links/links.ts index 290a1f3fbd8208d..a150ab2e7e0cebd 100644 --- a/x-pack/plugins/security_solution/public/common/links/links.ts +++ b/x-pack/plugins/security_solution/public/common/links/links.ts @@ -8,6 +8,9 @@ import { AppDeepLink, AppNavLinkStatus, Capabilities } from '@kbn/core/public'; import { get } from 'lodash'; import { SecurityPageName } from '../../../common/constants'; +import { useEnableExperimental } from '../hooks/use_experimental_features'; +import { useLicense } from '../hooks/use_license'; +import { useKibana } from '../lib/kibana'; import { appLinks, getAppLinks } from './app_links'; import { Feature, @@ -32,8 +35,6 @@ const createDeepLink = (link: LinkItem, linkProps?: UserPermissions): AppDeepLin }), } : {}), - ...(link.icon != null ? { euiIconType: link.icon } : {}), - ...(link.image != null ? { icon: link.image } : {}), ...(link.globalSearchKeywords != null ? { keywords: link.globalSearchKeywords } : {}), ...(link.globalNavEnabled != null ? { navLinkStatus: link.globalNavEnabled ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden } @@ -47,8 +48,8 @@ const createNavLinkItem = (link: LinkItem, linkProps?: UserPermissions): NavLink path: link.path, title: link.title, ...(link.description != null ? { description: link.description } : {}), - ...(link.icon != null ? { icon: link.icon } : {}), - ...(link.image != null ? { image: link.image } : {}), + ...(link.landingIcon != null ? { icon: link.landingIcon } : {}), + ...(link.landingImage != null ? { image: link.landingImage } : {}), ...(link.links && link.links.length ? { links: reduceLinks({ @@ -195,3 +196,11 @@ export const getAncestorLinksInfo = (id: SecurityPageName): LinkInfo[] => { export const needsUrlState = (id: SecurityPageName): boolean => { return !getNormalizedLink(id).skipUrlState; }; + +export const useAppNavLinks = (): NavLinkItem[] => { + const license = useLicense(); + const enableExperimental = useEnableExperimental(); + const capabilities = useKibana().services.application.capabilities; + + return getNavLinkItems({ enableExperimental, license, capabilities }); +}; diff --git a/x-pack/plugins/security_solution/public/common/links/types.ts b/x-pack/plugins/security_solution/public/common/links/types.ts index eea348b3df73777..320c38d1d229b2f 100644 --- a/x-pack/plugins/security_solution/public/common/links/types.ts +++ b/x-pack/plugins/security_solution/public/common/links/types.ts @@ -7,6 +7,7 @@ import { Capabilities } from '@kbn/core/types'; import { LicenseType } from '@kbn/licensing-plugin/common/types'; +import { IconType } from '@elastic/eui'; import { LicenseService } from '../../../common/license'; import { ExperimentalFeatures } from '../../../common/experimental_features'; import { CASES_FEATURE_ID, SecurityPageName, SERVER_APP_ID } from '../../../common/constants'; @@ -41,9 +42,17 @@ export interface LinkItem { globalSearchEnabled?: boolean; globalSearchKeywords?: string[]; hideWhenExperimentalKey?: keyof ExperimentalFeatures; - icon?: string; id: SecurityPageName; - image?: string; + /** + * Icon that is displayed on menu navigation landing page. + * Only required for pages that are displayed inside a landing page. + */ + landingIcon?: IconType; + /** + * Image that is displayed on menu navigation landing page. + * Only required for pages that are displayed inside a landing page. + */ + landingImage?: string; isBeta?: boolean; licenseType?: LicenseType; links?: LinkItem[]; @@ -54,7 +63,7 @@ export interface LinkItem { export interface NavLinkItem { description?: string; - icon?: string; + icon?: IconType; id: SecurityPageName; links?: NavLinkItem[]; image?: string; diff --git a/x-pack/plugins/security_solution/public/hosts/links.ts b/x-pack/plugins/security_solution/public/hosts/links.ts index 35730291d6c749c..421fe9693a57a80 100644 --- a/x-pack/plugins/security_solution/public/hosts/links.ts +++ b/x-pack/plugins/security_solution/public/hosts/links.ts @@ -8,10 +8,16 @@ import { i18n } from '@kbn/i18n'; import { HOSTS_PATH, SecurityPageName } from '../../common/constants'; import { HOSTS } from '../app/translations'; import { LinkItem } from '../common/links/types'; +import hostsPageImg from '../common/images/hosts_page.png'; export const links: LinkItem = { id: SecurityPageName.hosts, title: HOSTS, + landingImage: hostsPageImg, + description: i18n.translate('xpack.securitySolution.landing.threatHunting.hostsDescription', { + defaultMessage: + 'A computer or other device that communicates with other hosts on a network. Hosts on a network include clients and servers -- that send or receive data, services or applications.', + }), path: HOSTS_PATH, globalNavEnabled: true, globalSearchKeywords: [ diff --git a/x-pack/plugins/security_solution/public/landing_pages/components/landing_links_icons.test.tsx b/x-pack/plugins/security_solution/public/landing_pages/components/landing_links_icons.test.tsx index 3553f44cc621ff4..4db27261654edba 100644 --- a/x-pack/plugins/security_solution/public/landing_pages/components/landing_links_icons.test.tsx +++ b/x-pack/plugins/security_solution/public/landing_pages/components/landing_links_icons.test.tsx @@ -8,14 +8,16 @@ import { fireEvent, render } from '@testing-library/react'; import React from 'react'; import { SecurityPageName } from '../../app/types'; +import { NavLinkItem } from '../../common/links/types'; import { TestProviders } from '../../common/mock'; -import { LandingLinksIcons, NavItem } from './landing_links_icons'; +import { LandingLinksIcons } from './landing_links_icons'; -const DEFAULT_NAV_ITEM: NavItem = { +const DEFAULT_NAV_ITEM: NavLinkItem = { id: SecurityPageName.overview, - label: 'TEST LABEL', + title: 'TEST LABEL', description: 'TEST DESCRIPTION', icon: 'myTestIcon', + path: '', }; const mockNavigateTo = jest.fn(); @@ -42,28 +44,28 @@ jest.mock('../../common/components/link_to', () => { describe('LandingLinksIcons', () => { it('renders', () => { - const label = 'test label'; + const title = 'test label'; const { queryByText } = render( - + ); - expect(queryByText(label)).toBeInTheDocument(); + expect(queryByText(title)).toBeInTheDocument(); }); it('renders navigation link', () => { const id = SecurityPageName.administration; - const label = 'myTestLable'; + const title = 'myTestLable'; const { getByText } = render( - + ); - fireEvent.click(getByText(label)); + fireEvent.click(getByText(title)); expect(mockNavigateTo).toHaveBeenCalledWith({ url: '/administration' }); }); diff --git a/x-pack/plugins/security_solution/public/landing_pages/components/landing_links_icons.tsx b/x-pack/plugins/security_solution/public/landing_pages/components/landing_links_icons.tsx index 82a0d2148f68350..04a3e20b1f17892 100644 --- a/x-pack/plugins/security_solution/public/landing_pages/components/landing_links_icons.tsx +++ b/x-pack/plugins/security_solution/public/landing_pages/components/landing_links_icons.tsx @@ -4,33 +4,18 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { - EuiFlexGrid, - EuiFlexGroup, - EuiFlexItem, - EuiIcon, - EuiText, - EuiTitle, - IconType, -} from '@elastic/eui'; +import { EuiFlexGrid, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiText, EuiTitle } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; -import { SecurityPageName } from '../../app/types'; + import { SecuritySolutionLinkAnchor, withSecuritySolutionLink, } from '../../common/components/links'; +import { NavLinkItem } from '../../common/links/types'; interface LandingLinksImagesProps { - items: NavItem[]; -} - -export interface NavItem { - id: SecurityPageName; - label: string; - icon: IconType; - description: string; - path?: string; + items: NavLinkItem[]; } const Link = styled.a` @@ -50,7 +35,7 @@ const StyledEuiTitle = styled(EuiTitle)` export const LandingLinksIcons: React.FC = ({ items }) => ( - {items.map(({ label, description, path, id, icon }) => ( + {items.map(({ title, description, id, icon }) => ( = ({ items }) responsive={false} > - - - -

{label}

+ +

{title}

diff --git a/x-pack/plugins/security_solution/public/landing_pages/components/landing_links_images.test.tsx b/x-pack/plugins/security_solution/public/landing_pages/components/landing_links_images.test.tsx index 479de5e13f43261..fff8b6f6a45b10e 100644 --- a/x-pack/plugins/security_solution/public/landing_pages/components/landing_links_images.test.tsx +++ b/x-pack/plugins/security_solution/public/landing_pages/components/landing_links_images.test.tsx @@ -8,14 +8,16 @@ import { render } from '@testing-library/react'; import React from 'react'; import { SecurityPageName } from '../../app/types'; +import { NavLinkItem } from '../../common/links/types'; import { TestProviders } from '../../common/mock'; -import { LandingLinksImages, NavItem } from './landing_links_images'; +import { LandingLinksImages } from './landing_links_images'; -const DEFAULT_NAV_ITEM: NavItem = { +const DEFAULT_NAV_ITEM: NavLinkItem = { id: SecurityPageName.overview, - label: 'TEST LABEL', + title: 'TEST LABEL', description: 'TEST DESCRIPTION', image: 'TEST_IMAGE.png', + path: '', }; jest.mock('../../common/lib/kibana/kibana_react', () => { @@ -32,27 +34,27 @@ jest.mock('../../common/lib/kibana/kibana_react', () => { describe('LandingLinksImages', () => { it('renders', () => { - const label = 'test label'; + const title = 'test label'; const { queryByText } = render( - + ); - expect(queryByText(label)).toBeInTheDocument(); + expect(queryByText(title)).toBeInTheDocument(); }); it('renders image', () => { - const image = 'test_image.jpeg'; - const label = 'TEST_LABEL'; + const landingImage = 'test_image.jpeg'; + const title = 'TEST_LABEL'; const { getByTestId } = render( - + ); - expect(getByTestId('LandingLinksImage')).toHaveAttribute('src', image); + expect(getByTestId('LandingLinksImage')).toHaveAttribute('src', landingImage); }); }); diff --git a/x-pack/plugins/security_solution/public/landing_pages/components/landing_links_images.tsx b/x-pack/plugins/security_solution/public/landing_pages/components/landing_links_images.tsx index b6a16da8cdc82eb..6a3a19fdfe8a202 100644 --- a/x-pack/plugins/security_solution/public/landing_pages/components/landing_links_images.tsx +++ b/x-pack/plugins/security_solution/public/landing_pages/components/landing_links_images.tsx @@ -7,19 +7,11 @@ import { EuiFlexGroup, EuiFlexItem, EuiImage, EuiPanel, EuiText, EuiTitle } from '@elastic/eui'; import React from 'react'; import styled from 'styled-components'; -import { SecurityPageName } from '../../app/types'; import { withSecuritySolutionLink } from '../../common/components/links'; +import { LinkInfo } from '../../common/links/types'; interface LandingLinksImagesProps { - items: NavItem[]; -} - -export interface NavItem { - id: SecurityPageName; - label: string; - image: string; - description: string; - path?: string; + items: LinkInfo[]; } const PrimaryEuiTitle = styled(EuiTitle)` @@ -47,24 +39,26 @@ const Content = styled(EuiFlexItem)` export const LandingLinksImages: React.FC = ({ items }) => ( - {items.map(({ label, description, path, image, id }) => ( + {items.map(({ title, description, landingImage, id }) => ( - + {/* Empty onClick is to force hover style on `EuiPanel` */} {}}> - + {landingImage && ( + + )} -

{label}

+

{title}

{description} diff --git a/x-pack/plugins/security_solution/public/landing_pages/constants.ts b/x-pack/plugins/security_solution/public/landing_pages/constants.ts new file mode 100644 index 000000000000000..a6b72a5e7db4f96 --- /dev/null +++ b/x-pack/plugins/security_solution/public/landing_pages/constants.ts @@ -0,0 +1,36 @@ +/* + * 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 { SecurityPageName } from '../app/types'; + +export interface LandingNavGroup { + label: string; + itemIds: SecurityPageName[]; +} + +export const MANAGE_NAVIGATION_CATEGORIES: LandingNavGroup[] = [ + { + label: i18n.translate('xpack.securitySolution.landing.siemTitle', { + defaultMessage: 'SIEM', + }), + itemIds: [SecurityPageName.rules, SecurityPageName.exceptions], + }, + { + label: i18n.translate('xpack.securitySolution.landing.endpointsTitle', { + defaultMessage: 'ENDPOINTS', + }), + itemIds: [ + SecurityPageName.endpoints, + SecurityPageName.policies, + SecurityPageName.trustedApps, + SecurityPageName.eventFilters, + SecurityPageName.blocklist, + SecurityPageName.hostIsolationExceptions, + ], + }, +]; diff --git a/x-pack/plugins/security_solution/public/landing_pages/pages/dashboards.tsx b/x-pack/plugins/security_solution/public/landing_pages/pages/dashboards.tsx index 8c49fda169ad371..c2d5a3d8d2ee97c 100644 --- a/x-pack/plugins/security_solution/public/landing_pages/pages/dashboards.tsx +++ b/x-pack/plugins/security_solution/public/landing_pages/pages/dashboards.tsx @@ -5,31 +5,24 @@ * 2.0. */ import React from 'react'; -import { i18n } from '@kbn/i18n'; import { SecurityPageName } from '../../app/types'; import { HeaderPage } from '../../common/components/header_page'; import { SecuritySolutionPageWrapper } from '../../common/components/page_wrapper'; import { SpyRoute } from '../../common/utils/route/spy_routes'; -import { LandingLinksImages, NavItem } from '../components/landing_links_images'; +import { LandingLinksImages } from '../components/landing_links_images'; import { DASHBOARDS_PAGE_TITLE } from './translations'; -import overviewPageImg from '../../common/images/overview_page.png'; -import { OVERVIEW } from '../../app/translations'; +import { useAppNavLinks } from '../../common/links'; -const items: NavItem[] = [ - { - id: SecurityPageName.overview, - label: OVERVIEW, - description: i18n.translate('xpack.securitySolution.landing.dashboards.overviewDescription', { - defaultMessage: 'What is going in your secuity environment', - }), - image: overviewPageImg, - }, -]; +export const DashboardsLandingPage = () => { + const dashboardlinks = useAppNavLinks().find( + ({ id }) => id === SecurityPageName.dashboardsLanding + ); -export const DashboardsLandingPage = () => ( - - - - - -); + return ( + + + + + + ); +}; diff --git a/x-pack/plugins/security_solution/public/landing_pages/pages/manage.test.tsx b/x-pack/plugins/security_solution/public/landing_pages/pages/manage.test.tsx index efb1bcf35c39ed2..1b786912b7c6eaa 100644 --- a/x-pack/plugins/security_solution/public/landing_pages/pages/manage.test.tsx +++ b/x-pack/plugins/security_solution/public/landing_pages/pages/manage.test.tsx @@ -9,43 +9,56 @@ import { render } from '@testing-library/react'; import React from 'react'; import { SecurityPageName } from '../../app/types'; import { TestProviders } from '../../common/mock'; -import { LandingCategories, NavConfigType } from './manage'; +import { LandingCategories } from './manage'; const RULES_ITEM_LABEL = 'elastic rules!'; const EXCEPTIONS_ITEM_LABEL = 'exceptional!'; +import { NavLinkItem } from '../../common/links/types'; -const testConfig: NavConfigType = { - categories: [ - { - label: 'first tests category', - itemIds: [SecurityPageName.rules], - }, - { - label: 'second tests category', - itemIds: [SecurityPageName.exceptions], - }, - ], - items: [ - { - id: SecurityPageName.rules, - label: RULES_ITEM_LABEL, - description: '', - icon: 'testIcon1', - }, - { - id: SecurityPageName.exceptions, - label: EXCEPTIONS_ITEM_LABEL, - description: '', - icon: 'testIcon2', - }, - ], -}; +const mockAppLinks: NavLinkItem[] = [ + { + id: SecurityPageName.administration, + path: '', + title: 'admin', + links: [ + { + id: SecurityPageName.rules, + title: RULES_ITEM_LABEL, + description: '', + icon: 'testIcon1', + path: '', + }, + { + id: SecurityPageName.exceptions, + title: EXCEPTIONS_ITEM_LABEL, + description: '', + icon: 'testIcon2', + path: '', + }, + ], + }, +]; + +jest.mock('../../common/links', () => ({ + useAppNavLinks: jest.fn(() => mockAppLinks), +})); describe('LandingCategories', () => { it('renders items', () => { const { queryByText } = render( - + ); @@ -57,15 +70,12 @@ describe('LandingCategories', () => { const { queryAllByTestId } = render( ); diff --git a/x-pack/plugins/security_solution/public/landing_pages/pages/manage.tsx b/x-pack/plugins/security_solution/public/landing_pages/pages/manage.tsx index da4d25f62130580..172506868cec964 100644 --- a/x-pack/plugins/security_solution/public/landing_pages/pages/manage.tsx +++ b/x-pack/plugins/security_solution/public/landing_pages/pages/manage.tsx @@ -5,140 +5,24 @@ * 2.0. */ import { EuiHorizontalRule, EuiSpacer, EuiTitle } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; import { compact } from 'lodash/fp'; import React from 'react'; import styled from 'styled-components'; -import { - BLOCKLIST, - ENDPOINTS, - EVENT_FILTERS, - EXCEPTIONS, - TRUSTED_APPLICATIONS, -} from '../../app/translations'; + import { SecurityPageName } from '../../app/types'; import { HeaderPage } from '../../common/components/header_page'; import { SecuritySolutionPageWrapper } from '../../common/components/page_wrapper'; +import { useAppNavLinks } from '../../common/links'; +import { NavLinkItem } from '../../common/links/types'; import { SpyRoute } from '../../common/utils/route/spy_routes'; -import { LandingLinksIcons, NavItem } from '../components/landing_links_icons'; -import { IconBlocklist } from '../icons/blocklist'; -import { IconEndpoints } from '../icons/endpoints'; -import { IconEndpointPolicies } from '../icons/endpoint_policies'; -import { IconEventFilters } from '../icons/event_filters'; -import { IconExceptionLists } from '../icons/exception_lists'; -import { IconHostIsolation } from '../icons/host_isolation'; -import { IconSiemRules } from '../icons/siem_rules'; -import { IconTrustedApplications } from '../icons/trusted_applications'; +import { LandingLinksIcons } from '../components/landing_links_icons'; +import { LandingNavGroup, MANAGE_NAVIGATION_CATEGORIES } from '../constants'; import { MANAGE_PAGE_TITLE } from './translations'; -// TODO -const FIX_ME_TEMPORARY_DESCRIPTION = 'Description here'; - -export interface NavConfigType { - items: NavItem[]; - categories: Array<{ label: string; itemIds: SecurityPageName[] }>; -} - -const config: NavConfigType = { - categories: [ - { - label: i18n.translate('xpack.securitySolution.landing.threatHunting.siemTitle', { - defaultMessage: 'SIEM', - }), - itemIds: [SecurityPageName.rules, SecurityPageName.exceptions], - }, - { - label: i18n.translate('xpack.securitySolution.landing.threatHunting.endpointsTitle', { - defaultMessage: 'ENDPOINTS', - }), - itemIds: [ - SecurityPageName.endpoints, - SecurityPageName.policies, - SecurityPageName.trustedApps, - SecurityPageName.eventFilters, - SecurityPageName.blocklist, - SecurityPageName.hostIsolationExceptions, - ], - }, - ], - items: [ - { - id: SecurityPageName.rules, - label: i18n.translate('xpack.securitySolution.landing.manage.rulesLabel', { - defaultMessage: 'SIEM rules', - }), - description: FIX_ME_TEMPORARY_DESCRIPTION, - icon: IconSiemRules, - }, - { - id: SecurityPageName.exceptions, - label: EXCEPTIONS, - description: FIX_ME_TEMPORARY_DESCRIPTION, - icon: IconExceptionLists, - }, - { - id: SecurityPageName.endpoints, - label: ENDPOINTS, - description: i18n.translate('xpack.securitySolution.landing.manage.endpointsDescription', { - defaultMessage: 'Hosts running endpoint security', - }), - icon: IconEndpoints, - }, - { - id: SecurityPageName.policies, - label: i18n.translate('xpack.securitySolution.landing.manage.endpointPoliceLabel', { - defaultMessage: 'Endpoint policies', - }), - description: FIX_ME_TEMPORARY_DESCRIPTION, - icon: IconEndpointPolicies, - }, - { - id: SecurityPageName.trustedApps, - label: TRUSTED_APPLICATIONS, - description: i18n.translate( - 'xpack.securitySolution.landing.manage.trustedApplicationsDescription', - { - defaultMessage: - 'Improve performance or alleviate conflicts with other applications running on your hosts', - } - ), - icon: IconTrustedApplications, - }, - { - id: SecurityPageName.eventFilters, - label: EVENT_FILTERS, - description: i18n.translate('xpack.securitySolution.landing.manage.eventFiltersDescription', { - defaultMessage: 'Exclude unwanted applications from running on your hosts', - }), - icon: IconEventFilters, - }, - { - id: SecurityPageName.blocklist, - label: BLOCKLIST, - description: FIX_ME_TEMPORARY_DESCRIPTION, - icon: IconBlocklist, - }, - { - id: SecurityPageName.hostIsolationExceptions, - label: i18n.translate('xpack.securitySolution.landing.manage.hostIsolationLabel', { - defaultMessage: 'Host isolation IP exceptions', - }), - description: i18n.translate( - 'xpack.securitySolution.landing.manage.hostIsolationDescription', - { - defaultMessage: 'Allow isolated hosts to communicate with specific IPs', - } - ), - - icon: IconHostIsolation, - }, - ], -}; - export const ManageLandingPage = () => ( - + ); @@ -148,16 +32,18 @@ const StyledEuiHorizontalRule = styled(EuiHorizontalRule)` margin-bottom: ${({ theme }) => theme.eui.paddingSizes.l}; `; -const getNavItembyId = (navConfig: NavConfigType) => (itemId: string) => - navConfig.items.find(({ id }: NavItem) => id === itemId); +const getNavItembyId = (links: NavLinkItem[]) => (itemId: string) => + links.find(({ id }: NavLinkItem) => id === itemId); + +const navItemsFromIds = (itemIds: SecurityPageName[], links: NavLinkItem[]) => + compact(itemIds.map(getNavItembyId(links))); -const navItemsFromIds = (itemIds: SecurityPageName[], navConfig: NavConfigType) => - compact(itemIds.map(getNavItembyId(navConfig))); +export const LandingCategories = React.memo(({ groups }: { groups: LandingNavGroup[] }) => { + const manageLink = useAppNavLinks().find(({ id }) => id === SecurityPageName.administration); -export const LandingCategories = React.memo(({ navConfig }: { navConfig: NavConfigType }) => { return ( <> - {navConfig.categories.map(({ label, itemIds }, index) => ( + {groups.map(({ label, itemIds }, index) => (
{index > 0 && ( <> @@ -169,7 +55,7 @@ export const LandingCategories = React.memo(({ navConfig }: { navConfig: NavConf

{label}

- +
))} diff --git a/x-pack/plugins/security_solution/public/landing_pages/pages/threat_hunting.tsx b/x-pack/plugins/security_solution/public/landing_pages/pages/threat_hunting.tsx index 2a0f4e471a75de8..7d486c102a2ddfe 100644 --- a/x-pack/plugins/security_solution/public/landing_pages/pages/threat_hunting.tsx +++ b/x-pack/plugins/security_solution/public/landing_pages/pages/threat_hunting.tsx @@ -5,51 +5,23 @@ * 2.0. */ import React from 'react'; -import { i18n } from '@kbn/i18n'; import { SecurityPageName } from '../../app/types'; import { HeaderPage } from '../../common/components/header_page'; import { SecuritySolutionPageWrapper } from '../../common/components/page_wrapper'; import { SpyRoute } from '../../common/utils/route/spy_routes'; -import { LandingLinksImages, NavItem } from '../components/landing_links_images'; +import { LandingLinksImages } from '../components/landing_links_images'; import { THREAT_HUNTING_PAGE_TITLE } from './translations'; -import userPageImg from '../../common/images/users_page.png'; -import hostsPageImg from '../../common/images/hosts_page.png'; -import networkPageImg from '../../common/images/network_page.png'; -import { HOSTS, NETWORK, USERS } from '../../app/translations'; +import { useAppNavLinks } from '../../common/links'; -const items: NavItem[] = [ - { - id: SecurityPageName.hosts, - label: HOSTS, - description: i18n.translate('xpack.securitySolution.landing.threatHunting.hostsDescription', { - defaultMessage: - 'Computer or other device that communicates with other hosts on a network. Hosts on a network include clients and servers -- that send or receive data, services or applications.', - }), - image: hostsPageImg, - }, - { - id: SecurityPageName.network, - label: NETWORK, - description: i18n.translate('xpack.securitySolution.landing.threatHunting.networkDescription', { - defaultMessage: - 'The action or process of interacting with others to exchange information and develop professional or social contacts.', - }), - image: networkPageImg, - }, - { - id: SecurityPageName.users, - label: USERS, - description: i18n.translate('xpack.securitySolution.landing.threatHunting.usersDescription', { - defaultMessage: 'Sudo commands dashboard from the Logs System integration.', - }), - image: userPageImg, - }, -]; - -export const ThreatHuntingLandingPage = () => ( - - - - - -); +export const ThreatHuntingLandingPage = () => { + const threatHuntinglinks = useAppNavLinks().find( + ({ id }) => id === SecurityPageName.threatHuntingLanding + ); + return ( + + + + + + ); +}; diff --git a/x-pack/plugins/security_solution/public/landing_pages/icons/blocklist.tsx b/x-pack/plugins/security_solution/public/management/icons/blocklist.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/landing_pages/icons/blocklist.tsx rename to x-pack/plugins/security_solution/public/management/icons/blocklist.tsx diff --git a/x-pack/plugins/security_solution/public/landing_pages/icons/endpoint_policies.tsx b/x-pack/plugins/security_solution/public/management/icons/endpoint_policies.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/landing_pages/icons/endpoint_policies.tsx rename to x-pack/plugins/security_solution/public/management/icons/endpoint_policies.tsx diff --git a/x-pack/plugins/security_solution/public/landing_pages/icons/endpoints.tsx b/x-pack/plugins/security_solution/public/management/icons/endpoints.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/landing_pages/icons/endpoints.tsx rename to x-pack/plugins/security_solution/public/management/icons/endpoints.tsx diff --git a/x-pack/plugins/security_solution/public/landing_pages/icons/event_filters.tsx b/x-pack/plugins/security_solution/public/management/icons/event_filters.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/landing_pages/icons/event_filters.tsx rename to x-pack/plugins/security_solution/public/management/icons/event_filters.tsx diff --git a/x-pack/plugins/security_solution/public/landing_pages/icons/exception_lists.tsx b/x-pack/plugins/security_solution/public/management/icons/exception_lists.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/landing_pages/icons/exception_lists.tsx rename to x-pack/plugins/security_solution/public/management/icons/exception_lists.tsx diff --git a/x-pack/plugins/security_solution/public/landing_pages/icons/host_isolation.tsx b/x-pack/plugins/security_solution/public/management/icons/host_isolation.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/landing_pages/icons/host_isolation.tsx rename to x-pack/plugins/security_solution/public/management/icons/host_isolation.tsx diff --git a/x-pack/plugins/security_solution/public/landing_pages/icons/siem_rules.tsx b/x-pack/plugins/security_solution/public/management/icons/siem_rules.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/landing_pages/icons/siem_rules.tsx rename to x-pack/plugins/security_solution/public/management/icons/siem_rules.tsx diff --git a/x-pack/plugins/security_solution/public/landing_pages/icons/trusted_applications.tsx b/x-pack/plugins/security_solution/public/management/icons/trusted_applications.tsx similarity index 100% rename from x-pack/plugins/security_solution/public/landing_pages/icons/trusted_applications.tsx rename to x-pack/plugins/security_solution/public/management/icons/trusted_applications.tsx diff --git a/x-pack/plugins/security_solution/public/management/links.ts b/x-pack/plugins/security_solution/public/management/links.ts index d941d538c80f7c6..98a78820c4b845c 100644 --- a/x-pack/plugins/security_solution/public/management/links.ts +++ b/x-pack/plugins/security_solution/public/management/links.ts @@ -31,6 +31,16 @@ import { } from '../app/translations'; import { FEATURE, LinkItem } from '../common/links/types'; +import { IconBlocklist } from './icons/blocklist'; +import { IconEndpoints } from './icons/endpoints'; +import { IconEndpointPolicies } from './icons/endpoint_policies'; +import { IconEventFilters } from './icons/event_filters'; +import { IconExceptionLists } from './icons/exception_lists'; +import { IconHostIsolation } from './icons/host_isolation'; +import { IconSiemRules } from './icons/siem_rules'; +import { IconTrustedApplications } from './icons/trusted_applications'; +const FIX_ME_TEMPORARY_DESCRIPTION = 'Description here'; + export const links: LinkItem = { id: SecurityPageName.administration, title: MANAGE, @@ -47,6 +57,12 @@ export const links: LinkItem = { { id: SecurityPageName.rules, title: RULES, + description: i18n.translate('xpack.securitySolution.appLinks.rulesDescription', { + defaultMessage: + "Create and manage rules to check for suspicious source events, and create alerts when a rule's conditions are met.", + }), + + landingIcon: IconSiemRules, path: RULES_PATH, globalNavEnabled: false, globalSearchKeywords: [ @@ -59,6 +75,10 @@ export const links: LinkItem = { { id: SecurityPageName.exceptions, title: EXCEPTIONS, + description: i18n.translate('xpack.securitySolution.appLinks.exceptionsDescription', { + defaultMessage: 'Create and manage exceptions to prevent the creation of unwanted alerts.', + }), + landingIcon: IconExceptionLists, path: EXCEPTIONS_PATH, globalNavEnabled: false, globalSearchKeywords: [ @@ -70,6 +90,10 @@ export const links: LinkItem = { }, { id: SecurityPageName.endpoints, + description: i18n.translate('xpack.securitySolution.appLinks.endpointsDescription', { + defaultMessage: 'Hosts running endpoint security', + }), + landingIcon: IconEndpoints, globalNavEnabled: true, title: ENDPOINTS, globalNavOrder: 9006, @@ -79,6 +103,11 @@ export const links: LinkItem = { { id: SecurityPageName.policies, title: POLICIES, + description: i18n.translate('xpack.securitySolution.appLinks.policiesDescription', { + defaultMessage: + 'Use policies to customize endpoint and cloud workload protections and other configurations', + }), + landingIcon: IconEndpointPolicies, path: POLICIES_PATH, skipUrlState: true, experimentalKey: 'policyListEnabled', @@ -86,24 +115,42 @@ export const links: LinkItem = { { id: SecurityPageName.trustedApps, title: TRUSTED_APPLICATIONS, + description: i18n.translate( + 'xpack.securitySolution.appLinks.trustedApplicationsDescription', + { + defaultMessage: + 'Improve performance or alleviate conflicts with other applications running on your hosts', + } + ), + landingIcon: IconTrustedApplications, path: TRUSTED_APPS_PATH, skipUrlState: true, }, { id: SecurityPageName.eventFilters, title: EVENT_FILTERS, + description: i18n.translate('xpack.securitySolution.appLinks.eventFiltersDescription', { + defaultMessage: 'Exclude unwanted applications from running on your hosts', + }), + landingIcon: IconEventFilters, path: EVENT_FILTERS_PATH, skipUrlState: true, }, { id: SecurityPageName.hostIsolationExceptions, title: HOST_ISOLATION_EXCEPTIONS, + description: i18n.translate('xpack.securitySolution.appLinks.hostIsolationDescription', { + defaultMessage: 'Allow isolated hosts to communicate with specific IPs', + }), + landingIcon: IconHostIsolation, path: HOST_ISOLATION_EXCEPTIONS_PATH, skipUrlState: true, }, { id: SecurityPageName.blocklist, title: BLOCKLIST, + description: FIX_ME_TEMPORARY_DESCRIPTION, + landingIcon: IconBlocklist, path: BLOCKLIST_PATH, skipUrlState: true, }, diff --git a/x-pack/plugins/security_solution/public/network/links.ts b/x-pack/plugins/security_solution/public/network/links.ts index ad209a220eebcb3..f52a0c6a1175440 100644 --- a/x-pack/plugins/security_solution/public/network/links.ts +++ b/x-pack/plugins/security_solution/public/network/links.ts @@ -9,10 +9,16 @@ import { i18n } from '@kbn/i18n'; import { NETWORK_PATH, SecurityPageName } from '../../common/constants'; import { NETWORK } from '../app/translations'; import { LinkItem } from '../common/links/types'; +import networkPageImg from '../common/images/network_page.png'; export const links: LinkItem = { id: SecurityPageName.network, title: NETWORK, + landingImage: networkPageImg, + description: i18n.translate('xpack.securitySolution.appLinks.network.description', { + defaultMessage: + 'The action or process of interacting with others to exchange information and develop professional or social contacts.', + }), path: NETWORK_PATH, globalNavEnabled: true, globalSearchKeywords: [ diff --git a/x-pack/plugins/security_solution/public/overview/links.ts b/x-pack/plugins/security_solution/public/overview/links.ts index 89f75053b3d6f9f..2cfb8df58274247 100644 --- a/x-pack/plugins/security_solution/public/overview/links.ts +++ b/x-pack/plugins/security_solution/public/overview/links.ts @@ -15,10 +15,16 @@ import { } from '../../common/constants'; import { DASHBOARDS, DETECTION_RESPONSE, GETTING_STARTED, OVERVIEW } from '../app/translations'; import { FEATURE, LinkItem } from '../common/links/types'; +import overviewPageImg from '../common/images/overview_page.png'; +import detectionResponsePageImg from '../common/images/detection_response_page.png'; export const overviewLinks: LinkItem = { id: SecurityPageName.overview, title: OVERVIEW, + landingImage: overviewPageImg, + description: i18n.translate('xpack.securitySolution.appLinks.overviewDescription', { + defaultMessage: 'What is going in your secuity environment', + }), path: OVERVIEW_PATH, globalNavEnabled: true, features: [FEATURE.general], @@ -47,6 +53,11 @@ export const gettingStartedLinks: LinkItem = { export const detectionResponseLinks: LinkItem = { id: SecurityPageName.detectionAndResponse, title: DETECTION_RESPONSE, + landingImage: detectionResponsePageImg, + description: i18n.translate('xpack.securitySolution.appLinks.detectionAndResponseDescription', { + defaultMessage: + "Monitor the impact of application and device performance from the end user's point of view.", + }), path: DETECTION_RESPONSE_PATH, globalNavEnabled: false, experimentalKey: 'detectionResponseEnabled', diff --git a/x-pack/plugins/security_solution/public/users/links.ts b/x-pack/plugins/security_solution/public/users/links.ts index bd7bef4af8e82f2..c7176ec11daefd2 100644 --- a/x-pack/plugins/security_solution/public/users/links.ts +++ b/x-pack/plugins/security_solution/public/users/links.ts @@ -9,10 +9,15 @@ import { i18n } from '@kbn/i18n'; import { SecurityPageName, USERS_PATH } from '../../common/constants'; import { USERS } from '../app/translations'; import { LinkItem } from '../common/links/types'; +import userPageImg from '../common/images/users_page.png'; export const links: LinkItem = { id: SecurityPageName.users, title: USERS, + landingImage: userPageImg, + description: i18n.translate('xpack.securitySolution.appLinks.users.description', { + defaultMessage: 'Sudo commands dashboard from the Logs System integration.', + }), path: USERS_PATH, globalNavEnabled: true, experimentalKey: 'usersEnabled',