Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
f72ea1c
Add TopNavMenuBeta to navigation plugin
kowalczyk-krzysztof Nov 19, 2025
3964578
Merge branch 'main' into feat/app-menu-init
kowalczyk-krzysztof Nov 20, 2025
c4e3f4f
Add lazy loading
kowalczyk-krzysztof Nov 20, 2025
1ecaafd
Merge branch 'main' into feat/app-menu-init
kowalczyk-krzysztof Nov 24, 2025
e152af1
Design changes
kowalczyk-krzysztof Nov 24, 2025
bf6a779
Add show more button base
kowalczyk-krzysztof Nov 25, 2025
aacea26
Add top_nav_popover
kowalczyk-krzysztof Nov 26, 2025
c30d977
Merge branch 'main' into feat/app-menu-init
kowalczyk-krzysztof Nov 27, 2025
d79955f
Add SplitButtonWithNotification
kowalczyk-krzysztof Nov 27, 2025
457c49a
Merge branch 'main' into feat/app-menu-init
kowalczyk-krzysztof Dec 2, 2025
43fe701
Merge branch 'main' into feat/app-menu-init
kowalczyk-krzysztof Dec 2, 2025
530d7c8
Add minWidth
kowalczyk-krzysztof Dec 2, 2025
6d4565c
Storybook temp solution
kowalczyk-krzysztof Dec 3, 2025
98e5d86
Merge branch 'main' into feat/app-menu-init
kowalczyk-krzysztof Dec 3, 2025
8554ef3
Add hidden funcionality
kowalczyk-krzysztof Dec 3, 2025
151ee55
Add popoverWidth
kowalczyk-krzysztof Dec 3, 2025
8017e7c
Add separator funcionality
kowalczyk-krzysztof Dec 3, 2025
589ab29
Type fixes
kowalczyk-krzysztof Dec 3, 2025
e8db532
Add responsivness
kowalczyk-krzysztof Dec 3, 2025
3713c75
Merge branch 'main' into feat/app-menu-init
kowalczyk-krzysztof Dec 4, 2025
b5feab3
Change dot props
kowalczyk-krzysztof Dec 4, 2025
fb76de3
Make action items in mobile menu open popovers
kowalczyk-krzysztof Dec 4, 2025
500c8d1
Add discover tabs to story
kowalczyk-krzysztof Dec 4, 2025
5036ced
Fix Storybook bg color
kowalczyk-krzysztof Dec 4, 2025
9fc3ee2
Fix unified tabs pushing out topnavmenu
kowalczyk-krzysztof Dec 4, 2025
5b50155
Merge branch 'main' into feat/app-menu-init
kowalczyk-krzysztof Dec 5, 2025
120d724
Code cleanup
kowalczyk-krzysztof Dec 5, 2025
55c2cb8
Code cleanup
kowalczyk-krzysztof Dec 5, 2025
5ba6c7d
Code cleanup
kowalczyk-krzysztof Dec 5, 2025
8fb78a2
Add tests
kowalczyk-krzysztof Dec 7, 2025
69a5538
Chores
kowalczyk-krzysztof Dec 7, 2025
bb9ab5a
Changes from node scripts/regenerate_moon_projects.js --update
kibanamachine Dec 7, 2025
347c6b9
Fix types
kowalczyk-krzysztof Dec 7, 2025
730f576
Merge remote-tracking branch 'refs/remotes/origin/feat/app-menu-init'…
kowalczyk-krzysztof Dec 7, 2025
5aaca24
Bundle sive improvements
kowalczyk-krzysztof Dec 7, 2025
051d980
Chores
kowalczyk-krzysztof Dec 8, 2025
8adfd6f
Merge branch 'main' into feat/app-menu-init
kowalczyk-krzysztof Dec 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ pageLoadAssetSize:
ml: 89000
mockIdpPlugin: 7544
monitoring: 28983
navigation: 14703
navigation: 18999
newsfeed: 12371
noDataPage: 1749
observability: 107797
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module.exports = {
'../../../../shared/shared-ux/**/guide.mdx',
'../../../../../../core/packages/chrome/**/*.stories.+(tsx|mdx)',
'../../../../shared/kbn-developer-toolbar/**/*.stories.+(tsx|mdx)',
'../../../../../plugins/shared/navigation/**/*.stories.+(tsx|mdx)',
],
typescript: {
reactDocgen: 'react-docgen-typescript',
Expand Down
1 change: 1 addition & 0 deletions src/platform/plugins/shared/navigation/moon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ dependsOn:
- '@kbn/core-chrome-navigation-tour'
- '@kbn/split-button'
- '@kbn/tour-queue'
- '@kbn/unified-tabs'
tags:
- plugin
- prod
Expand Down
1 change: 1 addition & 0 deletions src/platform/plugins/shared/navigation/public/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface NavigationPublicStart {
ui: {
TopNavMenu: (props: TopNavMenuProps<Query>) => React.ReactElement;
AggregateQueryTopNavMenu: (props: TopNavMenuProps<AggregateQuery>) => React.ReactElement;
TopNavMenuBeta: ({ config, visible}: { config: TopNavMenuConfigBeta, visible: boolean }) => React.ReactElement;
createTopNavWithCustomContext: (
customUnifiedSearch?: UnifiedSearchPublicPluginStart,
customExtensions?: RegisteredTopNavMenuData[]
Expand Down
3 changes: 2 additions & 1 deletion src/platform/plugins/shared/navigation/public/mocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import React from 'react';
import { of } from 'rxjs';
import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
import type { Plugin } from '.';
import { createTopNav } from './top_nav_menu';
import { createTopNav, createTopNavBeta } from './top_nav_menu';

export type Setup = jest.Mocked<ReturnType<Plugin['setup']>>;
export type Start = jest.Mocked<ReturnType<Plugin['start']>>;
Expand Down Expand Up @@ -44,6 +44,7 @@ const createStartContract = (): jest.Mocked<Start> => {
ui: {
TopNavMenu: jest.fn().mockImplementation(createTopNav(unifiedSearchMock, [])),
AggregateQueryTopNavMenu: jest.fn().mockImplementation(createTopNav(unifiedSearchMock, [])),
TopNavMenuBeta: jest.fn().mockImplementation(createTopNavBeta()),
createTopNavWithCustomContext: jest
.fn()
.mockImplementation(createTopNav(unifiedSearchMock, [])),
Expand Down
3 changes: 2 additions & 1 deletion src/platform/plugins/shared/navigation/public/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import type {
NavigationPublicStartDependencies,
AddSolutionNavigationArg,
} from './types';
import { TopNavMenuExtensionsRegistry, createTopNav } from './top_nav_menu';
import { TopNavMenuExtensionsRegistry, createTopNav, createTopNavBeta } from './top_nav_menu';
import type { RegisteredTopNavMenuData } from './top_nav_menu/top_nav_menu_data';

import { SolutionNavigationTourManager } from './solution_tour/solution_tour';
Expand Down Expand Up @@ -143,6 +143,7 @@ export class NavigationPublicPlugin
ui: {
TopNavMenu: createTopNav(unifiedSearch, extensions),
AggregateQueryTopNavMenu: createTopNav(unifiedSearch, extensions),
TopNavMenuBeta: createTopNavBeta(),
createTopNavWithCustomContext: createCustomTopNav,
},
addSolutionNavigation: (solutionNavigation) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,49 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import React from 'react';
import React, { Suspense, lazy } from 'react';
import { I18nProvider } from '@kbn/i18n-react';
import type { AggregateQuery, Query } from '@kbn/es-query';
import type { UnifiedSearchPublicPluginStart } from '@kbn/unified-search-plugin/public';
import type { TopNavMenuConfigBeta } from '../top_nav_menu_beta';
import type { TopNavMenuProps } from './top_nav_menu';
import { TopNavMenu } from './top_nav_menu';
import type { RegisteredTopNavMenuData } from './top_nav_menu_data';

const LazyTopNavMenu = lazy(async () => {
const { TopNavMenu } = await import('./top_nav_menu');
return { default: TopNavMenu };
});

const LazyTopNavMenuBeta = lazy(async () => {
const { TopNavMenuBeta } = await import('../top_nav_menu_beta/top_nav_menu_beta');
return { default: TopNavMenuBeta };
});

export function createTopNavBeta() {
return ({ config, visible }: { config: TopNavMenuConfigBeta; visible?: boolean }) => {
return (
<I18nProvider>
<Suspense>
<LazyTopNavMenuBeta visible={visible} config={config} />
</Suspense>
</I18nProvider>
);
};
}

/**
* @deprecated
*/
export function createTopNav(
/**
* @deprecated TopNavMenuBeta will decouple from UnifiedSearch, so this parameter
* will be removed once TopNavMenuBeta becomes the default.
*/
unifiedSearch: UnifiedSearchPublicPluginStart,
/**
* @deprecated TopNavMenuBeta will not allow for reigstering global menu items, so this parameter
* will be removed once TopNavMenuBeta becomes the default.
*/
extraConfig: RegisteredTopNavMenuData[]
) {
return <QT extends AggregateQuery | Query = Query>(props: TopNavMenuProps<QT>) => {
Expand All @@ -27,7 +60,13 @@ export function createTopNav(

return (
<I18nProvider>
<TopNavMenu {...props} unifiedSearch={unifiedSearch} config={config} />
<Suspense>
<LazyTopNavMenu
{...(props as TopNavMenuProps<Query | AggregateQuery>)}
unifiedSearch={unifiedSearch}
config={config}
/>
</Suspense>
</I18nProvider>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

export { createTopNav } from './create_top_nav_menu';
export { createTopNav, createTopNavBeta } from './create_top_nav_menu';
export type { TopNavMenuProps } from './top_nav_menu';
export { TopNavMenu } from './top_nav_menu';
export type { TopNavMenuData } from './top_nav_menu_data';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ export type TopNavMenuProps<QT extends Query | AggregateQuery = Query> = Omit<
'kibana' | 'intl' | 'timeHistory'
> & {
config?: TopNavMenuData[];
/**
* @deprecated Badges will no longer be part of TopNavMenu in the future. Instead, they will be part of BreadcrumbsWithExtensions.
*/
badges?: TopNavMenuBadgeProps[];
showSearchBar?: boolean;
showQueryInput?: boolean;
Expand Down Expand Up @@ -70,6 +73,9 @@ export type TopNavMenuProps<QT extends Query | AggregateQuery = Query> = Omit<
*
**/

/**
* @deprecated
*/
export function TopNavMenu<QT extends AggregateQuery | Query = Query>(
props: TopNavMenuProps<QT>
): ReactElement | null {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ export type TopNavMenuBadgeProps = EuiBadgeProps & {
renderCustomBadge?: (props: { badgeText: string }) => ReactElement;
};

/**
* @deprecated Badges will be moved to use BreadcrumbsWithExtension API.
*/
export const TopNavMenuBadges = ({ badges }: { badges: TopNavMenuBadgeProps[] | undefined }) => {
const { euiTheme } = useEuiTheme();
if (!badges || badges.length === 0) return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

import type { RegisteredTopNavMenuData } from './top_nav_menu_data';

/**
* @deprecated This registry will be removed once TopNavMenuBeta becomes the default.
*/
export class TopNavMenuExtensionsRegistry {
private menuItems: RegisteredTopNavMenuData[];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ interface TopNavMenuItemsProps {
gutterSize?: EuiHeaderLinksProps['gutterSize'];
}

/**
* @deprecated Use `TopNavMenuBeta` instead.
*/
export const TopNavMenuItems = ({
config,
className,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# TopNavMenuBeta

`TopNavMenuBeta` is the replacement for the existing `TopNavMenu` component, providing an improved API and enhanced functionality for building top navigation menus in your application.

## Usage

- Using `core.navigation.ui` API:

```typescript
// In your plugin's start method
public start(core: CoreStart, plugins: PluginsStart) {
const { ui } = plugins.navigation;
// TODO: Define how to mount in header after upcoming extension point changes.
return {
renderTopNav: (props) => <ui.TopNavMenuBeta {...props} />
};
}
```

- Direct import:

```typescript
import { TopNavMenuBeta} from '@kbn/navigation-plugin/public'

const MyComponent = (props: TopNavMenuConfigBeta) => {

// TODO: Define how to mount in header after upcoming extension point changes.
return <TopNavMenuBeta {...props} />
}
```

## API changes

`TopNavMenuBeta` offers a more restricted API than `TopNavMenu`

1. Decoupling from `UnifiedSearch` - top nav menu will no longer be bundled with unified search. You will need to directly import unified search and render it.

2. Removal of badges - badges will no longer be available in top nav menu. According to UX guidelines, current badges should be moved to use breadcrumbs extension API.

3. `items` can only be `EuiHeaderLink` (a button with type `text`). For more advanced use cases, use action buttons.

4. Action buttons - `TopNavMenuBeta` introduces action buttons:

- `primaryActionButton` - this is meant to be used for primary actions (e.g saving), can be either an `EuiButton` or a split button, always placed as the rightmost item

- `secondaryActionButton` - this is meant for secondary actions (e.g adding a new panel), can only be an `EuiButton`, placed to the left from `primaryActionButton`

5. Removal of `TopNavMenuExtensionsRegistry` - registering global items is no longer possible, add items locally to your application.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

export const TOP_NAV_MENU_ITEM_LIMIT = 5;
export const TOP_NAV_MENU_NOTIFICATION_INDICATOR_TOP = 2;
export const TOP_NAV_MENU_NOTIFICATION_INDICATOR_LEFT = 25;
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

export { TopNavMenuBeta } from './top_nav_menu_beta';
export { TopNavMenuItem } from './top_nav_menu_item';
export { TopNavMenuActionButton } from './top_nav_menu_action_button';
export { TopNavMenuOverflowButton } from './top_nav_menu_overflow_button';
export { TopNavMenuPopover } from './top_nav_menu_popover';
export { TopNavMenuPopoverActionButtons } from './top_nav_menu_popover_action_buttons';

export type {
TopNavMenuConfigBeta,
TopNavMenuItemType,
TopNavMenuSecondaryActionItem,
TopNavMenuPrimaryActionItem,
TopNavMenuPopoverItem,
TopNavMenuSplitButtonProps,
} from './types';

export {
TOP_NAV_MENU_ITEM_LIMIT,
TOP_NAV_MENU_NOTIFICATION_INDICATOR_LEFT,
TOP_NAV_MENU_NOTIFICATION_INDICATOR_TOP,
} from './constants';

export {
getDisplayedItemsAllowedAmount,
getShouldOverflow,
isDisabled,
getTooltip,
mapTopNavItemToPanelItem,
getTopNavItems,
getPopoverPanels,
getPopoverActionItems,
getIsSelectedColor,
} from './utils';
Loading
Loading