diff --git a/src/legacy/core_plugins/kibana/index.js b/src/legacy/core_plugins/kibana/index.js
index 5807c439bd277..4d36f3260ca10 100644
--- a/src/legacy/core_plugins/kibana/index.js
+++ b/src/legacy/core_plugins/kibana/index.js
@@ -26,8 +26,7 @@ import { exportApi } from './server/routes/api/export';
import { getUiSettingDefaults } from './server/ui_setting_defaults';
import { registerCspCollector } from './server/lib/csp_usage_collector';
import { injectVars } from './inject_vars';
-import { i18n } from '@kbn/i18n';
-import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/server';
+
import { kbnBaseUrl } from '../../../plugins/kibana_legacy/server';
const mkdirAsync = promisify(Fs.mkdir);
@@ -59,19 +58,7 @@ export default function(kibana) {
main: 'plugins/kibana/kibana',
},
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
- links: [
- {
- id: 'kibana:stack_management',
- title: i18n.translate('kbn.managementTitle', {
- defaultMessage: 'Stack Management',
- }),
- order: 9003,
- url: `${kbnBaseUrl}#/management`,
- euiIconType: 'managementApp',
- linkToLastSubUrl: false,
- category: DEFAULT_APP_CATEGORIES.management,
- },
- ],
+ links: [],
injectDefaultVars(server, options) {
const mapConfig = server.config().get('map');
diff --git a/src/legacy/core_plugins/kibana/public/.eslintrc.js b/src/legacy/core_plugins/kibana/public/.eslintrc.js
deleted file mode 100644
index 1153706eb8566..0000000000000
--- a/src/legacy/core_plugins/kibana/public/.eslintrc.js
+++ /dev/null
@@ -1,83 +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.
- */
-
-const topLevelConfig = require('../../../../../.eslintrc.js');
-const path = require('path');
-
-const topLevelRestricedZones = topLevelConfig.overrides.find(
- override =>
- override.files[0] === '**/*.{js,ts,tsx}' &&
- Object.keys(override.rules)[0] === '@kbn/eslint/no-restricted-paths'
-).rules['@kbn/eslint/no-restricted-paths'][1].zones;
-
-/**
- * Builds custom restricted paths configuration for the shimmed plugins within the kibana plugin.
- * These custom rules extend the default checks in the top level `eslintrc.js` by also checking two other things:
- * * Making sure nothing within np_ready imports from the `ui` directory
- * * Making sure no other code is importing things deep from within the shimmed plugins
- * @param shimmedPlugins List of plugin names within the kibana plugin that are partially np ready
- * @returns zones configuration for the no-restricted-paths linter
- */
-function buildRestrictedPaths(shimmedPlugins) {
- return shimmedPlugins
- .map(shimmedPlugin => [
- {
- target: [`src/legacy/core_plugins/kibana/public/${shimmedPlugin}/np_ready/**/*`],
- from: [
- 'ui/**/*',
- 'src/legacy/ui/**/*',
- 'src/legacy/core_plugins/kibana/public/**/*',
- `!src/legacy/core_plugins/kibana/public/${shimmedPlugin}/**/*`,
- ],
- allowSameFolder: false,
- errorMessage: `${shimmedPlugin} is a shimmed plugin that is not allowed to import modules from the legacy platform. If you need legacy modules for the transition period, import them either in the legacy_imports, kibana_services or index module.`,
- },
- {
- target: [
- 'src/**/*',
- `!src/legacy/core_plugins/kibana/public/${shimmedPlugin}/**/*`,
- 'x-pack/**/*',
- ],
- from: [
- `src/legacy/core_plugins/kibana/public/${shimmedPlugin}/**/*`,
- `!src/legacy/core_plugins/kibana/public/${shimmedPlugin}/index.ts`,
- `!src/legacy/core_plugins/kibana/public/${shimmedPlugin}/legacy.ts`,
- ],
- allowSameFolder: false,
- errorMessage: `kibana/public/${shimmedPlugin} is behaving like a NP plugin and does not allow deep imports. If you need something from within ${shimmedPlugin} in another plugin, consider re-exporting it from the top level index module`,
- },
- ])
- .reduce((acc, part) => [...acc, ...part], []);
-}
-
-module.exports = {
- rules: {
- 'no-console': 2,
- 'import/no-default-export': 'error',
- '@kbn/eslint/no-restricted-paths': [
- 'error',
- {
- basePath: path.resolve(__dirname, '../../../../../'),
- zones: topLevelRestricedZones.concat(
- buildRestrictedPaths(['visualize', 'discover', 'dashboard', 'devTools'])
- ),
- },
- ],
- },
-};
diff --git a/src/legacy/core_plugins/kibana/public/_hacks.scss b/src/legacy/core_plugins/kibana/public/_hacks.scss
deleted file mode 100644
index e69de29bb2d1d..0000000000000
diff --git a/src/legacy/core_plugins/kibana/public/kibana.js b/src/legacy/core_plugins/kibana/public/kibana.js
index 0bf74edc77cb6..610ae4d452384 100644
--- a/src/legacy/core_plugins/kibana/public/kibana.js
+++ b/src/legacy/core_plugins/kibana/public/kibana.js
@@ -38,7 +38,7 @@ import 'uiExports/shareContextMenuExtensions';
import 'uiExports/interpreter';
import 'ui/autoload/all';
-import './management';
+
import { localApplicationService } from './local_application_service';
npSetup.plugins.kibanaLegacy.registerLegacyAppAlias('doc', 'discover', { keepPrefix: true });
diff --git a/src/legacy/core_plugins/kibana/public/management/_management_app.scss b/src/legacy/core_plugins/kibana/public/management/_management_app.scss
deleted file mode 100644
index bd3cabbc574d3..0000000000000
--- a/src/legacy/core_plugins/kibana/public/management/_management_app.scss
+++ /dev/null
@@ -1,69 +0,0 @@
-.mgtPanel {
- margin-bottom: $euiSize;
- background: $euiColorEmptyShade;
-}
-
-/**
- * 1. Override kuiPanelBody styles to accommodate padding of items within the panel body..
- */
-.mgtPanel__body {
- padding: 5px 10px; /* 1 */
-}
-
-/**
- * 1. Create vertical space between items when they wrap.
- */
-.mgtPanel__item {
- padding: 5px 15px; /* 1 */
-}
-
-// SASSTODO: Remove when this is replaced by the side nav
-.mgtPanel__link {
- @include euiFontSizeL;
-
- line-height: 1.5; // Make sure the space between wrapped lines is than the vertical space between items.
-
- &.mgtPanel__link--disabled {
- opacity: $euiColorDarkShade;
- cursor: default;
-
- &:hover, &:visited {
- color: $euiColorPrimary;
- }
- }
-}
-
-// SASSTODO: Remove when this form is replaced by EUI
-kbn-management-objects {
- form {
- margin-bottom: $euiSize;
- }
- .list-unstyled {
- li {
- border-bottom: $euiBorderThin;
- padding: $euiSizeS;
- }
- }
- .empty {
- color: $euiColorDarkShade;
- }
-
- .item {
- padding: $euiSizeM;
-
- .item-title {
- margin-left: $euiSizeL;
- }
-
- .actions {
- margin-top: $euiSizeXS;
- }
- }
-
- .header {
- .title, .controls {
- padding-right: 1em;
- display: inline-block;
- }
- }
-}
diff --git a/src/legacy/core_plugins/kibana/public/management/app.html b/src/legacy/core_plugins/kibana/public/management/app.html
deleted file mode 100644
index 11198c02960c7..0000000000000
--- a/src/legacy/core_plugins/kibana/public/management/app.html
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/src/legacy/core_plugins/kibana/public/management/index.js b/src/legacy/core_plugins/kibana/public/management/index.js
deleted file mode 100644
index ff253629a4825..0000000000000
--- a/src/legacy/core_plugins/kibana/public/management/index.js
+++ /dev/null
@@ -1,166 +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 React from 'react';
-import { render, unmountComponentAtNode } from 'react-dom';
-import { FormattedMessage } from '@kbn/i18n/react';
-
-import uiRoutes from 'ui/routes';
-import { I18nContext } from 'ui/i18n';
-import { uiModules } from 'ui/modules';
-import appTemplate from './app.html';
-import landingTemplate from './landing.html';
-import { management, MANAGEMENT_BREADCRUMB } from 'ui/management';
-import { ManagementSidebarNav } from '../../../../../plugins/management/public';
-import { timefilter } from 'ui/timefilter';
-import {
- EuiPageContent,
- EuiTitle,
- EuiText,
- EuiSpacer,
- EuiIcon,
- EuiHorizontalRule,
-} from '@elastic/eui';
-import { npStart } from 'ui/new_platform';
-
-const SIDENAV_ID = 'management-sidenav';
-const LANDING_ID = 'management-landing';
-
-uiRoutes.when('/management', {
- template: landingTemplate,
- k7Breadcrumbs: () => [MANAGEMENT_BREADCRUMB],
-});
-
-uiRoutes.when('/management/:section', {
- redirectTo: '/management',
-});
-
-export function updateLandingPage(version) {
- const node = document.getElementById(LANDING_ID);
- if (!node) {
- return;
- }
-
- render(
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ,
- node
- );
-}
-
-export function updateSidebar(legacySections, id) {
- const node = document.getElementById(SIDENAV_ID);
- if (!node) {
- return;
- }
-
- render(
-
-
- ,
- node
- );
-}
-
-export const destroyReact = id => {
- const node = document.getElementById(id);
- node && unmountComponentAtNode(node);
-};
-
-uiModules.get('apps/management').directive('kbnManagementApp', function($location) {
- return {
- restrict: 'E',
- template: appTemplate,
- transclude: true,
- scope: {
- sectionName: '@section',
- omitPages: '@omitBreadcrumbPages',
- pageTitle: '=',
- },
-
- link: function($scope) {
- timefilter.disableAutoRefreshSelector();
- timefilter.disableTimeRangeSelector();
- $scope.sections = management.visibleItems;
- $scope.section = management.getSection($scope.sectionName) || management;
-
- if ($scope.section) {
- $scope.section.items.forEach(item => {
- item.active = `#${$location.path()}`.indexOf(item.url) > -1;
- });
- }
-
- updateSidebar($scope.sections, $scope.section.id);
- $scope.$on('$destroy', () => destroyReact(SIDENAV_ID));
- management.addListener(() => updateSidebar(management.visibleItems, $scope.section.id));
-
- updateLandingPage($scope.$root.chrome.getKibanaVersion());
- $scope.$on('$destroy', () => destroyReact(LANDING_ID));
- },
- };
-});
-
-uiModules.get('apps/management').directive('kbnManagementLanding', function(kbnVersion) {
- return {
- restrict: 'E',
- link: function($scope) {
- $scope.sections = management.visibleItems;
- $scope.kbnVersion = kbnVersion;
- },
- };
-});
diff --git a/src/legacy/core_plugins/kibana/public/management/index.scss b/src/legacy/core_plugins/kibana/public/management/index.scss
index 123580c0b7907..fb267b714f1c9 100644
--- a/src/legacy/core_plugins/kibana/public/management/index.scss
+++ b/src/legacy/core_plugins/kibana/public/management/index.scss
@@ -7,9 +7,7 @@
// mgtChart__legend--small
// mgtChart__legend-isLoading
-@import 'hacks';
-
// Core
-@import 'management_app';
@import '../../../../../plugins/advanced_settings/public/index';
+
@import 'sections/index_patterns/index';
diff --git a/src/legacy/core_plugins/kibana/public/management/landing.html b/src/legacy/core_plugins/kibana/public/management/landing.html
deleted file mode 100644
index 39459b26f7415..0000000000000
--- a/src/legacy/core_plugins/kibana/public/management/landing.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/types.ts b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/types.ts
deleted file mode 100644
index 81184d6fdd1a3..0000000000000
--- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/types.ts
+++ /dev/null
@@ -1,34 +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.
- */
-
-export interface IndexPatternCreationOption {
- text: string;
- description?: string;
- onClick: () => void;
-}
-
-export interface IndexPattern {
- id: string;
- title: string;
- url: string;
- active: boolean;
- default: boolean;
- tag?: string[];
- sort: string;
-}
diff --git a/src/plugins/management/public/__snapshots__/management_app.test.tsx.snap b/src/plugins/management/public/__snapshots__/management_app.test.tsx.snap
deleted file mode 100644
index 7f13472ee02ee..0000000000000
--- a/src/plugins/management/public/__snapshots__/management_app.test.tsx.snap
+++ /dev/null
@@ -1,11 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Management app can mount and unmount 1`] = `
-
-
- Test App - Hello world!
-
-
-`;
-
-exports[`Management app can mount and unmount 2`] = ``;
diff --git a/src/legacy/core_plugins/kibana/public/management/saved_object_registry.ts b/src/plugins/management/public/application.tsx
similarity index 58%
rename from src/legacy/core_plugins/kibana/public/management/saved_object_registry.ts
rename to src/plugins/management/public/application.tsx
index 587a372f91555..f42109ba2f96a 100644
--- a/src/legacy/core_plugins/kibana/public/management/saved_object_registry.ts
+++ b/src/plugins/management/public/application.tsx
@@ -17,8 +17,21 @@
* under the License.
*/
-import { npSetup } from 'ui/new_platform';
+import React from 'react';
+import ReactDOM from 'react-dom';
-const registry = npSetup.plugins.savedObjectsManagement?.serviceRegistry;
+import { AppMountContext, AppMountParameters } from 'kibana/public';
+import { ManagementApp, ManagementAppDependencies } from './components/management_app';
-export const savedObjectManagementRegistry = registry!;
+export const renderApp = async (
+ context: AppMountContext,
+ { history, appBasePath, element }: AppMountParameters,
+ dependencies: ManagementAppDependencies
+) => {
+ ReactDOM.render(
+ ,
+ element
+ );
+
+ return () => ReactDOM.unmountComponentAtNode(element);
+};
diff --git a/src/plugins/management/public/components/_index.scss b/src/plugins/management/public/components/_index.scss
deleted file mode 100644
index df0ebb48803d9..0000000000000
--- a/src/plugins/management/public/components/_index.scss
+++ /dev/null
@@ -1 +0,0 @@
-@import './management_sidebar_nav/index';
diff --git a/src/plugins/management/public/components/index.ts b/src/plugins/management/public/components/index.ts
index 2650d23d3c25c..3a2a3eafb89e2 100644
--- a/src/plugins/management/public/components/index.ts
+++ b/src/plugins/management/public/components/index.ts
@@ -17,5 +17,4 @@
* under the License.
*/
-export { ManagementSidebarNav } from './management_sidebar_nav';
-export { ManagementChrome } from './management_chrome';
+export { ManagementApp } from './management_app';
diff --git a/src/plugins/management/public/components/langing/index.ts b/src/plugins/management/public/components/langing/index.ts
new file mode 100644
index 0000000000000..d7309ad0c21c2
--- /dev/null
+++ b/src/plugins/management/public/components/langing/index.ts
@@ -0,0 +1 @@
+export { ManagementLandingPage } from './landing';
diff --git a/src/plugins/management/public/components/langing/landing.tsx b/src/plugins/management/public/components/langing/landing.tsx
new file mode 100644
index 0000000000000..a82044784bc95
--- /dev/null
+++ b/src/plugins/management/public/components/langing/landing.tsx
@@ -0,0 +1,71 @@
+/*
+ * 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 React from 'react';
+import { FormattedMessage } from '@kbn/i18n/react';
+
+import {
+ EuiHorizontalRule,
+ EuiIcon,
+ EuiPageContent,
+ EuiSpacer,
+ EuiText,
+ EuiTitle,
+} from '@elastic/eui';
+
+interface ManagementLandingPageProps {
+ version: string;
+}
+
+export const ManagementLandingPage = ({ version }: ManagementLandingPageProps) => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
diff --git a/src/plugins/management/public/components/management_app/_management_app.scss b/src/plugins/management/public/components/management_app/_management_app.scss
new file mode 100644
index 0000000000000..6eaf82ba8283d
--- /dev/null
+++ b/src/plugins/management/public/components/management_app/_management_app.scss
@@ -0,0 +1,19 @@
+.mgtPanel {
+ margin-bottom: $euiSize;
+ background: $euiColorEmptyShade;
+}
+
+/**
+ * 1. Override kuiPanelBody styles to accommodate padding of items within the panel body..
+ */
+.mgtPanel__body {
+ padding: 5px 10px; /* 1 */
+}
+
+/**
+ * 1. Create vertical space between items when they wrap.
+ */
+.mgtPanel__item {
+ padding: 5px 15px; /* 1 */
+}
+
diff --git a/src/plugins/management/public/legacy/index.js b/src/plugins/management/public/components/management_app/index.ts
similarity index 87%
rename from src/plugins/management/public/legacy/index.js
rename to src/plugins/management/public/components/management_app/index.ts
index f2e0ba89b7b59..83f8ae0159978 100644
--- a/src/plugins/management/public/legacy/index.js
+++ b/src/plugins/management/public/components/management_app/index.ts
@@ -17,5 +17,4 @@
* under the License.
*/
-export { LegacyManagementAdapter } from './sections_register';
-export { LegacyManagementSection } from './section';
+export { ManagementApp, ManagementAppDependencies } from './management_app';
diff --git a/src/plugins/management/public/components/management_app/management_app.tsx b/src/plugins/management/public/components/management_app/management_app.tsx
new file mode 100644
index 0000000000000..64010f7c6a072
--- /dev/null
+++ b/src/plugins/management/public/components/management_app/management_app.tsx
@@ -0,0 +1,90 @@
+/*
+ * 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 React, { useState, useEffect, useCallback } from 'react';
+import { AppMountParameters } from 'kibana/public';
+import { Route, Router, Switch } from 'react-router-dom';
+import { EuiPage, EuiPageBody } from '@elastic/eui';
+import { ManagementStart } from '../../types';
+
+import { ManagementLandingPage } from '../langing';
+import { ManagementSidebarNav } from '../management_sidebar_nav';
+import { ManagementSectionWrapper } from '../management_section_wrapper';
+
+import { ManagementItem } from '../../management_item';
+
+import './_management_app.scss';
+
+interface ManagementAppProps {
+ appBasePath: string;
+ history: AppMountParameters['history'];
+ dependencies: ManagementAppDependencies;
+}
+
+export interface ManagementAppDependencies {
+ management: ManagementStart;
+ kibanaVersion: string;
+}
+
+export const ManagementApp = ({ dependencies, history }: ManagementAppProps) => {
+ const [selectedId, setSelectedId] = useState('');
+ const [sections, setSections] = useState();
+ const onManagementSectionSelected = useCallback(
+ (id: string, path: string) => {
+ setSelectedId(id);
+ history.push(path);
+ },
+ [history]
+ );
+
+ useEffect(() => {
+ setSections(dependencies.management.sections.getSectionsEnabled());
+ }, [dependencies.management.sections]);
+
+ if (!sections) {
+ return null;
+ }
+
+ return (
+
+
+
+
+
+ {sections.map(section =>
+ section.apps.map(app => (
+ }
+ />
+ ))
+ )}
+ }
+ />
+
+
+
+
+ );
+};
diff --git a/src/plugins/management/public/components/management_chrome/management_chrome.tsx b/src/plugins/management/public/components/management_chrome/management_chrome.tsx
deleted file mode 100644
index df844e2208936..0000000000000
--- a/src/plugins/management/public/components/management_chrome/management_chrome.tsx
+++ /dev/null
@@ -1,59 +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 * as React from 'react';
-import { EuiPage, EuiPageBody, EuiPageSideBar } 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 {
- private container = React.createRef();
- componentDidMount() {
- if (this.container.current) {
- this.props.onMounted(this.container.current);
- }
- }
- render() {
- return (
-
-
-
-
-
-
-
-
-
-
- );
- }
-}
diff --git a/src/plugins/management/public/components/management_chrome/index.ts b/src/plugins/management/public/components/management_section_wrapper/index.tsx
similarity index 91%
rename from src/plugins/management/public/components/management_chrome/index.ts
rename to src/plugins/management/public/components/management_section_wrapper/index.tsx
index b82c1af871be7..2736e3a6ac8a8 100644
--- a/src/plugins/management/public/components/management_chrome/index.ts
+++ b/src/plugins/management/public/components/management_section_wrapper/index.tsx
@@ -17,4 +17,4 @@
* under the License.
*/
-export { ManagementChrome } from './management_chrome';
+export { ManagementSectionWrapper } from './management_section_wrapper';
diff --git a/src/plugins/management/public/components/management_section_wrapper/management_section_wrapper.tsx b/src/plugins/management/public/components/management_section_wrapper/management_section_wrapper.tsx
new file mode 100644
index 0000000000000..e0d8b5ac88d61
--- /dev/null
+++ b/src/plugins/management/public/components/management_section_wrapper/management_section_wrapper.tsx
@@ -0,0 +1,59 @@
+/*
+ * 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 React, { useEffect, createRef, useRef, RefObject } from 'react';
+import { ManagementItem } from '../../management_item';
+import { Unmount } from '../../types';
+
+interface ManagementSectionWrapperProps {
+ section: ManagementItem;
+}
+
+export const ManagementSectionWrapper = ({ section }: ManagementSectionWrapperProps) => {
+ const mountElementRef = useRef>();
+ const { mount, basePath } = section;
+ const unmount = useRef();
+
+ mountElementRef.current = createRef();
+
+ useEffect(() => {
+ if (mount && basePath) {
+ const mountResult = mount({
+ basePath,
+ element: mountElementRef.current!.current,
+ setBreadcrumbs: () => 'todo',
+ });
+
+ if (mountResult instanceof Promise) {
+ mountResult.then(um => {
+ unmount.current = um;
+ });
+ } else {
+ unmount.current = mountResult;
+ }
+ return () => {
+ if (unmount.current) {
+ unmount.current();
+ }
+ };
+ }
+ }, [basePath, mount]);
+
+ return ;
+};
diff --git a/src/plugins/management/public/components/management_sidebar_nav/__snapshots__/management_sidebar_nav.test.ts.snap b/src/plugins/management/public/components/management_sidebar_nav/__snapshots__/management_sidebar_nav.test.ts.snap
deleted file mode 100644
index e7225b356ed68..0000000000000
--- a/src/plugins/management/public/components/management_sidebar_nav/__snapshots__/management_sidebar_nav.test.ts.snap
+++ /dev/null
@@ -1,95 +0,0 @@
-// 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,
- },
-]
-`;
diff --git a/src/plugins/management/public/components/management_sidebar_nav/management_sidebar_nav.test.ts b/src/plugins/management/public/components/management_sidebar_nav/management_sidebar_nav.test.ts
deleted file mode 100644
index e04e0a7572612..0000000000000
--- a/src/plugins/management/public/components/management_sidebar_nav/management_sidebar_nav.test.ts
+++ /dev/null
@@ -1,98 +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 { IndexedArray } from '../../../../../legacy/ui/public/indexed_array';
-import { mergeLegacyItems } from './management_sidebar_nav';
-
-const toIndexedArray = (initialSet: any[]) =>
- new IndexedArray({
- index: ['id'],
- order: ['order'],
- initialSet,
- });
-
-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 },
- ]),
- ...activeProps,
-};
-const activeSection = {
- display: 'activeSection',
- id: 'activeSection',
- order: 10,
- visibleItems: toIndexedArray([visibleItem]),
- ...activeProps,
-};
-
-const managementSections = [
- notVisibleSection,
- disabledSection,
- noItemsSection,
- noActiveItemsSection,
- activeSection,
-];
-
-describe('Management', () => {
- 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();
- });
-});
diff --git a/src/plugins/management/public/components/management_sidebar_nav/management_sidebar_nav.tsx b/src/plugins/management/public/components/management_sidebar_nav/management_sidebar_nav.tsx
index 01a98eb0ddb1f..785820a2640e9 100644
--- a/src/plugins/management/public/components/management_sidebar_nav/management_sidebar_nav.tsx
+++ b/src/plugins/management/public/components/management_sidebar_nav/management_sidebar_nav.tsx
@@ -17,184 +17,75 @@
* under the License.
*/
-import {
- EuiIcon,
- // @ts-ignore
- EuiSideNav,
- EuiScreenReaderOnly,
-} from '@elastic/eui';
-import { FormattedMessage } from '@kbn/i18n/react';
+import { EuiIcon, EuiSideNav, EuiSideNavItemType, EuiScreenReaderOnly } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
-import React from 'react';
-import { LegacySection, LegacyApp } from '../../types';
-import { ManagementApp } from '../../management_app';
-import { ManagementSection } from '../../management_section';
+import React, { useState } from 'react';
+import { ManagementItem } from '../../management_item';
-interface NavApp {
- id: string;
- name: string;
- [key: string]: unknown;
- order: number; // only needed while merging platform and legacy
-}
-
-interface NavSection extends NavApp {
- items: NavApp[];
-}
+import './_index.scss';
interface ManagementSidebarNavProps {
- getSections: () => ManagementSection[];
- legacySections: LegacySection[];
+ sections: ManagementItem[];
+ onManagementSectionSelected: (id: string, path: string) => void;
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 headerLabel = i18n.translate('management.nav.label', {
+ defaultMessage: 'Management',
});
-const managementSectionToNavSection = (section: ManagementSection) => {
- const iconType = section.euiIconType
- ? section.euiIconType
- : section.icon
- ? section.icon
- : 'empty';
-
- return {
- icon: ,
- ...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 ? : null,
- items: [],
- 'data-test-subj': section.id,
- // @ts-ignore
- order: section.order,
+const navMenuLabel = i18n.translate('management.nav.menu', {
+ defaultMessage: 'Management menu',
});
-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;
-};
+/** @internal **/
+export const ManagementSidebarNav = ({
+ selectedId,
+ sections,
+ onManagementSectionSelected,
+}: ManagementSidebarNavProps) => {
+ const HEADER_ID = 'stack-management-nav-header';
+ const [isSideNavOpenOnMobile, setIsSideNavOpenOnMobile] = useState(false);
+ const toggleOpenOnMobile = () => setIsSideNavOpenOnMobile(!isSideNavOpenOnMobile);
+
+ const toNavItems = (managementSections: ManagementItem[]) => {
+ if (!managementSections || !managementSections.length) {
+ return undefined;
+ }
+
+ return (managementSections || [])
+ .filter(section => section.getEnabledItems())
+ .map(section => ({
+ ...createNavItem(section),
+ }));
+ };
-const sectionsToItems = (
- sections: ManagementSection[],
- legacySections: LegacySection[],
- selectedId: string
-) => {
- const navItems = sideNavItems(sections, selectedId);
- return mergeLegacyItems(navItems, legacySections, selectedId);
-};
+ const createNavItem = (section: ManagementItem): EuiSideNavItemType => {
+ const iconType = section.euiIconType || section.icon;
-export class ManagementSidebarNav extends React.Component<
- ManagementSidebarNavProps,
- ManagementSidebarNavState
-> {
- constructor(props: ManagementSidebarNavProps) {
- super(props);
- this.state = {
- isSideNavOpenOnMobile: false,
+ return {
+ id: section.id,
+ name: section.title,
+ isSelected: section.id === selectedId,
+ icon: iconType ? : undefined,
+ items: toNavItems(section.apps),
+ onClick: () => section.basePath && onManagementSectionSelected(section.id, section.basePath),
};
- }
-
- public render() {
- const HEADER_ID = 'stack-management-nav-header';
-
- return (
- <>
-
-
-
-
- >
- );
- }
-
- private renderMobileTitle() {
- return ;
- }
-
- private toggleOpenOnMobile = () => {
- this.setState({
- isSideNavOpenOnMobile: !this.state.isSideNavOpenOnMobile,
- });
};
-}
+
+ return (
+ <>
+
+
+
+
+ >
+ );
+};
diff --git a/src/plugins/management/public/index.ts b/src/plugins/management/public/index.ts
index 9e59834303546..adfa57f6c9e74 100644
--- a/src/plugins/management/public/index.ts
+++ b/src/plugins/management/public/index.ts
@@ -19,18 +19,17 @@
import { PluginInitializerContext } from 'kibana/public';
import { ManagementPlugin } from './plugin';
+import { ManagementItem } from './management_item';
+
+import { ManagementItemMountParams, CreateManagementItemArgs } from './types';
export function plugin(initializerContext: PluginInitializerContext) {
return new ManagementPlugin();
}
-export {
- ManagementSetup,
- ManagementStart,
- RegisterManagementApp,
- RegisterManagementAppArgs,
- ManagementAppMountParams,
-} from './types';
-export { ManagementApp } from './management_app';
-export { ManagementSection } from './management_section';
-export { ManagementSidebarNav } from './components'; // for use in legacy management apps
+export type ManagementAppMountParams = ManagementItemMountParams;
+export type RegisterManagementAppArgs = Omit;
+export type ManagementApp = Omit;
+export type ManagementSection = Omit;
+
+export { ManagementSetup, ManagementStart } from './types';
diff --git a/src/plugins/management/public/legacy/redirect_messages.tsx b/src/plugins/management/public/legacy/redirect_messages.tsx
deleted file mode 100644
index f8cb975e6fae5..0000000000000
--- a/src/plugins/management/public/legacy/redirect_messages.tsx
+++ /dev/null
@@ -1,67 +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 React from 'react';
-import { EuiCallOut } from '@elastic/eui';
-import { NotificationsStart, OverlayStart } from 'kibana/public';
-import { parse } from 'query-string';
-import { i18n } from '@kbn/i18n';
-import { toMountPoint } from '../../../kibana_react/public';
-import { MarkdownSimple } from '../../../kibana_react/public';
-
-/**
- * Show banners and toasts carried over from other applications. This is only necessary as long as
- * management is rendered in the legacy platform (which requires a full page reload to switch to).
- *
- * Once management is rendered using the core application service, this file and the places setting
- * bannerMessage and notFoundMessage URL params can be removed.
- * @param notifications Core notifications service
- * @param overlays Core overlays service
- */
-export function showLegacyRedirectMessages(
- notifications: NotificationsStart,
- overlays: OverlayStart
-) {
- const queryPosition = window.location.hash.indexOf('?');
- if (queryPosition === -1) {
- return;
- }
-
- const urlParams = parse(window.location.hash.substr(queryPosition)) as Record;
-
- if (urlParams.bannerMessage) {
- const bannerId = overlays.banners.add(
- toMountPoint(
-
- )
- );
- setTimeout(() => {
- overlays.banners.remove(bannerId);
- }, 15000);
- }
-
- if (urlParams.notFoundMessage) {
- notifications.toasts.addWarning({
- title: i18n.translate('management.history.savedObjectIsMissingNotificationMessage', {
- defaultMessage: 'Saved object is missing',
- }),
- text: toMountPoint({urlParams.notFoundMessage}),
- });
- }
-}
diff --git a/src/plugins/management/public/legacy/section.js b/src/plugins/management/public/legacy/section.js
deleted file mode 100644
index 7d733b7b3173b..0000000000000
--- a/src/plugins/management/public/legacy/section.js
+++ /dev/null
@@ -1,160 +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 { assign } from 'lodash';
-import { IndexedArray } from '../../../../legacy/ui/public/indexed_array';
-
-const listeners = [];
-
-export class LegacyManagementSection {
- /**
- * @param {string} id
- * @param {object} options
- * @param {number|null} options.order
- * @param {string|null} options.display - defaults to id
- * @param {string|null} options.url - defaults to ''
- * @param {boolean|null} options.visible - defaults to true
- * @param {boolean|null} options.disabled - defaults to false
- * @param {string|null} options.tooltip - defaults to ''
- * @param {string|null} options.icon - defaults to ''
- * @returns {ManagementSection}
- */
-
- constructor(id, options = {}, capabilities) {
- this.display = id;
- this.id = id;
- this.items = new IndexedArray({
- index: ['id'],
- order: ['order'],
- });
- this.visible = true;
- this.disabled = false;
- this.tooltip = '';
- this.icon = '';
- this.url = '';
- this.capabilities = capabilities;
-
- assign(this, options);
- }
-
- get visibleItems() {
- return this.items.inOrder.filter(item => {
- const capabilityManagementSection = this.capabilities.management[this.id];
- const itemCapability = capabilityManagementSection
- ? capabilityManagementSection[item.id]
- : null;
-
- return item.visible && itemCapability !== false;
- });
- }
-
- /**
- * Registers a callback that will be executed when management sections are updated
- * Globally bound to solve for sidebar nav needs
- *
- * @param {function} fn
- */
- addListener(fn) {
- listeners.push(fn);
- }
-
- /**
- * Registers a sub-section
- *
- * @param {string} id
- * @param {object} options
- * @returns {ManagementSection}
- */
-
- register(id, options = {}) {
- const item = new LegacyManagementSection(
- id,
- assign(options, { parent: this }),
- this.capabilities
- );
-
- if (this.hasItem(id)) {
- throw new Error(`'${id}' is already registered`);
- }
-
- this.items.push(item);
- listeners.forEach(fn => fn());
-
- return item;
- }
-
- /**
- * Deregisters a section
- *
- * @param {string} id
- */
- deregister(id) {
- this.items.remove(item => item.id === id);
- listeners.forEach(fn => fn(this.items));
- }
-
- /**
- * Determine if an id is already registered
- *
- * @param {string} id
- * @returns {boolean}
- */
-
- hasItem(id) {
- return this.items.byId.hasOwnProperty(id);
- }
-
- /**
- * Fetches a section by id
- *
- * @param {string} id
- * @returns {ManagementSection}
- */
-
- getSection(id) {
- if (!id) {
- return;
- }
-
- const sectionPath = id.split('/');
- return sectionPath.reduce((currentSection, nextSection) => {
- if (!currentSection) {
- return;
- }
-
- return currentSection.items.byId[nextSection];
- }, this);
- }
-
- hide() {
- this.visible = false;
- }
-
- show() {
- this.visible = true;
- }
-
- disable() {
- this.disabled = true;
- }
-
- enable() {
- this.disabled = false;
- }
-}
diff --git a/src/plugins/management/public/legacy/section.test.js b/src/plugins/management/public/legacy/section.test.js
deleted file mode 100644
index 45cc80ef80edd..0000000000000
--- a/src/plugins/management/public/legacy/section.test.js
+++ /dev/null
@@ -1,285 +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 { LegacyManagementSection } from './section';
-import { IndexedArray } from '../../../../legacy/ui/public/indexed_array';
-
-const capabilitiesMock = {
- management: {
- kibana: { sampleFeature2: false },
- },
-};
-
-describe('ManagementSection', () => {
- describe('constructor', () => {
- it('defaults display to id', () => {
- const section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
- expect(section.display).toBe('kibana');
- });
-
- it('defaults visible to true', () => {
- const section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
- expect(section.visible).toBe(true);
- });
-
- it('defaults disabled to false', () => {
- const section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
- expect(section.disabled).toBe(false);
- });
-
- it('defaults tooltip to empty string', () => {
- const section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
- expect(section.tooltip).toBe('');
- });
-
- it('defaults url to empty string', () => {
- const section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
- expect(section.url).toBe('');
- });
-
- it('exposes items', () => {
- const section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
- expect(section.items).toHaveLength(0);
- });
-
- it('exposes visibleItems', () => {
- const section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
- expect(section.visibleItems).toHaveLength(0);
- });
-
- it('assigns all options', () => {
- const section = new LegacyManagementSection(
- 'kibana',
- { description: 'test', url: 'foobar' },
- capabilitiesMock
- );
- expect(section.description).toBe('test');
- expect(section.url).toBe('foobar');
- });
- });
-
- describe('register', () => {
- let section;
-
- beforeEach(() => {
- section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
- });
-
- it('returns a ManagementSection', () => {
- expect(section.register('about')).toBeInstanceOf(LegacyManagementSection);
- });
-
- it('provides a reference to the parent', () => {
- expect(section.register('about').parent).toBe(section);
- });
-
- it('adds item', function() {
- section.register('about', { description: 'test' });
-
- expect(section.items).toHaveLength(1);
- expect(section.items[0]).toBeInstanceOf(LegacyManagementSection);
- expect(section.items[0].id).toBe('about');
- });
-
- it('can only register a section once', () => {
- let threwException = false;
- section.register('about');
-
- try {
- section.register('about');
- } catch (e) {
- threwException = e.message.indexOf('is already registered') > -1;
- }
-
- expect(threwException).toBe(true);
- });
-
- it('calls listener when item added', () => {
- let listerCalled = false;
- const listenerFn = () => {
- listerCalled = true;
- };
-
- section.addListener(listenerFn);
- section.register('about');
- expect(listerCalled).toBe(true);
- });
- });
-
- describe('deregister', () => {
- let section;
-
- beforeEach(() => {
- section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
- section.register('about');
- });
-
- it('deregisters an existing section', () => {
- section.deregister('about');
- expect(section.items).toHaveLength(0);
- });
-
- it('allows deregistering a section more than once', () => {
- section.deregister('about');
- section.deregister('about');
- expect(section.items).toHaveLength(0);
- });
-
- it('calls listener when item added', () => {
- let listerCalled = false;
- const listenerFn = () => {
- listerCalled = true;
- };
-
- section.addListener(listenerFn);
- section.deregister('about');
- expect(listerCalled).toBe(true);
- });
- });
-
- describe('getSection', () => {
- let section;
-
- beforeEach(() => {
- section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
- section.register('about');
- });
-
- it('returns registered section', () => {
- expect(section.getSection('about')).toBeInstanceOf(LegacyManagementSection);
- });
-
- it('returns undefined if un-registered', () => {
- expect(section.getSection('unknown')).not.toBeDefined();
- });
-
- it('returns sub-sections specified via a /-separated path', () => {
- section.getSection('about').register('time');
- expect(section.getSection('about/time')).toBeInstanceOf(LegacyManagementSection);
- expect(section.getSection('about/time')).toBe(section.getSection('about').getSection('time'));
- });
-
- it('returns undefined if a sub-section along a /-separated path does not exist', () => {
- expect(section.getSection('about/damn/time')).toBe(undefined);
- });
- });
-
- describe('items', () => {
- let section;
-
- beforeEach(() => {
- section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
-
- section.register('three', { order: 3 });
- section.register('one', { order: 1 });
- section.register('two', { order: 2 });
- });
-
- it('is an indexed array', () => {
- expect(section.items).toBeInstanceOf(IndexedArray);
- });
-
- it('is indexed on id', () => {
- const keys = Object.keys(section.items.byId).sort();
- expect(section.items.byId).toBeInstanceOf(Object);
-
- expect(keys).toEqual(['one', 'three', 'two']);
- });
-
- it('can be ordered', () => {
- const ids = section.items.inOrder.map(i => {
- return i.id;
- });
- expect(ids).toEqual(['one', 'two', 'three']);
- });
- });
-
- describe('visible', () => {
- let section;
-
- beforeEach(() => {
- section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
- });
-
- it('hide sets visible to false', () => {
- section.hide();
- expect(section.visible).toBe(false);
- });
-
- it('show sets visible to true', () => {
- section.hide();
- section.show();
- expect(section.visible).toBe(true);
- });
- });
-
- describe('disabled', () => {
- let section;
-
- beforeEach(() => {
- section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
- });
-
- it('disable sets disabled to true', () => {
- section.disable();
- expect(section.disabled).toBe(true);
- });
-
- it('enable sets disabled to false', () => {
- section.enable();
- expect(section.disabled).toBe(false);
- });
- });
-
- describe('visibleItems', () => {
- let section;
-
- beforeEach(() => {
- section = new LegacyManagementSection('kibana', {}, capabilitiesMock);
-
- section.register('three', { order: 3 });
- section.register('one', { order: 1 });
- section.register('two', { order: 2 });
- });
-
- it('maintains the order', () => {
- const ids = section.visibleItems.map(i => {
- return i.id;
- });
- expect(ids).toEqual(['one', 'two', 'three']);
- });
-
- it('does not include hidden items', () => {
- section.getSection('two').hide();
-
- const ids = section.visibleItems.map(i => {
- return i.id;
- });
- expect(ids).toEqual(['one', 'three']);
- });
-
- it('does not include visible items hidden via uiCapabilities', () => {
- section.register('sampleFeature2', { order: 4, visible: true });
- const ids = section.visibleItems.map(i => {
- return i.id;
- });
- expect(ids).toEqual(['one', 'two', 'three']);
- });
- });
-});
diff --git a/src/plugins/management/public/legacy/sections_register.js b/src/plugins/management/public/legacy/sections_register.js
deleted file mode 100644
index aae58ba3e4651..0000000000000
--- a/src/plugins/management/public/legacy/sections_register.js
+++ /dev/null
@@ -1,64 +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 { LegacyManagementSection } from './section';
-import { i18n } from '@kbn/i18n';
-
-export class LegacyManagementAdapter {
- main = undefined;
- init = capabilities => {
- this.main = new LegacyManagementSection(
- 'management',
- {
- display: i18n.translate('management.displayName', {
- defaultMessage: 'Stack Management',
- }),
- },
- capabilities
- );
-
- this.main.register('data', {
- display: i18n.translate('management.connectDataDisplayName', {
- defaultMessage: 'Connect Data',
- }),
- order: 0,
- });
-
- this.main.register('elasticsearch', {
- display: 'Elasticsearch',
- order: 20,
- icon: 'logoElasticsearch',
- });
-
- this.main.register('kibana', {
- display: 'Kibana',
- order: 30,
- icon: 'logoKibana',
- });
-
- this.main.register('logstash', {
- display: 'Logstash',
- order: 30,
- icon: 'logoLogstash',
- });
-
- return this.main;
- };
- getManagement = () => this.main;
-}
diff --git a/src/plugins/management/public/management_app.test.tsx b/src/plugins/management/public/management_app.test.tsx
deleted file mode 100644
index a76b234d95ef5..0000000000000
--- a/src/plugins/management/public/management_app.test.tsx
+++ /dev/null
@@ -1,66 +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 * 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(Test App - Hello world!
, 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);
-});
diff --git a/src/plugins/management/public/management_app.tsx b/src/plugins/management/public/management_app.tsx
deleted file mode 100644
index 843bbfde654ee..0000000000000
--- a/src/plugins/management/public/management_app.tsx
+++ /dev/null
@@ -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 * 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, StartServicesAccessor } from '../../../core/public/';
-
-export class ManagementApp {
- readonly id: string;
- readonly title: string;
- readonly basePath: string;
- readonly order: number;
- readonly mount: ManagementSectionMount;
- private enabledStatus = true;
-
- constructor(
- { id, title, basePath, order = 100, mount }: CreateManagementApp,
- getSections: () => ManagementSection[],
- registerLegacyApp: KibanaLegacySetup['registerLegacyApp'],
- getLegacyManagementSections: () => LegacyManagementSection,
- getStartServices: StartServicesAccessor
- ) {
- 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;
- if (!this.enabledStatus) {
- const [coreStart] = await getStartServices();
- coreStart.application.navigateToApp('kibana#/management');
- return () => {};
- }
- async function setBreadcrumbs(crumbs: ChromeBreadcrumb[]) {
- const [coreStart] = await getStartServices();
- coreStart.chrome.setBreadcrumbs([
- {
- text: i18n.translate('management.breadcrumb', {
- defaultMessage: 'Stack Management',
- }),
- href: '#/management',
- },
- ...crumbs,
- ]);
- }
-
- ReactDOM.render(
- {
- 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;
- }
-}
diff --git a/src/plugins/management/public/management_section.test.ts b/src/plugins/management/public/management_item.test.ts
similarity index 56%
rename from src/plugins/management/public/management_section.test.ts
rename to src/plugins/management/public/management_item.test.ts
index c68175ee0a678..d8d69f0c4ff59 100644
--- a/src/plugins/management/public/management_section.test.ts
+++ b/src/plugins/management/public/management_item.test.ts
@@ -17,34 +17,21 @@
* under the License.
*/
-import { ManagementSection } from './management_section';
-// @ts-ignore
-import { LegacyManagementSection } from './legacy';
-import { coreMock } from '../../../core/public/mocks';
+import { ManagementItem } from './management_item';
-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
- );
-}
+const createSection = (
+ config: ManagementItem = {
+ id: 'test-section',
+ title: 'Test Section',
+ } as ManagementItem
+) => new ManagementItem(config);
test('cannot register two apps with the same id', () => {
- const registerLegacyApp = jest.fn();
- const section = createSection(registerLegacyApp);
-
+ const section = createSection();
const testAppConfig = { id: 'test-app', title: 'Test App', mount: () => () => {} };
section.registerApp(testAppConfig);
- expect(registerLegacyApp).toHaveBeenCalled();
+
expect(section.apps.length).toEqual(1);
expect(() => {
@@ -53,13 +40,14 @@ test('cannot register two apps with the same id', () => {
});
test('can enable and disable apps', () => {
- const registerLegacyApp = jest.fn();
- const section = createSection(registerLegacyApp);
-
+ const section = createSection();
const testAppConfig = { id: 'test-app', title: 'Test App', mount: () => () => {} };
const app = section.registerApp(testAppConfig);
- expect(section.getAppsEnabled().length).toEqual(1);
+
+ expect(section.getEnabledItems().length).toEqual(1);
+
app.disable();
- expect(section.getAppsEnabled().length).toEqual(0);
+
+ expect(section.getEnabledItems().length).toEqual(0);
});
diff --git a/src/plugins/management/public/management_item.ts b/src/plugins/management/public/management_item.ts
new file mode 100644
index 0000000000000..f3bb536cef5b3
--- /dev/null
+++ b/src/plugins/management/public/management_item.ts
@@ -0,0 +1,87 @@
+/*
+ * 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 { CreateManagementItemArgs, MANAGEMENT_SECTION_TYPE, Mount } from './types';
+
+export class ManagementItem {
+ public readonly id: string = '';
+ public readonly title: string = '';
+ public readonly apps: any[] = [];
+ public readonly order: number;
+ public readonly euiIconType?: string;
+ public readonly icon?: string;
+ public readonly mount?: Mount;
+
+ public enabled: boolean = true;
+ public basePath?: string;
+ public type: MANAGEMENT_SECTION_TYPE;
+
+ constructor({
+ id,
+ title,
+ order = 100,
+ euiIconType,
+ basePath,
+ icon,
+ mount,
+ type,
+ }: CreateManagementItemArgs) {
+ this.id = id;
+ this.title = title;
+ this.order = order;
+ this.euiIconType = euiIconType;
+ this.icon = icon;
+ this.basePath = basePath;
+ this.mount = mount;
+ this.type = type || MANAGEMENT_SECTION_TYPE.SECTION;
+ }
+
+ registerApp(args: CreateManagementItemArgs) {
+ if (this.getApp(args.id)) {
+ throw new Error(`Management app already registered - id: ${args.id}, title: ${args.title}`);
+ }
+ const basePath = `/${this.id}/${args.id}`;
+
+ const section = new ManagementItem({
+ ...args,
+ type: MANAGEMENT_SECTION_TYPE.APP,
+ basePath,
+ });
+
+ this.apps.push(section);
+
+ return section;
+ }
+
+ getApp(id: string) {
+ return this.apps.find(app => app.id === id);
+ }
+
+ getEnabledItems() {
+ return this.apps.filter(app => app.enabled).sort((a, b) => a.order - b.order);
+ }
+
+ disable() {
+ this.enabled = false;
+ }
+
+ enable() {
+ this.enabled = true;
+ }
+}
diff --git a/src/plugins/management/public/management_section.ts b/src/plugins/management/public/management_section.ts
deleted file mode 100644
index 483605341ae4c..0000000000000
--- a/src/plugins/management/public/management_section.ts
+++ /dev/null
@@ -1,78 +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 { CreateSection, RegisterManagementAppArgs } from './types';
-import { KibanaLegacySetup } from '../../kibana_legacy/public';
-import { StartServicesAccessor } 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: StartServicesAccessor;
-
- constructor(
- { id, title, order = 100, euiIconType, icon }: CreateSection,
- getSections: () => ManagementSection[],
- registerLegacyApp: KibanaLegacySetup['registerLegacyApp'],
- getLegacyManagementSection: () => ManagementSection,
- getStartServices: StartServicesAccessor
- ) {
- 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);
- }
-}
diff --git a/src/plugins/management/public/management_service.test.ts b/src/plugins/management/public/management_service.test.ts
index 18569ef285ff3..eb91d22a2ebfe 100644
--- a/src/plugins/management/public/management_service.test.ts
+++ b/src/plugins/management/public/management_service.test.ts
@@ -18,38 +18,47 @@
*/
import { ManagementService } from './management_service';
-import { coreMock } from '../../../core/public/mocks';
-import { npSetup } from '../../../legacy/ui/public/new_platform/__mocks__';
jest.mock('ui/new_platform');
-test('Provides default sections', () => {
- const service = new ManagementService().setup(
- npSetup.plugins.kibanaLegacy,
- () => {},
- coreMock.createSetup().getStartServices
- );
- expect(service.getAllSections().length).toEqual(2);
- expect(service.getSection('kibana')).not.toBeUndefined();
- expect(service.getSection('elasticsearch')).not.toBeUndefined();
-});
+describe('ManagementService', () => {
+ let managementService: ManagementService;
+
+ beforeEach(() => {
+ managementService = new ManagementService();
+ });
+
+ test('Provides default sections', () => {
+ managementService.setup();
+ const start = managementService.start();
+
+ expect(start.getSectionsEnabled().length).toEqual(2);
+ expect(start.getSection('kibana')).not.toBeUndefined();
+ expect(start.getSection('elasticsearch')).not.toBeUndefined();
+ });
+
+ test('Register section, enable and disable', () => {
+ // Setup phase:
+ const setup = managementService.setup();
+ const testSection = setup.register({ id: 'test-section', title: 'Test Section' });
+
+ expect(setup.getSection('test-section')).not.toBeUndefined();
+
+ const testApp = testSection.registerApp({
+ id: 'test-app',
+ title: 'Test App',
+ mount: () => () => {},
+ });
+
+ expect(testSection.getApp('test-app')).not.toBeUndefined();
+
+ // Start phase:
+ const start = managementService.start();
+
+ expect(start.getSectionsEnabled().length).toEqual(1);
+
+ testApp.disable();
-test('Register section, enable and disable', () => {
- const service = new ManagementService().setup(
- npSetup.plugins.kibanaLegacy,
- () => {},
- 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(start.getSectionsEnabled().length).toEqual(0);
});
- expect(testSection.getApp('test-app')).not.toBeUndefined();
- expect(service.getSectionsEnabled().length).toEqual(1);
- testApp.disable();
- expect(service.getSectionsEnabled().length).toEqual(0);
});
diff --git a/src/plugins/management/public/management_service.ts b/src/plugins/management/public/management_service.ts
index 8fc207e32e6ce..ec3e8f4de01f8 100644
--- a/src/plugins/management/public/management_service.ts
+++ b/src/plugins/management/public/management_service.ts
@@ -17,70 +17,34 @@
* 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 { StartServicesAccessor, CoreStart } from '../../../core/public';
+import { ManagementItem } from './management_item';
+import { CreateManagementItemArgs, SectionsServiceSetup, SectionsServiceStart } from './types';
+
+const getSectionByName = (sections: ManagementItem[], sectionId: ManagementItem['id']) => {
+ return sections.find(section => section.id === sectionId);
+};
export class ManagementService {
- private sections: ManagementSection[] = [];
+ private sections: ManagementItem[] = [];
- private register(
- registerLegacyApp: KibanaLegacySetup['registerLegacyApp'],
- getLegacyManagement: () => LegacyManagementSection,
- getStartServices: StartServicesAccessor
- ) {
- return (section: CreateSection) => {
- if (this.getSection(section.id)) {
- throw Error(`ManagementSection '${section.id}' already registered`);
- }
+ private getSection = (sectionId: ManagementItem['id']) =>
+ getSectionByName(this.sections, sectionId);
- 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 register = (section: CreateManagementItemArgs) => {
+ if (getSectionByName(this.sections, section.id)) {
+ throw Error(`ManagementSection '${section.id}' already registered`);
+ }
- private getAllSections() {
- return this.sections;
- }
-
- private getSectionsEnabled() {
- return this.sections
- .filter(section => section.getAppsEnabled().length > 0)
- .sort((a, b) => a.order - b.order);
- }
+ const newSection = new ManagementItem(section);
- private sharedInterface = {
- getSection: this.getSection.bind(this),
- getSectionsEnabled: this.getSectionsEnabled.bind(this),
- getAllSections: this.getAllSections.bind(this),
+ this.sections.push(newSection);
+ return newSection;
};
- public setup(
- kibanaLegacy: KibanaLegacySetup,
- getLegacyManagement: () => LegacyManagementSection,
- getStartServices: StartServicesAccessor
- ) {
- const register = this.register.bind(this)(
- kibanaLegacy.registerLegacyApp,
- getLegacyManagement,
- getStartServices
- );
+ setup(): SectionsServiceSetup {
+ this.register({ id: 'kibana', title: 'Kibana', order: 30, euiIconType: 'logoKibana' });
- register({ id: 'kibana', title: 'Kibana', order: 30, euiIconType: 'logoKibana' });
- register({
+ this.register({
id: 'elasticsearch',
title: 'Elasticsearch',
order: 20,
@@ -88,15 +52,19 @@ export class ManagementService {
});
return {
- register,
- ...this.sharedInterface,
+ register: this.register,
+ getSection: this.getSection,
};
}
- public start(navigateToApp: CoreStart['application']['navigateToApp']) {
+ start(): SectionsServiceStart {
return {
- navigateToApp, // apps are currently registered as top level apps but this may change in the future
- ...this.sharedInterface,
+ getSections: () => this.sections,
+ getSectionsEnabled: () =>
+ this.sections
+ .filter(section => section.enabled && section.apps.length)
+ .sort((a, b) => a.order - b.order),
+ getSection: this.getSection,
};
}
}
diff --git a/src/plugins/management/public/mocks/index.ts b/src/plugins/management/public/mocks/index.ts
index 82789d3c3f55f..696bed79f9b07 100644
--- a/src/plugins/management/public/mocks/index.ts
+++ b/src/plugins/management/public/mocks/index.ts
@@ -18,32 +18,33 @@
*/
import { ManagementSetup, ManagementStart } from '../types';
-import { ManagementSection } from '../management_section';
+import { ManagementItem } from '../management_item';
-const createManagementSectionMock = (): jest.Mocked> => {
- return {
+const createManagementSectionMock = () =>
+ (({
+ disable: jest.fn(),
+ enable: jest.fn(),
registerApp: jest.fn(),
getApp: jest.fn(),
- getAppsEnabled: jest.fn().mockReturnValue([]),
- };
-};
+ getEnabledItems: jest.fn().mockReturnValue([]),
+ } as unknown) as ManagementItem);
-const createSetupContract = (): DeeplyMockedKeys => ({
- sections: {
- register: jest.fn(),
- getSection: jest.fn().mockReturnValue(createManagementSectionMock()),
- getAllSections: jest.fn().mockReturnValue([]),
- },
-});
+const createSetupContract = () =>
+ ({
+ sections: {
+ register: jest.fn(),
+ getSection: jest.fn().mockReturnValue(createManagementSectionMock()),
+ },
+ } as ManagementSetup);
-const createStartContract = (): DeeplyMockedKeys => ({
- legacy: {},
- sections: {
- getSection: jest.fn(),
- getAllSections: jest.fn(),
- navigateToApp: jest.fn(),
- },
-});
+const createStartContract = () =>
+ ({
+ sections: {
+ getSection: jest.fn(),
+ getSections: jest.fn(),
+ getSectionsEnabled: jest.fn(),
+ },
+ } as ManagementStart);
export const managementPluginMock = {
createSetupContract,
diff --git a/src/plugins/management/public/plugin.ts b/src/plugins/management/public/plugin.ts
index e7f86996a9a1b..cdf9a2fe1ffb7 100644
--- a/src/plugins/management/public/plugin.ts
+++ b/src/plugins/management/public/plugin.ts
@@ -18,23 +18,20 @@
*/
import { i18n } from '@kbn/i18n';
-import { CoreSetup, CoreStart, Plugin } from 'kibana/public';
import { ManagementSetup, ManagementStart } from './types';
-import { ManagementService } from './management_service';
-import { KibanaLegacySetup } from '../../kibana_legacy/public';
import { FeatureCatalogueCategory, HomePublicPluginSetup } from '../../home/public';
-// @ts-ignore
-import { LegacyManagementAdapter } from './legacy';
-import { showLegacyRedirectMessages } from './legacy/redirect_messages';
+import { CoreSetup, CoreStart, Plugin, DEFAULT_APP_CATEGORIES } from '../../../core/public';
+
+import { ManagementService } from './management_service';
+
+interface ManagementSetupDependencies {
+ home: HomePublicPluginSetup;
+}
export class ManagementPlugin implements Plugin {
private managementSections = new ManagementService();
- private legacyManagement = new LegacyManagementAdapter();
- public setup(
- core: CoreSetup,
- { kibanaLegacy, home }: { kibanaLegacy: KibanaLegacySetup; home: HomePublicPluginSetup }
- ) {
+ public setup(core: CoreSetup, { home }: ManagementSetupDependencies) {
home.featureCatalogue.register({
id: 'stack-management',
title: i18n.translate('management.stackManagement.managementLabel', {
@@ -44,25 +41,38 @@ export class ManagementPlugin implements Plugin ManagementSection | undefined;
- getAllSections: () => ManagementSection[];
- register: RegisterSection;
+export interface SectionsServiceSetup {
+ register: (args: CreateManagementItemArgs) => ManagementItem;
+ getSection: (sectionId: ManagementItem['id']) => ManagementItem | undefined;
}
-interface SectionsServiceStart {
- getSection: (sectionId: ManagementSection['id']) => ManagementSection | undefined;
- getAllSections: () => ManagementSection[];
- navigateToApp: ApplicationStart['navigateToApp'];
+export interface SectionsServiceStart {
+ getSection: (sectionId: ManagementItem['id']) => ManagementItem | undefined;
+ getSectionsEnabled: () => ManagementItem[];
+ getSections: () => ManagementItem[];
}
-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 type Unmount = () => Promise | void;
+export type Mount = (params: ManagementItemMountParams) => Unmount | Promise;
-export interface RegisterManagementAppArgs {
- id: string;
- title: string;
- mount: ManagementSectionMount;
- order?: number;
+export enum MANAGEMENT_SECTION_TYPE {
+ SECTION = 'section',
+ APP = 'app',
}
-export type RegisterManagementApp = (managementApp: RegisterManagementAppArgs) => ManagementApp;
-
-export type Unmount = () => Promise | void;
-
-export interface ManagementAppMountParams {
+export interface ManagementItemMountParams {
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;
-
-export interface CreateManagementApp {
+export interface CreateManagementItemArgs {
id: string;
title: string;
- basePath: string;
order?: number;
- mount: ManagementSectionMount;
+ basePath?: string;
+ mount?: Mount;
+ euiIconType?: string; // takes precedence over `icon` property.
+ icon?: string; // URL to image file; fallback if no `euiIconType`
+ type?: MANAGEMENT_SECTION_TYPE;
}
-export interface LegacySection extends LegacyApp {
- visibleItems: LegacyApp[];
-}
+/** @internal **/
+export type CreateManagementItem = (args: CreateManagementItemArgs) => ManagementItem;
-export interface LegacyApp {
- disabled: boolean;
- visible: boolean;
- id: string;
- display: string;
- url?: string;
- euiIconType?: IconType;
- icon?: string;
- order: number;
-}
+/** @public **/
+export type CreateSection = CreateManagementItem;