Skip to content

Commit

Permalink
Shim dev tools (#49349)
Browse files Browse the repository at this point in the history
  • Loading branch information
flash1293 authored Nov 14, 2019
1 parent d43c5c6 commit 62d0353
Show file tree
Hide file tree
Showing 53 changed files with 581 additions and 550 deletions.
3 changes: 0 additions & 3 deletions src/legacy/core_plugins/console/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ export default function(kibana: any) {
const npSrc = resolve(__dirname, 'np_ready/public');

let defaultVars: any;
const apps: any[] = [];
return new kibana.Plugin({
id: 'console',
require: ['elasticsearch'],
Expand Down Expand Up @@ -181,8 +180,6 @@ export default function(kibana: any) {
},

uiExports: {
apps,
hacks: ['plugins/console/quarantined/hacks/register'],
devTools: [`${npSrc}/legacy`],
styleSheetPaths: resolve(__dirname, 'public/quarantined/index.scss'),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export function Main() {
};

return (
<>
<div id="consoleRoot">
<EuiFlexGroup
className="consoleContainer"
gutterSize="none"
Expand Down Expand Up @@ -124,6 +124,6 @@ export function Main() {
{showSettings ? <Settings onClose={() => setShowSettings(false)} /> : null}

{showHelp ? <HelpPanel onClose={() => setShowHelp(false)} /> : null}
</>
</div>
);
}
69 changes: 10 additions & 59 deletions src/legacy/core_plugins/console/np_ready/public/legacy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,80 +24,31 @@ import 'brace/mode/json';
import 'brace/mode/text';

/* eslint-disable @kbn/eslint/no-restricted-paths */
import { toastNotifications as notifications } from 'ui/notify';
import { npSetup, npStart } from 'ui/new_platform';
import uiRoutes from 'ui/routes';
import { DOC_LINK_VERSION } from 'ui/documentation_links';
import { I18nContext } from 'ui/i18n';
import { ResizeChecker } from 'ui/resize_checker';
import 'ui/capabilities/route_setup';
/* eslint-enable @kbn/eslint/no-restricted-paths */

import template from '../../public/quarantined/index.html';
import { App, AppUnmount, NotificationsSetup } from '../../../../../core/public';

export interface XPluginSet {
devTools: DevToolsSetup;
feature_catalogue: FeatureCatalogueSetup;
__LEGACY: {
I18nContext: any;
ResizeChecker: any;
docLinkVersion: string;
};
}

import { plugin } from '.';
import { DevToolsSetup } from '../../../../../plugins/dev_tools/public';
import { FeatureCatalogueSetup } from '../../../../../plugins/feature_catalogue/public';

const pluginInstance = plugin({} as any);

const anyObject = {} as any;

uiRoutes.when('/dev_tools/console', {
requireUICapability: 'dev_tools.show',
controller: function RootController($scope) {
// Stub out this config for now...
$scope.topNavMenu = [];

$scope.initReactApp = () => {
const targetElement = document.querySelector<HTMLDivElement>('#consoleRoot');
if (!targetElement) {
const message = `Could not mount Console App!`;
npSetup.core.fatalErrors.add(message);
throw new Error(message);
}

let unmount: AppUnmount | Promise<AppUnmount>;

const mockedSetupCore = {
...npSetup.core,
notifications: (notifications as unknown) as NotificationsSetup,
application: {
register(app: App): void {
try {
unmount = app.mount(anyObject, { element: targetElement, appBasePath: '' });
} catch (e) {
npSetup.core.fatalErrors.add(e);
}
},
registerMountContext() {},
},
};

pluginInstance.setup(mockedSetupCore, {
...npSetup.plugins,
__LEGACY: {
I18nContext,
ResizeChecker,
docLinkVersion: DOC_LINK_VERSION,
},
});
pluginInstance.start(npStart.core);

$scope.$on('$destroy', async () => {
if (unmount) {
const fn = await unmount;
fn();
}
});
};
pluginInstance.setup(npSetup.core, {
...npSetup.plugins,
__LEGACY: {
I18nContext,
ResizeChecker,
},
template,
});
pluginInstance.start(npStart.core);
43 changes: 36 additions & 7 deletions src/legacy/core_plugins/console/np_ready/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,55 @@
*/

import { render, unmountComponentAtNode } from 'react-dom';
import { i18n } from '@kbn/i18n';

import { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
import { PluginInitializerContext, Plugin, CoreStart, CoreSetup } from '../../../../../core/public';
import { XPluginSet } from './legacy';
import { boot } from './application';

export class ConsoleUIPlugin implements Plugin<any, any> {
// @ts-ignore
constructor(private readonly ctx: PluginInitializerContext) {}

async setup({ application, notifications }: CoreSetup, pluginSet: XPluginSet) {
async setup({ notifications }: CoreSetup, pluginSet: XPluginSet) {
const {
__LEGACY: { docLinkVersion, I18nContext, ResizeChecker },
__LEGACY: { I18nContext, ResizeChecker },
devTools,
feature_catalogue,
} = pluginSet;

application.register({
feature_catalogue.register({
id: 'console',
title: i18n.translate('console.devToolsTitle', {
defaultMessage: 'Console',
}),
description: i18n.translate('console.devToolsDescription', {
defaultMessage: 'Skip cURL and use this JSON interface to work with your data directly.',
}),
icon: 'consoleApp',
path: '/app/kibana#/dev_tools/console',
showOnHomePage: true,
category: FeatureCatalogueCategory.ADMIN,
});

devTools.register({
id: 'console',
order: 1,
title: 'Console',
mount(ctx, { element }) {
render(boot({ docLinkVersion, I18nContext, ResizeChecker, notifications }), element);
title: i18n.translate('console.consoleDisplayName', {
defaultMessage: 'Console',
}),
enableRouting: false,
async mount(ctx, { element }) {
const { boot } = await import('./application');
render(
boot({
docLinkVersion: ctx.core.docLinks.DOC_LINK_VERSION,
I18nContext,
ResizeChecker,
notifications,
}),
element
);
return () => {
unmountComponentAtNode(element);
};
Expand Down
3 changes: 0 additions & 3 deletions src/legacy/core_plugins/console/public/quarantined/index.html

This file was deleted.

2 changes: 1 addition & 1 deletion src/legacy/core_plugins/kibana/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export default function (kibana) {

uiExports: {
hacks: [
'plugins/kibana/dev_tools/hacks/hide_empty_tools',
'plugins/kibana/dev_tools',
],
fieldFormats: ['plugins/kibana/field_formats/register'],
savedObjectTypes: [
Expand Down
3 changes: 3 additions & 0 deletions src/legacy/core_plugins/kibana/public/dev_tools/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@
}
}

.devApp {
height: 100%;
}
184 changes: 184 additions & 0 deletions src/legacy/core_plugins/kibana/public/dev_tools/application.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
/*
* 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 { I18nProvider } from '@kbn/i18n/react';
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 } from 'kibana/public';
import { DevTool } from '../../../../../plugins/dev_tools/public';

interface DevToolsWrapperProps {
devTools: readonly DevTool[];
activeDevTool: DevTool;
appMountContext: AppMountContext;
updateRoute: (newRoute: string) => void;
}

interface MountedDevToolDescriptor {
devTool: DevTool;
mountpoint: HTMLElement;
unmountHandler: () => void;
}

function DevToolsWrapper({
devTools,
activeDevTool,
appMountContext,
updateRoute,
}: DevToolsWrapperProps) {
const mountedTool = useRef<MountedDevToolDescriptor | null>(null);

useEffect(
() => () => {
if (mountedTool.current) {
mountedTool.current.unmountHandler();
}
},
[]
);

return (
<main className="devApp">
<EuiTabs>
{devTools.map(currentDevTool => (
<EuiToolTip content={currentDevTool.tooltipContent} key={currentDevTool.id}>
<EuiTab
disabled={currentDevTool.disabled}
isSelected={currentDevTool === activeDevTool}
onClick={() => {
if (!currentDevTool.disabled) {
updateRoute(`/dev_tools/${currentDevTool.id}`);
}
}}
>
{currentDevTool.title}
</EuiTab>
</EuiToolTip>
))}
</EuiTabs>
<div
className="devApp__container"
role="tabpanel"
data-test-subj={activeDevTool.id}
ref={async element => {
if (
element &&
(mountedTool.current === null ||
mountedTool.current.devTool !== activeDevTool ||
mountedTool.current.mountpoint !== element)
) {
if (mountedTool.current) {
mountedTool.current.unmountHandler();
}
const unmountHandler = await activeDevTool.mount(appMountContext, {
element,
appBasePath: '',
});
mountedTool.current = {
devTool: activeDevTool,
mountpoint: element,
unmountHandler,
};
}
}}
/>
</main>
);
}

function redirectOnMissingCapabilities(appMountContext: AppMountContext) {
if (!appMountContext.core.application.capabilities.dev_tools.show) {
window.location.hash = '/home';
return true;
}
return false;
}

function setBadge(appMountContext: AppMountContext) {
if (appMountContext.core.application.capabilities.dev_tools.save) {
return;
}
appMountContext.core.chrome.setBadge({
text: i18n.translate('kbn.devTools.badge.readOnly.text', {
defaultMessage: 'Read only',
}),
tooltip: i18n.translate('kbn.devTools.badge.readOnly.tooltip', {
defaultMessage: 'Unable to save',
}),
iconType: 'glasses',
});
}

function setBreadcrumbs(appMountContext: AppMountContext) {
appMountContext.core.chrome.setBreadcrumbs([
{
text: i18n.translate('kbn.devTools.k7BreadcrumbsDevToolsLabel', {
defaultMessage: 'Dev Tools',
}),
href: '#/dev_tools',
},
]);
}

export function renderApp(
element: HTMLElement,
appMountContext: AppMountContext,
basePath: string,
devTools: readonly DevTool[]
) {
if (redirectOnMissingCapabilities(appMountContext)) {
return () => {};
}
setBadge(appMountContext);
setBreadcrumbs(appMountContext);
ReactDOM.render(
<I18nProvider>
<Router>
<Switch>
{devTools.map(devTool => (
<Route
key={devTool.id}
path={`/dev_tools/${devTool.id}`}
exact={!devTool.enableRouting}
render={props => (
<DevToolsWrapper
updateRoute={props.history.push}
activeDevTool={devTool}
devTools={devTools}
appMountContext={appMountContext}
/>
)}
/>
))}
<Route path="/dev_tools">
<Redirect to={`/dev_tools/${devTools[0].id}`} />
</Route>
</Switch>
</Router>
</I18nProvider>,
element
);

return () => ReactDOM.unmountComponentAtNode(element);
}
Loading

0 comments on commit 62d0353

Please sign in to comment.