Skip to content

Commit

Permalink
[APM] Start moving to renderApp
Browse files Browse the repository at this point in the history
Extract app rendering to a renderApp method.

Use start core and plugins in context to be ready for getStartServices API.
  • Loading branch information
smith committed Dec 12, 2019
1 parent fe44595 commit c946200
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 91 deletions.
8 changes: 4 additions & 4 deletions x-pack/legacy/plugins/apm/public/context/ApmPluginContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { CoreStart, PackageInfo } from 'kibana/public';
import { createContext } from 'react';
import { AppMountContext, PackageInfo } from 'kibana/public';
import { ApmPluginSetupDeps, ConfigSchema } from '../new-platform/plugin';
import { ApmPluginStartDeps, ConfigSchema } from '../new-platform/plugin';

export interface ApmPluginContextValue {
config: ConfigSchema;
core: AppMountContext['core'];
core: CoreStart;
packageInfo: PackageInfo;
plugins: ApmPluginSetupDeps;
plugins: ApmPluginStartDeps;
}

export const ApmPluginContext = createContext({} as ApmPluginContextValue);
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { AppMountParameters } from 'kibana/public';
import React from 'react';
import ReactDOM from 'react-dom';
import { Route, Router, Switch } from 'react-router-dom';
import styled from 'styled-components';
import { routes } from '../../components/app/Main/route_config';
import { ScrollToTopOnPathChange } from '../../components/app/Main/ScrollToTopOnPathChange';
import { UpdateBreadcrumbs } from '../../components/app/Main/UpdateBreadcrumbs';
import {
ApmPluginContext,
ApmPluginContextValue
} from '../../context/ApmPluginContext';
import { LicenseProvider } from '../../context/LicenseContext';
import { LoadingIndicatorProvider } from '../../context/LoadingIndicatorContext';
import { LocationProvider } from '../../context/LocationContext';
import { MatchedRouteProvider } from '../../context/MatchedRouteContext';
import { UrlParamsProvider } from '../../context/UrlParamsContext';
import { px, unit, units } from '../../style/variables';
import { history } from '../../utils/history';

const MainContainer = styled.main`
min-width: ${px(unit * 50)};
padding: ${px(units.plus)};
height: 100%;
`;

const App = ({
apmPluginContextValue
}: {
apmPluginContextValue: ApmPluginContextValue;
}) => {
const i18nCore = apmPluginContextValue.core.i18n;

return (
<ApmPluginContext.Provider value={apmPluginContextValue}>
<i18nCore.Context>
<Router history={history}>
<LocationProvider>
<MatchedRouteProvider routes={routes}>
<UrlParamsProvider>
<LoadingIndicatorProvider>
<LicenseProvider>
<MainContainer data-test-subj="apmMainContainer">
<UpdateBreadcrumbs routes={routes} />
<Route component={ScrollToTopOnPathChange} />
<Switch>
{routes.map((route, i) => (
<Route key={i} {...route} />
))}
</Switch>
</MainContainer>
</LicenseProvider>
</LoadingIndicatorProvider>
</UrlParamsProvider>
</MatchedRouteProvider>
</LocationProvider>
</Router>
</i18nCore.Context>
</ApmPluginContext.Provider>
);
};

export function renderApp(
apmPluginContextValue: ApmPluginContextValue,
params: AppMountParameters
) {
ReactDOM.render(
<App apmPluginContextValue={apmPluginContextValue} />,
params.element
);
return () => ReactDOM.unmountComponentAtNode(params.element);
}
123 changes: 36 additions & 87 deletions x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,68 +4,39 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, Switch } from 'react-router-dom';
import styled from 'styled-components';
import { metadata } from 'ui/metadata';
import { HomePublicPluginSetup } from '../../../../../../src/plugins/home/public';
import {
AppMountParameters,
CoreSetup,
CoreStart,
PackageInfo,
Plugin,
CoreSetup,
PluginInitializerContext,
PackageInfo
PluginInitializerContext
} from '../../../../../../src/core/public';
import { DataPublicPluginSetup } from '../../../../../../src/plugins/data/public';
import { history } from '../utils/history';
import { LocationProvider } from '../context/LocationContext';
import { UrlParamsProvider } from '../context/UrlParamsContext';
import { px, unit, units } from '../style/variables';
import { LoadingIndicatorProvider } from '../context/LoadingIndicatorContext';
import { LicenseProvider } from '../context/LicenseContext';
import { UpdateBreadcrumbs } from '../components/app/Main/UpdateBreadcrumbs';
import { routes } from '../components/app/Main/route_config';
import { ScrollToTopOnPathChange } from '../components/app/Main/ScrollToTopOnPathChange';
import { MatchedRouteProvider } from '../context/MatchedRouteContext';
import { DataPublicPluginStart } from '../../../../../../src/plugins/data/public';
import { HomePublicPluginSetup } from '../../../../../../src/plugins/home/public';
import { ApmPluginContextValue } from '../context/ApmPluginContext';
import { createStaticIndexPattern } from '../services/rest/index_pattern';
import { setHelpExtension } from './setHelpExtension';
import { setReadonlyBadge } from './updateBadge';
import { renderApp } from './application';
import { featureCatalogueEntry } from './featureCatalogueEntry';
import { getConfigFromInjectedMetadata } from './getConfigFromInjectedMetadata';
import { setHelpExtension } from './setHelpExtension';
import { toggleAppLinkInNav } from './toggleAppLinkInNav';
import { ApmPluginContext } from '../context/ApmPluginContext';
import { setReadonlyBadge } from './updateBadge';

export const REACT_APP_ROOT_ID = 'react-apm-root';

const MainContainer = styled.main`
min-width: ${px(unit * 50)};
padding: ${px(units.plus)};
height: 100%;
`;

const App = () => {
return (
<MainContainer data-test-subj="apmMainContainer">
<UpdateBreadcrumbs routes={routes} />
<Route component={ScrollToTopOnPathChange} />
<Switch>
{routes.map((route, i) => (
<Route key={i} {...route} />
))}
</Switch>
</MainContainer>
);
};

export type ApmPluginSetup = void;
export type ApmPluginStart = void;

export interface ApmPluginSetupDeps {
data: DataPublicPluginSetup;
home: HomePublicPluginSetup;
}

export interface ApmPluginStartDeps {
data: DataPublicPluginStart;
}

export interface ConfigSchema {
indexPatternTitle: string;
serviceMapEnabled: boolean;
Expand All @@ -76,28 +47,18 @@ export interface ConfigSchema {

export class ApmPlugin
implements Plugin<ApmPluginSetup, ApmPluginStart, ApmPluginSetupDeps, {}> {
// When we switch over from the old platform to new platform the plugins will
// be coming from setup instead of start, since that's where we do
// `core.application.register`. During the transitions we put plugins on an
// instance property so we can use it in start.
setupPlugins: ApmPluginSetupDeps = {} as ApmPluginSetupDeps;

constructor(
// @ts-ignore Not using initializerContext now, but will be once NP
// migration is complete.
private readonly initializerContext: PluginInitializerContext<ConfigSchema>
) {}

// Take the DOM element as the constructor, so we can mount the app.
public setup(_core: CoreSetup, plugins: ApmPluginSetupDeps) {
plugins.home.featureCatalogue.register(featureCatalogueEntry);
this.setupPlugins = plugins;
public setup(_coreSetup: CoreSetup, depsSetup: ApmPluginSetupDeps) {
depsSetup.home.featureCatalogue.register(featureCatalogueEntry);
}

public start(core: CoreStart) {
const i18nCore = core.i18n;
const plugins = this.setupPlugins;

public start(coreStart: CoreStart, depsStart: ApmPluginStartDeps) {
// Once we're actually an NP plugin we'll get the config from the
// initializerContext like:
//
Expand All @@ -115,43 +76,31 @@ export class ApmPlugin
const packageInfo = metadata as PackageInfo;

// render APM feedback link in global help menu
setHelpExtension(core);
setReadonlyBadge(core);
toggleAppLinkInNav(core, config);
setHelpExtension(coreStart);
setReadonlyBadge(coreStart);
toggleAppLinkInNav(coreStart, config);

// create static index pattern and store as saved object. Not needed by APM UI but for legacy reasons in Discover, Dashboard etc.
createStaticIndexPattern(coreStart.http).catch(e => {
// eslint-disable-next-line no-console
console.log('Error fetching static index pattern', e);
});

const apmPluginContextValue = {
const apmPluginContextValue: ApmPluginContextValue = {
config,
core,
core: coreStart,
packageInfo,
plugins
plugins: depsStart
};

ReactDOM.render(
<ApmPluginContext.Provider value={apmPluginContextValue}>
<i18nCore.Context>
<Router history={history}>
<LocationProvider>
<MatchedRouteProvider routes={routes}>
<UrlParamsProvider>
<LoadingIndicatorProvider>
<LicenseProvider>
<App />
</LicenseProvider>
</LoadingIndicatorProvider>
</UrlParamsProvider>
</MatchedRouteProvider>
</LocationProvider>
</Router>
</i18nCore.Context>
</ApmPluginContext.Provider>,
document.getElementById(REACT_APP_ROOT_ID)
);
const params: AppMountParameters = {
appBasePath: coreStart.http.basePath.get(),
element: document.getElementById(REACT_APP_ROOT_ID) as HTMLElement
};

// create static index pattern and store as saved object. Not needed by APM UI but for legacy reasons in Discover, Dashboard etc.
createStaticIndexPattern(core.http).catch(e => {
// eslint-disable-next-line no-console
console.log('Error fetching static index pattern', e);
});
// Call renderApp directly here in `start`. When when we switch to NP, we'll
// be calling the `mount` method of `core.application.register` in `setup`
renderApp(apmPluginContextValue, params);
}

public stop() {}
Expand Down

0 comments on commit c946200

Please sign in to comment.