diff --git a/x-pack/plugins/beats_management/common/constants/index.ts b/x-pack/plugins/beats_management/common/constants/index.ts index b45f5e947cab2..b4e919607c604 100644 --- a/x-pack/plugins/beats_management/common/constants/index.ts +++ b/x-pack/plugins/beats_management/common/constants/index.ts @@ -7,4 +7,4 @@ export { PLUGIN } from './plugin'; export { INDEX_NAMES } from './index_names'; export { UNIQUENESS_ENFORCING_TYPES, ConfigurationBlockTypes } from './configuration_blocks'; -export const BASE_PATH = '/management/beats/'; +export const BASE_PATH = '/management/beats_management/'; diff --git a/x-pack/plugins/beats_management/index.ts b/x-pack/plugins/beats_management/index.ts index 8b1ee828107dd..e6677d6bbcd57 100644 --- a/x-pack/plugins/beats_management/index.ts +++ b/x-pack/plugins/beats_management/index.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import Joi from 'joi'; -import { resolve } from 'url'; +import { resolve } from 'path'; import { PLUGIN } from './common/constants'; import { initServerWithKibana } from './server/kibana.index'; @@ -22,16 +22,17 @@ export const configPrefix = 'xpack.beats'; export function beats(kibana: any) { return new kibana.Plugin({ - config: () => config, - configPrefix, id: PLUGIN.ID, require: ['kibana', 'elasticsearch', 'xpack_main'], - init(server: any) { - initServerWithKibana(server); - }, publicDir: resolve(__dirname, 'public'), uiExports: { managementSections: ['plugins/beats_management'], }, + config: () => config, + configPrefix, + + init(server: any) { + initServerWithKibana(server); + }, }); } diff --git a/x-pack/plugins/beats_management/public/index.tsx b/x-pack/plugins/beats_management/public/index.tsx index 20f82f9ec3f3a..1334deb1524e6 100644 --- a/x-pack/plugins/beats_management/public/index.tsx +++ b/x-pack/plugins/beats_management/public/index.tsx @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { createHashHistory } from 'history'; import React from 'react'; import { BASE_PATH } from '../common/constants'; import { compose } from './lib/compose/kibana'; @@ -16,9 +15,8 @@ import { PageRouter } from './routes'; import '@elastic/eui/dist/eui_theme_light.css'; function startApp(libs: any) { - const history = createHashHistory(); libs.framework.registerManagementSection('beats', 'Beats Management', BASE_PATH); - libs.framework.render(); + libs.framework.render(); } startApp(compose()); diff --git a/x-pack/plugins/beats_management/public/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/plugins/beats_management/public/lib/adapters/framework/kibana_framework_adapter.ts index 8ac20baab0f3f..042ebd71f9862 100644 --- a/x-pack/plugins/beats_management/public/lib/adapters/framework/kibana_framework_adapter.ts +++ b/x-pack/plugins/beats_management/public/lib/adapters/framework/kibana_framework_adapter.ts @@ -7,17 +7,14 @@ import { IModule, IScope } from 'angular'; import * as React from 'react'; import * as ReactDOM from 'react-dom'; + import { BufferedKibanaServiceCall, - Chrome, FrameworkAdapter, KibanaAdapterServiceRefs, KibanaUIConfig, - UiKibanaAdapterScope, } from '../../lib'; -const ROOT_ELEMENT_ID = 'react-beats-cm-root'; - export class KibanaFrameworkAdapter implements FrameworkAdapter { public appState: object; public kbnVersion?: string; @@ -26,11 +23,13 @@ export class KibanaFrameworkAdapter implements FrameworkAdapter { private adapterService: KibanaAdapterServiceProvider; private rootComponent: React.ReactElement | null = null; private uiModule: IModule; + private routes: any; - constructor(uiModule: IModule, management: any) { + constructor(uiModule: IModule, management: any, routes: any) { this.adapterService = new KibanaAdapterServiceProvider(); this.management = management; this.uiModule = uiModule; + this.routes = routes; this.appState = {}; } @@ -41,7 +40,7 @@ export class KibanaFrameworkAdapter implements FrameworkAdapter { }; public render = (component: React.ReactElement) => { - this.adapterService.callOrBuffer(() => (this.rootComponent = component)); + this.rootComponent = component; }; public registerManagementSection(pluginId: string, displayName: string, basePath: string) { @@ -58,73 +57,51 @@ export class KibanaFrameworkAdapter implements FrameworkAdapter { visible: true, display: displayName, order: 30, - url: `#/${basePath}`, + url: `#${basePath}`, }); this.register(this.uiModule); } + private manageAngularLifecycle($scope: any, $route: any, elem: any) { + const lastRoute = $route.current; + const deregister = $scope.$on('$locationChangeSuccess', () => { + const currentRoute = $route.current; + // if templates are the same we are on the same route + if (lastRoute.$$route.template === currentRoute.$$route.template) { + // this prevents angular from destroying scope + $route.current = lastRoute; + } + }); + $scope.$on('$destroy', () => { + if (deregister) { + deregister(); + } + // manually unmount component when scope is destroyed + if (elem) { + ReactDOM.unmountComponentAtNode(elem); + } + }); + } + private register = (adapterModule: IModule) => { - adapterModule.provider('kibanaAdapter', this.adapterService); - - adapterModule.directive('beatsCMKibanaAdapter', () => ({ - controller: ($scope: UiKibanaAdapterScope, $element: JQLite) => ({ - $onDestroy: () => { - const targetRootElement = $element[0].querySelector(`#${ROOT_ELEMENT_ID}`); - - if (targetRootElement) { - ReactDOM.unmountComponentAtNode(targetRootElement); - } - }, - $onInit: () => { - $scope.topNavMenu = []; - }, - $postLink: () => { - $scope.$watchGroup([], ([targetElement]) => { - if (!targetElement) { - return; - } - - ReactDOM.unmountComponentAtNode(targetElement); + const adapter = this; + this.routes.when(`/management/beats_management/?`, { + template: '
', + controllerAs: 'beatsManagement', + // tslint:disable-next-line: max-classes-per-file + controller: class BeatsManagementController { + constructor($scope: any, $route: any) { + $scope.$$postDigest(() => { + const elem = document.getElementById('beatsReactRoot'); + ReactDOM.render(adapter.rootComponent as React.ReactElement, elem); + adapter.manageAngularLifecycle($scope, $route, elem); }); - $scope.$watchGroup( - [() => this.rootComponent, () => $element[0].querySelector(`#${ROOT_ELEMENT_ID}`)], - ([rootComponent, targetElement]) => { - if (!targetElement) { - return; - } - - if (rootComponent) { - ReactDOM.render(rootComponent, targetElement); - } else { - ReactDOM.unmountComponentAtNode(targetElement); - } - } - ); - }, - }), - scope: true, - template: ` -
- `, - })); - - adapterModule.run(( - chrome: Chrome, - config: KibanaUIConfig, - kbnVersion: string, - Private: (provider: Provider) => Provider, - // @ts-ignore: inject kibanaAdapter to force eager instatiation - kibanaAdapter: any - ) => { - this.kbnVersion = kbnVersion; - - chrome.setRootTemplate( - '' - ); + $scope.$onInit = () => { + $scope.topNavMenu = []; + }; + } + }, }); }; } diff --git a/x-pack/plugins/beats_management/public/lib/compose/kibana.ts b/x-pack/plugins/beats_management/public/lib/compose/kibana.ts index fe23bbc1306b8..7a98e62c18459 100644 --- a/x-pack/plugins/beats_management/public/lib/compose/kibana.ts +++ b/x-pack/plugins/beats_management/public/lib/compose/kibana.ts @@ -6,21 +6,21 @@ import 'ui/autoload/all'; // @ts-ignore: path dynamic for kibana -import chrome from 'ui/chrome'; -// @ts-ignore: path dynamic for kibana import { management } from 'ui/management'; // @ts-ignore: path dynamic for kibana import { uiModules } from 'ui/modules'; // @ts-ignore: path dynamic for kibana +import routes from 'ui/routes'; +// @ts-ignore: path dynamic for kibana import { KibanaFrameworkAdapter } from '../adapters/framework/kibana_framework_adapter'; import { FrontendLibs } from '../lib'; export function compose(): FrontendLibs { // const kbnVersion = (window as any).__KBN__.version; - const pluginUIModule = uiModules.get('app/beats'); + const pluginUIModule = uiModules.get('app/beats_management'); - const framework = new KibanaFrameworkAdapter(pluginUIModule, management); + const framework = new KibanaFrameworkAdapter(pluginUIModule, management, routes); const libs: FrontendLibs = { framework, diff --git a/x-pack/plugins/beats_management/public/routes.tsx b/x-pack/plugins/beats_management/public/routes.tsx index d1f6db5ebf11d..f5863b28aaafa 100644 --- a/x-pack/plugins/beats_management/public/routes.tsx +++ b/x-pack/plugins/beats_management/public/routes.tsx @@ -4,24 +4,19 @@ * you may not use this file except in compliance with the Elastic License. */ -import { History } from 'history'; import React from 'react'; -import { Route, Router, Switch } from 'react-router-dom'; +import { HashRouter, Route, Switch } from 'react-router-dom'; import { NotFoundPage } from './pages/404'; import { HomePage } from './pages/home'; -interface RouterProps { - history: History; -} - -export const PageRouter: React.SFC = ({ history }) => { +export const PageRouter: React.SFC<{}> = () => { return ( - + - + ); }; diff --git a/x-pack/plugins/index_management/index.js b/x-pack/plugins/index_management/index.js index c3d3e8fe1caf5..9a78cfef48c13 100644 --- a/x-pack/plugins/index_management/index.js +++ b/x-pack/plugins/index_management/index.js @@ -12,15 +12,13 @@ import { registerStatsRoute } from './server/routes/api/stats'; import { registerLicenseChecker } from './server/lib/register_license_checker'; import { PLUGIN } from './common/constants'; -export function indexManagement(kibana) { +export function indexManagement(kibana) { return new kibana.Plugin({ id: PLUGIN.ID, publicDir: resolve(__dirname, 'public'), require: ['kibana', 'elasticsearch', 'xpack_main'], uiExports: { - managementSections: [ - 'plugins/index_management', - ] + managementSections: ['plugins/index_management'], }, init: function (server) { registerLicenseChecker(server); @@ -28,6 +26,6 @@ export function indexManagement(kibana) { registerSettingsRoutes(server); registerStatsRoute(server); registerMappingRoute(server); - } + }, }); }