diff --git a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts index 06e5156dfac6e..9a45290c95389 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts +++ b/packages/core/chrome/core-chrome-browser-internal/src/project_navigation/utils.ts @@ -274,11 +274,6 @@ function validateNodeProps< `[Chrome navigation] Error in node [${id}]. Only one of "href" or "cloudLink" can be provided.` ); } - if (renderAs === 'panelOpener' && !link) { - throw new Error( - `[Chrome navigation] Error in node [${id}]. If renderAs is set to "panelOpener", a "link" must also be provided.` - ); - } if (renderAs === 'item' && !link && !onClick) { throw new Error( `[Chrome navigation] Error in node [${id}]. If renderAs is set to "item", a "link" or "onClick" must also be provided.` diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item_open_panel.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item_open_panel.tsx index 9d354ec27bc31..277da24ffeb50 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item_open_panel.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item_open_panel.tsx @@ -61,6 +61,7 @@ export const NavigationItemOpenPanel: FC = ({ item, navigateToUrl, active const isNotMobile = useIsWithinMinBreakpoint('s'); const isIconVisible = isNotMobile && !isSideNavCollapsed && !!children && children.length > 0; const isActive = isActiveFromUrl(item.path, activeNodes); + const hasLandingPage = Boolean(href); const itemClassNames = classNames( 'sideNavItem', @@ -73,30 +74,36 @@ export const NavigationItemOpenPanel: FC = ({ item, navigateToUrl, active [`nav-item-id-${id}`]: id, [`nav-item-isActive`]: isActive, }); + const buttonDataTestSubj = classNames(`panelOpener`, `panelOpener-${path}`, { [`panelOpener-id-${id}`]: id, [`panelOpener-deepLinkId-${deepLink?.id}`]: !!deepLink, }); + const togglePanel = useCallback(() => { + if (selectedNode?.id === item.id) { + closePanel(); + } else { + openPanel(item); + } + }, [selectedNode?.id, item, closePanel, openPanel]); + const onLinkClick = useCallback( (e: React.MouseEvent) => { if (!href) { + togglePanel(); return; } e.preventDefault(); navigateToUrl(href); closePanel(); }, - [closePanel, href, navigateToUrl] + [closePanel, href, navigateToUrl, togglePanel] ); const onIconClick = useCallback(() => { - if (selectedNode?.id === item.id) { - closePanel(); - } else { - openPanel(item); - } - }, [openPanel, closePanel, item, selectedNode]); + togglePanel(); + }, [togglePanel]); const isExpanded = selectedNode?.path === path; @@ -123,7 +130,7 @@ export const NavigationItemOpenPanel: FC = ({ item, navigateToUrl, active size="s" color="text" onClick={onIconClick} - iconType="spaces" + iconType={hasLandingPage ? 'spaces' : 'arrowRight'} iconSize="m" aria-label={i18n.translate('sharedUXPackages.chrome.sideNavigation.togglePanel', { defaultMessage: 'Toggle "{title}" panel navigation', diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/panel/navigation_panel.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/panel/navigation_panel.tsx index 5077cefc44625..f991dd6a30714 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/panel/navigation_panel.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/panel/navigation_panel.tsx @@ -32,6 +32,12 @@ const getTestSubj = (selectedNode: PanelSelectedNode | null): string | undefined }); }; +const getTargetTestSubj = (target: EventTarget | null): string | undefined => { + if (!target) return; + + return (target as HTMLElement).dataset.testSubj; +}; + export const NavigationPanel: FC = () => { const { euiTheme } = useEuiTheme(); const { isOpen, close, getContent, selectedNode } = usePanel(); @@ -48,12 +54,22 @@ export const NavigationPanel: FC = () => { const onOutsideClick = useCallback( ({ target }: Event) => { - // Only close if we are not clicking on the currently selected nav node - if ( - !(target as HTMLButtonElement).dataset.testSubj?.includes( - `panelOpener-${selectedNode?.path}` - ) - ) { + let doClose = true; + + if (target) { + // Only close if we are not clicking on the currently selected nav node + const testSubj = + getTargetTestSubj(target) ?? getTargetTestSubj((target as HTMLElement).parentNode); + + if ( + testSubj?.includes(`nav-item-${selectedNode?.path}`) || + testSubj?.includes(`panelOpener-${selectedNode?.path}`) + ) { + doClose = false; + } + } + + if (doClose) { close(); } }, diff --git a/test/functional/page_objects/solution_navigation.ts b/test/functional/page_objects/solution_navigation.ts index 882c5a478dbce..a0544e1100507 100644 --- a/test/functional/page_objects/solution_navigation.ts +++ b/test/functional/page_objects/solution_navigation.ts @@ -59,7 +59,11 @@ export function SolutionNavigationProvider(ctx: Pick { - return pathNameSerialized.includes(prepend('/app/ml/aiops/log_rate_analysis')); - }, - }, - { - link: 'logs:anomalies', - }, - { - link: 'logs:log-categories', - }, - { - title: i18n.translate('xpack.observability.obltNav.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.observability.obltNav.ml.job.notifications', { - defaultMessage: 'Job notifications', - }), - link: 'ml:notifications', - }, - ], }, { link: 'inventory', @@ -138,33 +82,26 @@ export function createNavTree(pluginsStart: ObservabilityPublicPluginsStart) { title: i18n.translate('xpack.observability.obltNav.applications', { defaultMessage: 'Applications', }), - renderAs: 'accordion', + renderAs: 'panelOpener', 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:dependencies', - getIsActive: ({ pathNameSerialized, prepend }) => { - return pathNameSerialized.startsWith(prepend('/app/apm/dependencies')); - }, + children: [ + { link: 'apm:services' }, + { link: 'apm:traces' }, + { link: 'apm:dependencies' }, + { + link: 'ux', + title: i18n.translate('xpack.observability.obltNav.apm.ux', { + defaultMessage: 'User experience', + }), + }, + ], }, { id: 'synthetics', title: i18n.translate('xpack.observability.obltNav.apm.syntheticsGroupTitle', { defaultMessage: 'Synthetics', }), - renderAs: 'accordion', children: [ { link: 'synthetics', @@ -172,10 +109,17 @@ export function createNavTree(pluginsStart: ObservabilityPublicPluginsStart) { defaultMessage: 'Monitors', }), }, - { link: 'synthetics:certificates' }, + { + link: 'synthetics:certificates', + title: i18n.translate( + 'xpack.observability.obltNav.apm.synthetics.tlsCertificates', + { + defaultMessage: 'TLS certificates', + } + ), + }, ], }, - { link: 'ux' }, ], }, { @@ -183,32 +127,36 @@ export function createNavTree(pluginsStart: ObservabilityPublicPluginsStart) { title: i18n.translate('xpack.observability.obltNav.infrastructure', { defaultMessage: 'Infrastructure', }), - renderAs: 'accordion', + renderAs: 'panelOpener', 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:metrics-explorer', + children: [ + { + link: 'metrics:inventory', + title: i18n.translate('xpack.observability.infrastructure.inventory', { + defaultMessage: 'Infrastructure inventory', + }), + }, + { link: 'metrics:hosts' }, + { + link: 'metrics:metrics-explorer', + title: i18n.translate( + 'xpack.observability.obltNav.infrastructure.metricsExplorer', + { + defaultMessage: 'Metrics explorer', + } + ), + }, + ], }, { id: 'profiling', title: i18n.translate( 'xpack.observability.obltNav.infrastructure.universalProfiling', { - defaultMessage: 'Universal Profiling', + defaultMessage: 'Universal profiling', } ), - renderAs: 'accordion', children: [ { link: 'profiling:stacktraces', @@ -223,138 +171,12 @@ export function createNavTree(pluginsStart: ObservabilityPublicPluginsStart) { }, ], }, - { - id: 'otherTools', - title: i18n.translate('xpack.observability.obltNav.otherTools', { - defaultMessage: 'Other tools', - }), - renderAs: 'accordion', - children: [ - { - link: 'logs:stream', - title: i18n.translate('xpack.observability.obltNav.otherTools.logsStream', { - defaultMessage: 'Logs stream', - }), - }, - { link: 'maps' }, - { link: 'canvas' }, - { link: 'graph' }, - ], - }, - ], - }, - ], - footer: [ - { type: 'recentlyAccessed' }, - { - type: 'navItem', - title: i18n.translate('xpack.observability.obltNav.getStarted', { - defaultMessage: 'Get started', - }), - link: 'observabilityOnboarding', - icon: 'launch', - }, - { - type: 'navItem', - id: 'devTools', - title: i18n.translate('xpack.observability.obltNav.devTools', { - defaultMessage: 'Developer tools', - }), - link: 'dev_tools', - icon: 'editorCodeBlock', - }, - { - type: 'navGroup', - id: 'project_settings_project_nav', - title: i18n.translate('xpack.observability.obltNav.management', { - defaultMessage: 'Management', - }), - icon: 'gear', - breadcrumbStatus: 'hidden', - 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', - }), - renderAs: 'panelOpener', - spaceBefore: null, - children: [ - { - title: 'Ingest', - children: [ - { link: 'management:ingest_pipelines' }, - { link: 'management:pipelines' }, - ], - }, - { - title: 'Data', - children: [ - { link: 'management:index_management' }, - { link: 'management:index_lifecycle_management' }, - { link: 'management:snapshot_restore' }, - { link: 'management:rollup_jobs' }, - { link: 'management:transform' }, - { link: 'management:cross_cluster_replication' }, - { link: 'management:remote_clusters' }, - { link: 'management:migrate_data' }, - ], - }, - { - title: 'Alerts and Insights', - children: [ - { link: 'management:triggersActions' }, - { link: 'management:cases' }, - { link: 'management:triggersActionsConnectors' }, - { link: 'management:reporting' }, - { link: 'management:jobsListLink' }, - { link: 'management:watcher' }, - { link: 'management:maintenanceWindows' }, - ], - }, - { - title: 'Security', - children: [ - { link: 'management:users' }, - { link: 'management:roles' }, - { link: 'management:api_keys' }, - { link: 'management:role_mappings' }, - ], - }, - { - title: 'Kibana', - children: [ - { link: 'management:dataViews' }, - { link: 'management:filesManagement' }, - { link: 'management:objects' }, - { link: 'management:tags' }, - { link: 'management:search_sessions' }, - { link: 'management:aiAssistantManagementSelection' }, - { link: 'management:spaces' }, - { link: 'management:settings' }, - ], - }, - { - title: 'Stack', - children: [ - { link: 'management:license_management' }, - { link: 'management:upgrade_assistant' }, - ], - }, - ], - }, - { - link: 'integrations', - }, - { - link: 'fleet', - }, { id: 'machine_learning-landing', - link: 'securitySolutionUI:machine_learning-landing', renderAs: 'panelOpener', - spaceBefore: null, + title: i18n.translate('xpack.observability.obltNav.machineLearning', { + defaultMessage: 'Machine learning', + }), children: [ { children: [ @@ -366,6 +188,12 @@ export function createNavTree(pluginsStart: ObservabilityPublicPluginsStart) { }, { link: 'ml:memoryUsage', + title: i18n.translate( + 'xpack.observability.obltNav.machineLearning.memoryUsage', + { + defaultMessage: 'Memory usage', + } + ), }, ], }, @@ -391,6 +219,9 @@ export function createNavTree(pluginsStart: ObservabilityPublicPluginsStart) { { link: 'ml:settings', }, + { + link: 'ml:suppliedConfigurations', + }, ], }, { @@ -426,6 +257,12 @@ export function createNavTree(pluginsStart: ObservabilityPublicPluginsStart) { children: [ { link: 'ml:nodesOverview', + title: i18n.translate( + 'xpack.observability.obltNav.ml.model_management.trainedModels', + { + defaultMessage: 'Trained models', + } + ), }, ], }, @@ -448,7 +285,7 @@ export function createNavTree(pluginsStart: ObservabilityPublicPluginsStart) { { link: 'ml:indexDataVisualizer', title: i18n.translate( - 'xpack.observability.obltNav.ml.data_visualizer.file_data_visualizer', + 'xpack.observability.obltNav.ml.data_visualizer.data_view_data_visualizer', { defaultMessage: 'Data view data visualizer', } @@ -456,6 +293,12 @@ export function createNavTree(pluginsStart: ObservabilityPublicPluginsStart) { }, { link: 'ml:dataDrift', + title: i18n.translate( + 'xpack.observability.obltNav.ml.data_visualizer.data_drift', + { + defaultMessage: 'Data drift', + } + ), }, ], }, @@ -468,17 +311,182 @@ export function createNavTree(pluginsStart: ObservabilityPublicPluginsStart) { children: [ { link: 'ml:logRateAnalysis', + title: i18n.translate( + 'xpack.observability.obltNav.ml.aiops_labs.log_rate_analysis', + { + defaultMessage: 'Log rate analysis', + } + ), }, { link: 'ml:logPatternAnalysis', + title: i18n.translate( + 'xpack.observability.obltNav.ml.aiops_labs.log_pattern_analysis', + { + defaultMessage: 'Log pattern analysis', + } + ), }, { link: 'ml:changePointDetections', + title: i18n.translate( + 'xpack.observability.obltNav.ml.aiops_labs.change_point_detection', + { + defaultMessage: 'Change point detection', + } + ), }, ], }, ], }, + { + id: 'otherTools', + title: i18n.translate('xpack.observability.obltNav.otherTools', { + defaultMessage: 'Other tools', + }), + renderAs: 'panelOpener', + icon: 'editorCodeBlock', + children: [ + { + link: 'logs:stream', + title: i18n.translate('xpack.observability.obltNav.otherTools.logsStream', { + defaultMessage: 'Logs stream', + }), + }, + { + link: 'logs:anomalies', + title: i18n.translate('xpack.observability.obltNav.otherTools.logsAnomalies', { + defaultMessage: 'Logs anomalies', + }), + }, + { + link: 'logs:log-categories', + title: i18n.translate('xpack.observability.obltNav.otherTools.logsCategories', { + defaultMessage: 'Logs categories', + }), + }, + { link: 'maps' }, + { link: 'canvas' }, + { link: 'graph' }, + { + link: 'visualize', + title: i18n.translate('xpack.observability.obltNav.otherTools.logsCategories', { + defaultMessage: 'Visualize library', + }), + }, + ], + }, + ], + }, + ], + footer: [ + { type: 'recentlyAccessed' }, + { + type: 'navItem', + title: i18n.translate('xpack.observability.obltNav.addData', { + defaultMessage: 'Add data', + }), + link: 'observabilityOnboarding', + icon: 'launch', + }, + { + type: 'navItem', + id: 'devTools', + title: i18n.translate('xpack.observability.obltNav.devTools', { + defaultMessage: 'Developer tools', + }), + link: 'dev_tools', + icon: 'editorCodeBlock', + }, + { + type: 'navGroup', + id: 'project_settings_project_nav', + title: i18n.translate('xpack.observability.obltNav.management', { + defaultMessage: 'Management', + }), + icon: 'gear', + breadcrumbStatus: 'hidden', + 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', + }), + renderAs: 'panelOpener', + spaceBefore: null, + children: [ + { + title: 'Ingest', + children: [ + { link: 'management:ingest_pipelines' }, + { link: 'management:pipelines' }, + ], + }, + { + title: 'Data', + children: [ + { link: 'management:index_management' }, + { link: 'management:data_quality' }, + { link: 'management:index_lifecycle_management' }, + { link: 'management:snapshot_restore' }, + { link: 'management:rollup_jobs' }, + { link: 'management:transform' }, + { link: 'management:cross_cluster_replication' }, + { link: 'management:remote_clusters' }, + { link: 'management:migrate_data' }, + ], + }, + { + title: 'Alerts and Insights', + children: [ + { link: 'management:triggersActions' }, + { link: 'management:cases' }, + { link: 'management:triggersActionsConnectors' }, + { link: 'management:reporting' }, + { link: 'management:jobsListLink' }, + { link: 'management:watcher' }, + { link: 'management:maintenanceWindows' }, + ], + }, + { + title: 'Security', + children: [ + { link: 'management:users' }, + { link: 'management:roles' }, + { link: 'management:api_keys' }, + { link: 'management:role_mappings' }, + ], + }, + { + title: 'Kibana', + children: [ + { link: 'management:dataViews' }, + { link: 'management:filesManagement' }, + { link: 'management:objects' }, + { link: 'management:tags' }, + { link: 'management:search_sessions' }, + { link: 'management:aiAssistantManagementSelection' }, + { link: 'management:spaces' }, + { link: 'management:settings' }, + ], + }, + { + title: 'Stack', + children: [ + { link: 'management:license_management' }, + { link: 'management:upgrade_assistant' }, + ], + }, + ], + }, + { + link: 'integrations', + }, + { + link: 'fleet', + }, { id: 'cloudLinkUserAndRoles', cloudLink: 'userAndRoles', diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 28b028fdc3481..e5b2fea15f343 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -32385,15 +32385,10 @@ "xpack.observability.obltNav.apm.syntheticsGroupTitle": "Synthetics", "xpack.observability.obltNav.applications": "Applications", "xpack.observability.obltNav.devTools": "Outils de développeur", - "xpack.observability.obltNav.getStarted": "Démarrer", "xpack.observability.obltNav.headerSolutionSwitcher.obltSolutionTitle": "Observabilité", "xpack.observability.obltNav.infrastructure": "Infrastructure", "xpack.observability.obltNav.infrastructure.universalProfiling": "Universal Profiling", "xpack.observability.obltNav.management": "Gestion", - "xpack.observability.obltNav.ml.aiAndMlGroupTitle": "IA et ML", - "xpack.observability.obltNav.ml.changePointDetection": "Modifier la détection du point", - "xpack.observability.obltNav.ml.job.notifications": "Notifications de tâches", - "xpack.observability.obltNav.ml.logRateAnalysis": "Analyse du taux de log", "xpack.observability.obltNav.otherTools": "Autres outils", "xpack.observability.obltNav.otherTools.logsStream": "Flux de logs", "xpack.observability.obltNav.stackManagement": "Gestion de la Suite", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 7df47bf1efe61..7a89a90e520c7 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -32130,15 +32130,10 @@ "xpack.observability.obltNav.apm.syntheticsGroupTitle": "Synthetics", "xpack.observability.obltNav.applications": "アプリケーション", "xpack.observability.obltNav.devTools": "開発者ツール", - "xpack.observability.obltNav.getStarted": "使ってみる", "xpack.observability.obltNav.headerSolutionSwitcher.obltSolutionTitle": "Observability", "xpack.observability.obltNav.infrastructure": "インフラストラクチャー", "xpack.observability.obltNav.infrastructure.universalProfiling": "ユニバーサルプロファイリング", "xpack.observability.obltNav.management": "管理", - "xpack.observability.obltNav.ml.aiAndMlGroupTitle": "AI & ML", - "xpack.observability.obltNav.ml.changePointDetection": "変化点検出", - "xpack.observability.obltNav.ml.job.notifications": "ジョブ通知", - "xpack.observability.obltNav.ml.logRateAnalysis": "ログレート分析", "xpack.observability.obltNav.otherTools": "その他のツール", "xpack.observability.obltNav.otherTools.logsStream": "ログストリーム", "xpack.observability.obltNav.stackManagement": "スタック管理", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 581eb4ace7963..9d05f3e54bf4f 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -32173,15 +32173,10 @@ "xpack.observability.obltNav.apm.syntheticsGroupTitle": "Synthetics", "xpack.observability.obltNav.applications": "应用程序", "xpack.observability.obltNav.devTools": "开发者工具", - "xpack.observability.obltNav.getStarted": "开始使用", "xpack.observability.obltNav.headerSolutionSwitcher.obltSolutionTitle": "Observability", "xpack.observability.obltNav.infrastructure": "基础设施", "xpack.observability.obltNav.infrastructure.universalProfiling": "Universal Profiling", "xpack.observability.obltNav.management": "管理", - "xpack.observability.obltNav.ml.aiAndMlGroupTitle": "AI 和 ML", - "xpack.observability.obltNav.ml.changePointDetection": "更改点检测", - "xpack.observability.obltNav.ml.job.notifications": "作业通知", - "xpack.observability.obltNav.ml.logRateAnalysis": "日志速率分析", "xpack.observability.obltNav.otherTools": "其他工具", "xpack.observability.obltNav.otherTools.logsStream": "日志流", "xpack.observability.obltNav.stackManagement": "Stack Management", 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 c21844d851dce..87daa58fc2681 100644 --- a/x-pack/test/functional_solution_sidenav/tests/observability_sidenav.ts +++ b/x-pack/test/functional_solution_sidenav/tests/observability_sidenav.ts @@ -5,6 +5,7 @@ * 2.0. */ +import expect from '@kbn/expect'; import { FtrProviderContext } from '../ftr_provider_context'; export default function ({ getPageObjects, getService }: FtrProviderContext) { @@ -48,15 +49,35 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { deepLinkId: 'observabilityOnboarding', }); - // check the AI & ML subsection - await solutionNavigation.sidenav.openSection('observability_project_nav.aiMl'); // open AI & ML subsection - await solutionNavigation.sidenav.clickLink({ deepLinkId: 'ml:anomalyDetection' }); - await solutionNavigation.sidenav.expectLinkActive({ deepLinkId: 'ml:anomalyDetection' }); - await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Anomaly Detection' }); + // open apm (Application) panel using the link button (not the button icon) + await solutionNavigation.sidenav.openPanel('apm', { button: 'link' }); + { + const isOpen = await solutionNavigation.sidenav.isPanelOpen('apm'); + expect(isOpen).to.be(true); + } + + await solutionNavigation.sidenav.closePanel('apm', { button: 'link' }); + { + const isOpen = await solutionNavigation.sidenav.isPanelOpen('apm'); + expect(isOpen).to.be(false); + } + + // open Infrastructure panel using the icon button and navigate to some link inside the panel + await solutionNavigation.sidenav.openPanel('metrics', { button: 'icon' }); + { + const isOpen = await solutionNavigation.sidenav.isPanelOpen('metrics'); + expect(isOpen).to.be(true); + } + await solutionNavigation.sidenav.clickPanelLink('metrics:inventory'); await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ - deepLinkId: 'ml:anomalyDetection', + text: 'Infrastructure inventory', }); + { + const isOpen = await solutionNavigation.sidenav.isPanelOpen('metrics'); + expect(isOpen).to.be(false); + } + // navigate to a different section await solutionNavigation.sidenav.openSection('project_settings_project_nav'); await solutionNavigation.sidenav.clickLink({ deepLinkId: 'management' }); diff --git a/x-pack/test/observability_functional/apps/observability/index.ts b/x-pack/test/observability_functional/apps/observability/index.ts index 96256248e5d88..f061fe68649d5 100644 --- a/x-pack/test/observability_functional/apps/observability/index.ts +++ b/x-pack/test/observability_functional/apps/observability/index.ts @@ -26,5 +26,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./pages/rule_details_page')); loadTestFile(require.resolve('./pages/alert_details_page')); loadTestFile(require.resolve('./pages/alerts/metric_threshold')); + loadTestFile(require.resolve('./sidenav/sidenav')); }); } diff --git a/x-pack/test/observability_functional/apps/observability/sidenav/sidenav.ts b/x-pack/test/observability_functional/apps/observability/sidenav/sidenav.ts new file mode 100644 index 0000000000000..201729b0bcc06 --- /dev/null +++ b/x-pack/test/observability_functional/apps/observability/sidenav/sidenav.ts @@ -0,0 +1,72 @@ +/* + * 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 expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function ({ getPageObjects, getService }: FtrProviderContext) { + const { common, solutionNavigation } = getPageObjects(['common', 'solutionNavigation']); + const spaces = getService('spaces'); + const browser = getService('browser'); + + describe('o11y sidenav', () => { + let cleanUp: () => Promise; + let spaceCreated: { id: string } = { id: '' }; + before(async () => { + // Navigate to the spaces management page which will log us in Kibana + await common.navigateToUrl('management', 'kibana/spaces', { + shouldUseHashForSubUrl: false, + }); + // Create a space with the observability solution and navigate to its home page + ({ cleanUp, space: spaceCreated } = await spaces.create({ solution: 'oblt' })); + await browser.navigateTo(spaces.getRootUrl(spaceCreated.id)); + }); + + after(async () => { + // Clean up space created + await cleanUp(); + }); + + describe('sidenav & breadcrumbs', () => { + it('renders the correct nav and navigate to links', async () => { + await solutionNavigation.sidenav.clickLink({ navId: 'observabilityAIAssistant' }); // click on AI Assistant link + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'AI Assistant' }); + + // check Other Tools section + await solutionNavigation.sidenav.openPanel('otherTools', { button: 'link' }); + { + const isOpen = await solutionNavigation.sidenav.isPanelOpen('otherTools'); + expect(isOpen).to.be(true); + } + await solutionNavigation.sidenav.expectLinkExists({ + panelNavLinkId: 'logs:anomalies', + }); + + await solutionNavigation.sidenav.expectLinkExists({ + panelNavLinkId: 'logs:log-categories', + }); + + await solutionNavigation.sidenav.clickPanelLink('visualize'); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + text: 'Visualize library', + }); + + // check Machine Learning section + await solutionNavigation.sidenav.openPanel('machine_learning-landing'); + { + const isOpen = await solutionNavigation.sidenav.isPanelOpen('machine_learning-landing'); + expect(isOpen).to.be(true); + } + + await solutionNavigation.sidenav.clickPanelLink('ml:suppliedConfigurations'); + await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ + text: 'Supplied configurations', + }); + }); + }); + }); +} diff --git a/x-pack/test/observability_functional/with_rac_write.config.ts b/x-pack/test/observability_functional/with_rac_write.config.ts index 83227af64d701..6ca4262b3ea42 100644 --- a/x-pack/test/observability_functional/with_rac_write.config.ts +++ b/x-pack/test/observability_functional/with_rac_write.config.ts @@ -52,6 +52,9 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) { ...xpackFunctionalConfig.get('kbnTestServer'), serverArgs: [ ...xpackFunctionalConfig.get('kbnTestServer.serverArgs'), + '--xpack.cloud.id=ftr_fake_cloud_id:aGVsbG8uY29tOjQ0MyRFUzEyM2FiYyRrYm4xMjNhYmM=', + '--xpack.cloud.base_url=https://cloud.elastic.co', + '--xpack.spaces.allowSolutionVisibility=true', `--elasticsearch.hosts=https://${servers.elasticsearch.hostname}:${servers.elasticsearch.port}`, `--elasticsearch.ssl.certificateAuthorities=${CA_CERT_PATH}`, `--plugin-path=${resolve(__dirname, '../functional_with_es_ssl/plugins/alerts')}`,