mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
NavigationItemOpenPanel: remove handling of landing page ("four squares" design) (#210893)
## Summary Part of Epic: https://github.com/elastic/kibana-team/issues/1439 Requires: https://github.com/elastic/kibana/issues/212903 Changes: 1. Moves the Solution Side Nav away from the "four squares" design pattern: where clicking the item label opens a landing page and the item icon opens the secondary nav panel. This was a custom component implemented in the Kibana package, not part of the EUI `EuiCollapsibleNavBeta` component. 2. Changes some usage of `@emotion/css` to `@emotion/react` for better developer experience ### Screenshots <details><summary>Before</summary>  </details> <details><summary>After</summary>  </details> ### Checklist Check the PR satisfies following conditions. Reviewers should verify this PR satisfies this list as well. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) ### Identify risks Does this PR introduce any risks? For example, consider risks like hard to test bugs, performance regression, potential of data loss. Describe the risk, its severity, and mitigation for each identified risk. Invite stakeholders and evaluate how to proceed before merging. - [ ] This design pattern was only used in Security Solution. There is a small risk of regression issues in Security Solution navigation. This was mitigated by manual testing during development.
This commit is contained in:
parent
a49dc03330
commit
77523f7b15
15 changed files with 93 additions and 251 deletions
|
@ -56,9 +56,9 @@ describe('Panel', () => {
|
|||
navTreeDef: of(navigationTree),
|
||||
});
|
||||
|
||||
expect(await findByTestId(/panelOpener-root.group1/)).toBeVisible();
|
||||
expect(await findByTestId(/nav-item-root.group1/)).toBeVisible();
|
||||
expect(queryByTestId(/sideNavPanel/)).toBeNull();
|
||||
(await findByTestId(/panelOpener-root.group1/)).click(); // open the panel
|
||||
(await findByTestId(/nav-item-root.group1/)).click(); // open the panel
|
||||
expect(queryByTestId(/sideNavPanel/)).toBeVisible();
|
||||
});
|
||||
|
||||
|
@ -77,7 +77,7 @@ describe('Panel', () => {
|
|||
title: 'Group 1',
|
||||
path: 'root.group1',
|
||||
href: '/app/item1',
|
||||
renderAs: 'panelOpener',
|
||||
renderAs: 'block',
|
||||
children: [
|
||||
// All children are hidden, this group should not render
|
||||
{
|
||||
|
@ -109,8 +109,8 @@ describe('Panel', () => {
|
|||
navTreeDef: of(navigationTree),
|
||||
});
|
||||
|
||||
expect(queryByTestId(/panelOpener-root.group1/)).toBeNull();
|
||||
expect(queryByTestId(/panelOpener-root.group2/)).toBeVisible();
|
||||
expect(queryByTestId(/nav-item-root.group1.item1/)).toBeNull();
|
||||
expect(queryByTestId(/nav-item-root.group2/)).toBeVisible();
|
||||
});
|
||||
|
||||
describe('toggle the panel open and closed', () => {
|
||||
|
@ -280,7 +280,7 @@ describe('Panel', () => {
|
|||
expect(queryByTestId(/sideNavPanel/)).toBeNull();
|
||||
expect(queryByTestId(/customPanelContent/)).toBeNull();
|
||||
|
||||
queryByTestId(/panelOpener-root.group1/)?.click(); // open the panel
|
||||
queryByTestId(/nav-item-root.group1/)?.click(); // open the panel
|
||||
|
||||
expect(queryByTestId(/sideNavPanel/)).not.toBeNull();
|
||||
expect(queryByTestId(/customPanelContent/)).not.toBeNull();
|
||||
|
@ -351,7 +351,7 @@ describe('Panel', () => {
|
|||
navTreeDef: of(navTree),
|
||||
});
|
||||
|
||||
queryByTestId(/panelOpener-root.group1/)?.click(); // open the panel
|
||||
queryByTestId(/nav-item-root.group1/)?.click(); // open the panel
|
||||
|
||||
expect(queryByTestId(/panelGroupId-foo/)).toBeVisible();
|
||||
expect(queryByTestId(/panelGroupTitleId-foo/)?.textContent).toBe('Foo');
|
||||
|
@ -418,7 +418,7 @@ describe('Panel', () => {
|
|||
navTreeDef: of(navTree),
|
||||
});
|
||||
|
||||
queryByTestId(/panelOpener-root.group1/)?.click(); // open the panel
|
||||
queryByTestId(/nav-item-root.group1/)?.click(); // open the panel
|
||||
|
||||
expect(queryByTestId(/panelGroupTitleId-foo/)).toBeNull(); // No title rendered
|
||||
|
||||
|
@ -485,7 +485,7 @@ describe('Panel', () => {
|
|||
navTreeDef: of(navTree),
|
||||
});
|
||||
|
||||
queryByTestId(/panelOpener-root.group1/)?.click(); // open the panel
|
||||
queryByTestId(/nav-item-root.group1/)?.click(); // open the panel
|
||||
|
||||
expect(queryByTestId(/panelGroupId-foo/)).toBeVisible();
|
||||
|
||||
|
@ -554,7 +554,7 @@ describe('Panel', () => {
|
|||
navTreeDef: of(navTree),
|
||||
});
|
||||
|
||||
queryByTestId(/panelOpener-root.group1/)?.click(); // open the panel
|
||||
queryByTestId(/nav-item-root.group1/)?.click(); // open the panel
|
||||
|
||||
expect(queryByTestId(/panelGroupId-foo/)).toBeVisible(); // no crash
|
||||
});
|
||||
|
@ -611,7 +611,7 @@ describe('Panel', () => {
|
|||
|
||||
expect(componentSpy).not.toHaveBeenCalled();
|
||||
|
||||
queryByTestId(/panelOpener-root.group1/)?.click(); // open the panel
|
||||
queryByTestId(/nav-item-root.group1/)?.click(); // open the panel
|
||||
|
||||
expect(componentSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
|
|
@ -8,115 +8,34 @@
|
|||
*/
|
||||
|
||||
import React, { useCallback, type FC } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import classNames from 'classnames';
|
||||
import { css } from '@emotion/css';
|
||||
import {
|
||||
EuiButtonIcon,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiListGroup,
|
||||
EuiListGroupItem,
|
||||
type EuiThemeComputed,
|
||||
useEuiTheme,
|
||||
transparentize,
|
||||
useIsWithinMinBreakpoint,
|
||||
EuiButton,
|
||||
} from '@elastic/eui';
|
||||
import { css } from '@emotion/react';
|
||||
import { transparentize, EuiButton } from '@elastic/eui';
|
||||
import type { ChromeProjectNavigationNode } from '@kbn/core-chrome-browser';
|
||||
import { SubItemTitle } from './subitem_title';
|
||||
import { useNavigation as useServices } from '../../services';
|
||||
import { isActiveFromUrl } from '../../utils';
|
||||
import type { NavigateToUrlFn } from '../../types';
|
||||
import { usePanel } from './panel';
|
||||
|
||||
const getStyles = (euiTheme: EuiThemeComputed<{}>) => css`
|
||||
* {
|
||||
// EuiListGroupItem changes the links font-weight, we need to override it
|
||||
font-weight: ${euiTheme.font.weight.regular};
|
||||
}
|
||||
&.sideNavItem:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
&.sideNavItem--isActive:hover,
|
||||
&.sideNavItem--isActive {
|
||||
background-color: ${transparentize(euiTheme.colors.lightShade, 0.5)};
|
||||
& * {
|
||||
font-weight: ${euiTheme.font.weight.medium};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const getButtonStyles = (
|
||||
euiTheme: EuiThemeComputed<{}>,
|
||||
isActive: boolean,
|
||||
withBadge?: boolean
|
||||
) => css`
|
||||
background-color: ${isActive ? transparentize(euiTheme.colors.lightShade, 0.5) : 'transparent'};
|
||||
transform: none !important; /* don't translateY 1px */
|
||||
color: inherit;
|
||||
font-weight: inherit;
|
||||
padding-inline: ${euiTheme.size.s};
|
||||
& > span {
|
||||
justify-content: flex-start;
|
||||
position: relative;
|
||||
}
|
||||
${!withBadge
|
||||
? `
|
||||
& .euiIcon {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
transform: translateY(50%);
|
||||
}
|
||||
`
|
||||
: `
|
||||
& .euiBetaBadge {
|
||||
margin-left: -${euiTheme.size.m};
|
||||
}
|
||||
`}
|
||||
`;
|
||||
interface Props {
|
||||
item: ChromeProjectNavigationNode;
|
||||
navigateToUrl: NavigateToUrlFn;
|
||||
activeNodes: ChromeProjectNavigationNode[][];
|
||||
}
|
||||
|
||||
export const NavigationItemOpenPanel: FC<Props> = ({ item, navigateToUrl, activeNodes }: Props) => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
export const NavigationItemOpenPanel: FC<Props> = ({ item, activeNodes }: Props) => {
|
||||
const { open: openPanel, close: closePanel, selectedNode } = usePanel();
|
||||
const { isSideNavCollapsed } = useServices();
|
||||
const { title, deepLink, children, withBadge } = item;
|
||||
const { title, deepLink, withBadge } = item;
|
||||
const { id, path } = item;
|
||||
const href = deepLink?.url ?? item.href;
|
||||
const isNotMobile = useIsWithinMinBreakpoint('s');
|
||||
const isIconVisible = isNotMobile && !isSideNavCollapsed && !!children && children.length > 0;
|
||||
const hasLandingPage = Boolean(href);
|
||||
const isExpanded = selectedNode?.path === path;
|
||||
const isActive = isActiveFromUrl(item.path, activeNodes) || isExpanded;
|
||||
|
||||
const itemClassNames = classNames(
|
||||
'sideNavItem',
|
||||
{ 'sideNavItem--isActive': isActive },
|
||||
getStyles(euiTheme)
|
||||
);
|
||||
|
||||
const buttonClassNames = classNames(
|
||||
'sideNavItem',
|
||||
getButtonStyles(euiTheme, isActive, withBadge)
|
||||
);
|
||||
|
||||
const dataTestSubj = classNames(`nav-item`, `nav-item-${path}`, {
|
||||
[`nav-item-deepLinkId-${deepLink?.id}`]: !!deepLink,
|
||||
[`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(
|
||||
(target: EventTarget) => {
|
||||
if (selectedNode?.id === item.id) {
|
||||
|
@ -130,74 +49,49 @@ export const NavigationItemOpenPanel: FC<Props> = ({ item, navigateToUrl, active
|
|||
|
||||
const onLinkClick = useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
if (!href) {
|
||||
togglePanel(e.target);
|
||||
return;
|
||||
}
|
||||
e.preventDefault();
|
||||
navigateToUrl(href);
|
||||
closePanel();
|
||||
},
|
||||
[closePanel, href, navigateToUrl, togglePanel]
|
||||
);
|
||||
|
||||
const onIconClick = useCallback(
|
||||
(e: React.MouseEvent) => {
|
||||
togglePanel(e.target);
|
||||
},
|
||||
[togglePanel]
|
||||
);
|
||||
|
||||
if (!hasLandingPage) {
|
||||
return (
|
||||
<EuiButton
|
||||
onClick={onLinkClick}
|
||||
iconSide="right"
|
||||
iconType="arrowRight"
|
||||
size="s"
|
||||
fullWidth
|
||||
className={buttonClassNames}
|
||||
data-test-subj={dataTestSubj}
|
||||
>
|
||||
{withBadge ? <SubItemTitle item={item} /> : title}
|
||||
</EuiButton>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiFlexGroup alignItems="center" gutterSize="xs">
|
||||
<EuiFlexItem css={{ flexBasis: isIconVisible ? '80%' : '100%' }}>
|
||||
<EuiListGroup gutterSize="none">
|
||||
<EuiListGroupItem
|
||||
label={withBadge ? <SubItemTitle item={item} /> : title}
|
||||
href={href}
|
||||
wrapText
|
||||
onClick={onLinkClick}
|
||||
className={itemClassNames}
|
||||
color="text"
|
||||
size="s"
|
||||
data-test-subj={dataTestSubj}
|
||||
/>
|
||||
</EuiListGroup>
|
||||
</EuiFlexItem>
|
||||
{isIconVisible && (
|
||||
<EuiFlexItem grow={0} css={{ flexBasis: '15%' }}>
|
||||
<EuiButtonIcon
|
||||
display={isExpanded ? 'base' : 'empty'}
|
||||
size="s"
|
||||
color="text"
|
||||
onClick={onIconClick}
|
||||
iconType="spaces"
|
||||
iconSize="m"
|
||||
aria-label={i18n.translate('sharedUXPackages.chrome.sideNavigation.togglePanel', {
|
||||
defaultMessage: 'Toggle "{title}" panel navigation',
|
||||
values: { title },
|
||||
})}
|
||||
aria-expanded={isExpanded}
|
||||
data-test-subj={buttonDataTestSubj}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
<EuiButton
|
||||
onClick={onLinkClick}
|
||||
iconSide="right"
|
||||
iconType="arrowRight"
|
||||
size="s"
|
||||
fullWidth
|
||||
css={({ euiTheme }) => css`
|
||||
background-color: ${isActive
|
||||
? transparentize(euiTheme.colors.lightShade, 0.5)
|
||||
: 'transparent'};
|
||||
transform: none !important; /* don't translateY 1px */
|
||||
color: inherit;
|
||||
font-weight: inherit;
|
||||
padding-inline: ${euiTheme.size.s};
|
||||
& > span {
|
||||
justify-content: flex-start;
|
||||
position: relative;
|
||||
}
|
||||
${!withBadge
|
||||
? `
|
||||
& .euiIcon {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
transform: translateY(50%);
|
||||
}
|
||||
`
|
||||
: `
|
||||
& .euiBetaBadge {
|
||||
margin-left: -${euiTheme.size.m};
|
||||
}
|
||||
`}
|
||||
`}
|
||||
data-test-subj={dataTestSubj}
|
||||
>
|
||||
{withBadge ? <SubItemTitle item={item} /> : title}
|
||||
</EuiButton>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*/
|
||||
|
||||
import React, { type FC, useMemo, useEffect, useState, useCallback } from 'react';
|
||||
import { css } from '@emotion/css';
|
||||
import { css } from '@emotion/react';
|
||||
import {
|
||||
EuiTitle,
|
||||
EuiCollapsibleNavItem,
|
||||
|
@ -153,7 +153,7 @@ const renderBlockTitle: (
|
|||
size="xxxs"
|
||||
className="eui-textTruncate"
|
||||
data-test-subj={dataTestSubj}
|
||||
css={({ euiTheme }: any) => {
|
||||
css={({ euiTheme }) => {
|
||||
return {
|
||||
marginTop: spaceBefore ? euiTheme.size[spaceBefore] : undefined,
|
||||
paddingBlock: euiTheme.size.xs,
|
||||
|
@ -396,7 +396,9 @@ function nodeToEuiCollapsibleNavProps(
|
|||
};
|
||||
}
|
||||
|
||||
if (renderAs === 'panelOpener') {
|
||||
const hasVisibleSubItems = subItems && subItems.length > 0;
|
||||
|
||||
if (renderAs === 'panelOpener' && hasVisibleSubItems) {
|
||||
// Render as a panel opener (button to open a panel as a second navigation)
|
||||
return {
|
||||
items: [...renderPanelOpener(navNode, deps)],
|
||||
|
@ -404,7 +406,7 @@ function nodeToEuiCollapsibleNavProps(
|
|||
};
|
||||
}
|
||||
|
||||
if (renderAs === 'block' && deps.treeDepth > 0 && subItems) {
|
||||
if (renderAs === 'block' && deps.treeDepth > 0 && hasVisibleSubItems) {
|
||||
// Render as a group block (bold title + list of links underneath)
|
||||
return {
|
||||
items: [...renderGroup(navNode, subItems)],
|
||||
|
@ -425,10 +427,10 @@ function nodeToEuiCollapsibleNavProps(
|
|||
['data-test-subj']: dataTestSubj,
|
||||
iconProps: { size: deps.treeDepth === 0 ? 'm' : 's' },
|
||||
|
||||
// Render as an accordion or a link (handled by EUI) depending if
|
||||
// "items" is undefined or not. If it is undefined --> a link, otherwise an
|
||||
// accordion is rendered.
|
||||
...(subItems
|
||||
// If navNode has subItems, render as an accordion.
|
||||
// Otherwise render as a link.
|
||||
// NavItemProp declarations are handled by us, rendering is handled by EUI.
|
||||
...(hasVisibleSubItems
|
||||
? { items: subItems, isCollapsible }
|
||||
: { href, ...linkProps, external: isExternalLink }),
|
||||
},
|
||||
|
@ -446,12 +448,6 @@ function nodeToEuiCollapsibleNavProps(
|
|||
return { items, isVisible };
|
||||
}
|
||||
|
||||
const className = css`
|
||||
.euiAccordion__childWrapper {
|
||||
transition: none; // Remove the transition as it does not play well with dynamic links added to the accordion
|
||||
}
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
navNode: ChromeProjectNavigationNode;
|
||||
}
|
||||
|
@ -562,8 +558,14 @@ export const NavigationSectionUI: FC<Props> = React.memo(({ navNode: _navNode })
|
|||
return null;
|
||||
}
|
||||
|
||||
const navItemStyles = css`
|
||||
.euiAccordion__childWrapper {
|
||||
transition: none; // Remove the transition as it does not play well with dynamic links added to the accordion
|
||||
}
|
||||
`;
|
||||
|
||||
if (!items) {
|
||||
return <EuiCollapsibleNavItem {...props} className={className} />;
|
||||
return <EuiCollapsibleNavItem {...props} css={navItemStyles} />;
|
||||
}
|
||||
|
||||
// Item type ExclusiveUnion - accordions should not contain links
|
||||
|
@ -572,7 +574,7 @@ export const NavigationSectionUI: FC<Props> = React.memo(({ navNode: _navNode })
|
|||
return (
|
||||
<EuiCollapsibleNavItem
|
||||
{...rest}
|
||||
className={className}
|
||||
css={navItemStyles}
|
||||
items={items}
|
||||
accordionProps={getAccordionProps(navNode.path)}
|
||||
/>
|
||||
|
|
|
@ -14,7 +14,8 @@
|
|||
},
|
||||
"include": [
|
||||
"**/*.ts",
|
||||
"**/*.tsx"
|
||||
"**/*.tsx",
|
||||
"../../../../../../../typings/emotion.d.ts"
|
||||
],
|
||||
"kbn_references": [
|
||||
"@kbn/core-chrome-browser",
|
||||
|
@ -22,7 +23,7 @@
|
|||
"@kbn/i18n",
|
||||
"@kbn/shared-ux-storybook-mock",
|
||||
"@kbn/core-http-browser",
|
||||
"@kbn/core-analytics-browser",
|
||||
"@kbn/core-analytics-browser"
|
||||
],
|
||||
"exclude": [
|
||||
"target/**/*"
|
||||
|
|
|
@ -211,35 +211,23 @@ export function SolutionNavigationProvider(ctx: Pick<FtrProviderContext, 'getSer
|
|||
return false;
|
||||
}
|
||||
},
|
||||
async openPanel(
|
||||
sectionId: NavigationId,
|
||||
{ button }: { button: 'icon' | 'link' } = { button: 'icon' }
|
||||
) {
|
||||
async openPanel(sectionId: NavigationId) {
|
||||
log.debug('SolutionNavigation.sidenav.openPanel', sectionId);
|
||||
|
||||
const isOpen = await this.isPanelOpen(sectionId);
|
||||
if (isOpen) return;
|
||||
|
||||
const panelOpenerBtn = await testSubjects.find(
|
||||
button === 'icon' ? `~panelOpener-id-${sectionId}` : `~nav-item-id-${sectionId}`,
|
||||
TIMEOUT_CHECK
|
||||
);
|
||||
const panelOpenerBtn = await testSubjects.find(`~nav-item-id-${sectionId}`, TIMEOUT_CHECK);
|
||||
|
||||
await panelOpenerBtn.click();
|
||||
},
|
||||
async closePanel(
|
||||
sectionId: NavigationId,
|
||||
{ button }: { button: 'icon' | 'link' } = { button: 'icon' }
|
||||
) {
|
||||
async closePanel(sectionId: NavigationId) {
|
||||
log.debug('SolutionNavigation.sidenav.closePanel', sectionId);
|
||||
|
||||
const isOpen = await this.isPanelOpen(sectionId);
|
||||
if (!isOpen) return;
|
||||
|
||||
const panelOpenerBtn = await testSubjects.find(
|
||||
button === 'icon' ? `~panelOpener-id-${sectionId}` : `~nav-item-id-${sectionId}`,
|
||||
TIMEOUT_CHECK
|
||||
);
|
||||
const panelOpenerBtn = await testSubjects.find(`~nav-item-id-${sectionId}`, TIMEOUT_CHECK);
|
||||
|
||||
await panelOpenerBtn.click();
|
||||
},
|
||||
|
|
|
@ -7992,7 +7992,6 @@
|
|||
"sharedUXPackages.chrome.sideNavigation.feedbackCallout.btn": "Faites-nous en part",
|
||||
"sharedUXPackages.chrome.sideNavigation.feedbackCallout.title": "Comment fonctionne la navigation de votre côté ? Il manque quelque chose ?",
|
||||
"sharedUXPackages.chrome.sideNavigation.recentlyAccessed.title": "Récent",
|
||||
"sharedUXPackages.chrome.sideNavigation.togglePanel": "Afficher/Masquer le panneau de navigation \"{title}\"",
|
||||
"sharedUXPackages.codeEditor.ariaLabel": "Éditeur de code",
|
||||
"sharedUXPackages.codeEditor.codeEditorEditButton": "{codeEditorAriaLabel}, activer le mode d’édition",
|
||||
"sharedUXPackages.codeEditor.enterKeyLabel": "Entrée",
|
||||
|
|
|
@ -7985,7 +7985,6 @@
|
|||
"sharedUXPackages.chrome.sideNavigation.feedbackCallout.btn": "お知らせください",
|
||||
"sharedUXPackages.chrome.sideNavigation.feedbackCallout.title": "ナビゲーションはどのように機能していますか?ここまでで何か、忘れていることはありませんか?",
|
||||
"sharedUXPackages.chrome.sideNavigation.recentlyAccessed.title": "最近",
|
||||
"sharedUXPackages.chrome.sideNavigation.togglePanel": "\"{title}\"パネルナビゲーションを切り替える",
|
||||
"sharedUXPackages.codeEditor.ariaLabel": "コードエディター",
|
||||
"sharedUXPackages.codeEditor.codeEditorEditButton": "{codeEditorAriaLabel}、編集モードを有効化",
|
||||
"sharedUXPackages.codeEditor.enterKeyLabel": "Enter",
|
||||
|
|
|
@ -7998,7 +7998,6 @@
|
|||
"sharedUXPackages.chrome.sideNavigation.feedbackCallout.btn": "请告诉我们",
|
||||
"sharedUXPackages.chrome.sideNavigation.feedbackCallout.title": "导航如何为您提供帮助?缺少什么内容?",
|
||||
"sharedUXPackages.chrome.sideNavigation.recentlyAccessed.title": "最近",
|
||||
"sharedUXPackages.chrome.sideNavigation.togglePanel": "切换“{title}”面板导航",
|
||||
"sharedUXPackages.codeEditor.ariaLabel": "代码编辑器",
|
||||
"sharedUXPackages.codeEditor.codeEditorEditButton": "{codeEditorAriaLabel},激活编辑模式",
|
||||
"sharedUXPackages.codeEditor.enterKeyLabel": "Enter",
|
||||
|
|
|
@ -75,20 +75,6 @@ exports[`arrows ArrowBody renders correctly against snapshot 1`] = `
|
|||
|
||||
.css-8kffb{margin-right:8px;overflow:hidden;text-overflow:ellipsis;}
|
||||
</style>
|
||||
<style
|
||||
data-emotion="css"
|
||||
data-s=""
|
||||
>
|
||||
|
||||
.css-1kcx8qm{}
|
||||
</style>
|
||||
<style
|
||||
data-emotion="css"
|
||||
data-s=""
|
||||
>
|
||||
|
||||
.css-1kcx8qm .euiAccordion__childWrapper{-webkit-transition:none;transition:none;}
|
||||
</style>
|
||||
<style
|
||||
data-emotion="css-global"
|
||||
data-s=""
|
||||
|
|
|
@ -49,21 +49,21 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
deepLinkId: 'observabilityOnboarding',
|
||||
});
|
||||
|
||||
// open apm (Application) panel using the link button (not the button icon)
|
||||
await solutionNavigation.sidenav.openPanel('apm', { button: 'link' });
|
||||
// open apm (Application) panel
|
||||
await solutionNavigation.sidenav.openPanel('apm');
|
||||
{
|
||||
const isOpen = await solutionNavigation.sidenav.isPanelOpen('apm');
|
||||
expect(isOpen).to.be(true);
|
||||
}
|
||||
|
||||
await solutionNavigation.sidenav.closePanel('apm', { button: 'link' });
|
||||
await solutionNavigation.sidenav.closePanel('apm');
|
||||
{
|
||||
const isOpen = await solutionNavigation.sidenav.isPanelOpen('apm');
|
||||
expect(isOpen).to.be(false);
|
||||
}
|
||||
|
||||
// open Infrastructure panel and navigate to some link inside the panel
|
||||
await solutionNavigation.sidenav.openPanel('metrics', { button: 'link' });
|
||||
await solutionNavigation.sidenav.openPanel('metrics');
|
||||
{
|
||||
const isOpen = await solutionNavigation.sidenav.isPanelOpen('metrics');
|
||||
expect(isOpen).to.be(true);
|
||||
|
|
|
@ -43,7 +43,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'AI Assistant' });
|
||||
|
||||
// check Other Tools section
|
||||
await solutionNavigation.sidenav.openPanel('otherTools', { button: 'link' });
|
||||
await solutionNavigation.sidenav.openPanel('otherTools');
|
||||
{
|
||||
const isOpen = await solutionNavigation.sidenav.isPanelOpen('otherTools');
|
||||
expect(isOpen).to.be(true);
|
||||
|
@ -62,7 +62,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
});
|
||||
|
||||
// check Machine Learning section
|
||||
await solutionNavigation.sidenav.openPanel('machine_learning-landing', { button: 'link' });
|
||||
await solutionNavigation.sidenav.openPanel('machine_learning-landing');
|
||||
{
|
||||
const isOpen = await solutionNavigation.sidenav.isPanelOpen('machine_learning-landing');
|
||||
expect(isOpen).to.be(true);
|
||||
|
|
|
@ -60,12 +60,8 @@ import {
|
|||
ENTITY_ANALYTICS_URL,
|
||||
INDICATORS_URL,
|
||||
DISCOVER_URL,
|
||||
RULES_LANDING_URL,
|
||||
RULES_COVERAGE_URL,
|
||||
INVESTIGATIONS_URL,
|
||||
OSQUERY_URL,
|
||||
MACHINE_LEARNING_LANDING_URL,
|
||||
ASSETS_URL,
|
||||
HOSTS_URL,
|
||||
} from '../../../urls/navigation';
|
||||
import { RULES_MANAGEMENT_URL } from '../../../urls/rules_management';
|
||||
|
@ -265,10 +261,6 @@ describe('Serverless side navigation links', { tags: '@serverless' }, () => {
|
|||
cy.url().should('include', DASHBOARDS_URL);
|
||||
});
|
||||
|
||||
it('navigates to the Rules landing page', () => {
|
||||
navigateFromHeaderTo(ServerlessHeaders.RULES_LANDING, true);
|
||||
cy.url().should('include', RULES_LANDING_URL);
|
||||
});
|
||||
it('navigates to the Rules page', () => {
|
||||
navigateFromHeaderTo(ServerlessHeaders.RULES, true);
|
||||
cy.url().should('include', RULES_MANAGEMENT_URL);
|
||||
|
@ -304,11 +296,6 @@ describe('Serverless side navigation links', { tags: '@serverless' }, () => {
|
|||
cy.url().should('include', CASES_URL);
|
||||
});
|
||||
|
||||
it('navigates to the Investigations page', () => {
|
||||
navigateFromHeaderTo(ServerlessHeaders.INVESTIGATIONS, true);
|
||||
cy.url().should('include', INVESTIGATIONS_URL);
|
||||
});
|
||||
|
||||
it('navigates to the Timelines page', () => {
|
||||
navigateFromHeaderTo(ServerlessHeaders.TIMELINES, true);
|
||||
cy.url().should('include', TIMELINES_URL);
|
||||
|
@ -323,11 +310,6 @@ describe('Serverless side navigation links', { tags: '@serverless' }, () => {
|
|||
cy.url().should('include', INDICATORS_URL);
|
||||
});
|
||||
|
||||
it('navigates to the Explore landing page', () => {
|
||||
navigateFromHeaderTo(ServerlessHeaders.EXPLORE, true);
|
||||
cy.url().should('include', EXPLORE_URL);
|
||||
});
|
||||
|
||||
it('navigates to the Hosts page', () => {
|
||||
navigateFromHeaderTo(ServerlessHeaders.HOSTS, true);
|
||||
cy.url().should('include', HOSTS_URL);
|
||||
|
@ -343,16 +325,8 @@ describe('Serverless side navigation links', { tags: '@serverless' }, () => {
|
|||
cy.url().should('include', USERS_URL);
|
||||
});
|
||||
|
||||
it('navigates to the Assets page', () => {
|
||||
navigateFromHeaderTo(ServerlessHeaders.ASSETS, true);
|
||||
cy.url().should('include', ASSETS_URL);
|
||||
});
|
||||
it('navigates to the Endpoints page', () => {
|
||||
navigateFromHeaderTo(ServerlessHeaders.ENDPOINTS, true);
|
||||
cy.url().should('include', ENDPOINTS_URL);
|
||||
});
|
||||
it('navigates to the Machine learning landing page', () => {
|
||||
navigateFromHeaderTo(ServerlessHeaders.MACHINE_LEARNING, true);
|
||||
cy.url().should('include', MACHINE_LEARNING_LANDING_URL);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,25 +8,22 @@
|
|||
// main panels links
|
||||
export const DASHBOARDS = '[data-test-subj*="nav-item-deepLinkId-securitySolutionUI:dashboards"]';
|
||||
export const DASHBOARDS_PANEL_BTN =
|
||||
'[data-test-subj*="panelOpener-deepLinkId-securitySolutionUI:dashboards"]';
|
||||
'[data-test-subj*="nav-item-deepLinkId-securitySolutionUI:dashboards"]';
|
||||
|
||||
export const INVESTIGATIONS =
|
||||
'[data-test-subj*="nav-item-deepLinkId-securitySolutionUI:investigations"]';
|
||||
export const INVESTIGATIONS_PANEL_BTN =
|
||||
'[data-test-subj*="panelOpener-deepLinkId-securitySolutionUI:investigations"]';
|
||||
'[data-test-subj*="nav-item-deepLinkId-securitySolutionUI:investigations"]';
|
||||
|
||||
export const EXPLORE = '[data-test-subj*="nav-item-deepLinkId-securitySolutionUI:explore"]';
|
||||
export const EXPLORE_PANEL_BTN =
|
||||
'[data-test-subj*="panelOpener-deepLinkId-securitySolutionUI:explore"]';
|
||||
'[data-test-subj*="nav-item-deepLinkId-securitySolutionUI:explore"]';
|
||||
|
||||
export const RULES_LANDING =
|
||||
'[data-test-subj*="nav-item-deepLinkId-securitySolutionUI:rules-landing"]';
|
||||
export const RULES_PANEL_BTN =
|
||||
'[data-test-subj*="panelOpener-deepLinkId-securitySolutionUI:rules-landing"]';
|
||||
'[data-test-subj*="nav-item-deepLinkId-securitySolutionUI:rules-landing"]';
|
||||
|
||||
export const ASSETS = '[data-test-subj*="nav-item-deepLinkId-securitySolutionUI:assets"]';
|
||||
export const ASSETS_PANEL_BTN =
|
||||
'[data-test-subj*="panelOpener-deepLinkId-securitySolutionUI:assets"]';
|
||||
export const ASSETS_PANEL_BTN = '[data-test-subj*="nav-item-deepLinkId-securitySolutionUI:assets"]';
|
||||
|
||||
export const MACHINE_LEARNING =
|
||||
'[data-test-subj*="nav-item-deepLinkId-securitySolutionUI:machine_learning-landing"]';
|
||||
|
|
|
@ -24,7 +24,10 @@ export const navigateToDiscoverPageInServerless = () => {
|
|||
};
|
||||
|
||||
export const navigateToExplorePageInServerless = () => {
|
||||
navigateTo(EXPLORE);
|
||||
// NOTE: the "Explore" page is not directly accessible from the side nav at this time
|
||||
navigateTo(EXPLORE); // open secondary navigation panel
|
||||
navigateTo('[data-test-subj~="panelNavItem-id-hosts"]'); // navigate to "Hosts"
|
||||
navigateToExploreUsingBreadcrumb();
|
||||
};
|
||||
|
||||
export const navigateToHostsUsingBreadcrumb = () => {
|
||||
|
|
|
@ -12,7 +12,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
const pageObjects = getPageObjects(['svlCommonPage', 'svlCommonNavigation', 'header']);
|
||||
|
||||
const openInfraSection = async () => {
|
||||
await pageObjects.svlCommonNavigation.sidenav.openPanel('metrics', { button: 'link' });
|
||||
await pageObjects.svlCommonNavigation.sidenav.openPanel('metrics');
|
||||
};
|
||||
|
||||
describe('Infra Side Navigation', () => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue