mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Management - New platform api (#52579)
* implement management new platform api
This commit is contained in:
parent
e1e1d964c6
commit
9282f19bf5
43 changed files with 1296 additions and 212 deletions
|
@ -28,7 +28,8 @@ import { I18nContext } from 'ui/i18n';
|
|||
import { uiModules } from 'ui/modules';
|
||||
import appTemplate from './app.html';
|
||||
import landingTemplate from './landing.html';
|
||||
import { management, SidebarNav, MANAGEMENT_BREADCRUMB } from 'ui/management';
|
||||
import { management, MANAGEMENT_BREADCRUMB } from 'ui/management';
|
||||
import { ManagementSidebarNav } from '../../../../../plugins/management/public';
|
||||
import {
|
||||
FeatureCatalogueRegistryProvider,
|
||||
FeatureCatalogueCategory,
|
||||
|
@ -42,6 +43,7 @@ import {
|
|||
EuiIcon,
|
||||
EuiHorizontalRule,
|
||||
} from '@elastic/eui';
|
||||
import { npStart } from 'ui/new_platform';
|
||||
|
||||
const SIDENAV_ID = 'management-sidenav';
|
||||
const LANDING_ID = 'management-landing';
|
||||
|
@ -102,7 +104,7 @@ export function updateLandingPage(version) {
|
|||
);
|
||||
}
|
||||
|
||||
export function updateSidebar(items, id) {
|
||||
export function updateSidebar(legacySections, id) {
|
||||
const node = document.getElementById(SIDENAV_ID);
|
||||
if (!node) {
|
||||
return;
|
||||
|
@ -110,7 +112,12 @@ export function updateSidebar(items, id) {
|
|||
|
||||
render(
|
||||
<I18nContext>
|
||||
<SidebarNav sections={items} selectedId={id} className="mgtSideNav" />
|
||||
<ManagementSidebarNav
|
||||
getSections={npStart.plugins.management.sections.getSectionsEnabled}
|
||||
legacySections={legacySections}
|
||||
selectedId={id}
|
||||
className="mgtSideNav"
|
||||
/>
|
||||
</I18nContext>,
|
||||
node
|
||||
);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
@import './saved_objects/index';
|
||||
@import './share/index';
|
||||
@import './style_compile/index';
|
||||
@import '../../../plugins/management/public/components/index';
|
||||
|
||||
// The following are prefixed with "vis"
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
@import './components/index';
|
|
@ -1,24 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Management filters and filters and maps section objects into SidebarNav items 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"data-test-subj": "activeSection",
|
||||
"href": undefined,
|
||||
"icon": null,
|
||||
"id": "activeSection",
|
||||
"isSelected": false,
|
||||
"items": Array [
|
||||
Object {
|
||||
"data-test-subj": "item",
|
||||
"href": undefined,
|
||||
"icon": null,
|
||||
"id": "item",
|
||||
"isSelected": false,
|
||||
"name": "item",
|
||||
},
|
||||
],
|
||||
"name": "activeSection",
|
||||
},
|
||||
]
|
||||
`;
|
|
@ -1,107 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { EuiIcon, EuiSideNav, IconType, EuiScreenReaderOnly } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { IndexedArray } from 'ui/indexed_array';
|
||||
|
||||
interface Subsection {
|
||||
disabled: boolean;
|
||||
visible: boolean;
|
||||
id: string;
|
||||
display: string;
|
||||
url?: string;
|
||||
icon?: IconType;
|
||||
}
|
||||
interface Section extends Subsection {
|
||||
visibleItems: IndexedArray<Subsection>;
|
||||
}
|
||||
|
||||
const sectionVisible = (section: Subsection) => !section.disabled && section.visible;
|
||||
const sectionToNav = (selectedId: string) => ({ display, id, url, icon }: Subsection) => ({
|
||||
id,
|
||||
name: display,
|
||||
icon: icon ? <EuiIcon type={icon} /> : null,
|
||||
isSelected: selectedId === id,
|
||||
href: url,
|
||||
'data-test-subj': id,
|
||||
});
|
||||
|
||||
export const sideNavItems = (sections: Section[], selectedId: string) =>
|
||||
sections
|
||||
.filter(sectionVisible)
|
||||
.filter(section => section.visibleItems.filter(sectionVisible).length)
|
||||
.map(section => ({
|
||||
items: section.visibleItems.filter(sectionVisible).map(sectionToNav(selectedId)),
|
||||
...sectionToNav(selectedId)(section),
|
||||
}));
|
||||
|
||||
interface SidebarNavProps {
|
||||
sections: Section[];
|
||||
selectedId: string;
|
||||
}
|
||||
|
||||
interface SidebarNavState {
|
||||
isSideNavOpenOnMobile: boolean;
|
||||
}
|
||||
|
||||
export class SidebarNav extends React.Component<SidebarNavProps, SidebarNavState> {
|
||||
constructor(props: SidebarNavProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isSideNavOpenOnMobile: false,
|
||||
};
|
||||
}
|
||||
|
||||
public render() {
|
||||
const HEADER_ID = 'management-nav-header';
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiScreenReaderOnly>
|
||||
<h2 id={HEADER_ID}>
|
||||
{i18n.translate('common.ui.management.nav.label', {
|
||||
defaultMessage: 'Management',
|
||||
})}
|
||||
</h2>
|
||||
</EuiScreenReaderOnly>
|
||||
<EuiSideNav
|
||||
aria-labelledby={HEADER_ID}
|
||||
mobileTitle={this.renderMobileTitle()}
|
||||
isOpenOnMobile={this.state.isSideNavOpenOnMobile}
|
||||
toggleOpenOnMobile={this.toggleOpenOnMobile}
|
||||
items={sideNavItems(this.props.sections, this.props.selectedId)}
|
||||
className="mgtSideBarNav"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
private renderMobileTitle() {
|
||||
return <FormattedMessage id="common.ui.management.nav.menu" defaultMessage="Management menu" />;
|
||||
}
|
||||
|
||||
private toggleOpenOnMobile = () => {
|
||||
this.setState({
|
||||
isSideNavOpenOnMobile: !this.state.isSideNavOpenOnMobile,
|
||||
});
|
||||
};
|
||||
}
|
|
@ -23,8 +23,6 @@ export {
|
|||
PAGE_FOOTER_COMPONENT,
|
||||
} from '../../../core_plugins/kibana/public/management/sections/settings/components/default_component_registry';
|
||||
export { registerSettingsComponent } from '../../../core_plugins/kibana/public/management/sections/settings/components/component_registry';
|
||||
export { SidebarNav } from './components';
|
||||
export { MANAGEMENT_BREADCRUMB } from './breadcrumbs';
|
||||
|
||||
import { npStart } from 'ui/new_platform';
|
||||
export const management = npStart.plugins.management.legacy;
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
"version": "kibana",
|
||||
"server": false,
|
||||
"ui": true,
|
||||
"requiredPlugins": []
|
||||
"requiredPlugins": ["kibana_legacy"]
|
||||
}
|
||||
|
|
11
src/plugins/management/public/__snapshots__/management_app.test.tsx.snap
generated
Normal file
11
src/plugins/management/public/__snapshots__/management_app.test.tsx.snap
generated
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Management app can mount and unmount 1`] = `
|
||||
<div>
|
||||
<div>
|
||||
Test App - Hello world!
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Management app can mount and unmount 2`] = `<div />`;
|
1
src/plugins/management/public/components/_index.scss
Normal file
1
src/plugins/management/public/components/_index.scss
Normal file
|
@ -0,0 +1 @@
|
|||
@import './management_sidebar_nav/index';
|
21
src/plugins/management/public/components/index.ts
Normal file
21
src/plugins/management/public/components/index.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export { ManagementSidebarNav } from './management_sidebar_nav';
|
||||
export { ManagementChrome } from './management_chrome';
|
|
@ -17,4 +17,4 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export { SidebarNav } from './sidebar_nav';
|
||||
export { ManagementChrome } from './management_chrome';
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import { EuiPage, EuiPageBody } from '@elastic/eui';
|
||||
import { I18nProvider } from '@kbn/i18n/react';
|
||||
import { ManagementSidebarNav } from '../management_sidebar_nav';
|
||||
import { LegacySection } from '../../types';
|
||||
import { ManagementSection } from '../../management_section';
|
||||
|
||||
interface Props {
|
||||
getSections: () => ManagementSection[];
|
||||
legacySections: LegacySection[];
|
||||
selectedId: string;
|
||||
onMounted: (element: HTMLDivElement) => void;
|
||||
}
|
||||
|
||||
export class ManagementChrome extends React.Component<Props> {
|
||||
private container = React.createRef<HTMLDivElement>();
|
||||
componentDidMount() {
|
||||
if (this.container.current) {
|
||||
this.props.onMounted(this.container.current);
|
||||
}
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<I18nProvider>
|
||||
<EuiPage>
|
||||
<ManagementSidebarNav
|
||||
getSections={this.props.getSections}
|
||||
legacySections={this.props.legacySections}
|
||||
selectedId={this.props.selectedId}
|
||||
/>
|
||||
<EuiPageBody>
|
||||
<div ref={this.container} />
|
||||
</EuiPageBody>
|
||||
</EuiPage>
|
||||
</I18nProvider>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Management adds legacy apps to existing SidebarNav sections 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"data-test-subj": "activeSection",
|
||||
"icon": null,
|
||||
"id": "activeSection",
|
||||
"items": Array [
|
||||
Object {
|
||||
"data-test-subj": "item",
|
||||
"href": undefined,
|
||||
"id": "item",
|
||||
"isSelected": false,
|
||||
"name": "item",
|
||||
"order": undefined,
|
||||
},
|
||||
],
|
||||
"name": "activeSection",
|
||||
"order": 10,
|
||||
},
|
||||
Object {
|
||||
"data-test-subj": "no-active-items",
|
||||
"icon": null,
|
||||
"id": "no-active-items",
|
||||
"items": Array [
|
||||
Object {
|
||||
"data-test-subj": "disabled",
|
||||
"href": undefined,
|
||||
"id": "disabled",
|
||||
"isSelected": false,
|
||||
"name": "disabled",
|
||||
"order": undefined,
|
||||
},
|
||||
Object {
|
||||
"data-test-subj": "notVisible",
|
||||
"href": undefined,
|
||||
"id": "notVisible",
|
||||
"isSelected": false,
|
||||
"name": "notVisible",
|
||||
"order": undefined,
|
||||
},
|
||||
],
|
||||
"name": "No active items",
|
||||
"order": 10,
|
||||
},
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`Management maps legacy sections and apps into SidebarNav items 1`] = `
|
||||
Array [
|
||||
Object {
|
||||
"data-test-subj": "no-active-items",
|
||||
"icon": null,
|
||||
"id": "no-active-items",
|
||||
"items": Array [
|
||||
Object {
|
||||
"data-test-subj": "disabled",
|
||||
"href": undefined,
|
||||
"id": "disabled",
|
||||
"isSelected": false,
|
||||
"name": "disabled",
|
||||
"order": undefined,
|
||||
},
|
||||
Object {
|
||||
"data-test-subj": "notVisible",
|
||||
"href": undefined,
|
||||
"id": "notVisible",
|
||||
"isSelected": false,
|
||||
"name": "notVisible",
|
||||
"order": undefined,
|
||||
},
|
||||
],
|
||||
"name": "No active items",
|
||||
"order": 10,
|
||||
},
|
||||
Object {
|
||||
"data-test-subj": "activeSection",
|
||||
"icon": null,
|
||||
"id": "activeSection",
|
||||
"items": Array [
|
||||
Object {
|
||||
"data-test-subj": "item",
|
||||
"href": undefined,
|
||||
"id": "item",
|
||||
"isSelected": false,
|
||||
"name": "item",
|
||||
"order": undefined,
|
||||
},
|
||||
],
|
||||
"name": "activeSection",
|
||||
"order": 10,
|
||||
},
|
||||
]
|
||||
`;
|
|
@ -1,4 +1,4 @@
|
|||
.mgtSidebarNav {
|
||||
.mgtSideBarNav {
|
||||
width: 192px;
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export { ManagementSidebarNav } from './management_sidebar_nav';
|
|
@ -17,8 +17,8 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { IndexedArray } from '../../indexed_array';
|
||||
import { sideNavItems } from '../components/sidebar_nav';
|
||||
import { IndexedArray } from '../../../../../legacy/ui/public/indexed_array';
|
||||
import { mergeLegacyItems } from './management_sidebar_nav';
|
||||
|
||||
const toIndexedArray = (initialSet: any[]) =>
|
||||
new IndexedArray({
|
||||
|
@ -30,30 +30,33 @@ const toIndexedArray = (initialSet: any[]) =>
|
|||
const activeProps = { visible: true, disabled: false };
|
||||
const disabledProps = { visible: true, disabled: true };
|
||||
const notVisibleProps = { visible: false, disabled: false };
|
||||
|
||||
const visibleItem = { display: 'item', id: 'item', ...activeProps };
|
||||
|
||||
const notVisibleSection = {
|
||||
display: 'Not visible',
|
||||
id: 'not-visible',
|
||||
order: 10,
|
||||
visibleItems: toIndexedArray([visibleItem]),
|
||||
...notVisibleProps,
|
||||
};
|
||||
const disabledSection = {
|
||||
display: 'Disabled',
|
||||
id: 'disabled',
|
||||
order: 10,
|
||||
visibleItems: toIndexedArray([visibleItem]),
|
||||
...disabledProps,
|
||||
};
|
||||
const noItemsSection = {
|
||||
display: 'No items',
|
||||
id: 'no-items',
|
||||
order: 10,
|
||||
visibleItems: toIndexedArray([]),
|
||||
...activeProps,
|
||||
};
|
||||
const noActiveItemsSection = {
|
||||
display: 'No active items',
|
||||
id: 'no-active-items',
|
||||
order: 10,
|
||||
visibleItems: toIndexedArray([
|
||||
{ display: 'disabled', id: 'disabled', ...disabledProps },
|
||||
{ display: 'notVisible', id: 'notVisible', ...notVisibleProps },
|
||||
|
@ -63,6 +66,7 @@ const noActiveItemsSection = {
|
|||
const activeSection = {
|
||||
display: 'activeSection',
|
||||
id: 'activeSection',
|
||||
order: 10,
|
||||
visibleItems: toIndexedArray([visibleItem]),
|
||||
...activeProps,
|
||||
};
|
||||
|
@ -76,7 +80,19 @@ const managementSections = [
|
|||
];
|
||||
|
||||
describe('Management', () => {
|
||||
it('filters and filters and maps section objects into SidebarNav items', () => {
|
||||
expect(sideNavItems(managementSections, 'active-item-id')).toMatchSnapshot();
|
||||
it('maps legacy sections and apps into SidebarNav items', () => {
|
||||
expect(mergeLegacyItems([], managementSections, 'active-item-id')).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('adds legacy apps to existing SidebarNav sections', () => {
|
||||
const navSection = {
|
||||
'data-test-subj': 'activeSection',
|
||||
icon: null,
|
||||
id: 'activeSection',
|
||||
items: [],
|
||||
name: 'activeSection',
|
||||
order: 10,
|
||||
};
|
||||
expect(mergeLegacyItems([navSection], managementSections, 'active-item-id')).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -0,0 +1,200 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
EuiIcon,
|
||||
// @ts-ignore
|
||||
EuiSideNav,
|
||||
EuiScreenReaderOnly,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import React from 'react';
|
||||
import { LegacySection, LegacyApp } from '../../types';
|
||||
import { ManagementApp } from '../../management_app';
|
||||
import { ManagementSection } from '../../management_section';
|
||||
|
||||
interface NavApp {
|
||||
id: string;
|
||||
name: string;
|
||||
[key: string]: unknown;
|
||||
order: number; // only needed while merging platform and legacy
|
||||
}
|
||||
|
||||
interface NavSection extends NavApp {
|
||||
items: NavApp[];
|
||||
}
|
||||
|
||||
interface ManagementSidebarNavProps {
|
||||
getSections: () => ManagementSection[];
|
||||
legacySections: LegacySection[];
|
||||
selectedId: string;
|
||||
}
|
||||
|
||||
interface ManagementSidebarNavState {
|
||||
isSideNavOpenOnMobile: boolean;
|
||||
}
|
||||
|
||||
const managementSectionOrAppToNav = (appOrSection: ManagementApp | ManagementSection) => ({
|
||||
id: appOrSection.id,
|
||||
name: appOrSection.title,
|
||||
'data-test-subj': appOrSection.id,
|
||||
order: appOrSection.order,
|
||||
});
|
||||
|
||||
const managementSectionToNavSection = (section: ManagementSection) => {
|
||||
const iconType = section.euiIconType
|
||||
? section.euiIconType
|
||||
: section.icon
|
||||
? section.icon
|
||||
: 'empty';
|
||||
|
||||
return {
|
||||
icon: <EuiIcon type={iconType} size="m" />,
|
||||
...managementSectionOrAppToNav(section),
|
||||
};
|
||||
};
|
||||
|
||||
const managementAppToNavItem = (selectedId?: string, parentId?: string) => (
|
||||
app: ManagementApp
|
||||
) => ({
|
||||
isSelected: selectedId === app.id,
|
||||
href: `#/management/${parentId}/${app.id}`,
|
||||
...managementSectionOrAppToNav(app),
|
||||
});
|
||||
|
||||
const legacySectionToNavSection = (section: LegacySection) => ({
|
||||
name: section.display,
|
||||
id: section.id,
|
||||
icon: section.icon ? <EuiIcon type={section.icon} /> : null,
|
||||
items: [],
|
||||
'data-test-subj': section.id,
|
||||
// @ts-ignore
|
||||
order: section.order,
|
||||
});
|
||||
|
||||
const legacyAppToNavItem = (app: LegacyApp, selectedId: string) => ({
|
||||
isSelected: selectedId === app.id,
|
||||
name: app.display,
|
||||
id: app.id,
|
||||
href: app.url,
|
||||
'data-test-subj': app.id,
|
||||
// @ts-ignore
|
||||
order: app.order,
|
||||
});
|
||||
|
||||
const sectionVisible = (section: LegacySection | LegacyApp) => !section.disabled && section.visible;
|
||||
|
||||
const sideNavItems = (sections: ManagementSection[], selectedId: string) =>
|
||||
sections.map(section => ({
|
||||
items: section.getAppsEnabled().map(managementAppToNavItem(selectedId, section.id)),
|
||||
...managementSectionToNavSection(section),
|
||||
}));
|
||||
|
||||
const findOrAddSection = (navItems: NavSection[], legacySection: LegacySection): NavSection => {
|
||||
const foundSection = navItems.find(sec => sec.id === legacySection.id);
|
||||
|
||||
if (foundSection) {
|
||||
return foundSection;
|
||||
} else {
|
||||
const newSection = legacySectionToNavSection(legacySection);
|
||||
navItems.push(newSection);
|
||||
navItems.sort((a: NavSection, b: NavSection) => a.order - b.order); // only needed while merging platform and legacy
|
||||
return newSection;
|
||||
}
|
||||
};
|
||||
|
||||
export const mergeLegacyItems = (
|
||||
navItems: NavSection[],
|
||||
legacySections: LegacySection[],
|
||||
selectedId: string
|
||||
) => {
|
||||
const filteredLegacySections = legacySections
|
||||
.filter(sectionVisible)
|
||||
.filter(section => section.visibleItems.length);
|
||||
|
||||
filteredLegacySections.forEach(legacySection => {
|
||||
const section = findOrAddSection(navItems, legacySection);
|
||||
legacySection.visibleItems.forEach(app => {
|
||||
section.items.push(legacyAppToNavItem(app, selectedId));
|
||||
return section.items.sort((a, b) => a.order - b.order);
|
||||
});
|
||||
});
|
||||
|
||||
return navItems;
|
||||
};
|
||||
|
||||
const sectionsToItems = (
|
||||
sections: ManagementSection[],
|
||||
legacySections: LegacySection[],
|
||||
selectedId: string
|
||||
) => {
|
||||
const navItems = sideNavItems(sections, selectedId);
|
||||
return mergeLegacyItems(navItems, legacySections, selectedId);
|
||||
};
|
||||
|
||||
export class ManagementSidebarNav extends React.Component<
|
||||
ManagementSidebarNavProps,
|
||||
ManagementSidebarNavState
|
||||
> {
|
||||
constructor(props: ManagementSidebarNavProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isSideNavOpenOnMobile: false,
|
||||
};
|
||||
}
|
||||
|
||||
public render() {
|
||||
const HEADER_ID = 'management-nav-header';
|
||||
|
||||
return (
|
||||
<>
|
||||
<EuiScreenReaderOnly>
|
||||
<h2 id={HEADER_ID}>
|
||||
{i18n.translate('management.nav.label', {
|
||||
defaultMessage: 'Management',
|
||||
})}
|
||||
</h2>
|
||||
</EuiScreenReaderOnly>
|
||||
<EuiSideNav
|
||||
aria-labelledby={HEADER_ID}
|
||||
mobileTitle={this.renderMobileTitle()}
|
||||
isOpenOnMobile={this.state.isSideNavOpenOnMobile}
|
||||
toggleOpenOnMobile={this.toggleOpenOnMobile}
|
||||
items={sectionsToItems(
|
||||
this.props.getSections(),
|
||||
this.props.legacySections,
|
||||
this.props.selectedId
|
||||
)}
|
||||
className="mgtSideBarNav"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
private renderMobileTitle() {
|
||||
return <FormattedMessage id="management.nav.menu" defaultMessage="Management menu" />;
|
||||
}
|
||||
|
||||
private toggleOpenOnMobile = () => {
|
||||
this.setState({
|
||||
isSideNavOpenOnMobile: !this.state.isSideNavOpenOnMobile,
|
||||
});
|
||||
};
|
||||
}
|
|
@ -24,4 +24,7 @@ export function plugin(initializerContext: PluginInitializerContext) {
|
|||
return new ManagementPlugin();
|
||||
}
|
||||
|
||||
export { ManagementStart } from './types';
|
||||
export { ManagementSetup, ManagementStart, RegisterManagementApp } from './types';
|
||||
export { ManagementApp } from './management_app';
|
||||
export { ManagementSection } from './management_section';
|
||||
export { ManagementSidebarNav } from './components'; // for use in legacy management apps
|
||||
|
|
|
@ -17,4 +17,5 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export { management } from './sections_register';
|
||||
export { LegacyManagementAdapter } from './sections_register';
|
||||
export { LegacyManagementSection } from './section';
|
||||
|
|
|
@ -22,7 +22,7 @@ import { IndexedArray } from '../../../../legacy/ui/public/indexed_array';
|
|||
|
||||
const listeners = [];
|
||||
|
||||
export class ManagementSection {
|
||||
export class LegacyManagementSection {
|
||||
/**
|
||||
* @param {string} id
|
||||
* @param {object} options
|
||||
|
@ -83,7 +83,11 @@ export class ManagementSection {
|
|||
*/
|
||||
|
||||
register(id, options = {}) {
|
||||
const item = new ManagementSection(id, assign(options, { parent: this }), this.capabilities);
|
||||
const item = new LegacyManagementSection(
|
||||
id,
|
||||
assign(options, { parent: this }),
|
||||
this.capabilities
|
||||
);
|
||||
|
||||
if (this.hasItem(id)) {
|
||||
throw new Error(`'${id}' is already registered`);
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { ManagementSection } from './section';
|
||||
import { LegacyManagementSection } from './section';
|
||||
import { IndexedArray } from '../../../../legacy/ui/public/indexed_array';
|
||||
|
||||
const capabilitiesMock = {
|
||||
|
@ -29,42 +29,42 @@ const capabilitiesMock = {
|
|||
describe('ManagementSection', () => {
|
||||
describe('constructor', () => {
|
||||
it('defaults display to id', () => {
|
||||
const section = new ManagementSection('kibana', {}, capabilitiesMock);
|
||||
const section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
|
||||
expect(section.display).toBe('kibana');
|
||||
});
|
||||
|
||||
it('defaults visible to true', () => {
|
||||
const section = new ManagementSection('kibana', {}, capabilitiesMock);
|
||||
const section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
|
||||
expect(section.visible).toBe(true);
|
||||
});
|
||||
|
||||
it('defaults disabled to false', () => {
|
||||
const section = new ManagementSection('kibana', {}, capabilitiesMock);
|
||||
const section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
|
||||
expect(section.disabled).toBe(false);
|
||||
});
|
||||
|
||||
it('defaults tooltip to empty string', () => {
|
||||
const section = new ManagementSection('kibana', {}, capabilitiesMock);
|
||||
const section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
|
||||
expect(section.tooltip).toBe('');
|
||||
});
|
||||
|
||||
it('defaults url to empty string', () => {
|
||||
const section = new ManagementSection('kibana', {}, capabilitiesMock);
|
||||
const section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
|
||||
expect(section.url).toBe('');
|
||||
});
|
||||
|
||||
it('exposes items', () => {
|
||||
const section = new ManagementSection('kibana', {}, capabilitiesMock);
|
||||
const section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
|
||||
expect(section.items).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('exposes visibleItems', () => {
|
||||
const section = new ManagementSection('kibana', {}, capabilitiesMock);
|
||||
const section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
|
||||
expect(section.visibleItems).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('assigns all options', () => {
|
||||
const section = new ManagementSection(
|
||||
const section = new LegacyManagementSection(
|
||||
'kibana',
|
||||
{ description: 'test', url: 'foobar' },
|
||||
capabilitiesMock
|
||||
|
@ -78,11 +78,11 @@ describe('ManagementSection', () => {
|
|||
let section;
|
||||
|
||||
beforeEach(() => {
|
||||
section = new ManagementSection('kibana', {}, capabilitiesMock);
|
||||
section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
|
||||
});
|
||||
|
||||
it('returns a ManagementSection', () => {
|
||||
expect(section.register('about')).toBeInstanceOf(ManagementSection);
|
||||
expect(section.register('about')).toBeInstanceOf(LegacyManagementSection);
|
||||
});
|
||||
|
||||
it('provides a reference to the parent', () => {
|
||||
|
@ -93,7 +93,7 @@ describe('ManagementSection', () => {
|
|||
section.register('about', { description: 'test' });
|
||||
|
||||
expect(section.items).toHaveLength(1);
|
||||
expect(section.items[0]).toBeInstanceOf(ManagementSection);
|
||||
expect(section.items[0]).toBeInstanceOf(LegacyManagementSection);
|
||||
expect(section.items[0].id).toBe('about');
|
||||
});
|
||||
|
||||
|
@ -126,7 +126,7 @@ describe('ManagementSection', () => {
|
|||
let section;
|
||||
|
||||
beforeEach(() => {
|
||||
section = new ManagementSection('kibana', {}, capabilitiesMock);
|
||||
section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
|
||||
section.register('about');
|
||||
});
|
||||
|
||||
|
@ -157,12 +157,12 @@ describe('ManagementSection', () => {
|
|||
let section;
|
||||
|
||||
beforeEach(() => {
|
||||
section = new ManagementSection('kibana', {}, capabilitiesMock);
|
||||
section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
|
||||
section.register('about');
|
||||
});
|
||||
|
||||
it('returns registered section', () => {
|
||||
expect(section.getSection('about')).toBeInstanceOf(ManagementSection);
|
||||
expect(section.getSection('about')).toBeInstanceOf(LegacyManagementSection);
|
||||
});
|
||||
|
||||
it('returns undefined if un-registered', () => {
|
||||
|
@ -171,7 +171,7 @@ describe('ManagementSection', () => {
|
|||
|
||||
it('returns sub-sections specified via a /-separated path', () => {
|
||||
section.getSection('about').register('time');
|
||||
expect(section.getSection('about/time')).toBeInstanceOf(ManagementSection);
|
||||
expect(section.getSection('about/time')).toBeInstanceOf(LegacyManagementSection);
|
||||
expect(section.getSection('about/time')).toBe(section.getSection('about').getSection('time'));
|
||||
});
|
||||
|
||||
|
@ -184,7 +184,7 @@ describe('ManagementSection', () => {
|
|||
let section;
|
||||
|
||||
beforeEach(() => {
|
||||
section = new ManagementSection('kibana', {}, capabilitiesMock);
|
||||
section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
|
||||
|
||||
section.register('three', { order: 3 });
|
||||
section.register('one', { order: 1 });
|
||||
|
@ -214,7 +214,7 @@ describe('ManagementSection', () => {
|
|||
let section;
|
||||
|
||||
beforeEach(() => {
|
||||
section = new ManagementSection('kibana', {}, capabilitiesMock);
|
||||
section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
|
||||
});
|
||||
|
||||
it('hide sets visible to false', () => {
|
||||
|
@ -233,7 +233,7 @@ describe('ManagementSection', () => {
|
|||
let section;
|
||||
|
||||
beforeEach(() => {
|
||||
section = new ManagementSection('kibana', {}, capabilitiesMock);
|
||||
section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
|
||||
});
|
||||
|
||||
it('disable sets disabled to true', () => {
|
||||
|
@ -251,7 +251,7 @@ describe('ManagementSection', () => {
|
|||
let section;
|
||||
|
||||
beforeEach(() => {
|
||||
section = new ManagementSection('kibana', {}, capabilitiesMock);
|
||||
section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
|
||||
|
||||
section.register('three', { order: 3 });
|
||||
section.register('one', { order: 1 });
|
||||
|
|
|
@ -17,44 +17,48 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { ManagementSection } from './section';
|
||||
import { LegacyManagementSection } from './section';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export const management = capabilities => {
|
||||
const main = new ManagementSection(
|
||||
'management',
|
||||
{
|
||||
display: i18n.translate('management.displayName', {
|
||||
defaultMessage: 'Management',
|
||||
export class LegacyManagementAdapter {
|
||||
main = undefined;
|
||||
init = capabilities => {
|
||||
this.main = new LegacyManagementSection(
|
||||
'management',
|
||||
{
|
||||
display: i18n.translate('management.displayName', {
|
||||
defaultMessage: 'Management',
|
||||
}),
|
||||
},
|
||||
capabilities
|
||||
);
|
||||
|
||||
this.main.register('data', {
|
||||
display: i18n.translate('management.connectDataDisplayName', {
|
||||
defaultMessage: 'Connect Data',
|
||||
}),
|
||||
},
|
||||
capabilities
|
||||
);
|
||||
order: 0,
|
||||
});
|
||||
|
||||
main.register('data', {
|
||||
display: i18n.translate('management.connectDataDisplayName', {
|
||||
defaultMessage: 'Connect Data',
|
||||
}),
|
||||
order: 0,
|
||||
});
|
||||
this.main.register('elasticsearch', {
|
||||
display: 'Elasticsearch',
|
||||
order: 20,
|
||||
icon: 'logoElasticsearch',
|
||||
});
|
||||
|
||||
main.register('elasticsearch', {
|
||||
display: 'Elasticsearch',
|
||||
order: 20,
|
||||
icon: 'logoElasticsearch',
|
||||
});
|
||||
this.main.register('kibana', {
|
||||
display: 'Kibana',
|
||||
order: 30,
|
||||
icon: 'logoKibana',
|
||||
});
|
||||
|
||||
main.register('kibana', {
|
||||
display: 'Kibana',
|
||||
order: 30,
|
||||
icon: 'logoKibana',
|
||||
});
|
||||
this.main.register('logstash', {
|
||||
display: 'Logstash',
|
||||
order: 30,
|
||||
icon: 'logoLogstash',
|
||||
});
|
||||
|
||||
main.register('logstash', {
|
||||
display: 'Logstash',
|
||||
order: 30,
|
||||
icon: 'logoLogstash',
|
||||
});
|
||||
|
||||
return main;
|
||||
};
|
||||
return this.main;
|
||||
};
|
||||
getManagement = () => this.main;
|
||||
}
|
||||
|
|
66
src/plugins/management/public/management_app.test.tsx
Normal file
66
src/plugins/management/public/management_app.test.tsx
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import { coreMock } from '../../../core/public/mocks';
|
||||
|
||||
import { ManagementApp } from './management_app';
|
||||
// @ts-ignore
|
||||
import { LegacyManagementSection } from './legacy';
|
||||
|
||||
function createTestApp() {
|
||||
const legacySection = new LegacyManagementSection('legacy');
|
||||
return new ManagementApp(
|
||||
{
|
||||
id: 'test-app',
|
||||
title: 'Test App',
|
||||
basePath: '',
|
||||
mount(params) {
|
||||
params.setBreadcrumbs([{ text: 'Test App' }]);
|
||||
ReactDOM.render(<div>Test App - Hello world!</div>, params.element);
|
||||
|
||||
return () => {
|
||||
ReactDOM.unmountComponentAtNode(params.element);
|
||||
};
|
||||
},
|
||||
},
|
||||
() => [],
|
||||
jest.fn(),
|
||||
() => legacySection,
|
||||
coreMock.createSetup().getStartServices
|
||||
);
|
||||
}
|
||||
|
||||
test('Management app can mount and unmount', async () => {
|
||||
const testApp = createTestApp();
|
||||
const container = document.createElement('div');
|
||||
document.body.appendChild(container);
|
||||
const unmount = testApp.mount({ element: container, basePath: '', setBreadcrumbs: jest.fn() });
|
||||
expect(container).toMatchSnapshot();
|
||||
(await unmount)();
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('Enabled by default, can disable', () => {
|
||||
const testApp = createTestApp();
|
||||
expect(testApp.enabled).toBe(true);
|
||||
testApp.disable();
|
||||
expect(testApp.enabled).toBe(false);
|
||||
});
|
102
src/plugins/management/public/management_app.tsx
Normal file
102
src/plugins/management/public/management_app.tsx
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { CreateManagementApp, ManagementSectionMount, Unmount } from './types';
|
||||
import { KibanaLegacySetup } from '../../kibana_legacy/public';
|
||||
// @ts-ignore
|
||||
import { LegacyManagementSection } from './legacy';
|
||||
import { ManagementChrome } from './components';
|
||||
import { ManagementSection } from './management_section';
|
||||
import { ChromeBreadcrumb, CoreSetup } from '../../../core/public/';
|
||||
|
||||
export class ManagementApp {
|
||||
readonly id: string;
|
||||
readonly title: string;
|
||||
readonly basePath: string;
|
||||
readonly order: number;
|
||||
readonly mount: ManagementSectionMount;
|
||||
protected enabledStatus: boolean = true;
|
||||
|
||||
constructor(
|
||||
{ id, title, basePath, order = 100, mount }: CreateManagementApp,
|
||||
getSections: () => ManagementSection[],
|
||||
registerLegacyApp: KibanaLegacySetup['registerLegacyApp'],
|
||||
getLegacyManagementSections: () => LegacyManagementSection,
|
||||
getStartServices: CoreSetup['getStartServices']
|
||||
) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.basePath = basePath;
|
||||
this.order = order;
|
||||
this.mount = mount;
|
||||
|
||||
registerLegacyApp({
|
||||
id: basePath.substr(1), // get rid of initial slash
|
||||
title,
|
||||
mount: async ({}, params) => {
|
||||
let appUnmount: Unmount;
|
||||
async function setBreadcrumbs(crumbs: ChromeBreadcrumb[]) {
|
||||
const [coreStart] = await getStartServices();
|
||||
coreStart.chrome.setBreadcrumbs([
|
||||
{
|
||||
text: i18n.translate('management.breadcrumb', {
|
||||
defaultMessage: 'Management',
|
||||
}),
|
||||
href: '#/management',
|
||||
},
|
||||
...crumbs,
|
||||
]);
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<ManagementChrome
|
||||
getSections={getSections}
|
||||
selectedId={id}
|
||||
legacySections={getLegacyManagementSections().items}
|
||||
onMounted={async element => {
|
||||
appUnmount = await mount({
|
||||
basePath,
|
||||
element,
|
||||
setBreadcrumbs,
|
||||
});
|
||||
}}
|
||||
/>,
|
||||
params.element
|
||||
);
|
||||
|
||||
return async () => {
|
||||
appUnmount();
|
||||
ReactDOM.unmountComponentAtNode(params.element);
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
public enable() {
|
||||
this.enabledStatus = true;
|
||||
}
|
||||
public disable() {
|
||||
this.enabledStatus = false;
|
||||
}
|
||||
public get enabled() {
|
||||
return this.enabledStatus;
|
||||
}
|
||||
}
|
65
src/plugins/management/public/management_section.test.ts
Normal file
65
src/plugins/management/public/management_section.test.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { ManagementSection } from './management_section';
|
||||
// @ts-ignore
|
||||
import { LegacyManagementSection } from './legacy';
|
||||
import { coreMock } from '../../../core/public/mocks';
|
||||
|
||||
function createSection(registerLegacyApp: () => void) {
|
||||
const legacySection = new LegacyManagementSection('legacy');
|
||||
const getLegacySection = () => legacySection;
|
||||
const getManagementSections: () => ManagementSection[] = () => [];
|
||||
|
||||
const testSectionConfig = { id: 'test-section', title: 'Test Section' };
|
||||
return new ManagementSection(
|
||||
testSectionConfig,
|
||||
getManagementSections,
|
||||
registerLegacyApp,
|
||||
getLegacySection,
|
||||
coreMock.createSetup().getStartServices
|
||||
);
|
||||
}
|
||||
|
||||
test('cannot register two apps with the same id', () => {
|
||||
const registerLegacyApp = jest.fn();
|
||||
const section = createSection(registerLegacyApp);
|
||||
|
||||
const testAppConfig = { id: 'test-app', title: 'Test App', mount: () => () => {} };
|
||||
|
||||
section.registerApp(testAppConfig);
|
||||
expect(registerLegacyApp).toHaveBeenCalled();
|
||||
expect(section.apps.length).toEqual(1);
|
||||
|
||||
expect(() => {
|
||||
section.registerApp(testAppConfig);
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
test('can enable and disable apps', () => {
|
||||
const registerLegacyApp = jest.fn();
|
||||
const section = createSection(registerLegacyApp);
|
||||
|
||||
const testAppConfig = { id: 'test-app', title: 'Test App', mount: () => () => {} };
|
||||
|
||||
const app = section.registerApp(testAppConfig);
|
||||
expect(section.getAppsEnabled().length).toEqual(1);
|
||||
app.disable();
|
||||
expect(section.getAppsEnabled().length).toEqual(0);
|
||||
});
|
78
src/plugins/management/public/management_section.ts
Normal file
78
src/plugins/management/public/management_section.ts
Normal file
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { CreateSection, RegisterManagementAppArgs } from './types';
|
||||
import { KibanaLegacySetup } from '../../kibana_legacy/public';
|
||||
import { CoreSetup } from '../../../core/public';
|
||||
// @ts-ignore
|
||||
import { LegacyManagementSection } from './legacy';
|
||||
import { ManagementApp } from './management_app';
|
||||
|
||||
export class ManagementSection {
|
||||
public readonly id: string = '';
|
||||
public readonly title: string = '';
|
||||
public readonly apps: ManagementApp[] = [];
|
||||
public readonly order: number;
|
||||
public readonly euiIconType?: string;
|
||||
public readonly icon?: string;
|
||||
private readonly getSections: () => ManagementSection[];
|
||||
private readonly registerLegacyApp: KibanaLegacySetup['registerLegacyApp'];
|
||||
private readonly getLegacyManagementSection: () => LegacyManagementSection;
|
||||
private readonly getStartServices: CoreSetup['getStartServices'];
|
||||
|
||||
constructor(
|
||||
{ id, title, order = 100, euiIconType, icon }: CreateSection,
|
||||
getSections: () => ManagementSection[],
|
||||
registerLegacyApp: KibanaLegacySetup['registerLegacyApp'],
|
||||
getLegacyManagementSection: () => ManagementSection,
|
||||
getStartServices: CoreSetup['getStartServices']
|
||||
) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.order = order;
|
||||
this.euiIconType = euiIconType;
|
||||
this.icon = icon;
|
||||
this.getSections = getSections;
|
||||
this.registerLegacyApp = registerLegacyApp;
|
||||
this.getLegacyManagementSection = getLegacyManagementSection;
|
||||
this.getStartServices = getStartServices;
|
||||
}
|
||||
|
||||
registerApp({ id, title, order, mount }: RegisterManagementAppArgs) {
|
||||
if (this.getApp(id)) {
|
||||
throw new Error(`Management app already registered - id: ${id}, title: ${title}`);
|
||||
}
|
||||
|
||||
const app = new ManagementApp(
|
||||
{ id, title, order, mount, basePath: `/management/${this.id}/${id}` },
|
||||
this.getSections,
|
||||
this.registerLegacyApp,
|
||||
this.getLegacyManagementSection,
|
||||
this.getStartServices
|
||||
);
|
||||
this.apps.push(app);
|
||||
return app;
|
||||
}
|
||||
getApp(id: ManagementApp['id']) {
|
||||
return this.apps.find(app => app.id === id);
|
||||
}
|
||||
getAppsEnabled() {
|
||||
return this.apps.filter(app => app.enabled).sort((a, b) => a.order - b.order);
|
||||
}
|
||||
}
|
55
src/plugins/management/public/management_service.test.ts
Normal file
55
src/plugins/management/public/management_service.test.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { ManagementService } from './management_service';
|
||||
import { coreMock } from '../../../core/public/mocks';
|
||||
|
||||
const mockKibanaLegacy = { registerLegacyApp: () => {}, forwardApp: () => {} };
|
||||
|
||||
test('Provides default sections', () => {
|
||||
const service = new ManagementService().setup(
|
||||
mockKibanaLegacy,
|
||||
() => {},
|
||||
coreMock.createSetup().getStartServices
|
||||
);
|
||||
expect(service.getAllSections().length).toEqual(3);
|
||||
expect(service.getSection('kibana')).not.toBeUndefined();
|
||||
expect(service.getSection('logstash')).not.toBeUndefined();
|
||||
expect(service.getSection('elasticsearch')).not.toBeUndefined();
|
||||
});
|
||||
|
||||
test('Register section, enable and disable', () => {
|
||||
const service = new ManagementService().setup(
|
||||
mockKibanaLegacy,
|
||||
() => {},
|
||||
coreMock.createSetup().getStartServices
|
||||
);
|
||||
const testSection = service.register({ id: 'test-section', title: 'Test Section' });
|
||||
expect(service.getSection('test-section')).not.toBeUndefined();
|
||||
|
||||
const testApp = testSection.registerApp({
|
||||
id: 'test-app',
|
||||
title: 'Test App',
|
||||
mount: () => () => {},
|
||||
});
|
||||
expect(testSection.getApp('test-app')).not.toBeUndefined();
|
||||
expect(service.getSectionsEnabled().length).toEqual(1);
|
||||
testApp.disable();
|
||||
expect(service.getSectionsEnabled().length).toEqual(0);
|
||||
});
|
103
src/plugins/management/public/management_service.ts
Normal file
103
src/plugins/management/public/management_service.ts
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { ManagementSection } from './management_section';
|
||||
import { KibanaLegacySetup } from '../../kibana_legacy/public';
|
||||
// @ts-ignore
|
||||
import { LegacyManagementSection } from './legacy';
|
||||
import { CreateSection } from './types';
|
||||
import { CoreSetup, CoreStart } from '../../../core/public';
|
||||
|
||||
export class ManagementService {
|
||||
private sections: ManagementSection[] = [];
|
||||
|
||||
private register(
|
||||
registerLegacyApp: KibanaLegacySetup['registerLegacyApp'],
|
||||
getLegacyManagement: () => LegacyManagementSection,
|
||||
getStartServices: CoreSetup['getStartServices']
|
||||
) {
|
||||
return (section: CreateSection) => {
|
||||
if (this.getSection(section.id)) {
|
||||
throw Error(`ManagementSection '${section.id}' already registered`);
|
||||
}
|
||||
|
||||
const newSection = new ManagementSection(
|
||||
section,
|
||||
this.getSectionsEnabled.bind(this),
|
||||
registerLegacyApp,
|
||||
getLegacyManagement,
|
||||
getStartServices
|
||||
);
|
||||
this.sections.push(newSection);
|
||||
return newSection;
|
||||
};
|
||||
}
|
||||
private getSection(sectionId: ManagementSection['id']) {
|
||||
return this.sections.find(section => section.id === sectionId);
|
||||
}
|
||||
|
||||
private getAllSections() {
|
||||
return this.sections;
|
||||
}
|
||||
|
||||
private getSectionsEnabled() {
|
||||
return this.sections
|
||||
.filter(section => section.getAppsEnabled().length > 0)
|
||||
.sort((a, b) => a.order - b.order);
|
||||
}
|
||||
|
||||
private sharedInterface = {
|
||||
getSection: this.getSection.bind(this),
|
||||
getSectionsEnabled: this.getSectionsEnabled.bind(this),
|
||||
getAllSections: this.getAllSections.bind(this),
|
||||
};
|
||||
|
||||
public setup(
|
||||
kibanaLegacy: KibanaLegacySetup,
|
||||
getLegacyManagement: () => LegacyManagementSection,
|
||||
getStartServices: CoreSetup['getStartServices']
|
||||
) {
|
||||
const register = this.register.bind(this)(
|
||||
kibanaLegacy.registerLegacyApp,
|
||||
getLegacyManagement,
|
||||
getStartServices
|
||||
);
|
||||
|
||||
register({ id: 'kibana', title: 'Kibana', order: 30, euiIconType: 'logoKibana' });
|
||||
register({ id: 'logstash', title: 'Logstash', order: 30, euiIconType: 'logoLogstash' });
|
||||
register({
|
||||
id: 'elasticsearch',
|
||||
title: 'Elasticsearch',
|
||||
order: 20,
|
||||
euiIconType: 'logoElasticsearch',
|
||||
});
|
||||
|
||||
return {
|
||||
register,
|
||||
...this.sharedInterface,
|
||||
};
|
||||
}
|
||||
|
||||
public start(navigateToApp: CoreStart['application']['navigateToApp']) {
|
||||
return {
|
||||
navigateToApp, // apps are currently registered as top level apps but this may change in the future
|
||||
...this.sharedInterface,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -18,18 +18,30 @@
|
|||
*/
|
||||
|
||||
import { CoreSetup, CoreStart, Plugin } from 'kibana/public';
|
||||
import { ManagementStart } from './types';
|
||||
import { ManagementSetup, ManagementStart } from './types';
|
||||
import { ManagementService } from './management_service';
|
||||
import { KibanaLegacySetup } from '../../kibana_legacy/public';
|
||||
// @ts-ignore
|
||||
import { management } from './legacy';
|
||||
import { LegacyManagementAdapter } from './legacy';
|
||||
|
||||
export class ManagementPlugin implements Plugin<{}, ManagementStart> {
|
||||
public setup(core: CoreSetup) {
|
||||
return {};
|
||||
export class ManagementPlugin implements Plugin<ManagementSetup, ManagementStart> {
|
||||
private managementSections = new ManagementService();
|
||||
private legacyManagement = new LegacyManagementAdapter();
|
||||
|
||||
public setup(core: CoreSetup, { kibana_legacy }: { kibana_legacy: KibanaLegacySetup }) {
|
||||
return {
|
||||
sections: this.managementSections.setup(
|
||||
kibana_legacy,
|
||||
this.legacyManagement.getManagement,
|
||||
core.getStartServices
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
public start(core: CoreStart) {
|
||||
return {
|
||||
legacy: management(core.application.capabilities),
|
||||
sections: this.managementSections.start(core.application.navigateToApp),
|
||||
legacy: this.legacyManagement.init(core.application.capabilities),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,82 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { IconType } from '@elastic/eui';
|
||||
import { ManagementApp } from './management_app';
|
||||
import { ManagementSection } from './management_section';
|
||||
import { ChromeBreadcrumb, ApplicationStart } from '../../../core/public/';
|
||||
|
||||
export interface ManagementSetup {
|
||||
sections: SectionsServiceSetup;
|
||||
}
|
||||
|
||||
export interface ManagementStart {
|
||||
sections: SectionsServiceStart;
|
||||
legacy: any;
|
||||
}
|
||||
|
||||
interface SectionsServiceSetup {
|
||||
getSection: (sectionId: ManagementSection['id']) => ManagementSection | undefined;
|
||||
getAllSections: () => ManagementSection[];
|
||||
register: RegisterSection;
|
||||
}
|
||||
|
||||
interface SectionsServiceStart {
|
||||
getSection: (sectionId: ManagementSection['id']) => ManagementSection | undefined;
|
||||
getAllSections: () => ManagementSection[];
|
||||
navigateToApp: ApplicationStart['navigateToApp'];
|
||||
}
|
||||
|
||||
export interface CreateSection {
|
||||
id: string;
|
||||
title: string;
|
||||
order?: number;
|
||||
euiIconType?: string; // takes precedence over `icon` property.
|
||||
icon?: string; // URL to image file; fallback if no `euiIconType`
|
||||
}
|
||||
|
||||
export type RegisterSection = (section: CreateSection) => ManagementSection;
|
||||
|
||||
export interface RegisterManagementAppArgs {
|
||||
id: string;
|
||||
title: string;
|
||||
mount: ManagementSectionMount;
|
||||
order?: number;
|
||||
}
|
||||
|
||||
export type RegisterManagementApp = (managementApp: RegisterManagementAppArgs) => ManagementApp;
|
||||
|
||||
export type Unmount = () => Promise<void> | void;
|
||||
|
||||
interface ManagementAppMountParams {
|
||||
basePath: string; // base path for setting up your router
|
||||
element: HTMLElement; // element the section should render into
|
||||
setBreadcrumbs: (crumbs: ChromeBreadcrumb[]) => void;
|
||||
}
|
||||
|
||||
export type ManagementSectionMount = (
|
||||
params: ManagementAppMountParams
|
||||
) => Unmount | Promise<Unmount>;
|
||||
|
||||
export interface CreateManagementApp {
|
||||
id: string;
|
||||
title: string;
|
||||
basePath: string;
|
||||
order?: number;
|
||||
mount: ManagementSectionMount;
|
||||
}
|
||||
|
||||
export interface LegacySection extends LegacyApp {
|
||||
visibleItems: LegacyApp[];
|
||||
}
|
||||
|
||||
export interface LegacyApp {
|
||||
disabled: boolean;
|
||||
visible: boolean;
|
||||
id: string;
|
||||
display: string;
|
||||
url?: string;
|
||||
euiIconType?: IconType;
|
||||
icon?: string;
|
||||
order: number;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ export default async function({ readConfigFile }) {
|
|||
require.resolve('./test_suites/panel_actions'),
|
||||
require.resolve('./test_suites/embeddable_explorer'),
|
||||
require.resolve('./test_suites/core_plugins'),
|
||||
require.resolve('./test_suites/management'),
|
||||
],
|
||||
services: {
|
||||
...functionalConfig.get('services'),
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"id": "management_test_plugin",
|
||||
"version": "0.0.1",
|
||||
"kibanaVersion": "kibana",
|
||||
"configPath": ["management_test_plugin"],
|
||||
"server": false,
|
||||
"ui": true,
|
||||
"requiredPlugins": ["management"]
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "management_test_plugin",
|
||||
"version": "1.0.0",
|
||||
"main": "target/test/plugin_functional/plugins/management_test_plugin",
|
||||
"kibana": {
|
||||
"version": "kibana",
|
||||
"templateVersion": "1.0.0"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
"kbn": "node ../../../../scripts/kbn.js",
|
||||
"build": "rm -rf './target' && tsc"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "3.7.2"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { PluginInitializer } from 'kibana/public';
|
||||
import {
|
||||
ManagementTestPlugin,
|
||||
ManagementTestPluginSetup,
|
||||
ManagementTestPluginStart,
|
||||
} from './plugin';
|
||||
|
||||
export const plugin: PluginInitializer<ManagementTestPluginSetup, ManagementTestPluginStart> = () =>
|
||||
new ManagementTestPlugin();
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import * as React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { HashRouter as Router, Switch, Route, Link } from 'react-router-dom';
|
||||
import { CoreSetup, Plugin } from 'kibana/public';
|
||||
import { ManagementSetup } from '../../../../../src/plugins/management/public';
|
||||
|
||||
export class ManagementTestPlugin
|
||||
implements Plugin<ManagementTestPluginSetup, ManagementTestPluginStart> {
|
||||
public setup(core: CoreSetup, { management }: { management: ManagementSetup }) {
|
||||
const testSection = management.sections.register({
|
||||
id: 'test-section',
|
||||
title: 'Test Section',
|
||||
euiIconType: 'logoKibana',
|
||||
order: 25,
|
||||
});
|
||||
|
||||
testSection!.registerApp({
|
||||
id: 'test-management',
|
||||
title: 'Management Test',
|
||||
mount(params) {
|
||||
params.setBreadcrumbs([{ text: 'Management Test' }]);
|
||||
ReactDOM.render(
|
||||
<Router>
|
||||
<h1 data-test-subj="test-management-header">Hello from management test plugin</h1>
|
||||
<Switch>
|
||||
<Route exact path={`${params.basePath}`}>
|
||||
<Link to={`${params.basePath}/one`} data-test-subj="test-management-link-one">
|
||||
Link to /one
|
||||
</Link>
|
||||
</Route>
|
||||
<Route path={`${params.basePath}/one`}>
|
||||
<Link to={`${params.basePath}`} data-test-subj="test-management-link-basepath">
|
||||
Link to basePath
|
||||
</Link>
|
||||
</Route>
|
||||
</Switch>
|
||||
</Router>,
|
||||
params.element
|
||||
);
|
||||
|
||||
return () => {
|
||||
ReactDOM.unmountComponentAtNode(params.element);
|
||||
};
|
||||
},
|
||||
});
|
||||
return {};
|
||||
}
|
||||
|
||||
public start() {}
|
||||
public stop() {}
|
||||
}
|
||||
|
||||
export type ManagementTestPluginSetup = ReturnType<ManagementTestPlugin['setup']>;
|
||||
export type ManagementTestPluginStart = ReturnType<ManagementTestPlugin['start']>;
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"extends": "../../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./target",
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
"index.ts",
|
||||
"public/**/*.ts",
|
||||
"public/**/*.tsx",
|
||||
"../../../../typings/**/*",
|
||||
],
|
||||
"exclude": []
|
||||
}
|
24
test/plugin_functional/test_suites/management/index.js
Normal file
24
test/plugin_functional/test_suites/management/index.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export default function({ loadTestFile }) {
|
||||
describe('management plugin', () => {
|
||||
loadTestFile(require.resolve('./management_plugin'));
|
||||
});
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
export default function({ getService, getPageObjects }) {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const PageObjects = getPageObjects(['common']);
|
||||
|
||||
describe('management plugin', function describeIndexTests() {
|
||||
before(async () => {
|
||||
await PageObjects.common.navigateToActualUrl('kibana', 'management');
|
||||
});
|
||||
|
||||
it('should be able to navigate to management test app', async () => {
|
||||
await testSubjects.click('test-management');
|
||||
await testSubjects.existOrFail('test-management-header');
|
||||
});
|
||||
|
||||
it('should be able to navigate within management test app', async () => {
|
||||
await testSubjects.click('test-management-link-one');
|
||||
await testSubjects.click('test-management-link-basepath');
|
||||
await testSubjects.existOrFail('test-management-link-one');
|
||||
});
|
||||
});
|
||||
}
|
2
x-pack/legacy/plugins/infra/types/eui.d.ts
vendored
2
x-pack/legacy/plugins/infra/types/eui.d.ts
vendored
|
@ -34,7 +34,7 @@ declare module '@elastic/eui' {
|
|||
items: Array<{
|
||||
id: string;
|
||||
name: string;
|
||||
onClick: () => void;
|
||||
onClick?: () => void;
|
||||
}>;
|
||||
}>;
|
||||
mobileTitle?: React.ReactNode;
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
|
||||
import { ManagementService } from '.';
|
||||
|
||||
const mockSections = {
|
||||
getSection: jest.fn(),
|
||||
getAllSections: jest.fn(),
|
||||
navigateToApp: jest.fn(),
|
||||
};
|
||||
|
||||
describe('ManagementService', () => {
|
||||
describe('#start', () => {
|
||||
it('registers the spaces management page under the kibana section', () => {
|
||||
|
@ -18,6 +24,7 @@ describe('ManagementService', () => {
|
|||
legacy: {
|
||||
getSection: jest.fn().mockReturnValue(mockKibanaSection),
|
||||
},
|
||||
sections: mockSections,
|
||||
};
|
||||
|
||||
const deps = {
|
||||
|
@ -49,6 +56,7 @@ describe('ManagementService', () => {
|
|||
legacy: {
|
||||
getSection: jest.fn().mockReturnValue(mockKibanaSection),
|
||||
},
|
||||
sections: mockSections,
|
||||
};
|
||||
|
||||
const deps = {
|
||||
|
@ -66,6 +74,7 @@ describe('ManagementService', () => {
|
|||
legacy: {
|
||||
getSection: jest.fn().mockReturnValue(undefined),
|
||||
},
|
||||
sections: mockSections,
|
||||
};
|
||||
|
||||
const deps = {
|
||||
|
@ -94,6 +103,7 @@ describe('ManagementService', () => {
|
|||
legacy: {
|
||||
getSection: jest.fn().mockReturnValue(mockKibanaSection),
|
||||
},
|
||||
sections: mockSections,
|
||||
};
|
||||
|
||||
const deps = {
|
||||
|
|
|
@ -441,7 +441,9 @@
|
|||
"common.ui.flotCharts.tueLabel": "火",
|
||||
"common.ui.flotCharts.wedLabel": "水",
|
||||
"common.ui.management.breadcrumb": "管理",
|
||||
"common.ui.management.nav.menu": "管理メニュー",
|
||||
"management.connectDataDisplayName": "データに接続",
|
||||
"management.displayName": "管理",
|
||||
"management.nav.menu": "管理メニュー",
|
||||
"common.ui.modals.cancelButtonLabel": "キャンセル",
|
||||
"common.ui.notify.fatalError.errorStatusMessage": "エラー {errStatus} {errStatusText}: {errMessage}",
|
||||
"common.ui.notify.fatalError.unavailableServerErrorMessage": "HTTP リクエストが接続に失敗しました。Kibana サーバーが実行されていて、ご使用のブラウザの接続が正常に動作していることを確認するか、システム管理者にお問い合わせください。",
|
||||
|
|
|
@ -441,7 +441,9 @@
|
|||
"common.ui.flotCharts.tueLabel": "周二",
|
||||
"common.ui.flotCharts.wedLabel": "周三",
|
||||
"common.ui.management.breadcrumb": "管理",
|
||||
"common.ui.management.nav.menu": "管理菜单",
|
||||
"management.connectDataDisplayName": "连接数据",
|
||||
"management.displayName": "管理",
|
||||
"management.nav.menu": "管理菜单",
|
||||
"common.ui.modals.cancelButtonLabel": "取消",
|
||||
"common.ui.notify.fatalError.errorStatusMessage": "错误 {errStatus} {errStatusText}:{errMessage}",
|
||||
"common.ui.notify.fatalError.unavailableServerErrorMessage": "HTTP 请求无法连接。请检查 Kibana 服务器是否正在运行以及您的浏览器是否具有有效的连接,或请联系您的系统管理员。",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue