diff --git a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx index 41362b3d80dcd..17fde5e54ab1b 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/chrome_service.tsx @@ -121,6 +121,7 @@ export class ChromeService { const helpSupportUrl$ = new BehaviorSubject(KIBANA_ASK_ELASTIC_LINK); const isNavDrawerLocked$ = new BehaviorSubject(localStorage.getItem(IS_LOCKED_KEY) === 'true'); const chromeStyle$ = new BehaviorSubject('classic'); + const projectNavigation$ = new BehaviorSubject(undefined); const getKbnVersionClass = () => { // we assume that the version is valid and has the form 'X.X.X' @@ -170,6 +171,10 @@ export class ChromeService { chromeStyle$.next(style); }; + const setProjectNavigation = (navigation: JSX.Element) => { + projectNavigation$.next(navigation); + }; + const isIE = () => { const ua = window.navigator.userAgent; const msie = ua.indexOf('MSIE '); // IE 10 or older @@ -211,7 +216,13 @@ export class ChromeService { } const getHeaderComponent = () => { - const Component = ({ style$ }: { style$: typeof chromeStyle$ }) => { + const Component = ({ + style$, + navigation$, + }: { + style$: typeof chromeStyle$; + navigation$: typeof projectNavigation$; + }) => { if (style$.getValue() === 'project') { return ( ); }; - return ; + return ; }; return { @@ -335,6 +347,7 @@ export class ChromeService { getBodyClasses$: () => bodyClasses$.pipe(takeUntil(this.stop$)), setChromeStyle, getChromeStyle$: () => chromeStyle$.pipe(takeUntil(this.stop$)), + setProjectNavigation, }; } diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx index e85ae262c3bb7..0bd633652e458 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/header.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { Router } from 'react-router-dom'; -import { EuiHeader, EuiHeaderLogo, EuiHeaderSection, EuiHeaderSectionItem } from '@elastic/eui'; +import { EuiHeader, EuiHeaderSection, EuiHeaderSectionItem } from '@elastic/eui'; import { ChromeBreadcrumb, ChromeGlobalHelpExtensionMenuLink, @@ -33,6 +33,7 @@ interface Props { helpSupportUrl$: Observable; kibanaVersion: string; application: InternalApplicationStart; + navigation: JSX.Element | null; navControlsRight$: Observable; } @@ -40,22 +41,13 @@ export const ProjectHeader = ({ application, kibanaDocLink, kibanaVersion, + navigation, ...observables }: Props) => { - const renderLogo = () => ( - e.preventDefault()} - aria-label="Go to home page" - /> - ); - return ( <> - {renderLogo()} @@ -81,9 +73,7 @@ export const ProjectHeader = ({ - - - + {navigation} ); diff --git a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/navigation.tsx b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/navigation.tsx index 20549325ec851..445a80cca586d 100644 --- a/packages/core/chrome/core-chrome-browser-internal/src/ui/project/navigation.tsx +++ b/packages/core/chrome/core-chrome-browser-internal/src/ui/project/navigation.tsx @@ -11,7 +11,7 @@ import useLocalStorage from 'react-use/lib/useLocalStorage'; import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; -import { EuiButtonIcon, EuiCollapsibleNav, EuiThemeProvider, useEuiTheme } from '@elastic/eui'; +import { EuiButtonIcon, EuiCollapsibleNav } from '@elastic/eui'; const LOCAL_STORAGE_IS_OPEN_KEY = 'PROJECT_NAVIGATION_OPEN' as const; const SIZE_OPEN = 248; @@ -33,8 +33,6 @@ const closedAriaLabel = i18n.translate('core.ui.chrome.projectNav.collapsibleNav }); export const ProjectNavigation: React.FC = ({ children }) => { - const { euiTheme, colorMode } = useEuiTheme(); - const [isOpen, setIsOpen] = useLocalStorage(LOCAL_STORAGE_IS_OPEN_KEY, true); const toggleOpen = useCallback(() => { @@ -43,34 +41,31 @@ export const ProjectNavigation: React.FC = ({ children }) => { const collabsibleNavCSS = css` border-inline-end-width: 1, - background: ${euiTheme.colors.darkestShade}, display: flex, flex-direction: row, `; return ( - - - - - } - > - {isOpen && children} - - + + + + } + > + {isOpen && children} + ); }; diff --git a/packages/core/chrome/core-chrome-browser-mocks/src/chrome_service.mock.ts b/packages/core/chrome/core-chrome-browser-mocks/src/chrome_service.mock.ts index c7c62c7811277..1a8042fb4e120 100644 --- a/packages/core/chrome/core-chrome-browser-mocks/src/chrome_service.mock.ts +++ b/packages/core/chrome/core-chrome-browser-mocks/src/chrome_service.mock.ts @@ -63,6 +63,7 @@ const createStartContractMock = () => { getBodyClasses$: jest.fn(), getChromeStyle$: jest.fn(), setChromeStyle: jest.fn(), + setProjectNavigation: jest.fn(), }; startContract.navLinks.getAll.mockReturnValue([]); startContract.getIsVisible$.mockReturnValue(new BehaviorSubject(false)); diff --git a/packages/core/chrome/core-chrome-browser/src/contracts.ts b/packages/core/chrome/core-chrome-browser/src/contracts.ts index 3f6f756e2d2b1..567fabad32156 100644 --- a/packages/core/chrome/core-chrome-browser/src/contracts.ts +++ b/packages/core/chrome/core-chrome-browser/src/contracts.ts @@ -161,4 +161,12 @@ export interface ChromeStart { * Get an observable of the current style type of the chrome. */ getChromeStyle$(): Observable; + + /** + * Sets the project navigation to render in the chrome. + * @param projectNavigation The navigation to render in the chrome. + * + * @remarks Has no effect if the chrome style is not `project`. + */ + setProjectNavigation(projectNavigation: JSX.Element): void; } diff --git a/packages/shared-ux/chrome/navigation/mocks/src/jest.ts b/packages/shared-ux/chrome/navigation/mocks/src/jest.ts index 166dc73b6290c..f3be43958509a 100644 --- a/packages/shared-ux/chrome/navigation/mocks/src/jest.ts +++ b/packages/shared-ux/chrome/navigation/mocks/src/jest.ts @@ -6,18 +6,21 @@ * Side Public License, v 1. */ +import { BehaviorSubject } from 'rxjs'; import { NavigationServices, SolutionProperties } from '../../types'; export const getServicesMock = (): NavigationServices => { const navigateToUrl = jest.fn().mockResolvedValue(undefined); const basePath = { prepend: jest.fn((path: string) => `/base${path}`) }; - const loadingCount = 0; + const loadingCount$ = new BehaviorSubject(0); + const recentlyAccessed$ = new BehaviorSubject([]); return { basePath, - loadingCount, navIsOpen: true, navigateToUrl, + loadingCount$, + recentlyAccessed$, }; }; diff --git a/packages/shared-ux/chrome/navigation/mocks/src/storybook.ts b/packages/shared-ux/chrome/navigation/mocks/src/storybook.ts index 27e27393dc5bb..16ae574fc0787 100644 --- a/packages/shared-ux/chrome/navigation/mocks/src/storybook.ts +++ b/packages/shared-ux/chrome/navigation/mocks/src/storybook.ts @@ -13,7 +13,12 @@ import { NavigationProps, NavigationServices } from '../../types'; type Arguments = NavigationProps & NavigationServices; export type Params = Pick< Arguments, - 'activeNavItemId' | 'loadingCount' | 'navIsOpen' | 'platformConfig' | 'solutions' + | 'activeNavItemId' + | 'loadingCount$' + | 'recentlyAccessed$' + | 'navIsOpen' + | 'platformConfig' + | 'solutions' >; export class StorybookMock extends AbstractStorybookMock { diff --git a/packages/shared-ux/chrome/navigation/src/ui/i18n_strings.ts b/packages/shared-ux/chrome/navigation/src/i18n_strings.ts similarity index 85% rename from packages/shared-ux/chrome/navigation/src/ui/i18n_strings.ts rename to packages/shared-ux/chrome/navigation/src/i18n_strings.ts index 9f6f3fbadca30..c268e7a42de10 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/i18n_strings.ts +++ b/packages/shared-ux/chrome/navigation/src/i18n_strings.ts @@ -27,4 +27,10 @@ export const getI18nStrings = () => ({ defaultMessage: 'My deployments', } ), + recentlyAccessed: i18n.translate( + 'sharedUXPackages.chrome.sideNavigation.recentlyAccessed.title', + { + defaultMessage: 'Recent', + } + ), }); diff --git a/packages/shared-ux/chrome/navigation/src/model/index.ts b/packages/shared-ux/chrome/navigation/src/model/index.ts index 8e8d94e995019..db3e5a29951ac 100644 --- a/packages/shared-ux/chrome/navigation/src/model/index.ts +++ b/packages/shared-ux/chrome/navigation/src/model/index.ts @@ -21,7 +21,6 @@ export interface NavigationModelDeps { * @public */ export enum Platform { - Recents = 'recents', Analytics = 'analytics', MachineLearning = 'ml', DevTools = 'devTools', diff --git a/packages/shared-ux/chrome/navigation/src/services.tsx b/packages/shared-ux/chrome/navigation/src/services.tsx index 8235963c18681..6b880a7c2729b 100644 --- a/packages/shared-ux/chrome/navigation/src/services.tsx +++ b/packages/shared-ux/chrome/navigation/src/services.tsx @@ -7,7 +7,6 @@ */ import React, { FC, useContext } from 'react'; -import useObservable from 'react-use/lib/useObservable'; import { NavigationKibanaDependencies, NavigationServices } from '../types'; const Context = React.createContext(null); @@ -27,17 +26,16 @@ export const NavigationKibanaProvider: FC = ({ ...dependencies }) => { const { core } = dependencies; - const { http } = core; + const { chrome, http } = core; const { basePath } = http; const { navigateToUrl } = core.application; - const loadingCount = useObservable(http.getLoadingCount$(), 0); - const value: NavigationServices = { basePath, - loadingCount, navigateToUrl, navIsOpen: true, + loadingCount$: http.getLoadingCount$(), + recentlyAccessed$: chrome.recentlyAccessed.get$(), }; return ( diff --git a/packages/shared-ux/chrome/navigation/src/ui/elastic_mark.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/elastic_mark.tsx similarity index 100% rename from packages/shared-ux/chrome/navigation/src/ui/elastic_mark.tsx rename to packages/shared-ux/chrome/navigation/src/ui/components/elastic_mark.tsx diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/header.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/header.tsx new file mode 100644 index 0000000000000..b9153a04b87e3 --- /dev/null +++ b/packages/shared-ux/chrome/navigation/src/ui/components/header.tsx @@ -0,0 +1,58 @@ +/* + * 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 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 or the Server + * Side Public License, v 1. + */ + +import { EuiHeaderLogo, EuiLoadingSpinner } from '@elastic/eui'; +import React from 'react'; +import useObservable from 'react-use/lib/useObservable'; +import { NavigationProps, NavigationServices } from '../../../types'; +import { getI18nStrings } from '../../i18n_strings'; +import { ElasticMark } from './elastic_mark'; +import './header_logo.scss'; + +type Props = Pick; +type Services = Pick< + NavigationServices, + 'basePath' | 'navIsOpen' | 'navigateToUrl' | 'loadingCount$' +>; + +export const NavHeader = (props: Props & Services) => { + const strings = getI18nStrings(); + const { basePath, navIsOpen, navigateToUrl, loadingCount$, homeHref } = props; + + const loadingCount = useObservable(loadingCount$, 0); + const homeUrl = basePath.prepend(homeHref); + const navigateHome = (event: React.MouseEvent) => { + event.preventDefault(); + navigateToUrl(homeUrl); + }; + const logo = + loadingCount === 0 ? ( + + ) : ( + + + + ); + + return ( + <> + {logo} + {navIsOpen ? : null} + + ); +}; diff --git a/packages/shared-ux/chrome/navigation/src/ui/header_logo.scss b/packages/shared-ux/chrome/navigation/src/ui/components/header_logo.scss similarity index 100% rename from packages/shared-ux/chrome/navigation/src/ui/header_logo.scss rename to packages/shared-ux/chrome/navigation/src/ui/components/header_logo.scss diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/index.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/index.tsx new file mode 100644 index 0000000000000..2782906ee8266 --- /dev/null +++ b/packages/shared-ux/chrome/navigation/src/ui/components/index.tsx @@ -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 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 or the Server + * Side Public License, v 1. + */ + +export { NavHeader } from './header'; +export { LinkToCloud } from './link_to_cloud'; +export { NavigationBucket } from './navigation_bucket'; +export { RecentlyAccessed } from './recently_accessed'; diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/link_to_cloud.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/link_to_cloud.tsx new file mode 100644 index 0000000000000..ef9f1ba01ee16 --- /dev/null +++ b/packages/shared-ux/chrome/navigation/src/ui/components/link_to_cloud.tsx @@ -0,0 +1,45 @@ +/* + * 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 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 or the Server + * Side Public License, v 1. + */ + +import { EuiCollapsibleNavGroup, EuiLink } from '@elastic/eui'; +import React from 'react'; +import { NavigationProps } from '../../../types'; +import { getI18nStrings } from '../../i18n_strings'; + +interface Props { + linkToCloud?: NavigationProps['homeHref']; +} + +export const LinkToCloud = (props: Props) => { + const strings = getI18nStrings(); + + switch (props.linkToCloud) { + case 'projects': + return ( + + + + ); + case 'deployments': + return ( + + + + ); + default: + return null; + } +}; diff --git a/packages/shared-ux/chrome/navigation/src/ui/navigation_bucket.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_bucket.tsx similarity index 87% rename from packages/shared-ux/chrome/navigation/src/ui/navigation_bucket.tsx rename to packages/shared-ux/chrome/navigation/src/ui/components/navigation_bucket.tsx index 0b0d6b5b223ab..48ee855901497 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/navigation_bucket.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/components/navigation_bucket.tsx @@ -8,9 +8,9 @@ import { EuiCollapsibleNavGroup, EuiIcon, EuiSideNav, EuiText } from '@elastic/eui'; import React from 'react'; -import { NavigationBucketProps } from '../../types'; -import { useNavigation } from '../services'; -import { navigationStyles as styles } from '../styles'; +import { NavigationBucketProps } from '../../../types'; +import { useNavigation } from '../../services'; +import { navigationStyles as styles } from '../../styles'; export const NavigationBucket = (opts: NavigationBucketProps) => { const { id, items, activeNavItemId, ...props } = opts; diff --git a/packages/shared-ux/chrome/navigation/src/ui/components/recently_accessed.tsx b/packages/shared-ux/chrome/navigation/src/ui/components/recently_accessed.tsx new file mode 100644 index 0000000000000..1af9d2bd3a846 --- /dev/null +++ b/packages/shared-ux/chrome/navigation/src/ui/components/recently_accessed.tsx @@ -0,0 +1,56 @@ +/* + * 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 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 or the Server + * Side Public License, v 1. + */ + +import { EuiCollapsibleNavGroup, EuiSideNav, EuiSideNavItemType } from '@elastic/eui'; +import React from 'react'; +import useObservable from 'react-use/lib/useObservable'; +import { NavigationProps, NavigationServices } from '../../../types'; +import { getI18nStrings } from '../../i18n_strings'; +import { navigationStyles as styles } from '../../styles'; + +type Props = Pick; +type Services = Pick; + +export const RecentlyAccessed = (props: Props & Services) => { + const strings = getI18nStrings(); + const recentlyAccessed = useObservable(props.recentlyAccessed$, []); + + // consumer may filter objects from recent that are not applicable to the project + let filteredRecent = recentlyAccessed; + if (props.recentlyAccessedFilter) { + filteredRecent = props.recentlyAccessedFilter(recentlyAccessed); + } + + if (filteredRecent.length > 0) { + const navItems: Array> = [ + { + name: '', // no list header title + id: 'recents_root', + items: recentlyAccessed.map(({ id, label, link }) => ({ + id, + name: label, + href: link, + })), + }, + ]; + + return ( + + + + ); + } + + return null; +}; diff --git a/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx b/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx index 20c0c2201acfb..4c4886c5f269d 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/navigation.stories.tsx @@ -13,9 +13,10 @@ import { EuiPopover, EuiThemeProvider, } from '@elastic/eui'; +import { css } from '@emotion/react'; import { ComponentMeta, ComponentStory } from '@storybook/react'; import React, { useCallback, useState } from 'react'; -import { css } from '@emotion/react'; +import { BehaviorSubject } from 'rxjs'; import { getSolutionPropertiesMock, NavigationStorybookMock } from '../../mocks'; import mdx from '../../README.mdx'; import { NavigationProps, NavigationServices } from '../../types'; @@ -132,7 +133,7 @@ ReducedPlatformLinks.argTypes = storybookMock.getArgumentTypes(); export const WithRequestsLoading: ComponentStory = Template.bind({}); WithRequestsLoading.args = { activeNavItemId: 'example_project.root.get_started', - loadingCount: 1, + loadingCount$: new BehaviorSubject(1), solutions: [getSolutionPropertiesMock()], }; WithRequestsLoading.argTypes = storybookMock.getArgumentTypes(); diff --git a/packages/shared-ux/chrome/navigation/src/ui/navigation.test.tsx b/packages/shared-ux/chrome/navigation/src/ui/navigation.test.tsx index 075925f05de6a..a85b8eb81b10b 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/navigation.test.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/navigation.test.tsx @@ -8,6 +8,7 @@ import { render } from '@testing-library/react'; import React from 'react'; +import { BehaviorSubject } from 'rxjs'; import { getServicesMock } from '../../mocks/src/jest'; import { PlatformConfigSet, SolutionProperties } from '../../types'; import { Platform } from '../model'; @@ -114,7 +115,7 @@ describe('', () => { }); test('shows loading state', async () => { - services.loadingCount = 5; + services.loadingCount$ = new BehaviorSubject(5); const { findByTestId } = render( diff --git a/packages/shared-ux/chrome/navigation/src/ui/navigation.tsx b/packages/shared-ux/chrome/navigation/src/ui/navigation.tsx index 60f3af10a6b54..4c8d4bf20f796 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/navigation.tsx +++ b/packages/shared-ux/chrome/navigation/src/ui/navigation.tsx @@ -10,96 +10,31 @@ import { EuiCollapsibleNavGroup, EuiFlexGroup, EuiFlexItem, - EuiHeaderLogo, - EuiLink, - EuiLoadingSpinner, EuiSpacer, useEuiTheme, } from '@elastic/eui'; import React from 'react'; -import { getI18nStrings } from './i18n_strings'; import { NavigationBucketProps, NavigationProps } from '../../types'; import { NavigationModel } from '../model'; import { useNavigation } from '../services'; -import { ElasticMark } from './elastic_mark'; -import './header_logo.scss'; -import { NavigationBucket } from './navigation_bucket'; +import { LinkToCloud, NavHeader, NavigationBucket, RecentlyAccessed } from './components'; export const Navigation = (props: NavigationProps) => { - const { loadingCount, activeNavItemId, ...services } = useNavigation(); + const { activeNavItemId, basePath, navIsOpen, navigateToUrl, ...observables } = useNavigation(); const { euiTheme } = useEuiTheme(); const activeNav = activeNavItemId ?? props.activeNavItemId; - const nav = new NavigationModel(services, props.platformConfig, props.solutions, activeNav); + const nav = new NavigationModel( + { basePath, navigateToUrl }, + props.platformConfig, + props.solutions, + activeNav + ); const solutions = nav.getSolutions(); const { analytics, ml, devTools, management } = nav.getPlatform(); - const strings = getI18nStrings(); - - const NavHeader = () => { - const homeUrl = services.basePath.prepend(props.homeHref); - const navigateHome = (event: React.MouseEvent) => { - event.preventDefault(); - services.navigateToUrl(homeUrl); - }; - const logo = - loadingCount === 0 ? ( - - ) : ( - - - - ); - - return ( - <> - {logo} - {services.navIsOpen ? ( - - ) : null} - - ); - }; - - const LinkToCloud = () => { - switch (props.linkToCloud) { - case 'projects': - return ( - - - - ); - case 'deployments': - return ( - - - - ); - default: - return null; - } - }; - // higher-order-component to keep the common props DRY const NavigationBucketHoc = (outerProps: Omit) => ( @@ -109,10 +44,12 @@ export const Navigation = (props: NavigationProps) => { - + - + + + {solutions.map((solutionBucket, idx) => { return ; diff --git a/packages/shared-ux/chrome/navigation/types/index.ts b/packages/shared-ux/chrome/navigation/types/index.ts index bd7aaddcb67c6..2de081df42530 100644 --- a/packages/shared-ux/chrome/navigation/types/index.ts +++ b/packages/shared-ux/chrome/navigation/types/index.ts @@ -17,7 +17,8 @@ import { BasePathService, NavigateToUrlFn, RecentItem } from './internal'; export interface NavigationServices { activeNavItemId?: string; basePath: BasePathService; - loadingCount: number; + loadingCount$: Observable; + recentlyAccessed$: Observable; navIsOpen: boolean; navigateToUrl: NavigateToUrlFn; } @@ -124,6 +125,10 @@ export interface NavigationProps { * Control of the link that takes the user to their projects or deployments */ linkToCloud?: 'projects' | 'deployments'; + /** + * Filter function to allow consumer to remove items from the recently accessed section + */ + recentlyAccessedFilter?: (items: RecentItem[]) => RecentItem[]; } export type NavigationBucketProps = (SolutionProperties & diff --git a/x-pack/plugins/serverless/public/plugin.tsx b/x-pack/plugins/serverless/public/plugin.tsx index 9c9debe3e9f21..a09d4f14f5b88 100644 --- a/x-pack/plugins/serverless/public/plugin.tsx +++ b/x-pack/plugins/serverless/public/plugin.tsx @@ -41,7 +41,10 @@ export class ServerlessPlugin implements Plugin + core.chrome.setProjectNavigation(navigation), + }; } public stop() {} diff --git a/x-pack/plugins/serverless/public/types.ts b/x-pack/plugins/serverless/public/types.ts index 92a804b34a948..4af0b062ede0c 100644 --- a/x-pack/plugins/serverless/public/types.ts +++ b/x-pack/plugins/serverless/public/types.ts @@ -8,5 +8,6 @@ // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ServerlessPluginSetup {} -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface ServerlessPluginStart {} +export interface ServerlessPluginStart { + setServerlessNavigation: (navigation: JSX.Element) => void; +} diff --git a/x-pack/plugins/serverless_search/public/plugin.ts b/x-pack/plugins/serverless_search/public/plugin.ts deleted file mode 100644 index 62a83cff6f477..0000000000000 --- a/x-pack/plugins/serverless_search/public/plugin.ts +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; -import { - ServerlessSearchPluginSetup, - ServerlessSearchPluginSetupDependencies, - ServerlessSearchPluginStart, - ServerlessSearchPluginStartDependencies, -} from './types'; - -export class ServerlessSearchPlugin - implements Plugin -{ - public setup( - _core: CoreSetup, - _setupDeps: ServerlessSearchPluginSetupDependencies - ): ServerlessSearchPluginSetup { - return {}; - } - - public start( - _core: CoreStart, - _startDeps: ServerlessSearchPluginStartDependencies - ): ServerlessSearchPluginStart { - return {}; - } - - public stop() {} -} diff --git a/x-pack/plugins/serverless_search/public/plugin.tsx b/x-pack/plugins/serverless_search/public/plugin.tsx new file mode 100644 index 0000000000000..4c415d8412fa9 --- /dev/null +++ b/x-pack/plugins/serverless_search/public/plugin.tsx @@ -0,0 +1,99 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; +import { + Navigation, + NavigationKibanaProvider, + NavigationProps, + NavItemProps, +} from '@kbn/shared-ux-chrome-navigation'; +import React from 'react'; +import { + ServerlessSearchPluginSetup, + ServerlessSearchPluginSetupDependencies, + ServerlessSearchPluginStart, + ServerlessSearchPluginStartDependencies, +} from './types'; + +const navItems: NavItemProps[] = [ + { + name: '', + id: 'root', + items: [ + { + id: 'overview', + name: 'Overview', + href: '/app/enterprise_search/overview', + }, + { + id: 'indices', + name: 'Indices', + href: '/app/enterprise_search/content/search_indices', + }, + { + id: 'engines', + name: 'Engines', + href: '/app/enterprise_search/content/engines', + }, + { + id: 'api_keys', + name: 'API keys', + href: '/app/management/security/api_keys', + }, + { + id: 'ingest_pipelines', + name: 'Ingest pipelines', + href: '/app/management/ingest/ingest_pipelines', + }, + ], + }, +]; + +export class ServerlessSearchPlugin + implements Plugin +{ + public setup( + _core: CoreSetup, + _setupDeps: ServerlessSearchPluginSetupDependencies + ): ServerlessSearchPluginSetup { + return {}; + } + + public start( + core: CoreStart, + { serverless }: ServerlessSearchPluginStartDependencies + ): ServerlessSearchPluginStart { + const recentlyAccessedFilter: NavigationProps['recentlyAccessedFilter'] = (items) => { + // Example: only allow recent dashboards + return items.filter(({ link }) => link.match('/app/dashboards')); + }; + + serverless.setServerlessNavigation( + + + + ); + return {}; + } + + public stop() {} +} diff --git a/x-pack/plugins/serverless_search/tsconfig.json b/x-pack/plugins/serverless_search/tsconfig.json index c8150e5a71926..23f99f3add4e4 100644 --- a/x-pack/plugins/serverless_search/tsconfig.json +++ b/x-pack/plugins/serverless_search/tsconfig.json @@ -20,5 +20,6 @@ "@kbn/enterprise-search-plugin", "@kbn/management-plugin", "@kbn/serverless", + "@kbn/shared-ux-chrome-navigation", ] }