Use modern mount context in Dev Tools and Console (#70379)

* Use modern mount context in Dev Tools and Console, and clean up plugin definitions of Grok Debugger, Search Profiler, and Painless Lab.

* Remove return value from Console lifecycle method.

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
CJ Cenizal 2020-07-01 12:40:52 -07:00 committed by GitHub
parent 97924a6d86
commit 91b8e7de24
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 89 additions and 84 deletions

View file

@ -18,17 +18,13 @@
*/ */
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { Plugin, CoreSetup } from 'src/core/public';
import { CoreSetup, CoreStart, Plugin } from 'kibana/public';
import { FeatureCatalogueCategory } from '../../home/public'; import { FeatureCatalogueCategory } from '../../home/public';
import { AppSetupUIPluginDependencies } from './types'; import { AppSetupUIPluginDependencies } from './types';
export class ConsoleUIPlugin implements Plugin<void, void, AppSetupUIPluginDependencies> { export class ConsoleUIPlugin implements Plugin<void, void, AppSetupUIPluginDependencies> {
constructor() {} public setup(
async setup(
{ notifications, getStartServices }: CoreSetup, { notifications, getStartServices }: CoreSetup,
{ devTools, home, usageCollection }: AppSetupUIPluginDependencies { devTools, home, usageCollection }: AppSetupUIPluginDependencies
) { ) {
@ -53,16 +49,25 @@ export class ConsoleUIPlugin implements Plugin<void, void, AppSetupUIPluginDepen
defaultMessage: 'Console', defaultMessage: 'Console',
}), }),
enableRouting: false, enableRouting: false,
mount: async ({ core: { docLinks, i18n: i18nDep } }, { element }) => { mount: async ({ element }) => {
const [core] = await getStartServices();
const {
injectedMetadata,
i18n: { Context: I18nContext },
docLinks: { DOC_LINK_VERSION },
} = core;
const { renderApp } = await import('./application'); const { renderApp } = await import('./application');
const [{ injectedMetadata }] = await getStartServices();
const elasticsearchUrl = injectedMetadata.getInjectedVar( const elasticsearchUrl = injectedMetadata.getInjectedVar(
'elasticsearchUrl', 'elasticsearchUrl',
'http://localhost:9200' 'http://localhost:9200'
) as string; ) as string;
return renderApp({ return renderApp({
docLinkVersion: docLinks.DOC_LINK_VERSION, docLinkVersion: DOC_LINK_VERSION,
I18nContext: i18nDep.Context, I18nContext,
notifications, notifications,
elasticsearchUrl, elasticsearchUrl,
usageCollection, usageCollection,
@ -72,5 +77,5 @@ export class ConsoleUIPlugin implements Plugin<void, void, AppSetupUIPluginDepen
}); });
} }
async start(core: CoreStart) {} public start() {}
} }

View file

