From 6f6e804132e020268ec68d066c91261daf2afad5 Mon Sep 17 00:00:00 2001 From: Mykola Harmash Date: Fri, 27 Oct 2023 15:57:01 +0200 Subject: [PATCH 1/2] [ObsUX] Toggle Hosts sidenav item in serverless --- .../settings/observability_project/index.ts | 1 + .../hooks/use_side_navigation_settings.ts | 25 + .../components/side_navigation/index.tsx | 431 +++++++++--------- .../page_objects/svl_common_navigation.ts | 11 + .../test_suites/observability/infra/index.ts | 1 + .../observability/infra/navigation.ts | 63 +++ 6 files changed, 324 insertions(+), 208 deletions(-) create mode 100644 x-pack/plugins/serverless_observability/public/components/side_navigation/hooks/use_side_navigation_settings.ts create mode 100644 x-pack/test_serverless/functional/test_suites/observability/infra/navigation.ts diff --git a/packages/serverless/settings/observability_project/index.ts b/packages/serverless/settings/observability_project/index.ts index a1ae020b8abe3..cae05789e3116 100644 --- a/packages/serverless/settings/observability_project/index.ts +++ b/packages/serverless/settings/observability_project/index.ts @@ -27,4 +27,5 @@ export const OBSERVABILITY_PROJECT_SETTINGS = [ settings.OBSERVABILITY_APM_TRACE_EXPLORER_TAB_ID, settings.OBSERVABILITY_ENABLE_AWS_LAMBDA_METRICS_ID, settings.OBSERVABILITY_APM_ENABLE_CRITICAL_PATH_ID, + settings.OBSERVABILITY_ENABLE_INFRASTRUCTURE_HOSTS_VIEW_ID, ]; diff --git a/x-pack/plugins/serverless_observability/public/components/side_navigation/hooks/use_side_navigation_settings.ts b/x-pack/plugins/serverless_observability/public/components/side_navigation/hooks/use_side_navigation_settings.ts new file mode 100644 index 0000000000000..2ba83663cabc6 --- /dev/null +++ b/x-pack/plugins/serverless_observability/public/components/side_navigation/hooks/use_side_navigation_settings.ts @@ -0,0 +1,25 @@ +/* + * 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 { CoreStart } from '@kbn/core/public'; +import useObservable from 'react-use/lib/useObservable'; +import { enableInfrastructureHostsView } from '@kbn/observability-plugin/public'; + +export interface SideNavigationSettings { + hasInfrastructureHosts: boolean; +} + +export function useSideNavigationSettings(core: CoreStart): SideNavigationSettings { + const hasInfrastructureHosts = useObservable( + core.settings.client.get$(enableInfrastructureHostsView), + false + ); + + return { + hasInfrastructureHosts, + }; +} diff --git a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx index d53281dbf6de1..b57fe439c38be 100644 --- a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx +++ b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx @@ -13,228 +13,237 @@ import { NavigationKibanaProvider, NavigationTreeDefinition, } from '@kbn/shared-ux-chrome-navigation'; -import React from 'react'; +import React, { useMemo } from 'react'; import { i18n } from '@kbn/i18n'; +import { + SideNavigationSettings, + useSideNavigationSettings, +} from './hooks/use_side_navigation_settings'; -const navigationTree: NavigationTreeDefinition = { - body: [ - { type: 'recentlyAccessed' }, - { - type: 'navGroup', - id: 'observability_project_nav', - title: 'Observability', - icon: 'logoObservability', - defaultIsCollapsed: false, - isCollapsible: false, - breadcrumbStatus: 'hidden', - children: [ - { - title: i18n.translate('xpack.serverlessObservability.nav.logExplorer', { - defaultMessage: 'Log Explorer', - }), - link: 'observability-log-explorer', - renderAs: 'item', - children: [ - { - // This is to show "discover" breadcrumbs when navigating from "log explorer" to "discover" - link: 'discover', - sideNavStatus: 'hidden', - }, - ], - }, - { - title: i18n.translate('xpack.serverlessObservability.nav.dashboards', { - defaultMessage: 'Dashboards', - }), - link: 'dashboards', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/dashboards')); - }, - }, - { - title: i18n.translate('xpack.serverlessObservability.nav.visualizations', { - defaultMessage: 'Visualizations', - }), - link: 'visualize', - getIsActive: ({ pathNameSerialized, prepend }) => { - return ( - pathNameSerialized.startsWith(prepend('/app/visualize')) || - pathNameSerialized.startsWith(prepend('/app/lens')) || - pathNameSerialized.startsWith(prepend('/app/maps')) - ); +function getNavigationTree(settings: SideNavigationSettings): NavigationTreeDefinition { + return { + body: [ + { type: 'recentlyAccessed' }, + { + type: 'navGroup', + id: 'observability_project_nav', + title: 'Observability', + icon: 'logoObservability', + defaultIsCollapsed: false, + isCollapsible: false, + breadcrumbStatus: 'hidden', + children: [ + { + title: i18n.translate('xpack.serverlessObservability.nav.logExplorer', { + defaultMessage: 'Log Explorer', + }), + link: 'observability-log-explorer', + renderAs: 'item', + children: [ + { + // This is to show "discover" breadcrumbs when navigating from "log explorer" to "discover" + link: 'discover', + sideNavStatus: 'hidden', + }, + ], }, - }, - { - link: 'observability-overview:alerts', - }, - { - link: 'observability-overview:cases', - renderAs: 'item', - children: [ - { - link: 'observability-overview:cases_configure', + { + title: i18n.translate('xpack.serverlessObservability.nav.dashboards', { + defaultMessage: 'Dashboards', + }), + link: 'dashboards', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith(prepend('/app/dashboards')); }, - { - link: 'observability-overview:cases_create', + }, + { + title: i18n.translate('xpack.serverlessObservability.nav.visualizations', { + defaultMessage: 'Visualizations', + }), + link: 'visualize', + getIsActive: ({ pathNameSerialized, prepend }) => { + return ( + pathNameSerialized.startsWith(prepend('/app/visualize')) || + pathNameSerialized.startsWith(prepend('/app/lens')) || + pathNameSerialized.startsWith(prepend('/app/maps')) + ); }, - ], - }, - { - link: 'observability-overview:slos', - }, - { - id: 'aiops', - title: 'AIOps', - renderAs: 'accordion', - spaceBefore: null, - children: [ - { - title: i18n.translate('xpack.serverlessObservability.nav.ml.jobs', { - defaultMessage: 'Anomaly detection', - }), - link: 'ml:anomalyDetection', - renderAs: 'item', - children: [ - { - link: 'ml:singleMetricViewer', - }, - { - link: 'ml:anomalyExplorer', + }, + { + link: 'observability-overview:alerts', + }, + { + link: 'observability-overview:cases', + renderAs: 'item', + children: [ + { + link: 'observability-overview:cases_configure', + }, + { + link: 'observability-overview:cases_create', + }, + ], + }, + { + link: 'observability-overview:slos', + }, + { + id: 'aiops', + title: 'AIOps', + renderAs: 'accordion', + spaceBefore: null, + children: [ + { + title: i18n.translate('xpack.serverlessObservability.nav.ml.jobs', { + defaultMessage: 'Anomaly detection', + }), + link: 'ml:anomalyDetection', + renderAs: 'item', + children: [ + { + link: 'ml:singleMetricViewer', + }, + { + link: 'ml:anomalyExplorer', + }, + { + link: 'ml:settings', + }, + ], + }, + { + title: i18n.translate('xpack.serverlessObservability.ml.logRateAnalysis', { + defaultMessage: 'Log rate analysis', + }), + link: 'ml:logRateAnalysis', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.includes(prepend('/app/ml/aiops/log_rate_analysis')); }, - { - link: 'ml:settings', + }, + { + title: i18n.translate('xpack.serverlessObservability.ml.changePointDetection', { + defaultMessage: 'Change point detection', + }), + link: 'ml:changePointDetections', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.includes( + prepend('/app/ml/aiops/change_point_detection') + ); }, - ], - }, - { - title: i18n.translate('xpack.serverlessObservability.ml.logRateAnalysis', { - defaultMessage: 'Log rate analysis', - }), - link: 'ml:logRateAnalysis', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.includes(prepend('/app/ml/aiops/log_rate_analysis')); }, - }, - { - title: i18n.translate('xpack.serverlessObservability.ml.changePointDetection', { - defaultMessage: 'Change point detection', - }), - link: 'ml:changePointDetections', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.includes(prepend('/app/ml/aiops/change_point_detection')); + { + title: i18n.translate('xpack.serverlessObservability.nav.ml.job.notifications', { + defaultMessage: 'Job notifications', + }), + link: 'ml:notifications', }, - }, - { - title: i18n.translate('xpack.serverlessObservability.nav.ml.job.notifications', { - defaultMessage: 'Job notifications', - }), - link: 'ml:notifications', - }, - ], - }, - { - id: 'apm', - title: i18n.translate('xpack.serverlessObservability.nav.applications', { - defaultMessage: 'Applications', - }), - renderAs: 'accordion', - children: [ - { - link: 'apm:services', - getIsActive: ({ pathNameSerialized }) => { - const regex = /app\/apm\/.*service.*/; - return regex.test(pathNameSerialized); + ], + }, + { + id: 'apm', + title: i18n.translate('xpack.serverlessObservability.nav.applications', { + defaultMessage: 'Applications', + }), + renderAs: 'accordion', + children: [ + { + link: 'apm:services', + getIsActive: ({ pathNameSerialized }) => { + const regex = /app\/apm\/.*service.*/; + return regex.test(pathNameSerialized); + }, }, - }, - { - link: 'apm:traces', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/apm/traces')); + { + link: 'apm:traces', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith(prepend('/app/apm/traces')); + }, }, - }, - { - link: 'apm:dependencies', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/apm/dependencies')); + { + link: 'apm:dependencies', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith(prepend('/app/apm/dependencies')); + }, }, - }, - ], - }, - { - id: 'metrics', - title: i18n.translate('xpack.serverlessObservability.nav.infrastructure', { - defaultMessage: 'Infrastructure', - }), - renderAs: 'accordion', - children: [ - { - link: 'metrics:inventory', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/metrics/inventory')); + ], + }, + { + id: 'metrics', + title: i18n.translate('xpack.serverlessObservability.nav.infrastructure', { + defaultMessage: 'Infrastructure', + }), + renderAs: 'accordion', + children: [ + { + link: 'metrics:inventory', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith(prepend('/app/metrics/inventory')); + }, }, - }, - { - link: 'metrics:hosts', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/metrics/hosts')); + { + link: 'metrics:hosts', + sideNavStatus: settings.hasInfrastructureHosts ? 'visible' : 'hidden', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith(prepend('/app/metrics/hosts')); + }, }, - }, - ], - }, - ], - }, - ], - footer: [ - { - type: 'navItem', - title: i18n.translate('xpack.serverlessObservability.nav.getStarted', { - defaultMessage: 'Get started', - }), - link: 'observabilityOnboarding', - icon: 'launch', - }, - { - type: 'navItem', - id: 'devTools', - title: i18n.translate('xpack.serverlessObservability.nav.devTools', { - defaultMessage: 'Developer tools', - }), - link: 'dev_tools', - icon: 'editorCodeBlock', - }, - { - type: 'navGroup', - id: 'project_settings_project_nav', - title: i18n.translate('xpack.serverlessObservability.nav.projectSettings', { - defaultMessage: 'Project settings', - }), - icon: 'gear', - breadcrumbStatus: 'hidden', - children: [ - { - link: 'management', - title: i18n.translate('xpack.serverlessObservability.nav.mngt', { - defaultMessage: 'Management', - }), - }, - { - link: 'integrations', - }, - { - link: 'fleet', - }, - { - id: 'cloudLinkUserAndRoles', - cloudLink: 'userAndRoles', - }, - { - id: 'cloudLinkBilling', - cloudLink: 'billingAndSub', - }, - ], - }, - ], -}; + ], + }, + ], + }, + ], + footer: [ + { + type: 'navItem', + title: i18n.translate('xpack.serverlessObservability.nav.getStarted', { + defaultMessage: 'Get started', + }), + link: 'observabilityOnboarding', + icon: 'launch', + }, + { + type: 'navItem', + id: 'devTools', + title: i18n.translate('xpack.serverlessObservability.nav.devTools', { + defaultMessage: 'Developer tools', + }), + link: 'dev_tools', + icon: 'editorCodeBlock', + }, + { + type: 'navGroup', + id: 'project_settings_project_nav', + title: i18n.translate('xpack.serverlessObservability.nav.projectSettings', { + defaultMessage: 'Project settings', + }), + icon: 'gear', + breadcrumbStatus: 'hidden', + children: [ + { + link: 'management', + title: i18n.translate('xpack.serverlessObservability.nav.mngt', { + defaultMessage: 'Management', + }), + }, + { + link: 'integrations', + }, + { + link: 'fleet', + }, + { + id: 'cloudLinkUserAndRoles', + cloudLink: 'userAndRoles', + }, + { + id: 'cloudLinkBilling', + cloudLink: 'billingAndSub', + }, + ], + }, + ], + }; +} export const getObservabilitySideNavComponent = ( @@ -242,6 +251,12 @@ export const getObservabilitySideNavComponent = { serverless, cloud }: { serverless: ServerlessPluginStart; cloud: CloudStart } ) => () => { + const settings = useSideNavigationSettings(core); + + const navigationTree = useMemo(() => { + return getNavigationTree(settings); + }, [settings]); + return ( diff --git a/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts b/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts index 483496315bd04..41101d5a653d4 100644 --- a/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts +++ b/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts @@ -65,6 +65,17 @@ export function SvlCommonNavigationProvider(ctx: FtrProviderContext) { expect(await getByVisibleText('~nav-item', by.text)).not.be(null); } }, + async expectLinkMissing( + by: { deepLinkId: AppDeepLinkId } | { navId: string } | { text: string } + ) { + if ('deepLinkId' in by) { + await testSubjects.missingOrFail(`~nav-item-deepLinkId-${by.deepLinkId}`); + } else if ('navId' in by) { + await testSubjects.missingOrFail(`~nav-item-id-${by.navId}`); + } else { + expect(await getByVisibleText('~nav-item', by.text)).be(null); + } + }, async expectLinkActive( by: { deepLinkId: AppDeepLinkId } | { navId: string } | { text: string } ) { diff --git a/x-pack/test_serverless/functional/test_suites/observability/infra/index.ts b/x-pack/test_serverless/functional/test_suites/observability/infra/index.ts index 814b0c97e4b1a..b646ba71f960e 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/infra/index.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/infra/index.ts @@ -10,6 +10,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('Observability Infra', function () { loadTestFile(require.resolve('./header_menu')); + loadTestFile(require.resolve('./navigation')); loadTestFile(require.resolve('./node_details')); loadTestFile(require.resolve('./hosts_page')); loadTestFile(require.resolve('./infra')); diff --git a/x-pack/test_serverless/functional/test_suites/observability/infra/navigation.ts b/x-pack/test_serverless/functional/test_suites/observability/infra/navigation.ts new file mode 100644 index 0000000000000..6f03c8831ce85 --- /dev/null +++ b/x-pack/test_serverless/functional/test_suites/observability/infra/navigation.ts @@ -0,0 +1,63 @@ +/* + * 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 { enableInfrastructureHostsView } from '@kbn/observability-plugin/common'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default ({ getPageObjects, getService }: FtrProviderContext) => { + const kibanaServer = getService('kibanaServer'); + const svlObltNavigation = getService('svlObltNavigation'); + const browser = getService('browser'); + const pageObjects = getPageObjects(['svlCommonPage', 'svlCommonNavigation', 'header']); + + const setHostsSetting = async (value: boolean) => { + await kibanaServer.uiSettings.update({ [enableInfrastructureHostsView]: value }); + await browser.refresh(); + await pageObjects.svlCommonNavigation.expectExists(); + }; + + const openInfraSection = async () => { + await pageObjects.svlCommonNavigation.sidenav.openSection('observability_project_nav.metrics'); + }; + + describe('Infra Side Navigation', () => { + before(async () => { + await pageObjects.svlCommonPage.login(); + await svlObltNavigation.navigateToLandingPage(); + }); + + after(async () => { + await pageObjects.svlCommonPage.forceLogout(); + }); + + describe('when Hosts settings is on', () => { + before(async () => { + await setHostsSetting(true); + await openInfraSection(); + }); + + it("shows the 'Hosts' nav item", async () => { + await pageObjects.svlCommonNavigation.sidenav.expectLinkExists({ + deepLinkId: 'metrics:hosts', + }); + }); + }); + + describe('when Hosts settings is off', () => { + before(async () => { + await setHostsSetting(false); + await openInfraSection(); + }); + + it("hides the 'Hosts' nav item", async () => { + await pageObjects.svlCommonNavigation.sidenav.expectLinkMissing({ + deepLinkId: 'metrics:hosts', + }); + }); + }); + }); +}; From 11ec043fedc1e7e4e629949adc403e5b7d61da4f Mon Sep 17 00:00:00 2001 From: Mykola Harmash Date: Fri, 27 Oct 2023 17:06:10 +0200 Subject: [PATCH 2/2] Remove redundant sidenav logic --- .../hooks/use_side_navigation_settings.ts | 25 - .../components/side_navigation/index.tsx | 431 +++++++++--------- 2 files changed, 208 insertions(+), 248 deletions(-) delete mode 100644 x-pack/plugins/serverless_observability/public/components/side_navigation/hooks/use_side_navigation_settings.ts diff --git a/x-pack/plugins/serverless_observability/public/components/side_navigation/hooks/use_side_navigation_settings.ts b/x-pack/plugins/serverless_observability/public/components/side_navigation/hooks/use_side_navigation_settings.ts deleted file mode 100644 index 2ba83663cabc6..0000000000000 --- a/x-pack/plugins/serverless_observability/public/components/side_navigation/hooks/use_side_navigation_settings.ts +++ /dev/null @@ -1,25 +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 { CoreStart } from '@kbn/core/public'; -import useObservable from 'react-use/lib/useObservable'; -import { enableInfrastructureHostsView } from '@kbn/observability-plugin/public'; - -export interface SideNavigationSettings { - hasInfrastructureHosts: boolean; -} - -export function useSideNavigationSettings(core: CoreStart): SideNavigationSettings { - const hasInfrastructureHosts = useObservable( - core.settings.client.get$(enableInfrastructureHostsView), - false - ); - - return { - hasInfrastructureHosts, - }; -} diff --git a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx index b57fe439c38be..d53281dbf6de1 100644 --- a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx +++ b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx @@ -13,237 +13,228 @@ import { NavigationKibanaProvider, NavigationTreeDefinition, } from '@kbn/shared-ux-chrome-navigation'; -import React, { useMemo } from 'react'; +import React from 'react'; import { i18n } from '@kbn/i18n'; -import { - SideNavigationSettings, - useSideNavigationSettings, -} from './hooks/use_side_navigation_settings'; -function getNavigationTree(settings: SideNavigationSettings): NavigationTreeDefinition { - return { - body: [ - { type: 'recentlyAccessed' }, - { - type: 'navGroup', - id: 'observability_project_nav', - title: 'Observability', - icon: 'logoObservability', - defaultIsCollapsed: false, - isCollapsible: false, - breadcrumbStatus: 'hidden', - children: [ - { - title: i18n.translate('xpack.serverlessObservability.nav.logExplorer', { - defaultMessage: 'Log Explorer', - }), - link: 'observability-log-explorer', - renderAs: 'item', - children: [ - { - // This is to show "discover" breadcrumbs when navigating from "log explorer" to "discover" - link: 'discover', - sideNavStatus: 'hidden', - }, - ], - }, - { - title: i18n.translate('xpack.serverlessObservability.nav.dashboards', { - defaultMessage: 'Dashboards', - }), - link: 'dashboards', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/dashboards')); - }, - }, - { - title: i18n.translate('xpack.serverlessObservability.nav.visualizations', { - defaultMessage: 'Visualizations', - }), - link: 'visualize', - getIsActive: ({ pathNameSerialized, prepend }) => { - return ( - pathNameSerialized.startsWith(prepend('/app/visualize')) || - pathNameSerialized.startsWith(prepend('/app/lens')) || - pathNameSerialized.startsWith(prepend('/app/maps')) - ); +const navigationTree: NavigationTreeDefinition = { + body: [ + { type: 'recentlyAccessed' }, + { + type: 'navGroup', + id: 'observability_project_nav', + title: 'Observability', + icon: 'logoObservability', + defaultIsCollapsed: false, + isCollapsible: false, + breadcrumbStatus: 'hidden', + children: [ + { + title: i18n.translate('xpack.serverlessObservability.nav.logExplorer', { + defaultMessage: 'Log Explorer', + }), + link: 'observability-log-explorer', + renderAs: 'item', + children: [ + { + // This is to show "discover" breadcrumbs when navigating from "log explorer" to "discover" + link: 'discover', + sideNavStatus: 'hidden', }, + ], + }, + { + title: i18n.translate('xpack.serverlessObservability.nav.dashboards', { + defaultMessage: 'Dashboards', + }), + link: 'dashboards', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith(prepend('/app/dashboards')); }, - { - link: 'observability-overview:alerts', + }, + { + title: i18n.translate('xpack.serverlessObservability.nav.visualizations', { + defaultMessage: 'Visualizations', + }), + link: 'visualize', + getIsActive: ({ pathNameSerialized, prepend }) => { + return ( + pathNameSerialized.startsWith(prepend('/app/visualize')) || + pathNameSerialized.startsWith(prepend('/app/lens')) || + pathNameSerialized.startsWith(prepend('/app/maps')) + ); }, - { - link: 'observability-overview:cases', - renderAs: 'item', - children: [ - { - link: 'observability-overview:cases_configure', - }, - { - link: 'observability-overview:cases_create', - }, - ], - }, - { - link: 'observability-overview:slos', - }, - { - id: 'aiops', - title: 'AIOps', - renderAs: 'accordion', - spaceBefore: null, - children: [ - { - title: i18n.translate('xpack.serverlessObservability.nav.ml.jobs', { - defaultMessage: 'Anomaly detection', - }), - link: 'ml:anomalyDetection', - renderAs: 'item', - children: [ - { - link: 'ml:singleMetricViewer', - }, - { - link: 'ml:anomalyExplorer', - }, - { - link: 'ml:settings', - }, - ], - }, - { - title: i18n.translate('xpack.serverlessObservability.ml.logRateAnalysis', { - defaultMessage: 'Log rate analysis', - }), - link: 'ml:logRateAnalysis', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.includes(prepend('/app/ml/aiops/log_rate_analysis')); + }, + { + link: 'observability-overview:alerts', + }, + { + link: 'observability-overview:cases', + renderAs: 'item', + children: [ + { + link: 'observability-overview:cases_configure', + }, + { + link: 'observability-overview:cases_create', + }, + ], + }, + { + link: 'observability-overview:slos', + }, + { + id: 'aiops', + title: 'AIOps', + renderAs: 'accordion', + spaceBefore: null, + children: [ + { + title: i18n.translate('xpack.serverlessObservability.nav.ml.jobs', { + defaultMessage: 'Anomaly detection', + }), + link: 'ml:anomalyDetection', + renderAs: 'item', + children: [ + { + link: 'ml:singleMetricViewer', }, - }, - { - title: i18n.translate('xpack.serverlessObservability.ml.changePointDetection', { - defaultMessage: 'Change point detection', - }), - link: 'ml:changePointDetections', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.includes( - prepend('/app/ml/aiops/change_point_detection') - ); + { + link: 'ml:anomalyExplorer', }, + { + link: 'ml:settings', + }, + ], + }, + { + title: i18n.translate('xpack.serverlessObservability.ml.logRateAnalysis', { + defaultMessage: 'Log rate analysis', + }), + link: 'ml:logRateAnalysis', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.includes(prepend('/app/ml/aiops/log_rate_analysis')); }, - { - title: i18n.translate('xpack.serverlessObservability.nav.ml.job.notifications', { - defaultMessage: 'Job notifications', - }), - link: 'ml:notifications', + }, + { + title: i18n.translate('xpack.serverlessObservability.ml.changePointDetection', { + defaultMessage: 'Change point detection', + }), + link: 'ml:changePointDetections', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.includes(prepend('/app/ml/aiops/change_point_detection')); }, - ], - }, - { - id: 'apm', - title: i18n.translate('xpack.serverlessObservability.nav.applications', { - defaultMessage: 'Applications', - }), - renderAs: 'accordion', - children: [ - { - link: 'apm:services', - getIsActive: ({ pathNameSerialized }) => { - const regex = /app\/apm\/.*service.*/; - return regex.test(pathNameSerialized); - }, + }, + { + title: i18n.translate('xpack.serverlessObservability.nav.ml.job.notifications', { + defaultMessage: 'Job notifications', + }), + link: 'ml:notifications', + }, + ], + }, + { + id: 'apm', + title: i18n.translate('xpack.serverlessObservability.nav.applications', { + defaultMessage: 'Applications', + }), + renderAs: 'accordion', + children: [ + { + link: 'apm:services', + getIsActive: ({ pathNameSerialized }) => { + const regex = /app\/apm\/.*service.*/; + return regex.test(pathNameSerialized); }, - { - link: 'apm:traces', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/apm/traces')); - }, + }, + { + link: 'apm:traces', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith(prepend('/app/apm/traces')); }, - { - link: 'apm:dependencies', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/apm/dependencies')); - }, + }, + { + link: 'apm:dependencies', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith(prepend('/app/apm/dependencies')); }, - ], - }, - { - id: 'metrics', - title: i18n.translate('xpack.serverlessObservability.nav.infrastructure', { - defaultMessage: 'Infrastructure', - }), - renderAs: 'accordion', - children: [ - { - link: 'metrics:inventory', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/metrics/inventory')); - }, + }, + ], + }, + { + id: 'metrics', + title: i18n.translate('xpack.serverlessObservability.nav.infrastructure', { + defaultMessage: 'Infrastructure', + }), + renderAs: 'accordion', + children: [ + { + link: 'metrics:inventory', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith(prepend('/app/metrics/inventory')); }, - { - link: 'metrics:hosts', - sideNavStatus: settings.hasInfrastructureHosts ? 'visible' : 'hidden', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/metrics/hosts')); - }, + }, + { + link: 'metrics:hosts', + getIsActive: ({ pathNameSerialized, prepend }) => { + return pathNameSerialized.startsWith(prepend('/app/metrics/hosts')); }, - ], - }, - ], - }, - ], - footer: [ - { - type: 'navItem', - title: i18n.translate('xpack.serverlessObservability.nav.getStarted', { - defaultMessage: 'Get started', - }), - link: 'observabilityOnboarding', - icon: 'launch', - }, - { - type: 'navItem', - id: 'devTools', - title: i18n.translate('xpack.serverlessObservability.nav.devTools', { - defaultMessage: 'Developer tools', - }), - link: 'dev_tools', - icon: 'editorCodeBlock', - }, - { - type: 'navGroup', - id: 'project_settings_project_nav', - title: i18n.translate('xpack.serverlessObservability.nav.projectSettings', { - defaultMessage: 'Project settings', - }), - icon: 'gear', - breadcrumbStatus: 'hidden', - children: [ - { - link: 'management', - title: i18n.translate('xpack.serverlessObservability.nav.mngt', { - defaultMessage: 'Management', - }), - }, - { - link: 'integrations', - }, - { - link: 'fleet', - }, - { - id: 'cloudLinkUserAndRoles', - cloudLink: 'userAndRoles', - }, - { - id: 'cloudLinkBilling', - cloudLink: 'billingAndSub', - }, - ], - }, - ], - }; -} + }, + ], + }, + ], + }, + ], + footer: [ + { + type: 'navItem', + title: i18n.translate('xpack.serverlessObservability.nav.getStarted', { + defaultMessage: 'Get started', + }), + link: 'observabilityOnboarding', + icon: 'launch', + }, + { + type: 'navItem', + id: 'devTools', + title: i18n.translate('xpack.serverlessObservability.nav.devTools', { + defaultMessage: 'Developer tools', + }), + link: 'dev_tools', + icon: 'editorCodeBlock', + }, + { + type: 'navGroup', + id: 'project_settings_project_nav', + title: i18n.translate('xpack.serverlessObservability.nav.projectSettings', { + defaultMessage: 'Project settings', + }), + icon: 'gear', + breadcrumbStatus: 'hidden', + children: [ + { + link: 'management', + title: i18n.translate('xpack.serverlessObservability.nav.mngt', { + defaultMessage: 'Management', + }), + }, + { + link: 'integrations', + }, + { + link: 'fleet', + }, + { + id: 'cloudLinkUserAndRoles', + cloudLink: 'userAndRoles', + }, + { + id: 'cloudLinkBilling', + cloudLink: 'billingAndSub', + }, + ], + }, + ], +}; export const getObservabilitySideNavComponent = ( @@ -251,12 +242,6 @@ export const getObservabilitySideNavComponent = { serverless, cloud }: { serverless: ServerlessPluginStart; cloud: CloudStart } ) => () => { - const settings = useSideNavigationSettings(core); - - const navigationTree = useMemo(() => { - return getNavigationTree(settings); - }, [settings]); - return (