mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Serverless navigation] Add documentation (#162318)
This PR adds the documentation for the serverless navigation. ### Note for reviewer The documentation is best viewed in rendered markdown: https://github.com/sebelga/kibana/blob/project-navigation-documentation/packages/shared-ux/chrome/serverless_projects_documentation.md --------- Co-authored-by: Anton Dosov <anton.dosov@elastic.co> Co-authored-by: Tim Sullivan <tim.sullivan@elastic.co>
This commit is contained in:
parent
7c16dd9817
commit
8c6de90954
4 changed files with 518 additions and 7 deletions
|
@ -177,6 +177,9 @@
|
|||
},
|
||||
{
|
||||
"id": "kibDevTutorialScreenshotting"
|
||||
},
|
||||
{
|
||||
"id": "kibDevTutorialsServerlessProjectNavigation"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -19,7 +19,6 @@ export interface Props<
|
|||
Id extends string = string,
|
||||
ChildrenId extends string = Id
|
||||
> extends NodeProps<LinkId, Id, ChildrenId> {
|
||||
element?: string;
|
||||
unstyled?: boolean;
|
||||
}
|
||||
|
||||
|
@ -36,10 +35,9 @@ function NavigationItemComp<
|
|||
const navigationContext = useNavigation();
|
||||
const navNodeRef = React.useRef<ChromeProjectNavigationNodeEnhanced | null>(null);
|
||||
|
||||
const { element, children, node } = useMemo(() => {
|
||||
const { element: _element, children: _children, ...rest } = props;
|
||||
const { children, node } = useMemo(() => {
|
||||
const { children: _children, ...rest } = props;
|
||||
return {
|
||||
element: _element,
|
||||
children: _children,
|
||||
node: rest,
|
||||
};
|
||||
|
@ -70,9 +68,7 @@ function NavigationItemComp<
|
|||
return <>{children}</>;
|
||||
}
|
||||
|
||||
const Element = element || Fragment;
|
||||
|
||||
return <Element>{navNode.title}</Element>;
|
||||
return <Fragment>{navNode.title}</Fragment>;
|
||||
}
|
||||
|
||||
export const NavigationItem = React.memo(NavigationItemComp) as typeof NavigationItemComp;
|
||||
|
|
|
@ -18,6 +18,10 @@ import { navigationStyles as styles } from '../../styles';
|
|||
import { getI18nStrings } from '../i18n_strings';
|
||||
|
||||
export interface Props {
|
||||
/**
|
||||
* Optional observable for recently accessed items. If not provided, the
|
||||
* recently items from the Chrome service will be used.
|
||||
*/
|
||||
recentlyAccessed$?: Observable<RecentItem[]>;
|
||||
/**
|
||||
* If true, the recently accessed list will be collapsed by default.
|
||||
|
|
508
packages/shared-ux/chrome/serverless_projects_documentation.mdx
Normal file
508
packages/shared-ux/chrome/serverless_projects_documentation.mdx
Normal file
|
@ -0,0 +1,508 @@
|
|||
---
|
||||
id: kibDevTutorialsServerlessProjectNavigation
|
||||
slug: /kibana-dev-docs/serverless-project-navigation
|
||||
title: Serverless project navigation
|
||||
description: Project navigation replaces the default Kibana navigation in serverless mode, providing a more tailored experience for each project. Learn how to build a custom navigation for your project.
|
||||
date: 2023-07-26
|
||||
tags: ['kibana', 'serverless', 'navigation']
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
Welcome to the serverless project navigation documentation. Our tools help teams build customizable and flexible navigation for their serverless projects. Project navigation replaces the default Kibana navigation in serverless mode, providing a more tailored experience for each project.
|
||||
|
||||
- [Serverless project navigation](#serverless-project-navigation)
|
||||
- [Left Side Navigation](#left-side-navigation)
|
||||
- [Navigation Tree Definition](#navigation-tree-definition)
|
||||
- [Example](#example)
|
||||
- [Navigation tree API](#navigation-tree-api)
|
||||
- [`NavigationTreeDefinition`](#navigationtreedefinition)
|
||||
- [`GroupDefinition`](#groupdefinition)
|
||||
- [`RecentlyAccessedDefinition`](#recentlyaccesseddefinition)
|
||||
- [React components](#react-components)
|
||||
- [`unstyled`](#unstyled)
|
||||
- [Important concepts](#important-concepts)
|
||||
- [Deep links](#deep-links)
|
||||
- [Cloud link](#cloud-links)
|
||||
- [Preconfigured navigation sections](#preconfigured-navigation-sections)
|
||||
- [Active navigation path](#active-navigation-path)
|
||||
- [Breadcrumbs](#breadcrumbs)
|
||||
- [Header action menu](#header-action-menu)
|
||||
- [Global Search](#global-search)
|
||||
- [Testing](#testing)
|
||||
|
||||
### Building Blocks
|
||||
|
||||
The project navigation is composed of several key building blocks that work together to form a comprehensive navigation system. These building blocks include:
|
||||
|
||||
1. **Left Side Navigation**: Allow users to navigate through different sections of the project.
|
||||
2. **Breadcrumbs**: A visual representation of the user's current location within the navigation hierarchy.
|
||||
3. **Header action menu**: A customizable toolbar that provides quick access to important actions and features.
|
||||
4. **Global Search**: A navigational search input that enables users to quickly access specific content within the project.
|
||||
|
||||
In the following sections, we will explore each of these building blocks in detail.
|
||||
|
||||
## Left Side Navigation
|
||||
|
||||
> **Note**
|
||||
> Left Side Navigation is available in shared_ux storybook under the `Chrome/Navigation` section. You can explore the components and their properties there.
|
||||
> `yarn storybook shared_ux`
|
||||
|
||||
The left side navigation is a primary way for users to navigate through different sections of the project. It consists of a tree of navigation items that can be expanded and collapsed. Apart from the navigation tree it also supports special pre-built blocks like recently accessed items. The main part of the navigation tree is project's navigation: this is fully configured and supported by the project teams (e.g. Observability). We also provide pre-configured platform sections as presets that solutions can use as part of their navigation (e.g. `ml`, `analytics`). Solutions can customize those sections to their needs.
|
||||
|
||||
There are two approaches to building the side navigation:
|
||||
|
||||
1. **Navigation tree definition**: Developers provide a navigation tree definition. This approach is recommended if the use case works with the existing building blocks.
|
||||
|
||||
2. **React components**: Alternatively, we provide a set of pre-built components that can be used to construct the left side navigation. These components include:
|
||||
|
||||
`<Navigation />`: The parent component that encapsulates the entire navigation area.
|
||||
`<Navigation.Group />`: A component representing a group of navigation items.
|
||||
`<Navigation.Item />`: A component representing an individual navigation item.
|
||||
`<Navigation.Footer />`: A component for displaying additional content at the bottom of the navigation.
|
||||
`<Navigation.RecentlyAccessed />`: A component for displaying a list of recently accessed items.
|
||||
|
||||
By leveraging these components, you can create a customized left side navigation for a serverless project.
|
||||
|
||||
> **Note**
|
||||
> Both approaches have an identical set of properties that can be passed. Some of those properties will be documented in the tree definition section below.
|
||||
|
||||
### Navigation Tree Definition
|
||||
|
||||
Use the `NavigationTreeDefinition` interface to create your left side navigation using a tree definition. This interface allows you to define the complete navigation tree, including the **body** and **footer** of the navigation.
|
||||
|
||||
#### Example
|
||||
|
||||
Let's start by seeing an example, and we'll detail the different properties below.
|
||||
|
||||
```ts
|
||||
import { type NavigationTreeDefinition, getPresets } from '@kbn/shared-ux-chrome-navigation';
|
||||
|
||||
const navigationTree: NavigationTreeDefinition = {
|
||||
body: [
|
||||
{ type: 'recentlyAccessed' }, // Add the recently accessed items
|
||||
{
|
||||
type: 'navGroup', // A top level group for the project's navigation the main part of the navigation tree
|
||||
id: 'search_project_nav',
|
||||
title: 'Elasticsearch',
|
||||
icon: 'logoElasticsearch',
|
||||
defaultIsCollapsed: false, // ensures this section is automatically expanded when users first load the page
|
||||
breadcrumbStatus: 'hidden', // this node of the navigation tree does not need to appear in the breadcrumbs, since the home logo icon navigates to the same link
|
||||
children: [
|
||||
{
|
||||
id: 'search_getting_started',
|
||||
title: 'Getting started',
|
||||
link: 'serverlessElasticsearch', // All **internal** links must be deepLinks (core's `app.deepLinks`), learn more in #deep-links section
|
||||
},
|
||||
{
|
||||
id: 'explore',
|
||||
title: 'Explore', // A nested group with its children
|
||||
children: [
|
||||
{
|
||||
link: 'discover',
|
||||
},
|
||||
{
|
||||
link: 'dashboards',
|
||||
},
|
||||
{
|
||||
link: 'visualize',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'navGroup',
|
||||
...getPresets('ml'), // Insert all the machine learning links, learn more in #preconfigured-navigation-presets section
|
||||
},
|
||||
],
|
||||
footer: [
|
||||
{
|
||||
type: 'navGroup',
|
||||
id: 'project_settings_project_nav',
|
||||
title: 'Project settings',
|
||||
icon: 'gear',
|
||||
breadcrumbStatus: 'hidden',
|
||||
children: [
|
||||
{
|
||||
id: 'settings',
|
||||
children: [
|
||||
{
|
||||
link: 'management',
|
||||
title: 'Management',
|
||||
},
|
||||
{
|
||||
id: 'cloudLinkUserAndRoles',
|
||||
cloudLink: 'userAndRoles', // Add an external link to Cloud, learn more in #cloud-links section
|
||||
},
|
||||
{
|
||||
id: 'cloudLinkPerformance',
|
||||
cloudLink: 'performance',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
Once the navigation tree is defined we need to
|
||||
|
||||
1. Pass it to the `<DefaultNavigation />` component
|
||||
2. Set your navigation component in the `serverless` plugin
|
||||
|
||||
```tsx
|
||||
import { DefaultNavigation, NavigationKibanaProvider } from '@kbn/shared-ux-chrome-navigation';
|
||||
|
||||
const createServerlessSearchSideNavComponent =
|
||||
(
|
||||
core: CoreStart,
|
||||
{ serverless, cloud }: { serverless: ServerlessPluginStart; cloud: CloudStart }
|
||||
) =>
|
||||
() => {
|
||||
return (
|
||||
<NavigationKibanaProvider core={core} serverless={serverless} cloud={cloud}>
|
||||
<DefaultNavigation navigationTree={navigationTree} dataTestSubj="svlSearchSideNav" />
|
||||
</NavigationKibanaProvider>
|
||||
);
|
||||
};
|
||||
|
||||
// plugin.ts (public) "start()"
|
||||
serverless.setSideNavComponent(createComponent(core, { serverless, cloud }));
|
||||
```
|
||||
|
||||
#### Navigation tree API
|
||||
|
||||
> **Warning**
|
||||
> The API reference is manually maintained and might be out of date. Please refer [to the source](https://github.com/elastic/kibana/blob/2c4f8b76c520f2ffd0516a29601c03db9b09d221/packages/shared-ux/chrome/navigation/src/ui/types.ts#L83-L124) for the most up-to-date information, until we have automated the API reference.
|
||||
|
||||
##### `NavigationTreeDefinition`
|
||||
|
||||
| Property | Type | Description |
|
||||
| -------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `body` | `RootNavigationItemDefinition[]` | The main content of the navigation, which can contain various types of items such as `cloudLink`, `recentlyAccessed`, or `navGroup`. |
|
||||
| `footer` | `RootNavigationItemDefinition[]` | The footer content of the navigation, which can contain additional items similar to the `body` section. |
|
||||
|
||||
Each item in the `body` or `footer` arrays can have its own unique structure defined by the `RootNavigationItemDefinition` interface.
|
||||
|
||||
The `RootNavigationItemDefinition` is one of:
|
||||
|
||||
- `GroupDefinition`
|
||||
- `RecentlyAccessedDefinition`
|
||||
|
||||
##### `GroupDefinition`
|
||||
|
||||
The `GroupDefinition` interface represents a group of items in the side navigation. It extends the `NodeDefinition` interface and has the following additional properties:
|
||||
|
||||
| Property | Type | Description |
|
||||
| -------------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `type` | `'navGroup'` | Indicates that this item is a navigation group. |
|
||||
| `defaultIsCollapsed` | `boolean \| undefined` | Determines if the group is initially collapsed or expanded. Use `undefined` (recommended) to open the group if any of its children nodes match the current URL, `false` to always open the group, or `true` to always collapse it. |
|
||||
| `preset` | `NavigationGroupPreset` | A preset value for the group, such as `'analytics'`, `'devtools'`, `'ml'`, or `'management'`. |
|
||||
| `id` | `Id` | Optional ID of the navigation node. |
|
||||
| `title` | `string` | Optional title of the navigation node. If not provided and a "link" is provided, the title will be the Deep link title. |
|
||||
| `link` | `LinkId` | Optional App ID or deep link ID for the navigation node. [More about deep links](#deep-links) |
|
||||
| `cloudLink` | `CloudLinkId` | Optional cloud link ID for the navigation node. [More about cloud links](#cloud-links) |
|
||||
| `icon` | `string` | Optional icon for the navigation node. Note that not all navigation depths will render the icon. |
|
||||
| `children` | `NodeDefinition[]` | Optional children of the navigation node. |
|
||||
| `href` | `string` | Use `href` for absolute links only. Internal links should use "link". |
|
||||
| `getIsActive` | `function` | Optional function to control the active state. This function is called whenever the location changes. |
|
||||
| `breadcrumbStatus` | `'hidden'\|'visible'` | An optional flag to indicate if the breadcrumb should be hidden when this node is active. The default value is `'visible'`. |
|
||||
|
||||
##### `RecentlyAccessedDefinition`
|
||||
|
||||
| Property | Type | Description |
|
||||
| -------------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `type` | `'recentlyAccessed'` | Indicates that this item represents the recently accessed section. |
|
||||
| `recentlyAccessed$` | `Observable<RecentItem[]>` | An optional observable for recently accessed items. If not provided, the recently accessed items from the Chrome service will be used. |
|
||||
| `defaultIsCollapsed` | `boolean` | If set to `true`, the recently accessed list will be collapsed by default. The default value is `false`. |
|
||||
|
||||
### React components
|
||||
|
||||
If you need other navigation sections in your navigation you will need to use our React components. They have the same properties as seen above except the `unstyled` prop that we will detail below.
|
||||
|
||||
```tsx
|
||||
import { NavigationKibanaProvider, Navigation } from '@kbn/shared-ux-chrome-navigation';
|
||||
|
||||
const createServerlessSearchSideNavComponent =
|
||||
(
|
||||
core: CoreStart,
|
||||
{ serverless, cloud }: { serverless: ServerlessPluginStart; cloud: CloudStart }
|
||||
) =>
|
||||
() => {
|
||||
return (
|
||||
<NavigationKibanaProvider core={core} serverless={serverless} cloud={cloud}>
|
||||
<Navigation>
|
||||
<Navigation.Group id="group1" title="Group 1" defaultIsCollapsed={false}>
|
||||
<Navigation.Item id="item1" title="Item 1" />
|
||||
<Navigation.Item id="item2" title="Item 2" />
|
||||
<Navigation.Item id="item3" title="Item 3" />
|
||||
</Navigation.Group>
|
||||
|
||||
<div>
|
||||
<p>Any other section you might need</p>
|
||||
</div>
|
||||
|
||||
<Navigation.Group id="group2" title="Group 2">
|
||||
<Navigation.Item id="item1">
|
||||
<EuiText color="blue">Title can also be a React node</EuiText>
|
||||
</Navigation.Item>
|
||||
|
||||
<Navigation.Group id="nestedGroup" title="Group can be nested">
|
||||
<Navigation.Item id="item1" title="Item 1" />
|
||||
</Navigation.Group>
|
||||
</Navigation.Group>
|
||||
<Navigation.Footer>
|
||||
<Navigation.Group preset="devtools" />
|
||||
</Navigation.Footer>
|
||||
</Navigation>
|
||||
</NavigationKibanaProvider>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
And as with the tree definition above you will have to set the navigation component on the `serverless` plugin.
|
||||
|
||||
```ts
|
||||
// plugin.ts (public) "start()"
|
||||
serverless.setSideNavComponent(createComponent(core, { serverless, cloud }));
|
||||
```
|
||||
|
||||
#### `unstyled`
|
||||
|
||||
If you want to have a completely customized UI, without the Shared UX components, but also want the benefits of self-updating breadcrumbs (see the [#breadcrumbs](#breadcrumbs) section), just declare your navigation tree and pass the `unstyled` property to your `<Navigation />`.
|
||||
|
||||
```tsx
|
||||
/**
|
||||
* This JSX will correctly declare your tree structure but will not have any UI applied.
|
||||
Tree generated:
|
||||
[{
|
||||
id: 'my-group',
|
||||
title: "My Group,
|
||||
children: [{
|
||||
id: 'item-1',
|
||||
title: 'Item 1',
|
||||
}, {
|
||||
id: 'item-2',
|
||||
title: 'Item 2',
|
||||
}]
|
||||
}]
|
||||
*/
|
||||
<Navigation unstyled>
|
||||
<Navigation.Group id="my-group" title="My group">
|
||||
<Navigation.Item id="item-1" title="Item 1">
|
||||
<div>Your custom UI</div>
|
||||
</Navigation.Item>
|
||||
<Navigation.Item id="item-2" title="Item 2">
|
||||
<div>Your custom UI</div>
|
||||
</Navigation.Item>
|
||||
</Navigation.Group>
|
||||
</Navigation>
|
||||
```
|
||||
|
||||
### Important Concepts
|
||||
|
||||
#### Deep links
|
||||
|
||||
[Deep links](https://github.com/elastic/kibana/blob/f5034e60a501e7b61a3e1bff34e64c9b94c71344/packages/core/application/core-application-browser/src/application.ts#L281-L314) are a Kibana core's mechanism for registering sub-pages within an app. In "classic" Kibana they are used for the default side navigation, navigation APIs and the global search. Teams can register the deep links when they register their app. They can also update their registered deep links, or unregister deep links dynamically.
|
||||
|
||||
The serverless navigation API uses the same deep links mechanism to configure the navigation tree. The `link` property of the `NodeDefinition` interface refers to the deep links registered by apps. The `link` property can be either can be either the ID of an app, or a deep link ID.
|
||||
|
||||
There are multiple benefits of using deep links instead of the hardcoded URLs when configuring the navigation tree:
|
||||
|
||||
- Validation: the deep links are validated when the tree is built. If the deep link wasn't registered by any of the apps, an error will be thrown.
|
||||
- Type safety: the list of deep links is typed, and we don't rely on static URLs that can break.
|
||||
- Dynamic updates: the deep links can be updated or removed dynamically by apps that own them. The navigation tree will be updated accordingly.
|
||||
|
||||
Internal navigation should be configured using deep links. The `href` property should be used only for external links. There is also a special type of external links for links pointing to the cloud console - `cloudLink`.
|
||||
|
||||
#### Cloud links
|
||||
|
||||
The `cloudLink` property of the `NodeDefinition` interface refers to the predefined list of cloud links that are configured in `kibana.yml`.
|
||||
Currently available pages are `'userAndRoles' | 'performance' | 'billingAndSub'`
|
||||
|
||||
```ts
|
||||
import { type NavigationTreeDefinition, getPresets } from '@kbn/shared-ux-chrome-navigation';
|
||||
|
||||
const navigationTree: NavigationTreeDefinition = {
|
||||
body: [
|
||||
{
|
||||
type: 'navGroup',
|
||||
id: 'topNav',
|
||||
children: [
|
||||
{
|
||||
id: 'cloudLinkUserAndRoles',
|
||||
cloudLink: 'userAndRoles',
|
||||
},
|
||||
{
|
||||
id: 'cloudLinkPerformance',
|
||||
cloudLink: 'performance',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
#### Preconfigured navigation sections
|
||||
|
||||
When configuring the navigation tree you can use the preconfigured sections for areas of the Kibana platform, like `devtools`, `management`, `ml`, `analytics`:
|
||||
|
||||
```ts
|
||||
import { type NavigationTreeDefinition, getPresets } from '@kbn/shared-ux-chrome-navigation';
|
||||
|
||||
const navigationTree: NavigationTreeDefinition = {
|
||||
body: [
|
||||
{
|
||||
type: 'navGroup',
|
||||
...getPresets('ml'), // Insert all the machine learning links
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
The benefit of using the preset instead of building the platform sections manually is that the team who owns the platform area can update the preset as they see fit.
|
||||
|
||||
You can also customize the preset like so:
|
||||
|
||||
```ts
|
||||
import type { NodeDefinition } from '@kbn/core-chrome-browser';
|
||||
import { type NavigationTreeDefinition, getPresets } from '@kbn/shared-ux-chrome-navigation';
|
||||
|
||||
const navigationTree: NavigationTreeDefinition = {
|
||||
body: [
|
||||
{
|
||||
type: 'navGroup',
|
||||
// And specific links from analytics
|
||||
...getPresets('analytics'),
|
||||
title: 'My analytics', // Change the title
|
||||
children: getPresets('analytics').children.map((child) => ({
|
||||
...child,
|
||||
children: child.children?.filter((item) => {
|
||||
// force remove discover and dashboard
|
||||
return item.link !== 'discover' && item.link !== 'dashboards';
|
||||
}),
|
||||
})) as NonEmptyArray<NodeDefinition>,
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
#### Active Navigation Path
|
||||
|
||||
Active navigation path is automatically tracked by the side navigation component. The active path is determined by the current URL and the deep links registered by apps. The active path is used to highlight the active navigation items and to determine the breadcrumbs.
|
||||
|
||||
By default, the path matching logic uses `startsWith` against the path from the deep link and then picks the longest match. This can be overridden using `getIsActive` predicate.
|
||||
|
||||
```ts
|
||||
import { type NavigationTreeDefinition } from '@kbn/shared-ux-chrome-navigation';
|
||||
|
||||
const navigationTree: NavigationTreeDefinition = {
|
||||
body: [
|
||||
{
|
||||
title: `Dashboards`,
|
||||
link: 'dashboards',
|
||||
getIsActive: ({ pathNameSerialized, prepend }) => {
|
||||
return pathNameSerialized.startsWith(prepend('/app/dashboards'));
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
Technically, multiple paths can be active simultaneously and multiple nodes can be highlighted in the side navigation. However, this is not recommended as it can be confusing for the user.
|
||||
|
||||
You can programmatically access the active paths using the `getActiveNavigationNodes$` method:
|
||||
|
||||
```ts
|
||||
const activesNodes$ = pluginsStart.serverless.getActiveNavigationNodes$();
|
||||
```
|
||||
|
||||
## Breadcrumbs
|
||||
|
||||
Breadcrumbs is a list of links that represent the current navigation path. Project navigation breadcrumbs are automatically generated based on the navigation tree set for the [side navigation](#left-side-navigation) and the currently active navigation path.
|
||||
|
||||
Project breadcrumbs are built from 3 sections:
|
||||
|
||||
1. **Home link:** 🏠
|
||||
2. **Platform navigation:** is automatically controlled by SharedUX services
|
||||
3. **Deeper context:** is manually controlled by projects
|
||||
|
||||
### Project breadcrumbs sections
|
||||
|
||||
#### 🏠 Home breadcrumb
|
||||
|
||||
Home breadcrumb is always displayed as the first breadcrumb and leads to what project specifies as home page in `kibana.yml`.
|
||||
|
||||
#### Navigation breadcrumbs
|
||||
|
||||
Navigation breadcrumbs are automatically generated based on the navigation tree set for the [side navigation](#left-side-navigation) and the currently active navigation path.
|
||||
|
||||
#### Deeper context breadcrumbs
|
||||
|
||||
Deeper context breadcrumbs are manually controlled by projects. They are added to the breadcrumbs using the `pluginsStart.serverless.setBreadcrumbs` method.
|
||||
|
||||
```ts
|
||||
pluginsStart.serverless.setBreadcrumbs([
|
||||
{
|
||||
text: 'Deeper Context',
|
||||
href: '/some/deeper/context',
|
||||
},
|
||||
]);
|
||||
```
|
||||
|
||||
These breadcrumbs are removed when the active navigation path changes.
|
||||
|
||||
### Overriding breadcrumbs
|
||||
|
||||
Projects can override navigation breadcrumbs. This will override navigation breadcrumbs, but will keep the Home breadcrumb:
|
||||
|
||||
```ts
|
||||
pluginsStart.serverless.setBreadcrumbs([b1, b2, b3], { absolute: true });
|
||||
```
|
||||
|
||||
The override is automatically reset when the active navigation path changes.
|
||||
|
||||
## Header Action Menu
|
||||
|
||||
The Header Action Menu, aka application toolbar, is a horizontal bar that is **conditionally** displayed at the top of the page below the header where apps can put their custom actions. Like the header, the toolbar has fixed position. Unlike the header however, this bar only appears when an application has registered content to show. Another UI difference, is the toolbar could be covered by flyouts or full-page overlays on the page. There might be other slight styling and positioning changes comparing to the toolbar in the default Kibana navigation.
|
||||
There is no serverless specific API or behavior change for the toolbar. To set custom content in this area, use the same API as in the default Kibana `setHeaderActionMenu` [source](https://github.com/elastic/kibana/blob/188009f9376d5976b5db37e04c52a2b5bdaf9771/packages/core/application/core-application-browser/src/app_mount.ts#L176-L205). To unset content, call `setHeaderActionMenu` with `undefined`.
|
||||
|
||||
> **Note**
|
||||
> The display of the toolbar container is conditional, based on whether there is toolbar content to show. Make sure to pass `undefined` to `setHeaderActionMenu` if there is no application content to show. In classic layout, passing an empty `span` or `div` element suffices to "clear" the toolbar, but in serverless projects it will cause a large empty container to show below the header.
|
||||
|
||||
## Global Search
|
||||
|
||||
The global search (navigational search) is a search bar that can be opened from the header. It allows users to search for apps, pages, and other resources. Unlike the classic layout, the user must click a magnifying glass icon to reveal the search text input, but everything else in the serverless project layout is the same.
|
||||
There is no serverless specific API or behavior changes for this: refer to [the global search plugin](https://github.com/elastic/kibana/blob/bd778221dcf8b934f2947d6be3173f8a2796ef74/x-pack/plugins/global_search/README.md) to learn about the API.
|
||||
|
||||
# Testing
|
||||
|
||||
> **Note**
|
||||
> For the general guidance on functional testing serverless projects refer to [the doc](https://docs.google.com/document/d/1tiax7xoDYwFXYZjRTgVKkVMjN-SQzBWk4yn1JY6Z5UY/edit#heading=h.t3qzojfbvfj4)
|
||||
|
||||
To test project navigation in functional tests use `svlCommonNavigation` page object:
|
||||
|
||||
```ts
|
||||
const svlCommonNavigation = getPageObject('svlCommonNavigation');
|
||||
```
|
||||
|
||||
The page object exposes helpers for using links in the sidenav and breadcrumbs, as well as using page-level components such as global search, recent items, the Elastic logo icon. There are also utilities to check that no page reload happened during the navigation.
|
||||
|
||||
Find the full list of helpers in [the source](https://github.com/elastic/kibana/blob/621401ed6a435d4c9beaa03ac1f61ace9716217a/x-pack/test_serverless/functional/page_objects/svl_common_navigation.ts#L44-L206). The most notable are:
|
||||
|
||||
- `svlCommonNavigation.expectExists()` checks that serverless project navigation is displayed and not the statefull one
|
||||
- `svlCommonNavigation.sideNav.expectLinkExists({ deepLinkId: 'discover'})` checks that the link is visible. Can check by deepLinkId, text or navId
|
||||
- `svlCommonNavigation.sideNav.clickLink({ deepLinkId: 'discover'})` clicks the link. Use to navigate using the sidenav as the users would. Can be used with deepLinkId, text or navId
|
||||
- `svlCommonNavigation.sideNav.openSection(sectionId)` opens navigation section.
|
||||
- `svlCommonNavigation.breadcrumbs.expectBreadcrumbExists({deepLinkId: 'discover'})` check that breadcrumbs is in the list using deepLinkId or text
|
||||
|
||||
For each project there is a navigation test suite that does a shared navigation smoke check and can be used as an example of using the shared navigation page object.
|
||||
|
||||
- x-pack/test_serverless/functional/test_suites/
|
||||
- search/navigation
|
||||
- observability/navigation
|
||||
- security/navigation
|
||||
|
||||
We recommend solution teams to improve these basic navigation smoke tests to cover more project specific functionality.
|
Loading…
Add table
Add a link
Reference in a new issue