[8.x] NavigationItemOpenPanel: remove handling of landing page ("four squares" design) (#210893) (#218133)

# Backport

This will backport the following commits from `main` to `8.x`:
- [NavigationItemOpenPanel: remove handling of landing page ("four
squares" design)
(#210893)](https://github.com/elastic/kibana/pull/210893)

<!--- Backport version: 9.6.6 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sorenlouv/backport)

<!--BACKPORT [{"author":{"name":"Tim
Sullivan","email":"tsullivan@users.noreply.github.com"},"sourceCommit":{"committedDate":"2025-04-09T14:25:30Z","message":"NavigationItemOpenPanel:
remove handling of landing page (\"four squares\" design)
(#210893)\n\n## Summary\n\nPart of Epic:
https://github.com/elastic/kibana-team/issues/1439\nRequires:
https://github.com/elastic/kibana/issues/212903\n\nChanges:\n1. Moves
the Solution Side Nav away from the \"four squares\" design\npattern:
where clicking the item label opens a landing page and the item\nicon
opens the secondary nav panel. This was a custom component\nimplemented
in the Kibana package, not part of the EUI\n`EuiCollapsibleNavBeta`
component.\n2. Changes some usage of `@emotion/css` to `@emotion/react`
for better\ndeveloper experience\n\n###
Screenshots\n\n<details><summary>Before</summary>\n\n\n![01-security-solution-before](a8ef8476-e36d-479f-9eba-2450b1df71ac)\n\n</details>\n\n###
Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers
should verify this PR satisfies this list as well.\n\n- [x] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [x] The PR
description includes the appropriate Release Notes section,\nand the
correct `release_note:*` label is applied per
the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n\n###
Identify risks\n\nDoes this PR introduce any risks? For example,
consider risks like hard\nto test bugs, performance regression,
potential of data loss.\n\nDescribe the risk, its severity, and
mitigation for each identified\nrisk. Invite stakeholders and evaluate
how to proceed before merging.\n\n- [ ] This design pattern was only
used in Security Solution. There is a\nsmall risk of regression issues
in Security Solution navigation. This\nwas mitigated by manual testing
during
development.","sha":"77523f7b15aabe612933c352e71d93e441d2eb3e","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["blocked","release_note:skip","backport
missing","Team:
SecuritySolution","Team:SharedUX","ci:project-deploy-observability","backport:version","v9.1.0","v8.19.0"],"title":"NavigationItemOpenPanel:
remove handling of landing page (\"four squares\"
design)","number":210893,"url":"https://github.com/elastic/kibana/pull/210893","mergeCommit":{"message":"NavigationItemOpenPanel:
remove handling of landing page (\"four squares\" design)
(#210893)\n\n## Summary\n\nPart of Epic:
https://github.com/elastic/kibana-team/issues/1439\nRequires:
https://github.com/elastic/kibana/issues/212903\n\nChanges:\n1. Moves
the Solution Side Nav away from the \"four squares\" design\npattern:
where clicking the item label opens a landing page and the item\nicon
opens the secondary nav panel. This was a custom component\nimplemented
in the Kibana package, not part of the EUI\n`EuiCollapsibleNavBeta`
component.\n2. Changes some usage of `@emotion/css` to `@emotion/react`
for better\ndeveloper experience\n\n###
Screenshots\n\n<details><summary>Before</summary>\n\n\n![01-security-solution-before](a8ef8476-e36d-479f-9eba-2450b1df71ac)\n\n</details>\n\n###
Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers
should verify this PR satisfies this list as well.\n\n- [x] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [x] The PR
description includes the appropriate Release Notes section,\nand the
correct `release_note:*` label is applied per
the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n\n###
Identify risks\n\nDoes this PR introduce any risks? For example,
consider risks like hard\nto test bugs, performance regression,
potential of data loss.\n\nDescribe the risk, its severity, and
mitigation for each identified\nrisk. Invite stakeholders and evaluate
how to proceed before merging.\n\n- [ ] This design pattern was only
used in Security Solution. There is a\nsmall risk of regression issues
in Security Solution navigation. This\nwas mitigated by manual testing
during
development.","sha":"77523f7b15aabe612933c352e71d93e441d2eb3e"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/210893","number":210893,"mergeCommit":{"message":"NavigationItemOpenPanel:
remove handling of landing page (\"four squares\" design)
(#210893)\n\n## Summary\n\nPart of Epic:
https://github.com/elastic/kibana-team/issues/1439\nRequires:
https://github.com/elastic/kibana/issues/212903\n\nChanges:\n1. Moves
the Solution Side Nav away from the \"four squares\" design\npattern:
where clicking the item label opens a landing page and the item\nicon
opens the secondary nav panel. This was a custom component\nimplemented
in the Kibana package, not part of the EUI\n`EuiCollapsibleNavBeta`
component.\n2. Changes some usage of `@emotion/css` to `@emotion/react`
for better\ndeveloper experience\n\n###
Screenshots\n\n<details><summary>Before</summary>\n\n\n![01-security-solution-before](a8ef8476-e36d-479f-9eba-2450b1df71ac)\n\n</details>\n\n###
Checklist\n\nCheck the PR satisfies following conditions. \n\nReviewers
should verify this PR satisfies this list as well.\n\n- [x] [Unit or
functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere
updated or added to match the most common scenarios\n- [x] The PR
description includes the appropriate Release Notes section,\nand the
correct `release_note:*` label is applied per
the\n[guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)\n\n###
Identify risks\n\nDoes this PR introduce any risks? For example,
consider risks like hard\nto test bugs, performance regression,
potential of data loss.\n\nDescribe the risk, its severity, and
mitigation for each identified\nrisk. Invite stakeholders and evaluate
how to proceed before merging.\n\n- [ ] This design pattern was only
used in Security Solution. There is a\nsmall risk of regression issues
in Security Solution navigation. This\nwas mitigated by manual testing
during
development.","sha":"77523f7b15aabe612933c352e71d93e441d2eb3e"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->
This commit is contained in:
Tim Sullivan 2025-04-15 02:16:12 -07:00 committed by GitHub
parent 8e6d961497
commit 0cc28d0e71
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 94 additions and 252 deletions

View file

@ -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();
});

View file

@ -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>
);
};

View file

@ -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)}
/>

View file

@ -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/**/*"

View file

@ -209,35 +209,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();
},

View file

@ -8073,7 +8073,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",

View file

@ -8065,7 +8065,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",

View file

@ -8080,7 +8080,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",

View file

@ -89,20 +89,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=""

View file

@ -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);

View file

@ -37,7 +37,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);
@ -56,7 +56,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);

View file

@ -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,
CLOUD_DEFEND_URL,
HOSTS_URL,
} from '../../../urls/navigation';
@ -271,10 +267,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);
@ -310,11 +302,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);
@ -329,11 +316,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);
@ -349,10 +331,6 @@ 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);
@ -361,8 +339,4 @@ describe('Serverless side navigation links', { tags: '@serverless' }, () => {
navigateFromHeaderTo(ServerlessHeaders.CLOUD_DEFEND, true);
cy.url().should('include', CLOUD_DEFEND_URL);
});
it('navigates to the Machine learning landing page', () => {
navigateFromHeaderTo(ServerlessHeaders.MACHINE_LEARNING, true);
cy.url().should('include', MACHINE_LEARNING_LANDING_URL);
});
});

View file

@ -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"]';

View file

@ -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 = () => {

View file

@ -15,7 +15,7 @@ export function MachineLearningNavigationProviderObservability({
const svlCommonNavigation = getPageObject('svlCommonNavigation');
async function navigateToArea(id: string) {
await svlCommonNavigation.sidenav.openPanel('machine_learning-landing', { button: 'link' });
await svlCommonNavigation.sidenav.openPanel('machine_learning-landing');
await testSubjects.existOrFail(`~panelNavItem-id-ml:${id}`, {
timeout: 60 * 1000,
});

View file

@ -21,7 +21,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
};
const openInfraSection = async () => {
await pageObjects.svlCommonNavigation.sidenav.openPanel('metrics', { button: 'link' });
await pageObjects.svlCommonNavigation.sidenav.openPanel('metrics');
};
describe('Infra Side Navigation', () => {