From ef907a32f2ca3885d60aebd4875f5c8104ee99b1 Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Thu, 3 Apr 2025 08:38:04 -0700 Subject: [PATCH] [Security Solution] Use static declaration for navigation hierarchy (#215969) ## Summary Part of Epic: https://github.com/elastic/kibana-team/issues/1439 Addresses https://github.com/elastic/kibana/issues/212903, but does not remove the landing page access. The landing page access will be removed in https://github.com/elastic/kibana/pull/210893 **Changes** 1. Converts the declaration of the Security Solution side navigation for serverless and stateful projects into a static declaration, rather than algorithmically parsing registered links to dynamically build the declaration. 2. Updates the contents of the "Assets" panel to prepare for removal of that landing page. 3. Eliminates the top-level nesting of the nav items, which removes the extra space between the project title and the first nav items. See https://github.com/elastic/kibana/pull/215969/commits/45454bdc4d03cc793705fc4cef66f67620a98b59 **Known issue**: Clicking the "Browse integrations" button does not close the secondary nav panel. Doing that will be a relatively simple chore, but will require some changes in the SharedUX chrome-navigation package, as well as the `LinkButton` component in the Security Solution navigation-links package. ### Screenshots Serverless ![static-nav-declaration-security-serverless-3iorteikghiskhgkseh](https://github.com/user-attachments/assets/47bcbea9-7e3c-481e-b1b8-4b13bb5d63b1) Stateful/ECH ![static-nav-declaration-security-stateful-3iorteikghiskhgkseh](https://github.com/user-attachments/assets/3d3c8a0e-95d1-4da7-a657-c824577b6ec1) ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md) - [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 --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- packages/kbn-optimizer/limits.yml | 2 +- .../shared/deeplinks/security/deep_links.ts | 1 + .../translations/translations/fr-FR.json | 7 - .../translations/translations/ja-JP.json | 7 - .../translations/translations/zh-CN.json | 7 - .../security/packages/navigation/links.ts | 2 + .../packages/navigation/src/i18n_strings.ts | 239 ++++ .../packages/navigation/src/links.tsx | 6 + .../packages/navigation/tsconfig.json | 3 +- .../navigation_tree.test.ts.snap | 1266 ----------------- .../public/app/solution_navigation/index.ts | 8 - .../navigation_tree.test.ts | 1102 -------------- .../solution_navigation/navigation_tree.ts | 207 --- .../solution_navigation.tsx | 84 -- .../public/app/solution_navigation/util.ts | 35 - .../plugins/security_solution/public/mocks.ts | 4 - .../public/plugin_contract.ts | 8 - .../plugins/security_solution/public/types.ts | 2 - .../plugins/security_solution/tsconfig.json | 2 - .../side_navigation.test.tsx.snap | 729 ++++++++++ .../navigation/side_navigation.test.tsx | 34 + .../public/navigation/side_navigation.ts | 120 -- .../public/navigation/side_navigation.tsx | 805 +++++++++++ .../side_navigation.test.tsx.snap | 1061 ++++++++++++++ .../ai_soc/ai_soc_navigation.test.ts | 141 -- .../navigation/ai_soc/ai_soc_navigation.ts | 297 +++- .../public/navigation/ai_soc/utils.test.ts | 235 --- .../public/navigation/ai_soc/utils.ts | 29 - .../navigation/security_side_navigation.tsx | 592 ++++++++ .../navigation/side_navigation.test.tsx | 60 + .../public/navigation/side_navigation.ts | 125 +- .../navigation/stack_management_navigation.ts | 162 +++ .../tests/security_sidenav.ts | 2 +- .../e2e/explore/navigation/navigation.cy.ts | 7 +- .../screens/serverless_security_header.ts | 41 +- .../services/ml/security_navigation.ts | 4 +- 36 files changed, 3958 insertions(+), 3478 deletions(-) create mode 100644 x-pack/solutions/security/packages/navigation/src/i18n_strings.ts delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/__snapshots__/navigation_tree.test.ts.snap delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/index.ts delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/navigation_tree.test.ts delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/navigation_tree.ts delete mode 100644 x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/solution_navigation.tsx create mode 100644 x-pack/solutions/security/plugins/security_solution_ess/public/navigation/__snapshots__/side_navigation.test.tsx.snap create mode 100644 x-pack/solutions/security/plugins/security_solution_ess/public/navigation/side_navigation.test.tsx delete mode 100644 x-pack/solutions/security/plugins/security_solution_ess/public/navigation/side_navigation.ts create mode 100644 x-pack/solutions/security/plugins/security_solution_ess/public/navigation/side_navigation.tsx create mode 100644 x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/__snapshots__/side_navigation.test.tsx.snap delete mode 100644 x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/ai_soc_navigation.test.ts delete mode 100644 x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/utils.test.ts delete mode 100644 x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/utils.ts create mode 100644 x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/security_side_navigation.tsx create mode 100644 x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/side_navigation.test.tsx create mode 100644 x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/stack_management_navigation.ts diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index c8a3bdca9327..41e72a5e3399 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -150,7 +150,7 @@ pageLoadAssetSize: searchSynonyms: 20262 security: 81771 securitySolution: 98429 - securitySolutionEss: 31781 + securitySolutionEss: 36000 securitySolutionServerless: 62488 serverless: 16573 serverlessChat: 22715 diff --git a/src/platform/packages/shared/deeplinks/security/deep_links.ts b/src/platform/packages/shared/deeplinks/security/deep_links.ts index f89b05b8d657..120b81af0706 100644 --- a/src/platform/packages/shared/deeplinks/security/deep_links.ts +++ b/src/platform/packages/shared/deeplinks/security/deep_links.ts @@ -27,6 +27,7 @@ export enum SecurityPageName { */ cloudSecurityPostureBenchmarks = 'cloud_security_posture-benchmarks', cloudSecurityPostureDashboard = 'cloud_security_posture-dashboard', + cloudSecurityPostureVulnerabilityDashboard = 'cloud_security_posture-vulnerability_dashboard', cloudSecurityPostureFindings = 'cloud_security_posture-findings', cloudSecurityPostureRules = 'cloud_security_posture-rules', dashboards = 'dashboards', diff --git a/x-pack/platform/plugins/private/translations/translations/fr-FR.json b/x-pack/platform/plugins/private/translations/translations/fr-FR.json index 3d16709e007b..20c2cfcfe183 100644 --- a/x-pack/platform/plugins/private/translations/translations/fr-FR.json +++ b/x-pack/platform/plugins/private/translations/translations/fr-FR.json @@ -41965,13 +41965,6 @@ "xpack.securitySolutionServerless.endpointProtectionUpdates.cardMessage": "Pour modifier les mises à jour de protection, vous devez ajouter au moins Endpoint Complete à votre projet.", "xpack.securitySolutionServerless.endpointProtectionUpdates.cardTitle": "Mises à jour de la protection", "xpack.securitySolutionServerless.entityStoreEnablementCallout.additionalChargesMessage": "Veuillez noter que l'activation de ces fonctionnalités peut entraîner des frais supplémentaires en fonction de votre formule d'abonnement. Examinez attentivement les détails de votre abonnement avant de procéder afin d'éviter des coûts inattendus.", - "xpack.securitySolutionServerless.navLinks.projectSettings.mngt.access": "Accès", - "xpack.securitySolutionServerless.navLinks.projectSettings.mngt.alertsAndInsights": "Alertes et informations exploitables", - "xpack.securitySolutionServerless.navLinks.projectSettings.mngt.content": "Contenu", - "xpack.securitySolutionServerless.navLinks.projectSettings.mngt.data": "Données", - "xpack.securitySolutionServerless.navLinks.projectSettings.mngt.other": "Autre", - "xpack.securitySolutionServerless.navLinks.projectSettings.mngt.usersAndRoles": "Gérer les membres de l'organisation", - "xpack.securitySolutionServerless.navLinks.projectSettings.title": "Paramètres de projet", "xpack.securitySolutionServerless.osquery.paywall.body": "Passez votre licence au niveau {productTypeRequired} pour utiliser les actions de réponse Osquery.", "xpack.securitySolutionServerless.osquery.paywall.title": "Toujours plus avec Security !", "xpack.securitySolutionServerless.rules.endpointSecurity.agentTamperProtection.badgeText": "Endpoint Complete", diff --git a/x-pack/platform/plugins/private/translations/translations/ja-JP.json b/x-pack/platform/plugins/private/translations/translations/ja-JP.json index 0fabaa477d57..d3162bcb1b56 100644 --- a/x-pack/platform/plugins/private/translations/translations/ja-JP.json +++ b/x-pack/platform/plugins/private/translations/translations/ja-JP.json @@ -41937,13 +41937,6 @@ "xpack.securitySolutionServerless.endpointProtectionUpdates.cardMessage": "保護更新を変更するには、少なくともエンドポイント完了をプロジェクトに追加する必要があります。", "xpack.securitySolutionServerless.endpointProtectionUpdates.cardTitle": "保護更新", "xpack.securitySolutionServerless.entityStoreEnablementCallout.additionalChargesMessage": "これらの機能を有効にすると、サブスクリプションプランによっては追加料金が発生する場合があります。想定外の費用を避けるため、続行する前に、プランの詳細を十分に確認してください。", - "xpack.securitySolutionServerless.navLinks.projectSettings.mngt.access": "アクセス", - "xpack.securitySolutionServerless.navLinks.projectSettings.mngt.alertsAndInsights": "アラートとインサイト", - "xpack.securitySolutionServerless.navLinks.projectSettings.mngt.content": "コンテンツ", - "xpack.securitySolutionServerless.navLinks.projectSettings.mngt.data": "データ", - "xpack.securitySolutionServerless.navLinks.projectSettings.mngt.other": "Other", - "xpack.securitySolutionServerless.navLinks.projectSettings.mngt.usersAndRoles": "組織メンバーを管理", - "xpack.securitySolutionServerless.navLinks.projectSettings.title": "プロジェクト設定", "xpack.securitySolutionServerless.osquery.paywall.body": "Osquery Response Actionsを使用するには、ライセンスを{productTypeRequired}にアップグレードしてください。", "xpack.securitySolutionServerless.osquery.paywall.title": "Securityではさまざまなことが可能です!", "xpack.securitySolutionServerless.rules.endpointSecurity.agentTamperProtection.badgeText": "エンドポイント完了", diff --git a/x-pack/platform/plugins/private/translations/translations/zh-CN.json b/x-pack/platform/plugins/private/translations/translations/zh-CN.json index c18f6b375aed..9821d02e3b1d 100644 --- a/x-pack/platform/plugins/private/translations/translations/zh-CN.json +++ b/x-pack/platform/plugins/private/translations/translations/zh-CN.json @@ -42003,13 +42003,6 @@ "xpack.securitySolutionServerless.endpointProtectionUpdates.cardMessage": "要修改防护更新,必须至少将 Endpoint Complete 添加到您的项目。", "xpack.securitySolutionServerless.endpointProtectionUpdates.cardTitle": "防护更新", "xpack.securitySolutionServerless.entityStoreEnablementCallout.additionalChargesMessage": "请注意,激活这些功能可能会产生其他费用,具体取决于您的订阅计划。请仔细复查您的计划详情,以避免出现意外成本,然后继续。", - "xpack.securitySolutionServerless.navLinks.projectSettings.mngt.access": "访问", - "xpack.securitySolutionServerless.navLinks.projectSettings.mngt.alertsAndInsights": "告警和洞见", - "xpack.securitySolutionServerless.navLinks.projectSettings.mngt.content": "内容", - "xpack.securitySolutionServerless.navLinks.projectSettings.mngt.data": "数据", - "xpack.securitySolutionServerless.navLinks.projectSettings.mngt.other": "其他", - "xpack.securitySolutionServerless.navLinks.projectSettings.mngt.usersAndRoles": "管理组织成员", - "xpack.securitySolutionServerless.navLinks.projectSettings.title": "项目设置", "xpack.securitySolutionServerless.osquery.paywall.body": "将您的许可证升级到{productTypeRequired}以使用 Osquery 响应操作。", "xpack.securitySolutionServerless.osquery.paywall.title": "Security 让您事半功倍!", "xpack.securitySolutionServerless.rules.endpointSecurity.agentTamperProtection.badgeText": "Endpoint Complete", diff --git a/x-pack/solutions/security/packages/navigation/links.ts b/x-pack/solutions/security/packages/navigation/links.ts index e2c4d1766e6b..0d24e94c039a 100644 --- a/x-pack/solutions/security/packages/navigation/links.ts +++ b/x-pack/solutions/security/packages/navigation/links.ts @@ -5,6 +5,7 @@ * 2.0. */ +export { i18nStrings } from './src/i18n_strings'; export { useGetLinkUrl, useGetLinkProps, @@ -12,5 +13,6 @@ export { LinkButton, LinkAnchor, isSecurityId, + securityLink, } from './src/links'; export type { GetLinkUrl, GetLinkProps, LinkProps } from './src/links'; diff --git a/x-pack/solutions/security/packages/navigation/src/i18n_strings.ts b/x-pack/solutions/security/packages/navigation/src/i18n_strings.ts new file mode 100644 index 000000000000..a9774f24bb27 --- /dev/null +++ b/x-pack/solutions/security/packages/navigation/src/i18n_strings.ts @@ -0,0 +1,239 @@ +/* + * 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'; + +export const i18nStrings = { + rules: { + title: i18n.translate('securitySolutionPackages.navLinks.rules', { + defaultMessage: 'Rules', + }), + management: { + title: i18n.translate('securitySolutionPackages.navLinks.rules.management', { + defaultMessage: 'Management', + }), + siemMigrationsRules: i18n.translate( + 'securitySolutionPackages.navLinks.rules.management.siemRuleMigrations', + { defaultMessage: 'SIEM rule migrations' } + ), + discover: i18n.translate('securitySolutionPackages.navLinks.rules.discover', { + defaultMessage: 'Discover', + }), + }, + }, + investigations: { + title: i18n.translate('securitySolutionPackages.navLinks.investigations', { + defaultMessage: 'Investigations', + }), + }, + explore: { + title: i18n.translate('securitySolutionPackages.navLinks.explore', { + defaultMessage: 'Explore', + }), + }, + assets: { + title: i18n.translate('securitySolutionPackages.navLinks.assets', { + defaultMessage: 'Assets', + }), + fleet: { + title: i18n.translate('securitySolutionPackages.navLinks.assets.fleet', { + defaultMessage: 'Fleet', + }), + policies: i18n.translate('securitySolutionPackages.navLinks.assets.fleetPolicies', { + defaultMessage: 'Policies', + }), + }, + endpoints: { + title: i18n.translate('securitySolutionPackages.navLinks.assets.endpoints', { + defaultMessage: 'Endpoints', + }), + }, + integrationsCallout: { + title: i18n.translate('securitySolutionPackages.navLinks.assets.integrationsCallout.title', { + defaultMessage: 'Integrations', + }), + body: i18n.translate('securitySolutionPackages.navLinks.assets.integrationsCallout.body', { + defaultMessage: 'Choose an integration to start collecting and analyzing your data.', + }), + button: i18n.translate( + 'securitySolutionPackages.navLinks.assets.integrationsCallout.button', + { defaultMessage: 'Browse integrations' } + ), + }, + }, + ml: { + title: i18n.translate('securitySolutionPackages.navLinks.ml', { + defaultMessage: 'Machine learning', + }), + overview: i18n.translate('securitySolutionPackages.navLinks.ml.overview', { + defaultMessage: 'Overview', + }), + notifications: i18n.translate('securitySolutionPackages.navLinks.ml.notifications', { + defaultMessage: 'Notifications', + }), + memoryUsage: i18n.translate('securitySolutionPackages.navLinks.ml.memoryUsage', { + defaultMessage: 'Memory usage', + }), + anomalyDetection: { + title: i18n.translate('securitySolutionPackages.navLinks.ml.anomalyDetection', { + defaultMessage: 'Anomaly detection', + }), + jobs: i18n.translate('securitySolutionPackages.navLinks.ml.anomalyDetection.jobs', { + defaultMessage: 'Jobs', + }), + anomalyExplorer: i18n.translate( + 'securitySolutionPackages.navLinks.ml.anomalyDetection.anomalyExplorer', + { defaultMessage: 'Anomaly explorer' } + ), + singleMetricViewer: i18n.translate( + 'securitySolutionPackages.navLinks.ml.anomalyDetection.singleMetricViewer', + { defaultMessage: 'Single metric viewer' } + ), + suppliedConfigurations: i18n.translate( + 'securitySolutionPackages.navLinks.ml.anomalyDetection.suppliedConfigurations', + { defaultMessage: 'Supplied configurations' } + ), + settings: i18n.translate('securitySolutionPackages.navLinks.ml.anomalyDetection.settings', { + defaultMessage: 'Settings', + }), + }, + dataFrameAnalytics: { + title: i18n.translate('securitySolutionPackages.navLinks.ml.dataFrameAnalytics', { + defaultMessage: 'Data frame analytics', + }), + jobs: i18n.translate('securitySolutionPackages.navLinks.ml.dataFrameAnalytics.jobs', { + defaultMessage: 'Jobs', + }), + resultExplorer: i18n.translate( + 'securitySolutionPackages.navLinks.ml.dataFrameAnalytics.resultExplorer', + { defaultMessage: 'Result explorer' } + ), + analyticsMap: i18n.translate( + 'securitySolutionPackages.navLinks.ml.dataFrameAnalytics.analyticsMap', + { defaultMessage: 'Analytics map' } + ), + }, + modelManagement: { + title: i18n.translate('securitySolutionPackages.navLinks.ml.modelManagement', { + defaultMessage: 'Model management', + }), + trainedModels: i18n.translate( + 'securitySolutionPackages.navLinks.ml.modelManagement.trainedModels', + { defaultMessage: 'Trained models' } + ), + }, + dataVisualizer: { + title: i18n.translate('securitySolutionPackages.navLinks.ml.dataVisualizer', { + defaultMessage: 'Data visualizer', + }), + fileDataVisualizer: i18n.translate( + 'securitySolutionPackages.navLinks.ml.dataVisualizer.fileDataVisualizer', + { defaultMessage: 'File data visualizer' } + ), + dataViewDataVisualizer: i18n.translate( + 'securitySolutionPackages.navLinks.ml.dataVisualizer.dataViewDataVisualizer', + { defaultMessage: 'Data view data visualizer' } + ), + esqlDataVisualizer: i18n.translate( + 'securitySolutionPackages.navLinks.ml.dataVisualizer.esqlDataVisualizer', + { defaultMessage: 'ES|QL data visualizer' } + ), + dataDrift: i18n.translate('securitySolutionPackages.navLinks.ml.dataVisualizer.dataDrift', { + defaultMessage: 'Data drift', + }), + }, + aiopsLabs: { + title: i18n.translate('securitySolutionPackages.navLinks.ml.aiopsLabs', { + defaultMessage: 'Aiops labs', + }), + logRateAnalysis: i18n.translate( + 'securitySolutionPackages.navLinks.ml.aiopsLabs.logRateAnalysis', + { defaultMessage: 'Log rate analysis' } + ), + logPatternAnalysis: i18n.translate( + 'securitySolutionPackages.navLinks.ml.aiopsLabs.logPatternAnalysis', + { defaultMessage: 'Log pattern analysis' } + ), + changePointDetection: i18n.translate( + 'securitySolutionPackages.navLinks.ml.aiopsLabs.changePointDetection', + { defaultMessage: 'Change point detection' } + ), + }, + }, + entityRiskScore: i18n.translate('securitySolutionPackages.navLinks.entityRiskScore', { + defaultMessage: 'Entity Risk Score', + }), + entityStore: i18n.translate('securitySolutionPackages.navLinks.entityStore', { + defaultMessage: 'Entity Store', + }), + devTools: i18n.translate('securitySolutionPackages.navLinks.devTools', { + defaultMessage: 'Developer tools', + }), + management: { + title: i18n.translate('securitySolutionPackages.navLinks.management.title', { + defaultMessage: 'Management', + }), + }, + projectSettings: { + title: i18n.translate('securitySolutionPackages.navLinks.projectSettings.title', { + defaultMessage: 'Project Settings', + }), + }, + stackManagement: { + title: i18n.translate('securitySolutionPackages.navLinks.mngt.title', { + defaultMessage: 'Stack Management', + }), + ingest: { + title: i18n.translate('securitySolutionPackages.navLinks.mngt.ingest', { + defaultMessage: 'Ingest', + }), + }, + data: { + title: i18n.translate('securitySolutionPackages.navLinks.mngt.data', { + defaultMessage: 'Data', + }), + }, + access: { + title: i18n.translate('securitySolutionPackages.navLinks.mngt.access', { + defaultMessage: 'Access', + }), + usersAndRoles: i18n.translate('securitySolutionPackages.navLinks.mngt.usersAndRoles', { + defaultMessage: 'Manage organization members', + }), + }, + alertsAndInsights: { + title: i18n.translate('securitySolutionPackages.navLinks.mngt.alertsAndInsights', { + defaultMessage: 'Alerts and Insights', + }), + }, + security: { + title: i18n.translate('securitySolutionPackages.navLinks.mngt.security', { + defaultMessage: 'Security', + }), + }, + kibana: { + title: i18n.translate('securitySolutionPackages.navLinks.mngt.kibana', { + defaultMessage: 'Kibana', + }), + }, + content: { + title: i18n.translate('securitySolutionPackages.navLinks.mngt.content', { + defaultMessage: 'Content', + }), + }, + stack: { + title: i18n.translate('securitySolutionPackages.navLinks.mngt.stack', { + defaultMessage: 'Stack', + }), + }, + other: { + title: i18n.translate('securitySolutionPackages.navLinks.mngt.other', { + defaultMessage: 'Other', + }), + }, + }, +}; diff --git a/x-pack/solutions/security/packages/navigation/src/links.tsx b/x-pack/solutions/security/packages/navigation/src/links.tsx index 172d7361a342..f671b971404b 100644 --- a/x-pack/solutions/security/packages/navigation/src/links.tsx +++ b/x-pack/solutions/security/packages/navigation/src/links.tsx @@ -8,6 +8,8 @@ import type { HTMLAttributeAnchorTarget } from 'react'; import React, { type MouseEventHandler, type MouseEvent, useCallback } from 'react'; import { EuiButton, EuiLink, type EuiLinkProps } from '@elastic/eui'; +import type { SecurityPageName } from '@kbn/deeplinks-security'; +import type { AppDeepLinkId } from '@kbn/core-chrome-browser'; import { useGetAppUrl, useNavigateTo } from './navigation'; export interface BaseLinkProps { @@ -170,3 +172,7 @@ export const formatPath = (path: string, urlState: string) => { export const isModified = (event: MouseEvent) => event.metaKey || event.altKey || event.ctrlKey || event.shiftKey; + +export const securityLink = (pageName: SecurityPageName): AppDeepLinkId => { + return `securitySolutionUI:${pageName}`; +}; diff --git a/x-pack/solutions/security/packages/navigation/tsconfig.json b/x-pack/solutions/security/packages/navigation/tsconfig.json index 41296e15768c..1b43e5957291 100644 --- a/x-pack/solutions/security/packages/navigation/tsconfig.json +++ b/x-pack/solutions/security/packages/navigation/tsconfig.json @@ -15,7 +15,8 @@ "kbn_references": [ "@kbn/i18n", "@kbn/core", - "@kbn/deeplinks-security" + "@kbn/deeplinks-security", + "@kbn/core-chrome-browser" ], "exclude": ["target/**/*"] } diff --git a/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/__snapshots__/navigation_tree.test.ts.snap b/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/__snapshots__/navigation_tree.test.ts.snap deleted file mode 100644 index 7674cbad7431..000000000000 --- a/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/__snapshots__/navigation_tree.test.ts.snap +++ /dev/null @@ -1,1266 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`formatNavigationTree creates the navigation tree for serverless 1`] = ` -Object { - "body": Array [ - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "id": "discover:", - "link": "discover", - "title": "Discover", - }, - Object { - "children": Array [ - Object { - "id": "overview", - "link": "securitySolutionUI:overview", - "sideNavStatus": "hidden", - "title": "Overview", - }, - Object { - "id": "detection_response", - "link": "securitySolutionUI:detection_response", - "sideNavStatus": "hidden", - "title": "Detection & Response", - }, - Object { - "id": "cloud_security_posture-dashboard", - "link": "securitySolutionUI:cloud_security_posture-dashboard", - "sideNavStatus": "hidden", - "title": "Cloud Security Posture", - }, - Object { - "id": "cloud_security_posture-vulnerability_dashboard", - "link": "securitySolutionUI:cloud_security_posture-vulnerability_dashboard", - "sideNavStatus": "hidden", - "title": "Cloud Native Vulnerability Management", - }, - Object { - "id": "entity_analytics", - "link": "securitySolutionUI:entity_analytics", - "sideNavStatus": "hidden", - "title": "Entity Analytics", - }, - Object { - "id": "data_quality", - "link": "securitySolutionUI:data_quality", - "sideNavStatus": "hidden", - "title": "Data Quality", - }, - ], - "id": "dashboards", - "link": "securitySolutionUI:dashboards", - "renderAs": "panelOpener", - "title": "Dashboards", - }, - ], - "id": undefined, - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "children": Array [ - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "children": Array [ - Object { - "id": "rules-add", - "link": "securitySolutionUI:rules-add", - "title": "Add Rules", - }, - Object { - "id": "rules-create", - "link": "securitySolutionUI:rules-create", - "title": "Create new rule", - }, - ], - "id": "rules", - "link": "securitySolutionUI:rules", - "title": "Detection rules (SIEM)", - }, - Object { - "id": "cloud_security_posture-benchmarks", - "link": "securitySolutionUI:cloud_security_posture-benchmarks", - "title": "Benchmarks", - }, - Object { - "id": "exceptions", - "link": "securitySolutionUI:exceptions", - "title": "Shared exception lists", - }, - ], - "id": "category-management", - "title": "Management", - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "id": "coverage-overview", - "link": "securitySolutionUI:coverage-overview", - "title": "MITRE ATT&CK® Coverage", - }, - ], - "id": "category-discover", - "title": "Discover", - }, - ], - "id": "rules-landing", - "link": "securitySolutionUI:rules-landing", - "renderAs": "panelOpener", - "title": "Rules", - }, - Object { - "id": "alerts", - "link": "securitySolutionUI:alerts", - "title": "Alerts", - }, - Object { - "id": "attack_discovery", - "link": "securitySolutionUI:attack_discovery", - "title": "Attack discovery", - }, - Object { - "id": "cloud_security_posture-findings", - "link": "securitySolutionUI:cloud_security_posture-findings", - "title": "Findings", - }, - Object { - "children": Array [ - Object { - "id": "cases_create", - "link": "securitySolutionUI:cases_create", - "sideNavStatus": "hidden", - "title": "Create", - }, - Object { - "id": "cases_configure", - "link": "securitySolutionUI:cases_configure", - "sideNavStatus": "hidden", - "title": "Settings", - }, - ], - "id": "cases", - "link": "securitySolutionUI:cases", - "renderAs": "panelOpener", - "title": "Cases", - }, - ], - "id": undefined, - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "id": "timelines-templates", - "link": "securitySolutionUI:timelines-templates", - "sideNavStatus": "hidden", - "title": "Templates", - }, - ], - "id": "timelines", - "link": "securitySolutionUI:timelines", - "title": "Timelines", - }, - Object { - "id": "notes", - "link": "securitySolutionUI:notes", - "title": "Notes", - }, - Object { - "id": "osquery:", - "link": "osquery", - "title": "Osquery", - }, - ], - "id": "investigations", - "link": "securitySolutionUI:investigations", - "renderAs": "panelOpener", - "title": "Investigations", - }, - Object { - "id": "threat_intelligence", - "link": "securitySolutionUI:threat_intelligence", - "title": "Intelligence", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "breadcrumbStatus": "hidden", - "id": "hosts-all", - "link": "securitySolutionUI:hosts-all", - "title": "All hosts", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "hosts-uncommon_processes", - "link": "securitySolutionUI:hosts-uncommon_processes", - "title": "Uncommon Processes", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "hosts-anomalies", - "link": "securitySolutionUI:hosts-anomalies", - "title": "Anomalies", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "hosts-events", - "link": "securitySolutionUI:hosts-events", - "title": "Events", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "hosts-risk", - "link": "securitySolutionUI:hosts-risk", - "title": "Host risk", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "hosts-sessions", - "link": "securitySolutionUI:hosts-sessions", - "title": "Sessions", - }, - ], - "id": "hosts", - "link": "securitySolutionUI:hosts", - "title": "Hosts", - }, - Object { - "children": Array [ - Object { - "breadcrumbStatus": "hidden", - "id": "network-flows", - "link": "securitySolutionUI:network-flows", - "title": "Flows", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "network-dns", - "link": "securitySolutionUI:network-dns", - "title": "DNS", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "network-http", - "link": "securitySolutionUI:network-http", - "title": "HTTP", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "network-tls", - "link": "securitySolutionUI:network-tls", - "title": "TLS", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "network-anomalies", - "link": "securitySolutionUI:network-anomalies", - "title": "Anomalies", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "network-events", - "link": "securitySolutionUI:network-events", - "title": "Events", - }, - ], - "id": "network", - "link": "securitySolutionUI:network", - "title": "Network", - }, - Object { - "children": Array [ - Object { - "breadcrumbStatus": "hidden", - "id": "users-all", - "link": "securitySolutionUI:users-all", - "title": "All users", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "users-authentications", - "link": "securitySolutionUI:users-authentications", - "title": "Authentications", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "users-anomalies", - "link": "securitySolutionUI:users-anomalies", - "title": "Anomalies", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "users-risk", - "link": "securitySolutionUI:users-risk", - "title": "User risk", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "users-events", - "link": "securitySolutionUI:users-events", - "title": "Events", - }, - ], - "id": "users", - "link": "securitySolutionUI:users", - "title": "Users", - }, - ], - "id": "explore", - "link": "securitySolutionUI:explore", - "renderAs": "panelOpener", - "title": "Explore", - }, - ], - "id": undefined, - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "id": "fleet:agents", - "link": "fleet:agents", - "title": "Agents", - }, - Object { - "id": "fleet:policies", - "link": "fleet:policies", - "title": "Policies", - }, - Object { - "id": "fleet:enrollment_tokens", - "link": "fleet:enrollment_tokens", - "title": "Enrollment tokens", - }, - Object { - "id": "fleet:uninstall_tokens", - "link": "fleet:uninstall_tokens", - "title": "Uninstall tokens", - }, - Object { - "id": "fleet:data_streams", - "link": "fleet:data_streams", - "title": "Data streams", - }, - Object { - "id": "fleet:settings", - "link": "fleet:settings", - "title": "Settings", - }, - ], - "id": "fleet:", - "link": "fleet", - "title": "Fleet", - }, - Object { - "children": Array [ - Object { - "id": "policy", - "link": "securitySolutionUI:policy", - "title": "Policies", - }, - Object { - "id": "trusted_apps", - "link": "securitySolutionUI:trusted_apps", - "title": "Trusted applications", - }, - Object { - "id": "event_filters", - "link": "securitySolutionUI:event_filters", - "title": "Event filters", - }, - Object { - "id": "host_isolation_exceptions", - "link": "securitySolutionUI:host_isolation_exceptions", - "title": "Host isolation exceptions", - }, - Object { - "id": "blocklist", - "link": "securitySolutionUI:blocklist", - "title": "Blocklist", - }, - Object { - "id": "response_actions_history", - "link": "securitySolutionUI:response_actions_history", - "title": "Response actions history", - }, - ], - "id": "endpoints", - "link": "securitySolutionUI:endpoints", - "title": "Endpoints", - }, - ], - "id": "assets", - "link": "securitySolutionUI:assets", - "renderAs": "panelOpener", - "title": "Assets", - }, - ], - "id": undefined, - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "children": Array [ - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "id": "ml:overview", - "link": "ml:overview", - "title": "Overview", - }, - Object { - "id": "ml:notifications", - "link": "ml:notifications", - "title": "Notifications", - }, - Object { - "id": "ml:memoryUsage", - "link": "ml:memoryUsage", - "title": "Memory usage", - }, - ], - "id": undefined, - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "id": "ml:anomalyDetection", - "link": "ml:anomalyDetection", - "title": "Jobs", - }, - Object { - "id": "ml:anomalyExplorer", - "link": "ml:anomalyExplorer", - "title": "Anomaly explorer", - }, - Object { - "id": "ml:singleMetricViewer", - "link": "ml:singleMetricViewer", - "title": "Single metric viewer", - }, - Object { - "id": "ml:suppliedConfigurations", - "link": "ml:suppliedConfigurations", - "title": "Supplied configurations", - }, - Object { - "id": "ml:settings", - "link": "ml:settings", - "title": "Settings", - }, - ], - "id": "category-anomaly_detection", - "title": "Anomaly detection", - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "id": "ml:dataFrameAnalytics", - "link": "ml:dataFrameAnalytics", - "title": "Jobs", - }, - Object { - "id": "ml:resultExplorer", - "link": "ml:resultExplorer", - "title": "Result explorer", - }, - Object { - "id": "ml:analyticsMap", - "link": "ml:analyticsMap", - "title": "Analytics map", - }, - ], - "id": "category-data_frame analytics", - "title": "Data frame analytics", - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "id": "ml:nodesOverview", - "link": "ml:nodesOverview", - "title": "Trained models", - }, - ], - "id": "category-model_management", - "title": "Model management", - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "id": "ml:fileUpload", - "link": "ml:fileUpload", - "title": "File data visualizer", - }, - Object { - "id": "ml:indexDataVisualizer", - "link": "ml:indexDataVisualizer", - "title": "Data view data visualizer", - }, - Object { - "id": "ml:esqlDataVisualizer", - "link": "ml:esqlDataVisualizer", - "title": "ES|QL data visualizer", - }, - Object { - "id": "ml:dataDrift", - "link": "ml:dataDrift", - "title": "Data drift", - }, - ], - "id": "category-data_visualizer", - "title": "Data visualizer", - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "id": "ml:logRateAnalysis", - "link": "ml:logRateAnalysis", - "title": "Log Rate Analysis", - }, - Object { - "id": "ml:logPatternAnalysis", - "link": "ml:logPatternAnalysis", - "title": "Log pattern analysis", - }, - Object { - "id": "ml:changePointDetections", - "link": "ml:changePointDetections", - "title": "Change point detection", - }, - ], - "id": "category-aiops_labs", - "title": "Aiops labs", - }, - ], - "id": "machine_learning-landing", - "link": "securitySolutionUI:machine_learning-landing", - "renderAs": "panelOpener", - "title": "Machine learning", - }, - ], - "id": undefined, - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "id": "entity_analytics-management", - "link": "securitySolutionUI:entity_analytics-management", - "sideNavStatus": "hidden", - "title": "Entity Risk Score", - }, - Object { - "id": "entity_analytics-entity_store_management", - "link": "securitySolutionUI:entity_analytics-entity_store_management", - "sideNavStatus": "hidden", - "title": "Entity Store", - }, - ], - "id": undefined, - }, - ], - "defaultIsCollapsed": false, - "icon": "logoSecurity", - "id": "security_solution_nav", - "isCollapsible": false, - "title": "Security", - "type": "navGroup", - }, - ], - "footer": Array [ - Object { - "icon": "launch", - "link": "securitySolutionUI:get_started", - "title": "Get started", - "type": "navItem", - }, - Object { - "icon": "editorCodeBlock", - "link": "dev_tools", - "title": "Developer tools", - "type": "navItem", - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "link": "management", - "title": "Stack Management", - }, - Object { - "link": "integrations", - "title": "Integrations", - }, - ], - "icon": "gear", - "id": "category-management", - "title": "Management", - "type": "navGroup", - }, - ], -} -`; - -exports[`formatNavigationTree creates the navigation tree for stateful 1`] = ` -Object { - "body": Array [ - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "id": "discover:", - "link": "discover", - "title": "Discover", - }, - Object { - "children": Array [ - Object { - "id": "overview", - "link": "securitySolutionUI:overview", - "sideNavStatus": "hidden", - "title": "Overview", - }, - Object { - "id": "detection_response", - "link": "securitySolutionUI:detection_response", - "sideNavStatus": "hidden", - "title": "Detection & Response", - }, - Object { - "id": "cloud_security_posture-dashboard", - "link": "securitySolutionUI:cloud_security_posture-dashboard", - "sideNavStatus": "hidden", - "title": "Cloud Security Posture", - }, - Object { - "id": "cloud_security_posture-vulnerability_dashboard", - "link": "securitySolutionUI:cloud_security_posture-vulnerability_dashboard", - "sideNavStatus": "hidden", - "title": "Cloud Native Vulnerability Management", - }, - Object { - "id": "entity_analytics", - "link": "securitySolutionUI:entity_analytics", - "sideNavStatus": "hidden", - "title": "Entity Analytics", - }, - Object { - "id": "data_quality", - "link": "securitySolutionUI:data_quality", - "sideNavStatus": "hidden", - "title": "Data Quality", - }, - ], - "id": "dashboards", - "link": "securitySolutionUI:dashboards", - "renderAs": "panelOpener", - "title": "Dashboards", - }, - ], - "id": undefined, - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "children": Array [ - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "children": Array [ - Object { - "id": "rules-add", - "link": "securitySolutionUI:rules-add", - "title": "Add Rules", - }, - Object { - "id": "rules-create", - "link": "securitySolutionUI:rules-create", - "title": "Create new rule", - }, - ], - "id": "rules", - "link": "securitySolutionUI:rules", - "title": "Detection rules (SIEM)", - }, - Object { - "id": "cloud_security_posture-benchmarks", - "link": "securitySolutionUI:cloud_security_posture-benchmarks", - "title": "Benchmarks", - }, - Object { - "id": "exceptions", - "link": "securitySolutionUI:exceptions", - "title": "Shared exception lists", - }, - Object { - "id": "siem_migrations-rules", - "link": "securitySolutionUI:siem_migrations-rules", - "title": "SIEM Rule Migrations", - }, - ], - "id": "category-management", - "title": "Management", - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "id": "coverage-overview", - "link": "securitySolutionUI:coverage-overview", - "title": "MITRE ATT&CK® Coverage", - }, - ], - "id": "category-discover", - "title": "Discover", - }, - ], - "id": "rules-landing", - "link": "securitySolutionUI:rules-landing", - "renderAs": "panelOpener", - "title": "Rules", - }, - Object { - "id": "alerts", - "link": "securitySolutionUI:alerts", - "title": "Alerts", - }, - Object { - "id": "attack_discovery", - "link": "securitySolutionUI:attack_discovery", - "title": "Attack discovery", - }, - Object { - "id": "cloud_security_posture-findings", - "link": "securitySolutionUI:cloud_security_posture-findings", - "title": "Findings", - }, - Object { - "children": Array [ - Object { - "id": "cases_create", - "link": "securitySolutionUI:cases_create", - "sideNavStatus": "hidden", - "title": "Create", - }, - Object { - "id": "cases_configure", - "link": "securitySolutionUI:cases_configure", - "sideNavStatus": "hidden", - "title": "Settings", - }, - ], - "id": "cases", - "link": "securitySolutionUI:cases", - "renderAs": "panelOpener", - "title": "Cases", - }, - ], - "id": undefined, - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "id": "timelines-templates", - "link": "securitySolutionUI:timelines-templates", - "sideNavStatus": "hidden", - "title": "Templates", - }, - ], - "id": "timelines", - "link": "securitySolutionUI:timelines", - "title": "Timelines", - }, - Object { - "id": "notes", - "link": "securitySolutionUI:notes", - "title": "Notes", - }, - Object { - "id": "osquery:", - "link": "osquery", - "title": "Osquery", - }, - ], - "id": "investigations", - "link": "securitySolutionUI:investigations", - "renderAs": "panelOpener", - "title": "Investigations", - }, - Object { - "id": "threat_intelligence", - "link": "securitySolutionUI:threat_intelligence", - "title": "Intelligence", - }, - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "breadcrumbStatus": "hidden", - "id": "hosts-all", - "link": "securitySolutionUI:hosts-all", - "title": "All hosts", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "hosts-uncommon_processes", - "link": "securitySolutionUI:hosts-uncommon_processes", - "title": "Uncommon Processes", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "hosts-anomalies", - "link": "securitySolutionUI:hosts-anomalies", - "title": "Anomalies", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "hosts-events", - "link": "securitySolutionUI:hosts-events", - "title": "Events", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "hosts-risk", - "link": "securitySolutionUI:hosts-risk", - "title": "Host risk", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "hosts-sessions", - "link": "securitySolutionUI:hosts-sessions", - "title": "Sessions", - }, - ], - "id": "hosts", - "link": "securitySolutionUI:hosts", - "title": "Hosts", - }, - Object { - "children": Array [ - Object { - "breadcrumbStatus": "hidden", - "id": "network-flows", - "link": "securitySolutionUI:network-flows", - "title": "Flows", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "network-dns", - "link": "securitySolutionUI:network-dns", - "title": "DNS", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "network-http", - "link": "securitySolutionUI:network-http", - "title": "HTTP", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "network-tls", - "link": "securitySolutionUI:network-tls", - "title": "TLS", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "network-anomalies", - "link": "securitySolutionUI:network-anomalies", - "title": "Anomalies", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "network-events", - "link": "securitySolutionUI:network-events", - "title": "Events", - }, - ], - "id": "network", - "link": "securitySolutionUI:network", - "title": "Network", - }, - Object { - "children": Array [ - Object { - "breadcrumbStatus": "hidden", - "id": "users-all", - "link": "securitySolutionUI:users-all", - "title": "All users", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "users-authentications", - "link": "securitySolutionUI:users-authentications", - "title": "Authentications", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "users-anomalies", - "link": "securitySolutionUI:users-anomalies", - "title": "Anomalies", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "users-risk", - "link": "securitySolutionUI:users-risk", - "title": "User risk", - }, - Object { - "breadcrumbStatus": "hidden", - "id": "users-events", - "link": "securitySolutionUI:users-events", - "title": "Events", - }, - ], - "id": "users", - "link": "securitySolutionUI:users", - "title": "Users", - }, - ], - "id": "explore", - "link": "securitySolutionUI:explore", - "renderAs": "panelOpener", - "title": "Explore", - }, - ], - "id": undefined, - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "children": Array [ - Object { - "children": Array [ - Object { - "id": "fleet:agents", - "link": "fleet:agents", - "title": "Agents", - }, - Object { - "id": "fleet:policies", - "link": "fleet:policies", - "title": "Policies", - }, - Object { - "id": "fleet:enrollment_tokens", - "link": "fleet:enrollment_tokens", - "title": "Enrollment tokens", - }, - Object { - "id": "fleet:uninstall_tokens", - "link": "fleet:uninstall_tokens", - "title": "Uninstall tokens", - }, - Object { - "id": "fleet:data_streams", - "link": "fleet:data_streams", - "title": "Data streams", - }, - Object { - "id": "fleet:settings", - "link": "fleet:settings", - "title": "Settings", - }, - ], - "id": "fleet:", - "link": "fleet", - "title": "Fleet", - }, - Object { - "children": Array [ - Object { - "id": "policy", - "link": "securitySolutionUI:policy", - "title": "Policies", - }, - Object { - "id": "trusted_apps", - "link": "securitySolutionUI:trusted_apps", - "title": "Trusted applications", - }, - Object { - "id": "event_filters", - "link": "securitySolutionUI:event_filters", - "title": "Event filters", - }, - Object { - "id": "host_isolation_exceptions", - "link": "securitySolutionUI:host_isolation_exceptions", - "title": "Host isolation exceptions", - }, - Object { - "id": "blocklist", - "link": "securitySolutionUI:blocklist", - "title": "Blocklist", - }, - Object { - "id": "response_actions_history", - "link": "securitySolutionUI:response_actions_history", - "title": "Response actions history", - }, - ], - "id": "endpoints", - "link": "securitySolutionUI:endpoints", - "title": "Endpoints", - }, - ], - "id": "assets", - "link": "securitySolutionUI:assets", - "renderAs": "panelOpener", - "title": "Assets", - }, - ], - "id": undefined, - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "children": Array [ - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "id": "ml:overview", - "link": "ml:overview", - "title": "Overview", - }, - Object { - "id": "ml:notifications", - "link": "ml:notifications", - "title": "Notifications", - }, - Object { - "id": "ml:memoryUsage", - "link": "ml:memoryUsage", - "title": "Memory usage", - }, - ], - "id": undefined, - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "id": "ml:anomalyDetection", - "link": "ml:anomalyDetection", - "title": "Jobs", - }, - Object { - "id": "ml:anomalyExplorer", - "link": "ml:anomalyExplorer", - "title": "Anomaly explorer", - }, - Object { - "id": "ml:singleMetricViewer", - "link": "ml:singleMetricViewer", - "title": "Single metric viewer", - }, - Object { - "id": "ml:suppliedConfigurations", - "link": "ml:suppliedConfigurations", - "title": "Supplied configurations", - }, - Object { - "id": "ml:settings", - "link": "ml:settings", - "title": "Settings", - }, - ], - "id": "category-anomaly_detection", - "title": "Anomaly detection", - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "id": "ml:dataFrameAnalytics", - "link": "ml:dataFrameAnalytics", - "title": "Jobs", - }, - Object { - "id": "ml:resultExplorer", - "link": "ml:resultExplorer", - "title": "Result explorer", - }, - Object { - "id": "ml:analyticsMap", - "link": "ml:analyticsMap", - "title": "Analytics map", - }, - ], - "id": "category-data_frame analytics", - "title": "Data frame analytics", - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "id": "ml:nodesOverview", - "link": "ml:nodesOverview", - "title": "Trained models", - }, - ], - "id": "category-model_management", - "title": "Model management", - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "id": "ml:fileUpload", - "link": "ml:fileUpload", - "title": "File data visualizer", - }, - Object { - "id": "ml:indexDataVisualizer", - "link": "ml:indexDataVisualizer", - "title": "Data view data visualizer", - }, - Object { - "id": "ml:esqlDataVisualizer", - "link": "ml:esqlDataVisualizer", - "title": "ES|QL data visualizer", - }, - Object { - "id": "ml:dataDrift", - "link": "ml:dataDrift", - "title": "Data drift", - }, - ], - "id": "category-data_visualizer", - "title": "Data visualizer", - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "id": "ml:logRateAnalysis", - "link": "ml:logRateAnalysis", - "title": "Log Rate Analysis", - }, - Object { - "id": "ml:logPatternAnalysis", - "link": "ml:logPatternAnalysis", - "title": "Log pattern analysis", - }, - Object { - "id": "ml:changePointDetections", - "link": "ml:changePointDetections", - "title": "Change point detection", - }, - ], - "id": "category-aiops_labs", - "title": "Aiops labs", - }, - ], - "id": "machine_learning-landing", - "link": "securitySolutionUI:machine_learning-landing", - "renderAs": "panelOpener", - "title": "Machine learning", - }, - ], - "id": undefined, - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "id": "entity_analytics-management", - "link": "securitySolutionUI:entity_analytics-management", - "sideNavStatus": "hidden", - "title": "Entity Risk Score", - }, - Object { - "id": "entity_analytics-entity_store_management", - "link": "securitySolutionUI:entity_analytics-entity_store_management", - "sideNavStatus": "hidden", - "title": "Entity Store", - }, - ], - "id": undefined, - }, - ], - "defaultIsCollapsed": false, - "icon": "logoSecurity", - "id": "security_solution_nav", - "isCollapsible": false, - "title": "Security", - "type": "navGroup", - }, - ], - "footer": Array [ - Object { - "icon": "launch", - "link": "securitySolutionUI:get_started", - "title": "Get started", - "type": "navItem", - }, - Object { - "icon": "editorCodeBlock", - "link": "dev_tools", - "title": "Developer tools", - "type": "navItem", - }, - Object { - "breadcrumbStatus": "hidden", - "children": Array [ - Object { - "link": "management", - "title": "Stack Management", - }, - Object { - "link": "monitoring", - "title": "Stack Monitoring", - }, - Object { - "link": "integrations", - "title": "Integrations", - }, - ], - "icon": "gear", - "id": "category-management", - "title": "Management", - "type": "navGroup", - }, - ], -} -`; diff --git a/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/index.ts b/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/index.ts deleted file mode 100644 index 6f159dc2be53..000000000000 --- a/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/index.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -export { getSolutionNavigation } from './solution_navigation'; diff --git a/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/navigation_tree.test.ts b/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/navigation_tree.test.ts deleted file mode 100644 index cc2d9b8e3b7c..000000000000 --- a/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/navigation_tree.test.ts +++ /dev/null @@ -1,1102 +0,0 @@ -/* - * 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 type { SolutionLinkCategory, SolutionNavLink } from '../../common/links'; -import { formatNavigationTree } from './navigation_tree'; - -describe('formatNavigationTree', () => { - test('creates the navigation tree for stateful', () => { - const solutionNavLinks = [ - { - id: 'dashboards', - title: 'Dashboards', - skipUrlState: false, - links: [ - { - id: 'overview', - title: 'Overview', - description: - 'Summary of your security environment activity, including alerts, events, recent items, and a news feed!', - landingImage: - '/XXXXXXXXXXXX/bundles/plugin/securitySolution/1.0.0/87e5860cdcd749a7.png', - }, - { - id: 'detection_response', - title: 'Detection & Response', - description: - 'Information about your Alerts and Cases within the Security Solution, including Hosts and Users with Alerts.', - landingImage: - '/XXXXXXXXXXXX/bundles/plugin/securitySolution/1.0.0/6ee57fbd46b6f258.png', - }, - { - id: 'cloud_security_posture-dashboard', - title: 'Cloud Security Posture', - description: 'An overview of findings across all CSP integrations.', - landingImage: - '/XXXXXXXXXXXX/bundles/plugin/securitySolution/1.0.0/d6dc7207d7b53949.png', - }, - { - id: 'cloud_security_posture-vulnerability_dashboard', - title: 'Cloud Native Vulnerability Management', - description: - 'Cloud Native Vulnerability Management (CNVM) allows you to identify vulnerabilities in your cloud workloads.', - landingImage: - '/XXXXXXXXXXXX/bundles/plugin/securitySolution/1.0.0/d40d1de2a50c69e9.png', - }, - { - id: 'entity_analytics', - title: 'Entity Analytics', - description: - 'Entity analytics, anomalies, and threats to narrow down the monitoring surface area.', - landingImage: - '/XXXXXXXXXXXX/bundles/plugin/securitySolution/1.0.0/39655a2668786e83.png', - isBeta: false, - }, - { - id: 'data_quality', - title: 'Data Quality', - description: - 'Check index mappings and values for compatibility with the Elastic Common Schema (ECS)', - landingImage: - '/XXXXXXXXXXXX/bundles/plugin/securitySolution/1.0.0/83ddb143ca02889a.png', - }, - ], - }, - { id: 'alerts', title: 'Alerts' }, - { id: 'attack_discovery', title: 'Attack discovery' }, - { id: 'cloud_security_posture-findings', title: 'Findings' }, - { - id: 'cases', - title: 'Cases', - links: [ - { id: 'cases_create', title: 'Create', disabled: true }, - { id: 'cases_configure', title: 'Settings', disabled: true }, - ], - }, - { - id: 'threat_intelligence', - title: 'Intelligence', - description: - 'Elastic threat intelligence helps you see if you are open to or have been subject to current or historical known threats.', - }, - { - id: 'explore', - title: 'Explore', - skipUrlState: true, - links: [ - { - id: 'hosts', - title: 'Hosts', - description: 'A comprehensive overview of all hosts and host-related security events.', - landingImage: - '/XXXXXXXXXXXX/bundles/plugin/securitySolution/1.0.0/f0d892a24aca5c21.png', - links: [ - { id: 'hosts-all', title: 'All hosts', isBeta: false }, - { id: 'hosts-uncommon_processes', title: 'Uncommon Processes' }, - { id: 'hosts-anomalies', title: 'Anomalies' }, - { id: 'hosts-events', title: 'Events' }, - { id: 'hosts-risk', title: 'Host risk' }, - { id: 'hosts-sessions', title: 'Sessions', isBeta: false }, - ], - }, - { - id: 'network', - title: 'Network', - description: - 'Provides key activity metrics in an interactive map as well as event tables that enable interaction with the Timeline.', - landingImage: - '/XXXXXXXXXXXX/bundles/plugin/securitySolution/1.0.0/9473122fa26519cd.png', - links: [ - { id: 'network-flows', title: 'Flows' }, - { id: 'network-dns', title: 'DNS' }, - { id: 'network-http', title: 'HTTP' }, - { id: 'network-tls', title: 'TLS' }, - { id: 'network-anomalies', title: 'Anomalies' }, - { id: 'network-events', title: 'Events' }, - ], - }, - { - id: 'users', - title: 'Users', - description: - 'A comprehensive overview of user data that enables understanding of authentication and user behavior within your environment.', - landingImage: - '/XXXXXXXXXXXX/bundles/plugin/securitySolution/1.0.0/fd3fbca6f8f1d5fa.png', - links: [ - { id: 'users-all', title: 'All users' }, - { id: 'users-authentications', title: 'Authentications' }, - { id: 'users-anomalies', title: 'Anomalies' }, - { id: 'users-risk', title: 'User risk' }, - { id: 'users-events', title: 'Events' }, - ], - }, - ], - }, - { - id: 'rules-landing', - title: 'Rules', - categories: [ - { - label: 'Management', - linkIds: [ - 'rules', - 'cloud_security_posture-benchmarks', - 'exceptions', - 'siem_migrations-rules', - ], - }, - { label: 'Discover', linkIds: ['coverage-overview'] }, - ], - skipUrlState: true, - links: [ - { - id: 'rules', - title: 'Detection rules (SIEM)', - description: 'Create and manage detection rules for threat detection and monitoring.', - links: [ - { id: 'rules-add', title: 'Add Rules', skipUrlState: true }, - { id: 'rules-create', title: 'Create new rule', skipUrlState: true }, - ], - }, - { - id: 'exceptions', - title: 'Shared exception lists', - description: - 'Create and manage shared exception lists to prevent the creation of unwanted alerts.', - skipUrlState: true, - }, - { - id: 'cloud_security_posture-benchmarks', - title: 'Benchmarks', - description: 'View benchmark rules for Cloud Security Posture management.', - }, - { - id: 'coverage-overview', - title: 'MITRE ATT&CK® Coverage', - description: 'Review and maintain your protections MITRE ATT&CK® coverage.', - }, - { - id: 'siem_migrations-rules', - title: 'SIEM Rule Migrations', - description: - 'Our generative AI powered SIEM migration tool automates some of the most time consuming migrations tasks and processed.', - skipUrlState: true, - isBeta: true, - betaOptions: { text: 'Technical Preview' }, - }, - ], - }, - { - id: 'get_started', - title: 'Get started', - sideNavIcon: 'launch', - isFooterLink: true, - skipUrlState: true, - }, - { - id: 'assets', - title: 'Assets', - skipUrlState: true, - links: [ - { - id: 'fleet:', - title: 'Fleet', - description: 'Centralized management for Elastic Agents', - links: [ - { id: 'fleet:agents', title: 'Agents' }, - { id: 'fleet:policies', title: 'Policies' }, - { id: 'fleet:enrollment_tokens', title: 'Enrollment tokens' }, - { id: 'fleet:uninstall_tokens', title: 'Uninstall tokens' }, - { id: 'fleet:data_streams', title: 'Data streams' }, - { id: 'fleet:settings', title: 'Settings' }, - ], - }, - { - id: 'endpoints', - title: 'Endpoints', - description: 'Hosts running Elastic Defend.', - skipUrlState: true, - links: [ - { - id: 'policy', - title: 'Policies', - description: - 'Use policies to customize endpoint and cloud workload protections and other configurations.', - skipUrlState: true, - }, - { - id: 'trusted_apps', - title: 'Trusted applications', - description: - 'Improve performance or alleviate conflicts with other applications running on your hosts.', - skipUrlState: true, - }, - { - id: 'event_filters', - title: 'Event filters', - description: - 'Exclude high volume or unwanted events being written into Elasticsearch.', - skipUrlState: true, - }, - { - id: 'host_isolation_exceptions', - title: 'Host isolation exceptions', - description: 'Allow isolated hosts to communicate with specific IPs.', - skipUrlState: true, - }, - { - id: 'blocklist', - title: 'Blocklist', - description: 'Exclude unwanted applications from running on your hosts.', - skipUrlState: true, - }, - { - id: 'response_actions_history', - title: 'Response actions history', - description: 'View the history of response actions performed on hosts.', - skipUrlState: true, - }, - ], - }, - ], - }, - { - id: 'entity_analytics-management', - title: 'Entity Risk Score', - description: "Monitor entities' risk scores, and track anomalies.", - disabled: true, - skipUrlState: true, - }, - { - id: 'entity_analytics-entity_store_management', - title: 'Entity Store', - description: 'Store data for entities observed in events.', - disabled: true, - skipUrlState: true, - }, - { - id: 'investigations', - title: 'Investigations', - skipUrlState: true, - links: [ - { - id: 'timelines', - title: 'Timelines', - description: 'Central place for timelines and timeline templates', - links: [{ id: 'timelines-templates', title: 'Templates', disabled: true }], - }, - { - id: 'notes', - title: 'Notes', - description: - 'Oversee, revise, and revisit the notes attached to alerts, events and Timelines.', - landingIcon: 'filebeatApp', - skipUrlState: true, - }, - { - id: 'osquery:', - title: 'Osquery', - description: - 'Deploy Osquery with Elastic Agent, then run and schedule queries in Kibana', - }, - ], - }, - { - id: 'machine_learning-landing', - title: 'Machine learning', - skipUrlState: true, - categories: [ - { type: 'separator', linkIds: ['ml:overview', 'ml:notifications', 'ml:memoryUsage'] }, - { - type: 'title', - label: 'Anomaly detection', - linkIds: [ - 'ml:anomalyDetection', - 'ml:anomalyExplorer', - 'ml:singleMetricViewer', - 'ml:suppliedConfigurations', - 'ml:settings', - ], - }, - { - type: 'title', - label: 'Data frame analytics', - linkIds: ['ml:dataFrameAnalytics', 'ml:resultExplorer', 'ml:analyticsMap'], - }, - { type: 'title', label: 'Model management', linkIds: ['ml:nodesOverview'] }, - { - type: 'title', - label: 'Data visualizer', - linkIds: [ - 'ml:fileUpload', - 'ml:indexDataVisualizer', - 'ml:esqlDataVisualizer', - 'ml:dataDrift', - ], - }, - { - type: 'title', - label: 'Aiops labs', - linkIds: ['ml:logRateAnalysis', 'ml:logPatternAnalysis', 'ml:changePointDetections'], - }, - ], - links: [ - { id: 'ml:overview', title: 'Overview', description: 'Overview page' }, - { id: 'ml:notifications', title: 'Notifications', description: 'Notifications page' }, - { id: 'ml:memoryUsage', title: 'Memory usage', description: 'Memory usage page' }, - { id: 'ml:anomalyDetection', title: 'Jobs', description: 'Jobs page' }, - { - id: 'ml:anomalyExplorer', - title: 'Anomaly explorer', - description: 'Anomaly explorer page', - }, - { - id: 'ml:singleMetricViewer', - title: 'Single metric viewer', - description: 'Single metric viewer page', - }, - { - id: 'ml:suppliedConfigurations', - title: 'Supplied configurations', - description: 'Supplied configurations page', - }, - { id: 'ml:settings', title: 'Settings', description: 'Settings page' }, - { id: 'ml:dataFrameAnalytics', title: 'Jobs', description: 'Jobs page' }, - { - id: 'ml:resultExplorer', - title: 'Result explorer', - description: 'Result explorer page', - }, - { id: 'ml:analyticsMap', title: 'Analytics map', description: 'Analytics map page' }, - { id: 'ml:nodesOverview', title: 'Trained models', description: 'Trained models page' }, - { - id: 'ml:fileUpload', - title: 'File data visualizer', - description: 'File data visualizer page', - }, - { - id: 'ml:indexDataVisualizer', - title: 'Data view data visualizer', - description: 'Data view data visualizer page', - }, - { - id: 'ml:esqlDataVisualizer', - title: 'ES|QL data visualizer', - landingIcon: 'sqlApp', - description: 'ES|QL data visualizer page', - }, - { id: 'ml:dataDrift', title: 'Data drift', description: 'Data drift' }, - { - id: 'ml:logRateAnalysis', - title: 'Log Rate Analysis', - description: 'Log Rate Analysis Page', - }, - { - id: 'ml:logPatternAnalysis', - title: 'Log pattern analysis', - description: 'Log pattern analysis page', - }, - { - id: 'ml:changePointDetections', - title: 'Change point detection', - description: 'Change point detection page', - }, - ], - }, - { id: 'discover:', title: 'Discover' }, - { - id: 'dev_tools:', - title: 'Developer tools', - sideNavIcon: 'editorCodeBlock', - isFooterLink: true, - }, - { id: 'management:', title: 'Stack Management', isFooterLink: true }, - { id: 'monitoring:', title: 'Stack Monitoring', isFooterLink: true }, - { id: 'integrations:/browse/security', title: 'Integrations', isFooterLink: true }, - { - id: 'maps:', - title: 'Maps', - description: - 'Analyze geospatial data and identify geo patterns in multiple layers and indices.', - landingIcon: 'graphApp', - disabled: true, - }, - { - id: 'visualize:', - title: 'Visualize library', - description: 'Manage visualization library. Create, edit, and share visualizations.', - landingIcon: 'visualizeApp', - disabled: true, - }, - ] as SolutionNavLink[]; - - const bodyCategories = [ - { type: 'separator', linkIds: ['discover:', 'dashboards'] }, - { - type: 'separator', - linkIds: [ - 'rules-landing', - 'alerts', - 'attack_discovery', - 'cloud_security_posture-findings', - 'cases', - ], - }, - { type: 'separator', linkIds: ['investigations', 'threat_intelligence', 'explore'] }, - { type: 'separator', linkIds: ['asset_inventory'] }, - { type: 'separator', linkIds: ['assets'] }, - { type: 'separator', linkIds: ['machine_learning-landing'] }, - { - type: 'separator', - linkIds: ['entity_analytics-management', 'entity_analytics-entity_store_management'], - }, - ] as SolutionLinkCategory[]; - - const footerCategories = [ - { type: 'separator', linkIds: ['get_started', 'dev_tools:'] }, - { - type: 'accordion', - label: 'Management', - iconType: 'gear', - linkIds: ['management:', 'monitoring:', 'integrations:/browse/security'], - }, - ] as SolutionLinkCategory[]; - - expect( - formatNavigationTree(solutionNavLinks, bodyCategories, footerCategories) - ).toMatchSnapshot(); - }); - - test('creates the navigation tree for serverless', () => { - const solutionNavLinks = [ - { - id: 'dashboards', - title: 'Dashboards', - skipUrlState: false, - links: [ - { - id: 'overview', - title: 'Overview', - description: - 'Summary of your security environment activity, including alerts, events, recent items, and a news feed!', - landingImage: - '/XXXXXXXXXXXX/bundles/plugin/securitySolution/1.0.0/87e5860cdcd749a7.png', - }, - { - id: 'detection_response', - title: 'Detection & Response', - description: - 'Information about your Alerts and Cases within the Security Solution, including Hosts and Users with Alerts.', - landingImage: - '/XXXXXXXXXXXX/bundles/plugin/securitySolution/1.0.0/6ee57fbd46b6f258.png', - }, - { - id: 'cloud_security_posture-dashboard', - title: 'Cloud Security Posture', - description: 'An overview of findings across all CSP integrations.', - landingImage: - '/XXXXXXXXXXXX/bundles/plugin/securitySolution/1.0.0/d6dc7207d7b53949.png', - }, - { - id: 'cloud_security_posture-vulnerability_dashboard', - title: 'Cloud Native Vulnerability Management', - description: - 'Cloud Native Vulnerability Management (CNVM) allows you to identify vulnerabilities in your cloud workloads.', - landingImage: - '/XXXXXXXXXXXX/bundles/plugin/securitySolution/1.0.0/d40d1de2a50c69e9.png', - }, - { - id: 'entity_analytics', - title: 'Entity Analytics', - description: - 'Entity analytics, anomalies, and threats to narrow down the monitoring surface area.', - landingImage: - '/XXXXXXXXXXXX/bundles/plugin/securitySolution/1.0.0/39655a2668786e83.png', - isBeta: false, - }, - { - id: 'data_quality', - title: 'Data Quality', - description: - 'Check index mappings and values for compatibility with the Elastic Common Schema (ECS)', - landingImage: - '/XXXXXXXXXXXX/bundles/plugin/securitySolution/1.0.0/83ddb143ca02889a.png', - }, - ], - }, - { - id: 'alerts', - title: 'Alerts', - }, - { - id: 'attack_discovery', - title: 'Attack discovery', - }, - { - id: 'cloud_security_posture-findings', - title: 'Findings', - }, - { - id: 'cases', - title: 'Cases', - links: [ - { - id: 'cases_create', - title: 'Create', - disabled: true, - }, - { - id: 'cases_configure', - title: 'Settings', - disabled: true, - }, - ], - }, - { - id: 'threat_intelligence', - title: 'Intelligence', - description: - 'Elastic threat intelligence helps you see if you are open to or have been subject to current or historical known threats.', - }, - { - id: 'explore', - title: 'Explore', - skipUrlState: true, - links: [ - { - id: 'hosts', - title: 'Hosts', - description: 'A comprehensive overview of all hosts and host-related security events.', - landingImage: - '/XXXXXXXXXXXX/bundles/plugin/securitySolution/1.0.0/f0d892a24aca5c21.png', - links: [ - { - id: 'hosts-all', - title: 'All hosts', - isBeta: false, - }, - { - id: 'hosts-uncommon_processes', - title: 'Uncommon Processes', - }, - { - id: 'hosts-anomalies', - title: 'Anomalies', - }, - { - id: 'hosts-events', - title: 'Events', - }, - { - id: 'hosts-risk', - title: 'Host risk', - }, - { - id: 'hosts-sessions', - title: 'Sessions', - isBeta: false, - }, - ], - }, - { - id: 'network', - title: 'Network', - description: - 'Provides key activity metrics in an interactive map as well as event tables that enable interaction with the Timeline.', - landingImage: - '/XXXXXXXXXXXX/bundles/plugin/securitySolution/1.0.0/9473122fa26519cd.png', - links: [ - { - id: 'network-flows', - title: 'Flows', - }, - { - id: 'network-dns', - title: 'DNS', - }, - { - id: 'network-http', - title: 'HTTP', - }, - { - id: 'network-tls', - title: 'TLS', - }, - { - id: 'network-anomalies', - title: 'Anomalies', - }, - { - id: 'network-events', - title: 'Events', - }, - ], - }, - { - id: 'users', - title: 'Users', - description: - 'A comprehensive overview of user data that enables understanding of authentication and user behavior within your environment.', - landingImage: - '/XXXXXXXXXXXX/bundles/plugin/securitySolution/1.0.0/fd3fbca6f8f1d5fa.png', - links: [ - { - id: 'users-all', - title: 'All users', - }, - { - id: 'users-authentications', - title: 'Authentications', - }, - { - id: 'users-anomalies', - title: 'Anomalies', - }, - { - id: 'users-risk', - title: 'User risk', - }, - { - id: 'users-events', - title: 'Events', - }, - ], - }, - ], - }, - { - id: 'rules-landing', - title: 'Rules', - categories: [ - { - label: 'Management', - linkIds: [ - 'rules', - 'cloud_security_posture-benchmarks', - 'exceptions', - 'siem_migrations-rules', - ], - }, - { - label: 'Discover', - linkIds: ['coverage-overview'], - }, - ], - skipUrlState: true, - links: [ - { - id: 'rules', - title: 'Detection rules (SIEM)', - description: 'Create and manage detection rules for threat detection and monitoring.', - links: [ - { - id: 'rules-add', - title: 'Add Rules', - skipUrlState: true, - }, - { - id: 'rules-create', - title: 'Create new rule', - skipUrlState: true, - }, - ], - }, - { - id: 'exceptions', - title: 'Shared exception lists', - description: - 'Create and manage shared exception lists to prevent the creation of unwanted alerts.', - skipUrlState: true, - }, - { - id: 'cloud_security_posture-benchmarks', - title: 'Benchmarks', - description: 'View benchmark rules for Cloud Security Posture management.', - }, - { - id: 'coverage-overview', - title: 'MITRE ATT&CK® Coverage', - description: 'Review and maintain your protections MITRE ATT&CK® coverage.', - }, - ], - }, - { - id: 'get_started', - title: 'Get started', - sideNavIcon: 'launch', - isFooterLink: true, - skipUrlState: true, - }, - { - id: 'assets', - title: 'Assets', - skipUrlState: true, - links: [ - { - id: 'fleet:', - title: 'Fleet', - description: 'Centralized management for Elastic Agents', - links: [ - { - id: 'fleet:agents', - title: 'Agents', - }, - { - id: 'fleet:policies', - title: 'Policies', - }, - { - id: 'fleet:enrollment_tokens', - title: 'Enrollment tokens', - }, - { - id: 'fleet:uninstall_tokens', - title: 'Uninstall tokens', - }, - { - id: 'fleet:data_streams', - title: 'Data streams', - }, - { - id: 'fleet:settings', - title: 'Settings', - }, - ], - }, - { - id: 'endpoints', - title: 'Endpoints', - description: 'Hosts running Elastic Defend.', - skipUrlState: true, - links: [ - { - id: 'policy', - title: 'Policies', - description: - 'Use policies to customize endpoint and cloud workload protections and other configurations.', - skipUrlState: true, - }, - { - id: 'trusted_apps', - title: 'Trusted applications', - description: - 'Improve performance or alleviate conflicts with other applications running on your hosts.', - skipUrlState: true, - }, - { - id: 'event_filters', - title: 'Event filters', - description: - 'Exclude high volume or unwanted events being written into Elasticsearch.', - skipUrlState: true, - }, - { - id: 'host_isolation_exceptions', - title: 'Host isolation exceptions', - description: 'Allow isolated hosts to communicate with specific IPs.', - skipUrlState: true, - }, - { - id: 'blocklist', - title: 'Blocklist', - description: 'Exclude unwanted applications from running on your hosts.', - skipUrlState: true, - }, - { - id: 'response_actions_history', - title: 'Response actions history', - description: 'View the history of response actions performed on hosts.', - skipUrlState: true, - }, - ], - }, - ], - }, - { - id: 'entity_analytics-management', - title: 'Entity Risk Score', - description: "Monitor entities' risk scores, and track anomalies.", - disabled: true, - skipUrlState: true, - }, - { - id: 'entity_analytics-entity_store_management', - title: 'Entity Store', - description: 'Store data for entities observed in events.', - disabled: true, - skipUrlState: true, - }, - { - id: 'investigations', - title: 'Investigations', - skipUrlState: true, - links: [ - { - id: 'timelines', - title: 'Timelines', - description: 'Central place for timelines and timeline templates', - links: [ - { - id: 'timelines-templates', - title: 'Templates', - disabled: true, - }, - ], - }, - { - id: 'notes', - title: 'Notes', - description: - 'Oversee, revise, and revisit the notes attached to alerts, events and Timelines.', - landingIcon: 'filebeatApp', - skipUrlState: true, - }, - { - id: 'osquery:', - title: 'Osquery', - description: - 'Deploy Osquery with Elastic Agent, then run and schedule queries in Kibana', - }, - ], - }, - { - id: 'machine_learning-landing', - title: 'Machine learning', - skipUrlState: true, - categories: [ - { - type: 'separator', - linkIds: ['ml:overview', 'ml:notifications', 'ml:memoryUsage'], - }, - { - type: 'title', - label: 'Anomaly detection', - linkIds: [ - 'ml:anomalyDetection', - 'ml:anomalyExplorer', - 'ml:singleMetricViewer', - 'ml:suppliedConfigurations', - 'ml:settings', - ], - }, - { - type: 'title', - label: 'Data frame analytics', - linkIds: ['ml:dataFrameAnalytics', 'ml:resultExplorer', 'ml:analyticsMap'], - }, - { - type: 'title', - label: 'Model management', - linkIds: ['ml:nodesOverview'], - }, - { - type: 'title', - label: 'Data visualizer', - linkIds: [ - 'ml:fileUpload', - 'ml:indexDataVisualizer', - 'ml:esqlDataVisualizer', - 'ml:dataDrift', - ], - }, - { - type: 'title', - label: 'Aiops labs', - linkIds: ['ml:logRateAnalysis', 'ml:logPatternAnalysis', 'ml:changePointDetections'], - }, - ], - links: [ - { - id: 'ml:overview', - title: 'Overview', - description: 'Overview page', - }, - { - id: 'ml:notifications', - title: 'Notifications', - description: 'Notifications page', - }, - { - id: 'ml:memoryUsage', - title: 'Memory usage', - description: 'Memory usage page', - }, - { - id: 'ml:anomalyDetection', - title: 'Jobs', - description: 'Jobs page', - }, - { - id: 'ml:anomalyExplorer', - title: 'Anomaly explorer', - description: 'Anomaly explorer page', - }, - { - id: 'ml:singleMetricViewer', - title: 'Single metric viewer', - description: 'Single metric viewer page', - }, - { - id: 'ml:suppliedConfigurations', - title: 'Supplied configurations', - description: 'Supplied configurations page', - }, - { - id: 'ml:settings', - title: 'Settings', - description: 'Settings page', - }, - { - id: 'ml:dataFrameAnalytics', - title: 'Jobs', - description: 'Jobs page', - }, - { - id: 'ml:resultExplorer', - title: 'Result explorer', - description: 'Result explorer page', - }, - { - id: 'ml:analyticsMap', - title: 'Analytics map', - description: 'Analytics map page', - }, - { - id: 'ml:nodesOverview', - title: 'Trained models', - description: 'Trained models page', - }, - { - id: 'ml:fileUpload', - title: 'File data visualizer', - description: 'File data visualizer page', - }, - { - id: 'ml:indexDataVisualizer', - title: 'Data view data visualizer', - description: 'Data view data visualizer page', - }, - { - id: 'ml:esqlDataVisualizer', - title: 'ES|QL data visualizer', - landingIcon: 'sqlApp', - description: 'ES|QL data visualizer page', - }, - { - id: 'ml:dataDrift', - title: 'Data drift', - description: 'Data drift', - }, - { - id: 'ml:logRateAnalysis', - title: 'Log Rate Analysis', - description: 'Log Rate Analysis Page', - }, - { - id: 'ml:logPatternAnalysis', - title: 'Log pattern analysis', - description: 'Log pattern analysis page', - }, - { - id: 'ml:changePointDetections', - title: 'Change point detection', - description: 'Change point detection page', - }, - ], - }, - { - id: 'discover:', - title: 'Discover', - }, - { - id: 'dev_tools:', - title: 'Developer tools', - sideNavIcon: 'editorCodeBlock', - isFooterLink: true, - }, - { - id: 'management:', - title: 'Stack Management', - isFooterLink: true, - }, - { - id: 'integrations:/browse/security', - title: 'Integrations', - isFooterLink: true, - }, - { - id: 'maps:', - title: 'Maps', - description: - 'Analyze geospatial data and identify geo patterns in multiple layers and indices.', - landingIcon: 'graphApp', - disabled: true, - }, - { - id: 'visualize:', - title: 'Visualize library', - description: 'Manage visualization library. Create, edit, and share visualizations.', - landingIcon: 'visualizeApp', - disabled: true, - }, - ] as SolutionNavLink[]; - - const bodyCategories = [ - { - type: 'separator', - linkIds: ['discover:', 'dashboards'], - }, - { - type: 'separator', - linkIds: [ - 'rules-landing', - 'alerts', - 'attack_discovery', - 'cloud_security_posture-findings', - 'cases', - ], - }, - { - type: 'separator', - linkIds: ['investigations', 'threat_intelligence', 'explore'], - }, - { - type: 'separator', - linkIds: ['asset_inventory'], - }, - { - type: 'separator', - linkIds: ['assets'], - }, - { - type: 'separator', - linkIds: ['machine_learning-landing'], - }, - { - type: 'separator', - linkIds: ['entity_analytics-management', 'entity_analytics-entity_store_management'], - }, - ] as SolutionLinkCategory[]; - - const footerCategories = [ - { - type: 'separator', - linkIds: ['get_started', 'dev_tools:'], - }, - { - type: 'accordion', - label: 'Management', - iconType: 'gear', - linkIds: ['management:', 'monitoring:', 'integrations:/browse/security'], - }, - ] as SolutionLinkCategory[]; - - expect( - formatNavigationTree(solutionNavLinks, bodyCategories, footerCategories) - ).toMatchSnapshot(); - }); -}); diff --git a/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/navigation_tree.ts b/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/navigation_tree.ts deleted file mode 100644 index 8a5efab539d1..000000000000 --- a/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/navigation_tree.ts +++ /dev/null @@ -1,207 +0,0 @@ -/* - * 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 { partition } from 'lodash/fp'; -import type { - AppDeepLinkId, - NodeDefinition, - NavigationTreeDefinition, - RootNavigationItemDefinition, -} from '@kbn/core-chrome-browser'; -import type { LinkCategory } from '@kbn/security-solution-navigation'; -import { - isSeparatorLinkCategory, - isTitleLinkCategory, - isAccordionLinkCategory, -} from '@kbn/security-solution-navigation'; -import type { SolutionPageName, SolutionLinkCategory, SolutionNavLink } from '../../common/links'; -import { - getNavLinkIdFromSolutionPageName, - isBreadcrumbHidden, - isSideNavStatusHidden, -} from './util'; -import { SOLUTION_NAME } from '../../common/translations'; - -export const formatNavigationTree = ( - solutionNavLinks: SolutionNavLink[], - bodyCategories: Readonly, - footerCategories: Readonly -): NavigationTreeDefinition => { - const [footerNavItems, bodyNavItems] = partition('isFooterLink', solutionNavLinks); - const bodyChildren = addMainLinksPanelOpenerProp( - formatNodesFromLinks(bodyNavItems, bodyCategories, []) - ); - return { - body: [ - { - type: 'navGroup', - id: 'security_solution_nav', - title: SOLUTION_NAME, - icon: 'logoSecurity', - breadcrumbStatus: 'hidden', - defaultIsCollapsed: false, - children: bodyChildren, - isCollapsible: false, - }, - ], - footer: formatFooterNodesFromLinks(footerNavItems, footerCategories), - }; -}; - -// Body - -const formatNodesFromLinks = ( - solutionNavLinks: SolutionNavLink[], - parentCategories: Readonly>>, - ids: SolutionPageName[] -): NodeDefinition[] => { - const nodes: NodeDefinition[] = []; - if (parentCategories?.length) { - parentCategories.forEach((category) => { - nodes.push(...formatNodesFromLinksWithCategory(solutionNavLinks, category, ids)); - }, []); - } else { - nodes.push(...formatNodesFromLinksWithoutCategory(solutionNavLinks, ids)); - } - return nodes; -}; - -const formatNodesFromLinksWithCategory = ( - solutionNavLinks: SolutionNavLink[], - category: LinkCategory, - ids: SolutionPageName[] -): NodeDefinition[] => { - if (!category?.linkIds) { - return []; - } - - if (category.linkIds) { - const children = category.linkIds.reduce((acc, linkId) => { - const solutionNavLink = solutionNavLinks.find(({ id }) => id === linkId); - if (solutionNavLink != null) { - acc.push(createNodeFromSolutionNavLink(solutionNavLink, ids)); - } - return acc; - }, []); - if (!children.length) { - return []; - } - - const id = isTitleLinkCategory(category) ? getCategoryIdFromLabel(category.label) : undefined; - - return [ - { - id, - ...(isTitleLinkCategory(category) && { title: category.label }), - breadcrumbStatus: 'hidden', - children, - }, - ]; - } - return []; -}; - -const formatNodesFromLinksWithoutCategory = ( - solutionNavLinks: SolutionNavLink[], - ids: SolutionPageName[] -): NodeDefinition[] => { - return solutionNavLinks.map((solutionNavLink) => - createNodeFromSolutionNavLink(solutionNavLink, ids) - ); -}; - -const createNodeFromSolutionNavLink = ( - solutionNavLink: SolutionNavLink, - ids: SolutionPageName[] -): NodeDefinition => { - const { id, title, links, categories, disabled } = solutionNavLink; - const link = getNavLinkIdFromSolutionPageName(id); - const node: NodeDefinition = { - id, - link: link as AppDeepLinkId, - title, - ...(isBreadcrumbHidden(id) && { breadcrumbStatus: 'hidden' }), - ...((isSideNavStatusHidden(ids) || disabled) && { sideNavStatus: 'hidden' }), - }; - if (links?.length) { - node.children = formatNodesFromLinks(links, categories ?? [], ids.concat(id)); - } - return node; -}; - -// Footer - -const formatFooterNodesFromLinks = ( - solutionNavLinks: SolutionNavLink[], - parentCategories?: Readonly>> -): RootNavigationItemDefinition[] => { - const nodes: RootNavigationItemDefinition[] = []; - if (parentCategories?.length) { - parentCategories.forEach((category) => { - if (isSeparatorLinkCategory(category)) { - nodes.push( - ...category.linkIds.reduce((acc, linkId) => { - const solutionNavLink = solutionNavLinks.find(({ id }) => id === linkId); - if (solutionNavLink != null) { - acc.push({ - type: 'navItem', - link: getNavLinkIdFromSolutionPageName(solutionNavLink.id) as AppDeepLinkId, - title: solutionNavLink.title, - icon: solutionNavLink.sideNavIcon, - }); - } - return acc; - }, []) - ); - } - if (isAccordionLinkCategory(category)) { - nodes.push({ - type: 'navGroup', - id: getCategoryIdFromLabel(category.label), - title: category.label, - icon: category.iconType, - breadcrumbStatus: 'hidden', - children: - category.linkIds?.reduce((acc, linkId) => { - const solutionNavLink = solutionNavLinks.find(({ id }) => id === linkId); - if (solutionNavLink != null) { - acc.push({ - title: solutionNavLink.title, - link: getNavLinkIdFromSolutionPageName(solutionNavLink.id) as AppDeepLinkId, - }); - } - return acc; - }, []) ?? [], - }); - } - }, []); - } - return nodes; -}; - -// Utils - -const getCategoryIdFromLabel = (label: string): string => - `category-${label.toLowerCase().replace(' ', '_')}`; - -/** - * Adds the `renderAs: 'panelOpener'` prop to the main links that have children - * This function expects all main links to be in nested groups to add the separation between them. - * If these "separator" groups change this function will need to be updated. - */ -const addMainLinksPanelOpenerProp = (nodes: NodeDefinition[]): NodeDefinition[] => - nodes.map((node): NodeDefinition => { - if (node.children?.length) { - return { - ...node, - children: node.children.map((child) => ({ - ...child, - ...(child.children && { renderAs: 'panelOpener' }), - })), - }; - } - return node; - }); diff --git a/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/solution_navigation.tsx b/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/solution_navigation.tsx deleted file mode 100644 index cbdf5ec5d0a8..000000000000 --- a/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/solution_navigation.tsx +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ -import React from 'react'; -import type { PanelContentProvider } from '@kbn/shared-ux-chrome-navigation'; -import type { PanelComponentProps } from '@kbn/shared-ux-chrome-navigation/src/ui/components/panel/types'; -import { SolutionSideNavPanelContent } from '@kbn/security-solution-side-nav/panel'; -import useObservable from 'react-use/lib/useObservable'; -import type { Observable } from 'rxjs'; -import { map } from 'rxjs'; -import type { NavigationTreeDefinition } from '@kbn/core-chrome-browser'; - -import { NavigationProvider } from '@kbn/security-solution-navigation'; -import type { CoreStart } from '@kbn/core/public'; -import { usePanelSideNavItems } from './use_panel_side_nav_items'; -import { CATEGORIES, FOOTER_CATEGORIES } from './categories'; -import { formatNavigationTree } from './navigation_tree'; -import type { SolutionNavLinks$ } from '../../common/links'; -import { navLinks$ } from '../../common/links/nav_links'; - -export const withNavigationProvider = ( - Component: React.ComponentType, - core: CoreStart -) => - function WithNavigationProvider(props: T) { - return ( - - - - ); - }; - -const getPanelContent = ( - core: CoreStart, - solutionNavLinks$: SolutionNavLinks$ -): React.FC => { - const PanelContentProvider: React.FC = React.memo( - function PanelContentProvider({ selectedNode: { id: linkId }, closePanel }) { - const solutionNavLinks = useObservable(solutionNavLinks$, []); - const currentPanelItem = solutionNavLinks.find((item) => item.id === linkId); - - const { title = '', links = [], categories } = currentPanelItem ?? {}; - const items = usePanelSideNavItems(links); - - if (items.length === 0) { - return null; - } - return ( - - ); - } - ); - - return withNavigationProvider(PanelContentProvider, core); -}; - -export interface SolutionNavigation { - navigationTree$: Observable; - panelContentProvider: PanelContentProvider; -} - -export const getSolutionNavigation = (core: CoreStart): SolutionNavigation => { - const panelContent = getPanelContent(core, navLinks$); - const panelContentProvider: PanelContentProvider = (id: string) => { - // Stack Management uses the default panel content - if (!id.endsWith('.stack_management')) { - return { content: panelContent }; - } - }; - - const navigationTree$ = navLinks$.pipe( - map((solutionNavLinks) => formatNavigationTree(solutionNavLinks, CATEGORIES, FOOTER_CATEGORIES)) - ); - - return { navigationTree$, panelContentProvider }; -}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/util.ts b/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/util.ts index 967d21037919..e088d72b94ef 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/util.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/util.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { ExternalPageName, SecurityPageName } from '@kbn/security-solution-navigation'; import { APP_UI_ID } from '../../../common'; import type { SolutionPageName } from '../../common/links'; @@ -20,37 +19,3 @@ export const getSolutionPageNameFromNavLinkId = (navLinkId: string): SolutionPag const fullId = cleanId.replace(`${APP_UI_ID}:`, ''); // remove Security appId if present return fullId as SolutionPageName; }; - -// We need to hide breadcrumbs for some pages (tabs) because they appear duplicated. -// These breadcrumbs are incorrectly processed as trailing breadcrumbs in SecuritySolution, because of `SpyRoute` architecture limitations. -// They are navLinks tree with a SecurityPageName, so they should be treated as leading breadcrumbs in ESS as well. -// TODO: Improve the breadcrumbs logic in `use_breadcrumbs_nav` to avoid this workaround. -const HIDDEN_BREADCRUMBS = new Set([ - SecurityPageName.networkFlows, - SecurityPageName.networkDns, - SecurityPageName.networkHttp, - SecurityPageName.networkTls, - SecurityPageName.networkAnomalies, - SecurityPageName.networkEvents, - SecurityPageName.usersAll, - SecurityPageName.usersAuthentications, - SecurityPageName.usersAnomalies, - SecurityPageName.usersRisk, - SecurityPageName.usersEvents, - SecurityPageName.hostsAll, - SecurityPageName.hostsUncommonProcesses, - SecurityPageName.hostsAnomalies, - SecurityPageName.hostsEvents, - SecurityPageName.hostsRisk, - SecurityPageName.hostsSessions, -]); - -export const isBreadcrumbHidden = (id: SolutionPageName): boolean => - HIDDEN_BREADCRUMBS.has(id) || - /* management sub-pages set their breadcrumbs themselves, the main Management breadcrumb is configured with our navigationTree definition */ - (id.startsWith(ExternalPageName.management) && id !== ExternalPageName.management); - -export const isSideNavStatusHidden = (ids: SolutionPageName[]): boolean => { - // Dashboard nav children should not be visible. The Dashboard nav item should only navigate to a landing page - return ids[0] === SecurityPageName.dashboards; -}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/mocks.ts b/x-pack/solutions/security/plugins/security_solution/public/mocks.ts index b45d0eb1316b..cd3445251240 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/mocks.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/mocks.ts @@ -37,10 +37,6 @@ const startMock = (): PluginStart => ({ getUpselling: () => upselling, setOnboardingSettings: onboardingService.setSettings.bind(onboardingService), setIsSolutionNavigationEnabled: jest.fn(), - getSolutionNavigation: jest.fn(async () => ({ - navigationTree$: of({ body: [], footer: [] }), - panelContentProvider: jest.fn(), - })), }); export const securitySolutionMock = { diff --git a/x-pack/solutions/security/plugins/security_solution/public/plugin_contract.ts b/x-pack/solutions/security/plugins/security_solution/public/plugin_contract.ts index 0f526070f26f..ad83de0074e0 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/plugin_contract.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/plugin_contract.ts @@ -57,7 +57,6 @@ export class PluginContract { updateNavLinks(isSolutionNavigationEnabled, core); }, setOnboardingSettings: this.onboardingService.setSettings.bind(this.onboardingService), - getSolutionNavigation: () => lazySolutionNavigation(core), }; } @@ -81,10 +80,3 @@ const lazyResolver = async () => { ); return resolverPluginSetup(); }; -const lazySolutionNavigation = async (core: CoreStart) => { - const { getSolutionNavigation } = await import( - /* webpackChunkName: "solution_navigation" */ - './app/solution_navigation' - ); - return getSolutionNavigation(core); -}; diff --git a/x-pack/solutions/security/plugins/security_solution/public/types.ts b/x-pack/solutions/security/plugins/security_solution/public/types.ts index 0e66d43f54a9..ec45c33d8bfd 100644 --- a/x-pack/solutions/security/plugins/security_solution/public/types.ts +++ b/x-pack/solutions/security/plugins/security_solution/public/types.ts @@ -93,7 +93,6 @@ import type { ExperimentalFeatures } from '../common/experimental_features'; import type { SetComponents, GetComponents$ } from './contract_components'; import type { ConfigSettings } from '../common/config_settings'; import type { OnboardingService } from './onboarding/service'; -import type { SolutionNavigation } from './app/solution_navigation/solution_navigation'; import type { TelemetryServiceStart } from './common/lib/telemetry'; import type { SiemMigrationsService } from './siem_migrations/service'; @@ -222,7 +221,6 @@ export interface PluginStart { getUpselling: () => UpsellingService; setOnboardingSettings: OnboardingService['setSettings']; setIsSolutionNavigationEnabled: (isSolutionNavigationEnabled: boolean) => void; - getSolutionNavigation: () => Promise; } export type InspectResponse = Inspect & { response: string[] }; diff --git a/x-pack/solutions/security/plugins/security_solution/tsconfig.json b/x-pack/solutions/security/plugins/security_solution/tsconfig.json index 8e8972716e6c..4d99c798ad54 100644 --- a/x-pack/solutions/security/plugins/security_solution/tsconfig.json +++ b/x-pack/solutions/security/plugins/security_solution/tsconfig.json @@ -191,8 +191,6 @@ "@kbn/core-http-request-handler-context-server", "@kbn/core-http-server-mocks", "@kbn/data-service", - "@kbn/core-chrome-browser", - "@kbn/shared-ux-chrome-navigation", "@kbn/core-ui-settings-browser-mocks", "@kbn/management-plugin", "@kbn/security-plugin-types-server", diff --git a/x-pack/solutions/security/plugins/security_solution_ess/public/navigation/__snapshots__/side_navigation.test.tsx.snap b/x-pack/solutions/security/plugins/security_solution_ess/public/navigation/__snapshots__/side_navigation.test.tsx.snap new file mode 100644 index 000000000000..daf3a8c7f664 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution_ess/public/navigation/__snapshots__/side_navigation.test.tsx.snap @@ -0,0 +1,729 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ESS Security Side Nav registers the navigation tree definition 1`] = ` +Object { + "body": Array [ + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "discover:", + "link": "discover", + }, + Object { + "children": Array [ + Object { + "id": "overview", + "link": "securitySolutionUI:overview", + "sideNavStatus": "hidden", + }, + Object { + "id": "detection_response", + "link": "securitySolutionUI:detection_response", + "sideNavStatus": "hidden", + }, + Object { + "id": "cloud_security_posture-dashboard", + "link": "securitySolutionUI:cloud_security_posture-dashboard", + "sideNavStatus": "hidden", + }, + Object { + "id": "cloud_security_posture-vulnerability_dashboard", + "link": "securitySolutionUI:cloud_security_posture-vulnerability_dashboard", + "sideNavStatus": "hidden", + }, + Object { + "id": "entity_analytics", + "link": "securitySolutionUI:entity_analytics", + "sideNavStatus": "hidden", + }, + Object { + "id": "data_quality", + "link": "securitySolutionUI:data_quality", + "sideNavStatus": "hidden", + }, + ], + "id": "dashboards", + "link": "securitySolutionUI:dashboards", + "renderAs": "item", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "children": Array [ + Object { + "id": "rules-add", + "link": "securitySolutionUI:rules-add", + }, + Object { + "id": "rules-create", + "link": "securitySolutionUI:rules-create", + }, + ], + "id": "rules", + "link": "securitySolutionUI:rules", + "renderAs": "item", + }, + Object { + "id": "cloud_security_posture-benchmarks", + "link": "securitySolutionUI:cloud_security_posture-benchmarks", + }, + Object { + "id": "exceptions", + "link": "securitySolutionUI:exceptions", + }, + Object { + "id": "siem_migrations-rules", + "link": "securitySolutionUI:siem_migrations-rules", + "title": "SIEM rule migrations", + }, + ], + "id": "category-management", + "title": "Management", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "coverage-overview", + "link": "securitySolutionUI:coverage-overview", + }, + ], + "id": "category-discover", + "title": "Discover", + }, + ], + "id": "rules-landing", + "link": "securitySolutionUI:rules-landing", + "renderAs": "panelOpener", + "title": "Rules", + }, + Object { + "id": "alerts", + "link": "securitySolutionUI:alerts", + }, + Object { + "id": "attack_discovery", + "link": "securitySolutionUI:attack_discovery", + }, + Object { + "id": "cloud_security_posture-findings", + "link": "securitySolutionUI:cloud_security_posture-findings", + }, + Object { + "children": Array [ + Object { + "id": "cases_create", + "link": "securitySolutionUI:cases_create", + "sideNavStatus": "hidden", + }, + Object { + "id": "cases_configure", + "link": "securitySolutionUI:cases_configure", + "sideNavStatus": "hidden", + }, + ], + "id": "cases", + "link": "securitySolutionUI:cases", + "renderAs": "panelOpener", + }, + ], + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "id": "timelines-templates", + "link": "securitySolutionUI:timelines-templates", + "sideNavStatus": "hidden", + }, + ], + "id": "timelines", + "link": "securitySolutionUI:timelines", + "renderAs": "item", + }, + Object { + "id": "notes", + "link": "securitySolutionUI:notes", + "renderAs": "item", + }, + Object { + "id": "osquery:", + "link": "osquery", + "renderAs": "item", + }, + ], + "id": "investigations", + "link": "securitySolutionUI:investigations", + "renderAs": "panelOpener", + "title": "Investigations", + }, + Object { + "id": "threat_intelligence", + "link": "securitySolutionUI:threat_intelligence", + }, + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "id": "hosts-all", + "link": "securitySolutionUI:hosts-all", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "hosts-uncommon_processes", + "link": "securitySolutionUI:hosts-uncommon_processes", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "hosts-anomalies", + "link": "securitySolutionUI:hosts-anomalies", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "hosts-events", + "link": "securitySolutionUI:hosts-events", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "hosts-risk", + "link": "securitySolutionUI:hosts-risk", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "hosts-sessions", + "link": "securitySolutionUI:hosts-sessions", + }, + ], + "id": "hosts", + "link": "securitySolutionUI:hosts", + "renderAs": "item", + }, + Object { + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "id": "network-flows", + "link": "securitySolutionUI:network-flows", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "network-dns", + "link": "securitySolutionUI:network-dns", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "network-http", + "link": "securitySolutionUI:network-http", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "network-tls", + "link": "securitySolutionUI:network-tls", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "network-anomalies", + "link": "securitySolutionUI:network-anomalies", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "network-events", + "link": "securitySolutionUI:network-events", + }, + ], + "id": "network", + "link": "securitySolutionUI:network", + "renderAs": "item", + }, + Object { + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "id": "users-all", + "link": "securitySolutionUI:users-all", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "users-authentications", + "link": "securitySolutionUI:users-authentications", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "users-anomalies", + "link": "securitySolutionUI:users-anomalies", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "users-risk", + "link": "securitySolutionUI:users-risk", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "users-events", + "link": "securitySolutionUI:users-events", + }, + ], + "id": "users", + "link": "securitySolutionUI:users", + "renderAs": "item", + }, + ], + "id": "explore", + "link": "securitySolutionUI:explore", + "renderAs": "panelOpener", + "title": "Explore", + }, + ], + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "id": "fleet:agents", + "link": "fleet:agents", + }, + Object { + "id": "fleet:policies", + "link": "fleet:policies", + "title": "Policies", + }, + Object { + "id": "fleet:enrollment_tokens", + "link": "fleet:enrollment_tokens", + }, + Object { + "id": "fleet:uninstall_tokens", + "link": "fleet:uninstall_tokens", + }, + Object { + "id": "fleet:data_streams", + "link": "fleet:data_streams", + }, + Object { + "id": "fleet:settings", + "link": "fleet:settings", + }, + ], + "id": "fleet:", + "link": "fleet", + "title": "Fleet", + }, + Object { + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "id": "endpoints", + "link": "securitySolutionUI:endpoints", + }, + Object { + "id": "policy", + "link": "securitySolutionUI:policy", + }, + Object { + "id": "trusted_apps", + "link": "securitySolutionUI:trusted_apps", + }, + Object { + "id": "event_filters", + "link": "securitySolutionUI:event_filters", + }, + Object { + "id": "host_isolation_exceptions", + "link": "securitySolutionUI:host_isolation_exceptions", + }, + Object { + "id": "blocklist", + "link": "securitySolutionUI:blocklist", + }, + Object { + "id": "response_actions_history", + "link": "securitySolutionUI:response_actions_history", + }, + ], + "id": "endpoints", + "link": "securitySolutionUI:endpoints", + "title": "Endpoints", + }, + Object { + "id": "assets_custom", + "renderItem": [Function], + "title": "", + }, + ], + "id": "assets", + "link": "securitySolutionUI:assets", + "renderAs": "panelOpener", + "title": "Assets", + }, + ], + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "ml:overview", + "link": "ml:overview", + "title": "Overview", + }, + Object { + "id": "ml:notifications", + "link": "ml:notifications", + "title": "Notifications", + }, + Object { + "id": "ml:memoryUsage", + "link": "ml:memoryUsage", + "title": "Memory usage", + }, + ], + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "ml:anomalyDetection", + "link": "ml:anomalyDetection", + "title": "Jobs", + }, + Object { + "id": "ml:anomalyExplorer", + "link": "ml:anomalyExplorer", + "title": "Anomaly explorer", + }, + Object { + "id": "ml:singleMetricViewer", + "link": "ml:singleMetricViewer", + "title": "Single metric viewer", + }, + Object { + "id": "ml:suppliedConfigurations", + "link": "ml:suppliedConfigurations", + "title": "Supplied configurations", + }, + Object { + "id": "ml:settings", + "link": "ml:settings", + "title": "Settings", + }, + ], + "id": "category-anomaly_detection", + "title": "Anomaly detection", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "ml:dataFrameAnalytics", + "link": "ml:dataFrameAnalytics", + "title": "Jobs", + }, + Object { + "id": "ml:resultExplorer", + "link": "ml:resultExplorer", + "title": "Result explorer", + }, + Object { + "id": "ml:analyticsMap", + "link": "ml:analyticsMap", + "title": "Analytics map", + }, + ], + "id": "category-data_frame analytics", + "title": "Data frame analytics", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "ml:nodesOverview", + "link": "ml:nodesOverview", + "title": "Trained models", + }, + ], + "id": "category-model_management", + "title": "Model management", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "ml:fileUpload", + "link": "ml:fileUpload", + "title": "File data visualizer", + }, + Object { + "id": "ml:indexDataVisualizer", + "link": "ml:indexDataVisualizer", + "title": "Data view data visualizer", + }, + Object { + "id": "ml:esqlDataVisualizer", + "link": "ml:esqlDataVisualizer", + "title": "ES|QL data visualizer", + }, + Object { + "id": "ml:dataDrift", + "link": "ml:dataDrift", + "title": "Data drift", + }, + ], + "id": "category-data_visualizer", + "title": "Data visualizer", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "ml:logRateAnalysis", + "link": "ml:logRateAnalysis", + "title": "Log rate analysis", + }, + Object { + "id": "ml:logPatternAnalysis", + "link": "ml:logPatternAnalysis", + "title": "Log pattern analysis", + }, + Object { + "id": "ml:changePointDetections", + "link": "ml:changePointDetections", + "title": "Change point detection", + }, + ], + "id": "category-aiops_labs", + "title": "Aiops labs", + }, + ], + "id": "machine_learning-landing", + "link": "securitySolutionUI:machine_learning-landing", + "renderAs": "panelOpener", + "title": "Machine learning", + }, + ], + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "entity_analytics-management", + "link": "securitySolutionUI:entity_analytics-management", + "sideNavStatus": "hidden", + "title": "Entity Risk Score", + }, + Object { + "id": "entity_analytics-entity_store_management", + "link": "securitySolutionUI:entity_analytics-entity_store_management", + "sideNavStatus": "hidden", + "title": "Entity Store", + }, + ], + }, + ], + "defaultIsCollapsed": false, + "icon": "logoSecurity", + "id": "security_solution_nav", + "isCollapsible": false, + "title": "Security", + "type": "navGroup", + }, + ], + "footer": Array [ + Object { + "icon": "launch", + "link": "securitySolutionUI:get_started", + "type": "navItem", + }, + Object { + "icon": "editorCodeBlock", + "link": "dev_tools", + "title": "Developer tools", + "type": "navItem", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "link": "management:ingest_pipelines", + }, + Object { + "link": "management:pipelines", + }, + ], + "title": "Ingest", + }, + Object { + "children": Array [ + Object { + "link": "management:index_management", + }, + Object { + "link": "management:index_lifecycle_management", + }, + Object { + "link": "management:snapshot_restore", + }, + Object { + "link": "management:rollup_jobs", + }, + Object { + "link": "management:transform", + }, + Object { + "link": "management:cross_cluster_replication", + }, + Object { + "link": "management:remote_clusters", + }, + Object { + "link": "management:migrate_data", + }, + ], + "title": "Data", + }, + Object { + "children": Array [ + Object { + "link": "management:triggersActions", + }, + Object { + "link": "management:cases", + }, + Object { + "link": "management:triggersActionsConnectors", + }, + Object { + "link": "management:reporting", + }, + Object { + "link": "management:jobsListLink", + }, + Object { + "link": "management:watcher", + }, + Object { + "link": "management:maintenanceWindows", + }, + Object { + "link": "securitySolutionUI:entity_analytics-management", + }, + Object { + "link": "securitySolutionUI:entity_analytics-entity_store_management", + }, + ], + "title": "Alerts and Insights", + }, + Object { + "children": Array [ + Object { + "link": "management:users", + }, + Object { + "link": "management:roles", + }, + Object { + "link": "management:api_keys", + }, + Object { + "link": "management:role_mappings", + }, + ], + "title": "Security", + }, + Object { + "children": Array [ + Object { + "link": "management:dataViews", + }, + Object { + "link": "management:filesManagement", + }, + Object { + "link": "management:objects", + }, + Object { + "link": "management:tags", + }, + Object { + "link": "management:search_sessions", + }, + Object { + "link": "management:aiAssistantManagementSelection", + }, + Object { + "link": "management:spaces", + }, + Object { + "link": "maps", + }, + Object { + "link": "visualize", + }, + Object { + "link": "graph", + }, + Object { + "link": "canvas", + }, + Object { + "link": "management:settings", + }, + ], + "title": "Kibana", + }, + Object { + "children": Array [ + Object { + "link": "management:license_management", + }, + Object { + "link": "management:upgrade_assistant", + }, + ], + "title": "Stack", + }, + ], + "id": "stack_management", + "renderAs": "panelOpener", + "spaceBefore": null, + "title": "Stack Management", + }, + Object { + "link": "monitoring", + }, + Object { + "link": "integrations", + }, + ], + "icon": "gear", + "id": "category-management", + "title": "Management", + "type": "navGroup", + }, + ], +} +`; diff --git a/x-pack/solutions/security/plugins/security_solution_ess/public/navigation/side_navigation.test.tsx b/x-pack/solutions/security/plugins/security_solution_ess/public/navigation/side_navigation.test.tsx new file mode 100644 index 000000000000..c0e9340ba72e --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution_ess/public/navigation/side_navigation.test.tsx @@ -0,0 +1,34 @@ +/* + * 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 { mockServices } from '../common/__mocks__/services.mock'; +import { initSideNavigation } from './side_navigation'; + +describe('ESS Security Side Nav', () => { + const services = mockServices; + + it('registers the navigation tree definition', (done) => { + const addSolutionNavigation = jest.spyOn(services.navigation, 'addSolutionNavigation'); + + expect(addSolutionNavigation).not.toHaveBeenCalled(); + + initSideNavigation(services); + + expect(addSolutionNavigation).toHaveBeenCalled(); + + const [addSolutionNavigationArg] = addSolutionNavigation.mock.calls[0]; + const { navigationTree$ } = addSolutionNavigationArg; + + navigationTree$.subscribe({ + next: (value) => { + expect(value).toMatchSnapshot(); + }, + error: (err) => done(err), + complete: () => done(), + }); + }); +}); diff --git a/x-pack/solutions/security/plugins/security_solution_ess/public/navigation/side_navigation.ts b/x-pack/solutions/security/plugins/security_solution_ess/public/navigation/side_navigation.ts deleted file mode 100644 index 7ae283b863ef..000000000000 --- a/x-pack/solutions/security/plugins/security_solution_ess/public/navigation/side_navigation.ts +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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 { map } from 'rxjs'; -import produce from 'immer'; -import { i18n } from '@kbn/i18n'; -import { SecurityPageName, SECURITY_UI_APP_ID } from '@kbn/security-solution-navigation'; -import type { AppDeepLinkId, GroupDefinition, NodeDefinition } from '@kbn/core-chrome-browser'; -import { type Services } from '../common/services'; - -export const SOLUTION_NAME = i18n.translate('xpack.securitySolutionEss.nav.solutionName', { - defaultMessage: 'Security', -}); - -export const initSideNavigation = async (services: Services) => { - const { securitySolution, navigation } = services; - - navigation.isSolutionNavEnabled$.subscribe((isSolutionNavigationEnabled) => { - securitySolution.setIsSolutionNavigationEnabled(isSolutionNavigationEnabled); - }); - - const { navigationTree$, panelContentProvider } = await securitySolution.getSolutionNavigation(); - - const essNavigationTree$ = navigationTree$.pipe( - map((navigationTree) => - produce(navigationTree, (draft) => { - const footerGroup: GroupDefinition | undefined = draft.footer?.find( - (node): node is GroupDefinition => node.type === 'navGroup' - ); - const management = footerGroup?.children.find((child) => child.link === 'management'); - if (management) { - management.renderAs = 'panelOpener'; - management.id = 'stack_management'; - management.spaceBefore = null; - management.children = stackManagementLinks; - delete management.link; - } - }) - ) - ); - - navigation.addSolutionNavigation({ - id: 'security', - homePage: `${SECURITY_UI_APP_ID}:${SecurityPageName.landing}`, - title: SOLUTION_NAME, - icon: 'logoSecurity', - navigationTree$: essNavigationTree$, - panelContentProvider, - dataTestSubj: 'securitySolutionSideNav', - }); -}; - -// Stack Management static node definition -const stackManagementLinks: Array> = [ - { - title: 'Ingest', - children: [{ link: 'management:ingest_pipelines' }, { link: 'management:pipelines' }], - }, - { - title: 'Data', - children: [ - { link: 'management:index_management' }, - { link: 'management:index_lifecycle_management' }, - { link: 'management:snapshot_restore' }, - { link: 'management:rollup_jobs' }, - { link: 'management:transform' }, - { link: 'management:cross_cluster_replication' }, - { link: 'management:remote_clusters' }, - { link: 'management:migrate_data' }, - ], - }, - { - title: 'Alerts and Insights', - children: [ - { link: 'management:triggersActions' }, - { link: 'management:cases' }, - { link: 'management:triggersActionsConnectors' }, - { link: 'management:reporting' }, - { link: 'management:jobsListLink' }, - { link: 'management:watcher' }, - { link: 'management:maintenanceWindows' }, - { link: `${SECURITY_UI_APP_ID}:${SecurityPageName.entityAnalyticsManagement}` }, - { link: `${SECURITY_UI_APP_ID}:${SecurityPageName.entityAnalyticsEntityStoreManagement}` }, - ], - }, - { - title: 'Security', - children: [ - { link: 'management:users' }, - { link: 'management:roles' }, - { link: 'management:api_keys' }, - { link: 'management:role_mappings' }, - ], - }, - { - title: 'Kibana', - children: [ - { link: 'management:dataViews' }, - { link: 'management:filesManagement' }, - { link: 'management:objects' }, - { link: 'management:tags' }, - { link: 'management:search_sessions' }, - { link: 'management:aiAssistantManagementSelection' }, - { link: 'management:spaces' }, - { link: 'maps' }, - { link: 'visualize' }, - { link: 'graph' }, - { link: 'canvas' }, - { link: 'management:settings' }, - ], - }, - { - title: 'Stack', - children: [{ link: 'management:license_management' }, { link: 'management:upgrade_assistant' }], - }, -]; diff --git a/x-pack/solutions/security/plugins/security_solution_ess/public/navigation/side_navigation.tsx b/x-pack/solutions/security/plugins/security_solution_ess/public/navigation/side_navigation.tsx new file mode 100644 index 000000000000..4031ed4b8ae4 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution_ess/public/navigation/side_navigation.tsx @@ -0,0 +1,805 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import * as Rx from 'rxjs'; + +import { EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; +import type { NavigationTreeDefinition } from '@kbn/core-chrome-browser'; +import { i18n } from '@kbn/i18n'; +import { + ExternalPageName, + NavigationProvider, + SECURITY_UI_APP_ID, + SecurityPageName, +} from '@kbn/security-solution-navigation'; +import { LinkButton, securityLink, i18nStrings } from '@kbn/security-solution-navigation/links'; +import { type Services } from '../common/services'; + +export const SOLUTION_NAME = i18n.translate('xpack.securitySolutionEss.nav.solutionName', { + defaultMessage: 'Security', +}); + +const createNavigationTree$ = (services: Services): Rx.Observable => { + return Rx.of({ + body: [ + { + type: 'navGroup', + id: 'security_solution_nav', + title: SOLUTION_NAME, + icon: 'logoSecurity', + breadcrumbStatus: 'hidden', + defaultIsCollapsed: false, + children: [ + { + id: 'discover:', + link: 'discover', + }, + { + id: 'dashboards', + link: securityLink(SecurityPageName.dashboards), + renderAs: 'item', + children: [ + { + id: 'overview', + link: securityLink(SecurityPageName.overview), + sideNavStatus: 'hidden', + }, + { + id: 'detection_response', + link: securityLink(SecurityPageName.detectionAndResponse), + sideNavStatus: 'hidden', + }, + { + id: 'cloud_security_posture-dashboard', + link: securityLink(SecurityPageName.cloudSecurityPostureDashboard), + sideNavStatus: 'hidden', + }, + { + id: 'cloud_security_posture-vulnerability_dashboard', + link: securityLink(SecurityPageName.cloudSecurityPostureVulnerabilityDashboard), + sideNavStatus: 'hidden', + }, + { + id: 'entity_analytics', + link: securityLink(SecurityPageName.entityAnalytics), + sideNavStatus: 'hidden', + }, + { + id: 'data_quality', + link: securityLink(SecurityPageName.dataQuality), + sideNavStatus: 'hidden', + }, + ], + }, + { + breadcrumbStatus: 'hidden', + children: [ + { + id: 'rules-landing', + link: securityLink(SecurityPageName.rulesLanding), + title: i18nStrings.rules.title, + children: [ + { + id: 'category-management', + title: i18nStrings.rules.management.title, + breadcrumbStatus: 'hidden', + children: [ + { + id: 'rules', + link: securityLink(SecurityPageName.rules), + renderAs: 'item', + children: [ + { + id: 'rules-add', + link: securityLink(SecurityPageName.rulesAdd), + }, + { + id: 'rules-create', + link: securityLink(SecurityPageName.rulesCreate), + }, + ], + }, + { + id: 'cloud_security_posture-benchmarks', + link: securityLink(SecurityPageName.cloudSecurityPostureBenchmarks), + }, + { + id: 'exceptions', + link: securityLink(SecurityPageName.exceptions), + }, + { + id: 'siem_migrations-rules', + link: securityLink(SecurityPageName.siemMigrationsRules), + title: i18nStrings.rules.management.siemMigrationsRules, + }, + ], + }, + { + id: 'category-discover', + title: i18nStrings.rules.management.discover, + breadcrumbStatus: 'hidden', + children: [ + { + id: 'coverage-overview', + link: securityLink(SecurityPageName.coverageOverview), + }, + ], + }, + ], + renderAs: 'panelOpener', + }, + { + id: 'alerts', + link: securityLink(SecurityPageName.alerts), + }, + { + id: 'attack_discovery', + link: securityLink(SecurityPageName.attackDiscovery), + }, + { + id: 'cloud_security_posture-findings', + link: securityLink(SecurityPageName.cloudSecurityPostureFindings), + }, + { + id: 'cases', + link: securityLink(SecurityPageName.case), + children: [ + { + id: 'cases_create', + link: securityLink(SecurityPageName.caseCreate), + sideNavStatus: 'hidden', + }, + { + id: 'cases_configure', + link: securityLink(SecurityPageName.caseConfigure), + sideNavStatus: 'hidden', + }, + ], + renderAs: 'panelOpener', + }, + ], + }, + { + breadcrumbStatus: 'hidden', + children: [ + { + id: 'investigations', + link: securityLink(SecurityPageName.investigations), + title: i18nStrings.investigations.title, + children: [ + { + id: 'timelines', + link: securityLink(SecurityPageName.timelines), + renderAs: 'item', + children: [ + { + id: 'timelines-templates', + link: securityLink(SecurityPageName.timelinesTemplates), + sideNavStatus: 'hidden', + }, + ], + }, + { + id: 'notes', + link: securityLink(SecurityPageName.notes), + renderAs: 'item', + }, + { + id: 'osquery:', + link: 'osquery', + renderAs: 'item', + }, + ], + renderAs: 'panelOpener', + }, + { + id: 'threat_intelligence', + link: securityLink(SecurityPageName.threatIntelligence), + }, + { + id: 'explore', + link: securityLink(SecurityPageName.exploreLanding), + title: i18nStrings.explore.title, + children: [ + { + id: 'hosts', + link: securityLink(SecurityPageName.hosts), + renderAs: 'item', + children: [ + { + id: 'hosts-all', + link: securityLink(SecurityPageName.hostsAll), + breadcrumbStatus: 'hidden', + }, + { + id: 'hosts-uncommon_processes', + link: securityLink(SecurityPageName.hostsUncommonProcesses), + breadcrumbStatus: 'hidden', + }, + { + id: 'hosts-anomalies', + link: securityLink(SecurityPageName.hostsAnomalies), + breadcrumbStatus: 'hidden', + }, + { + id: 'hosts-events', + link: securityLink(SecurityPageName.hostsEvents), + breadcrumbStatus: 'hidden', + }, + { + id: 'hosts-risk', + link: securityLink(SecurityPageName.hostsRisk), + breadcrumbStatus: 'hidden', + }, + { + id: 'hosts-sessions', + link: securityLink(SecurityPageName.hostsSessions), + breadcrumbStatus: 'hidden', + }, + ], + }, + { + id: 'network', + link: securityLink(SecurityPageName.network), + renderAs: 'item', + children: [ + { + id: 'network-flows', + link: securityLink(SecurityPageName.networkFlows), + breadcrumbStatus: 'hidden', + }, + { + id: 'network-dns', + link: securityLink(SecurityPageName.networkDns), + breadcrumbStatus: 'hidden', + }, + { + id: 'network-http', + link: securityLink(SecurityPageName.networkHttp), + breadcrumbStatus: 'hidden', + }, + { + id: 'network-tls', + link: securityLink(SecurityPageName.networkTls), + breadcrumbStatus: 'hidden', + }, + { + id: 'network-anomalies', + link: securityLink(SecurityPageName.networkAnomalies), + breadcrumbStatus: 'hidden', + }, + { + id: 'network-events', + link: securityLink(SecurityPageName.networkEvents), + breadcrumbStatus: 'hidden', + }, + ], + }, + { + id: 'users', + link: securityLink(SecurityPageName.users), + renderAs: 'item', + children: [ + { + id: 'users-all', + link: securityLink(SecurityPageName.usersAll), + breadcrumbStatus: 'hidden', + }, + { + id: 'users-authentications', + link: securityLink(SecurityPageName.usersAuthentications), + breadcrumbStatus: 'hidden', + }, + { + id: 'users-anomalies', + link: securityLink(SecurityPageName.usersAnomalies), + breadcrumbStatus: 'hidden', + }, + { + id: 'users-risk', + link: securityLink(SecurityPageName.usersRisk), + breadcrumbStatus: 'hidden', + }, + { + id: 'users-events', + link: securityLink(SecurityPageName.usersEvents), + breadcrumbStatus: 'hidden', + }, + ], + }, + ], + renderAs: 'panelOpener', + }, + ], + }, + { + breadcrumbStatus: 'hidden', + children: [ + { + id: 'assets', + link: securityLink(SecurityPageName.assets), + title: i18nStrings.assets.title, + children: [ + { + id: 'fleet:', + link: 'fleet', + title: i18nStrings.assets.fleet.title, + children: [ + { + id: 'fleet:agents', + link: 'fleet:agents', + }, + { + id: 'fleet:policies', + link: 'fleet:policies', + title: i18nStrings.assets.fleet.policies, + }, + { + id: 'fleet:enrollment_tokens', + link: 'fleet:enrollment_tokens', + }, + { + id: 'fleet:uninstall_tokens', + link: 'fleet:uninstall_tokens', + }, + { + id: 'fleet:data_streams', + link: 'fleet:data_streams', + }, + { + id: 'fleet:settings', + link: 'fleet:settings', + }, + ], + }, + { + id: 'endpoints', + link: securityLink(SecurityPageName.endpoints), + title: i18nStrings.assets.endpoints.title, + children: [ + { + id: 'endpoints', + link: securityLink(SecurityPageName.endpoints), + breadcrumbStatus: 'hidden', + }, + { + id: 'policy', + link: securityLink(SecurityPageName.policies), + }, + { + id: 'trusted_apps', + link: securityLink(SecurityPageName.trustedApps), + }, + { + id: 'event_filters', + link: securityLink(SecurityPageName.eventFilters), + }, + { + id: 'host_isolation_exceptions', + link: securityLink(SecurityPageName.hostIsolationExceptions), + }, + { + id: 'blocklist', + link: securityLink(SecurityPageName.blocklist), + }, + { + id: 'response_actions_history', + link: securityLink(SecurityPageName.responseActionsHistory), + }, + ], + }, + { + id: 'assets_custom', + title: '', + renderItem: () => { + return ( + <> + + +

+ {i18n.translate( + 'xpack.securitySolutionEss.nav.assets.integrationsCallout.body', + { + defaultMessage: + 'Choose an integration to start collecting and analyzing your data.', + } + )} +

+ + + + + {i18n.translate( + 'xpack.securitySolutionEss.nav.assets.integrationsCallout.button', + { defaultMessage: 'Browse integrations' } + )} + + + + +
+ + ); + }, + }, + ], + renderAs: 'panelOpener', + }, + ], + }, + { + breadcrumbStatus: 'hidden', + children: [ + { + id: 'machine_learning-landing', + link: securityLink(SecurityPageName.mlLanding), + title: i18nStrings.ml.title, + children: [ + { + breadcrumbStatus: 'hidden', + children: [ + { + id: 'ml:overview', + link: 'ml:overview', + title: i18nStrings.ml.overview, + }, + { + id: 'ml:notifications', + link: 'ml:notifications', + title: i18nStrings.ml.notifications, + }, + { + id: 'ml:memoryUsage', + link: 'ml:memoryUsage', + title: i18nStrings.ml.memoryUsage, + }, + ], + }, + { + id: 'category-anomaly_detection', + title: i18nStrings.ml.anomalyDetection.title, + breadcrumbStatus: 'hidden', + children: [ + { + id: 'ml:anomalyDetection', + link: 'ml:anomalyDetection', + title: i18nStrings.ml.anomalyDetection.jobs, + }, + { + id: 'ml:anomalyExplorer', + link: 'ml:anomalyExplorer', + title: i18nStrings.ml.anomalyDetection.anomalyExplorer, + }, + { + id: 'ml:singleMetricViewer', + link: 'ml:singleMetricViewer', + title: i18nStrings.ml.anomalyDetection.singleMetricViewer, + }, + { + id: 'ml:suppliedConfigurations', + link: 'ml:suppliedConfigurations', + title: i18nStrings.ml.anomalyDetection.suppliedConfigurations, + }, + { + id: 'ml:settings', + link: 'ml:settings', + title: i18nStrings.ml.anomalyDetection.settings, + }, + ], + }, + { + id: 'category-data_frame analytics', + title: i18nStrings.ml.dataFrameAnalytics.title, + breadcrumbStatus: 'hidden', + children: [ + { + id: 'ml:dataFrameAnalytics', + link: 'ml:dataFrameAnalytics', + title: i18nStrings.ml.dataFrameAnalytics.jobs, + }, + { + id: 'ml:resultExplorer', + link: 'ml:resultExplorer', + title: i18nStrings.ml.dataFrameAnalytics.resultExplorer, + }, + { + id: 'ml:analyticsMap', + link: 'ml:analyticsMap', + title: i18nStrings.ml.dataFrameAnalytics.analyticsMap, + }, + ], + }, + { + id: 'category-model_management', + title: i18nStrings.ml.modelManagement.title, + breadcrumbStatus: 'hidden', + children: [ + { + id: 'ml:nodesOverview', + link: 'ml:nodesOverview', + title: i18nStrings.ml.modelManagement.trainedModels, + }, + ], + }, + { + id: 'category-data_visualizer', + title: i18nStrings.ml.dataVisualizer.title, + breadcrumbStatus: 'hidden', + children: [ + { + id: 'ml:fileUpload', + link: 'ml:fileUpload', + title: i18nStrings.ml.dataVisualizer.fileDataVisualizer, + }, + { + id: 'ml:indexDataVisualizer', + link: 'ml:indexDataVisualizer', + title: i18nStrings.ml.dataVisualizer.dataViewDataVisualizer, + }, + { + id: 'ml:esqlDataVisualizer', + link: 'ml:esqlDataVisualizer', + title: i18nStrings.ml.dataVisualizer.esqlDataVisualizer, + }, + { + id: 'ml:dataDrift', + link: 'ml:dataDrift', + title: i18nStrings.ml.dataVisualizer.dataDrift, + }, + ], + }, + { + id: 'category-aiops_labs', + title: i18nStrings.ml.aiopsLabs.title, + breadcrumbStatus: 'hidden', + children: [ + { + id: 'ml:logRateAnalysis', + link: 'ml:logRateAnalysis', + title: i18nStrings.ml.aiopsLabs.logRateAnalysis, + }, + { + id: 'ml:logPatternAnalysis', + link: 'ml:logPatternAnalysis', + title: i18nStrings.ml.aiopsLabs.logPatternAnalysis, + }, + { + id: 'ml:changePointDetections', + link: 'ml:changePointDetections', + title: i18nStrings.ml.aiopsLabs.changePointDetection, + }, + ], + }, + ], + renderAs: 'panelOpener', + }, + ], + }, + { + breadcrumbStatus: 'hidden', + children: [ + { + id: 'entity_analytics-management', + link: securityLink(SecurityPageName.entityAnalyticsManagement), + title: i18nStrings.entityRiskScore, + sideNavStatus: 'hidden', + }, + { + id: 'entity_analytics-entity_store_management', + link: securityLink(SecurityPageName.entityAnalyticsEntityStoreManagement), + title: i18nStrings.entityStore, + sideNavStatus: 'hidden', + }, + ], + }, + ], + isCollapsible: false, + }, + ], + footer: [ + { + type: 'navItem', + link: securityLink(SecurityPageName.landing), + icon: 'launch', + }, + { + type: 'navItem', + link: 'dev_tools', + title: i18nStrings.devTools, + icon: 'editorCodeBlock', + }, + { + type: 'navGroup', + id: 'category-management', + title: i18nStrings.management.title, + icon: 'gear', + breadcrumbStatus: 'hidden', + children: [ + { + title: i18nStrings.stackManagement.title, + renderAs: 'panelOpener', + id: 'stack_management', + spaceBefore: null, + children: [ + { + title: i18nStrings.stackManagement.ingest.title, + children: [ + { + link: 'management:ingest_pipelines', + }, + { + link: 'management:pipelines', + }, + ], + }, + { + title: i18nStrings.stackManagement.data.title, + children: [ + { + link: 'management:index_management', + }, + { + link: 'management:index_lifecycle_management', + }, + { + link: 'management:snapshot_restore', + }, + { + link: 'management:rollup_jobs', + }, + { + link: 'management:transform', + }, + { + link: 'management:cross_cluster_replication', + }, + { + link: 'management:remote_clusters', + }, + { + link: 'management:migrate_data', + }, + ], + }, + { + title: i18nStrings.stackManagement.alertsAndInsights.title, + children: [ + { + link: 'management:triggersActions', + }, + { + link: 'management:cases', + }, + { + link: 'management:triggersActionsConnectors', + }, + { + link: 'management:reporting', + }, + { + link: 'management:jobsListLink', + }, + { + link: 'management:watcher', + }, + { + link: 'management:maintenanceWindows', + }, + { + link: securityLink(SecurityPageName.entityAnalyticsManagement), + }, + { + link: securityLink(SecurityPageName.entityAnalyticsEntityStoreManagement), + }, + ], + }, + { + title: i18nStrings.stackManagement.security.title, + children: [ + { + link: 'management:users', + }, + { + link: 'management:roles', + }, + { + link: 'management:api_keys', + }, + { + link: 'management:role_mappings', + }, + ], + }, + { + title: i18nStrings.stackManagement.kibana.title, + children: [ + { + link: 'management:dataViews', + }, + { + link: 'management:filesManagement', + }, + { + link: 'management:objects', + }, + { + link: 'management:tags', + }, + { + link: 'management:search_sessions', + }, + { + link: 'management:aiAssistantManagementSelection', + }, + { + link: 'management:spaces', + }, + { + link: 'maps', + }, + { + link: 'visualize', + }, + { + link: 'graph', + }, + { + link: 'canvas', + }, + { + link: 'management:settings', + }, + ], + }, + { + title: i18nStrings.stackManagement.stack.title, + children: [ + { + link: 'management:license_management', + }, + { + link: 'management:upgrade_assistant', + }, + ], + }, + ], + }, + { + link: 'monitoring', + }, + { + link: 'integrations', + }, + ], + }, + ], + }); +}; + +export const initSideNavigation = async (services: Services) => { + const { securitySolution, navigation } = services; + + navigation.isSolutionNavEnabled$.subscribe((isSolutionNavigationEnabled) => { + securitySolution.setIsSolutionNavigationEnabled(isSolutionNavigationEnabled); + }); + + navigation.addSolutionNavigation({ + id: 'security', + homePage: `${SECURITY_UI_APP_ID}:${SecurityPageName.landing}`, + title: SOLUTION_NAME, + icon: 'logoSecurity', + navigationTree$: createNavigationTree$(services), + dataTestSubj: 'securitySolutionSideNav', + }); +}; diff --git a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/__snapshots__/side_navigation.test.tsx.snap b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/__snapshots__/side_navigation.test.tsx.snap new file mode 100644 index 000000000000..6bc20dbd86af --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/__snapshots__/side_navigation.test.tsx.snap @@ -0,0 +1,1061 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Security Side Nav registers the navigation tree definition for serverless security 1`] = ` +Object { + "body": Array [ + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "discover:", + "link": "discover", + }, + Object { + "children": Array [ + Object { + "id": "overview", + "link": "securitySolutionUI:overview", + "sideNavStatus": "hidden", + }, + Object { + "id": "detection_response", + "link": "securitySolutionUI:detection_response", + "sideNavStatus": "hidden", + }, + Object { + "id": "cloud_security_posture-dashboard", + "link": "securitySolutionUI:cloud_security_posture-dashboard", + "sideNavStatus": "hidden", + }, + Object { + "id": "cloud_security_posture-vulnerability_dashboard", + "link": "securitySolutionUI:cloud_security_posture-vulnerability_dashboard", + "sideNavStatus": "hidden", + }, + Object { + "id": "entity_analytics", + "link": "securitySolutionUI:entity_analytics", + "sideNavStatus": "hidden", + }, + Object { + "id": "data_quality", + "link": "securitySolutionUI:data_quality", + "sideNavStatus": "hidden", + }, + ], + "id": "dashboards", + "link": "securitySolutionUI:dashboards", + "renderAs": "item", + }, + Object { + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "children": Array [ + Object { + "id": "rules-add", + "link": "securitySolutionUI:rules-add", + }, + Object { + "id": "rules-create", + "link": "securitySolutionUI:rules-create", + }, + ], + "id": "rules", + "link": "securitySolutionUI:rules", + "renderAs": "item", + }, + Object { + "id": "cloud_security_posture-benchmarks", + "link": "securitySolutionUI:cloud_security_posture-benchmarks", + }, + Object { + "id": "exceptions", + "link": "securitySolutionUI:exceptions", + }, + Object { + "id": "siem_migrations-rules", + "link": "securitySolutionUI:siem_migrations-rules", + "title": "SIEM rule migrations", + }, + ], + "id": "category-management", + "title": "Management", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "coverage-overview", + "link": "securitySolutionUI:coverage-overview", + }, + ], + "id": "category-discover", + "title": "Discover", + }, + ], + "id": "rules-landing", + "link": "securitySolutionUI:rules-landing", + "renderAs": "panelOpener", + "title": "Rules", + }, + Object { + "id": "alerts", + "link": "securitySolutionUI:alerts", + }, + Object { + "id": "attack_discovery", + "link": "securitySolutionUI:attack_discovery", + }, + Object { + "id": "cloud_security_posture-findings", + "link": "securitySolutionUI:cloud_security_posture-findings", + }, + Object { + "children": Array [ + Object { + "id": "cases_create", + "link": "securitySolutionUI:cases_create", + "sideNavStatus": "hidden", + }, + Object { + "id": "cases_configure", + "link": "securitySolutionUI:cases_configure", + "sideNavStatus": "hidden", + }, + ], + "id": "cases", + "link": "securitySolutionUI:cases", + "renderAs": "item", + }, + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "id": "timelines-templates", + "link": "securitySolutionUI:timelines-templates", + "sideNavStatus": "hidden", + }, + ], + "id": "timelines", + "link": "securitySolutionUI:timelines", + "renderAs": "item", + }, + Object { + "id": "notes", + "link": "securitySolutionUI:notes", + "renderAs": "item", + }, + Object { + "id": "osquery:", + "link": "osquery", + "renderAs": "item", + }, + ], + "id": "investigations", + "link": "securitySolutionUI:investigations", + "renderAs": "panelOpener", + "title": "Investigations", + }, + Object { + "id": "threat_intelligence", + "link": "securitySolutionUI:threat_intelligence", + }, + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "id": "hosts-all", + "link": "securitySolutionUI:hosts-all", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "hosts-uncommon_processes", + "link": "securitySolutionUI:hosts-uncommon_processes", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "hosts-anomalies", + "link": "securitySolutionUI:hosts-anomalies", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "hosts-events", + "link": "securitySolutionUI:hosts-events", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "hosts-risk", + "link": "securitySolutionUI:hosts-risk", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "hosts-sessions", + "link": "securitySolutionUI:hosts-sessions", + }, + ], + "id": "hosts", + "link": "securitySolutionUI:hosts", + "renderAs": "item", + }, + Object { + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "id": "network-flows", + "link": "securitySolutionUI:network-flows", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "network-dns", + "link": "securitySolutionUI:network-dns", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "network-http", + "link": "securitySolutionUI:network-http", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "network-tls", + "link": "securitySolutionUI:network-tls", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "network-anomalies", + "link": "securitySolutionUI:network-anomalies", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "network-events", + "link": "securitySolutionUI:network-events", + }, + ], + "id": "network", + "link": "securitySolutionUI:network", + "renderAs": "item", + }, + Object { + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "id": "users-all", + "link": "securitySolutionUI:users-all", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "users-authentications", + "link": "securitySolutionUI:users-authentications", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "users-anomalies", + "link": "securitySolutionUI:users-anomalies", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "users-risk", + "link": "securitySolutionUI:users-risk", + }, + Object { + "breadcrumbStatus": "hidden", + "id": "users-events", + "link": "securitySolutionUI:users-events", + }, + ], + "id": "users", + "link": "securitySolutionUI:users", + "renderAs": "item", + }, + ], + "id": "explore", + "link": "securitySolutionUI:explore", + "renderAs": "panelOpener", + "spaceBefore": null, + "title": "Explore", + }, + Object { + "children": Array [ + Object { + "children": Array [ + Object { + "id": "fleet:agents", + "link": "fleet:agents", + }, + Object { + "id": "fleet:policies", + "link": "fleet:policies", + "title": "Policies", + }, + Object { + "id": "fleet:enrollment_tokens", + "link": "fleet:enrollment_tokens", + }, + Object { + "id": "fleet:uninstall_tokens", + "link": "fleet:uninstall_tokens", + }, + Object { + "id": "fleet:data_streams", + "link": "fleet:data_streams", + }, + Object { + "id": "fleet:settings", + "link": "fleet:settings", + }, + ], + "id": "fleet:", + "link": "fleet", + "title": "Fleet", + }, + Object { + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "id": "endpoints", + "link": "securitySolutionUI:endpoints", + }, + Object { + "id": "policy", + "link": "securitySolutionUI:policy", + }, + Object { + "id": "trusted_apps", + "link": "securitySolutionUI:trusted_apps", + }, + Object { + "id": "event_filters", + "link": "securitySolutionUI:event_filters", + }, + Object { + "id": "host_isolation_exceptions", + "link": "securitySolutionUI:host_isolation_exceptions", + }, + Object { + "id": "blocklist", + "link": "securitySolutionUI:blocklist", + }, + Object { + "id": "response_actions_history", + "link": "securitySolutionUI:response_actions_history", + }, + ], + "id": "endpoints", + "link": "securitySolutionUI:endpoints", + "title": "Endpoints", + }, + Object { + "id": "assets_custom", + "renderItem": [Function], + "title": "", + }, + ], + "id": "assets", + "link": "securitySolutionUI:assets", + "renderAs": "panelOpener", + "title": "Assets", + }, + Object { + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "ml:overview", + "link": "ml:overview", + "title": "Overview", + }, + Object { + "id": "ml:notifications", + "link": "ml:notifications", + "title": "Notifications", + }, + Object { + "id": "ml:memoryUsage", + "link": "ml:memoryUsage", + "title": "Memory usage", + }, + ], + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "ml:anomalyDetection", + "link": "ml:anomalyDetection", + "title": "Jobs", + }, + Object { + "id": "ml:anomalyExplorer", + "link": "ml:anomalyExplorer", + "title": "Anomaly explorer", + }, + Object { + "id": "ml:singleMetricViewer", + "link": "ml:singleMetricViewer", + "title": "Single metric viewer", + }, + Object { + "id": "ml:suppliedConfigurations", + "link": "ml:suppliedConfigurations", + "title": "Supplied configurations", + }, + Object { + "id": "ml:settings", + "link": "ml:settings", + "title": "Settings", + }, + ], + "id": "category-anomaly_detection", + "title": "Anomaly detection", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "ml:dataFrameAnalytics", + "link": "ml:dataFrameAnalytics", + "title": "Jobs", + }, + Object { + "id": "ml:resultExplorer", + "link": "ml:resultExplorer", + "title": "Result explorer", + }, + Object { + "id": "ml:analyticsMap", + "link": "ml:analyticsMap", + "title": "Analytics map", + }, + ], + "id": "category-data_frame analytics", + "title": "Data frame analytics", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "ml:nodesOverview", + "link": "ml:nodesOverview", + "title": "Trained models", + }, + ], + "id": "category-model_management", + "title": "Model management", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "ml:fileUpload", + "link": "ml:fileUpload", + "title": "File data visualizer", + }, + Object { + "id": "ml:indexDataVisualizer", + "link": "ml:indexDataVisualizer", + "title": "Data view data visualizer", + }, + Object { + "id": "ml:esqlDataVisualizer", + "link": "ml:esqlDataVisualizer", + "title": "ES|QL data visualizer", + }, + Object { + "id": "ml:dataDrift", + "link": "ml:dataDrift", + "title": "Data drift", + }, + ], + "id": "category-data_visualizer", + "title": "Data visualizer", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "ml:logRateAnalysis", + "link": "ml:logRateAnalysis", + "title": "Log rate analysis", + }, + Object { + "id": "ml:logPatternAnalysis", + "link": "ml:logPatternAnalysis", + "title": "Log pattern analysis", + }, + Object { + "id": "ml:changePointDetections", + "link": "ml:changePointDetections", + "title": "Change point detection", + }, + ], + "id": "category-aiops_labs", + "title": "Aiops labs", + }, + ], + "id": "machine_learning-landing", + "link": "securitySolutionUI:machine_learning-landing", + "renderAs": "panelOpener", + "title": "Machine learning", + }, + Object { + "id": "entity_analytics-management", + "link": "securitySolutionUI:entity_analytics-management", + "sideNavStatus": "hidden", + "title": "Entity Risk Score", + }, + Object { + "id": "entity_analytics-entity_store_management", + "link": "securitySolutionUI:entity_analytics-entity_store_management", + "sideNavStatus": "hidden", + "title": "Entity Store", + }, + ], + "defaultIsCollapsed": false, + "icon": "logoSecurity", + "id": "security_solution_nav", + "isCollapsible": false, + "title": "Security", + "type": "navGroup", + }, + ], + "footer": Array [ + Object { + "icon": "launch", + "link": "securitySolutionUI:get_started", + "type": "navItem", + }, + Object { + "icon": "editorCodeBlock", + "link": "dev_tools", + "title": "Developer tools", + "type": "navItem", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "link": "management:index_management", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:transform", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:ingest_pipelines", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:dataViews", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:jobsListLink", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:pipelines", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:data_quality", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:data_usage", + }, + ], + "title": "Data", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "link": "management:api_keys", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:roles", + }, + Object { + "cloudLink": "userAndRoles", + "title": "Manage organization members", + }, + ], + "title": "Access", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "link": "management:triggersActions", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:triggersActionsConnectors", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:maintenanceWindows", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "securitySolutionUI:entity_analytics-management", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "securitySolutionUI:entity_analytics-entity_store_management", + }, + ], + "title": "Alerts and Insights", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "link": "management:spaces", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:objects", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:filesManagement", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:reporting", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:tags", + }, + Object { + "link": "maps", + }, + Object { + "link": "visualize", + }, + ], + "title": "Content", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "link": "management:settings", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:securityAiAssistantManagement", + }, + ], + "title": "Other", + }, + ], + "id": "stack_management", + "renderAs": "panelOpener", + "spaceBefore": null, + "title": "Stack Management", + }, + Object { + "link": "integrations", + }, + Object { + "cloudLink": "billingAndSub", + }, + ], + "icon": "gear", + "id": "category-management", + "title": "Project Settings", + "type": "navGroup", + }, + ], +} +`; + +exports[`Security Side Nav registers the navigation tree definition for serverless security with AI SOC 1`] = ` +Object { + "body": Array [ + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "discover:", + "link": "discover", + }, + Object { + "id": "attack_discovery", + "link": "securitySolutionUI:attack_discovery", + }, + Object { + "children": Array [ + Object { + "id": "cases_create", + "link": "securitySolutionUI:cases_create", + "sideNavStatus": "hidden", + }, + Object { + "id": "cases_configure", + "link": "securitySolutionUI:cases_configure", + "sideNavStatus": "hidden", + }, + ], + "id": "cases", + "link": "securitySolutionUI:cases", + "renderAs": "panelOpener", + }, + Object { + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "ml:overview", + "link": "ml:overview", + "title": "Overview", + }, + Object { + "id": "ml:notifications", + "link": "ml:notifications", + "title": "Notifications", + }, + Object { + "id": "ml:memoryUsage", + "link": "ml:memoryUsage", + "title": "Memory usage", + }, + ], + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "ml:anomalyDetection", + "link": "ml:anomalyDetection", + "title": "Jobs", + }, + Object { + "id": "ml:anomalyExplorer", + "link": "ml:anomalyExplorer", + "title": "Anomaly explorer", + }, + Object { + "id": "ml:singleMetricViewer", + "link": "ml:singleMetricViewer", + "title": "Single metric viewer", + }, + Object { + "id": "ml:suppliedConfigurations", + "link": "ml:suppliedConfigurations", + "title": "Supplied configurations", + }, + Object { + "id": "ml:settings", + "link": "ml:settings", + "title": "Settings", + }, + ], + "id": "category-anomaly_detection", + "title": "Anomaly detection", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "ml:dataFrameAnalytics", + "link": "ml:dataFrameAnalytics", + "title": "Jobs", + }, + Object { + "id": "ml:resultExplorer", + "link": "ml:resultExplorer", + "title": "Result explorer", + }, + Object { + "id": "ml:analyticsMap", + "link": "ml:analyticsMap", + "title": "Analytics map", + }, + ], + "id": "category-data_frame analytics", + "title": "Data frame analytics", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "ml:nodesOverview", + "link": "ml:nodesOverview", + "title": "Trained models", + }, + ], + "id": "category-model_management", + "title": "Model management", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "ml:fileUpload", + "link": "ml:fileUpload", + "title": "File data visualizer", + }, + Object { + "id": "ml:indexDataVisualizer", + "link": "ml:indexDataVisualizer", + "title": "Data view data visualizer", + }, + Object { + "id": "ml:esqlDataVisualizer", + "link": "ml:esqlDataVisualizer", + "title": "ES|QL data visualizer", + }, + Object { + "id": "ml:dataDrift", + "link": "ml:dataDrift", + "title": "Data drift", + }, + ], + "id": "category-data_visualizer", + "title": "Data visualizer", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "id": "ml:logRateAnalysis", + "link": "ml:logRateAnalysis", + "title": "Log rate analysis", + }, + Object { + "id": "ml:logPatternAnalysis", + "link": "ml:logPatternAnalysis", + "title": "Log pattern analysis", + }, + Object { + "id": "ml:changePointDetections", + "link": "ml:changePointDetections", + "title": "Change point detection", + }, + ], + "id": "category-aiops_labs", + "title": "Aiops labs", + }, + ], + "id": "machine_learning-landing", + "link": "securitySolutionUI:machine_learning-landing", + "renderAs": "panelOpener", + }, + Object { + "id": "alert_summary", + "link": "securitySolutionUI:alert_summary", + }, + Object { + "children": Array [ + Object { + "link": "securitySolutionUI:configurations-ai_settings", + }, + Object { + "link": "securitySolutionUI:configurations-basic_rules", + }, + Object { + "link": "securitySolutionUI:configurations-integrations", + }, + ], + "id": "configurations", + "link": "securitySolutionUI:configurations", + "renderAs": "panelOpener", + }, + ], + "defaultIsCollapsed": false, + "icon": [Function], + "id": "security_solution_ai_nav", + "isCollapsible": false, + "title": "AI for SOC", + "type": "navGroup", + }, + ], + "footer": Array [ + Object { + "icon": "launch", + "link": "securitySolutionUI:get_started", + "type": "navItem", + }, + Object { + "icon": "editorCodeBlock", + "link": "dev_tools", + "title": "Developer tools", + "type": "navItem", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "link": "management:index_management", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:transform", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:ingest_pipelines", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:dataViews", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:jobsListLink", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:pipelines", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:data_quality", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:data_usage", + }, + ], + "title": "Data", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "link": "management:api_keys", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:roles", + }, + Object { + "cloudLink": "userAndRoles", + "title": "Manage organization members", + }, + ], + "title": "Access", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "link": "management:triggersActions", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:triggersActionsConnectors", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:maintenanceWindows", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "securitySolutionUI:entity_analytics-management", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "securitySolutionUI:entity_analytics-entity_store_management", + }, + ], + "title": "Alerts and Insights", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "link": "management:spaces", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:objects", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:filesManagement", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:reporting", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:tags", + }, + Object { + "link": "maps", + }, + Object { + "link": "visualize", + }, + ], + "title": "Content", + }, + Object { + "breadcrumbStatus": "hidden", + "children": Array [ + Object { + "breadcrumbStatus": "hidden", + "link": "management:settings", + }, + Object { + "breadcrumbStatus": "hidden", + "link": "management:securityAiAssistantManagement", + }, + ], + "title": "Other", + }, + ], + "id": "stack_management", + "renderAs": "panelOpener", + "spaceBefore": null, + "title": "Stack Management", + }, + Object { + "link": "integrations", + }, + Object { + "cloudLink": "billingAndSub", + }, + ], + "icon": "gear", + "id": "category-management", + "title": "Project Settings", + "type": "navGroup", + }, + ], +} +`; diff --git a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/ai_soc_navigation.test.ts b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/ai_soc_navigation.test.ts deleted file mode 100644 index 442d6faed728..000000000000 --- a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/ai_soc_navigation.test.ts +++ /dev/null @@ -1,141 +0,0 @@ -/* - * 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 { applyAiSocNavigation, aiGroup } from './ai_soc_navigation'; -import { alertSummaryLink, configurationsLink } from './links'; -import { ProductLine, ProductTier } from '../../../common/product'; -import * as utils from './utils'; // We'll spy on the named export from here -import type { WritableDraft } from 'immer/dist/internal'; -import type { - AppDeepLinkId, - GroupDefinition, - NavigationTreeDefinition, - NodeDefinition, -} from '@kbn/core-chrome-browser'; - -const nonAiProduct = { product_line: ProductLine.security, product_tier: ProductTier.essentials }; -const aiProduct = { product_line: ProductLine.aiSoc, product_tier: ProductTier.essentials }; - -const getSampleDraft = (): WritableDraft> => ({ - body: [ - { - type: 'navGroup', - id: 'security_solution_nav', - title: 'Security', - icon: 'logoSecurity', - breadcrumbStatus: 'hidden', - defaultIsCollapsed: false, - children: [ - { - breadcrumbStatus: 'hidden', - children: [ - { - id: 'discover:', - link: 'discover', - title: 'Discover', - }, - { - id: 'dashboards', - link: 'securitySolutionUI:dashboards', - title: 'Dashboards', - children: [ - { - id: 'overview', - link: 'securitySolutionUI:overview', - title: 'Overview', - }, - { - id: 'detection_response', - link: 'securitySolutionUI:detection_response', - title: 'Detection & Response', - }, - { - id: 'entity_analytics', - link: 'securitySolutionUI:entity_analytics', - title: 'Entity Analytics', - }, - { - id: 'data_quality', - link: 'securitySolutionUI:data_quality', - title: 'Data Quality', - }, - ], - renderAs: 'panelOpener', - }, - ], - }, - ], - isCollapsible: false, - }, - ], -}); - -describe('applyAiSocNavigation', () => { - let draft: WritableDraft>; - - beforeEach(() => { - draft = getSampleDraft(); - }); - - describe('when productTypes does NOT include aiSoc', () => { - it('should not modify the navigation tree', () => { - const productTypes = [nonAiProduct]; - - const originalDraft = JSON.parse(JSON.stringify(draft)); - applyAiSocNavigation(draft, productTypes); - - // Should remain unchanged - expect(draft).toEqual(originalDraft); - }); - }); - - describe('when productTypes includes aiSoc', () => { - let filterSpy: jest.SpyInstance; - - beforeEach(() => { - // Spy on filterFromWhitelist so we can control the filter result - filterSpy = jest - .spyOn(utils, 'filterFromWhitelist') - .mockImplementation((nodes: Array>, _whitelist: string[]) => { - // Simulate that the filter keeps only alertSummaryLink - return [alertSummaryLink]; - }); - }); - - afterEach(() => { - filterSpy.mockRestore(); - }); - - it('should modify the navigation tree correctly', () => { - const productTypes = [aiProduct]; - - applyAiSocNavigation(draft, productTypes); - - // The final draft.body should be replaced by one navGroup from aiGroup - // that has only the filtered children (we forced it to return [alertSummaryLink]). - expect(draft.body).toEqual([ - { - ...aiGroup, - children: [alertSummaryLink], - }, - ]); - - // Check that filterFromWhitelist was called with the original children plus alertSummaryLink - const securityGroup = getSampleDraft().body[0] as WritableDraft< - GroupDefinition - >; - const originalChildren = securityGroup.children; - const expectedChildrenForFiltering = [ - ...originalChildren, - alertSummaryLink, - configurationsLink, - ]; - - expect(filterSpy).toHaveBeenCalledWith(expectedChildrenForFiltering, expect.any(Array)); - }); - }); -}); diff --git a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/ai_soc_navigation.ts b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/ai_soc_navigation.ts index a520f4fcad88..40e3b4a5da48 100644 --- a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/ai_soc_navigation.ts +++ b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/ai_soc_navigation.ts @@ -5,71 +5,242 @@ * 2.0. */ -import type { - AppDeepLinkId, - GroupDefinition, - NavigationTreeDefinition, -} from '@kbn/core-chrome-browser'; +import * as Rx from 'rxjs'; + +import type { NavigationTreeDefinition } from '@kbn/core-chrome-browser'; +import { i18n } from '@kbn/i18n'; + +import { SecurityPageName } from '@kbn/security-solution-navigation'; +import { i18nStrings, securityLink } from '@kbn/security-solution-navigation/links'; -import type { WritableDraft } from 'immer/dist/internal'; -import { ExternalPageName, SecurityPageName } from '@kbn/security-solution-navigation'; -import { alertSummaryLink, configurationsLink } from './links'; -import { AiForTheSocIcon } from './icons'; -import { filterFromWhitelist } from './utils'; import { type SecurityProductTypes } from '../../../common/config'; import { ProductLine } from '../../../common/product'; +import { AiForTheSocIcon } from './icons'; +import { createStackManagementNavigationTree } from '../stack_management_navigation'; -const shouldUseAINavigation = (productTypes: SecurityProductTypes) => { - return productTypes.some((productType) => productType.product_line === ProductLine.aiSoc); -}; - -export const aiGroup: GroupDefinition = { - type: 'navGroup', - id: 'security_solution_ai_nav', - title: 'AI for SOC', - icon: AiForTheSocIcon, - breadcrumbStatus: 'hidden', - defaultIsCollapsed: false, - isCollapsible: false, - children: [], -}; -// Elements we want to show in AI for SOC navigation -// This is a temporary solution until we figure out a way to handle Upselling with new Tier -const whitelist = [ - SecurityPageName.case, - SecurityPageName.caseCreate, - SecurityPageName.caseConfigure, - SecurityPageName.alertSummary, - SecurityPageName.attackDiscovery, - SecurityPageName.configurations, - ExternalPageName.discover, - SecurityPageName.mlLanding, -]; - -// Apply AI for SOC navigation tree changes. -// The navigation tree received by parameter is generated at: x-pack/solutions/security/plugins/security_solution/public/app/solution_navigation/navigation_tree.ts -// An example of static navigation tree: x-pack/solutions/observability/plugins/observability/public/navigation_tree.ts - -// !! This is a temporary solution until the "classic" navigation is deprecated and the "generated" navigationTree is replaced by a static navigationTree (probably multiple of them). -export const applyAiSocNavigation = ( - draft: WritableDraft>, - productTypes: SecurityProductTypes -): void => { - if (!shouldUseAINavigation(productTypes)) { - return; - } - - const securityGroup = draft.body[0] as WritableDraft< - GroupDefinition - >; - - // hardcode elements existing only in AI for SOC group - securityGroup.children.push(alertSummaryLink, configurationsLink); - - // Overwrite the children with only the elements available for AI for SOC navigation - // Temporary solution until we have clarity how to proceed with Upselling in the new Tier - // (eg. Threat Intelligence couldn't be hidden) - securityGroup.children = filterFromWhitelist(securityGroup.children, whitelist); - - draft.body = [{ ...aiGroup, children: securityGroup.children }]; +const SOLUTION_NAME = i18n.translate( + 'xpack.securitySolutionServerless.socNavLinks.projectType.title', + { defaultMessage: 'AI for SOC' } +); + +export const shouldUseAINavigation = (productTypes: SecurityProductTypes) => + productTypes.some((productType) => productType.product_line === ProductLine.aiSoc); + +export const createAiSocNavigationTree$ = (): Rx.Observable => { + return Rx.of({ + body: [ + { + type: 'navGroup', + id: 'security_solution_ai_nav', + title: SOLUTION_NAME, + icon: AiForTheSocIcon, + breadcrumbStatus: 'hidden', + defaultIsCollapsed: false, + isCollapsible: false, + children: [ + { + id: 'discover:', + link: 'discover', + }, + { + id: 'attack_discovery', + link: securityLink(SecurityPageName.attackDiscovery), + }, + { + id: 'cases', + link: securityLink(SecurityPageName.case), + children: [ + { + id: 'cases_create', + link: securityLink(SecurityPageName.caseCreate), + sideNavStatus: 'hidden', + }, + { + id: 'cases_configure', + link: securityLink(SecurityPageName.caseConfigure), + sideNavStatus: 'hidden', + }, + ], + renderAs: 'panelOpener', + }, + { + id: 'machine_learning-landing', + link: securityLink(SecurityPageName.mlLanding), + children: [ + { + breadcrumbStatus: 'hidden', + children: [ + { + id: 'ml:overview', + link: 'ml:overview', + title: i18nStrings.ml.overview, + }, + { + id: 'ml:notifications', + link: 'ml:notifications', + title: i18nStrings.ml.notifications, + }, + { + id: 'ml:memoryUsage', + link: 'ml:memoryUsage', + title: i18nStrings.ml.memoryUsage, + }, + ], + }, + { + id: 'category-anomaly_detection', + title: i18nStrings.ml.anomalyDetection.title, + breadcrumbStatus: 'hidden', + children: [ + { + id: 'ml:anomalyDetection', + link: 'ml:anomalyDetection', + title: i18nStrings.ml.anomalyDetection.jobs, + }, + { + id: 'ml:anomalyExplorer', + link: 'ml:anomalyExplorer', + title: i18nStrings.ml.anomalyDetection.anomalyExplorer, + }, + { + id: 'ml:singleMetricViewer', + link: 'ml:singleMetricViewer', + title: i18nStrings.ml.anomalyDetection.singleMetricViewer, + }, + { + id: 'ml:suppliedConfigurations', + link: 'ml:suppliedConfigurations', + title: i18nStrings.ml.anomalyDetection.suppliedConfigurations, + }, + { + id: 'ml:settings', + link: 'ml:settings', + title: i18nStrings.ml.anomalyDetection.settings, + }, + ], + }, + { + id: 'category-data_frame analytics', + title: i18nStrings.ml.dataFrameAnalytics.title, + breadcrumbStatus: 'hidden', + children: [ + { + id: 'ml:dataFrameAnalytics', + link: 'ml:dataFrameAnalytics', + title: i18nStrings.ml.dataFrameAnalytics.jobs, + }, + { + id: 'ml:resultExplorer', + link: 'ml:resultExplorer', + title: i18nStrings.ml.dataFrameAnalytics.resultExplorer, + }, + { + id: 'ml:analyticsMap', + link: 'ml:analyticsMap', + title: i18nStrings.ml.dataFrameAnalytics.analyticsMap, + }, + ], + }, + { + id: 'category-model_management', + title: i18nStrings.ml.modelManagement.title, + breadcrumbStatus: 'hidden', + children: [ + { + id: 'ml:nodesOverview', + link: 'ml:nodesOverview', + title: i18nStrings.ml.modelManagement.trainedModels, + }, + ], + }, + { + id: 'category-data_visualizer', + title: i18nStrings.ml.dataVisualizer.title, + breadcrumbStatus: 'hidden', + children: [ + { + id: 'ml:fileUpload', + link: 'ml:fileUpload', + title: i18nStrings.ml.dataVisualizer.fileDataVisualizer, + }, + { + id: 'ml:indexDataVisualizer', + link: 'ml:indexDataVisualizer', + title: i18nStrings.ml.dataVisualizer.dataViewDataVisualizer, + }, + { + id: 'ml:esqlDataVisualizer', + link: 'ml:esqlDataVisualizer', + title: i18nStrings.ml.dataVisualizer.esqlDataVisualizer, + }, + { + id: 'ml:dataDrift', + link: 'ml:dataDrift', + title: i18nStrings.ml.dataVisualizer.dataDrift, + }, + ], + }, + { + id: 'category-aiops_labs', + title: i18nStrings.ml.aiopsLabs.title, + breadcrumbStatus: 'hidden', + children: [ + { + id: 'ml:logRateAnalysis', + link: 'ml:logRateAnalysis', + title: i18nStrings.ml.aiopsLabs.logRateAnalysis, + }, + { + id: 'ml:logPatternAnalysis', + link: 'ml:logPatternAnalysis', + title: i18nStrings.ml.aiopsLabs.logPatternAnalysis, + }, + { + id: 'ml:changePointDetections', + link: 'ml:changePointDetections', + title: i18nStrings.ml.aiopsLabs.changePointDetection, + }, + ], + }, + ], + renderAs: 'panelOpener', + }, + { + id: 'alert_summary', + link: securityLink(SecurityPageName.alertSummary), + }, + { + id: 'configurations', + link: securityLink(SecurityPageName.configurations), + renderAs: 'panelOpener', + children: [ + { + link: securityLink(SecurityPageName.configurationsAiSettings), + }, + { + link: securityLink(SecurityPageName.configurationsBasicRules), + }, + { + link: securityLink(SecurityPageName.configurationsIntegrations), + }, + ], + }, + ], + }, + ], + footer: [ + { + type: 'navItem', + link: securityLink(SecurityPageName.landing), + icon: 'launch', + }, + { + type: 'navItem', + link: 'dev_tools', + title: i18nStrings.devTools, + icon: 'editorCodeBlock', + }, + createStackManagementNavigationTree(), + ], + }); }; diff --git a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/utils.test.ts b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/utils.test.ts deleted file mode 100644 index ea5f8cd81853..000000000000 --- a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/utils.test.ts +++ /dev/null @@ -1,235 +0,0 @@ -/* - * 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 { filterFromWhitelist } from './utils'; -import type { AppDeepLinkId, NodeDefinition } from '@kbn/core-chrome-browser'; - -describe('AI SOC utils', () => { - describe('filterFromWhitelist', () => { - const nodes: Array> = [ - { - breadcrumbStatus: 'hidden', - children: [ - { - id: 'attack_discovery', - link: 'securitySolutionUI:attack_discovery', - title: 'Attack discovery', - }, - { - id: 'cases', - link: 'securitySolutionUI:cases', - title: 'Cases', - children: [ - { - id: 'cases_create', - link: 'securitySolutionUI:cases_create', - title: 'Create', - sideNavStatus: 'hidden', - }, - { - id: 'cases_configure', - link: 'securitySolutionUI:cases_configure', - title: 'Settings', - sideNavStatus: 'hidden', - }, - ], - renderAs: 'panelOpener', - }, - ], - }, - ]; - - it('should filter nodes based on whitelist of IDs', () => { - const idsToAttach = ['cases', 'attack_discovery']; - const result = filterFromWhitelist(nodes, idsToAttach); - expect(result).toEqual([ - { - id: 'attack_discovery', - link: 'securitySolutionUI:attack_discovery', - title: 'Attack discovery', - }, - { - id: 'cases', - link: 'securitySolutionUI:cases', - title: 'Cases', - children: [ - { - id: 'cases_create', - link: 'securitySolutionUI:cases_create', - title: 'Create', - sideNavStatus: 'hidden', - }, - { - id: 'cases_configure', - link: 'securitySolutionUI:cases_configure', - title: 'Settings', - sideNavStatus: 'hidden', - }, - ], - renderAs: 'panelOpener', - }, - ]); - }); - - it('should handle empty nodes array', () => { - const result = filterFromWhitelist([], ['cases']); - expect(result).toEqual([]); - }); - - it('should handle empty idsToAttach array', () => { - const result = filterFromWhitelist(nodes, []); - expect(result).toEqual([]); - }); - }); - - describe('filterFromWhitelist - Larger Dataset', () => { - let bigNodes: Array>; - - beforeEach(() => { - bigNodes = [ - { - breadcrumbStatus: 'hidden', - children: [ - { - id: 'discover:', - link: 'discover', - title: 'Discover', - }, - ], - }, - { - breadcrumbStatus: 'hidden', - children: [ - { - id: 'attack_discovery', - link: 'securitySolutionUI:attack_discovery', - title: 'Attack discovery', - }, - { - id: 'cases', - link: 'securitySolutionUI:cases', - title: 'Cases', - children: [ - { - id: 'cases_create', - link: 'securitySolutionUI:cases_create', - title: 'Create', - sideNavStatus: 'hidden', - }, - { - id: 'cases_configure', - link: 'securitySolutionUI:cases_configure', - title: 'Settings', - sideNavStatus: 'hidden', - }, - ], - renderAs: 'panelOpener', - }, - ], - }, - { - breadcrumbStatus: 'hidden', - children: [ - { - id: 'threat_intelligence', - link: 'securitySolutionUI:threat_intelligence', - title: 'Intelligence', - }, - ], - }, - { - breadcrumbStatus: 'hidden', - children: [ - { - id: 'assets', - link: 'securitySolutionUI:assets', - title: 'Assets', - children: [ - { - id: 'fleet:', - link: 'fleet', - title: 'Fleet', - children: [ - { - id: 'fleet:agents', - link: 'fleet:agents', - title: 'Agents', - }, - { - id: 'fleet:policies', - link: 'fleet:policies', - title: 'Policies', - }, - { - id: 'fleet:enrollment_tokens', - link: 'fleet:enrollment_tokens', - title: 'Enrollment tokens', - }, - { - id: 'fleet:uninstall_tokens', - link: 'fleet:uninstall_tokens', - title: 'Uninstall tokens', - }, - { - id: 'fleet:data_streams', - link: 'fleet:data_streams', - title: 'Data streams', - }, - { - id: 'fleet:settings', - link: 'fleet:settings', - title: 'Settings', - }, - ], - }, - ], - renderAs: 'panelOpener', - }, - ], - }, - { - id: 'management:securityAiAssistantManagement', - link: 'management:securityAiAssistantManagement', - title: 'Knowledge sources', - }, - ]; - }); - - it('should whitelist multiple nodes from deep in the structure', () => { - const result = filterFromWhitelist(bigNodes, ['fleet:policies', 'cases_create']); - expect(result).toHaveLength(2); - expect(result.map((n) => n.id).sort()).toEqual(['cases_create', 'fleet:policies'].sort()); - }); - - it('should preserve entire whitelisted node with children if matched directly', () => { - const result = filterFromWhitelist(bigNodes, ['assets']); - expect(result).toHaveLength(1); - expect(result[0].id).toEqual('assets'); - expect(result[0].children).toBeDefined(); - expect(result[0].children![0].id).toEqual('fleet:'); - }); - - it('should handle no matches found in nested structure', () => { - const result = filterFromWhitelist(bigNodes, ['random1', 'random2']); - expect(result).toEqual([]); - }); - - it('should handle partial matches plus top-level matches', () => { - const result = filterFromWhitelist(bigNodes, ['threat_intelligence', 'fleet:data_streams']); - expect(result).toHaveLength(2); - expect(result.map((r) => r.id).sort()).toEqual( - ['fleet:data_streams', 'threat_intelligence'].sort() - ); - }); - - it('should work if we match the top-level `discover:` node plus a nested fleet child', () => { - const result = filterFromWhitelist(bigNodes, ['discover:', 'fleet:agents']); - expect(result).toHaveLength(2); - expect(result.map((n) => n.id).sort()).toEqual(['discover:', 'fleet:agents'].sort()); - }); - }); -}); diff --git a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/utils.ts b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/utils.ts deleted file mode 100644 index b6be7d32d158..000000000000 --- a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/ai_soc/utils.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * 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 type { AppDeepLinkId, NodeDefinition } from '@kbn/core-chrome-browser'; -// Filter nodes from a whitelist of IDs, handling nested structures -export const filterFromWhitelist = ( - nodes: Array>, - idsToAttach: string[] -): Array> => { - const attachedNodes: Array> = []; - const stack: Array> = [...nodes]; - - while (stack.length > 0) { - const node = stack.pop(); - - if (node) { - if (idsToAttach.includes(node.id as string)) { - attachedNodes.unshift(node); - } else if (node.children) { - stack.unshift(...node.children); - } - } - } - - return attachedNodes; -}; diff --git a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/security_side_navigation.tsx b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/security_side_navigation.tsx new file mode 100644 index 000000000000..f2c98125cb84 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/security_side_navigation.tsx @@ -0,0 +1,592 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React from 'react'; +import * as Rx from 'rxjs'; + +import { EuiCallOut, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; +import type { NavigationTreeDefinition } from '@kbn/core-chrome-browser'; +import { i18n } from '@kbn/i18n'; + +import { + ExternalPageName, + NavigationProvider, + SecurityPageName, +} from '@kbn/security-solution-navigation'; +import { LinkButton, i18nStrings, securityLink } from '@kbn/security-solution-navigation/links'; + +import { type Services } from '../common/services'; +import { createStackManagementNavigationTree } from './stack_management_navigation'; + +const SOLUTION_NAME = i18n.translate( + 'xpack.securitySolutionServerless.navLinks.projectType.title', + { defaultMessage: 'Security' } +); + +export const createSecurityNavigationTree$ = ( + services: Services +): Rx.Observable => { + return Rx.of({ + body: [ + { + type: 'navGroup', + id: 'security_solution_nav', + title: SOLUTION_NAME, + icon: 'logoSecurity', + breadcrumbStatus: 'hidden', + defaultIsCollapsed: false, + children: [ + { + id: 'discover:', + link: 'discover', + }, + { + id: 'dashboards', + link: securityLink(SecurityPageName.dashboards), + renderAs: 'item', + children: [ + { + id: 'overview', + link: securityLink(SecurityPageName.overview), + sideNavStatus: 'hidden', + }, + { + id: 'detection_response', + link: securityLink(SecurityPageName.detectionAndResponse), + sideNavStatus: 'hidden', + }, + { + id: 'cloud_security_posture-dashboard', + link: securityLink(SecurityPageName.cloudSecurityPostureDashboard), + sideNavStatus: 'hidden', + }, + { + id: 'cloud_security_posture-vulnerability_dashboard', + link: securityLink(SecurityPageName.cloudSecurityPostureVulnerabilityDashboard), + sideNavStatus: 'hidden', + }, + { + id: 'entity_analytics', + link: securityLink(SecurityPageName.entityAnalytics), + sideNavStatus: 'hidden', + }, + { + id: 'data_quality', + link: securityLink(SecurityPageName.dataQuality), + sideNavStatus: 'hidden', + }, + ], + }, + { + id: 'rules-landing', + link: securityLink(SecurityPageName.rulesLanding), + title: i18nStrings.rules.title, + children: [ + { + id: 'category-management', + title: i18nStrings.rules.management.title, + breadcrumbStatus: 'hidden', + children: [ + { + id: 'rules', + link: securityLink(SecurityPageName.rules), + renderAs: 'item', + children: [ + { + id: 'rules-add', + link: securityLink(SecurityPageName.rulesAdd), + }, + { + id: 'rules-create', + link: securityLink(SecurityPageName.rulesCreate), + }, + ], + }, + { + id: 'cloud_security_posture-benchmarks', + link: securityLink(SecurityPageName.cloudSecurityPostureBenchmarks), + }, + { + id: 'exceptions', + link: securityLink(SecurityPageName.exceptions), + }, + { + id: 'siem_migrations-rules', + link: securityLink(SecurityPageName.siemMigrationsRules), + title: i18nStrings.rules.management.siemMigrationsRules, + }, + ], + }, + { + id: 'category-discover', + title: i18nStrings.rules.management.discover, + breadcrumbStatus: 'hidden', + children: [ + { + id: 'coverage-overview', + link: securityLink(SecurityPageName.coverageOverview), + }, + ], + }, + ], + renderAs: 'panelOpener', + }, + { + id: 'alerts', + link: securityLink(SecurityPageName.alerts), + }, + { + id: 'attack_discovery', + link: securityLink(SecurityPageName.attackDiscovery), + }, + { + id: 'cloud_security_posture-findings', + link: securityLink(SecurityPageName.cloudSecurityPostureFindings), + }, + { + id: 'cases', + link: securityLink(SecurityPageName.case), + children: [ + { + id: 'cases_create', + link: securityLink(SecurityPageName.caseCreate), + sideNavStatus: 'hidden', + }, + { + id: 'cases_configure', + link: securityLink(SecurityPageName.caseConfigure), + sideNavStatus: 'hidden', + }, + ], + renderAs: 'item', + }, + { + id: 'investigations', + link: securityLink(SecurityPageName.investigations), + title: i18nStrings.investigations.title, + children: [ + { + id: 'timelines', + link: securityLink(SecurityPageName.timelines), + renderAs: 'item', + children: [ + { + id: 'timelines-templates', + link: securityLink(SecurityPageName.timelinesTemplates), + sideNavStatus: 'hidden', + }, + ], + }, + { + id: 'notes', + link: securityLink(SecurityPageName.notes), + renderAs: 'item', + }, + { + id: 'osquery:', + link: 'osquery', + renderAs: 'item', + }, + ], + renderAs: 'panelOpener', + }, + { + id: 'threat_intelligence', + link: securityLink(SecurityPageName.threatIntelligence), + }, + { + id: 'explore', + link: securityLink(SecurityPageName.exploreLanding), + title: i18nStrings.explore.title, + spaceBefore: null, + children: [ + { + id: 'hosts', + link: securityLink(SecurityPageName.hosts), + renderAs: 'item', + children: [ + { + id: 'hosts-all', + link: securityLink(SecurityPageName.hostsAll), + breadcrumbStatus: 'hidden', + }, + { + id: 'hosts-uncommon_processes', + link: securityLink(SecurityPageName.hostsUncommonProcesses), + breadcrumbStatus: 'hidden', + }, + { + id: 'hosts-anomalies', + link: securityLink(SecurityPageName.hostsAnomalies), + breadcrumbStatus: 'hidden', + }, + { + id: 'hosts-events', + link: securityLink(SecurityPageName.hostsEvents), + breadcrumbStatus: 'hidden', + }, + { + id: 'hosts-risk', + link: securityLink(SecurityPageName.hostsRisk), + breadcrumbStatus: 'hidden', + }, + { + id: 'hosts-sessions', + link: securityLink(SecurityPageName.hostsSessions), + breadcrumbStatus: 'hidden', + }, + ], + }, + { + id: 'network', + link: securityLink(SecurityPageName.network), + renderAs: 'item', + children: [ + { + id: 'network-flows', + link: securityLink(SecurityPageName.networkFlows), + breadcrumbStatus: 'hidden', + }, + { + id: 'network-dns', + link: securityLink(SecurityPageName.networkDns), + breadcrumbStatus: 'hidden', + }, + { + id: 'network-http', + link: securityLink(SecurityPageName.networkHttp), + breadcrumbStatus: 'hidden', + }, + { + id: 'network-tls', + link: securityLink(SecurityPageName.networkTls), + breadcrumbStatus: 'hidden', + }, + { + id: 'network-anomalies', + link: securityLink(SecurityPageName.networkAnomalies), + breadcrumbStatus: 'hidden', + }, + { + id: 'network-events', + link: securityLink(SecurityPageName.networkEvents), + breadcrumbStatus: 'hidden', + }, + ], + }, + { + id: 'users', + link: securityLink(SecurityPageName.users), + renderAs: 'item', + children: [ + { + id: 'users-all', + link: securityLink(SecurityPageName.usersAll), + breadcrumbStatus: 'hidden', + }, + { + id: 'users-authentications', + link: securityLink(SecurityPageName.usersAuthentications), + breadcrumbStatus: 'hidden', + }, + { + id: 'users-anomalies', + link: securityLink(SecurityPageName.usersAnomalies), + breadcrumbStatus: 'hidden', + }, + { + id: 'users-risk', + link: securityLink(SecurityPageName.usersRisk), + breadcrumbStatus: 'hidden', + }, + { + id: 'users-events', + link: securityLink(SecurityPageName.usersEvents), + breadcrumbStatus: 'hidden', + }, + ], + }, + ], + renderAs: 'panelOpener', + }, + { + id: 'assets', + link: securityLink(SecurityPageName.assets), + title: i18nStrings.assets.title, + children: [ + { + id: 'fleet:', + link: 'fleet', + title: i18nStrings.assets.fleet.title, + children: [ + { + id: 'fleet:agents', + link: 'fleet:agents', + }, + { + id: 'fleet:policies', + link: 'fleet:policies', + title: i18nStrings.assets.fleet.policies, + }, + { + id: 'fleet:enrollment_tokens', + link: 'fleet:enrollment_tokens', + }, + { + id: 'fleet:uninstall_tokens', + link: 'fleet:uninstall_tokens', + }, + { + id: 'fleet:data_streams', + link: 'fleet:data_streams', + }, + { + id: 'fleet:settings', + link: 'fleet:settings', + }, + ], + }, + { + id: 'endpoints', + link: securityLink(SecurityPageName.endpoints), + title: i18nStrings.assets.endpoints.title, + children: [ + { + id: 'endpoints', + link: securityLink(SecurityPageName.endpoints), + breadcrumbStatus: 'hidden', + }, + { + id: 'policy', + link: securityLink(SecurityPageName.policies), + }, + { + id: 'trusted_apps', + link: securityLink(SecurityPageName.trustedApps), + }, + { + id: 'event_filters', + link: securityLink(SecurityPageName.eventFilters), + }, + { + id: 'host_isolation_exceptions', + link: securityLink(SecurityPageName.hostIsolationExceptions), + }, + { + id: 'blocklist', + link: securityLink(SecurityPageName.blocklist), + }, + { + id: 'response_actions_history', + link: securityLink(SecurityPageName.responseActionsHistory), + }, + ], + }, + { + id: 'assets_custom', + title: '', + renderItem: () => { + return ( + <> + + +

