Reorganize footer items for Solutions (#218050)

## Summary

Epic: https://github.com/elastic/kibana-team/issues/1439
~Depends on https://github.com/elastic/kibana/pull/218156~

Addresses footer issues and a few content issues


https://github.com/user-attachments/assets/07063aa7-8a49-4cb5-9fd2-a6e1cbd674b7


1. Footer item texts should not be bold
2. We should have the spacing of regular nav sub-items in the footer

Other fixes:
1. Fix text casing in "Machine Learning" (Note: [other casing issues
exist](https://github.com/elastic/kibana/issues/217352))
2. Remove `recentlyAccessed` sections

### Checklist

Check the PR satisfies following conditions. 

Reviewers should verify this PR satisfies this list as well.

- [x] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md)
- [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
This commit is contained in:
Tim Sullivan 2025-05-02 07:51:10 -07:00 committed by GitHub
parent c89c1ee30d
commit ee74bb4e65
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 779 additions and 657 deletions

View file

@ -42,14 +42,19 @@ const sectionStyles = {
paddingBlock: euiTheme.size.xs, paddingBlock: euiTheme.size.xs,
paddingInline: euiTheme.size.s, paddingInline: euiTheme.size.s,
}), }),
euiCollapsibleNavItem: ({ euiTheme }: Theme) => css` euiCollapsibleNavSection: ({ euiTheme }: Theme) => css`
.euiAccordion__childWrapper { .euiCollapsibleNavAccordion.isSelected {
transition: none; // Remove the transition as it does not play well with dynamic links added to the accordion .euiAccordion__triggerWrapper,
.euiCollapsibleNavLink {
background-color: ${euiTheme.colors.backgroundLightPrimary};
} }
}
.euiAccordion__children .euiCollapsibleNavItem__items { .euiAccordion__children .euiCollapsibleNavItem__items {
padding-inline-start: ${euiTheme.size.m}; padding-inline-start: ${euiTheme.size.m};
margin-inline-start: ${euiTheme.size.m}; margin-inline-start: ${euiTheme.size.m};
} }
&:only-child .euiCollapsibleNavItem__icon { &:only-child .euiCollapsibleNavItem__icon {
transform: scale(1.33); transform: scale(1.33);
} }
@ -60,15 +65,19 @@ const sectionStyles = {
:hover { :hover {
background-color: ${euiTheme.colors.backgroundBaseInteractiveHover}; background-color: ${euiTheme.colors.backgroundBaseInteractiveHover};
} }
&.isSelected { &.isSelected {
background-color: ${euiTheme.colors.backgroundLightPrimary};
:hover { :hover {
background-color: ${euiTheme.colors.backgroundLightPrimary}; background-color: ${euiTheme.colors.backgroundLightPrimary};
} }
} }
} }
`,
euiAccordionChildWrapper: ({ euiTheme }: Theme) => css`
.euiAccordion__childWrapper { .euiAccordion__childWrapper {
background-color: ${euiTheme.colors.backgroundBasePlain}; background-color: ${euiTheme.colors.backgroundBasePlain};
transition: none; // Remove the transition as it does not play well with dynamic links added to the accordion
} }
`, `,
}; };
@ -461,7 +470,8 @@ function nodeToEuiCollapsibleNavProps(
path, path,
isSelected, isSelected,
onClick, onClick,
css: sectionStyles.euiCollapsibleNavSubItem, css: [sectionStyles.euiCollapsibleNavSubItem, sectionStyles.euiAccordionChildWrapper],
className: classnames([isSelected ? 'isSelected' : undefined]),
icon: navNode.icon, icon: navNode.icon,
// @ts-expect-error title accepts JSX elements and they render correctly but the type definition expects a string // @ts-expect-error title accepts JSX elements and they render correctly but the type definition expects a string
title: navNode.withBadge ? <SubItemTitle item={navNode} /> : navNode.title, title: navNode.withBadge ? <SubItemTitle item={navNode} /> : navNode.title,
@ -609,12 +619,12 @@ export const NavigationSectionUI: FC<Props> = React.memo(({ navNode: _navNode })
{items ? ( {items ? (
<EuiCollapsibleNavItem <EuiCollapsibleNavItem
{...rest} {...rest}
css={sectionStyles.euiCollapsibleNavItem} css={[sectionStyles.euiCollapsibleNavSection, sectionStyles.euiAccordionChildWrapper]}
items={items} items={items}
accordionProps={getAccordionProps(navNode.path)} accordionProps={getAccordionProps(navNode.path)}
/> />
) : ( ) : (
<EuiCollapsibleNavItem {...props} css={sectionStyles.euiCollapsibleNavItem} /> <EuiCollapsibleNavItem {...props} css={sectionStyles.euiCollapsibleNavSection} />
)} )}
</div> </div>
); );

View file

