mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Shared UX] Move Page Template Solution Nav to package (#134974)
* [Shared UX] Move Page Template Solution Nav to package * Fixing test import; fix i18n scope. * Update packages/shared-ux/page/solution_nav/src/collapse_button.scss * Address feedback, simplify generic * Tweak types * Addressing review feedback * REverting mistakes, ugh * Fix Observability tour * Apply suggestions from code review Co-authored-by: Caroline Horn <549577+cchaos@users.noreply.github.com> * Addressing review feedback * Addressing review feedback * Fix i18n keys * Apply suggestions from code review Co-authored-by: Caroline Horn <549577+cchaos@users.noreply.github.com> * Fix solution nav collapse Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Caroline Horn <549577+cchaos@users.noreply.github.com>
This commit is contained in:
parent
6f0f59e1f1
commit
cd8a4ae677
36 changed files with 528 additions and 202 deletions
|
@ -251,6 +251,7 @@
|
|||
"@kbn/shared-ux-link-redirect-app": "link:bazel-bin/packages/shared-ux/link/redirect_app",
|
||||
"@kbn/shared-ux-page-analytics-no-data": "link:bazel-bin/packages/shared-ux/page/analytics_no_data",
|
||||
"@kbn/shared-ux-page-kibana-no-data": "link:bazel-bin/packages/shared-ux/page/kibana_no_data",
|
||||
"@kbn/shared-ux-page-solution-nav": "link:bazel-bin/packages/shared-ux/page/solution_nav",
|
||||
"@kbn/shared-ux-prompt-no-data-views": "link:bazel-bin/packages/shared-ux/prompt/no_data_views",
|
||||
"@kbn/shared-ux-services": "link:bazel-bin/packages/kbn-shared-ux-services",
|
||||
"@kbn/shared-ux-storybook": "link:bazel-bin/packages/kbn-shared-ux-storybook",
|
||||
|
@ -834,6 +835,7 @@
|
|||
"@types/kbn__shared-ux-link-redirect-app": "link:bazel-bin/packages/shared-ux/link/redirect_app/npm_module_types",
|
||||
"@types/kbn__shared-ux-page-analytics-no-data": "link:bazel-bin/packages/shared-ux/page/analytics_no_data/npm_module_types",
|
||||
"@types/kbn__shared-ux-page-kibana-no-data": "link:bazel-bin/packages/shared-ux/page/kibana_no_data/npm_module_types",
|
||||
"@types/kbn__shared-ux-page-solution-nav": "link:bazel-bin/packages/shared-ux/page/solution_nav/npm_module_types",
|
||||
"@types/kbn__shared-ux-prompt-no-data-views": "link:bazel-bin/packages/shared-ux/prompt/no_data_views/npm_module_types",
|
||||
"@types/kbn__shared-ux-services": "link:bazel-bin/packages/kbn-shared-ux-services/npm_module_types",
|
||||
"@types/kbn__shared-ux-storybook": "link:bazel-bin/packages/kbn-shared-ux-storybook/npm_module_types",
|
||||
|
|
|
@ -186,6 +186,7 @@ filegroup(
|
|||
"//packages/shared-ux/link/redirect_app:build",
|
||||
"//packages/shared-ux/page/analytics_no_data:build",
|
||||
"//packages/shared-ux/page/kibana_no_data:build",
|
||||
"//packages/shared-ux/page/solution_nav:build",
|
||||
"//packages/shared-ux/prompt/no_data_views:build",
|
||||
"//x-pack/packages/ml/agg_utils:build",
|
||||
"//x-pack/packages/ml/aiops_components:build",
|
||||
|
@ -361,6 +362,7 @@ filegroup(
|
|||
"//packages/shared-ux/link/redirect_app:build_types",
|
||||
"//packages/shared-ux/page/analytics_no_data:build_types",
|
||||
"//packages/shared-ux/page/kibana_no_data:build_types",
|
||||
"//packages/shared-ux/page/solution_nav:build_types",
|
||||
"//packages/shared-ux/prompt/no_data_views:build_types",
|
||||
"//x-pack/packages/ml/agg_utils:build_types",
|
||||
"//x-pack/packages/ml/aiops_components:build_types",
|
||||
|
|
|
@ -40,23 +40,24 @@ NPM_MODULE_EXTRA_FILES = [
|
|||
# "@npm//name-of-package"
|
||||
# eg. "@npm//lodash"
|
||||
RUNTIME_DEPS = [
|
||||
"//packages/kbn-i18n-react",
|
||||
"//packages/kbn-i18n",
|
||||
"//packages/shared-ux/avatar/solution",
|
||||
"//packages/shared-ux/link/redirect_app",
|
||||
"//packages/shared-ux/prompt/no_data_views",
|
||||
"//packages/shared-ux/card/no_data",
|
||||
"//packages/kbn-shared-ux-services",
|
||||
"//packages/kbn-shared-ux-storybook",
|
||||
"//packages/kbn-shared-ux-utility",
|
||||
"@npm//@elastic/eui",
|
||||
"@npm//@emotion/react",
|
||||
"@npm//@emotion/css",
|
||||
"@npm//@emotion/react",
|
||||
"@npm//classnames",
|
||||
"@npm//react-use",
|
||||
"@npm//react",
|
||||
"@npm//rxjs",
|
||||
"@npm//url-loader",
|
||||
"//packages/kbn-i18n-react",
|
||||
"//packages/kbn-i18n",
|
||||
"//packages/kbn-shared-ux-services",
|
||||
"//packages/kbn-shared-ux-storybook",
|
||||
"//packages/kbn-shared-ux-utility",
|
||||
"//packages/shared-ux/avatar/solution",
|
||||
"//packages/shared-ux/card/no_data",
|
||||
"//packages/shared-ux/link/redirect_app",
|
||||
"//packages/shared-ux/page/solution_nav",
|
||||
"//packages/shared-ux/prompt/no_data_views",
|
||||
]
|
||||
|
||||
# In this array place dependencies necessary to build the types, which will include the
|
||||
|
@ -69,25 +70,26 @@ RUNTIME_DEPS = [
|
|||
#
|
||||
# References to NPM packages work the same as RUNTIME_DEPS
|
||||
TYPES_DEPS = [
|
||||
"@npm//@elastic/eui",
|
||||
"@npm//@emotion/css",
|
||||
"@npm//@emotion/react",
|
||||
"@npm//@types/classnames",
|
||||
"@npm//@types/jest",
|
||||
"@npm//@types/node",
|
||||
"@npm//@types/react",
|
||||
"@npm//react-use",
|
||||
"@npm//rxjs",
|
||||
"//packages/kbn-ambient-ui-types",
|
||||
"//packages/kbn-i18n-react:npm_module_types",
|
||||
"//packages/kbn-i18n:npm_module_types",
|
||||
"//packages/shared-ux/avatar/solution:npm_module_types",
|
||||
"//packages/shared-ux/link/redirect_app:npm_module_types",
|
||||
"//packages/shared-ux/prompt/no_data_views:npm_module_types",
|
||||
"//packages/shared-ux/card/no_data:npm_module_types",
|
||||
"//packages/kbn-shared-ux-services:npm_module_types",
|
||||
"//packages/kbn-shared-ux-storybook:npm_module_types",
|
||||
"//packages/kbn-shared-ux-utility:npm_module_types",
|
||||
"@npm//@types/node",
|
||||
"@npm//@types/jest",
|
||||
"@npm//@types/react",
|
||||
"@npm//@types/classnames",
|
||||
"@npm//@emotion/react",
|
||||
"@npm//@emotion/css",
|
||||
"@npm//@elastic/eui",
|
||||
"@npm//react-use",
|
||||
"@npm//rxjs",
|
||||
"//packages/shared-ux/avatar/solution:npm_module_types",
|
||||
"//packages/shared-ux/card/no_data:npm_module_types",
|
||||
"//packages/shared-ux/link/redirect_app:npm_module_types",
|
||||
"//packages/shared-ux/page/solution_nav:npm_module_types",
|
||||
"//packages/shared-ux/prompt/no_data_views:npm_module_types",
|
||||
]
|
||||
|
||||
jsts_transpiler(
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export { KibanaPageTemplateSolutionNav } from './page_template/solution_nav';
|
||||
|
||||
// TODO: clintandrewhall - NoDataPageProps is a temporary addition until it is split into its own package
|
||||
export type { KibanaPageTemplateProps, NoDataPageProps } from './page_template';
|
||||
|
||||
|
|
|
@ -5,10 +5,12 @@
|
|||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
import { EuiPageTemplate } from '@elastic/eui';
|
||||
|
||||
import React from 'react';
|
||||
import { EuiPageTemplate } from '@elastic/eui';
|
||||
import { withSolutionNav } from '@kbn/shared-ux-page-solution-nav';
|
||||
|
||||
import { NoDataPage } from '../no_data_page';
|
||||
import { withSolutionNav } from '../../with_solution_nav';
|
||||
import { KibanaPageTemplateProps } from '../../types';
|
||||
import { getClasses, NO_DATA_PAGE_TEMPLATE_PROPS } from '../../util';
|
||||
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
|
||||
import React from 'react';
|
||||
import { EuiButton, EuiText } from '@elastic/eui';
|
||||
import { SolutionNavProps } from '@kbn/shared-ux-page-solution-nav';
|
||||
|
||||
import { KibanaPageTemplate } from './page_template';
|
||||
import mdx from './page_template.mdx';
|
||||
import { KibanaPageTemplateSolutionNavProps } from './solution_nav';
|
||||
import { KibanaPageTemplateProps } from './types';
|
||||
|
||||
export default {
|
||||
|
@ -36,7 +37,7 @@ const noDataConfig = {
|
|||
docsLink: 'http://wwww.docs.elastic.co',
|
||||
};
|
||||
|
||||
const items: KibanaPageTemplateSolutionNavProps['items'] = [
|
||||
const items: SolutionNavProps['items'] = [
|
||||
{
|
||||
name: 'Ingest',
|
||||
id: '1',
|
||||
|
|
|
@ -8,11 +8,12 @@
|
|||
|
||||
import React from 'react';
|
||||
import { shallow, render } from 'enzyme';
|
||||
import { SolutionNavProps } from '@kbn/shared-ux-page-solution-nav';
|
||||
|
||||
import { KibanaPageTemplate } from './page_template';
|
||||
import { KibanaPageTemplateSolutionNavProps } from './solution_nav';
|
||||
import { NoDataPageProps } from './no_data_page';
|
||||
|
||||
const items: KibanaPageTemplateSolutionNavProps['items'] = [
|
||||
const items: SolutionNavProps['items'] = [
|
||||
{
|
||||
name: 'Ingest',
|
||||
id: '1',
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import './page_template.scss';
|
||||
|
||||
import React, { FunctionComponent } from 'react';
|
||||
|
||||
import { NoDataConfigPage, NoDataConfigPageWithSolutionNavBar } from './no_data_page';
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
import React, { FunctionComponent } from 'react';
|
||||
|
||||
import { EuiEmptyPrompt, EuiPageTemplate } from '@elastic/eui';
|
||||
import { withSolutionNav } from '@kbn/shared-ux-page-solution-nav';
|
||||
|
||||
import { withSolutionNav } from './with_solution_nav';
|
||||
import { KibanaPageTemplateProps } from './types';
|
||||
import { getClasses } from './util';
|
||||
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
*/
|
||||
|
||||
import { EuiPageTemplateProps } from '@elastic/eui';
|
||||
import { KibanaPageTemplateSolutionNavProps } from './solution_nav';
|
||||
import { SolutionNavProps } from '@kbn/shared-ux-page-solution-nav';
|
||||
|
||||
import { NoDataPageProps } from './no_data_page';
|
||||
|
||||
export type KibanaPageTemplateProps = EuiPageTemplateProps & {
|
||||
|
@ -21,7 +22,7 @@ export type KibanaPageTemplateProps = EuiPageTemplateProps & {
|
|||
/**
|
||||
* Quick creation of EuiSideNav. Hooks up mobile instance too
|
||||
*/
|
||||
solutionNav?: KibanaPageTemplateSolutionNavProps;
|
||||
solutionNav?: SolutionNavProps;
|
||||
/**
|
||||
* Accepts a configuration object, that when provided, ignores pageHeader and children and instead
|
||||
* displays Agent, Beats, and custom cards to direct users to the right ingest location
|
||||
|
|
144
packages/shared-ux/page/solution_nav/BUILD.bazel
Normal file
144
packages/shared-ux/page/solution_nav/BUILD.bazel
Normal file
|
@ -0,0 +1,144 @@
|
|||
load("@npm//@bazel/typescript:index.bzl", "ts_config")
|
||||
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
|
||||
load("//src/dev/bazel:index.bzl", "jsts_transpiler", "pkg_npm", "pkg_npm_types", "ts_project")
|
||||
|
||||
PKG_DIRNAME = "solution_nav"
|
||||
PKG_REQUIRE_NAME = "@kbn/shared-ux-page-solution-nav"
|
||||
|
||||
SOURCE_FILES = glob(
|
||||
[
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.scss",
|
||||
"src/**/*.mdx",
|
||||
],
|
||||
exclude = [
|
||||
"**/*.test.*",
|
||||
"**/*.stories.*",
|
||||
],
|
||||
)
|
||||
|
||||
SRCS = SOURCE_FILES
|
||||
|
||||
filegroup(
|
||||
name = "srcs",
|
||||
srcs = SRCS,
|
||||
)
|
||||
|
||||
NPM_MODULE_EXTRA_FILES = [
|
||||
"package.json",
|
||||
]
|
||||
|
||||
# In this array place runtime dependencies, including other packages and NPM packages
|
||||
# which must be available for this code to run.
|
||||
#
|
||||
# To reference other packages use:
|
||||
# "//repo/relative/path/to/package"
|
||||
# eg. "//packages/kbn-utils"
|
||||
#
|
||||
# To reference a NPM package use:
|
||||
# "@npm//name-of-package"
|
||||
# eg. "@npm//lodash"
|
||||
RUNTIME_DEPS = [
|
||||
"@npm//@elastic/eui",
|
||||
"@npm//classnames",
|
||||
"@npm//enzyme",
|
||||
"@npm//react",\
|
||||
"//packages/kbn-i18n-react",
|
||||
"//packages/kbn-i18n",
|
||||
"//packages/shared-ux/avatar/solution",
|
||||
]
|
||||
|
||||
# In this array place dependencies necessary to build the types, which will include the
|
||||
# :npm_module_types target of other packages and packages from NPM, including @types/*
|
||||
# packages.
|
||||
#
|
||||
# To reference the types for another package use:
|
||||
# "//repo/relative/path/to/package:npm_module_types"
|
||||
# eg. "//packages/kbn-utils:npm_module_types"
|
||||
#
|
||||
# References to NPM packages work the same as RUNTIME_DEPS
|
||||
TYPES_DEPS = [
|
||||
"@npm//@elastic/eui",
|
||||
"@npm//@types/classnames",
|
||||
"@npm//@types/enzyme",
|
||||
"@npm//@types/jest",
|
||||
"@npm//@types/node",
|
||||
"@npm//@types/react",
|
||||
"//packages/kbn-ambient-ui-types",
|
||||
"//packages/kbn-i18n-react:npm_module_types",
|
||||
"//packages/kbn-i18n:npm_module_types",
|
||||
"//packages/shared-ux/avatar/solution:npm_module_types",
|
||||
]
|
||||
|
||||
jsts_transpiler(
|
||||
name = "target_node",
|
||||
srcs = SRCS,
|
||||
build_pkg_name = package_name(),
|
||||
)
|
||||
|
||||
jsts_transpiler(
|
||||
name = "target_web",
|
||||
srcs = SRCS,
|
||||
build_pkg_name = package_name(),
|
||||
web = True,
|
||||
additional_args = [
|
||||
"--copy-files",
|
||||
"--quiet"
|
||||
],
|
||||
)
|
||||
|
||||
ts_config(
|
||||
name = "tsconfig",
|
||||
src = "tsconfig.json",
|
||||
deps = [
|
||||
"//:tsconfig.base.json",
|
||||
"//:tsconfig.bazel.json",
|
||||
],
|
||||
)
|
||||
|
||||
ts_project(
|
||||
name = "tsc_types",
|
||||
args = ['--pretty'],
|
||||
srcs = SRCS,
|
||||
deps = TYPES_DEPS,
|
||||
declaration = True,
|
||||
emit_declaration_only = True,
|
||||
out_dir = "target_types",
|
||||
root_dir = "src",
|
||||
tsconfig = ":tsconfig",
|
||||
)
|
||||
|
||||
js_library(
|
||||
name = PKG_DIRNAME,
|
||||
srcs = NPM_MODULE_EXTRA_FILES,
|
||||
deps = RUNTIME_DEPS + [":target_node", ":target_web"],
|
||||
package_name = PKG_REQUIRE_NAME,
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
pkg_npm(
|
||||
name = "npm_module",
|
||||
deps = [":" + PKG_DIRNAME],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "build",
|
||||
srcs = [":npm_module"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
pkg_npm_types(
|
||||
name = "npm_module_types",
|
||||
srcs = SRCS,
|
||||
deps = [":tsc_types"],
|
||||
package_name = PKG_REQUIRE_NAME,
|
||||
tsconfig = ":tsconfig",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "build_types",
|
||||
srcs = [":npm_module_types"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
17
packages/shared-ux/page/solution_nav/README.mdx
Normal file
17
packages/shared-ux/page/solution_nav/README.mdx
Normal file
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
id: sharedUX/Page/SolutionNav
|
||||
slug: /shared-ux/page/solution-nav
|
||||
title: Solution Page Navigation
|
||||
summary: A customized `EuiSideNav` for pages within Solutions in Kibana.
|
||||
tags: ['shared-ux', 'component']
|
||||
date: 2022-06-30
|
||||
---
|
||||
|
||||
This is a customized `EuiSideNav` for pages within Solutions in Kibana. It also includes a Higher-order Component (HOC) to supply Side Navigation to an existing component. It is currently used in the Kibana Page Template for solutions that provide side navigation, (e.g. Observability). It does not currently depend on any Kibana services.
|
||||
|
||||
## API
|
||||
|
||||
| Export | Description |
|
||||
|---|---|
|
||||
| `SolutionNav` | The `SolutionNav` component |
|
||||
| `withSolutionNav` | The HOC which can provide the navigation to any component aligning with `KibanaPageTemplate` and its props. |
|
13
packages/shared-ux/page/solution_nav/jest.config.js
Normal file
13
packages/shared-ux/page/solution_nav/jest.config.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
preset: '@kbn/test',
|
||||
rootDir: '../../../..',
|
||||
roots: ['<rootDir>/packages/shared-ux/page/solution_nav'],
|
||||
};
|
8
packages/shared-ux/page/solution_nav/package.json
Normal file
8
packages/shared-ux/page/solution_nav/package.json
Normal file
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"name": "@kbn/shared-ux-page-solution-nav",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"main": "./target_node/index.js",
|
||||
"browser": "./target_web/index.js",
|
||||
"license": "SSPL-1.0 OR Elastic License 2.0"
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`KibanaPageTemplateSolutionNavCollapseButton isCollapsed 1`] = `
|
||||
exports[`SolutionNavCollapseButton isCollapsed 1`] = `
|
||||
<EuiButtonIcon
|
||||
aria-label="Open side navigation"
|
||||
className="kbnPageTemplateSolutionNavCollapseButton kbnPageTemplateSolutionNavCollapseButton-isCollapsed"
|
||||
className="kbnSolutionNavCollapseButton kbnSolutionNavCollapseButton-isCollapsed"
|
||||
color="text"
|
||||
iconType="menuRight"
|
||||
size="s"
|
||||
|
@ -11,10 +11,10 @@ exports[`KibanaPageTemplateSolutionNavCollapseButton isCollapsed 1`] = `
|
|||
/>
|
||||
`;
|
||||
|
||||
exports[`KibanaPageTemplateSolutionNavCollapseButton renders 1`] = `
|
||||
exports[`SolutionNavCollapseButton renders 1`] = `
|
||||
<EuiButtonIcon
|
||||
aria-label="Collapse side navigation"
|
||||
className="kbnPageTemplateSolutionNavCollapseButton"
|
||||
className="kbnSolutionNavCollapseButton"
|
||||
color="text"
|
||||
iconType="menuLeft"
|
||||
size="s"
|
|
@ -1,23 +1,23 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`KibanaPageTemplateSolutionNav accepts EuiSideNavProps 1`] = `
|
||||
exports[`SolutionNav accepts EuiSideNavProps 1`] = `
|
||||
<Fragment>
|
||||
<EuiCollapsibleNavGroup
|
||||
background="none"
|
||||
className="kbnPageTemplateSolutionNav"
|
||||
className="kbnSolutionNav"
|
||||
initialIsOpen={false}
|
||||
isCollapsible={true}
|
||||
paddingSize="none"
|
||||
title={
|
||||
<EuiTitle
|
||||
id="KibanaPageTemplateSolutionNav_generated-id_heading"
|
||||
id="SolutionNav_generated-id_heading"
|
||||
size="xs"
|
||||
>
|
||||
<h2>
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
defaultMessage="{solutionName} {menuText}"
|
||||
id="sharedUXComponents.solutionNav.mobileTitleText"
|
||||
id="sharedUXPackages.solutionNav.mobileTitleText"
|
||||
values={
|
||||
Object {
|
||||
"menuText": "menu",
|
||||
|
@ -37,7 +37,7 @@ exports[`KibanaPageTemplateSolutionNav accepts EuiSideNavProps 1`] = `
|
|||
>
|
||||
<EuiSideNav
|
||||
aria-hidden={false}
|
||||
aria-labelledby="KibanaPageTemplateSolutionNav_generated-id_heading"
|
||||
aria-labelledby="SolutionNav_generated-id_heading"
|
||||
data-test-subj="DTS"
|
||||
items={
|
||||
Array [
|
||||
|
@ -100,24 +100,24 @@ exports[`KibanaPageTemplateSolutionNav accepts EuiSideNavProps 1`] = `
|
|||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`KibanaPageTemplateSolutionNav accepts canBeCollapsed prop 1`] = `
|
||||
exports[`SolutionNav accepts canBeCollapsed prop 1`] = `
|
||||
<Fragment>
|
||||
<EuiCollapsibleNavGroup
|
||||
background="none"
|
||||
className="kbnPageTemplateSolutionNav"
|
||||
className="kbnSolutionNav"
|
||||
initialIsOpen={false}
|
||||
isCollapsible={true}
|
||||
paddingSize="none"
|
||||
title={
|
||||
<EuiTitle
|
||||
id="KibanaPageTemplateSolutionNav_generated-id_heading"
|
||||
id="SolutionNav_generated-id_heading"
|
||||
size="xs"
|
||||
>
|
||||
<h2>
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
defaultMessage="{solutionName} {menuText}"
|
||||
id="sharedUXComponents.solutionNav.mobileTitleText"
|
||||
id="sharedUXPackages.solutionNav.mobileTitleText"
|
||||
values={
|
||||
Object {
|
||||
"menuText": "menu",
|
||||
|
@ -137,7 +137,7 @@ exports[`KibanaPageTemplateSolutionNav accepts canBeCollapsed prop 1`] = `
|
|||
>
|
||||
<EuiSideNav
|
||||
aria-hidden={false}
|
||||
aria-labelledby="KibanaPageTemplateSolutionNav_generated-id_heading"
|
||||
aria-labelledby="SolutionNav_generated-id_heading"
|
||||
items={
|
||||
Array [
|
||||
Object {
|
||||
|
@ -199,11 +199,110 @@ exports[`KibanaPageTemplateSolutionNav accepts canBeCollapsed prop 1`] = `
|
|||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`KibanaPageTemplateSolutionNav heading accepts more headingProps 1`] = `
|
||||
exports[`SolutionNav accepts canBeCollapsed prop 2`] = `
|
||||
<Fragment>
|
||||
<EuiCollapsibleNavGroup
|
||||
background="none"
|
||||
className="kbnPageTemplateSolutionNav"
|
||||
className="kbnSolutionNav"
|
||||
initialIsOpen={false}
|
||||
isCollapsible={false}
|
||||
paddingSize="none"
|
||||
title={
|
||||
<EuiTitle
|
||||
id="SolutionNav_generated-id_heading"
|
||||
size="xs"
|
||||
>
|
||||
<h2>
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
defaultMessage="{solutionName} {menuText}"
|
||||
id="sharedUXPackages.solutionNav.mobileTitleText"
|
||||
values={
|
||||
Object {
|
||||
"menuText": "menu",
|
||||
"solutionName": "Solution",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</strong>
|
||||
</h2>
|
||||
</EuiTitle>
|
||||
}
|
||||
titleElement="span"
|
||||
>
|
||||
<EuiPanel
|
||||
color="transparent"
|
||||
paddingSize="s"
|
||||
>
|
||||
<EuiSideNav
|
||||
aria-hidden={false}
|
||||
aria-labelledby="SolutionNav_generated-id_heading"
|
||||
items={
|
||||
Array [
|
||||
Object {
|
||||
"id": "1",
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "1.1",
|
||||
"items": undefined,
|
||||
"name": "Ingest Node Pipelines",
|
||||
"tabIndex": undefined,
|
||||
},
|
||||
Object {
|
||||
"id": "1.2",
|
||||
"items": undefined,
|
||||
"name": "Logstash Pipelines",
|
||||
"tabIndex": undefined,
|
||||
},
|
||||
Object {
|
||||
"id": "1.3",
|
||||
"items": undefined,
|
||||
"name": "Beats Central Management",
|
||||
"tabIndex": undefined,
|
||||
},
|
||||
],
|
||||
"name": "Ingest",
|
||||
"tabIndex": undefined,
|
||||
},
|
||||
Object {
|
||||
"id": "2",
|
||||
"items": Array [
|
||||
Object {
|
||||
"id": "2.1",
|
||||
"items": undefined,
|
||||
"name": "Index Management",
|
||||
"tabIndex": undefined,
|
||||
},
|
||||
Object {
|
||||
"id": "2.2",
|
||||
"items": undefined,
|
||||
"name": "Index Lifecycle Policies",
|
||||
"tabIndex": undefined,
|
||||
},
|
||||
Object {
|
||||
"id": "2.3",
|
||||
"items": undefined,
|
||||
"name": "Snapshot and Restore",
|
||||
"tabIndex": undefined,
|
||||
},
|
||||
],
|
||||
"name": "Data",
|
||||
"tabIndex": undefined,
|
||||
},
|
||||
]
|
||||
}
|
||||
mobileBreakpoints={Array []}
|
||||
/>
|
||||
</EuiPanel>
|
||||
</EuiCollapsibleNavGroup>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`SolutionNav heading accepts more headingProps 1`] = `
|
||||
<Fragment>
|
||||
<EuiCollapsibleNavGroup
|
||||
background="none"
|
||||
className="kbnSolutionNav"
|
||||
initialIsOpen={false}
|
||||
isCollapsible={true}
|
||||
paddingSize="none"
|
||||
|
@ -216,7 +315,7 @@ exports[`KibanaPageTemplateSolutionNav heading accepts more headingProps 1`] = `
|
|||
<strong>
|
||||
<FormattedMessage
|
||||
defaultMessage="{solutionName} {menuText}"
|
||||
id="sharedUXComponents.solutionNav.mobileTitleText"
|
||||
id="sharedUXPackages.solutionNav.mobileTitleText"
|
||||
values={
|
||||
Object {
|
||||
"menuText": "menu",
|
||||
|
@ -238,24 +337,24 @@ exports[`KibanaPageTemplateSolutionNav heading accepts more headingProps 1`] = `
|
|||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`KibanaPageTemplateSolutionNav renders 1`] = `
|
||||
exports[`SolutionNav renders 1`] = `
|
||||
<Fragment>
|
||||
<EuiCollapsibleNavGroup
|
||||
background="none"
|
||||
className="kbnPageTemplateSolutionNav"
|
||||
className="kbnSolutionNav"
|
||||
initialIsOpen={false}
|
||||
isCollapsible={true}
|
||||
paddingSize="none"
|
||||
title={
|
||||
<EuiTitle
|
||||
id="KibanaPageTemplateSolutionNav_generated-id_heading"
|
||||
id="SolutionNav_generated-id_heading"
|
||||
size="xs"
|
||||
>
|
||||
<h2>
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
defaultMessage="{solutionName} {menuText}"
|
||||
id="sharedUXComponents.solutionNav.mobileTitleText"
|
||||
id="sharedUXPackages.solutionNav.mobileTitleText"
|
||||
values={
|
||||
Object {
|
||||
"menuText": "menu",
|
||||
|
@ -275,7 +374,7 @@ exports[`KibanaPageTemplateSolutionNav renders 1`] = `
|
|||
>
|
||||
<EuiSideNav
|
||||
aria-hidden={false}
|
||||
aria-labelledby="KibanaPageTemplateSolutionNav_generated-id_heading"
|
||||
aria-labelledby="SolutionNav_generated-id_heading"
|
||||
items={
|
||||
Array [
|
||||
Object {
|
||||
|
@ -337,29 +436,29 @@ exports[`KibanaPageTemplateSolutionNav renders 1`] = `
|
|||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`KibanaPageTemplateSolutionNav renders with icon 1`] = `
|
||||
exports[`SolutionNav renders with icon 1`] = `
|
||||
<Fragment>
|
||||
<EuiCollapsibleNavGroup
|
||||
background="none"
|
||||
className="kbnPageTemplateSolutionNav"
|
||||
className="kbnSolutionNav"
|
||||
initialIsOpen={false}
|
||||
isCollapsible={true}
|
||||
paddingSize="none"
|
||||
title={
|
||||
<EuiTitle
|
||||
id="KibanaPageTemplateSolutionNav_generated-id_heading"
|
||||
id="SolutionNav_generated-id_heading"
|
||||
size="xs"
|
||||
>
|
||||
<h2>
|
||||
<KibanaSolutionAvatar
|
||||
className="kbnPageTemplateSolutionNav__avatar"
|
||||
className="kbnSolutionNav__avatar"
|
||||
iconType="logoElastic"
|
||||
name="Solution"
|
||||
/>
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
defaultMessage="{solutionName} {menuText}"
|
||||
id="sharedUXComponents.solutionNav.mobileTitleText"
|
||||
id="sharedUXPackages.solutionNav.mobileTitleText"
|
||||
values={
|
||||
Object {
|
||||
"menuText": "menu",
|
||||
|
@ -379,7 +478,7 @@ exports[`KibanaPageTemplateSolutionNav renders with icon 1`] = `
|
|||
>
|
||||
<EuiSideNav
|
||||
aria-hidden={false}
|
||||
aria-labelledby="KibanaPageTemplateSolutionNav_generated-id_heading"
|
||||
aria-labelledby="SolutionNav_generated-id_heading"
|
||||
items={
|
||||
Array [
|
||||
Object {
|
|
@ -3,7 +3,7 @@
|
|||
exports[`WithSolutionNav renders wrapped component 1`] = `
|
||||
<TestComponent
|
||||
pageSideBar={
|
||||
<KibanaPageTemplateSolutionNav
|
||||
<SolutionNav
|
||||
icon="logoKibana"
|
||||
isOpenOnDesktop={true}
|
||||
items={
|
||||
|
@ -52,7 +52,7 @@ exports[`WithSolutionNav renders wrapped component 1`] = `
|
|||
}
|
||||
pageSideBarProps={
|
||||
Object {
|
||||
"className": "kbnPageTemplate__pageSideBar",
|
||||
"className": "kbnSolutionNav__sidebar",
|
||||
"paddingSize": "none",
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ exports[`WithSolutionNav renders wrapped component 1`] = `
|
|||
exports[`WithSolutionNav with children 1`] = `
|
||||
<TestComponent
|
||||
pageSideBar={
|
||||
<KibanaPageTemplateSolutionNav
|
||||
<SolutionNav
|
||||
icon="logoKibana"
|
||||
isOpenOnDesktop={true}
|
||||
items={
|
||||
|
@ -111,7 +111,7 @@ exports[`WithSolutionNav with children 1`] = `
|
|||
}
|
||||
pageSideBarProps={
|
||||
Object {
|
||||
"className": "kbnPageTemplate__pageSideBar",
|
||||
"className": "kbnSolutionNav__sidebar",
|
||||
"paddingSize": "none",
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
.kbnPageTemplateSolutionNavCollapseButton {
|
||||
.kbnSolutionNavCollapseButton {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
left: 248px - $euiSize;
|
||||
|
@ -14,24 +14,24 @@
|
|||
transition-delay: 0s !important;
|
||||
}
|
||||
|
||||
.kbnPageTemplate__pageSideBar:hover &,
|
||||
.kbnSolutionNav__sidebar:hover &,
|
||||
&:hover,
|
||||
&:focus {
|
||||
opacity: 1;
|
||||
left: 248px - $euiSizeL;
|
||||
}
|
||||
|
||||
.kbnPageTemplate__pageSideBar:hover & {
|
||||
.kbnSolutionNav__sidebar:hover & {
|
||||
transition-delay: $euiAnimSpeedSlow * 2;
|
||||
}
|
||||
|
||||
&:not(&-isCollapsed) {
|
||||
background-color: $euiColorEmptyShade !important; // Override all states
|
||||
background-color: $euiColorEmptyShade !important; // Override all states
|
||||
}
|
||||
}
|
||||
|
||||
// Make the button take up the entire area of the collapsed navigation
|
||||
.kbnPageTemplateSolutionNavCollapseButton-isCollapsed {
|
||||
.kbnSolutionNavCollapseButton-isCollapsed {
|
||||
opacity: 1 !important;
|
||||
transition-delay: 0s !important;
|
||||
left: 0 !important;
|
|
@ -8,21 +8,21 @@
|
|||
|
||||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
import { KibanaPageTemplateSolutionNavCollapseButton } from './solution_nav_collapse_button';
|
||||
import { SolutionNavCollapseButton } from './collapse_button';
|
||||
|
||||
describe('KibanaPageTemplateSolutionNavCollapseButton', () => {
|
||||
describe('SolutionNavCollapseButton', () => {
|
||||
test('renders', () => {
|
||||
const component = shallow(<KibanaPageTemplateSolutionNavCollapseButton isCollapsed={false} />);
|
||||
const component = shallow(<SolutionNavCollapseButton isCollapsed={false} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
expect(component.find('.kbnPageTemplateSolutionNavCollapseButton').prop('title')).toBe(
|
||||
expect(component.find('.kbnSolutionNavCollapseButton').prop('title')).toBe(
|
||||
'Collapse side navigation'
|
||||
);
|
||||
});
|
||||
|
||||
test('isCollapsed', () => {
|
||||
const component = shallow(<KibanaPageTemplateSolutionNavCollapseButton isCollapsed={true} />);
|
||||
const component = shallow(<SolutionNavCollapseButton isCollapsed={true} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
expect(component.find('.kbnPageTemplateSolutionNavCollapseButton').prop('title')).toBe(
|
||||
expect(component.find('.kbnSolutionNavCollapseButton').prop('title')).toBe(
|
||||
'Open side navigation'
|
||||
);
|
||||
});
|
|
@ -5,7 +5,7 @@
|
|||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
import './solution_nav_collapse_button.scss';
|
||||
import './collapse_button.scss';
|
||||
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
@ -13,34 +13,33 @@ import classNames from 'classnames';
|
|||
import { EuiButtonIcon, EuiButtonIconPropsForButton } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export type KibanaPageTemplateSolutionNavCollapseButtonProps =
|
||||
Partial<EuiButtonIconPropsForButton> & {
|
||||
/**
|
||||
* Boolean state of current collapsed status
|
||||
*/
|
||||
isCollapsed: boolean;
|
||||
};
|
||||
export type SolutionNavCollapseButtonProps = Partial<EuiButtonIconPropsForButton> & {
|
||||
/**
|
||||
* Boolean state of current collapsed status
|
||||
*/
|
||||
isCollapsed: boolean;
|
||||
};
|
||||
|
||||
const collapseLabel = i18n.translate('sharedUXComponents.solutionNav.collapsibleLabel', {
|
||||
const collapseLabel = i18n.translate('sharedUXPackages.solutionNav.collapsibleLabel', {
|
||||
defaultMessage: 'Collapse side navigation',
|
||||
});
|
||||
|
||||
const openLabel = i18n.translate('sharedUXComponents.solutionNav.openLabel', {
|
||||
const openLabel = i18n.translate('sharedUXPackages.solutionNav.openLabel', {
|
||||
defaultMessage: 'Open side navigation',
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates the styled icon button for showing/hiding solution nav
|
||||
*/
|
||||
export const KibanaPageTemplateSolutionNavCollapseButton = ({
|
||||
export const SolutionNavCollapseButton = ({
|
||||
className,
|
||||
isCollapsed,
|
||||
...rest
|
||||
}: KibanaPageTemplateSolutionNavCollapseButtonProps) => {
|
||||
}: SolutionNavCollapseButtonProps) => {
|
||||
const classes = classNames(
|
||||
'kbnPageTemplateSolutionNavCollapseButton',
|
||||
'kbnSolutionNavCollapseButton',
|
||||
{
|
||||
'kbnPageTemplateSolutionNavCollapseButton-isCollapsed': isCollapsed,
|
||||
'kbnSolutionNavCollapseButton-isCollapsed': isCollapsed,
|
||||
},
|
||||
className
|
||||
);
|
|
@ -6,7 +6,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
export type { KibanaPageTemplateSolutionNavProps } from './solution_nav';
|
||||
export { KibanaPageTemplateSolutionNav } from './solution_nav';
|
||||
export type { KibanaPageTemplateSolutionNavCollapseButtonProps } from './solution_nav_collapse_button';
|
||||
export { KibanaPageTemplateSolutionNavCollapseButton } from './solution_nav_collapse_button';
|
||||
export { SolutionNav } from './solution_nav';
|
||||
export type { SolutionNavProps } from './solution_nav';
|
||||
|
||||
export { withSolutionNav } from './with_solution_nav';
|
|
@ -2,28 +2,28 @@ $euiSideNavEmphasizedBackgroundColor: transparentize($euiColorLightShade, .7);
|
|||
@import '@elastic/eui/src/components/side_nav/mixins';
|
||||
|
||||
// Put the page background color in the flyout version too
|
||||
.kbnPageTemplateSolutionNav__flyout {
|
||||
.kbnSolutionNav__flyout {
|
||||
background-color: $euiPageBackgroundColor;
|
||||
}
|
||||
|
||||
.kbnPageTemplateSolutionNav {
|
||||
.kbnSolutionNav {
|
||||
@include euiSideNavEmbellish;
|
||||
@include euiYScroll;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@include euiBreakpoint('m' ,'l', 'xl') {
|
||||
@include euiBreakpoint('m', 'l', 'xl') {
|
||||
width: 248px;
|
||||
padding: $euiSizeL;
|
||||
}
|
||||
|
||||
.kbnPageTemplateSolutionNav__avatar {
|
||||
.kbnSolutionNav__avatar {
|
||||
margin-right: $euiSize;
|
||||
}
|
||||
}
|
||||
|
||||
.kbnPageTemplateSolutionNav--hidden {
|
||||
.kbnSolutionNav--hidden {
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
|
|
@ -7,16 +7,17 @@
|
|||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { KibanaPageTemplateSolutionNav, KibanaPageTemplateSolutionNavProps } from './solution_nav';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import { SolutionNav as Component, SolutionNavProps } from './solution_nav';
|
||||
|
||||
export default {
|
||||
title: 'Page Template/Solution Nav/Solution Nav',
|
||||
title: 'Page Template',
|
||||
description: 'Solution-specific navigation for the sidebar',
|
||||
};
|
||||
|
||||
type Params = Pick<KibanaPageTemplateSolutionNavProps, 'name' | 'icon'>;
|
||||
type Params = Pick<SolutionNavProps, 'name' | 'icon'>;
|
||||
|
||||
const items: KibanaPageTemplateSolutionNavProps['items'] = [
|
||||
const items: SolutionNavProps['items'] = [
|
||||
{
|
||||
name: <div>Ingest</div>,
|
||||
id: '1',
|
||||
|
@ -55,11 +56,13 @@ const items: KibanaPageTemplateSolutionNavProps['items'] = [
|
|||
},
|
||||
];
|
||||
|
||||
export const PureComponent = (params: Params) => {
|
||||
return <KibanaPageTemplateSolutionNav items={items} isOpenOnDesktop={true} {...params} />;
|
||||
export const SolutionNav = (params: Params) => {
|
||||
return (
|
||||
<Component items={items} isOpenOnDesktop={true} {...params} onCollapse={action('onCollapse')} />
|
||||
);
|
||||
};
|
||||
|
||||
PureComponent.argTypes = {
|
||||
SolutionNav.argTypes = {
|
||||
name: {
|
||||
control: 'text',
|
||||
defaultValue: 'Kibana',
|
||||
|
@ -79,6 +82,6 @@ PureComponent.argTypes = {
|
|||
},
|
||||
};
|
||||
|
||||
PureComponent.parameters = {
|
||||
SolutionNav.parameters = {
|
||||
layout: 'fullscreen',
|
||||
};
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { KibanaPageTemplateSolutionNav, KibanaPageTemplateSolutionNavProps } from './solution_nav';
|
||||
import { SolutionNav, SolutionNavProps } from './solution_nav';
|
||||
|
||||
jest.mock('@elastic/eui', () => {
|
||||
const original = jest.requireActual('@elastic/eui');
|
||||
|
@ -20,7 +20,7 @@ jest.mock('@elastic/eui', () => {
|
|||
};
|
||||
});
|
||||
|
||||
const items: KibanaPageTemplateSolutionNavProps['items'] = [
|
||||
const items: SolutionNavProps['items'] = [
|
||||
{
|
||||
name: 'Ingest',
|
||||
id: '1',
|
||||
|
@ -59,14 +59,11 @@ const items: KibanaPageTemplateSolutionNavProps['items'] = [
|
|||
},
|
||||
];
|
||||
|
||||
describe('KibanaPageTemplateSolutionNav', () => {
|
||||
describe('SolutionNav', () => {
|
||||
describe('heading', () => {
|
||||
test('accepts more headingProps', () => {
|
||||
const component = shallow(
|
||||
<KibanaPageTemplateSolutionNav
|
||||
name="Solution"
|
||||
headingProps={{ id: 'testID', element: 'h3' }}
|
||||
/>
|
||||
<SolutionNav name="Solution" headingProps={{ id: 'testID', element: 'h3' }} />
|
||||
);
|
||||
|
||||
expect(component).toMatchSnapshot();
|
||||
|
@ -74,37 +71,37 @@ describe('KibanaPageTemplateSolutionNav', () => {
|
|||
});
|
||||
|
||||
test('renders', () => {
|
||||
const component = shallow(<KibanaPageTemplateSolutionNav name="Solution" items={items} />);
|
||||
const component = shallow(<SolutionNav name="Solution" items={items} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('renders with icon', () => {
|
||||
const component = shallow(
|
||||
<KibanaPageTemplateSolutionNav name="Solution" icon="logoElastic" items={items} />
|
||||
);
|
||||
const component = shallow(<SolutionNav name="Solution" icon="logoElastic" items={items} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('renders with children', () => {
|
||||
const component = shallow(
|
||||
<KibanaPageTemplateSolutionNav name="Solution" data-test-subj="DTS">
|
||||
<SolutionNav name="Solution" data-test-subj="DTS">
|
||||
<span id="dummy_component" />
|
||||
</KibanaPageTemplateSolutionNav>
|
||||
</SolutionNav>
|
||||
);
|
||||
expect(component.find('#dummy_component').length > 0).toBeTruthy();
|
||||
});
|
||||
|
||||
test('accepts EuiSideNavProps', () => {
|
||||
const component = shallow(
|
||||
<KibanaPageTemplateSolutionNav name="Solution" data-test-subj="DTS" items={items} />
|
||||
);
|
||||
const component = shallow(<SolutionNav name="Solution" data-test-subj="DTS" items={items} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('accepts canBeCollapsed prop', () => {
|
||||
const component = shallow(
|
||||
<KibanaPageTemplateSolutionNav name="Solution" canBeCollapsed={true} items={items} />
|
||||
const canBeCollapsed = shallow(
|
||||
<SolutionNav name="Solution" canBeCollapsed={true} items={items} />
|
||||
);
|
||||
expect(component).toMatchSnapshot();
|
||||
expect(canBeCollapsed).toMatchSnapshot();
|
||||
const noCollapse = shallow(
|
||||
<SolutionNav name="Solution" canBeCollapsed={false} items={items} />
|
||||
);
|
||||
expect(noCollapse).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
import './solution_nav.scss';
|
||||
|
||||
import React, { FunctionComponent, useState, useMemo } from 'react';
|
||||
import React, { FC, useState, useMemo } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
EuiAvatarProps,
|
||||
|
@ -27,12 +27,12 @@ import { FormattedMessage } from '@kbn/i18n-react';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { KibanaSolutionAvatar } from '@kbn/shared-ux-avatar-solution';
|
||||
|
||||
import { KibanaPageTemplateSolutionNavCollapseButton } from './solution_nav_collapse_button';
|
||||
import { SolutionNavCollapseButton } from './collapse_button';
|
||||
|
||||
export type KibanaPageTemplateSolutionNavProps = Omit<
|
||||
EuiSideNavProps<{}>,
|
||||
'children' | 'items' | 'heading'
|
||||
> & {
|
||||
/**
|
||||
* Props for the `SolutionNav` component.
|
||||
*/
|
||||
export type SolutionNavProps = Omit<EuiSideNavProps<{}>, 'children' | 'items' | 'heading'> & {
|
||||
/**
|
||||
* Name of the solution, i.e. "Observability"
|
||||
*/
|
||||
|
@ -58,6 +58,9 @@ export type KibanaPageTemplateSolutionNavProps = Omit<
|
|||
* Control the collapsed state
|
||||
*/
|
||||
isOpenOnDesktop?: boolean;
|
||||
/**
|
||||
* Handler for when the navigation flyout is collapsed.
|
||||
*/
|
||||
onCollapse?: () => void;
|
||||
/**
|
||||
* Allows hiding of the navigation by the user.
|
||||
|
@ -77,14 +80,12 @@ const setTabIndex = (items: Array<EuiSideNavItemType<{}>>, isHidden: boolean) =>
|
|||
});
|
||||
};
|
||||
|
||||
const generateId = htmlIdGenerator('KibanaPageTemplateSolutionNav');
|
||||
const generateId = htmlIdGenerator('SolutionNav');
|
||||
|
||||
/**
|
||||
* A wrapper around EuiSideNav but also creates the appropriate title with optional solution logo
|
||||
* A wrapper around `EuiSideNav` that includes the appropriate title with optional solution logo.
|
||||
*/
|
||||
export const KibanaPageTemplateSolutionNav: FunctionComponent<
|
||||
KibanaPageTemplateSolutionNavProps
|
||||
> = ({
|
||||
export const SolutionNav: FC<SolutionNavProps> = ({
|
||||
children,
|
||||
headingProps,
|
||||
icon,
|
||||
|
@ -101,7 +102,7 @@ export const KibanaPageTemplateSolutionNav: FunctionComponent<
|
|||
const isMediumBreakpoint = useIsWithinBreakpoints(['m']);
|
||||
const isLargerBreakpoint = useIsWithinBreakpoints(['l', 'xl']);
|
||||
|
||||
// This is used for both the EuiSideNav and EuiFlyout toggling
|
||||
// This is used for both the `EuiSideNav` and `EuiFlyout` toggling
|
||||
const [isSideNavOpenOnMobile, setIsSideNavOpenOnMobile] = useState(false);
|
||||
const toggleOpenOnMobile = () => {
|
||||
setIsSideNavOpenOnMobile(!isSideNavOpenOnMobile);
|
||||
|
@ -110,33 +111,28 @@ export const KibanaPageTemplateSolutionNav: FunctionComponent<
|
|||
const isHidden = isLargerBreakpoint && !isOpenOnDesktop && canBeCollapsed;
|
||||
const isCustomSideNav = !!children;
|
||||
|
||||
const sideNavClasses = classNames('kbnPageTemplateSolutionNav', {
|
||||
'kbnPageTemplateSolutionNav--hidden': isHidden,
|
||||
const sideNavClasses = classNames('kbnSolutionNav', {
|
||||
'kbnSolutionNav--hidden': isHidden,
|
||||
});
|
||||
|
||||
/**
|
||||
* Create the avatar and titles
|
||||
*/
|
||||
// Create the avatar and titles.
|
||||
const headingID = headingProps?.id || generateId('heading');
|
||||
const HeadingElement = headingProps?.element || 'h2';
|
||||
|
||||
const titleText = (
|
||||
<EuiTitle size="xs" id={headingID}>
|
||||
<HeadingElement>
|
||||
{icon && (
|
||||
<KibanaSolutionAvatar
|
||||
className="kbnPageTemplateSolutionNav__avatar"
|
||||
iconType={icon}
|
||||
name={name}
|
||||
/>
|
||||
<KibanaSolutionAvatar className="kbnSolutionNav__avatar" iconType={icon} name={name} />
|
||||
)}
|
||||
<strong>
|
||||
<FormattedMessage
|
||||
id="sharedUXComponents.solutionNav.mobileTitleText"
|
||||
id="sharedUXPackages.solutionNav.mobileTitleText"
|
||||
defaultMessage="{solutionName} {menuText}"
|
||||
values={{
|
||||
solutionName: name || 'Navigation',
|
||||
menuText: isSmallerBreakpoint
|
||||
? i18n.translate('sharedUXComponents.solutionNav.menuText', {
|
||||
? i18n.translate('sharedUXPackages.solutionNav.menuText', {
|
||||
defaultMessage: 'menu',
|
||||
})
|
||||
: '',
|
||||
|
@ -147,16 +143,16 @@ export const KibanaPageTemplateSolutionNav: FunctionComponent<
|
|||
</EuiTitle>
|
||||
);
|
||||
|
||||
/**
|
||||
* Create the side nav content
|
||||
*/
|
||||
// Create the side nav content
|
||||
const sideNavContent = useMemo(() => {
|
||||
if (isCustomSideNav) {
|
||||
return children;
|
||||
}
|
||||
|
||||
if (!items) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiSideNav
|
||||
aria-labelledby={headingID}
|
||||
|
@ -196,7 +192,7 @@ export const KibanaPageTemplateSolutionNav: FunctionComponent<
|
|||
side="left"
|
||||
size={FLYOUT_SIZE}
|
||||
closeButtonPosition={closeFlyoutButtonPosition}
|
||||
className="kbnPageTemplateSolutionNav__flyout"
|
||||
className="kbnSolutionNav__flyout"
|
||||
hideCloseButton={!canBeCollapsed}
|
||||
>
|
||||
<div className={sideNavClasses}>
|
||||
|
@ -207,10 +203,7 @@ export const KibanaPageTemplateSolutionNav: FunctionComponent<
|
|||
</EuiFlyout>
|
||||
)}
|
||||
{canBeCollapsed && (
|
||||
<KibanaPageTemplateSolutionNavCollapseButton
|
||||
isCollapsed={true}
|
||||
onClick={toggleOpenOnMobile}
|
||||
/>
|
||||
<SolutionNavCollapseButton isCollapsed={true} onClick={toggleOpenOnMobile} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
@ -222,10 +215,7 @@ export const KibanaPageTemplateSolutionNav: FunctionComponent<
|
|||
{sideNavContent}
|
||||
</div>
|
||||
{canBeCollapsed && (
|
||||
<KibanaPageTemplateSolutionNavCollapseButton
|
||||
isCollapsed={!isOpenOnDesktop}
|
||||
onClick={onCollapse}
|
||||
/>
|
||||
<SolutionNavCollapseButton isCollapsed={!isOpenOnDesktop} onClick={onCollapse} />
|
||||
)}
|
||||
</>
|
||||
)}
|
|
@ -1,4 +1,4 @@
|
|||
.kbnPageTemplate__pageSideBar {
|
||||
.kbnSolutionNav__sidebar {
|
||||
overflow: hidden;
|
||||
// Temporary hack till the sizing is changed directly in EUI
|
||||
min-width: 248px;
|
||||
|
@ -7,13 +7,11 @@
|
|||
transition: min-width $euiAnimSpeedFast $euiAnimSlightResistance;
|
||||
}
|
||||
|
||||
&.kbnPageTemplate__pageSideBar--shrink {
|
||||
&.kbnSolutionNav__sidebar--shrink {
|
||||
min-width: $euiSizeXXL;
|
||||
}
|
||||
|
||||
.kbnPageTemplate--centeredBody & {
|
||||
@include euiBreakpoint('m', 'l', 'xl') {
|
||||
border-right: $euiBorderThin;
|
||||
}
|
||||
border-right: $euiBorderThin;
|
||||
}
|
||||
}
|
|
@ -6,16 +6,17 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { shallow } from 'enzyme';
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { SolutionNavProps } from './solution_nav';
|
||||
import { withSolutionNav } from './with_solution_nav';
|
||||
import { KibanaPageTemplateSolutionNavProps } from './solution_nav';
|
||||
|
||||
const TestComponent = () => {
|
||||
return <div>This is a wrapped component</div>;
|
||||
};
|
||||
|
||||
const items: KibanaPageTemplateSolutionNavProps['items'] = [
|
||||
const items: SolutionNavProps['items'] = [
|
||||
{
|
||||
name: 'Ingest',
|
||||
id: '1',
|
|
@ -8,24 +8,34 @@
|
|||
|
||||
import React, { ComponentType, useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { useIsWithinBreakpoints } from '@elastic/eui';
|
||||
import { EuiPageSideBarProps } from '@elastic/eui/src/components/page/page_side_bar';
|
||||
import { KibanaPageTemplateSolutionNav, KibanaPageTemplateSolutionNavProps } from './solution_nav';
|
||||
import { KibanaPageTemplateProps } from './types';
|
||||
import { useIsWithinBreakpoints, EuiPageTemplateProps } from '@elastic/eui';
|
||||
import { SolutionNav, SolutionNavProps } from './solution_nav';
|
||||
|
||||
import './with_solution_nav.scss';
|
||||
|
||||
// https://reactjs.org/docs/higher-order-components.html#convention-wrap-the-display-name-for-easy-debugging
|
||||
function getDisplayName(Component: ComponentType<any>) {
|
||||
return Component.displayName || Component.name || 'UnnamedComponent';
|
||||
}
|
||||
|
||||
type SolutionNavProps = KibanaPageTemplateProps & {
|
||||
solutionNav: KibanaPageTemplateSolutionNavProps;
|
||||
type TemplateProps = Pick<
|
||||
EuiPageTemplateProps,
|
||||
'pageSideBar' | 'pageSideBarProps' | 'template' | 'children'
|
||||
>;
|
||||
|
||||
type ComponentProps = TemplateProps & {
|
||||
isEmptyState?: boolean;
|
||||
};
|
||||
|
||||
type Props<P> = P &
|
||||
ComponentProps & {
|
||||
solutionNav: SolutionNavProps;
|
||||
};
|
||||
|
||||
const SOLUTION_NAV_COLLAPSED_KEY = 'solutionNavIsCollapsed';
|
||||
|
||||
export const withSolutionNav = (WrappedComponent: ComponentType<KibanaPageTemplateProps>) => {
|
||||
const WithSolutionNav = (props: SolutionNavProps) => {
|
||||
export const withSolutionNav = <P extends ComponentProps>(WrappedComponent: ComponentType<P>) => {
|
||||
const WithSolutionNav = (props: Props<P>) => {
|
||||
const isMediumBreakpoint = useIsWithinBreakpoints(['m']);
|
||||
const isLargerBreakpoint = useIsWithinBreakpoints(['l', 'xl']);
|
||||
const [isSideNavOpenOnDesktop, setisSideNavOpenOnDesktop] = useState(
|
||||
|
@ -33,6 +43,7 @@ export const withSolutionNav = (WrappedComponent: ComponentType<KibanaPageTempla
|
|||
);
|
||||
const { solutionNav, ...propagatedProps } = props;
|
||||
const { children, isEmptyState, template } = propagatedProps;
|
||||
|
||||
const toggleOpenOnDesktop = () => {
|
||||
setisSideNavOpenOnDesktop(!isSideNavOpenOnDesktop);
|
||||
// Have to store it as the opposite of the default we want
|
||||
|
@ -42,9 +53,9 @@ export const withSolutionNav = (WrappedComponent: ComponentType<KibanaPageTempla
|
|||
// Default navigation to allow collapsing
|
||||
const { canBeCollapsed = true } = solutionNav;
|
||||
const sideBarClasses = classNames(
|
||||
'kbnPageTemplate__pageSideBar',
|
||||
'kbnSolutionNav__sidebar',
|
||||
{
|
||||
'kbnPageTemplate__pageSideBar--shrink':
|
||||
'kbnSolutionNav__sidebar--shrink':
|
||||
isMediumBreakpoint || (canBeCollapsed && isLargerBreakpoint && !isSideNavOpenOnDesktop),
|
||||
},
|
||||
props.pageSideBarProps?.className
|
||||
|
@ -53,20 +64,27 @@ export const withSolutionNav = (WrappedComponent: ComponentType<KibanaPageTempla
|
|||
const templateToUse = isEmptyState && !template ? 'centeredContent' : template;
|
||||
|
||||
const pageSideBar = (
|
||||
<KibanaPageTemplateSolutionNav
|
||||
<SolutionNav
|
||||
isOpenOnDesktop={isSideNavOpenOnDesktop}
|
||||
onCollapse={toggleOpenOnDesktop}
|
||||
{...solutionNav}
|
||||
/>
|
||||
);
|
||||
|
||||
const pageSideBarProps = {
|
||||
paddingSize: 'none',
|
||||
paddingSize: 'none' as 'none',
|
||||
...props.pageSideBarProps,
|
||||
className: sideBarClasses,
|
||||
} as EuiPageSideBarProps; // needed because for some reason 'none' is not recognized as a valid value for paddingSize
|
||||
};
|
||||
|
||||
return (
|
||||
<WrappedComponent
|
||||
{...{ ...propagatedProps, pageSideBar, pageSideBarProps, template: templateToUse }}
|
||||
{...{
|
||||
...(propagatedProps as P),
|
||||
pageSideBar,
|
||||
pageSideBarProps,
|
||||
template: templateToUse,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</WrappedComponent>
|
19
packages/shared-ux/page/solution_nav/tsconfig.json
Normal file
19
packages/shared-ux/page/solution_nav/tsconfig.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"extends": "../../../../tsconfig.bazel.json",
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"emitDeclarationOnly": true,
|
||||
"outDir": "target_types",
|
||||
"rootDir": "src",
|
||||
"stripInternal": false,
|
||||
"types": [
|
||||
"jest",
|
||||
"node",
|
||||
"react",
|
||||
"@kbn/ambient-ui-types"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
|
@ -12,6 +12,11 @@
|
|||
}
|
||||
|
||||
.kbnPageTemplate--centeredBody & {
|
||||
border-right: $euiBorderThin;
|
||||
border-bottom: $euiBorderThin;
|
||||
|
||||
@include euiBreakpoint('m', 'l', 'xl') {
|
||||
border-bottom: none;
|
||||
border-right: $euiBorderThin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ const tourStepsConfig: TourStep[] = [
|
|||
})}
|
||||
</EuiText>
|
||||
),
|
||||
anchor: `[id^="KibanaPageTemplateSolutionNav"]`,
|
||||
anchor: `[id^="SolutionNav"]`,
|
||||
anchorPosition: 'rightUp',
|
||||
dataTestSubj: 'overviewStep',
|
||||
showOverlay: true,
|
||||
|
|
|
@ -66,7 +66,7 @@ const StyledKibanaPageTemplate = styled(KibanaPageTemplate)<{
|
|||
$addBottomPadding &&
|
||||
`
|
||||
@media (min-width: 768px) {
|
||||
.kbnPageTemplateSolutionNav {
|
||||
.kbnSolutionNav {
|
||||
padding-bottom: ${gutterTimeline};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5568,10 +5568,10 @@
|
|||
"sharedUXComponents.noDataPage.intro": "Ajoutez vos données pour commencer, ou {link} sur {solution}.",
|
||||
"sharedUXComponents.noDataPage.intro.link": "en savoir plus",
|
||||
"sharedUXComponents.noDataPage.welcomeTitle": "Bienvenue dans Elastic {solution}.",
|
||||
"sharedUXComponents.solutionNav.collapsibleLabel": "Réduire la navigation latérale",
|
||||
"sharedUXComponents.solutionNav.menuText": "menu",
|
||||
"sharedUXComponents.solutionNav.mobileTitleText": "{solutionName} {menuText}",
|
||||
"sharedUXComponents.solutionNav.openLabel": "Ouvrir la navigation latérale",
|
||||
"sharedUXPackages.solutionNav.collapsibleLabel": "Réduire la navigation latérale",
|
||||
"sharedUXPackages.solutionNav.menuText": "menu",
|
||||
"sharedUXPackages.solutionNav.mobileTitleText": "{solutionName} {menuText}",
|
||||
"sharedUXPackages.solutionNav.openLabel": "Ouvrir la navigation latérale",
|
||||
"sharedUXPackages.exitFullScreenButton.exitFullScreenModeButtonText": "Quitter le plein écran",
|
||||
"sharedUXPackages.exitFullScreenButton.fullScreenModeDescription": "En mode Plein écran, appuyez sur Échap pour quitter.",
|
||||
"sharedUXPackages.noDataConfig.addIntegrationsDescription": "Utilisez Elastic Agent pour collecter des données et créer des solutions Analytics.",
|
||||
|
|
|
@ -5568,10 +5568,10 @@
|
|||
"sharedUXComponents.noDataPage.intro": "データを追加して開始するか、{solution}については{link}をご覧ください。",
|
||||
"sharedUXComponents.noDataPage.intro.link": "詳細",
|
||||
"sharedUXComponents.noDataPage.welcomeTitle": "Elastic {solution}へようこそ。",
|
||||
"sharedUXComponents.solutionNav.collapsibleLabel": "サイドナビゲーションを折りたたむ",
|
||||
"sharedUXComponents.solutionNav.menuText": "メニュー",
|
||||
"sharedUXComponents.solutionNav.mobileTitleText": "{solutionName} {menuText}",
|
||||
"sharedUXComponents.solutionNav.openLabel": "サイドナビゲーションを開く",
|
||||
"sharedUXPackages.solutionNav.collapsibleLabel": "サイドナビゲーションを折りたたむ",
|
||||
"sharedUXPackages.solutionNav.menuText": "メニュー",
|
||||
"sharedUXPackages.solutionNav.mobileTitleText": "{solutionName} {menuText}",
|
||||
"sharedUXPackages.solutionNav.openLabel": "サイドナビゲーションを開く",
|
||||
"sharedUXPackages.exitFullScreenButton.exitFullScreenModeButtonText": "全画面を終了",
|
||||
"sharedUXPackages.exitFullScreenButton.fullScreenModeDescription": "ESC キーで全画面モードを終了します。",
|
||||
"sharedUXPackages.noDataConfig.addIntegrationsDescription": "Elasticエージェントを使用して、データを収集し、分析ソリューションを構築します。",
|
||||
|
|
|
@ -5573,10 +5573,10 @@
|
|||
"sharedUXComponents.noDataPage.intro": "添加您的数据以开始,或{link}{solution}。",
|
||||
"sharedUXComponents.noDataPage.intro.link": "了解详情",
|
||||
"sharedUXComponents.noDataPage.welcomeTitle": "欢迎使用 Elastic {solution}!",
|
||||
"sharedUXComponents.solutionNav.collapsibleLabel": "折叠侧边导航",
|
||||
"sharedUXComponents.solutionNav.menuText": "菜单",
|
||||
"sharedUXComponents.solutionNav.mobileTitleText": "{solutionName} {menuText}",
|
||||
"sharedUXComponents.solutionNav.openLabel": "打开侧边导航",
|
||||
"sharedUXPackages.solutionNav.collapsibleLabel": "折叠侧边导航",
|
||||
"sharedUXPackages.solutionNav.menuText": "菜单",
|
||||
"sharedUXPackages.solutionNav.mobileTitleText": "{solutionName} {menuText}",
|
||||
"sharedUXPackages.solutionNav.openLabel": "打开侧边导航",
|
||||
"sharedUXPackages.exitFullScreenButton.exitFullScreenModeButtonText": "退出全屏",
|
||||
"sharedUXPackages.exitFullScreenButton.fullScreenModeDescription": "在全屏模式下,按 ESC 键可退出。",
|
||||
"sharedUXPackages.noDataConfig.addIntegrationsDescription": "使用 Elastic 代理收集数据并增建分析解决方案。",
|
||||
|
|
|
@ -3560,6 +3560,10 @@
|
|||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/shared-ux-page-solution-nav@link:bazel-bin/packages/shared-ux/page/solution_nav":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@kbn/shared-ux-prompt-no-data-views@link:bazel-bin/packages/shared-ux/prompt/no_data_views":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
@ -7139,6 +7143,10 @@
|
|||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@types/kbn__shared-ux-page-solution-nav@link:bazel-bin/packages/shared-ux/page/solution_nav/npm_module_types":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
||||
"@types/kbn__shared-ux-prompt-no-data-views@link:bazel-bin/packages/shared-ux/prompt/no_data_views/npm_module_types":
|
||||
version "0.0.0"
|
||||
uid ""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue