mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
[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\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\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\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:
parent
8e6d961497
commit
0cc28d0e71
16 changed files with 94 additions and 252 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/**/*"
|
||||
|
|
|
@ -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();
|
||||
},
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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=""
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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 = () => {
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue