From b759b8f2794cdb452bad40eb33864a4a0867b3af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loix?= Date: Thu, 26 Oct 2023 10:29:00 +0100 Subject: [PATCH] [Serverless nav] Accordion auto-expand state + polish work (#169651) --- .../src/ui/project/navigation.tsx | 2 +- .../src/project_navigation.ts | 18 +- .../src/ui/components/navigation_group.tsx | 1 - .../src/ui/components/navigation_item.tsx | 2 + .../components/navigation_item_open_panel.tsx | 6 +- .../ui/components/navigation_section_ui.tsx | 191 ++++++++++++++++-- .../navigation/src/ui/navigation.stories.tsx | 4 +- .../chrome/navigation/src/ui/types.ts | 15 -- .../navigation_tree/navigation_tree.ts | 4 +- .../components/side_navigation/index.tsx | 13 +- .../serverless_search/public/layout/nav.tsx | 5 +- .../page_objects/svl_common_navigation.ts | 17 +- .../services/ml/observability_navigation.ts | 8 +- .../test_suites/observability/navigation.ts | 6 +- 14 files changed, 208 insertions(+), 84 deletions(-) diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/navigation.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/navigation.tsx index b8eea90c71c23..83b7831831f29 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/navigation.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/navigation.tsx @@ -36,7 +36,7 @@ export const ProjectNavigation: React.FC<{ onCollapseToggle={onCollapseToggle} css={ isCollapsed - ? { display: 'none;' } + ? undefined : { overflow: 'visible', clipPath: 'polygon(0 0, 300% 0, 300% 100%, 0 100%)' } } > diff --git a/packages/core/chrome/core-chrome-browser/src/project_navigation.ts b/packages/core/chrome/core-chrome-browser/src/project_navigation.ts index 23082fb9e03ac..e7c1689048b0b 100644 --- a/packages/core/chrome/core-chrome-browser/src/project_navigation.ts +++ b/packages/core/chrome/core-chrome-browser/src/project_navigation.ts @@ -8,7 +8,7 @@ import type { ComponentType } from 'react'; import type { Location } from 'history'; -import type { EuiAccordionProps, EuiThemeSizes, IconType } from '@elastic/eui'; +import type { EuiThemeSizes, IconType } from '@elastic/eui'; import type { AppId as DevToolsApp, DeepLinkId as DevToolsLink } from '@kbn/deeplinks-devtools'; import type { AppId as AnalyticsApp, @@ -112,6 +112,16 @@ interface NodeDefinitionBase { * @default 'block' */ renderAs?: RenderAs; + /** + * ["group" nodes only] Flag to indicate if the group is initially collapsed or not. + * + * `undefined`: (Recommended) the group will be opened if any of its children nodes matches the current URL. + * + * `false`: the group will be opened event if none of its children nodes matches the current URL. + * + * `true`: the group will be collapsed event if any of its children nodes matches the current URL. + */ + defaultIsCollapsed?: boolean; /** * ["group" nodes only] Optional flag to indicate if a horizontal rule should be rendered after the node. * Note: this property is currently only used for (1) "group" nodes and (2) in the navigation @@ -119,9 +129,11 @@ interface NodeDefinitionBase { */ appendHorizontalRule?: boolean; /** - * ["group" nodes only] Temp prop. Will be removed once the new navigation is fully implemented. + * ["group" nodes only] Flag to indicate if the accordion is collapsible. + * Must be used with `renderAs` set to `"accordion"` + * @default `true` */ - accordionProps?: Partial; + isCollapsible?: boolean; /** * ---------------------------------------------------------------------------------------------- * -------------------------------- ITEM NODES ONLY PROPS --------------------------------------- diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_group.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_group.tsx index 724e2bafac1f5..2f3ecbd381b45 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_group.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_group.tsx @@ -38,7 +38,6 @@ export interface Props< ChildrenId extends string = Id > extends NodeProps { unstyled?: boolean; - defaultIsCollapsed?: boolean; } function NavigationGroupInternalComp< diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item.tsx index 8c18f350bb0bf..87564319d518c 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_item.tsx @@ -74,12 +74,14 @@ function NavigationItemComp< if (isRootLevel) { const href = getNavigationNodeHref(navNode); + return ( ) => css` * { @@ -51,11 +52,12 @@ interface Props { export const NavigationItemOpenPanel: FC = ({ item, navigateToUrl }: Props) => { const { euiTheme } = useEuiTheme(); const { open: openPanel, close: closePanel, selectedNode } = usePanel(); + const { isSideNavCollapsed } = useServices(); const { title, deepLink, isActive, children } = item; const id = nodePathToString(item); const href = deepLink?.url ?? item.href; const isNotMobile = useIsWithinMinBreakpoint('s'); - const isIconVisible = isNotMobile && !!children && children.length > 0; + const isIconVisible = isNotMobile && !isSideNavCollapsed && !!children && children.length > 0; const itemClassNames = classNames( 'sideNavItem', diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_section_ui.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_section_ui.tsx index 947b642f95178..8fc2a2adf800a 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/components/navigation_section_ui.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_section_ui.tsx @@ -6,8 +6,9 @@ * Side Public License, v 1. */ -import React, { FC } from 'react'; - +import React, { FC, useCallback, useEffect, useMemo, useState } from 'react'; +import classNames from 'classnames'; +import { css } from '@emotion/css'; import { EuiTitle, EuiCollapsibleNavItem, @@ -26,13 +27,15 @@ import { nodePathToString, isAbsoluteLink, getNavigationNodeHref } from '../../u import { PanelContext, usePanel } from './panel'; import { NavigationItemOpenPanel } from './navigation_item_open_panel'; +const DEFAULT_SPACE_BETWEEN_LEVEL_1_GROUPS: EuiThemeSize = 'm'; +const DEFAULT_IS_COLLAPSED = true; +const DEFAULT_IS_COLLAPSIBLE = true; + const nodeHasLink = (navNode: ChromeProjectNavigationNode) => Boolean(navNode.deepLink) || Boolean(navNode.href); const nodeHasChildren = (navNode: ChromeProjectNavigationNode) => Boolean(navNode.children?.length); -const DEFAULT_SPACE_BETWEEN_LEVEL_1_GROUPS: EuiThemeSize = 'm'; - /** * Predicate to determine if a node should be visible in the main side nav. * If it is not visible it will be filtered out and not rendered. @@ -103,7 +106,6 @@ const renderBlockTitle: ( css={({ euiTheme }: any) => { return { marginTop: spaceBefore ? euiTheme.size[spaceBefore] : undefined, - // marginTop: euiTheme.size.base, paddingBlock: euiTheme.size.xs, paddingInline: euiTheme.size.s, }; @@ -148,12 +150,14 @@ const nodeToEuiCollapsibleNavProps = ( closePanel, isSideNavCollapsed, treeDepth, + itemsState, }: { navigateToUrl: NavigateToUrlFn; openPanel: PanelContext['open']; closePanel: PanelContext['close']; isSideNavCollapsed: boolean; treeDepth: number; + itemsState: AccordionItemsState; } ): { items: Array; @@ -172,7 +176,11 @@ const nodeToEuiCollapsibleNavProps = ( spaceBefore: _spaceBefore, } = navNode; const isExternal = Boolean(href) && isAbsoluteLink(href!); - const isSelected = hasChildren && !isItem ? false : isActive; + + const isAccordion = hasChildren && !isItem; + const isAccordionExpanded = (itemsState[id]?.isCollapsed ?? DEFAULT_IS_COLLAPSED) === false; + const isSelected = isAccordion && isAccordionExpanded ? false : isActive; + const dataTestSubj = classnames(`nav-item`, `nav-item-${id}`, { [`nav-item-deepLinkId-${deepLink?.id}`]: !!deepLink, [`nav-item-id-${id}`]: id, @@ -219,6 +227,7 @@ const nodeToEuiCollapsibleNavProps = ( closePanel, isSideNavCollapsed, treeDepth: treeDepth + 1, + itemsState, }) ) .filter(({ isVisible }) => isVisible) @@ -244,13 +253,6 @@ const nodeToEuiCollapsibleNavProps = ( } : undefined; - const accordionProps: Partial | undefined = isItem - ? undefined - : { - initialIsOpen: treeDepth === 0 ? isActive : true, // FIXME open state is controlled on component mount - ...navNode.accordionProps, - }; - if (renderAs === 'block' && treeDepth > 0 && subItems) { // Render as a group block (bold title + list of links underneath) return { @@ -267,7 +269,6 @@ const nodeToEuiCollapsibleNavProps = ( id, title, isSelected, - accordionProps, linkProps, onClick, href, @@ -290,6 +291,16 @@ const nodeToEuiCollapsibleNavProps = ( return { items, isVisible }; }; +interface AccordionItemsState { + [navNodeId: string]: { + isCollapsible: boolean; + isCollapsed: boolean; + // We want to auto expand the group automatically if the node is active (URL match) + // but once the user manually expand a group we don't want to close it afterward automatically. + doCollapseFromActiveState: boolean; + }; +} + interface Props { navNode: ChromeProjectNavigationNode; } @@ -298,23 +309,161 @@ export const NavigationSectionUI: FC = ({ navNode }) => { const { navigateToUrl, isSideNavCollapsed } = useServices(); const { open: openPanel, close: closePanel } = usePanel(); - const { items, isVisible } = nodeToEuiCollapsibleNavProps(navNode, { - navigateToUrl, - openPanel, - closePanel, - isSideNavCollapsed, - treeDepth: 0, + const navNodesById = useMemo(() => { + const byId = { + [nodePathToString(navNode)]: navNode, + }; + + const parse = (navNodes?: ChromeProjectNavigationNode[]) => { + if (!navNodes) return; + navNodes.forEach((childNode) => { + byId[nodePathToString(childNode)] = childNode; + parse(childNode.children); + }); + }; + parse(navNode.children); + + return byId; + }, [navNode]); + + const [itemsState, setItemsState] = useState(() => { + return Object.entries(navNodesById).reduce((acc, [_id, node]) => { + if (node.children) { + acc[_id] = { + isCollapsed: !node.isActive ?? DEFAULT_IS_COLLAPSED, + isCollapsible: node.isCollapsible ?? DEFAULT_IS_COLLAPSIBLE, + doCollapseFromActiveState: true, + }; + } + return acc; + }, {}); }); + const [subItems, setSubItems] = useState(); + + const toggleAccordion = useCallback((id: string) => { + setItemsState((prev) => { + const prevValue = prev[id]?.isCollapsed ?? DEFAULT_IS_COLLAPSED; + return { + ...prev, + [id]: { + ...prev[id], + isCollapsed: !prevValue, + doCollapseFromActiveState: false, // once we manually toggle we don't want to auto-close it when URL changes + }, + }; + }); + }, []); + + const setAccordionProps = useCallback( + ( + id: string, + _accordionProps?: Partial + ): Partial | undefined => { + const isCollapsed = itemsState[id]?.isCollapsed ?? DEFAULT_IS_COLLAPSED; + const isCollapsible = itemsState[id]?.isCollapsible ?? DEFAULT_IS_COLLAPSIBLE; + + let forceState: EuiAccordionProps['forceState'] = isCollapsed ? 'closed' : 'open'; + if (!isCollapsible) forceState = 'open'; // Allways open if the accordion is not collapsible + + const arrowProps: EuiAccordionProps['arrowProps'] = { + css: isCollapsible ? undefined : { display: 'none' }, + 'data-test-subj': classNames(`accordionArrow`, `accordionArrow-${id}`), + }; + + const updated: Partial = { + ..._accordionProps, + arrowProps, + forceState, + onToggle: () => { + toggleAccordion(id); + }, + }; + + return updated; + }, + [itemsState, toggleAccordion] + ); + + const { items, isVisible } = useMemo(() => { + return nodeToEuiCollapsibleNavProps(navNode, { + navigateToUrl, + openPanel, + closePanel, + isSideNavCollapsed, + treeDepth: 0, + itemsState, + }); + }, [closePanel, isSideNavCollapsed, navNode, navigateToUrl, openPanel, itemsState]); + const [props] = items; + const { items: accordionItems } = props; if (!isEuiCollapsibleNavItemProps(props)) { throw new Error(`Invalid EuiCollapsibleNavItem props for node ${props.id}`); } + /** + * Effect to set our internal state of each of the accordions (isCollapsed) based on the + * "isActive" state of the navNode. + */ + useEffect(() => { + setItemsState((prev) => { + return Object.entries(navNodesById).reduce((acc, [_id, node]) => { + if (node.children && (!prev[_id] || prev[_id].doCollapseFromActiveState)) { + acc[_id] = { + isCollapsed: !node.isActive ?? DEFAULT_IS_COLLAPSED, + isCollapsible: node.isCollapsible ?? DEFAULT_IS_COLLAPSIBLE, + doCollapseFromActiveState: true, + }; + } + return acc; + }, prev); + }); + }, [navNodesById]); + + useEffect(() => { + // Serializer to add recursively the accordionProps to each of the items + // that will control its "open"/"closed" state + handler to toggle the state. + const serializeAccordionItems = ( + _items?: EuiCollapsibleNavSubItemProps[] + ): EuiCollapsibleNavSubItemProps[] | undefined => { + if (!_items) return; + + return _items.map((item: EuiCollapsibleNavSubItemProps) => { + if (item.renderItem) { + return item; + } + const parsed: EuiCollapsibleNavSubItemProps = { + ...item, + items: serializeAccordionItems(item.items), + accordionProps: setAccordionProps(item.id!, item.accordionProps), + }; + return parsed; + }); + }; + + setSubItems(serializeAccordionItems(accordionItems)); + }, [accordionItems, setAccordionProps]); + if (!isVisible) { return null; } - return ; + return ( + + ); }; diff --git a/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx b/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx index 43c40ed39ab2e..be749a5cac9bb 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx @@ -631,9 +631,7 @@ const navigationDefinitionWithPanel: ProjectNavigationDefinition = { title: 'Example project', icon: 'logoObservability', defaultIsCollapsed: false, - accordionProps: { - arrowProps: { css: { display: 'none' } }, - }, + isCollapsible: false, children: [ { link: 'item1', diff --git a/packages/shared-ux/chrome/navigation/src/ui/types.ts b/packages/shared-ux/chrome/navigation/src/ui/types.ts index c9caa116c8b97..9051cc3747bf0 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/types.ts +++ b/packages/shared-ux/chrome/navigation/src/ui/types.ts @@ -8,7 +8,6 @@ import type { ReactNode } from 'react'; -import type { EuiAccordionProps } from '@elastic/eui'; import type { AppDeepLinkId, ChromeProjectNavigationNode, @@ -76,20 +75,6 @@ export interface GroupDefinition< ChildrenId extends string = Id > extends Omit, 'children'> { type: 'navGroup'; - /** - * Flag to indicate if the group is initially collapsed or not. - * - * `undefined`: (Recommended) the group will be opened if any of its children nodes matches the current URL. - * - * `false`: the group will be opened event if none of its children nodes matches the current URL. - * - * `true`: the group will be collapsed event if any of its children nodes matches the current URL. - */ - defaultIsCollapsed?: boolean; - /* - * Pass props to the EUI accordion component used to represent a nav group - */ - accordionProps?: Partial; children: Array>; } diff --git a/x-pack/plugins/security_solution_serverless/public/navigation/navigation_tree/navigation_tree.ts b/x-pack/plugins/security_solution_serverless/public/navigation/navigation_tree/navigation_tree.ts index bbab7fb56f057..bb8f610f7275d 100644 --- a/x-pack/plugins/security_solution_serverless/public/navigation/navigation_tree/navigation_tree.ts +++ b/x-pack/plugins/security_solution_serverless/public/navigation/navigation_tree/navigation_tree.ts @@ -52,9 +52,7 @@ export const formatNavigationTree = ( breadcrumbStatus: 'hidden', defaultIsCollapsed: false, children: bodyChildren, - accordionProps: { - arrowProps: { css: { display: 'none' } }, - }, + isCollapsible: false, }, ], footer: formatFooterNodesFromLinks(footerNavItems, footerCategories), 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 07b76980804e0..163660755a3be 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 @@ -25,9 +25,7 @@ const navigationTree: NavigationTreeDefinition = { title: 'Observability', icon: 'logoObservability', defaultIsCollapsed: false, - accordionProps: { - arrowProps: { css: { display: 'none' } }, - }, + isCollapsible: false, breadcrumbStatus: 'hidden', children: [ { @@ -80,9 +78,6 @@ const navigationTree: NavigationTreeDefinition = { id: 'aiops', title: 'AIOps', renderAs: 'accordion', - accordionProps: { - arrowProps: { css: { display: 'none' } }, - }, spaceBefore: null, children: [ { @@ -135,9 +130,6 @@ const navigationTree: NavigationTreeDefinition = { defaultMessage: 'Applications', }), renderAs: 'accordion', - accordionProps: { - arrowProps: { css: { display: 'none' } }, - }, children: [ { link: 'apm:services', @@ -166,9 +158,6 @@ const navigationTree: NavigationTreeDefinition = { defaultMessage: 'Infrastructure', }), renderAs: 'accordion', - accordionProps: { - arrowProps: { css: { display: 'none' } }, - }, children: [ { link: 'metrics:inventory', diff --git a/x-pack/plugins/serverless_search/public/layout/nav.tsx b/x-pack/plugins/serverless_search/public/layout/nav.tsx index 780b4ecb77ba1..3aaa1ae62884c 100644 --- a/x-pack/plugins/serverless_search/public/layout/nav.tsx +++ b/x-pack/plugins/serverless_search/public/layout/nav.tsx @@ -25,9 +25,7 @@ const navigationTree: NavigationTreeDefinition = { title: 'Elasticsearch', icon: 'logoElasticsearch', defaultIsCollapsed: false, - accordionProps: { - arrowProps: { css: { display: 'none' } }, - }, + isCollapsible: false, breadcrumbStatus: 'hidden', children: [ { @@ -76,7 +74,6 @@ const navigationTree: NavigationTreeDefinition = { }, ], }, - { id: 'content', title: i18n.translate('xpack.serverlessSearch.nav.content', { 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 a5f6a03329037..483496315bd04 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 @@ -19,7 +19,7 @@ type NavigationId = MlNavId | AlNavId | MgmtNavId | DevNavId | string; import type { FtrProviderContext } from '../ftr_provider_context'; import type { WebElementWrapper } from '../../../../test/functional/services/lib/web_element_wrapper'; -const getSectionIdTestSubj = (sectionId: NavigationId) => `~nav-item-${sectionId} `; +const getSectionIdTestSubj = (sectionId: NavigationId) => `~nav-item-${sectionId}`; export function SvlCommonNavigationProvider(ctx: FtrProviderContext) { const testSubjects = ctx.getService('testSubjects'); @@ -101,10 +101,7 @@ export function SvlCommonNavigationProvider(ctx: FtrProviderContext) { }, async isSectionOpen(sectionId: NavigationId) { await this.expectSectionExists(sectionId); - const section = await testSubjects.find(getSectionIdTestSubj(sectionId)); - const collapseBtn = await section.findByCssSelector( - `[aria-controls="${sectionId}"][aria-expanded]` - ); + const collapseBtn = await testSubjects.find(`~accordionArrow-${sectionId}`); const isExpanded = await collapseBtn.getAttribute('aria-expanded'); return isExpanded === 'true'; }, @@ -128,10 +125,7 @@ export function SvlCommonNavigationProvider(ctx: FtrProviderContext) { await this.expectSectionExists(sectionId); const isOpen = await this.isSectionOpen(sectionId); if (isOpen) return; - const section = await testSubjects.find(getSectionIdTestSubj(sectionId)); - const collapseBtn = await section.findByCssSelector( - `[aria-controls="${sectionId}"][aria-expanded]` - ); + const collapseBtn = await testSubjects.find(`~accordionArrow-${sectionId}`); await collapseBtn.click(); await this.expectSectionOpen(sectionId); }, @@ -139,10 +133,7 @@ export function SvlCommonNavigationProvider(ctx: FtrProviderContext) { await this.expectSectionExists(sectionId); const isOpen = await this.isSectionOpen(sectionId); if (!isOpen) return; - const section = await testSubjects.find(getSectionIdTestSubj(sectionId)); - const collapseBtn = await section.findByCssSelector( - `[aria-controls="${sectionId}"][aria-expanded]` - ); + const collapseBtn = await testSubjects.find(`~accordionArrow-${sectionId}`); await collapseBtn.click(); await this.expectSectionClosed(sectionId); }, diff --git a/x-pack/test_serverless/functional/services/ml/observability_navigation.ts b/x-pack/test_serverless/functional/services/ml/observability_navigation.ts index ec26c87be1d27..3dd18587a9140 100644 --- a/x-pack/test_serverless/functional/services/ml/observability_navigation.ts +++ b/x-pack/test_serverless/functional/services/ml/observability_navigation.ts @@ -7,11 +7,15 @@ import { FtrProviderContext } from '../../ftr_provider_context'; -export function MachineLearningNavigationProviderObservability({ getService }: FtrProviderContext) { +export function MachineLearningNavigationProviderObservability({ + getService, + getPageObject, +}: FtrProviderContext) { const testSubjects = getService('testSubjects'); + const svlCommonNavigation = getPageObject('svlCommonNavigation'); async function navigateToArea(id: string) { - await testSubjects.click('~nav-item-id-observability_project_nav.aiops'); + await svlCommonNavigation.sidenav.openSection('observability_project_nav.aiops'); await testSubjects.existOrFail(`~nav-item-id-observability_project_nav.aiops.ml:${id}`, { timeout: 60 * 1000, }); 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 c6c6e74edf62b..59f0554cd85ac 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/navigation.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/navigation.ts @@ -52,7 +52,7 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await expect(await browser.getCurrentUrl()).contain('/app/observability-log-explorer'); // check the aiops subsection - await svlCommonNavigation.sidenav.clickLink({ navId: 'observability_project_nav.aiops' }); // open ai ops subsection + await svlCommonNavigation.sidenav.openSection('observability_project_nav.aiops'); // open ai ops subsection await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'ml:anomalyDetection' }); await svlCommonNavigation.sidenav.expectLinkActive({ deepLinkId: 'ml:anomalyDetection' }); await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'AIOps' }); @@ -85,9 +85,7 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await expectNoPageReload(); }); - // Skipping this test as it is not supported in the new navigation for now. - // Will be fixed in https://github.com/elastic/kibana/issues/167328 - it.skip('active sidenav section is auto opened on load', async () => { + 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 browser.refresh();