@ -87,7 +87,15 @@ const NavigationWrapper: FC<Props & Omit<Partial<EuiCollapsibleNavBetaProps>, 'c
{props.clickActionText ?? 'Click me'} {props.clickActionText ?? 'Click me'}
</EuiButton> </EuiButton>
) : ( ) : (
<p>Hello world</p> <>
<h1>Solution side nav</h1>
<br />
<p>There should be multiple &quot;selected&quot; nodes in the side nav:</p>
<ul>
<li>* Item 03 &raquo; Item 22</li>
<li>* Footer parent 1 &raquo; Item 35</li>
</ul>
</>
)} )}
</EuiPageTemplate.Section> </EuiPageTemplate.Section>
</EuiPageTemplate> </EuiPageTemplate>
@ -455,9 +463,49 @@ const generalLayoutNavTree: NavigationTreeDefinitionUI = {
id: 'example_project_footer', id: 'example_project_footer',
path: '', path: '',
children: [ children: [
{
id: 'footer-section6',
title: 'Footer parent 1',
path: '',
renderAs: 'accordion',
spaceBefore: null,
icon: 'iInCircle',
defaultIsCollapsed: false,
children: [
{
id: 'item33',
path: '',
title: 'Item 33',
href: '/app/kibana',
icon: 'iInCircle',
},
{
id: 'item34',
path: '',
title: 'Item 34',
href: '/app/kibana',
icon: 'iInCircle',
},
{
id: 'item35',
path: '',
title: 'Item 35',
href: '/app/kibana',
icon: 'iInCircle',
openInNewTab: true,
},
],
},
{
id: 'item10',
path: '',
title: 'Item 10',
icon: 'iInCircle',
href: '/app/kibana',
},
{ {
id: 'footer-section5', id: 'footer-section5',
title: 'Parent item, closed', title: 'Footer parent 2',
path: '', path: '',
renderAs: 'accordion', renderAs: 'accordion',
spaceBefore: null, spaceBefore: null,
@ -502,46 +550,6 @@ const generalLayoutNavTree: NavigationTreeDefinitionUI = {
}, },
], ],
}, },
{
id: 'item10',
path: '',
title: 'Item 10',
icon: 'iInCircle',
href: '/app/kibana',
},
{
id: 'footer-section6',
title: 'Parent item, opened',
path: '',
renderAs: 'accordion',
spaceBefore: null,
icon: 'iInCircle',
defaultIsCollapsed: false,
children: [
{
id: 'item33',
path: '',
title: 'Item 33',
href: '/app/kibana',
icon: 'iInCircle',
},
{
id: 'item34',
path: '',
title: 'Item 34',
href: '/app/kibana',
icon: 'iInCircle',
},
{
id: 'item35',
path: '',
title: 'Item 35',
href: '/app/kibana',
icon: 'iInCircle',
openInNewTab: true,
},
],
},
], ],
}, },
], ],
@ -585,6 +593,11 @@ export const GeneralLayoutStructure = (args: NavigationServices) => {
{ id: '', path: 'example_project.root-section1.item03.child-section4' }, { id: '', path: 'example_project.root-section1.item03.child-section4' },
{ id: '', path: 'example_project.root-section1.item03.child-section4.sub3' }, { id: '', path: 'example_project.root-section1.item03.child-section4.sub3' },
], ],
[
{ id: '', path: 'example_project_footer' },
{ id: '', path: 'example_project_footer.footer-section6' },
{ id: '', path: 'example_project_footer.footer-section6.item35' },
],
]); ]);
return ( return (

View file

@ -11,7 +11,6 @@ import type { NavigationTreeDefinition } from '@kbn/core-chrome-browser';
export const createNavigationTree = (): NavigationTreeDefinition => { export const createNavigationTree = (): NavigationTreeDefinition => {
return { return {
body: [ body: [
{ type: 'recentlyAccessed' },
{ {
type: 'navGroup', type: 'navGroup',
id: 'workchat_project_nav', id: 'workchat_project_nav',
@ -36,7 +35,10 @@ export const createNavigationTree = (): NavigationTreeDefinition => {
], ],
footer: [ footer: [
{ {
type: 'navItem', type: 'navGroup',
id: 'workchat_project_nav_footer',
children: [
{
id: 'devTools', id: 'devTools',
title: i18n.translate('xpack.serverlessObservability.nav.devTools', { title: i18n.translate('xpack.serverlessObservability.nav.devTools', {
defaultMessage: 'Developer tools', defaultMessage: 'Developer tools',
@ -45,20 +47,20 @@ export const createNavigationTree = (): NavigationTreeDefinition => {
icon: 'editorCodeBlock', icon: 'editorCodeBlock',
}, },
{ {
type: 'navGroup',
id: 'project_settings_project_nav', id: 'project_settings_project_nav',
title: i18n.translate('xpack.serverlessObservability.nav.projectSettings', { title: i18n.translate('xpack.serverlessObservability.nav.projectSettings', {
defaultMessage: 'Project settings', defaultMessage: 'Project settings',
}), }),
icon: 'gear', icon: 'gear',
breadcrumbStatus: 'hidden', breadcrumbStatus: 'hidden',
renderAs: 'accordion',
spaceBefore: null,
children: [ children: [
{ {
id: 'management', id: 'management',
title: i18n.translate('xpack.serverlessObservability.nav.mngt', { title: i18n.translate('xpack.serverlessObservability.nav.mngt', {
defaultMessage: 'Management', defaultMessage: 'Management',
}), }),
spaceBefore: null,
renderAs: 'panelOpener', renderAs: 'panelOpener',
children: [ children: [
{ {
@ -85,9 +87,12 @@ export const createNavigationTree = (): NavigationTreeDefinition => {
children: [{ link: 'management:api_keys', breadcrumbStatus: 'hidden' }], children: [{ link: 'management:api_keys', breadcrumbStatus: 'hidden' }],
}, },
{ {
title: i18n.translate('xpack.serverlessObservability.nav.mngt.alertsAndInsights', { title: i18n.translate(
'xpack.serverlessObservability.nav.mngt.alertsAndInsights',
{
defaultMessage: 'Alerts and insights', defaultMessage: 'Alerts and insights',
}), }
),
breadcrumbStatus: 'hidden', breadcrumbStatus: 'hidden',
children: [ children: [
{ link: 'management:triggersActionsConnectors', breadcrumbStatus: 'hidden' }, { link: 'management:triggersActionsConnectors', breadcrumbStatus: 'hidden' },
@ -133,5 +138,7 @@ export const createNavigationTree = (): NavigationTreeDefinition => {
], ],
}, },
], ],
},
],
}; };
}; };

View file

@ -210,7 +210,7 @@ function createNavTree({ streamsAvailable }: { streamsAvailable?: boolean }) {
id: 'machine_learning-landing', id: 'machine_learning-landing',
renderAs: 'panelOpener', renderAs: 'panelOpener',
title: i18n.translate('xpack.observability.obltNav.machineLearning', { title: i18n.translate('xpack.observability.obltNav.machineLearning', {
defaultMessage: 'Machine learning', defaultMessage: 'Machine Learning',
}), }),
children: [ children: [
{ {
@ -325,9 +325,11 @@ function createNavTree({ streamsAvailable }: { streamsAvailable?: boolean }) {
}, },
], ],
footer: [ footer: [
{ type: 'recentlyAccessed' },
{ {
type: 'navItem', type: 'navGroup',
id: 'observability_project_nav_footer',
children: [
{
title: i18n.translate('xpack.observability.obltNav.addData', { title: i18n.translate('xpack.observability.obltNav.addData', {
defaultMessage: 'Add data', defaultMessage: 'Add data',
}), }),
@ -335,7 +337,6 @@ function createNavTree({ streamsAvailable }: { streamsAvailable?: boolean }) {
icon: 'launch', icon: 'launch',
}, },
{ {
type: 'navItem',
id: 'devTools', id: 'devTools',
title: i18n.translate('xpack.observability.obltNav.devTools', { title: i18n.translate('xpack.observability.obltNav.devTools', {
defaultMessage: 'Developer tools', defaultMessage: 'Developer tools',
@ -344,13 +345,14 @@ function createNavTree({ streamsAvailable }: { streamsAvailable?: boolean }) {
icon: 'editorCodeBlock', icon: 'editorCodeBlock',
}, },
{ {
type: 'navGroup',
id: 'project_settings_project_nav', id: 'project_settings_project_nav',
title: i18n.translate('xpack.observability.obltNav.management', { title: i18n.translate('xpack.observability.obltNav.management', {
defaultMessage: 'Management', defaultMessage: 'Management',
}), }),
icon: 'gear', icon: 'gear',
breadcrumbStatus: 'hidden', breadcrumbStatus: 'hidden',
renderAs: 'accordion',
spaceBefore: null,
children: [ children: [
{ {
id: 'stack_management', // This id can't be changed as we use it to open the panel programmatically id: 'stack_management', // This id can't be changed as we use it to open the panel programmatically
@ -455,6 +457,8 @@ function createNavTree({ streamsAvailable }: { streamsAvailable?: boolean }) {
], ],
}, },
], ],
},
],
}; };
return navTree; return navTree;

View file

@ -15,7 +15,6 @@ export const createNavigationTree = ({
}): NavigationTreeDefinition => { }): NavigationTreeDefinition => {
return { return {
body: [ body: [
{ type: 'recentlyAccessed' },
{ {
type: 'navGroup', type: 'navGroup',
id: 'observability_project_nav', id: 'observability_project_nav',
@ -173,7 +172,7 @@ export const createNavigationTree = ({
id: 'machine_learning-landing', id: 'machine_learning-landing',
renderAs: 'panelOpener', renderAs: 'panelOpener',
title: i18n.translate('xpack.serverlessObservability.nav.machineLearning', { title: i18n.translate('xpack.serverlessObservability.nav.machineLearning', {
defaultMessage: 'Machine learning', defaultMessage: 'Machine Learning',
}), }),
children: [ children: [
{ {
@ -259,7 +258,10 @@ export const createNavigationTree = ({
], ],
footer: [ footer: [
{ {
type: 'navItem', type: 'navGroup',
id: 'observability_project_nav_footer',
children: [
{
title: i18n.translate('xpack.serverlessObservability.nav.getStarted', { title: i18n.translate('xpack.serverlessObservability.nav.getStarted', {
defaultMessage: 'Add data', defaultMessage: 'Add data',
}), }),
@ -267,7 +269,6 @@ export const createNavigationTree = ({
icon: 'launch', icon: 'launch',
}, },
{ {
type: 'navItem',
id: 'devTools', id: 'devTools',
title: i18n.translate('xpack.serverlessObservability.nav.devTools', { title: i18n.translate('xpack.serverlessObservability.nav.devTools', {
defaultMessage: 'Developer tools', defaultMessage: 'Developer tools',
@ -276,13 +277,14 @@ export const createNavigationTree = ({
icon: 'editorCodeBlock', icon: 'editorCodeBlock',
}, },
{ {
type: 'navGroup',
id: 'project_settings_project_nav', id: 'project_settings_project_nav',
title: i18n.translate('xpack.serverlessObservability.nav.projectSettings', { title: i18n.translate('xpack.serverlessObservability.nav.projectSettings', {
defaultMessage: 'Project settings', defaultMessage: 'Project settings',
}), }),
icon: 'gear', icon: 'gear',
breadcrumbStatus: 'hidden', breadcrumbStatus: 'hidden',
renderAs: 'accordion',
spaceBefore: null,
children: [ children: [
{ {
id: 'management', id: 'management',
@ -317,9 +319,12 @@ export const createNavigationTree = ({
children: [{ link: 'management:api_keys', breadcrumbStatus: 'hidden' }], children: [{ link: 'management:api_keys', breadcrumbStatus: 'hidden' }],
}, },
{ {
title: i18n.translate('xpack.serverlessObservability.nav.mngt.alertsAndInsights', { title: i18n.translate(
'xpack.serverlessObservability.nav.mngt.alertsAndInsights',
{
defaultMessage: 'Alerts and insights', defaultMessage: 'Alerts and insights',
}), }
),
breadcrumbStatus: 'hidden', breadcrumbStatus: 'hidden',
children: [ children: [
{ link: 'management:triggersActionsConnectors', breadcrumbStatus: 'hidden' }, { link: 'management:triggersActionsConnectors', breadcrumbStatus: 'hidden' },
@ -381,5 +386,7 @@ export const createNavigationTree = ({
], ],
}, },
], ],
},
],
}; };
}; };

View file

@ -234,7 +234,8 @@ export const getNavigationTreeDefinition = ({
}, },
], ],
footer: [ footer: [
{ type: 'recentlyAccessed' }, {
children: [
{ {
breadcrumbStatus: 'hidden', breadcrumbStatus: 'hidden',
children: [ children: [
@ -329,9 +330,14 @@ export const getNavigationTreeDefinition = ({
], ],
icon: 'gear', icon: 'gear',
id: 'project_settings_project_nav', id: 'project_settings_project_nav',
renderAs: 'accordion',
spaceBefore: null,
title: i18n.translate('xpack.enterpriseSearch.searchNav.management', { title: i18n.translate('xpack.enterpriseSearch.searchNav.management', {
defaultMessage: 'Management', defaultMessage: 'Management',
}), }),
},
],
id: 'search_project_nav_footer',
type: 'navGroup', type: 'navGroup',
}, },
], ],

View file

@ -149,9 +149,12 @@ export const navigationTree = ({ isAppRegistered }: ApplicationStart): Navigatio
}, },
], ],
footer: [ footer: [
{
type: 'navGroup',
id: 'search_project_nav_footer',
children: [
{ {
id: 'gettingStarted', id: 'gettingStarted',
type: 'navItem',
title: i18n.translate('xpack.serverlessSearch.nav.gettingStarted', { title: i18n.translate('xpack.serverlessSearch.nav.gettingStarted', {
defaultMessage: 'Getting Started', defaultMessage: 'Getting Started',
}), }),
@ -159,13 +162,14 @@ export const navigationTree = ({ isAppRegistered }: ApplicationStart): Navigatio
icon: 'launch', icon: 'launch',
}, },
{ {
type: 'navGroup',
id: 'project_settings_project_nav', id: 'project_settings_project_nav',
title: i18n.translate('xpack.serverlessSearch.nav.projectSettings', { title: i18n.translate('xpack.serverlessSearch.nav.projectSettings', {
defaultMessage: 'Project settings', defaultMessage: 'Project settings',
}), }),
icon: 'gear', icon: 'gear',
breadcrumbStatus: 'hidden', breadcrumbStatus: 'hidden',
renderAs: 'accordion',
spaceBefore: null,
children: [ children: [
{ {
link: 'management:trained_models', link: 'management:trained_models',
@ -207,9 +211,12 @@ export const navigationTree = ({ isAppRegistered }: ApplicationStart): Navigatio
{ link: 'management:roles', breadcrumbStatus: 'hidden' }, { link: 'management:roles', breadcrumbStatus: 'hidden' },
{ {
cloudLink: 'userAndRoles', cloudLink: 'userAndRoles',
title: i18n.translate('xpack.serverlessSearch.nav.mngt.access.userAndRoles', { title: i18n.translate(
'xpack.serverlessSearch.nav.mngt.access.userAndRoles',
{
defaultMessage: 'Manage Organization Members', defaultMessage: 'Manage Organization Members',
}), }
),
}, },
], ],
}, },
@ -273,5 +280,7 @@ export const navigationTree = ({ isAppRegistered }: ApplicationStart): Navigatio
], ],
}, },
], ],
},
],
}; };
}; };

View file

@ -63,7 +63,7 @@ export const i18nStrings = {
}, },
ml: { ml: {
title: i18n.translate('securitySolutionPackages.navLinks.ml', { title: i18n.translate('securitySolutionPackages.navLinks.ml', {
defaultMessage: 'Machine learning', defaultMessage: 'Machine Learning',
}), }),
overview: i18n.translate('securitySolutionPackages.navLinks.ml.overview', { overview: i18n.translate('securitySolutionPackages.navLinks.ml.overview', {
defaultMessage: 'Overview', defaultMessage: 'Overview',

View file

@ -74,33 +74,39 @@ export const createNavigationTree = (services: Services): NavigationTreeDefiniti
}, },
], ],
footer: [ footer: [
{
id: 'security_solution_nav_footer',
type: 'navGroup',
children: [
{ {
id: SecurityPageName.landing, id: SecurityPageName.landing,
link: securityLink(SecurityPageName.landing), link: securityLink(SecurityPageName.landing),
type: 'navItem',
icon: 'launch', icon: 'launch',
}, },
{ {
type: 'navItem',
link: 'dev_tools', link: 'dev_tools',
title: i18nStrings.devTools, title: i18nStrings.devTools,
icon: 'editorCodeBlock', icon: 'editorCodeBlock',
}, },
{ {
type: 'navGroup',
title: i18nStrings.management.title, title: i18nStrings.management.title,
icon: 'gear', icon: 'gear',
breadcrumbStatus: 'hidden', breadcrumbStatus: 'hidden',
renderAs: 'accordion',
spaceBefore: null,
children: [ children: [
{ {
id: 'stack_management', // This id can't be changed as we use it to open the panel programmatically id: 'stack_management',
title: i18nStrings.stackManagement.title, title: i18nStrings.stackManagement.title,
renderAs: 'panelOpener', renderAs: 'panelOpener',
spaceBefore: null, spaceBefore: null,
children: [ children: [
{ {
title: i18nStrings.stackManagement.ingest.title, title: i18nStrings.stackManagement.ingest.title,
children: [{ link: 'management:ingest_pipelines' }, { link: 'management:pipelines' }], children: [
{ link: 'management:ingest_pipelines' },
{ link: 'management:pipelines' },
],
}, },
{ {
title: i18nStrings.stackManagement.data.title, title: i18nStrings.stackManagement.data.title,
@ -189,4 +195,6 @@ export const createNavigationTree = (services: Services): NavigationTreeDefiniti
], ],
}, },
], ],
},
],
}); });

View file

@ -96,17 +96,21 @@ export const createAiNavigationTree = (): NavigationTreeDefinition => ({
], ],
footer: [ footer: [
{ {
type: 'navItem', id: 'security_solution_ai_nav_footer',
type: 'navGroup',
children: [
{
id: SecurityPageName.landing, id: SecurityPageName.landing,
link: securityLink(SecurityPageName.landing), link: securityLink(SecurityPageName.landing),
icon: 'launch', icon: 'launch',
}, },
{ {
type: 'navItem',
link: 'dev_tools', link: 'dev_tools',
title: i18nStrings.devTools, title: i18nStrings.devTools,
icon: 'editorCodeBlock', icon: 'editorCodeBlock',
}, },
createStackManagementNavigationTree(), createStackManagementNavigationTree(),
], ],
},
],
}); });

View file

@ -82,17 +82,21 @@ export const createNavigationTree = (services: Services): NavigationTreeDefiniti
], ],
footer: [ footer: [
{ {
type: 'navItem', id: 'security_solution_nav_footer',
type: 'navGroup',
children: [
{
id: SecurityPageName.landing, id: SecurityPageName.landing,
link: securityLink(SecurityPageName.landing), link: securityLink(SecurityPageName.landing),
icon: 'launch', icon: 'launch',
}, },
{ {
type: 'navItem',
link: 'dev_tools', link: 'dev_tools',
title: i18nStrings.devTools, title: i18nStrings.devTools,
icon: 'editorCodeBlock', icon: 'editorCodeBlock',
}, },
createStackManagementNavigationTree(), createStackManagementNavigationTree(),
], ],
},
],
}); });

View file

@ -5,16 +5,17 @@
* 2.0. * 2.0.
*/ */
import type { GroupDefinition } from '@kbn/core-chrome-browser'; import type { NodeDefinition } from '@kbn/core-chrome-browser';
import { SecurityPageName } from '@kbn/security-solution-navigation'; import { SecurityPageName } from '@kbn/security-solution-navigation';
import { i18nStrings, securityLink } from '@kbn/security-solution-navigation/links'; import { i18nStrings, securityLink } from '@kbn/security-solution-navigation/links';
export const createStackManagementNavigationTree = (): GroupDefinition => ({ export const createStackManagementNavigationTree = (): NodeDefinition => ({
type: 'navGroup',
id: 'category-management', id: 'category-management',
title: i18nStrings.projectSettings.title, title: i18nStrings.projectSettings.title,
icon: 'gear', icon: 'gear',
breadcrumbStatus: 'hidden', breadcrumbStatus: 'hidden',
renderAs: 'accordion',
spaceBefore: null,
children: [ children: [
{ {
id: 'stack_management', // This id can't be changed as we use it to open the panel programmatically id: 'stack_management', // This id can't be changed as we use it to open the panel programmatically

View file

@ -241,9 +241,14 @@ export default function searchSolutionNavigation({
it('renders only expected items', async () => { it('renders only expected items', async () => {
await solutionNavigation.sidenav.openSection('search_project_nav.otherTools'); await solutionNavigation.sidenav.openSection('search_project_nav.otherTools');
await solutionNavigation.sidenav.openSection('project_settings_project_nav');
await solutionNavigation.sidenav.expectSectionOpen('search_project_nav.otherTools'); await solutionNavigation.sidenav.expectSectionOpen('search_project_nav.otherTools');
await solutionNavigation.sidenav.expectSectionOpen('project_settings_project_nav');
await solutionNavigation.sidenav.openSection(
'search_project_nav_footer.project_settings_project_nav'
);
await solutionNavigation.sidenav.expectSectionOpen(
'search_project_nav_footer.project_settings_project_nav'
);
await solutionNavigation.sidenav.expectOnlyDefinedLinks([ await solutionNavigation.sidenav.expectOnlyDefinedLinks([
'search_project_nav', 'search_project_nav',
@ -265,6 +270,7 @@ export default function searchSolutionNavigation({
'otherTools', 'otherTools',
'maps', 'maps',
'graph', 'graph',
'search_project_nav_footer',
'project_settings_project_nav', 'project_settings_project_nav',
'management:trained_models', 'management:trained_models',
'stack_management', 'stack_management',

View file

@ -79,7 +79,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
} }
// navigate to a different section // navigate to a different section
await solutionNavigation.sidenav.openSection('project_settings_project_nav'); await solutionNavigation.sidenav.openSection(
'observability_project_nav_footer.project_settings_project_nav'
);
await solutionNavigation.sidenav.clickLink({ navId: 'stack_management' }); await solutionNavigation.sidenav.clickLink({ navId: 'stack_management' });
await solutionNavigation.sidenav.expectLinkActive({ navId: 'stack_management' }); await solutionNavigation.sidenav.expectLinkActive({ navId: 'stack_management' });
await solutionNavigation.sidenav.clickPanelLink('management:tags'); await solutionNavigation.sidenav.clickPanelLink('management:tags');

View file

@ -60,7 +60,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
}); });
// navigate to a different section // navigate to a different section
await solutionNavigation.sidenav.openSection('project_settings_project_nav'); await solutionNavigation.sidenav.openSection(
'search_project_nav_footer.project_settings_project_nav'
);
await solutionNavigation.sidenav.clickLink({ navId: 'stack_management' }); await solutionNavigation.sidenav.clickLink({ navId: 'stack_management' });
await solutionNavigation.sidenav.expectLinkActive({ navId: 'stack_management' }); await solutionNavigation.sidenav.expectLinkActive({ navId: 'stack_management' });
await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Data' }); await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Data' });

View file

@ -76,7 +76,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
}); });
// Supplied configurations is under Management -> Anomaly Detection Jobs -> Click button mlSuppliedConfigurationsButton // Supplied configurations is under Management -> Anomaly Detection Jobs -> Click button mlSuppliedConfigurationsButton
await solutionNavigation.sidenav.openSection('project_settings_project_nav'); await solutionNavigation.sidenav.openSection(
'observability_project_nav_footer.project_settings_project_nav'
);
await solutionNavigation.sidenav.clickLink({ navId: 'stack_management' }); await solutionNavigation.sidenav.clickLink({ navId: 'stack_management' });
await solutionNavigation.sidenav.expectLinkActive({ navId: 'stack_management' }); await solutionNavigation.sidenav.expectLinkActive({ navId: 'stack_management' });
await solutionNavigation.sidenav.clickPanelLink('management:anomaly_detection'); await solutionNavigation.sidenav.clickPanelLink('management:anomaly_detection');

View file

@ -16,7 +16,9 @@ export function MachineLearningNavigationProviderObservability({
const svlCommonNavigation = getPageObject('svlCommonNavigation'); const svlCommonNavigation = getPageObject('svlCommonNavigation');
async function navigateToArea(id: string, expectedTestSubject: string) { async function navigateToArea(id: string, expectedTestSubject: string) {
await svlCommonNavigation.sidenav.openSection('project_settings_project_nav'); await svlCommonNavigation.sidenav.openSection(
'observability_project_nav_footer.project_settings_project_nav'
);
await retry.tryForTime(5 * 1000, async () => { await retry.tryForTime(5 * 1000, async () => {
await svlCommonNavigation.sidenav.clickLink({ navId: 'management' }); await svlCommonNavigation.sidenav.clickLink({ navId: 'management' });
await svlCommonNavigation.sidenav.clickPanelLink(id); await svlCommonNavigation.sidenav.clickPanelLink(id);

View file

@ -16,7 +16,9 @@ export function MachineLearningNavigationProviderSecurity({
const retry = getService('retry'); const retry = getService('retry');
async function navigateToArea(id: string, expectedTestSubject: string) { async function navigateToArea(id: string, expectedTestSubject: string) {
await svlCommonNavigation.sidenav.openSection('category-management'); await svlCommonNavigation.sidenav.openSection(
'security_solution_nav_footer.category-management'
);
await retry.tryForTime(5 * 1000, async () => { await retry.tryForTime(5 * 1000, async () => {
await svlCommonNavigation.sidenav.clickLink({ navId: 'stack_management' }); await svlCommonNavigation.sidenav.clickLink({ navId: 'stack_management' });
await svlCommonNavigation.sidenav.clickPanelLink(id); await svlCommonNavigation.sidenav.clickPanelLink(id);

View file

@ -32,7 +32,9 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({
deepLinkId: 'observabilityOnboarding', deepLinkId: 'observabilityOnboarding',
}); });
await svlCommonNavigation.sidenav.expectSectionClosed('project_settings_project_nav'); await svlCommonNavigation.sidenav.expectSectionClosed(
'observability_project_nav_footer.project_settings_project_nav'
);
// navigate to the logs explorer tab by default // navigate to the logs explorer tab by default
await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'discover' }); await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'discover' });
@ -48,7 +50,9 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
await svlCommonNavigation.sidenav.clickLink({ navId: 'observabilityAIAssistant' }); // click on AI Assistant link await svlCommonNavigation.sidenav.clickLink({ navId: 'observabilityAIAssistant' }); // click on AI Assistant link
await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'AI Assistant' }); await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'AI Assistant' });
// navigate to a different section // navigate to a different section
await svlCommonNavigation.sidenav.openSection('project_settings_project_nav'); await svlCommonNavigation.sidenav.openSection(
'observability_project_nav_footer.project_settings_project_nav'
);
await svlCommonNavigation.sidenav.clickLink({ navId: 'management' }); await svlCommonNavigation.sidenav.clickLink({ navId: 'management' });
await svlCommonNavigation.sidenav.expectLinkActive({ navId: 'management' }); await svlCommonNavigation.sidenav.expectLinkActive({ navId: 'management' });
await svlCommonNavigation.sidenav.clickPanelLink('management:tags'); await svlCommonNavigation.sidenav.clickPanelLink('management:tags');
@ -59,18 +63,24 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({ await svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({
deepLinkId: 'observabilityOnboarding', deepLinkId: 'observabilityOnboarding',
}); });
await svlCommonNavigation.sidenav.expectSectionOpen(`project_settings_project_nav`); // remains open await svlCommonNavigation.sidenav.expectSectionOpen(
'observability_project_nav_footer.project_settings_project_nav'
); // remains open
await expectNoPageReload(); await expectNoPageReload();
}); });
it('active sidenav section is auto opened on load', async () => { it('active sidenav section is auto opened on load', async () => {
await svlCommonNavigation.sidenav.openSection('project_settings_project_nav'); await svlCommonNavigation.sidenav.openSection(
'observability_project_nav_footer.project_settings_project_nav'
);
await svlCommonNavigation.sidenav.clickLink({ navId: 'management' }); await svlCommonNavigation.sidenav.clickLink({ navId: 'management' });
await svlCommonNavigation.sidenav.clickPanelLink('management:tags'); await svlCommonNavigation.sidenav.clickPanelLink('management:tags');
await browser.refresh(); await browser.refresh();
await svlCommonNavigation.expectExists(); await svlCommonNavigation.expectExists();
await svlCommonNavigation.sidenav.expectSectionOpen('project_settings_project_nav'); await svlCommonNavigation.sidenav.expectSectionOpen(
'observability_project_nav_footer.project_settings_project_nav'
);
}); });
it('shows cases in sidebar navigation', async () => { it('shows cases in sidebar navigation', async () => {
@ -120,7 +130,9 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
}); });
it('navigates to integrations', async () => { it('navigates to integrations', async () => {
await svlCommonNavigation.sidenav.openSection('project_settings_project_nav'); await svlCommonNavigation.sidenav.openSection(
'observability_project_nav_footer.project_settings_project_nav'
);
await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'integrations' }); await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'integrations' });
await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts([ await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts([
'Integrations', 'Integrations',
@ -129,13 +141,17 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
}); });
it('navigates to fleet', async () => { it('navigates to fleet', async () => {
await svlCommonNavigation.sidenav.openSection('project_settings_project_nav'); await svlCommonNavigation.sidenav.openSection(
'observability_project_nav_footer.project_settings_project_nav'
);
await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'fleet' }); await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'fleet' });
await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Fleet', 'Agents']); await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Fleet', 'Agents']);
}); });
it('navigates to maintenance windows', async () => { it('navigates to maintenance windows', async () => {
await svlCommonNavigation.sidenav.openSection('project_settings_project_nav'); await svlCommonNavigation.sidenav.openSection(
'observability_project_nav_footer.project_settings_project_nav'
);
await svlCommonNavigation.sidenav.clickLink({ navId: 'management' }); await svlCommonNavigation.sidenav.clickLink({ navId: 'management' });
await svlCommonNavigation.sidenav.clickPanelLink('management:maintenanceWindows'); await svlCommonNavigation.sidenav.clickPanelLink('management:maintenanceWindows');
await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts([ await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts([

View file

@ -29,7 +29,9 @@ export default function ({ getService, getPageObjects, getPageObject }: FtrProvi
describe('page navigation', () => { describe('page navigation', () => {
it('renders trained models list', async () => { it('renders trained models list', async () => {
await svlCommonNavigation.sidenav.openSection('project_settings_project_nav'); await svlCommonNavigation.sidenav.openSection(
'search_project_nav_footer.project_settings_project_nav'
);
await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management:trained_models' }); await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management:trained_models' });
await svlCommonNavigation.sidenav.expectLinkActive({ await svlCommonNavigation.sidenav.expectLinkActive({
deepLinkId: 'management:trained_models', deepLinkId: 'management:trained_models',

View file

@ -127,7 +127,9 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
} }
// Open Project Settings // Open Project Settings
await solutionNavigation.sidenav.openSection('project_settings_project_nav'); await solutionNavigation.sidenav.openSection(
'search_project_nav_footer.project_settings_project_nav'
);
// check Project Settings // check Project Settings
// > Trained Models // > Trained Models
await solutionNavigation.sidenav.clickLink({ await solutionNavigation.sidenav.clickLink({
@ -172,7 +174,9 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
}); });
it('navigate management', async () => { it('navigate management', async () => {
await svlCommonNavigation.sidenav.openSection('project_settings_project_nav'); await svlCommonNavigation.sidenav.openSection(
'search_project_nav_footer.project_settings_project_nav'
);
await svlCommonNavigation.sidenav.clickLink({ navId: 'management' }); await svlCommonNavigation.sidenav.clickLink({ navId: 'management' });
await svlCommonNavigation.sidenav.clickPanelLink('management:tags'); await svlCommonNavigation.sidenav.clickPanelLink('management:tags');
await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Management', 'Tags']); await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Management', 'Tags']);
@ -206,7 +210,9 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
}); });
it('renders expected side navigation items', async () => { it('renders expected side navigation items', async () => {
await solutionNavigation.sidenav.openSection('project_settings_project_nav'); await solutionNavigation.sidenav.openSection(
'search_project_nav_footer.project_settings_project_nav'
);
// Verify all expected top-level links exist // Verify all expected top-level links exist
await solutionNavigation.sidenav.expectLinkExists({ text: 'Data' }); await solutionNavigation.sidenav.expectLinkExists({ text: 'Data' });
await solutionNavigation.sidenav.expectLinkExists({ text: 'Index Management' }); await solutionNavigation.sidenav.expectLinkExists({ text: 'Index Management' });
@ -230,7 +236,9 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
await solutionNavigation.sidenav.expectLinkExists({ text: 'Performance' }); await solutionNavigation.sidenav.expectLinkExists({ text: 'Performance' });
await solutionNavigation.sidenav.expectLinkExists({ text: 'Billing and subscription' }); await solutionNavigation.sidenav.expectLinkExists({ text: 'Billing and subscription' });
await solutionNavigation.sidenav.openSection('project_settings_project_nav'); await solutionNavigation.sidenav.openSection(
'search_project_nav_footer.project_settings_project_nav'
);
await solutionNavigation.sidenav.expectOnlyDefinedLinks([ await solutionNavigation.sidenav.expectOnlyDefinedLinks([
'search_project_nav', 'search_project_nav',
'data', 'data',
@ -249,6 +257,7 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
'otherTools', 'otherTools',
'maps', 'maps',
'gettingStarted', 'gettingStarted',
'search_project_nav_footer',
'project_settings_project_nav', 'project_settings_project_nav',
'management:trained_models', 'management:trained_models',
'management', 'management',

View file

@ -19,7 +19,9 @@ export default function ({ getPageObjects }: FtrProviderContext) {
describe('ingest pipelines', function () { describe('ingest pipelines', function () {
before(async () => { before(async () => {
await pageObjects.svlCommonPage.loginWithRole('developer'); await pageObjects.svlCommonPage.loginWithRole('developer');
await pageObjects.svlCommonNavigation.sidenav.openSection('project_settings_project_nav'); await pageObjects.svlCommonNavigation.sidenav.openSection(
'search_project_nav_footer.project_settings_project_nav'
);
await pageObjects.svlCommonNavigation.sidenav.clickLink({ navId: 'management' }); await pageObjects.svlCommonNavigation.sidenav.clickLink({ navId: 'management' });
await pageObjects.svlCommonNavigation.sidenav.clickPanelLink('management:ingest_pipelines'); await pageObjects.svlCommonNavigation.sidenav.clickPanelLink('management:ingest_pipelines');
}); });

View file

@ -43,7 +43,9 @@ export default ({ getPageObject, getService }: FtrProviderContext) => {
const navigateToConnectors = async () => { const navigateToConnectors = async () => {
await svlSearchNavigation.navigateToLandingPage(); await svlSearchNavigation.navigateToLandingPage();
await svlCommonNavigation.sidenav.openSection('project_settings_project_nav'); await svlCommonNavigation.sidenav.openSection(
'search_project_nav_footer.project_settings_project_nav'
);
await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management' }); await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'management' });
await testSubjects.click('app-card-triggersActionsConnectors'); await testSubjects.click('app-card-triggersActionsConnectors');
}; };

View file

@ -78,7 +78,9 @@ export default function ({ getPageObject, getService }: FtrProviderContext) {
it('navigates to maintenance windows', async () => { it('navigates to maintenance windows', async () => {
await svlCommonPage.loginAsAdmin(); await svlCommonPage.loginAsAdmin();
await svlSecNavigation.navigateToLandingPage(); await svlSecNavigation.navigateToLandingPage();
await svlCommonNavigation.sidenav.openSection('category-management'); await svlCommonNavigation.sidenav.openSection(
'security_solution_nav_footer.category-management'
);
await svlCommonNavigation.sidenav.clickLink({ navId: 'stack_management' }); await svlCommonNavigation.sidenav.clickLink({ navId: 'stack_management' });
await svlCommonNavigation.sidenav.clickPanelLink('management:maintenanceWindows'); await svlCommonNavigation.sidenav.clickPanelLink('management:maintenanceWindows');
await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts([ await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts([