From 9fde716b71634dcd7168ef277133f3a1cd5cd43d Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Tue, 28 Jan 2025 09:39:20 -0700 Subject: [PATCH 1/9] [Solution Side Nav] No landing page for Stack Management, use flyout --- .../plugins/observability/public/navigation_tree.ts | 1 - .../search/plugins/enterprise_search/public/navigation_tree.ts | 1 - .../security_solution_ess/public/navigation/side_navigation.ts | 3 ++- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/x-pack/solutions/observability/plugins/observability/public/navigation_tree.ts b/x-pack/solutions/observability/plugins/observability/public/navigation_tree.ts index 619e9df7b7642..c2751c63274e5 100644 --- a/x-pack/solutions/observability/plugins/observability/public/navigation_tree.ts +++ b/x-pack/solutions/observability/plugins/observability/public/navigation_tree.ts @@ -439,7 +439,6 @@ function createNavTree({ streamsAvailable }: { streamsAvailable?: boolean }) { children: [ { id: 'stack_management', // This id can't be changed as we use it to open the panel programmatically - link: 'management', title: i18n.translate('xpack.observability.obltNav.stackManagement', { defaultMessage: 'Stack Management', }), diff --git a/x-pack/solutions/search/plugins/enterprise_search/public/navigation_tree.ts b/x-pack/solutions/search/plugins/enterprise_search/public/navigation_tree.ts index eaa1a7c424565..fd766389f7588 100644 --- a/x-pack/solutions/search/plugins/enterprise_search/public/navigation_tree.ts +++ b/x-pack/solutions/search/plugins/enterprise_search/public/navigation_tree.ts @@ -306,7 +306,6 @@ export const getNavigationTreeDefinition = ({ }, ], id: 'stack_management', // This id can't be changed as we use it to open the panel programmatically - link: 'management', renderAs: 'panelOpener', spaceBefore: null, title: i18n.translate('xpack.enterpriseSearch.searchNav.mngt', { 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 index 9e08345dac8f1..57d9b976916bb 100644 --- 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 @@ -34,9 +34,10 @@ export const initSideNavigation = async (services: Services) => { const management = footerGroup?.children.find((child) => child.link === 'management'); if (management) { management.renderAs = 'panelOpener'; - management.id = 'stack_management'; + management.id = 'stack_management'; // This id can't be changed as we use it to open the panel programmatically from the S.M. landing page (available through global search only) management.spaceBefore = null; management.children = stackManagementLinks; + delete management.link; // no landing page for stack management } }) ) From f2f9e2a2a39861bc70e3cf54e0ebbc3b8bda19c0 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Tue, 28 Jan 2025 10:34:44 -0700 Subject: [PATCH 2/9] Stack Management flyout for Serverless Security --- .../public/navigation/index.ts | 2 - .../public/navigation/management_cards.ts | 86 ------------------- .../public/navigation/side_navigation.ts | 44 +++++++++- 3 files changed, 41 insertions(+), 91 deletions(-) delete mode 100644 x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/management_cards.ts diff --git a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/index.ts b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/index.ts index bc72913044f6a..eb01c8d639582 100644 --- a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/index.ts +++ b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/index.ts @@ -9,12 +9,10 @@ import { APP_PATH } from '@kbn/security-solution-plugin/common'; import type { Services } from '../common/services'; import { subscribeBreadcrumbs } from './breadcrumbs'; import { initSideNavigation } from './side_navigation'; -import { enableManagementCardsLanding } from './management_cards'; export const startNavigation = (services: Services) => { services.serverless.setProjectHome(APP_PATH); initSideNavigation(services); - enableManagementCardsLanding(services); subscribeBreadcrumbs(services); }; diff --git a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/management_cards.ts b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/management_cards.ts deleted file mode 100644 index f6f36d6fa7a3f..0000000000000 --- a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/management_cards.ts +++ /dev/null @@ -1,86 +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 { appCategories, type CardNavExtensionDefinition } from '@kbn/management-cards-navigation'; -import { - getNavigationPropsFromId, - SecurityPageName, - ExternalPageName, -} from '@kbn/security-solution-navigation'; -import { i18n } from '@kbn/i18n'; -import type { Services } from '../common/services'; - -const SecurityManagementCards = new Map([ - [ExternalPageName.visualize, 'content'], - [ExternalPageName.maps, 'content'], - [SecurityPageName.entityAnalyticsManagement, 'alerts'], - [SecurityPageName.entityAnalyticsEntityStoreManagement, 'alerts'], -]); - -export const enableManagementCardsLanding = (services: Services) => { - const { securitySolution, management, application } = services; - - securitySolution.getNavLinks$().subscribe((navLinks) => { - const cardNavDefinitions = navLinks.reduce>( - (acc, navLink) => { - if (SecurityManagementCards.has(navLink.id)) { - const { appId, deepLinkId, path } = getNavigationPropsFromId(navLink.id); - - acc[navLink.id] = { - category: SecurityManagementCards.get(navLink.id) ?? 'other', - title: navLink.title, - description: navLink.description ?? '', - icon: navLink.landingIcon ?? '', - href: application.getUrlForApp(appId, { deepLinkId, path }), - skipValidation: true, - }; - } - return acc; - }, - {} - ); - - const securityAiAssistantManagement = getSecurityAiAssistantManagementDefinition(services); - - if (securityAiAssistantManagement) { - cardNavDefinitions.securityAiAssistantManagement = securityAiAssistantManagement; - } - - management.setupCardsNavigation({ - enabled: true, - extendCardNavDefinitions: services.serverless.getNavigationCards( - services.security.authz.isRoleManagementEnabled(), - cardNavDefinitions - ), - }); - }); -}; - -const getSecurityAiAssistantManagementDefinition = (services: Services) => { - const { application } = services; - const aiAssistantIsEnabled = application.capabilities.securitySolutionAssistant?.['ai-assistant']; - - if (aiAssistantIsEnabled) { - return { - category: appCategories.OTHER, - title: i18n.translate( - 'xpack.securitySolutionServerless.securityAiAssistantManagement.app.title', - { - defaultMessage: 'AI assistant for Security settings', - } - ), - description: i18n.translate( - 'xpack.securitySolutionServerless.securityAiAssistantManagement.app.description', - { - defaultMessage: 'Manage your AI assistant for Security settings.', - } - ), - icon: 'sparkles', - }; - } - - return null; -}; 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 b8e7bdea916c5..de5ab680f05db 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,10 +5,10 @@ * 2.0. */ -import { i18n } from '@kbn/i18n'; -import type { GroupDefinition } from '@kbn/core-chrome-browser'; -import produce from 'immer'; import { map } from 'rxjs'; +import produce from 'immer'; +import { i18n } from '@kbn/i18n'; +import type { AppDeepLinkId, GroupDefinition, NodeDefinition } from '@kbn/core-chrome-browser'; import { type Services } from '../common/services'; const PROJECT_SETTINGS_TITLE = i18n.translate( @@ -29,6 +29,15 @@ export const initSideNavigation = async (services: Services) => { const footerGroup: GroupDefinition | undefined = draft.footer?.find( ({ type }) => type === 'navGroup' ) as GroupDefinition; + // Adds children for Stack Management panel + 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; // no landing page for stack management + } if (footerGroup) { footerGroup.title = PROJECT_SETTINGS_TITLE; footerGroup.children.push({ cloudLink: 'billingAndSub', openInNewTab: true }); @@ -42,3 +51,32 @@ export const initSideNavigation = async (services: Services) => { dataTestSubj: 'securitySolutionSideNav', }); }; + +// Stack Management static node definition +const stackManagementLinks: Array> = [ + { + title: 'Data', + children: [{ link: 'management:data_quality' }], + }, + { + title: 'Access', + children: [{ cloudLink: 'userAndRoles' }], + }, + { + title: 'Alerts and Insights', + children: [ + { link: 'management:triggersActions' }, + { link: 'management:triggersActionsConnectors' }, + { link: 'securitySolutionUI:entity_analytics-management' }, + { link: 'securitySolutionUI:entity_analytics-entity_store_management' }, + ], + }, + { + title: 'Content', + children: [{ link: 'maps' }, { link: 'visualize' }], + }, + { + title: 'Other', + children: [{ link: 'management:securityAiAssistantManagement' }], + }, +]; From 1e89e0f6e8e72046fa6b11e377ac0fd3f1d010f9 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Tue, 28 Jan 2025 11:12:45 -0700 Subject: [PATCH 3/9] Stack Management flyout for Serverless Observability --- .../public/navigation_tree.ts | 32 ++++++++++++++++++- .../serverless_observability/public/plugin.ts | 30 ++--------------- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/x-pack/solutions/observability/plugins/serverless_observability/public/navigation_tree.ts b/x-pack/solutions/observability/plugins/serverless_observability/public/navigation_tree.ts index 803349493b1d6..4882725f4a79f 100644 --- a/x-pack/solutions/observability/plugins/serverless_observability/public/navigation_tree.ts +++ b/x-pack/solutions/observability/plugins/serverless_observability/public/navigation_tree.ts @@ -355,10 +355,40 @@ export const createNavigationTree = ({ breadcrumbStatus: 'hidden', children: [ { - link: 'management', + id: 'stack_management', title: i18n.translate('xpack.serverlessObservability.nav.mngt', { defaultMessage: 'Management', }), + spaceBefore: null, + renderAs: 'panelOpener', + children: [ + { + title: 'Data', + children: [{ link: 'management:dataViews' }, { link: 'management:data_quality' }], + }, + { + title: 'Alerts and insights', + children: [ + { link: 'management:triggersActionsConnectors' }, + { link: 'management:maintenanceWindows' }, + ], + }, + { + title: 'Content', + children: [ + { link: 'management:objects' }, + { link: 'management:filesManagement' }, + { link: 'management:tags' }, + ], + }, + { + title: 'Other', + children: [ + { link: 'management:settings' }, + { link: 'management:securityAiAssistantManagement' }, + ], + }, + ], }, { link: 'integrations', diff --git a/x-pack/solutions/observability/plugins/serverless_observability/public/plugin.ts b/x-pack/solutions/observability/plugins/serverless_observability/public/plugin.ts index d4df07673e870..d755124c9cf15 100644 --- a/x-pack/solutions/observability/plugins/serverless_observability/public/plugin.ts +++ b/x-pack/solutions/observability/plugins/serverless_observability/public/plugin.ts @@ -6,8 +6,6 @@ */ import { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; -import { i18n } from '@kbn/i18n'; -import { appCategories, appIds } from '@kbn/management-cards-navigation'; import { map, of } from 'rxjs'; import { createNavigationTree } from './navigation_tree'; import { createObservabilityDashboardRegistration } from './logs_signal/overview_registration'; @@ -46,10 +44,10 @@ export class ServerlessObservabilityPlugin } public start( - core: CoreStart, + _core: CoreStart, setupDeps: ServerlessObservabilityPublicStartDependencies ): ServerlessObservabilityPublicStart { - const { serverless, management, security } = setupDeps; + const { serverless } = setupDeps; const navigationTree$ = (setupDeps.streams?.status$ || of({ status: 'disabled' })).pipe( map(({ status }) => { return createNavigationTree({ streamsAvailable: status === 'enabled' }); @@ -57,30 +55,6 @@ export class ServerlessObservabilityPlugin ); serverless.setProjectHome('/app/observability/landing'); serverless.initNavigation('oblt', navigationTree$, { dataTestSubj: 'svlObservabilitySideNav' }); - const aiAssistantIsEnabled = core.application.capabilities.observabilityAIAssistant?.show; - const extendCardNavDefinitions = aiAssistantIsEnabled - ? serverless.getNavigationCards(security.authz.isRoleManagementEnabled(), { - observabilityAiAssistantManagement: { - category: appCategories.OTHER, - title: i18n.translate('xpack.serverlessObservability.aiAssistantManagementTitle', { - defaultMessage: 'AI Assistant Settings', - }), - description: i18n.translate( - 'xpack.serverlessObservability.aiAssistantManagementDescription', - { - defaultMessage: - 'Manage knowledge base and control assistant behavior, including response language.', - } - ), - icon: 'sparkles', - }, - }) - : undefined; - management.setupCardsNavigation({ - enabled: true, - hideLinksTo: [appIds.RULES], - extendCardNavDefinitions, - }); return {}; } From 48ff080fe31330bea3202c73f5fb72c81d1b0a2d Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Tue, 28 Jan 2025 11:31:10 -0700 Subject: [PATCH 4/9] Stack Management flyout for Serverless Search --- .../public/navigation_tree.ts | 36 ++++++++++++++++++- .../serverless_search/public/plugin.ts | 32 +---------------- 2 files changed, 36 insertions(+), 32 deletions(-) diff --git a/x-pack/solutions/search/plugins/serverless_search/public/navigation_tree.ts b/x-pack/solutions/search/plugins/serverless_search/public/navigation_tree.ts index d9b4982928045..d9aa9a48dae31 100644 --- a/x-pack/solutions/search/plugins/serverless_search/public/navigation_tree.ts +++ b/x-pack/solutions/search/plugins/serverless_search/public/navigation_tree.ts @@ -167,10 +167,44 @@ export const navigationTree = ({ isAppRegistered }: ApplicationStart): Navigatio }), }, { - link: 'management', + id: 'stack_management', title: i18n.translate('xpack.serverlessSearch.nav.mngt', { defaultMessage: 'Management', }), + spaceBefore: null, + renderAs: 'panelOpener', + children: [ + { + title: 'Data', + children: [{ link: 'management:dataViews' }, { link: 'management:data_quality' }], + }, + { + title: 'Access', + children: [{ link: 'management:api_keys' }, { cloudLink: 'userAndRoles' }], + }, + { + title: 'Alerts and insights', + children: [ + { link: 'management:triggersActions' }, + { link: 'management:triggersActionsConnectors' }, + ], + }, + { + title: 'Content', + children: [ + { link: 'management:objects' }, + { link: 'management:filesManagement' }, + { link: 'management:tags' }, + ], + }, + { + title: 'Other', + children: [ + { link: 'management:settings' }, + { link: 'management:securityAiAssistantManagement' }, + ], + }, + ], }, { id: 'cloudLinkDeployment', diff --git a/x-pack/solutions/search/plugins/serverless_search/public/plugin.ts b/x-pack/solutions/search/plugins/serverless_search/public/plugin.ts index 1e37bfbd2880a..3960c5b05ca9b 100644 --- a/x-pack/solutions/search/plugins/serverless_search/public/plugin.ts +++ b/x-pack/solutions/search/plugins/serverless_search/public/plugin.ts @@ -13,7 +13,6 @@ import { Plugin, } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; -import { appCategories, appIds } from '@kbn/management-cards-navigation'; import { AuthenticatedUser } from '@kbn/security-plugin/common'; import { QueryClient, MutationCache, QueryCache } from '@tanstack/react-query'; import { of } from 'rxjs'; @@ -164,41 +163,12 @@ export class ServerlessSearchPlugin core: CoreStart, services: ServerlessSearchPluginStartDependencies ): ServerlessSearchPluginStart { - const { serverless, management, indexManagement, security } = services; + const { serverless, indexManagement } = services; serverless.setProjectHome(services.searchIndices.startRoute); - const aiAssistantIsEnabled = core.application.capabilities.observabilityAIAssistant?.show; const navigationTree$ = of(navigationTree(core.application)); serverless.initNavigation('es', navigationTree$, { dataTestSubj: 'svlSearchSideNav' }); - const extendCardNavDefinitions = serverless.getNavigationCards( - security.authz.isRoleManagementEnabled(), - aiAssistantIsEnabled - ? { - observabilityAiAssistantManagement: { - category: appCategories.OTHER, - title: i18n.translate('xpack.serverlessSearch.aiAssistantManagementTitle', { - defaultMessage: 'AI Assistant Settings', - }), - description: i18n.translate( - 'xpack.serverlessSearch.aiAssistantManagementDescription', - { - defaultMessage: - 'Manage knowledge base and control assistant behavior, including response language.', - } - ), - icon: 'sparkles', - }, - } - : undefined - ); - - management.setupCardsNavigation({ - enabled: true, - hideLinksTo: [appIds.MAINTENANCE_WINDOWS], - extendCardNavDefinitions, - }); - indexManagement?.extensionsService.setIndexMappingsContent(createIndexMappingsContent(core)); indexManagement?.extensionsService.addIndexDetailsTab( createIndexDocumentsContent(core, services) From fb2458ed074507799e53e397536b605834c735dc Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Tue, 28 Jan 2025 11:35:17 -0700 Subject: [PATCH 5/9] Restore management cards --- .../serverless_observability/public/plugin.ts | 30 ++++++- .../serverless_search/public/plugin.ts | 32 ++++++- .../public/navigation/index.ts | 2 + .../public/navigation/management_cards.ts | 86 +++++++++++++++++++ 4 files changed, 147 insertions(+), 3 deletions(-) create mode 100644 x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/management_cards.ts diff --git a/x-pack/solutions/observability/plugins/serverless_observability/public/plugin.ts b/x-pack/solutions/observability/plugins/serverless_observability/public/plugin.ts index d755124c9cf15..d4df07673e870 100644 --- a/x-pack/solutions/observability/plugins/serverless_observability/public/plugin.ts +++ b/x-pack/solutions/observability/plugins/serverless_observability/public/plugin.ts @@ -6,6 +6,8 @@ */ import { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; +import { i18n } from '@kbn/i18n'; +import { appCategories, appIds } from '@kbn/management-cards-navigation'; import { map, of } from 'rxjs'; import { createNavigationTree } from './navigation_tree'; import { createObservabilityDashboardRegistration } from './logs_signal/overview_registration'; @@ -44,10 +46,10 @@ export class ServerlessObservabilityPlugin } public start( - _core: CoreStart, + core: CoreStart, setupDeps: ServerlessObservabilityPublicStartDependencies ): ServerlessObservabilityPublicStart { - const { serverless } = setupDeps; + const { serverless, management, security } = setupDeps; const navigationTree$ = (setupDeps.streams?.status$ || of({ status: 'disabled' })).pipe( map(({ status }) => { return createNavigationTree({ streamsAvailable: status === 'enabled' }); @@ -55,6 +57,30 @@ export class ServerlessObservabilityPlugin ); serverless.setProjectHome('/app/observability/landing'); serverless.initNavigation('oblt', navigationTree$, { dataTestSubj: 'svlObservabilitySideNav' }); + const aiAssistantIsEnabled = core.application.capabilities.observabilityAIAssistant?.show; + const extendCardNavDefinitions = aiAssistantIsEnabled + ? serverless.getNavigationCards(security.authz.isRoleManagementEnabled(), { + observabilityAiAssistantManagement: { + category: appCategories.OTHER, + title: i18n.translate('xpack.serverlessObservability.aiAssistantManagementTitle', { + defaultMessage: 'AI Assistant Settings', + }), + description: i18n.translate( + 'xpack.serverlessObservability.aiAssistantManagementDescription', + { + defaultMessage: + 'Manage knowledge base and control assistant behavior, including response language.', + } + ), + icon: 'sparkles', + }, + }) + : undefined; + management.setupCardsNavigation({ + enabled: true, + hideLinksTo: [appIds.RULES], + extendCardNavDefinitions, + }); return {}; } diff --git a/x-pack/solutions/search/plugins/serverless_search/public/plugin.ts b/x-pack/solutions/search/plugins/serverless_search/public/plugin.ts index 3960c5b05ca9b..1e37bfbd2880a 100644 --- a/x-pack/solutions/search/plugins/serverless_search/public/plugin.ts +++ b/x-pack/solutions/search/plugins/serverless_search/public/plugin.ts @@ -13,6 +13,7 @@ import { Plugin, } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; +import { appCategories, appIds } from '@kbn/management-cards-navigation'; import { AuthenticatedUser } from '@kbn/security-plugin/common'; import { QueryClient, MutationCache, QueryCache } from '@tanstack/react-query'; import { of } from 'rxjs'; @@ -163,12 +164,41 @@ export class ServerlessSearchPlugin core: CoreStart, services: ServerlessSearchPluginStartDependencies ): ServerlessSearchPluginStart { - const { serverless, indexManagement } = services; + const { serverless, management, indexManagement, security } = services; serverless.setProjectHome(services.searchIndices.startRoute); + const aiAssistantIsEnabled = core.application.capabilities.observabilityAIAssistant?.show; const navigationTree$ = of(navigationTree(core.application)); serverless.initNavigation('es', navigationTree$, { dataTestSubj: 'svlSearchSideNav' }); + const extendCardNavDefinitions = serverless.getNavigationCards( + security.authz.isRoleManagementEnabled(), + aiAssistantIsEnabled + ? { + observabilityAiAssistantManagement: { + category: appCategories.OTHER, + title: i18n.translate('xpack.serverlessSearch.aiAssistantManagementTitle', { + defaultMessage: 'AI Assistant Settings', + }), + description: i18n.translate( + 'xpack.serverlessSearch.aiAssistantManagementDescription', + { + defaultMessage: + 'Manage knowledge base and control assistant behavior, including response language.', + } + ), + icon: 'sparkles', + }, + } + : undefined + ); + + management.setupCardsNavigation({ + enabled: true, + hideLinksTo: [appIds.MAINTENANCE_WINDOWS], + extendCardNavDefinitions, + }); + indexManagement?.extensionsService.setIndexMappingsContent(createIndexMappingsContent(core)); indexManagement?.extensionsService.addIndexDetailsTab( createIndexDocumentsContent(core, services) diff --git a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/index.ts b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/index.ts index eb01c8d639582..bc72913044f6a 100644 --- a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/index.ts +++ b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/index.ts @@ -9,10 +9,12 @@ import { APP_PATH } from '@kbn/security-solution-plugin/common'; import type { Services } from '../common/services'; import { subscribeBreadcrumbs } from './breadcrumbs'; import { initSideNavigation } from './side_navigation'; +import { enableManagementCardsLanding } from './management_cards'; export const startNavigation = (services: Services) => { services.serverless.setProjectHome(APP_PATH); initSideNavigation(services); + enableManagementCardsLanding(services); subscribeBreadcrumbs(services); }; diff --git a/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/management_cards.ts b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/management_cards.ts new file mode 100644 index 0000000000000..f6f36d6fa7a3f --- /dev/null +++ b/x-pack/solutions/security/plugins/security_solution_serverless/public/navigation/management_cards.ts @@ -0,0 +1,86 @@ +/* + * 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 { appCategories, type CardNavExtensionDefinition } from '@kbn/management-cards-navigation'; +import { + getNavigationPropsFromId, + SecurityPageName, + ExternalPageName, +} from '@kbn/security-solution-navigation'; +import { i18n } from '@kbn/i18n'; +import type { Services } from '../common/services'; + +const SecurityManagementCards = new Map([ + [ExternalPageName.visualize, 'content'], + [ExternalPageName.maps, 'content'], + [SecurityPageName.entityAnalyticsManagement, 'alerts'], + [SecurityPageName.entityAnalyticsEntityStoreManagement, 'alerts'], +]); + +export const enableManagementCardsLanding = (services: Services) => { + const { securitySolution, management, application } = services; + + securitySolution.getNavLinks$().subscribe((navLinks) => { + const cardNavDefinitions = navLinks.reduce>( + (acc, navLink) => { + if (SecurityManagementCards.has(navLink.id)) { + const { appId, deepLinkId, path } = getNavigationPropsFromId(navLink.id); + + acc[navLink.id] = { + category: SecurityManagementCards.get(navLink.id) ?? 'other', + title: navLink.title, + description: navLink.description ?? '', + icon: navLink.landingIcon ?? '', + href: application.getUrlForApp(appId, { deepLinkId, path }), + skipValidation: true, + }; + } + return acc; + }, + {} + ); + + const securityAiAssistantManagement = getSecurityAiAssistantManagementDefinition(services); + + if (securityAiAssistantManagement) { + cardNavDefinitions.securityAiAssistantManagement = securityAiAssistantManagement; + } + + management.setupCardsNavigation({ + enabled: true, + extendCardNavDefinitions: services.serverless.getNavigationCards( + services.security.authz.isRoleManagementEnabled(), + cardNavDefinitions + ), + }); + }); +}; + +const getSecurityAiAssistantManagementDefinition = (services: Services) => { + const { application } = services; + const aiAssistantIsEnabled = application.capabilities.securitySolutionAssistant?.['ai-assistant']; + + if (aiAssistantIsEnabled) { + return { + category: appCategories.OTHER, + title: i18n.translate( + 'xpack.securitySolutionServerless.securityAiAssistantManagement.app.title', + { + defaultMessage: 'AI assistant for Security settings', + } + ), + description: i18n.translate( + 'xpack.securitySolutionServerless.securityAiAssistantManagement.app.description', + { + defaultMessage: 'Manage your AI assistant for Security settings.', + } + ), + icon: 'sparkles', + }; + } + + return null; +}; From 2feceaa95eff560e26dc41a1f3127f2c60ebe603 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Tue, 28 Jan 2025 14:40:40 -0700 Subject: [PATCH 6/9] Fix translations --- .../public/navigation_tree.ts | 16 ++++++++++---- .../public/navigation_tree.ts | 20 ++++++++++++----- .../public/navigation/side_navigation.ts | 22 ++++++++++++++----- 3 files changed, 44 insertions(+), 14 deletions(-) diff --git a/x-pack/solutions/observability/plugins/serverless_observability/public/navigation_tree.ts b/x-pack/solutions/observability/plugins/serverless_observability/public/navigation_tree.ts index 4882725f4a79f..d6f55c5fca4df 100644 --- a/x-pack/solutions/observability/plugins/serverless_observability/public/navigation_tree.ts +++ b/x-pack/solutions/observability/plugins/serverless_observability/public/navigation_tree.ts @@ -363,18 +363,24 @@ export const createNavigationTree = ({ renderAs: 'panelOpener', children: [ { - title: 'Data', + title: i18n.translate('xpack.serverlessObservability.nav.mngt.data', { + defaultMessage: 'Data', + }), children: [{ link: 'management:dataViews' }, { link: 'management:data_quality' }], }, { - title: 'Alerts and insights', + title: i18n.translate('xpack.serverlessObservability.nav.mngt.alertsAndInsights', { + defaultMessage: 'Alerts and insights', + }), children: [ { link: 'management:triggersActionsConnectors' }, { link: 'management:maintenanceWindows' }, ], }, { - title: 'Content', + title: i18n.translate('xpack.serverlessObservability.nav.mngt.content', { + defaultMessage: 'Content', + }), children: [ { link: 'management:objects' }, { link: 'management:filesManagement' }, @@ -382,7 +388,9 @@ export const createNavigationTree = ({ ], }, { - title: 'Other', + title: i18n.translate('xpack.serverlessObservability.nav.mngt.other', { + defaultMessage: 'Other', + }), children: [ { link: 'management:settings' }, { link: 'management:securityAiAssistantManagement' }, diff --git a/x-pack/solutions/search/plugins/serverless_search/public/navigation_tree.ts b/x-pack/solutions/search/plugins/serverless_search/public/navigation_tree.ts index d9aa9a48dae31..d0f8a2457bbbe 100644 --- a/x-pack/solutions/search/plugins/serverless_search/public/navigation_tree.ts +++ b/x-pack/solutions/search/plugins/serverless_search/public/navigation_tree.ts @@ -175,22 +175,30 @@ export const navigationTree = ({ isAppRegistered }: ApplicationStart): Navigatio renderAs: 'panelOpener', children: [ { - title: 'Data', + title: i18n.translate('xpack.serverlessSearch.nav.mngt.data', { + defaultMessage: 'Data', + }), children: [{ link: 'management:dataViews' }, { link: 'management:data_quality' }], }, { - title: 'Access', + title: i18n.translate('xpack.serverlessSearch.nav.mngt.access', { + defaultMessage: 'Access', + }), children: [{ link: 'management:api_keys' }, { cloudLink: 'userAndRoles' }], }, { - title: 'Alerts and insights', + title: i18n.translate('xpack.serverlessSearch.nav.mngt.alertsAndInsights', { + defaultMessage: 'Alerts and insights', + }), children: [ { link: 'management:triggersActions' }, { link: 'management:triggersActionsConnectors' }, ], }, { - title: 'Content', + title: i18n.translate('xpack.serverlessSearch.nav.mngt.content', { + defaultMessage: 'Content', + }), children: [ { link: 'management:objects' }, { link: 'management:filesManagement' }, @@ -198,7 +206,9 @@ export const navigationTree = ({ isAppRegistered }: ApplicationStart): Navigatio ], }, { - title: 'Other', + title: i18n.translate('xpack.serverlessSearch.nav.mngt.other', { + defaultMessage: 'Other', + }), children: [ { link: 'management:settings' }, { link: 'management:securityAiAssistantManagement' }, 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 de5ab680f05db..7ada48516ca8a 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 @@ -55,15 +55,22 @@ export const initSideNavigation = async (services: Services) => { // Stack Management static node definition const stackManagementLinks: Array> = [ { - title: 'Data', + title: i18n.translate('xpack.securitySolutionServerless.navLinks.projectSettings.mngt.data', { + defaultMessage: 'Data', + }), children: [{ link: 'management:data_quality' }], }, { - title: 'Access', + title: i18n.translate('xpack.securitySolutionServerless.navLinks.projectSettings.mngt.access', { + defaultMessage: 'Access', + }), children: [{ cloudLink: 'userAndRoles' }], }, { - title: 'Alerts and Insights', + title: i18n.translate( + 'xpack.securitySolutionServerless.navLinks.projectSettings.mngt.alertsAndInsights', + { defaultMessage: 'Alerts and Insights' } + ), children: [ { link: 'management:triggersActions' }, { link: 'management:triggersActionsConnectors' }, @@ -72,11 +79,16 @@ const stackManagementLinks: Array> ], }, { - title: 'Content', + title: i18n.translate( + 'xpack.securitySolutionServerless.navLinks.projectSettings.mngt.content', + { defaultMessage: 'Content' } + ), children: [{ link: 'maps' }, { link: 'visualize' }], }, { - title: 'Other', + title: i18n.translate('xpack.securitySolutionServerless.navLinks.projectSettings.mngt.other', { + defaultMessage: 'Other', + }), children: [{ link: 'management:securityAiAssistantManagement' }], }, ]; From 5bf0a2a80c2570d3d875042302453bb94491b11c Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Thu, 30 Jan 2025 15:55:59 -0700 Subject: [PATCH 7/9] Additional stack management links --- .../shared/deeplinks/management/deep_links.ts | 1 + .../public/navigation_tree.ts | 43 ++++++++++--- .../public/navigation_tree.ts | 52 +++++++++++++--- .../public/navigation/side_navigation.ts | 4 +- .../public/navigation/side_navigation.ts | 62 +++++++++++++++---- 5 files changed, 129 insertions(+), 33 deletions(-) diff --git a/src/platform/packages/shared/deeplinks/management/deep_links.ts b/src/platform/packages/shared/deeplinks/management/deep_links.ts index 4b47c6c6a4602..567367067d522 100644 --- a/src/platform/packages/shared/deeplinks/management/deep_links.ts +++ b/src/platform/packages/shared/deeplinks/management/deep_links.ts @@ -36,6 +36,7 @@ export type ManagementId = | 'cross_cluster_replication' | 'dataViews' | 'data_quality' + | 'data_usage' | 'filesManagement' | 'license_management' | 'index_lifecycle_management' diff --git a/x-pack/solutions/observability/plugins/serverless_observability/public/navigation_tree.ts b/x-pack/solutions/observability/plugins/serverless_observability/public/navigation_tree.ts index d6f55c5fca4df..0fec443ec3f6a 100644 --- a/x-pack/solutions/observability/plugins/serverless_observability/public/navigation_tree.ts +++ b/x-pack/solutions/observability/plugins/serverless_observability/public/navigation_tree.ts @@ -355,7 +355,7 @@ export const createNavigationTree = ({ breadcrumbStatus: 'hidden', children: [ { - id: 'stack_management', + id: 'management', title: i18n.translate('xpack.serverlessObservability.nav.mngt', { defaultMessage: 'Management', }), @@ -366,34 +366,59 @@ export const createNavigationTree = ({ title: i18n.translate('xpack.serverlessObservability.nav.mngt.data', { defaultMessage: 'Data', }), - children: [{ link: 'management:dataViews' }, { link: 'management:data_quality' }], + 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.serverlessObservability.nav.mngt.access', { + defaultMessage: 'Access', + }), + breadcrumbStatus: 'hidden', + children: [{ link: 'management:api_keys', breadcrumbStatus: 'hidden' }], }, { title: i18n.translate('xpack.serverlessObservability.nav.mngt.alertsAndInsights', { defaultMessage: 'Alerts and insights', }), + breadcrumbStatus: 'hidden', children: [ - { link: 'management:triggersActionsConnectors' }, - { link: 'management:maintenanceWindows' }, + { link: 'management:triggersActionsConnectors', breadcrumbStatus: 'hidden' }, + { link: 'management:maintenanceWindows', breadcrumbStatus: 'hidden' }, ], }, { title: i18n.translate('xpack.serverlessObservability.nav.mngt.content', { defaultMessage: 'Content', }), + breadcrumbStatus: 'hidden', children: [ - { link: 'management:objects' }, - { link: 'management:filesManagement' }, - { link: 'management:tags' }, + { 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' }, ], }, { title: i18n.translate('xpack.serverlessObservability.nav.mngt.other', { defaultMessage: 'Other', }), + breadcrumbStatus: 'hidden', children: [ - { link: 'management:settings' }, - { link: 'management:securityAiAssistantManagement' }, + { link: 'management:settings', breadcrumbStatus: 'hidden' }, + { + link: 'management:observabilityAiAssistantManagement', + breadcrumbStatus: 'hidden', + }, ], }, ], diff --git a/x-pack/solutions/search/plugins/serverless_search/public/navigation_tree.ts b/x-pack/solutions/search/plugins/serverless_search/public/navigation_tree.ts index d0f8a2457bbbe..f70106175ede5 100644 --- a/x-pack/solutions/search/plugins/serverless_search/public/navigation_tree.ts +++ b/x-pack/solutions/search/plugins/serverless_search/public/navigation_tree.ts @@ -167,7 +167,7 @@ export const navigationTree = ({ isAppRegistered }: ApplicationStart): Navigatio }), }, { - id: 'stack_management', + id: 'management', title: i18n.translate('xpack.serverlessSearch.nav.mngt', { defaultMessage: 'Management', }), @@ -178,40 +178,72 @@ export const navigationTree = ({ isAppRegistered }: ApplicationStart): Navigatio title: i18n.translate('xpack.serverlessSearch.nav.mngt.data', { defaultMessage: 'Data', }), - children: [{ link: 'management:dataViews' }, { link: 'management:data_quality' }], + 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.serverlessSearch.nav.mngt.access', { defaultMessage: 'Access', }), - children: [{ link: 'management:api_keys' }, { cloudLink: 'userAndRoles' }], + breadcrumbStatus: 'hidden', + children: [ + { link: 'management:api_keys', breadcrumbStatus: 'hidden' }, + { link: 'management:roles', breadcrumbStatus: 'hidden' }, + { + cloudLink: 'userAndRoles', + title: i18n.translate('xpack.serverlessSearch.nav.mngt.access.userAndRoles', { + defaultMessage: 'Manage Organization Members', + }), + }, + ], }, { title: i18n.translate('xpack.serverlessSearch.nav.mngt.alertsAndInsights', { defaultMessage: 'Alerts and insights', }), + breadcrumbStatus: 'hidden', children: [ - { link: 'management:triggersActions' }, - { link: 'management:triggersActionsConnectors' }, + { link: 'management:triggersActions', breadcrumbStatus: 'hidden' }, + { link: 'management:triggersActionsConnectors', breadcrumbStatus: 'hidden' }, ], }, { title: i18n.translate('xpack.serverlessSearch.nav.mngt.content', { defaultMessage: 'Content', }), + breadcrumbStatus: 'hidden', children: [ - { link: 'management:objects' }, - { link: 'management:filesManagement' }, - { link: 'management:tags' }, + { 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' }, ], }, { title: i18n.translate('xpack.serverlessSearch.nav.mngt.other', { defaultMessage: 'Other', }), + breadcrumbStatus: 'hidden', children: [ - { link: 'management:settings' }, - { link: 'management:securityAiAssistantManagement' }, + { link: 'management:settings', breadcrumbStatus: 'hidden' }, + { + link: 'management:observabilityAiAssistantManagement', + breadcrumbStatus: 'hidden', + title: i18n.translate( + 'xpack.serverlessSearch.nav.mngt.other.aiAssistantSettings', + { defaultMessage: 'AI Assistant Settings' } + ), + }, ], }, ], 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 index 57d9b976916bb..7ae283b863efe 100644 --- 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 @@ -34,10 +34,10 @@ export const initSideNavigation = async (services: Services) => { const management = footerGroup?.children.find((child) => child.link === 'management'); if (management) { management.renderAs = 'panelOpener'; - management.id = 'stack_management'; // This id can't be changed as we use it to open the panel programmatically from the S.M. landing page (available through global search only) + management.id = 'stack_management'; management.spaceBefore = null; management.children = stackManagementLinks; - delete management.link; // no landing page for stack management + delete management.link; } }) ) 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 7ada48516ca8a..f27dbbfb9ec79 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,10 +5,10 @@ * 2.0. */ -import { map } from 'rxjs'; -import produce from 'immer'; 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 Services } from '../common/services'; const PROJECT_SETTINGS_TITLE = i18n.translate( @@ -29,14 +29,13 @@ export const initSideNavigation = async (services: Services) => { const footerGroup: GroupDefinition | undefined = draft.footer?.find( ({ type }) => type === 'navGroup' ) as GroupDefinition; - // Adds children for Stack Management panel 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; // no landing page for stack management + delete management.link; } if (footerGroup) { footerGroup.title = PROJECT_SETTINGS_TITLE; @@ -58,24 +57,50 @@ const stackManagementLinks: Array> title: i18n.translate('xpack.securitySolutionServerless.navLinks.projectSettings.mngt.data', { defaultMessage: 'Data', }), - children: [{ link: 'management:data_quality' }], + 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', }), - children: [{ cloudLink: 'userAndRoles' }], + 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' }, - { link: 'management:triggersActionsConnectors' }, - { link: 'securitySolutionUI:entity_analytics-management' }, - { link: 'securitySolutionUI:entity_analytics-entity_store_management' }, + { 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', + }, ], }, { @@ -83,12 +108,25 @@ const stackManagementLinks: Array> 'xpack.securitySolutionServerless.navLinks.projectSettings.mngt.content', { defaultMessage: 'Content' } ), - children: [{ link: 'maps' }, { link: 'visualize' }], + 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', }), - children: [{ link: 'management:securityAiAssistantManagement' }], + breadcrumbStatus: 'hidden', + children: [ + { link: 'management:settings', breadcrumbStatus: 'hidden' }, + { link: 'management:securityAiAssistantManagement', breadcrumbStatus: 'hidden' }, + ], }, ]; From a780cdd5ffd9189d4e8d10533adb79ddb1e3e085 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Wed, 29 Jan 2025 11:52:55 -0700 Subject: [PATCH 8/9] fix functional tests --- .../tests/observability_sidenav.ts | 5 ++-- .../tests/search_sidenav.ts | 4 ++-- .../test_suites/observability/navigation.ts | 14 ++++++----- .../test_suites/search/navigation.ts | 23 ++++++++----------- .../test_suites/search/pipelines.ts | 4 ++-- .../test_suites/security/ftr/navigation.ts | 7 +++--- 6 files changed, 29 insertions(+), 28 deletions(-) diff --git a/x-pack/test/functional_solution_sidenav/tests/observability_sidenav.ts b/x-pack/test/functional_solution_sidenav/tests/observability_sidenav.ts index 8a93ffde38346..9e643dfdeb9a5 100644 --- a/x-pack/test/functional_solution_sidenav/tests/observability_sidenav.ts +++ b/x-pack/test/functional_solution_sidenav/tests/observability_sidenav.ts @@ -80,8 +80,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { // navigate to a different section await solutionNavigation.sidenav.openSection('project_settings_project_nav'); - await solutionNavigation.sidenav.clickLink({ deepLinkId: 'management' }); - await solutionNavigation.sidenav.expectLinkActive({ deepLinkId: 'management' }); + await solutionNavigation.sidenav.clickLink({ navId: 'stack_management' }); + await solutionNavigation.sidenav.expectLinkActive({ navId: 'stack_management' }); + await solutionNavigation.sidenav.clickPanelLink('management:tags'); await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Stack Management' }); // navigate back to the home page using header logo diff --git a/x-pack/test/functional_solution_sidenav/tests/search_sidenav.ts b/x-pack/test/functional_solution_sidenav/tests/search_sidenav.ts index 743f1cad451e6..811dd7bc8ca96 100644 --- a/x-pack/test/functional_solution_sidenav/tests/search_sidenav.ts +++ b/x-pack/test/functional_solution_sidenav/tests/search_sidenav.ts @@ -64,8 +64,8 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { // navigate to a different section await solutionNavigation.sidenav.openSection('project_settings_project_nav'); - await solutionNavigation.sidenav.clickLink({ deepLinkId: 'management' }); - await solutionNavigation.sidenav.expectLinkActive({ deepLinkId: 'management' }); + await solutionNavigation.sidenav.clickLink({ navId: 'stack_management' }); + await solutionNavigation.sidenav.expectLinkActive({ navId: 'stack_management' }); await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Stack Management' }); // navigate back to the home page using header logo diff --git a/x-pack/test_serverless/functional/test_suites/observability/navigation.ts b/x-pack/test_serverless/functional/test_suites/observability/navigation.ts index 55fabe8557526..e5205a86f2f3e 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/navigation.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/navigation.ts @@ -49,9 +49,10 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'AI Assistant' }); // navigate to a different section await svlCommonNavigation.sidenav.openSection('project_settings_project_nav'); - await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management' }); - await svlCommonNavigation.sidenav.expectLinkActive({ deepLinkId: 'management' }); - await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ deepLinkId: 'management' }); + await svlCommonNavigation.sidenav.clickLink({ navId: 'management' }); + await svlCommonNavigation.sidenav.expectLinkActive({ navId: 'management' }); + await svlCommonNavigation.sidenav.clickPanelLink('management:tags'); + await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Management', 'Tags']); // navigate back to serverless oblt overview await svlCommonNavigation.clickLogo(); @@ -65,7 +66,8 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { it('active sidenav section is auto opened on load', async () => { await svlCommonNavigation.sidenav.openSection('project_settings_project_nav'); - await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management' }); + await svlCommonNavigation.sidenav.clickLink({ navId: 'management' }); + await svlCommonNavigation.sidenav.clickPanelLink('management:tags'); await browser.refresh(); await svlCommonNavigation.expectExists(); await svlCommonNavigation.sidenav.expectSectionOpen('project_settings_project_nav'); @@ -134,8 +136,8 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { it('navigates to maintenance windows', async () => { await svlCommonNavigation.sidenav.openSection('project_settings_project_nav'); - await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management' }); - await testSubjects.click('app-card-maintenanceWindows'); + await svlCommonNavigation.sidenav.clickLink({ navId: 'management' }); + await svlCommonNavigation.sidenav.clickPanelLink('management:maintenanceWindows'); await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts([ 'Management', 'Maintenance Windows', diff --git a/x-pack/test_serverless/functional/test_suites/search/navigation.ts b/x-pack/test_serverless/functional/test_suites/search/navigation.ts index 6d482eeacbc7b..cd0df5d4866bb 100644 --- a/x-pack/test_serverless/functional/test_suites/search/navigation.ts +++ b/x-pack/test_serverless/functional/test_suites/search/navigation.ts @@ -164,16 +164,10 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { deepLinkId: 'ml:modelManagement', }); // > Management - await solutionNavigation.sidenav.clickLink({ - deepLinkId: 'management', - }); - await solutionNavigation.sidenav.expectLinkActive({ - deepLinkId: 'management', - }); - await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Management' }); - await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ - deepLinkId: 'management', - }); + await solutionNavigation.sidenav.clickLink({ navId: 'management' }); + await solutionNavigation.sidenav.expectLinkActive({ navId: 'management' }); + await svlCommonNavigation.sidenav.clickPanelLink('management:tags'); + await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Management', 'Tags']); // navigate back to serverless search overview await svlCommonNavigation.clickLogo(); @@ -206,9 +200,12 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { it('navigate management', async () => { await svlCommonNavigation.sidenav.openSection('project_settings_project_nav'); - await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management' }); - await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Management']); - await testSubjects.click('app-card-dataViews'); + await svlCommonNavigation.sidenav.clickLink({ navId: 'management' }); + await svlCommonNavigation.sidenav.clickPanelLink('management:tags'); + await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Management', 'Tags']); + + await svlCommonNavigation.sidenav.clickLink({ navId: 'management' }); + await svlCommonNavigation.sidenav.clickPanelLink('management:dataViews'); await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Management', 'Data views']); }); diff --git a/x-pack/test_serverless/functional/test_suites/search/pipelines.ts b/x-pack/test_serverless/functional/test_suites/search/pipelines.ts index 9cb53310e5405..2c9164926f82d 100644 --- a/x-pack/test_serverless/functional/test_suites/search/pipelines.ts +++ b/x-pack/test_serverless/functional/test_suites/search/pipelines.ts @@ -20,8 +20,8 @@ export default function ({ getPageObjects }: FtrProviderContext) { before(async () => { await pageObjects.svlCommonPage.loginWithRole('developer'); await pageObjects.svlCommonNavigation.sidenav.openSection('project_settings_project_nav'); - await pageObjects.svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management' }); - await pageObjects.svlManagementPage.clickIngestPipelinesManagementCard(); + await pageObjects.svlCommonNavigation.sidenav.clickLink({ navId: 'management' }); + await pageObjects.svlCommonNavigation.sidenav.clickPanelLink('management:ingest_pipelines'); }); it('has embedded console', async () => { diff --git a/x-pack/test_serverless/functional/test_suites/security/ftr/navigation.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/navigation.ts index b7d7ef5c6dbbb..b5ecfa9e63a38 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ftr/navigation.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/navigation.ts @@ -49,7 +49,7 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await svlCommonNavigation.search.hideSearch(); await headerPage.waitUntilLoadingHasFinished(); - await expect(await browser.getCurrentUrl()).contain('app/security/dashboards'); + expect(await browser.getCurrentUrl()).contain('app/security/dashboards'); }); it('shows cases in sidebar navigation', async () => { @@ -74,12 +74,13 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await testSubjects.existOrFail('cases-all-title'); }); }); + it('navigates to maintenance windows', async () => { await svlCommonPage.loginAsAdmin(); await svlSecNavigation.navigateToLandingPage(); await svlCommonNavigation.sidenav.openSection('category-management'); - await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management' }); - await testSubjects.click('app-card-maintenanceWindows'); + await svlCommonNavigation.sidenav.clickLink({ navId: 'stack_management' }); + await svlCommonNavigation.sidenav.clickPanelLink('management:maintenanceWindows'); await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts([ 'Stack Management', 'Maintenance Windows', From 949d5d176216652676fc9bdfbd75f282227ffeb0 Mon Sep 17 00:00:00 2001 From: Timothy Sullivan Date: Fri, 7 Feb 2025 13:38:10 -0700 Subject: [PATCH 9/9] Undo changes for Security Solution --- .../public/navigation/side_navigation.ts | 1 - .../public/navigation/side_navigation.ts | 90 +------------------ .../test_suites/security/ftr/navigation.ts | 7 +- 3 files changed, 4 insertions(+), 94 deletions(-) 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 index 7ae283b863efe..9e08345dac8f1 100644 --- 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 @@ -37,7 +37,6 @@ export const initSideNavigation = async (services: Services) => { management.id = 'stack_management'; management.spaceBefore = null; management.children = stackManagementLinks; - delete management.link; } }) ) 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 f27dbbfb9ec79..b8e7bdea916c5 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 @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; -import type { AppDeepLinkId, GroupDefinition, NodeDefinition } from '@kbn/core-chrome-browser'; +import type { GroupDefinition } from '@kbn/core-chrome-browser'; import produce from 'immer'; import { map } from 'rxjs'; import { type Services } from '../common/services'; @@ -29,14 +29,6 @@ export const initSideNavigation = async (services: Services) => { 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 }); @@ -50,83 +42,3 @@ export const initSideNavigation = async (services: Services) => { 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/test_serverless/functional/test_suites/security/ftr/navigation.ts b/x-pack/test_serverless/functional/test_suites/security/ftr/navigation.ts index b5ecfa9e63a38..b7d7ef5c6dbbb 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ftr/navigation.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ftr/navigation.ts @@ -49,7 +49,7 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await svlCommonNavigation.search.hideSearch(); await headerPage.waitUntilLoadingHasFinished(); - expect(await browser.getCurrentUrl()).contain('app/security/dashboards'); + await expect(await browser.getCurrentUrl()).contain('app/security/dashboards'); }); it('shows cases in sidebar navigation', async () => { @@ -74,13 +74,12 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await testSubjects.existOrFail('cases-all-title'); }); }); - it('navigates to maintenance windows', async () => { await svlCommonPage.loginAsAdmin(); await svlSecNavigation.navigateToLandingPage(); await svlCommonNavigation.sidenav.openSection('category-management'); - await svlCommonNavigation.sidenav.clickLink({ navId: 'stack_management' }); - await svlCommonNavigation.sidenav.clickPanelLink('management:maintenanceWindows'); + await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management' }); + await testSubjects.click('app-card-maintenanceWindows'); await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts([ 'Stack Management', 'Maintenance Windows',