Remove deprecated EUI components in kibana_react (#166225)

## Summary

Closes https://github.com/elastic/kibana/issues/161422

In this PR:

- [x] Removes `KibanaPageTemplate` utilities from `kibana_react`
- [x] Migrates remaining users of `KibanaPageTemplate` from
`kibana_react` to the one from `@kbn/shared-ux-page-kibana-template`
- [x]
`src/plugins/home/public/application/components/tutorial_directory.js`
- [x]
`src/plugins/home/public/application/components/tutorial/tutorial.js`
  - [x] `x-pack/plugins/osquery/public/components/empty_state.tsx`

## Visual Changes

Below are the main visual differences this PR introduces.

Sample data page before:

<img width="1419" alt="Screenshot 2023-09-13 at 12 12 11"
src="cbad5bd2-9c51-486c-a48d-ac44a80cdbf7">

Sample data page now:

<img width="1456" alt="Screenshot 2023-09-13 at 12 12 18"
src="4118db78-89e8-41ed-a3d3-51a221dde857">

Tutorials page before:

<img width="1402" alt="Screenshot 2023-09-13 at 13 09 58"
src="b51af548-211a-4a59-9143-b82f2ff55678">

Tutorials page now:

<img width="1439" alt="Screenshot 2023-09-13 at 13 10 04"
src="f71590a3-7c3d-4f60-a460-47aacdfcbf09">

---------

Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Vadim Kibana 2023-09-25 16:04:28 +02:00 committed by GitHub
parent a71242686a
commit dfcf60ae33
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 159 additions and 1094 deletions

View file

@ -3,7 +3,7 @@
exports[`KibanaPageTemplate render basic template 1`] = `
<div
class="euiPageTemplate kbnPageTemplate emotion-euiPageOuter-row-grow"
style="min-block-size:max(0, 100vh);padding-block-start:0"
style="min-block-size:calc(100vh - var(--euiFixedHeadersOffset, 0));padding-block-start:0"
>
<main
class="emotion-euiPageInner"

View file

@ -11,7 +11,8 @@ exports[`KibanaPageTemplateInner isEmpty no pageHeader 1`] = `
exports[`KibanaPageTemplateInner isEmpty pageHeader & children 1`] = `
<_EuiPageTemplate
className="kbnPageTemplate"
minHeight={0}
grow={false}
minHeight="calc(100vh - var(--euiFixedHeadersOffset, 0))"
offset={0}
>
<_EuiPageHeader

View file

@ -68,7 +68,8 @@ export const KibanaPageTemplateInner: FC<Props> = ({
// the following props can be removed to allow the template to auto-handle
// the fixed header and banner heights.
offset={0}
minHeight={0}
minHeight={header ? 'calc(100vh - var(--euiFixedHeadersOffset, 0))' : 0}
grow={header ? false : undefined}
{...rest}
>
{sideBar}

View file

@ -1,160 +1,166 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`isCloudEnabled is false should not render instruction toggle when ON_PREM_ELASTIC_CLOUD instructions are not provided 1`] = `
<KibanaPageTemplate
<_KibanaPageTemplate
template="empty"
>
<div>
<InjectIntl(IntroductionUI)
basePath={
Object {
"prepend": [Function],
}
}
description="tutorial used to drive jest tests"
notices={null}
title="jest test tutorial"
/>
<EuiSpacer />
<InjectIntl(InstructionSetUi)
instructionVariants={
Array [
<_EuiPageSection>
<div>
<InjectIntl(IntroductionUI)
basePath={
Object {
"id": "platform id",
"instructions": Array [
Object {
"title": "onPrem instructions",
},
],
},
]
}
isCloudEnabled={false}
offset={1}
onStatusCheck={[Function]}
paramValues={Object {}}
replaceTemplateStrings={[Function]}
setParameter={[Function]}
statusCheckState="NOT_CHECKED"
title="Instruction title"
/>
</div>
</KibanaPageTemplate>
`;
exports[`isCloudEnabled is false should render ON_PREM instructions with instruction toggle 1`] = `
<KibanaPageTemplate
template="empty"
>
<div>
<InjectIntl(IntroductionUI)
basePath={
Object {
"prepend": [Function],
"prepend": [Function],
}
}
}
description="tutorial used to drive jest tests"
iconType="logoApache"
notices={null}
title="jest test tutorial"
/>
<EuiSpacer />
<EuiFormRow
describedByIds={Array []}
display="row"
hasChildLabel={true}
hasEmptyLabelSpace={false}
labelType="label"
>
<EuiButtonGroup
buttonSize="m"
color="text"
idSelected="onPrem"
isFullWidth={true}
legend="Deployment type"
onChange={[Function]}
options={
description="tutorial used to drive jest tests"
notices={null}
title="jest test tutorial"
/>
<EuiSpacer />
<InjectIntl(InstructionSetUi)
instructionVariants={
Array [
Object {
"data-test-subj": "selfManagedTutorial",
"id": "onPrem",
"label": "Self managed",
},
Object {
"data-test-subj": "onCloudTutorial",
"id": "onPremElasticCloud",
"label": "Elastic Cloud",
"id": "platform id",
"instructions": Array [
Object {
"title": "onPrem instructions",
},
],
},
]
}
isCloudEnabled={false}
offset={1}
onStatusCheck={[Function]}
paramValues={Object {}}
replaceTemplateStrings={[Function]}
setParameter={[Function]}
statusCheckState="NOT_CHECKED"
title="Instruction title"
/>
</EuiFormRow>
<EuiSpacer />
<InjectIntl(InstructionSetUi)
instructionVariants={
Array [
</div>
</_EuiPageSection>
</_KibanaPageTemplate>
`;
exports[`isCloudEnabled is false should render ON_PREM instructions with instruction toggle 1`] = `
<_KibanaPageTemplate
template="empty"
>
<_EuiPageSection>
<div>
<InjectIntl(IntroductionUI)
basePath={
Object {
"id": "platform id",
"instructions": Array [
"prepend": [Function],
}
}
description="tutorial used to drive jest tests"
iconType="logoApache"
notices={null}
title="jest test tutorial"
/>
<EuiSpacer />
<EuiFormRow
describedByIds={Array []}
display="row"
hasChildLabel={true}
hasEmptyLabelSpace={false}
labelType="label"
>
<EuiButtonGroup
buttonSize="m"
color="text"
idSelected="onPrem"
isFullWidth={true}
legend="Deployment type"
onChange={[Function]}
options={
Array [
Object {
"title": "onPrem instructions",
"data-test-subj": "selfManagedTutorial",
"id": "onPrem",
"label": "Self managed",
},
],
},
]
}
isCloudEnabled={false}
offset={1}
onStatusCheck={[Function]}
paramValues={Object {}}
replaceTemplateStrings={[Function]}
setParameter={[Function]}
statusCheckState="NOT_CHECKED"
title="Instruction title"
/>
</div>
</KibanaPageTemplate>
Object {
"data-test-subj": "onCloudTutorial",
"id": "onPremElasticCloud",
"label": "Elastic Cloud",
},
]
}
/>
</EuiFormRow>
<EuiSpacer />
<InjectIntl(InstructionSetUi)
instructionVariants={
Array [
Object {
"id": "platform id",
"instructions": Array [
Object {
"title": "onPrem instructions",
},
],
},
]
}
isCloudEnabled={false}
offset={1}
onStatusCheck={[Function]}
paramValues={Object {}}
replaceTemplateStrings={[Function]}
setParameter={[Function]}
statusCheckState="NOT_CHECKED"
title="Instruction title"
/>
</div>
</_EuiPageSection>
</_KibanaPageTemplate>
`;
exports[`should render ELASTIC_CLOUD instructions when isCloudEnabled is true 1`] = `
<KibanaPageTemplate
<_KibanaPageTemplate
template="empty"
>
<div>
<InjectIntl(IntroductionUI)
basePath={
Object {
"prepend": [Function],
}
}
description="tutorial used to drive jest tests"
iconType="logoApache"
notices={null}
title="jest test tutorial"
/>
<EuiSpacer />
<InjectIntl(InstructionSetUi)
instructionVariants={
Array [
<_EuiPageSection>
<div>
<InjectIntl(IntroductionUI)
basePath={
Object {
"id": "platform id",
"instructions": Array [
Object {
"title": "elasticCloud instructions",
},
],
},
]
}
isCloudEnabled={true}
offset={1}
onStatusCheck={[Function]}
paramValues={Object {}}
replaceTemplateStrings={[Function]}
setParameter={[Function]}
statusCheckState="NOT_CHECKED"
title="Instruction title"
/>
</div>
</KibanaPageTemplate>
"prepend": [Function],
}
}
description="tutorial used to drive jest tests"
iconType="logoApache"
notices={null}
title="jest test tutorial"
/>
<EuiSpacer />
<InjectIntl(InstructionSetUi)
instructionVariants={
Array [
Object {
"id": "platform id",
"instructions": Array [
Object {
"title": "elasticCloud instructions",
},
],
},
]
}
isCloudEnabled={true}
offset={1}
onStatusCheck={[Function]}
paramValues={Object {}}
replaceTemplateStrings={[Function]}
setParameter={[Function]}
statusCheckState="NOT_CHECKED"
title="Instruction title"
/>
</div>
</_EuiPageSection>
</_KibanaPageTemplate>
`;

View file

@ -18,7 +18,7 @@ import * as StatusCheckStates from './status_check_states';
import { injectI18n, FormattedMessage } from '@kbn/i18n-react';
import { i18n } from '@kbn/i18n';
import { getServices } from '../../kibana_services';
import { KibanaPageTemplate } from '@kbn/kibana-react-plugin/public';
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
const INSTRUCTIONS_TYPE = {
ELASTIC_CLOUD: 'elasticCloud',
@ -360,7 +360,7 @@ class TutorialUi extends React.Component {
render() {
let content;
if (this.state.notFound) {
content = (
return (
<KibanaPageTemplate
isEmptyState={true}
pageHeader={{
@ -435,7 +435,11 @@ class TutorialUi extends React.Component {
);
}
return <KibanaPageTemplate template="empty">{content}</KibanaPageTemplate>;
return (
<KibanaPageTemplate template="empty">
<KibanaPageTemplate.Section>{content}</KibanaPageTemplate.Section>
</KibanaPageTemplate>
);
}
}

View file

@ -16,7 +16,7 @@ import { SampleDataTab } from '@kbn/home-sample-data-tab';
import { i18n } from '@kbn/i18n';
import { Synopsis } from './synopsis';
import { getServices } from '../kibana_services';
import { KibanaPageTemplate } from '@kbn/kibana-react-plugin/public';
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
import { getTutorials } from '../load_tutorials';
const SAMPLE_DATA_TAB_ID = 'sampleData';
@ -257,7 +257,7 @@ class TutorialDirectoryUi extends React.Component {
rightSideItems: headerLinks ? [headerLinks] : [],
}}
>
{this.renderTabContent()}
<KibanaPageTemplate.Section>{this.renderTabContent()}</KibanaPageTemplate.Section>
</KibanaPageTemplate>
);
}

View file

@ -54,17 +54,13 @@ export { POSITIONS, WEIGHTS, TOOLBAR_BUTTON_SIZES, ToolbarButton } from './toolb
export { reactRouterNavigate, reactRouterOnClickHandler } from './react_router_navigate';
export type {
KibanaPageTemplateProps,
NoDataPageActions,
NoDataPageActionsProps,
NoDataPageProps,
ElasticAgentCardProps,
} from './page_template';
export {
KibanaPageTemplate,
KibanaPageTemplateSolutionNavAvatar,
NO_DATA_PAGE_MAX_WIDTH,
NO_DATA_PAGE_TEMPLATE_PROPS,
NO_DATA_RECOMMENDED,
NoDataPage,
ElasticAgentCard,

View file

@ -1,440 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`KibanaPageTemplate render basic template 1`] = `
<div
class="euiPage euiPageTemplate kbnPageTemplate emotion-euiPage-row-grow"
style="min-height:460px"
>
<div
class="euiPageBody emotion-euiPageBody"
>
<header
class="euiPageHeader emotion-euiPageHeader-l-border"
title="test"
>
<div
class="euiPageHeaderContent emotion-euiPageHeaderContent-l"
style="max-width:1200px"
>
<div
class="euiFlexGroup euiPageHeaderContent__top emotion-euiFlexGroup-responsive-l-flexStart-stretch-row"
>
<div
class="euiFlexItem emotion-euiFlexItem-grow-1"
>
<div
class="euiText emotion-euiText-constrainedWidth-m"
>
<p>
test
</p>
</div>
</div>
<div
class="euiFlexItem emotion-euiFlexItem-growZero"
>
<div
class="euiFlexGroup emotion-euiFlexGroup-wrap-l-flexStart-stretch-row"
>
<div
class="euiFlexItem emotion-euiFlexItem-growZero"
>
test
</div>
</div>
</div>
</div>
</div>
</header>
<div
class="euiPanel euiPanel--plain euiPageContent euiPageContent--borderRadiusNone emotion-euiPanel-grow-none-plain"
role="main"
>
<div
class="euiPageContentBody euiPageContentBody--paddingLarge euiPageContentBody--restrictWidth-default"
/>
</div>
</div>
</div>
`;
exports[`KibanaPageTemplate render custom empty prompt only 1`] = `
<KibanaPageTemplateInner
isEmptyState={true}
>
<EuiEmptyPrompt
title={
<h1>
custom test
</h1>
}
/>
</KibanaPageTemplateInner>
`;
exports[`KibanaPageTemplate render custom empty prompt with page header 1`] = `
<KibanaPageTemplateInner
isEmptyState={true}
pageHeader={
Object {
"description": "test",
"iconType": "test",
"rightSideItems": Array [
"test",
],
"title": "test",
}
}
>
<EuiEmptyPrompt
title={
<h1>
custom test
</h1>
}
/>
</KibanaPageTemplateInner>
`;
exports[`KibanaPageTemplate render default empty prompt 1`] = `
<KibanaPageTemplateInner
isEmptyState={true}
pageHeader={
Object {
"description": "test",
"iconType": "test",
"rightSideItems": Array [
"test",
],
"title": "test",
}
}
/>
`;
exports[`KibanaPageTemplate render noDataContent 1`] = `
<WithSolutionNavBar(NoDataConfigPage)
noDataConfig={
Object {
"actions": Object {
"beats": Object {},
"custom": Object {},
"elasticAgent": Object {},
},
"docsLink": "test",
"solution": "Elastic",
}
}
solutionNav={
Object {
"icon": "solution",
"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,
},
],
"name": "Solution",
}
}
/>
`;
exports[`KibanaPageTemplate render solutionNav 1`] = `
<div
class="euiPage euiPageTemplate kbnPageTemplate emotion-euiPage-row-grow"
style="min-height:460px"
>
<div
class="euiPageSideBar euiPageSideBar--sticky kbnPageTemplate__pageSideBar"
>
<nav
aria-hidden="false"
aria-labelledby="euiSideNav_generated-id_heading"
class="euiSideNav kbnPageTemplateSolutionNav"
>
<h2
class="euiTitle euiSideNav__heading emotion-euiTitle-xs"
id="euiSideNav_generated-id_heading"
>
<div
aria-label="Solution"
class="euiAvatar euiAvatar--m euiAvatar--user kbnPageTemplateSolutionNavAvatar emotion-euiAvatar-user-m-uppercase-plain"
role="img"
title="Solution"
>
<span
class="euiAvatar__icon"
data-euiicon-type="solution"
/>
</div>
<strong>
Solution
</strong>
</h2>
<div
class="euiSideNav__content euiSideNav__contentMobile-xs euiSideNav__contentMobile-s"
id="euiSideNav_generated-id_content"
>
<div
class="euiSideNavItem euiSideNavItem--root euiSideNavItem--hasChildItems"
>
<div
class="euiSideNavItemButton"
>
<span
class="euiSideNavItemButton__content"
>
<span
class="euiSideNavItemButton__label euiSideNavItemButton__label--truncated"
>
Ingest
</span>
</span>
</div>
<div
class="euiSideNavItem__items"
>
<div
class="euiSideNavItem euiSideNavItem--trunk"
>
<div
class="euiSideNavItemButton"
>
<span
class="euiSideNavItemButton__content"
>
<span
class="euiSideNavItemButton__label euiSideNavItemButton__label--truncated"
>
Ingest Node Pipelines
</span>
</span>
</div>
</div>
<div
class="euiSideNavItem euiSideNavItem--trunk"
>
<div
class="euiSideNavItemButton"
>
<span
class="euiSideNavItemButton__content"
>
<span
class="euiSideNavItemButton__label euiSideNavItemButton__label--truncated"
>
Logstash Pipelines
</span>
</span>
</div>
</div>
<div
class="euiSideNavItem euiSideNavItem--trunk"
>
<div
class="euiSideNavItemButton"
>
<span
class="euiSideNavItemButton__content"
>
<span
class="euiSideNavItemButton__label euiSideNavItemButton__label--truncated"
>
Beats Central Management
</span>
</span>
</div>
</div>
</div>
</div>
<div
class="euiSideNavItem euiSideNavItem--root euiSideNavItem--hasChildItems"
>
<div
class="euiSideNavItemButton"
>
<span
class="euiSideNavItemButton__content"
>
<span
class="euiSideNavItemButton__label euiSideNavItemButton__label--truncated"
>
Data
</span>
</span>
</div>
<div
class="euiSideNavItem__items"
>
<div
class="euiSideNavItem euiSideNavItem--trunk"
>
<div
class="euiSideNavItemButton"
>
<span
class="euiSideNavItemButton__content"
>
<span
class="euiSideNavItemButton__label euiSideNavItemButton__label--truncated"
>
Index Management
</span>
</span>
</div>
</div>
<div
class="euiSideNavItem euiSideNavItem--trunk"
>
<div
class="euiSideNavItemButton"
>
<span
class="euiSideNavItemButton__content"
>
<span
class="euiSideNavItemButton__label euiSideNavItemButton__label--truncated"
>
Index Lifecycle Policies
</span>
</span>
</div>
</div>
<div
class="euiSideNavItem euiSideNavItem--trunk"
>
<div
class="euiSideNavItemButton"
>
<span
class="euiSideNavItemButton__content"
>
<span
class="euiSideNavItemButton__label euiSideNavItemButton__label--truncated"
>
Snapshot and Restore
</span>
</span>
</div>
</div>
</div>
</div>
</div>
</nav>
<button
aria-label="Collapse side navigation"
class="euiButtonIcon kbnPageTemplateSolutionNavCollapseButton emotion-euiButtonIcon-s-empty-text"
title="Collapse side navigation"
type="button"
>
<span
aria-hidden="true"
class="euiButtonIcon__icon"
color="inherit"
data-euiicon-type="menuLeft"
/>
</button>
</div>
<div
class="euiPanel euiPanel--plain euiPageBody emotion-euiPanel-grow-none-plain-hasShadow-euiPageBody"
>
<div
class="euiPageBody emotion-euiPageBody-l"
>
<header
class="euiPageHeader emotion-euiPageHeader-headerMargin"
title="test"
>
<div
class="euiPageHeaderContent emotion-euiPageHeaderContent-border-l"
style="max-width:1200px"
>
<div
class="euiFlexGroup euiPageHeaderContent__top emotion-euiFlexGroup-responsive-l-flexStart-stretch-row"
>
<div
class="euiFlexItem emotion-euiFlexItem-grow-1"
>
<div
class="euiText emotion-euiText-constrainedWidth-m"
>
<p>
test
</p>
</div>
</div>
<div
class="euiFlexItem emotion-euiFlexItem-growZero"
>
<div
class="euiFlexGroup emotion-euiFlexGroup-wrap-l-flexStart-stretch-row"
>
<div
class="euiFlexItem emotion-euiFlexItem-growZero"
>
test
</div>
</div>
</div>
</div>
</div>
</header>
<div
class="euiPanel euiPanel--transparent euiPageContent euiPageContent--borderRadiusNone emotion-euiPanel-grow-none-transparent"
role="main"
>
<div
class="euiPageContentBody euiPageContentBody--restrictWidth-default"
/>
</div>
</div>
</div>
</div>
`;

View file

@ -6,9 +6,5 @@
* Side Public License, v 1.
*/
export type { KibanaPageTemplateProps } from './page_template';
export { KibanaPageTemplate } from './page_template';
export { KibanaPageTemplateSolutionNavAvatar, KibanaPageTemplateSolutionNav } from './solution_nav';
export * from './no_data_page';
export { withSolutionNav } from './with_solution_nav';
export { NO_DATA_PAGE_MAX_WIDTH, NO_DATA_PAGE_TEMPLATE_PROPS } from './util';

View file

@ -8,4 +8,3 @@
export * from './no_data_page';
export * from './no_data_card';
export * from './no_data_config_page';

View file

@ -1,9 +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 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 { NoDataConfigPage, NoDataConfigPageWithSolutionNavBar } from './no_data_config_page';

View file

@ -1,38 +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 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 { EuiPageTemplate_Deprecated as EuiPageTemplate } from '@elastic/eui';
import React from 'react';
import { NoDataPage } from '../no_data_page';
import { withSolutionNav } from '../../with_solution_nav';
import { KibanaPageTemplateProps } from '../../page_template';
import { getClasses, NO_DATA_PAGE_TEMPLATE_PROPS } from '../../util';
export const NoDataConfigPage = (props: KibanaPageTemplateProps) => {
const { className, noDataConfig, ...rest } = props;
if (!noDataConfig) {
return null;
}
const template = NO_DATA_PAGE_TEMPLATE_PROPS.template;
const classes = getClasses(template, className);
return (
<EuiPageTemplate
data-test-subj={props['data-test-subj']}
template={template}
className={classes}
{...rest}
{...NO_DATA_PAGE_TEMPLATE_PROPS}
>
<NoDataPage {...noDataConfig} />
</EuiPageTemplate>
);
};
export const NoDataConfigPageWithSolutionNavBar = withSolutionNav(NoDataConfigPage);

View file

@ -1,22 +0,0 @@
.kbnPageTemplate__pageSideBar {
overflow: hidden;
// Temporary hack till the sizing is changed directly in EUI
min-width: 248px;
@include euiCanAnimate {
transition: min-width $euiAnimSpeedFast $euiAnimSlightResistance;
}
&.kbnPageTemplate__pageSideBar--shrink {
min-width: $euiSizeXXL;
}
.kbnPageTemplate--centeredBody & {
border-bottom: $euiBorderThin;
@include euiBreakpoint('m', 'l', 'xl') {
border-bottom: none;
border-right: $euiBorderThin;
}
}
}

View file

@ -1,173 +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 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 React from 'react';
import { shallow, render } from 'enzyme';
import { KibanaPageTemplate, KibanaPageTemplateProps } from './page_template';
import { EuiEmptyPrompt } from '@elastic/eui';
import { KibanaPageTemplateSolutionNavProps } from './solution_nav';
const navItems: KibanaPageTemplateSolutionNavProps['items'] = [
{
name: 'Ingest',
id: '1',
items: [
{
name: 'Ingest Node Pipelines',
id: '1.1',
},
{
name: 'Logstash Pipelines',
id: '1.2',
},
{
name: 'Beats Central Management',
id: '1.3',
},
],
},
{
name: 'Data',
id: '2',
items: [
{
name: 'Index Management',
id: '2.1',
},
{
name: 'Index Lifecycle Policies',
id: '2.2',
},
{
name: 'Snapshot and Restore',
id: '2.3',
},
],
},
];
const noDataConfig: KibanaPageTemplateProps['noDataConfig'] = {
solution: 'Elastic',
actions: {
elasticAgent: {},
beats: {},
custom: {},
},
docsLink: 'test',
};
describe('KibanaPageTemplate', () => {
test('render default empty prompt', () => {
const component = shallow(
<KibanaPageTemplate
isEmptyState={true}
pageHeader={{
iconType: 'test',
title: 'test',
description: 'test',
rightSideItems: ['test'],
}}
/>
);
expect(component).toMatchSnapshot();
});
test('render custom empty prompt only', () => {
const component = shallow(
<KibanaPageTemplate isEmptyState={true}>
<EuiEmptyPrompt title={<h1>custom test</h1>} />
</KibanaPageTemplate>
);
expect(component).toMatchSnapshot();
});
test('render custom empty prompt with page header', () => {
const component = shallow(
<KibanaPageTemplate
isEmptyState={true}
pageHeader={{
iconType: 'test',
title: 'test',
description: 'test',
rightSideItems: ['test'],
}}
>
<EuiEmptyPrompt title={<h1>custom test</h1>} />
</KibanaPageTemplate>
);
expect(component).toMatchSnapshot();
});
test('render basic template', () => {
const component = render(
<KibanaPageTemplate
pageHeader={{
iconType: 'test',
title: 'test',
description: 'test',
rightSideItems: ['test'],
}}
/>
);
expect(component).toMatchSnapshot();
});
test('render solutionNav', () => {
const component = render(
<KibanaPageTemplate
pageHeader={{
iconType: 'test',
title: 'test',
description: 'test',
rightSideItems: ['test'],
}}
solutionNav={{
name: 'Solution',
icon: 'solution',
items: navItems,
}}
/>
);
expect(component).toMatchSnapshot();
expect(component.find('div.kbnPageTemplate__pageSideBar').length).toBe(1);
});
test('render noDataContent', () => {
const component = shallow(
<KibanaPageTemplate
pageHeader={{
iconType: 'test',
title: 'test',
description: 'test',
rightSideItems: ['test'],
}}
solutionNav={{
name: 'Solution',
icon: 'solution',
items: navItems,
}}
noDataConfig={noDataConfig}
/>
);
expect(component).toMatchSnapshot();
});
test('render sidebar classes', () => {
const component = shallow(
<KibanaPageTemplate
solutionNav={{
name: 'Solution',
icon: 'solution',
items: navItems,
}}
pageSideBarProps={{ className: 'customClass' }}
/>
);
expect(component.html().includes('kbnPageTemplate__pageSideBar customClass')).toBe(true);
});
});

View file

@ -1,98 +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 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 './page_template.scss';
import React, { FunctionComponent } from 'react';
import { EuiPageTemplateProps_Deprecated } from '@elastic/eui';
import { KibanaPageTemplateSolutionNavProps } from './solution_nav';
import {
NoDataPageProps,
NoDataConfigPage,
NoDataConfigPageWithSolutionNavBar,
} from './no_data_page';
import { KibanaPageTemplateInner, KibanaPageTemplateWithSolutionNav } from './page_template_inner';
/**
* A thin wrapper around EuiPageTemplate with a few Kibana specific additions
* @deprecated Use `KibanaPageTemplateProps` from `@kbn/shared-ux-page-kibana-template-types`.
*/
export type KibanaPageTemplateProps = EuiPageTemplateProps_Deprecated & {
/**
* Changes the template type depending on other props provided.
* With `pageHeader` only: Uses `centeredBody` and fills an EuiEmptyPrompt with `pageHeader` info.
* With `children` only: Uses `centeredBody`
* With `pageHeader` and `children`: Uses `centeredContent`
*/
isEmptyState?: boolean;
/**
* Quick creation of EuiSideNav. Hooks up mobile instance too
*/
solutionNav?: KibanaPageTemplateSolutionNavProps;
/**
* 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
*/
noDataConfig?: NoDataPageProps;
};
/** @deprecated Use `KibanaPageTemplate` from `@kbn/shared-ux-page-kibana-template`. */
export const KibanaPageTemplate: FunctionComponent<KibanaPageTemplateProps> = ({
template,
className,
children,
solutionNav,
noDataConfig,
...rest
}) => {
/**
* If passing the custom template of `noDataConfig`
*/
if (noDataConfig && solutionNav) {
return (
<NoDataConfigPageWithSolutionNavBar
data-test-subj={rest['data-test-subj']}
className={className}
noDataConfig={noDataConfig}
solutionNav={solutionNav}
/>
);
}
if (noDataConfig) {
return (
<NoDataConfigPage
data-test-subj={rest['data-test-subj']}
className={className}
noDataConfig={noDataConfig}
/>
);
}
if (solutionNav) {
return (
<KibanaPageTemplateWithSolutionNav
template={template}
className={className}
solutionNav={solutionNav}
children={children}
{...rest}
/>
);
}
return (
<KibanaPageTemplateInner
template={template}
className={className}
children={children}
{...rest}
/>
);
};

View file

@ -1,61 +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 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 React, { FunctionComponent } from 'react';
import { EuiEmptyPrompt, EuiPageTemplate_Deprecated as EuiPageTemplate } from '@elastic/eui';
import { withSolutionNav } from './with_solution_nav';
import { KibanaPageTemplateProps } from './page_template';
import { getClasses } from './util';
type Props = KibanaPageTemplateProps;
/**
* A thin wrapper around EuiPageTemplate with a few Kibana specific additions
*/
export const KibanaPageTemplateInner: FunctionComponent<Props> = ({
template,
className,
pageHeader,
children,
isEmptyState,
...rest
}) => {
/**
* An easy way to create the right content for empty pages
*/
const emptyStateDefaultTemplate = 'centeredBody';
if (isEmptyState && pageHeader && !children) {
template = template ?? emptyStateDefaultTemplate;
const { iconType, pageTitle, description, rightSideItems } = pageHeader;
pageHeader = undefined;
children = (
<EuiEmptyPrompt
iconType={iconType}
iconColor={''} // This is likely a solution or app logo, so keep it multi-color
title={pageTitle ? <h1>{pageTitle}</h1> : undefined}
body={description ? <p>{description}</p> : undefined}
actions={rightSideItems}
/>
);
} else if (isEmptyState && pageHeader && children) {
template = template ?? 'centeredContent';
} else if (isEmptyState && !pageHeader) {
template = template ?? emptyStateDefaultTemplate;
}
const classes = getClasses(template, className);
return (
<EuiPageTemplate template={template} className={classes} pageHeader={pageHeader} {...rest}>
{children}
</EuiPageTemplate>
);
};
export const KibanaPageTemplateWithSolutionNav = withSolutionNav(KibanaPageTemplateInner);

View file

@ -1,20 +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 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 { KibanaPageTemplateProps } from '../page_template';
export const NO_DATA_PAGE_MAX_WIDTH = 950;
export const NO_DATA_PAGE_TEMPLATE_PROPS: KibanaPageTemplateProps = {
restrictWidth: NO_DATA_PAGE_MAX_WIDTH,
template: 'centeredBody',
pageContentProps: {
hasShadow: false,
color: 'transparent',
},
};

View file

@ -7,4 +7,3 @@
*/
export { getClasses } from './presentation';
export * from './constants';

View file

@ -1,77 +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 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 React, { ComponentType, useState } from 'react';
import classNames from 'classnames';
import { useIsWithinBreakpoints } from '@elastic/eui';
import { EuiPageSideBarProps_Deprecated as EuiPageSideBarProps } from '@elastic/eui/src/components/page/page_side_bar';
import { KibanaPageTemplateSolutionNav, KibanaPageTemplateSolutionNavProps } from './solution_nav';
import { KibanaPageTemplateProps } from '.';
// 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;
};
const SOLUTION_NAV_COLLAPSED_KEY = 'solutionNavIsCollapsed';
export const withSolutionNav = (WrappedComponent: ComponentType<KibanaPageTemplateProps>) => {
const WithSolutionNav = (props: SolutionNavProps) => {
const isMediumBreakpoint = useIsWithinBreakpoints(['m']);
const isLargerBreakpoint = useIsWithinBreakpoints(['l', 'xl']);
const [isSideNavOpenOnDesktop, setisSideNavOpenOnDesktop] = useState(
!JSON.parse(String(localStorage.getItem(SOLUTION_NAV_COLLAPSED_KEY)))
);
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
localStorage.setItem(SOLUTION_NAV_COLLAPSED_KEY, JSON.stringify(isSideNavOpenOnDesktop));
};
const sideBarClasses = classNames(
'kbnPageTemplate__pageSideBar',
{
'kbnPageTemplate__pageSideBar--shrink':
isMediumBreakpoint || (isLargerBreakpoint && !isSideNavOpenOnDesktop),
},
props.pageSideBarProps?.className
);
const templateToUse = isEmptyState && !template ? 'centeredContent' : template;
const pageSideBar = (
<KibanaPageTemplateSolutionNav
isOpenOnDesktop={isSideNavOpenOnDesktop}
onCollapse={toggleOpenOnDesktop}
{...solutionNav}
/>
);
const pageSideBarProps = {
paddingSize: '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={pageSideBar}
pageSideBarProps={pageSideBarProps}
template={templateToUse}
>
{children}
</WrappedComponent>
);
};
WithSolutionNav.displayName = `WithSolutionNavBar(${getDisplayName(WrappedComponent)})`;
return WithSolutionNav;
};

View file

@ -9,7 +9,7 @@ import React, { useCallback, useMemo } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import { EuiButton } from '@elastic/eui';
import { KibanaPageTemplate } from '@kbn/kibana-react-plugin/public';
import { KibanaPageTemplate } from '@kbn/shared-ux-page-kibana-template';
import { INTEGRATIONS_PLUGIN_ID } from '@kbn/fleet-plugin/common';
import { pagePathGetters } from '@kbn/fleet-plugin/public';
import { isModifiedEvent, isLeftClickEvent, useKibana } from '../common/lib/kibana';

View file

@ -77,5 +77,6 @@
"@kbn/core-saved-objects-server",
"@kbn/monaco",
"@kbn/io-ts-utils",
"@kbn/shared-ux-page-kibana-template",
]
}