@ -16,21 +16,21 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
import React, { useEffect, useRef } from 'react';
import ReactDOM from 'react-dom';
import { HashRouter as Router, Switch, Route, Redirect } from 'react-router-dom';
import { EuiTab, EuiTabs, EuiToolTip } from '@elastic/eui';
import { I18nProvider } from '@kbn/i18n/react'; import { I18nProvider } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { EuiTab, EuiTabs, EuiToolTip } from '@elastic/eui';
import { HashRouter as Router, Switch, Route, Redirect } from 'react-router-dom';
import * as React from 'react';
import ReactDOM from 'react-dom';
import { useEffect, useRef } from 'react';
import { AppMountContext, AppMountDeprecated, ScopedHistory } from 'kibana/public'; import { ApplicationStart, ChromeStart, ScopedHistory } from 'src/core/public';
import { DevToolApp } from './dev_tool'; import { DevToolApp } from './dev_tool';
interface DevToolsWrapperProps { interface DevToolsWrapperProps {
devTools: readonly DevToolApp[]; devTools: readonly DevToolApp[];
activeDevTool: DevToolApp; activeDevTool: DevToolApp;
appMountContext: AppMountContext;
updateRoute: (newRoute: string) => void; updateRoute: (newRoute: string) => void;
} }
@ -40,12 +40,7 @@ interface MountedDevToolDescriptor {
unmountHandler: () => void; unmountHandler: () => void;
} }
function DevToolsWrapper({ function DevToolsWrapper({ devTools, activeDevTool, updateRoute }: DevToolsWrapperProps) {
devTools,
activeDevTool,
appMountContext,
updateRoute,
}: DevToolsWrapperProps) {
const mountedTool = useRef<MountedDevToolDescriptor | null>(null); const mountedTool = useRef<MountedDevToolDescriptor | null>(null);
useEffect( useEffect(
@ -90,6 +85,7 @@ function DevToolsWrapper({
if (mountedTool.current) { if (mountedTool.current) {
mountedTool.current.unmountHandler(); mountedTool.current.unmountHandler();
} }
const params = { const params = {
element, element,
appBasePath: '', appBasePath: '',
@ -97,9 +93,9 @@ function DevToolsWrapper({
// TODO: adapt to use Core's ScopedHistory // TODO: adapt to use Core's ScopedHistory
history: {} as any, history: {} as any,
}; };
const unmountHandler = isAppMountDeprecated(activeDevTool.mount)
? await activeDevTool.mount(appMountContext, params) const unmountHandler = await activeDevTool.mount(params);
: await activeDevTool.mount(params);
mountedTool.current = { mountedTool.current = {
devTool: activeDevTool, devTool: activeDevTool,
mountpoint: element, mountpoint: element,
@ -112,19 +108,20 @@ function DevToolsWrapper({
); );
} }
function redirectOnMissingCapabilities(appMountContext: AppMountContext) { function redirectOnMissingCapabilities(application: ApplicationStart) {
if (!appMountContext.core.application.capabilities.dev_tools.show) { if (!application.capabilities.dev_tools.show) {
appMountContext.core.application.navigateToApp('home'); application.navigateToApp('home');
return true; return true;
} }
return false; return false;
} }
function setBadge(appMountContext: AppMountContext) { function setBadge(application: ApplicationStart, chrome: ChromeStart) {
if (appMountContext.core.application.capabilities.dev_tools.save) { if (application.capabilities.dev_tools.save) {
return; return;
} }
appMountContext.core.chrome.setBadge({
chrome.setBadge({
text: i18n.translate('devTools.badge.readOnly.text', { text: i18n.translate('devTools.badge.readOnly.text', {
defaultMessage: 'Read only', defaultMessage: 'Read only',
}), }),
@ -135,16 +132,16 @@ function setBadge(appMountContext: AppMountContext) {
}); });
} }
function setTitle(appMountContext: AppMountContext) { function setTitle(chrome: ChromeStart) {
appMountContext.core.chrome.docTitle.change( chrome.docTitle.change(
i18n.translate('devTools.pageTitle', { i18n.translate('devTools.pageTitle', {
defaultMessage: 'Dev Tools', defaultMessage: 'Dev Tools',
}) })
); );
} }
function setBreadcrumbs(appMountContext: AppMountContext) { function setBreadcrumbs(chrome: ChromeStart) {
appMountContext.core.chrome.setBreadcrumbs([ chrome.setBreadcrumbs([
{ {
text: i18n.translate('devTools.k7BreadcrumbsDevToolsLabel', { text: i18n.translate('devTools.k7BreadcrumbsDevToolsLabel', {
defaultMessage: 'Dev Tools', defaultMessage: 'Dev Tools',
@ -156,16 +153,19 @@ function setBreadcrumbs(appMountContext: AppMountContext) {
export function renderApp( export function renderApp(
element: HTMLElement, element: HTMLElement,
appMountContext: AppMountContext, application: ApplicationStart,
chrome: ChromeStart,
history: ScopedHistory, history: ScopedHistory,
devTools: readonly DevToolApp[] devTools: readonly DevToolApp[]
) { ) {
if (redirectOnMissingCapabilities(appMountContext)) { if (redirectOnMissingCapabilities(application)) {
return () => {}; return () => {};
} }
setBadge(appMountContext);
setBreadcrumbs(appMountContext); setBadge(application, chrome);
setTitle(appMountContext); setBreadcrumbs(chrome);
setTitle(chrome);
ReactDOM.render( ReactDOM.render(
<I18nProvider> <I18nProvider>
<Router> <Router>
@ -183,7 +183,6 @@ export function renderApp(
updateRoute={props.history.push} updateRoute={props.history.push}
activeDevTool={devTool} activeDevTool={devTool}
devTools={devTools} devTools={devTools}
appMountContext={appMountContext}
/> />
)} )}
/> />
@ -208,8 +207,3 @@ export function renderApp(
unlisten(); unlisten();
}; };
} }
function isAppMountDeprecated(mount: (...args: any[]) => any): mount is AppMountDeprecated {
// Mount functions with two arguments are assumed to expect deprecated `context` object.
return mount.length === 2;
}

View file

@ -16,7 +16,8 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
import { App } from 'kibana/public';
import { AppMount } from 'src/core/public';
/** /**
* Descriptor for a dev tool. A dev tool works similar to an application * Descriptor for a dev tool. A dev tool works similar to an application
@ -38,7 +39,7 @@ export class DevToolApp {
* This will be used as a label in the tab above the actual tool. * This will be used as a label in the tab above the actual tool.
*/ */
public readonly title: string; public readonly title: string;
public readonly mount: App['mount']; public readonly mount: AppMount;
/** /**
* Flag indicating to disable the tab of this dev tool. Navigating to a * Flag indicating to disable the tab of this dev tool. Navigating to a
@ -66,7 +67,7 @@ export class DevToolApp {
constructor( constructor(
id: string, id: string,
title: string, title: string,
mount: App['mount'], mount: AppMount,
enableRouting: boolean, enableRouting: boolean,
order: number, order: number,
toolTipContent = '', toolTipContent = '',

View file

@ -18,12 +18,14 @@
*/ */
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
import { AppUpdater, CoreSetup, Plugin } from 'kibana/public'; import { Plugin, CoreSetup, AppMountParameters } from 'src/core/public';
import { AppUpdater } from 'kibana/public';
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { sortBy } from 'lodash'; import { sortBy } from 'lodash';
import { AppNavLinkStatus, DEFAULT_APP_CATEGORIES } from '../../../core/public';
import { KibanaLegacySetup } from '../../kibana_legacy/public'; import { KibanaLegacySetup } from '../../kibana_legacy/public';
import { CreateDevToolArgs, DevToolApp, createDevToolApp } from './dev_tool'; import { CreateDevToolArgs, DevToolApp, createDevToolApp } from './dev_tool';
import { AppNavLinkStatus, DEFAULT_APP_CATEGORIES } from '../../../core/public';
import './index.scss'; import './index.scss';
@ -49,8 +51,10 @@ export class DevToolsPlugin implements Plugin<DevToolsSetup, void> {
return sortBy([...this.devTools.values()], 'order'); return sortBy([...this.devTools.values()], 'order');
} }
public setup(core: CoreSetup, { kibanaLegacy }: { kibanaLegacy: KibanaLegacySetup }) { public setup(coreSetup: CoreSetup, { kibanaLegacy }: { kibanaLegacy: KibanaLegacySetup }) {
core.application.register({ const { application: applicationSetup, getStartServices } = coreSetup;
applicationSetup.register({
id: 'dev_tools', id: 'dev_tools',
title: i18n.translate('devTools.devToolsTitle', { title: i18n.translate('devTools.devToolsTitle', {
defaultMessage: 'Dev Tools', defaultMessage: 'Dev Tools',
@ -59,15 +63,18 @@ export class DevToolsPlugin implements Plugin<DevToolsSetup, void> {
euiIconType: 'devToolsApp', euiIconType: 'devToolsApp',
order: 9001, order: 9001,
category: DEFAULT_APP_CATEGORIES.management, category: DEFAULT_APP_CATEGORIES.management,
mount: async (appMountContext, params) => { mount: async (params: AppMountParameters) => {
if (!this.getSortedDevTools) { const { element, history } = params;
throw new Error('not started yet'); element.classList.add('devAppWrapper');
}
const [core] = await getStartServices();
const { application, chrome } = core;
const { renderApp } = await import('./application'); const { renderApp } = await import('./application');
params.element.classList.add('devAppWrapper'); return renderApp(element, application, chrome, history, this.getSortedDevTools());
return renderApp(params.element, appMountContext, params.history, this.getSortedDevTools());
}, },
}); });
kibanaLegacy.forwardApp('dev_tools', 'dev_tools'); kibanaLegacy.forwardApp('dev_tools', 'dev_tools');
return { return {

View file

@ -4,8 +4,8 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import { Plugin } from './plugin'; import { GrokDebuggerUIPlugin } from './plugin';
export function plugin(initializerContext) { export function plugin(initializerContext) {
return new Plugin(initializerContext); return new GrokDebuggerUIPlugin(initializerContext);
} }

View file

@ -6,10 +6,11 @@
import { i18n } from '@kbn/i18n'; import { i18n } from '@kbn/i18n';
import { first } from 'rxjs/operators'; import { first } from 'rxjs/operators';
import { registerFeature } from './register_feature';
import { PLUGIN } from '../common/constants';
export class Plugin { import { PLUGIN } from '../common/constants';
import { registerFeature } from './register_feature';
export class GrokDebuggerUIPlugin {
setup(coreSetup, plugins) { setup(coreSetup, plugins) {
registerFeature(plugins.home); registerFeature(plugins.home);
@ -20,7 +21,7 @@ export class Plugin {
}), }),
id: PLUGIN.ID, id: PLUGIN.ID,
enableRouting: false, enableRouting: false,
async mount(context, { element }) { async mount({ element }) {
const [coreStart] = await coreSetup.getStartServices(); const [coreStart] = await coreSetup.getStartServices();
const license = await plugins.licensing.license$.pipe(first()).toPromise(); const license = await plugins.licensing.license$.pipe(first()).toPromise();
const { renderApp } = await import('./render_app'); const { renderApp } = await import('./render_app');

View file

@ -5,10 +5,10 @@
*/ */
import React from 'react'; import React from 'react';
import { i18n } from '@kbn/i18n';
import { Plugin, CoreStart, CoreSetup } from 'kibana/public';
import { first } from 'rxjs/operators'; import { first } from 'rxjs/operators';
import { EuiBetaBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { EuiBetaBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { Plugin, CoreSetup } from 'src/core/public';
import { FeatureCatalogueCategory } from '../../../../src/plugins/home/public'; import { FeatureCatalogueCategory } from '../../../../src/plugins/home/public';
@ -27,7 +27,7 @@ const checkLicenseStatus = (license: ILicense) => {
export class PainlessLabUIPlugin implements Plugin<void, void, PluginDependencies> { export class PainlessLabUIPlugin implements Plugin<void, void, PluginDependencies> {
languageService = new LanguageService(); languageService = new LanguageService();
async setup( public setup(
{ http, getStartServices, uiSettings }: CoreSetup, { http, getStartServices, uiSettings }: CoreSetup,
{ devTools, home, licensing }: PluginDependencies { devTools, home, licensing }: PluginDependencies
) { ) {
@ -70,7 +70,7 @@ export class PainlessLabUIPlugin implements Plugin<void, void, PluginDependencie
) as any, ) as any,
enableRouting: false, enableRouting: false,
disabled: false, disabled: false,
mount: async (ctx, { element }) => { mount: async ({ element }) => {
const [core] = await getStartServices(); const [core] = await getStartServices();
const { const {
@ -115,9 +115,9 @@ export class PainlessLabUIPlugin implements Plugin<void, void, PluginDependencie
}); });
} }
async start(core: CoreStart, plugins: any) {} public start() {}
async stop() { public stop() {
this.languageService.stop(); this.languageService.stop();
} }
} }

View file

@ -5,9 +5,8 @@
*/ */
import './styles/_index.scss'; import './styles/_index.scss';
import { PluginInitializerContext } from 'src/core/public';
import { SearchProfilerUIPlugin } from './plugin'; import { SearchProfilerUIPlugin } from './plugin';
export function plugin(ctx: PluginInitializerContext) { export function plugin() {
return new SearchProfilerUIPlugin(ctx); return new SearchProfilerUIPlugin();
} }

View file

@ -4,9 +4,9 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import { i18n } from '@kbn/i18n';
import { Plugin, CoreStart, CoreSetup, PluginInitializerContext } from 'kibana/public';
import { first } from 'rxjs/operators'; import { first } from 'rxjs/operators';
import { i18n } from '@kbn/i18n';
import { Plugin, CoreSetup } from 'src/core/public';
import { FeatureCatalogueCategory } from '../../../../src/plugins/home/public'; import { FeatureCatalogueCategory } from '../../../../src/plugins/home/public';
import { ILicense } from '../../licensing/common/types'; import { ILicense } from '../../licensing/common/types';
@ -20,9 +20,7 @@ const checkLicenseStatus = (license: ILicense) => {
}; };
export class SearchProfilerUIPlugin implements Plugin<void, void, AppPublicPluginDependencies> { export class SearchProfilerUIPlugin implements Plugin<void, void, AppPublicPluginDependencies> {
constructor(ctx: PluginInitializerContext) {} public setup(
async setup(
{ http, getStartServices }: CoreSetup, { http, getStartServices }: CoreSetup,
{ devTools, home, licensing }: AppPublicPluginDependencies { devTools, home, licensing }: AppPublicPluginDependencies
) { ) {
@ -47,7 +45,7 @@ export class SearchProfilerUIPlugin implements Plugin<void, void, AppPublicPlugi
}), }),
order: 5, order: 5,
enableRouting: false, enableRouting: false,
mount: async (ctx, params) => { mount: async (params) => {
const [coreStart] = await getStartServices(); const [coreStart] = await getStartServices();
const { notifications, i18n: i18nDep } = coreStart; const { notifications, i18n: i18nDep } = coreStart;
const { boot } = await import('./application/boot'); const { boot } = await import('./application/boot');
@ -74,7 +72,7 @@ export class SearchProfilerUIPlugin implements Plugin<void, void, AppPublicPlugi
}); });
} }
async start(core: CoreStart, plugins: any) {} public start() {}
async stop() {} public stop() {}
} }