From ff2a3ab7d29e995e2528f294a9455a3081856107 Mon Sep 17 00:00:00 2001 From: Joe Reuter Date: Wed, 20 Nov 2019 12:06:53 +0100 Subject: [PATCH] Load Lens together with kibana app (#50164) --- src/legacy/plugin_discovery/types.ts | 2 + .../legacy/plugins/lens/common/constants.ts | 8 ++- x-pack/legacy/plugins/lens/index.ts | 7 +- .../lens/public/app_plugin/app.test.tsx | 7 +- .../plugins/lens/public/app_plugin/app.tsx | 29 ++++---- .../plugins/lens/public/app_plugin/plugin.tsx | 68 ++++++++++++------- .../plugins/lens/public/help_menu_util.tsx | 6 +- x-pack/legacy/plugins/lens/public/index.ts | 33 --------- x-pack/legacy/plugins/lens/public/legacy.ts | 23 +++++++ x-pack/legacy/plugins/lens/public/redirect.ts | 19 ++++++ .../lens/public/register_embeddable.ts | 20 ------ .../lens/public/register_vis_type_alias.ts | 4 +- 12 files changed, 126 insertions(+), 100 deletions(-) create mode 100644 x-pack/legacy/plugins/lens/public/legacy.ts create mode 100644 x-pack/legacy/plugins/lens/public/redirect.ts delete mode 100644 x-pack/legacy/plugins/lens/public/register_embeddable.ts diff --git a/src/legacy/plugin_discovery/types.ts b/src/legacy/plugin_discovery/types.ts index 97d3a4352c2f8..d987260b099bd 100644 --- a/src/legacy/plugin_discovery/types.ts +++ b/src/legacy/plugin_discovery/types.ts @@ -62,6 +62,8 @@ export interface LegacyPluginOptions { }>; apps: any; hacks: string[]; + visualize: string[]; + devTools: string[]; styleSheetPaths: string; injectDefaultVars: (server: Server) => Record; noParse: string[]; diff --git a/x-pack/legacy/plugins/lens/common/constants.ts b/x-pack/legacy/plugins/lens/common/constants.ts index 787a348a788b8..c2eed1940fa1a 100644 --- a/x-pack/legacy/plugins/lens/common/constants.ts +++ b/x-pack/legacy/plugins/lens/common/constants.ts @@ -6,9 +6,13 @@ export const PLUGIN_ID = 'lens'; -export const BASE_APP_URL = '/app/lens'; +export const BASE_APP_URL = '/app/kibana'; export const BASE_API_URL = '/api/lens'; +export function getBasePath() { + return `${BASE_APP_URL}#/lens`; +} + export function getEditPath(id: string) { - return `${BASE_APP_URL}#/edit/${encodeURIComponent(id)}`; + return `${BASE_APP_URL}#/lens/edit/${encodeURIComponent(id)}`; } diff --git a/x-pack/legacy/plugins/lens/index.ts b/x-pack/legacy/plugins/lens/index.ts index 20f92ebbe0654..d4cea28d14085 100644 --- a/x-pack/legacy/plugins/lens/index.ts +++ b/x-pack/legacy/plugins/lens/index.ts @@ -12,7 +12,7 @@ import mappings from './mappings.json'; import { PLUGIN_ID, getEditPath } from './common'; import { lensServerPlugin } from './server'; -const NOT_INTERNATIONALIZED_PRODUCT_NAME = 'Lens Visualizations'; +export const NOT_INTERNATIONALIZED_PRODUCT_NAME = 'Lens Visualizations'; export const lens: LegacyPluginInitializer = kibana => { return new kibana.Plugin({ @@ -26,10 +26,11 @@ export const lens: LegacyPluginInitializer = kibana => { app: { title: NOT_INTERNATIONALIZED_PRODUCT_NAME, description: 'Explore and visualize data.', - main: `plugins/${PLUGIN_ID}/index`, + main: `plugins/${PLUGIN_ID}/redirect`, listed: false, }, - embeddableFactories: ['plugins/lens/register_embeddable'], + visualize: [`plugins/${PLUGIN_ID}/legacy`], + embeddableFactories: [`plugins/${PLUGIN_ID}/legacy`], styleSheetPaths: resolve(__dirname, 'public/index.scss'), mappings, visTypes: ['plugins/lens/register_vis_type_alias'], diff --git a/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx b/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx index 3fcb6609f28f1..ce05af46ade66 100644 --- a/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx +++ b/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx @@ -99,6 +99,12 @@ describe('Lens App', () => { data: { query: { filterManager: createMockFilterManager(), + timefilter: { + timefilter: { + getTime: jest.fn(() => ({ from: 'now-7d', to: 'now' })), + setTime: jest.fn(), + }, + }, }, }, dataShim: { @@ -109,7 +115,6 @@ describe('Lens App', () => { }), }, }, - timefilter: { history: {} }, }, storage: { get: jest.fn(), diff --git a/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx b/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx index fc5088c1271ad..553b98643f8a5 100644 --- a/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx +++ b/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx @@ -62,33 +62,35 @@ export function App({ docStorage: SavedObjectStore; redirectTo: (id?: string) => void; }) { - const timeDefaults = core.uiSettings.get('timepicker:timeDefaults'); const language = storage.get('kibana.userQueryLanguage') || core.uiSettings.get('search:queryLanguage'); - const [state, setState] = useState({ - isLoading: !!docId, - isSaveModalVisible: false, - indexPatternsForTopNav: [], - query: { query: '', language }, - dateRange: { - fromDate: timeDefaults.from, - toDate: timeDefaults.to, - }, - filters: [], + const [state, setState] = useState(() => { + const currentRange = data.query.timefilter.timefilter.getTime(); + return { + isLoading: !!docId, + isSaveModalVisible: false, + indexPatternsForTopNav: [], + query: { query: '', language }, + dateRange: { + fromDate: currentRange.from, + toDate: currentRange.to, + }, + filters: [], + }; }); const { lastKnownDoc } = state; useEffect(() => { - const subscription = data.query.filterManager.getUpdates$().subscribe({ + const filterSubscription = data.query.filterManager.getUpdates$().subscribe({ next: () => { setState(s => ({ ...s, filters: data.query.filterManager.getFilters() })); trackUiEvent('app_filters_updated'); }, }); return () => { - subscription.unsubscribe(); + filterSubscription.unsubscribe(); }; }, []); @@ -199,6 +201,7 @@ export function App({ dateRange.from !== state.dateRange.fromDate || dateRange.to !== state.dateRange.toDate ) { + data.query.timefilter.timefilter.setTime(dateRange); trackUiEvent('app_date_change'); } else { trackUiEvent('app_query_change'); diff --git a/x-pack/legacy/plugins/lens/public/app_plugin/plugin.tsx b/x-pack/legacy/plugins/lens/public/app_plugin/plugin.tsx index 56c19ea2bb9f2..60a375f696f7b 100644 --- a/x-pack/legacy/plugins/lens/public/app_plugin/plugin.tsx +++ b/x-pack/legacy/plugins/lens/public/app_plugin/plugin.tsx @@ -4,18 +4,27 @@ * you may not use this file except in compliance with the Elastic License. */ +import 'ui/autoload/all'; +// Used to run esaggs queries +import 'uiExports/fieldFormats'; +import 'uiExports/search'; +import 'uiExports/visRequestHandlers'; +import 'uiExports/visResponseHandlers'; +// Used for kibana_context function +import 'uiExports/savedObjectTypes'; + import React from 'react'; import { I18nProvider, FormattedMessage } from '@kbn/i18n/react'; import { HashRouter, Switch, Route, RouteComponentProps } from 'react-router-dom'; +import { render, unmountComponentAtNode } from 'react-dom'; import chrome from 'ui/chrome'; import { CoreSetup, CoreStart } from 'src/core/public'; -import { npSetup, npStart } from 'ui/new_platform'; import { DataPublicPluginStart } from 'src/plugins/data/public'; import { DataStart } from '../../../../../../src/legacy/core_plugins/data/public'; -import { start as dataShimStart } from '../../../../../../src/legacy/core_plugins/data/public/legacy'; import { Storage } from '../../../../../../src/plugins/kibana_utils/public'; import { editorFrameSetup, editorFrameStart, editorFrameStop } from '../editor_frame_plugin'; import { indexPatternDatasourceSetup, indexPatternDatasourceStop } from '../indexpattern_plugin'; +import { addHelpMenuToAppChrome } from '../help_menu_util'; import { SavedObjectIndexStore } from '../persistence'; import { xyVisualizationSetup, xyVisualizationStop } from '../xy_visualization_plugin'; import { metricVisualizationSetup, metricVisualizationStop } from '../metric_visualization_plugin'; @@ -31,10 +40,15 @@ import { stopReportManager, trackUiEvent, } from '../lens_ui_telemetry'; +import { LocalApplicationService } from '../../../../../../src/legacy/core_plugins/kibana/public/local_application_service'; +import { NOT_INTERNATIONALIZED_PRODUCT_NAME } from '../../index'; export interface LensPluginStartDependencies { data: DataPublicPluginStart; dataShim: DataStart; + __LEGACY: { + localApplicationService: LocalApplicationService; + }; } export class AppPlugin { private instance: EditorFrameInstance | null = null; @@ -58,11 +72,16 @@ export class AppPlugin { editorFrameSetupInterface.registerDatasource('indexpattern', indexPattern); } - start(core: CoreStart, { data, dataShim }: LensPluginStartDependencies) { + start( + core: CoreStart, + { data, dataShim, __LEGACY: { localApplicationService } }: LensPluginStartDependencies + ) { if (this.store === null) { throw new Error('Start lifecycle called before setup lifecycle'); } + addHelpMenuToAppChrome(core.chrome); + const store = this.store; const editorFrameStartInterface = editorFrameStart(); @@ -89,9 +108,9 @@ export class AppPlugin { docStorage={store} redirectTo={id => { if (!id) { - routeProps.history.push('/'); + routeProps.history.push('/lens'); } else { - routeProps.history.push(`/edit/${id}`); + routeProps.history.push(`/lens/edit/${id}`); } }} /> @@ -103,17 +122,27 @@ export class AppPlugin { return ; } - return ( - - - - - - - - - - ); + localApplicationService.register({ + id: 'lens', + title: NOT_INTERNATIONALIZED_PRODUCT_NAME, + mount: async (context, params) => { + render( + + + + + + + + + , + params.element + ); + return () => { + unmountComponentAtNode(params.element); + }; + }, + }); } stop() { @@ -131,10 +160,3 @@ export class AppPlugin { editorFrameStop(); } } - -const app = new AppPlugin(); - -export const appSetup = () => app.setup(npSetup.core, {}); -export const appStart = () => - app.start(npStart.core, { dataShim: dataShimStart, data: npStart.plugins.data }); -export const appStop = () => app.stop(); diff --git a/x-pack/legacy/plugins/lens/public/help_menu_util.tsx b/x-pack/legacy/plugins/lens/public/help_menu_util.tsx index 30a05dbc38537..fec7175ea48eb 100644 --- a/x-pack/legacy/plugins/lens/public/help_menu_util.tsx +++ b/x-pack/legacy/plugins/lens/public/help_menu_util.tsx @@ -10,12 +10,12 @@ import { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } from 'ui/documentation_links'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { render, unmountComponentAtNode } from 'react-dom'; -import { Chrome } from 'ui/chrome'; +import { ChromeStart } from 'kibana/public'; const docsPage = 'lens'; -export function addHelpMenuToAppChrome(chrome: Chrome) { - chrome.helpExtension.set(domElement => { +export function addHelpMenuToAppChrome(chrome: ChromeStart) { + chrome.setHelpExtension(domElement => { render(, domElement); return () => { unmountComponentAtNode(domElement); diff --git a/x-pack/legacy/plugins/lens/public/index.ts b/x-pack/legacy/plugins/lens/public/index.ts index 2a5422d4bb8a1..9f4141dbcae7d 100644 --- a/x-pack/legacy/plugins/lens/public/index.ts +++ b/x-pack/legacy/plugins/lens/public/index.ts @@ -5,36 +5,3 @@ */ export * from './types'; - -import 'ui/autoload/all'; -// Used to run esaggs queries -import 'uiExports/fieldFormats'; -import 'uiExports/search'; -import 'uiExports/visRequestHandlers'; -import 'uiExports/visResponseHandlers'; -import 'uiExports/interpreter'; -// Used for kibana_context function -import 'uiExports/savedObjectTypes'; - -import { render, unmountComponentAtNode } from 'react-dom'; -import { IScope } from 'angular'; -import chrome from 'ui/chrome'; -import { appStart, appSetup, appStop } from './app_plugin'; -import { PLUGIN_ID } from '../common'; -import { addHelpMenuToAppChrome } from './help_menu_util'; - -// TODO: Convert this to the "new platform" way of doing UI -function Root($scope: IScope, $element: JQLite) { - const el = $element[0]; - $scope.$on('$destroy', () => { - unmountComponentAtNode(el); - appStop(); - }); - - appSetup(); - addHelpMenuToAppChrome(chrome); - - return render(appStart(), el); -} - -chrome.setRootController(PLUGIN_ID, Root); diff --git a/x-pack/legacy/plugins/lens/public/legacy.ts b/x-pack/legacy/plugins/lens/public/legacy.ts new file mode 100644 index 0000000000000..0285e041de78c --- /dev/null +++ b/x-pack/legacy/plugins/lens/public/legacy.ts @@ -0,0 +1,23 @@ +/* + * 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 { npSetup, npStart } from 'ui/new_platform'; +import { start as dataShimStart } from '../../../../../src/legacy/core_plugins/data/public/legacy'; + +export * from './types'; + +import { localApplicationService } from '../../../../../src/legacy/core_plugins/kibana/public/local_application_service'; +import { AppPlugin } from './app_plugin'; + +const app = new AppPlugin(); +app.setup(npSetup.core, {}); +app.start(npStart.core, { + dataShim: dataShimStart, + data: npStart.plugins.data, + __LEGACY: { + localApplicationService, + }, +}); diff --git a/x-pack/legacy/plugins/lens/public/redirect.ts b/x-pack/legacy/plugins/lens/public/redirect.ts new file mode 100644 index 0000000000000..25b0188214c5e --- /dev/null +++ b/x-pack/legacy/plugins/lens/public/redirect.ts @@ -0,0 +1,19 @@ +/* + * 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. + */ + +// This file redirects lens urls starting with app/lens#... to their counterpart on app/kibana#lens/... to +// make sure it's compatible with the 7.5 release + +import { npSetup } from 'ui/new_platform'; +import chrome from 'ui/chrome'; + +chrome.setRootController('lens', () => { + // prefix the path in the hash with lens/ + const prefixedHashRoute = window.location.hash.replace(/^#\//, '#/lens/'); + + // redirect to the new lens url `app/kibana#/lens/...` + window.location.href = npSetup.core.http.basePath.prepend('/app/kibana' + prefixedHashRoute); +}); diff --git a/x-pack/legacy/plugins/lens/public/register_embeddable.ts b/x-pack/legacy/plugins/lens/public/register_embeddable.ts deleted file mode 100644 index f86cb91a0029e..0000000000000 --- a/x-pack/legacy/plugins/lens/public/register_embeddable.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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 { indexPatternDatasourceSetup } from './indexpattern_plugin'; -import { xyVisualizationSetup } from './xy_visualization_plugin'; -import { editorFrameSetup, editorFrameStart } from './editor_frame_plugin'; -import { datatableVisualizationSetup } from './datatable_visualization_plugin'; -import { metricVisualizationSetup } from './metric_visualization_plugin'; - -// bootstrap shimmed plugins to register everything necessary (expression functions and embeddables). -// the new platform will take care of this once in place. -indexPatternDatasourceSetup(); -datatableVisualizationSetup(); -xyVisualizationSetup(); -metricVisualizationSetup(); -editorFrameSetup(); -editorFrameStart(); diff --git a/x-pack/legacy/plugins/lens/public/register_vis_type_alias.ts b/x-pack/legacy/plugins/lens/public/register_vis_type_alias.ts index 562d0f0ef6135..185df12054a3c 100644 --- a/x-pack/legacy/plugins/lens/public/register_vis_type_alias.ts +++ b/x-pack/legacy/plugins/lens/public/register_vis_type_alias.ts @@ -6,10 +6,10 @@ import { i18n } from '@kbn/i18n'; import { visualizations } from '../../../../../src/legacy/core_plugins/visualizations/public'; -import { BASE_APP_URL, getEditPath } from '../common'; +import { getBasePath, getEditPath } from '../common'; visualizations.types.registerAlias({ - aliasUrl: BASE_APP_URL, + aliasUrl: getBasePath(), name: 'lens', promotion: { description: i18n.translate('xpack.lens.visTypeAlias.promotion.description', {