{i18nStrings.assets.integrationsCallout.body}

+ + + + + {i18nStrings.assets.integrationsCallout.button} + + + + +
+ + ); + }, + }, + ], + renderAs: 'panelOpener', + }, + { + id: 'machine_learning-landing', + link: securityLink(SecurityPageName.mlLanding), + title: i18nStrings.ml.title, + children: [ + { + breadcrumbStatus: 'hidden', + children: [ + { + id: 'ml:overview', + link: 'ml:overview', + title: i18nStrings.ml.overview, + }, + { + id: 'ml:notifications', + link: 'ml:notifications', + title: i18nStrings.ml.notifications, + }, + { + id: 'ml:memoryUsage', + link: 'ml:memoryUsage', + title: i18nStrings.ml.memoryUsage, + }, + ], + }, + { + id: 'category-anomaly_detection', + title: i18nStrings.ml.anomalyDetection.title, + breadcrumbStatus: 'hidden', + children: [ + { + id: 'ml:anomalyDetection', + link: 'ml:anomalyDetection', + title: i18nStrings.ml.anomalyDetection.jobs, + }, + { + id: 'ml:anomalyExplorer', + link: 'ml:anomalyExplorer', + title: i18nStrings.ml.anomalyDetection.anomalyExplorer, + }, + { + id: 'ml:singleMetricViewer', + link: 'ml:singleMetricViewer', + title: i18nStrings.ml.anomalyDetection.singleMetricViewer, + }, + { + id: 'ml:suppliedConfigurations', + link: 'ml:suppliedConfigurations', + title: i18nStrings.ml.anomalyDetection.suppliedConfigurations, + }, + { + id: 'ml:settings', + link: 'ml:settings', + title: i18nStrings.ml.anomalyDetection.settings, + }, + ], + }, + { + id: 'category-data_frame analytics', + title: i18nStrings.ml.dataFrameAnalytics.title, + breadcrumbStatus: 'hidden', + children: [ + { + id: 'ml:dataFrameAnalytics', + link: 'ml:dataFrameAnalytics', + title: i18nStrings.ml.dataFrameAnalytics.jobs, + }, + { + id: 'ml:resultExplorer', + link: 'ml:resultExplorer', + title: i18nStrings.ml.dataFrameAnalytics.resultExplorer, + }, + { + id: 'ml:analyticsMap', + link: 'ml:analyticsMap', + title: i18nStrings.ml.dataFrameAnalytics.analyticsMap, + }, + ], + }, + { + id: 'category-model_management', + title: i18nStrings.ml.modelManagement.title, + breadcrumbStatus: 'hidden', + children: [ + { + id: 'ml:nodesOverview', + link: 'ml:nodesOverview', + title: i18nStrings.ml.modelManagement.trainedModels, + }, + ], + }, + { + id: 'category-data_visualizer', + title: i18nStrings.ml.dataVisualizer.title, + breadcrumbStatus: 'hidden', + children: [ + { + id: 'ml:fileUpload', + link: 'ml:fileUpload', + title: i18nStrings.ml.dataVisualizer.fileDataVisualizer, + }, + { + id: 'ml:indexDataVisualizer', + link: 'ml:indexDataVisualizer', + title: i18nStrings.ml.dataVisualizer.dataViewDataVisualizer, + }, + { + id: 'ml:esqlDataVisualizer', + link: 'ml:esqlDataVisualizer', + title: i18nStrings.ml.dataVisualizer.esqlDataVisualizer, + }, + { + id: 'ml:dataDrift', + link: 'ml:dataDrift', + title: i18nStrings.ml.dataVisualizer.dataDrift, + }, + ], + }, + { + id: 'category-aiops_labs', + title: i18nStrings.ml.aiopsLabs.title, + breadcrumbStatus: 'hidden', + children: [ + { + id: 'ml:logRateAnalysis', + link: 'ml:logRateAnalysis', + title: i18nStrings.ml.aiopsLabs.logRateAnalysis, + }, + { + id: 'ml:logPatternAnalysis', + link: 'ml:logPatternAnalysis', + title: i18nStrings.ml.aiopsLabs.logPatternAnalysis, + }, + { + id: 'ml:changePointDetections', + link: 'ml:changePointDetections', + title: i18nStrings.ml.aiopsLabs.changePointDetection, + }, + ], + }, + ], + renderAs: 'panelOpener', + }, + { + id: 'entity_analytics-management', + link: securityLink(SecurityPageName.entityAnalyticsManagement), + title: i18nStrings.entityRiskScore, + sideNavStatus: 'hidden', + }, + { + id: 'entity_analytics-entity_store_management', + link: securityLink(SecurityPageName.entityAnalyticsEntityStoreManagement), + title: i18nStrings.entityStore, + sideNavStatus: 'hidden', + }, + ], + isCollapsible: false, + }, + ], + footer: [ + { + type: 'navItem', + link: securityLink(SecurityPageName.landing), + icon: 'launch', + }, + { + type: 'navItem', + link: 'dev_tools', + title: i18nStrings.devTools, + icon: 'editorCodeBlock', + }, + createStackManagementNavigationTree(), + ], + }); +}; diff --git a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/side_navigation.test.tsx b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/side_navigation.test.tsx new file mode 100644 index 000000000000..6d02a85189ed --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/side_navigation.test.tsx @@ -0,0 +1,60 @@ +/* + * 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 type { ProductLine, ProductTier } from '../../common/product'; +import { mockServices } from '../common/services/__mocks__/services.mock'; +import { initSideNavigation } from './side_navigation'; + +describe('Security Side Nav', () => { + const services = mockServices; + const initNavigationSpy = jest.spyOn(services.serverless, 'initNavigation'); + + afterEach(() => { + initNavigationSpy.mockReset(); + }); + + it('registers the navigation tree definition for serverless security', (done) => { + expect(initNavigationSpy).not.toHaveBeenCalled(); + + initSideNavigation(services, []); + + expect(initNavigationSpy).toHaveBeenCalled(); + + const [, navigationTree$] = initNavigationSpy.mock.calls[0]; + + navigationTree$.subscribe({ + next: (value) => { + expect(value).toMatchSnapshot(); + }, + error: (err) => done(err), + complete: () => done(), + }); + }); + + it('registers the navigation tree definition for serverless security with AI SOC', (done) => { + expect(initNavigationSpy).not.toHaveBeenCalled(); + + initSideNavigation(services, [ + { + product_line: 'ai_soc' as ProductLine, + product_tier: 'search_ai_lake' as ProductTier, + }, + ]); + + expect(initNavigationSpy).toHaveBeenCalled(); + + const [, navigationTree$] = initNavigationSpy.mock.calls[0]; + + navigationTree$.subscribe({ + next: (value) => { + expect(value).toMatchSnapshot(); + }, + error: (err) => done(err), + complete: () => done(), + }); + }); +}); diff --git a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/side_navigation.ts b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/side_navigation.ts index e0d505952a9a..2c1a6f4adce1 100644 --- a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/side_navigation.ts +++ b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/side_navigation.ts @@ -5,18 +5,10 @@ * 2.0. */ -import { i18n } from '@kbn/i18n'; -import type { AppDeepLinkId, GroupDefinition, NodeDefinition } from '@kbn/core-chrome-browser'; -import produce from 'immer'; -import { map } from 'rxjs'; import type { SecurityProductTypes } from '../../common/config'; import { type Services } from '../common/services'; -import { applyAiSocNavigation } from './ai_soc/ai_soc_navigation'; - -const PROJECT_SETTINGS_TITLE = i18n.translate( - 'xpack.securitySolutionServerless.navLinks.projectSettings.title', - { defaultMessage: 'Project Settings' } -); +import { createAiSocNavigationTree$, shouldUseAINavigation } from './ai_soc/ai_soc_navigation'; +import { createSecurityNavigationTree$ } from './security_side_navigation'; export const initSideNavigation = async ( services: Services, @@ -24,116 +16,11 @@ export const initSideNavigation = async ( ) => { services.securitySolution.setIsSolutionNavigationEnabled(true); - const { navigationTree$, panelContentProvider } = - await services.securitySolution.getSolutionNavigation(); + const navigationTree$ = shouldUseAINavigation(productTypes) + ? createAiSocNavigationTree$() + : createSecurityNavigationTree$(services); - const serverlessNavigationTree$ = navigationTree$.pipe( - map((navigationTree) => - produce(navigationTree, (draft) => { - // Adds serverless cloud links to the footer group ("Product settings" dropdown) - const footerGroup: GroupDefinition | undefined = draft.footer?.find( - ({ type }) => type === 'navGroup' - ) as GroupDefinition; - const management = footerGroup?.children.find((child) => child.link === 'management'); - if (management) { - management.renderAs = 'panelOpener'; - management.id = 'stack_management'; - management.spaceBefore = null; - management.children = stackManagementLinks; - delete management.link; - } - if (footerGroup) { - footerGroup.title = PROJECT_SETTINGS_TITLE; - footerGroup.children.push({ cloudLink: 'billingAndSub', openInNewTab: true }); - } - - applyAiSocNavigation(draft, productTypes); - }) - ) - ); - - services.serverless.initNavigation('security', serverlessNavigationTree$, { - panelContentProvider, + services.serverless.initNavigation('security', navigationTree$, { dataTestSubj: 'securitySolutionSideNav', }); }; - -// Stack Management static node definition -const stackManagementLinks: Array> = [ - { - title: i18n.translate('xpack.securitySolutionServerless.navLinks.projectSettings.mngt.data', { - defaultMessage: 'Data', - }), - breadcrumbStatus: 'hidden', - children: [ - { link: 'management:index_management', breadcrumbStatus: 'hidden' }, - { link: 'management:transform', breadcrumbStatus: 'hidden' }, - { link: 'management:ingest_pipelines', breadcrumbStatus: 'hidden' }, - { link: 'management:dataViews', breadcrumbStatus: 'hidden' }, - { link: 'management:jobsListLink', breadcrumbStatus: 'hidden' }, - { link: 'management:pipelines', breadcrumbStatus: 'hidden' }, - { link: 'management:data_quality', breadcrumbStatus: 'hidden' }, - { link: 'management:data_usage', breadcrumbStatus: 'hidden' }, - ], - }, - { - title: i18n.translate('xpack.securitySolutionServerless.navLinks.projectSettings.mngt.access', { - defaultMessage: 'Access', - }), - breadcrumbStatus: 'hidden', - children: [ - { link: 'management:api_keys', breadcrumbStatus: 'hidden' }, - { link: 'management:roles', breadcrumbStatus: 'hidden' }, - { - cloudLink: 'userAndRoles', - title: i18n.translate( - 'xpack.securitySolutionServerless.navLinks.projectSettings.mngt.usersAndRoles', - { defaultMessage: 'Manage organization members' } - ), - }, - ], - }, - { - title: i18n.translate( - 'xpack.securitySolutionServerless.navLinks.projectSettings.mngt.alertsAndInsights', - { defaultMessage: 'Alerts and Insights' } - ), - breadcrumbStatus: 'hidden', - children: [ - { link: 'management:triggersActions', breadcrumbStatus: 'hidden' }, - { link: 'management:triggersActionsConnectors', breadcrumbStatus: 'hidden' }, - { link: 'management:maintenanceWindows', breadcrumbStatus: 'hidden' }, - { link: 'securitySolutionUI:entity_analytics-management', breadcrumbStatus: 'hidden' }, - { - link: 'securitySolutionUI:entity_analytics-entity_store_management', - breadcrumbStatus: 'hidden', - }, - ], - }, - { - title: i18n.translate( - 'xpack.securitySolutionServerless.navLinks.projectSettings.mngt.content', - { defaultMessage: 'Content' } - ), - breadcrumbStatus: 'hidden', - children: [ - { link: 'management:spaces', breadcrumbStatus: 'hidden' }, - { link: 'management:objects', breadcrumbStatus: 'hidden' }, - { link: 'management:filesManagement', breadcrumbStatus: 'hidden' }, - { link: 'management:reporting', breadcrumbStatus: 'hidden' }, - { link: 'management:tags', breadcrumbStatus: 'hidden' }, - { link: 'maps' }, - { link: 'visualize' }, - ], - }, - { - title: i18n.translate('xpack.securitySolutionServerless.navLinks.projectSettings.mngt.other', { - defaultMessage: 'Other', - }), - breadcrumbStatus: 'hidden', - children: [ - { link: 'management:settings', breadcrumbStatus: 'hidden' }, - { link: 'management:securityAiAssistantManagement', breadcrumbStatus: 'hidden' }, - ], - }, -]; diff --git a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/stack_management_navigation.ts b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/stack_management_navigation.ts new file mode 100644 index 000000000000..0ff625193de9 --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/stack_management_navigation.ts @@ -0,0 +1,162 @@ +/* + * 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 type { GroupDefinition } from '@kbn/core-chrome-browser'; +import { SecurityPageName } from '@kbn/security-solution-navigation'; +import { i18nStrings, securityLink } from '@kbn/security-solution-navigation/links'; + +export const createStackManagementNavigationTree = (): GroupDefinition => ({ + type: 'navGroup', + id: 'category-management', + title: i18nStrings.projectSettings.title, + icon: 'gear', + breadcrumbStatus: 'hidden', + children: [ + { + id: 'stack_management', + title: i18nStrings.stackManagement.title, + renderAs: 'panelOpener', + spaceBefore: null, + children: [ + { + title: i18nStrings.stackManagement.data.title, + breadcrumbStatus: 'hidden', + children: [ + { + link: 'management:index_management', + breadcrumbStatus: 'hidden', + }, + { + link: 'management:transform', + breadcrumbStatus: 'hidden', + }, + { + link: 'management:ingest_pipelines', + breadcrumbStatus: 'hidden', + }, + { + link: 'management:dataViews', + breadcrumbStatus: 'hidden', + }, + { + link: 'management:jobsListLink', + breadcrumbStatus: 'hidden', + }, + { + link: 'management:pipelines', + breadcrumbStatus: 'hidden', + }, + { + link: 'management:data_quality', + breadcrumbStatus: 'hidden', + }, + { + link: 'management:data_usage', + breadcrumbStatus: 'hidden', + }, + ], + }, + { + title: i18nStrings.stackManagement.access.title, + breadcrumbStatus: 'hidden', + children: [ + { + link: 'management:api_keys', + breadcrumbStatus: 'hidden', + }, + { + link: 'management:roles', + breadcrumbStatus: 'hidden', + }, + { + cloudLink: 'userAndRoles', + title: i18nStrings.stackManagement.access.usersAndRoles, + }, + ], + }, + { + title: i18nStrings.stackManagement.alertsAndInsights.title, + breadcrumbStatus: 'hidden', + children: [ + { + link: 'management:triggersActions', + breadcrumbStatus: 'hidden', + }, + { + link: 'management:triggersActionsConnectors', + breadcrumbStatus: 'hidden', + }, + { + link: 'management:maintenanceWindows', + breadcrumbStatus: 'hidden', + }, + { + link: securityLink(SecurityPageName.entityAnalyticsManagement), + breadcrumbStatus: 'hidden', + }, + { + link: securityLink(SecurityPageName.entityAnalyticsEntityStoreManagement), + breadcrumbStatus: 'hidden', + }, + ], + }, + { + title: i18nStrings.stackManagement.content.title, + breadcrumbStatus: 'hidden', + children: [ + { + link: 'management:spaces', + breadcrumbStatus: 'hidden', + }, + { + link: 'management:objects', + breadcrumbStatus: 'hidden', + }, + { + link: 'management:filesManagement', + breadcrumbStatus: 'hidden', + }, + { + link: 'management:reporting', + breadcrumbStatus: 'hidden', + }, + { + link: 'management:tags', + breadcrumbStatus: 'hidden', + }, + { + link: 'maps', + }, + { + link: 'visualize', + }, + ], + }, + { + title: i18nStrings.stackManagement.other.title, + breadcrumbStatus: 'hidden', + children: [ + { + link: 'management:settings', + breadcrumbStatus: 'hidden', + }, + { + link: 'management:securityAiAssistantManagement', + breadcrumbStatus: 'hidden', + }, + ], + }, + ], + }, + { + link: 'integrations', + }, + { + cloudLink: 'billingAndSub', + }, + ], +}); diff --git a/x-pack/test/functional_solution_sidenav/tests/security_sidenav.ts b/x-pack/test/functional_solution_sidenav/tests/security_sidenav.ts index 12ad88677b4f..622d6a78809a 100644 --- a/x-pack/test/functional_solution_sidenav/tests/security_sidenav.ts +++ b/x-pack/test/functional_solution_sidenav/tests/security_sidenav.ts @@ -51,7 +51,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { // check the Investigations subsection await solutionNavigation.sidenav.openPanel('investigations'); // open Investigations panel - await testSubjects.click(`~solutionSideNavPanelLink-timelines`); + await testSubjects.click(`~panelNavItem-id-timelines`); await solutionNavigation.sidenav.expectLinkActive({ navId: 'investigations' }); await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Timelines' }); await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/explore/navigation/navigation.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/explore/navigation/navigation.cy.ts index 427210756286..2ef28795ed91 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/explore/navigation/navigation.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/explore/navigation/navigation.cy.ts @@ -66,7 +66,6 @@ import { OSQUERY_URL, MACHINE_LEARNING_LANDING_URL, ASSETS_URL, - FLEET_URL, HOSTS_URL, } from '../../../urls/navigation'; import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management'; @@ -275,7 +274,7 @@ describe('Serverless side navigation links', { tags: '@serverless' }, () => { cy.url().should('include', RULES_MANAGEMENT_URL); }); - it('navigates to the Rules page', () => { + it('navigates to the CSP Benchmarks page', () => { navigateFromHeaderTo(ServerlessHeaders.CSP_BENCHMARKS, true); cy.url().should('include', CSP_BENCHMARKS_URL); }); @@ -352,10 +351,6 @@ describe('Serverless side navigation links', { tags: '@serverless' }, () => { navigateFromHeaderTo(ServerlessHeaders.ENDPOINTS, true); cy.url().should('include', ENDPOINTS_URL); }); - it('navigates to the Fleet page', () => { - navigateFromHeaderTo(ServerlessHeaders.FLEET, true); - cy.url().should('include', FLEET_URL); - }); it('navigates to the Machine learning landing page', () => { navigateFromHeaderTo(ServerlessHeaders.MACHINE_LEARNING, true); cy.url().should('include', MACHINE_LEARNING_LANDING_URL); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/serverless_security_header.ts b/x-pack/test/security_solution_cypress/cypress/screens/serverless_security_header.ts index bf3c04a90395..15e0777f9d90 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/serverless_security_header.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/serverless_security_header.ts @@ -47,45 +47,44 @@ export const THREAT_INTELLIGENCE = export const CASES = '[data-test-subj*="nav-item-deepLinkId-securitySolutionUI:cases"]'; // nested panel links -export const OVERVIEW = '[data-test-subj="solutionSideNavPanelLink-overview"]'; +export const OVERVIEW = '[data-test-subj~="panelNavItem-id-overview"]'; -export const DETECTION_RESPONSE = '[data-test-subj="solutionSideNavPanelLink-detection_response"]'; +export const DETECTION_RESPONSE = '[data-test-subj~="panelNavItem-id-detection_response"]'; -export const ENTITY_ANALYTICS = '[data-test-subj="solutionSideNavPanelLink-entity_analytics"]'; +export const ENTITY_ANALYTICS = '[data-test-subj~="panelNavItem-id-entity_analytics"]'; -export const TIMELINES = '[data-test-subj="solutionSideNavPanelLink-timelines"]'; -export const OSQUERY = '[data-test-subj="solutionSideNavPanelLink-osquery:"]'; +export const TIMELINES = '[data-test-subj~="panelNavItem-id-timelines"]'; +export const OSQUERY = '[data-test-subj~="panelNavItem-id-osquery:"]'; -export const KUBERNETES = '[data-test-subj="solutionSideNavPanelLink-kubernetes"]'; +export const KUBERNETES = '[data-test-subj~="panelNavItem-id-kubernetes"]'; -export const CSP_DASHBOARD = - '[data-test-subj="solutionSideNavPanelLink-cloud_security_posture-dashboard"]'; +export const CSP_DASHBOARD = '[data-test-subj~="panelNavItem-id-cloud_security_posture-dashboard"]'; -export const HOSTS = '[data-test-subj="solutionSideNavPanelLink-hosts"]'; +export const HOSTS = '[data-test-subj~="panelNavItem-id-hosts"]'; -export const FLEET = '[data-test-subj="solutionSideNavPanelLink-fleet:"]'; -export const ENDPOINTS = '[data-test-subj="solutionSideNavPanelLink-endpoints"]'; +export const FLEET = '[data-test-subj~="panelNavItem-id-fleet:"]'; +export const ENDPOINTS = '[data-test-subj~="panelNavItem-id-endpoints"]'; -export const POLICIES = '[data-test-subj="solutionSideNavPanelLink-policy"]'; +export const POLICIES = '[data-test-subj~="panelNavItem-id-policy"]'; -export const TRUSTED_APPS = '[data-test-subj="solutionSideNavPanelLink-trusted_apps"]'; +export const TRUSTED_APPS = '[data-test-subj~="panelNavItem-id-trusted_apps"]'; -export const EVENT_FILTERS = '[data-test-subj="solutionSideNavPanelLink-event_filters"]'; +export const EVENT_FILTERS = '[data-test-subj~="panelNavItem-id-event_filters"]'; -export const BLOCKLIST = '[data-test-subj="solutionSideNavPanelLink-blocklist"]'; +export const BLOCKLIST = '[data-test-subj~="panelNavItem-id-blocklist"]'; export const CSP_BENCHMARKS = - '[data-test-subj="solutionSideNavPanelLink-cloud_security_posture-benchmarks"]'; + '[data-test-subj~="panelNavItem-id-cloud_security_posture-benchmarks"]'; -export const RULES_COVERAGE = '[data-test-subj="solutionSideNavPanelLink-coverage-overview"]'; +export const RULES_COVERAGE = '[data-test-subj~="panelNavItem-id-coverage-overview"]'; -export const NETWORK = '[data-test-subj="solutionSideNavPanelLink-network"]'; +export const NETWORK = '[data-test-subj~="panelNavItem-id-network"]'; -export const USERS = '[data-test-subj="solutionSideNavPanelLink-users"]'; +export const USERS = '[data-test-subj~="panelNavItem-id-users"]'; -export const RULES = '[data-test-subj="solutionSideNavPanelLink-rules"]'; +export const RULES = '[data-test-subj~="panelNavItem-id-rules"]'; -export const EXCEPTIONS = '[data-test-subj="solutionSideNavPanelLink-exceptions"]'; +export const EXCEPTIONS = '[data-test-subj~="panelNavItem-id-exceptions"]'; export const getBreadcrumb = (deepLinkId: string) => { return `breadcrumb-deepLinkId-${deepLinkId}`; diff --git a/x-pack/test_serverless/functional/services/ml/security_navigation.ts b/x-pack/test_serverless/functional/services/ml/security_navigation.ts index 70db8900b93e..e9711c88888f 100644 --- a/x-pack/test_serverless/functional/services/ml/security_navigation.ts +++ b/x-pack/test_serverless/functional/services/ml/security_navigation.ts @@ -12,10 +12,10 @@ export function MachineLearningNavigationProviderSecurity({ getService }: FtrPro async function navigateToArea(id: string) { await testSubjects.click('~panelOpener-deepLinkId-securitySolutionUI:machine_learning-landing'); - await testSubjects.existOrFail(`~solutionSideNavPanelLink-ml:${id}`, { + await testSubjects.existOrFail(`~panelNavItem-id-ml:${id}`, { timeout: 60 * 1000, }); - await testSubjects.click(`~solutionSideNavPanelLink-ml:${id}`); + await testSubjects.click(`~panelNavItem-id-ml:${id}`); } return {