mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Serverless nav] Accordion auto-expand state + polish work (#169651)
This commit is contained in:
parent
8e59304a06
commit
b759b8f279
14 changed files with 208 additions and 84 deletions
|
@ -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%)' }
|
||||
}
|
||||
>
|
||||
|
|
|
@ -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<EuiAccordionProps>;
|
||||
isCollapsible?: boolean;
|
||||
/**
|
||||
* ----------------------------------------------------------------------------------------------
|
||||
* -------------------------------- ITEM NODES ONLY PROPS ---------------------------------------
|
||||
|
|
|
@ -38,7 +38,6 @@ export interface Props<
|
|||
ChildrenId extends string = Id
|
||||
> extends NodeProps<LinkId, Id, ChildrenId> {
|
||||
unstyled?: boolean;
|
||||
defaultIsCollapsed?: boolean;
|
||||
}
|
||||
|
||||
function NavigationGroupInternalComp<
|
||||
|
|
|
@ -74,12 +74,14 @@ function NavigationItemComp<
|
|||
|
||||
if (isRootLevel) {
|
||||
const href = getNavigationNodeHref(navNode);
|
||||
|
||||
return (
|
||||
<EuiCollapsibleNavItem
|
||||
id={navNode.id}
|
||||
title={navNode.title}
|
||||
icon={navNode.icon}
|
||||
iconProps={{ size: 'm' }}
|
||||
isSelected={navNode.isActive}
|
||||
data-test-subj={`nav-item-${navNode.id}`}
|
||||
linkProps={{
|
||||
href,
|
||||
|
|
|
@ -23,8 +23,9 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import type { ChromeProjectNavigationNode } from '@kbn/core-chrome-browser';
|
||||
import type { NavigateToUrlFn } from '../../../types/internal';
|
||||
import { usePanel } from './panel';
|
||||
import { nodePathToString } from '../../utils';
|
||||
import { useNavigation as useServices } from '../../services';
|
||||
import { usePanel } from './panel';
|
||||
|
||||
const getStyles = (euiTheme: EuiThemeComputed<{}>) => css`
|
||||
* {
|
||||
|
@ -51,11 +52,12 @@ interface Props {
|
|||
export const NavigationItemOpenPanel: FC<Props> = ({ 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',
|
||||
|
|
|
@ -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<EuiCollapsibleNavItemProps | EuiCollapsibleNavSubItemProps>;
|
||||
|
@ -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<EuiAccordionProps> | 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<Props> = ({ 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<AccordionItemsState>(() => {
|
||||
return Object.entries(navNodesById).reduce<AccordionItemsState>((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<EuiCollapsibleNavSubItemProps[] | undefined>();
|
||||
|
||||
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<EuiAccordionProps>
|
||||
): Partial<EuiAccordionProps> | 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<EuiAccordionProps> = {
|
||||
..._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<AccordionItemsState>((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 <EuiCollapsibleNavItem {...props} />;
|
||||
return (
|
||||
<EuiCollapsibleNavItem
|
||||
{...props}
|
||||
// We add this css to prevent showing the outline when the page load when the
|
||||
// accordion is auto-expanded if one of its children is active
|
||||
className={css`
|
||||
.euiAccordion__childWrapper,
|
||||
.euiAccordion__children,
|
||||
.euiCollapsibleNavAccordion__children {
|
||||
outline: none;
|
||||
}
|
||||
`}
|
||||
items={subItems}
|
||||
accordionProps={setAccordionProps(navNode.id)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -631,9 +631,7 @@ const navigationDefinitionWithPanel: ProjectNavigationDefinition<any> = {
|
|||
title: 'Example project',
|
||||
icon: 'logoObservability',
|
||||
defaultIsCollapsed: false,
|
||||
accordionProps: {
|
||||
arrowProps: { css: { display: 'none' } },
|
||||
},
|
||||
isCollapsible: false,
|
||||
children: [
|
||||
{
|
||||
link: 'item1',
|
||||
|
|
|
@ -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<NodeDefinition<LinkId, Id, ChildrenId>, '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<EuiAccordionProps>;
|
||||
children: Array<NodeDefinition<LinkId, Id, ChildrenId>>;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,9 +52,7 @@ export const formatNavigationTree = (
|
|||
breadcrumbStatus: 'hidden',
|
||||
defaultIsCollapsed: false,
|
||||
children: bodyChildren,
|
||||
accordionProps: {
|
||||
arrowProps: { css: { display: 'none' } },
|
||||
},
|
||||
isCollapsible: false,
|
||||
},
|
||||
],
|
||||
footer: formatFooterNodesFromLinks(footerNavItems, footerCategories),
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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', {
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue