diff --git a/src/legacy/core_plugins/metrics/index.js b/src/legacy/core_plugins/metrics/index.ts similarity index 52% rename from src/legacy/core_plugins/metrics/index.js rename to src/legacy/core_plugins/metrics/index.ts index 0771bf9726c27..128f8d6a72944 100644 --- a/src/legacy/core_plugins/metrics/index.js +++ b/src/legacy/core_plugins/metrics/index.ts @@ -18,34 +18,39 @@ */ import { resolve } from 'path'; +import { Legacy } from 'kibana'; +import { PluginInitializerContext } from 'src/core/server'; +import { CoreSetup } from 'src/core/server'; -import { fieldsRoutes } from './server/routes/fields'; -import { visDataRoutes } from './server/routes/vis'; -import { SearchStrategiesRegister } from './server/lib/search_strategies/search_strategies_register'; +import { plugin } from './server/'; +import { CustomCoreSetup } from './server/plugin'; -export default function(kibana) { - return new kibana.Plugin({ - require: ['kibana', 'elasticsearch'], +import { LegacyPluginApi, LegacyPluginInitializer } from '../../../../src/legacy/types'; +const metricsPluginInitializer: LegacyPluginInitializer = ({ Plugin }: LegacyPluginApi) => + new Plugin({ + id: 'metrics', + require: ['kibana', 'elasticsearch', 'visualizations', 'interpreter', 'data'], + publicDir: resolve(__dirname, 'public'), uiExports: { - visTypes: ['plugins/metrics/kbn_vis_types'], - interpreter: ['plugins/metrics/tsvb_fn'], styleSheetPaths: resolve(__dirname, 'public/index.scss'), + hacks: [resolve(__dirname, 'public/legacy')], + injectDefaultVars: server => ({}), }, + init: (server: Legacy.Server) => { + const initializerContext = {} as PluginInitializerContext; + const core = { http: { server } } as CoreSetup & CustomCoreSetup; - config(Joi) { + plugin(initializerContext).setup(core); + }, + config(Joi: any) { return Joi.object({ enabled: Joi.boolean().default(true), chartResolution: Joi.number().default(150), minimumBucketSize: Joi.number().default(10), }).default(); }, + } as Legacy.PluginSpecOptions); - init(server) { - fieldsRoutes(server); - visDataRoutes(server); - - SearchStrategiesRegister.init(server); - }, - }); -} +// eslint-disable-next-line import/no-default-export +export default metricsPluginInitializer; diff --git a/src/legacy/core_plugins/metrics/public/kbn_vis_types/editor_controller.js b/src/legacy/core_plugins/metrics/public/editor_controller.js similarity index 87% rename from src/legacy/core_plugins/metrics/public/kbn_vis_types/editor_controller.js rename to src/legacy/core_plugins/metrics/public/editor_controller.js index 2639eba49a1ec..464cec744eed7 100644 --- a/src/legacy/core_plugins/metrics/public/kbn_vis_types/editor_controller.js +++ b/src/legacy/core_plugins/metrics/public/editor_controller.js @@ -20,11 +20,10 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import { I18nContext } from 'ui/i18n'; -import chrome from 'ui/chrome'; -import { fetchIndexPatternFields } from '../lib/fetch_fields'; +import { fetchIndexPatternFields } from './lib/fetch_fields'; -function ReactEditorControllerProvider(config) { - class ReactEditorController { +export function createEditorController(config, savedObjectsClient) { + return class { constructor(el, savedObj) { this.el = el; @@ -36,7 +35,6 @@ function ReactEditorControllerProvider(config) { } fetchDefaultIndexPattern = async () => { - const savedObjectsClient = chrome.getSavedObjectsClient(); const indexPattern = await savedObjectsClient.get( 'index-pattern', config.get('defaultIndex') @@ -85,12 +83,5 @@ function ReactEditorControllerProvider(config) { destroy() { unmountComponentAtNode(this.el); } - } - - return { - name: 'react_editor', - handler: ReactEditorController, }; } - -export { ReactEditorControllerProvider }; diff --git a/src/legacy/core_plugins/metrics/public/index.ts b/src/legacy/core_plugins/metrics/public/index.ts new file mode 100644 index 0000000000000..16b099ba16ae9 --- /dev/null +++ b/src/legacy/core_plugins/metrics/public/index.ts @@ -0,0 +1,25 @@ +/* + * 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 { PluginInitializerContext } from '../../../../core/public'; +import { MetricsPlugin as Plugin } from './plugin'; + +export function plugin(initializerContext: PluginInitializerContext) { + return new Plugin(initializerContext); +} diff --git a/src/legacy/core_plugins/metrics/public/kbn_vis_types/request_handler.js b/src/legacy/core_plugins/metrics/public/kbn_vis_types/request_handler.js deleted file mode 100644 index dd57f87d95d7a..0000000000000 --- a/src/legacy/core_plugins/metrics/public/kbn_vis_types/request_handler.js +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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 { validateInterval } from '../lib/validate_interval'; -import { timezoneProvider } from 'ui/vis/lib/timezone'; -import { timefilter } from 'ui/timefilter'; -import { kfetch } from 'ui/kfetch'; - -const MetricsRequestHandlerProvider = function(Private, config) { - const timezone = Private(timezoneProvider)(); - - return { - name: 'metrics', - - handler: async ({ uiState, timeRange, filters, query, visParams }) => { - const uiStateObj = uiState.get(visParams.type, {}); - const parsedTimeRange = timefilter.calculateBounds(timeRange); - const scaledDataFormat = config.get('dateFormat:scaled'); - const dateFormat = config.get('dateFormat'); - - if (visParams && visParams.id && !visParams.isModelInvalid) { - try { - const maxBuckets = config.get('metrics:max_buckets'); - - validateInterval(parsedTimeRange, visParams, maxBuckets); - - const resp = await kfetch({ - pathname: '/api/metrics/vis/data', - method: 'POST', - body: JSON.stringify({ - timerange: { - timezone, - ...parsedTimeRange, - }, - query, - filters, - panels: [visParams], - state: uiStateObj, - }), - }); - - return { - dateFormat, - scaledDataFormat, - timezone, - ...resp, - }; - } catch (error) { - return Promise.reject(error); - } - } - - return Promise.resolve({}); - }, - }; -}; - -export { MetricsRequestHandlerProvider }; diff --git a/src/legacy/core_plugins/metrics/public/legacy.ts b/src/legacy/core_plugins/metrics/public/legacy.ts new file mode 100644 index 0000000000000..49420e4b51273 --- /dev/null +++ b/src/legacy/core_plugins/metrics/public/legacy.ts @@ -0,0 +1,35 @@ +/* + * 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 { PluginInitializerContext } from 'kibana/public'; +import { npSetup, npStart } from 'ui/new_platform'; + +import { visualizations } from '../../visualizations/public'; +import { MetricsPluginSetupDependencies } from './plugin'; +import { plugin } from '.'; + +const plugins: Readonly = { + visualizations, + data: npSetup.plugins.data, +}; + +const pluginInstance = plugin({} as PluginInitializerContext); + +export const setup = pluginInstance.setup(npSetup.core, plugins); +export const start = pluginInstance.start(npStart.core); diff --git a/src/legacy/core_plugins/metrics/public/tsvb_fn.js b/src/legacy/core_plugins/metrics/public/metrics_fn.ts similarity index 69% rename from src/legacy/core_plugins/metrics/public/tsvb_fn.js rename to src/legacy/core_plugins/metrics/public/metrics_fn.ts index 983443a1574cd..5baab42f2e1ba 100644 --- a/src/legacy/core_plugins/metrics/public/tsvb_fn.js +++ b/src/legacy/core_plugins/metrics/public/metrics_fn.ts @@ -17,16 +17,37 @@ * under the License. */ -import { functionsRegistry } from 'plugins/interpreter/registries'; import { get } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { MetricsRequestHandlerProvider } from './kbn_vis_types/request_handler'; import { PersistedState } from 'ui/persisted_state'; - import chrome from 'ui/chrome'; -export const tsvb = () => ({ - name: 'tsvb', +import { ExpressionFunction, KibanaContext, Render } from '../../interpreter/types'; + +// @ts-ignore +import { createMetricsRequestHandler } from './request_handler'; + +const name = 'tsvb'; +type Context = KibanaContext | null; + +interface Arguments { + params: string; + uiState: string; +} + +type VisParams = Required; + +interface RenderValue { + visType: 'metrics'; + visData: Context; + visConfig: VisParams; + uiState: any; +} + +type Return = Promise>; + +export const createMetricsFn = (): ExpressionFunction => ({ + name, type: 'render', context: { types: ['kibana_context', 'null'], @@ -38,17 +59,17 @@ export const tsvb = () => ({ params: { types: ['string'], default: '"{}"', + help: '', }, uiState: { types: ['string'], default: '"{}"', + help: '', }, }, - async fn(context, args) { - const $injector = await chrome.dangerouslyGetActiveInjector(); - const Private = $injector.get('Private'); - const metricsRequestHandler = Private(MetricsRequestHandlerProvider).handler; - + async fn(context: Context, args: Arguments) { + const uiSettings = chrome.getUiSettingsClient(); + const metricsRequestHandler = createMetricsRequestHandler(uiSettings); const params = JSON.parse(args.params); const uiStateParams = JSON.parse(args.uiState); const uiState = new PersistedState(uiStateParams); @@ -58,7 +79,7 @@ export const tsvb = () => ({ query: get(context, 'query', null), filters: get(context, 'filters', null), visParams: params, - uiState: uiState, + uiState, }); response.visType = 'metrics'; @@ -67,13 +88,11 @@ export const tsvb = () => ({ type: 'render', as: 'visualization', value: { + uiState, visType: 'metrics', visConfig: params, - uiState: uiState, visData: response, }, }; }, }); - -functionsRegistry.register(tsvb); diff --git a/src/legacy/core_plugins/metrics/public/kbn_vis_types/index.js b/src/legacy/core_plugins/metrics/public/metrics_type.ts similarity index 72% rename from src/legacy/core_plugins/metrics/public/kbn_vis_types/index.js rename to src/legacy/core_plugins/metrics/public/metrics_type.ts index 1ffcb2b2db924..35182fbe25265 100644 --- a/src/legacy/core_plugins/metrics/public/kbn_vis_types/index.js +++ b/src/legacy/core_plugins/metrics/public/metrics_type.ts @@ -17,24 +17,27 @@ * under the License. */ -import { MetricsRequestHandlerProvider } from './request_handler'; +import chrome from 'ui/chrome'; import { i18n } from '@kbn/i18n'; -import { ReactEditorControllerProvider } from './editor_controller'; -import { VisFactoryProvider } from 'ui/vis/vis_factory'; +// @ts-ignore import { defaultFeedbackMessage } from 'ui/vis/default_feedback_message'; -import { PANEL_TYPES } from '../../common/panel_types'; +import { visFactory } from '../../visualizations/public'; -// register the provider with the visTypes registry so that other know it exists -import { VisTypesRegistryProvider } from 'ui/registry/vis_types'; -VisTypesRegistryProvider.register(MetricsVisProvider); +// @ts-ignore +import { createMetricsRequestHandler } from './request_handler'; +// @ts-ignore +import { createEditorController } from './editor_controller'; +// @ts-ignore +import { PANEL_TYPES } from '../common/panel_types'; -export function MetricsVisProvider(Private) { - const VisFactory = Private(VisFactoryProvider); - const ReactEditorController = Private(ReactEditorControllerProvider).handler; - const metricsRequestHandler = Private(MetricsRequestHandlerProvider).handler; +export const createMetricsTypeDefinition = () => { + const uiSettings = chrome.getUiSettingsClient(); + const savedObjectsClient = chrome.getSavedObjectsClient(); + const EditorController = createEditorController(uiSettings, savedObjectsClient); + const metricsRequestHandler = createMetricsRequestHandler(uiSettings); - return VisFactory.createReactVisualization({ + return visFactory.createReactVisualization({ name: 'metrics', title: i18n.translate('tsvb.kbnVisTypes.metricsTitle', { defaultMessage: 'TSVB' }), description: i18n.translate('tsvb.kbnVisTypes.metricsDescription', { @@ -76,11 +79,11 @@ export function MetricsVisProvider(Private) { show_legend: 1, show_grid: 1, }, - component: require('../components/vis_editor').VisEditor, + component: require('./components/vis_editor').VisEditor, }, - editor: ReactEditorController, + editor: EditorController, editorConfig: { - component: require('../components/vis_editor').VisEditor, + component: require('./components/vis_editor').VisEditor, }, options: { showQueryBar: false, @@ -90,4 +93,4 @@ export function MetricsVisProvider(Private) { requestHandler: metricsRequestHandler, responseHandler: 'none', }); -} +}; diff --git a/src/legacy/core_plugins/metrics/public/plugin.ts b/src/legacy/core_plugins/metrics/public/plugin.ts new file mode 100644 index 0000000000000..e1eca37970604 --- /dev/null +++ b/src/legacy/core_plugins/metrics/public/plugin.ts @@ -0,0 +1,48 @@ +/* + * 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 { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../../../core/public'; +import { Plugin as DataPublicPlugin } from '../../../../plugins/data/public'; +import { VisualizationsSetup } from '../../visualizations/public'; + +import { createMetricsFn } from './metrics_fn'; +import { createMetricsTypeDefinition } from './metrics_type'; + +/** @internal */ +export interface MetricsPluginSetupDependencies { + data: ReturnType; + visualizations: VisualizationsSetup; +} + +/** @internal */ +export class MetricsPlugin implements Plugin, void> { + initializerContext: PluginInitializerContext; + + constructor(initializerContext: PluginInitializerContext) { + this.initializerContext = initializerContext; + } + + public async setup(core: CoreSetup, { data, visualizations }: MetricsPluginSetupDependencies) { + data.expressions.registerFunction(createMetricsFn); + visualizations.types.VisTypesRegistryProvider.register(createMetricsTypeDefinition); + } + + public start(core: CoreStart) { + // nothing to do here yet + } +} diff --git a/src/legacy/core_plugins/metrics/public/request_handler.js b/src/legacy/core_plugins/metrics/public/request_handler.js new file mode 100644 index 0000000000000..362301fb4d4e4 --- /dev/null +++ b/src/legacy/core_plugins/metrics/public/request_handler.js @@ -0,0 +1,68 @@ +/* + * 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 { validateInterval } from './lib/validate_interval'; +import { timezoneProvider } from 'ui/vis/lib/timezone'; +import { timefilter } from 'ui/timefilter'; +import { kfetch } from 'ui/kfetch'; + +export const createMetricsRequestHandler = function(config) { + const timezone = timezoneProvider(config)(); + + return async ({ uiState, timeRange, filters, query, visParams }) => { + const uiStateObj = uiState.get(visParams.type, {}); + const parsedTimeRange = timefilter.calculateBounds(timeRange); + const scaledDataFormat = config.get('dateFormat:scaled'); + const dateFormat = config.get('dateFormat'); + + if (visParams && visParams.id && !visParams.isModelInvalid) { + try { + const maxBuckets = config.get('metrics:max_buckets'); + + validateInterval(parsedTimeRange, visParams, maxBuckets); + + const resp = await kfetch({ + pathname: '/api/metrics/vis/data', + method: 'POST', + body: JSON.stringify({ + timerange: { + timezone, + ...parsedTimeRange, + }, + query, + filters, + panels: [visParams], + state: uiStateObj, + }), + }); + + return { + dateFormat, + scaledDataFormat, + timezone, + ...resp, + }; + } catch (error) { + return Promise.reject(error); + } + } + + return Promise.resolve({}); + }; +}; diff --git a/src/legacy/core_plugins/metrics/server/index.ts b/src/legacy/core_plugins/metrics/server/index.ts new file mode 100644 index 0000000000000..14047c31f2dcd --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/index.ts @@ -0,0 +1,25 @@ +/* + * 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 { PluginInitializerContext } from 'kibana/server'; +import { MetricsServerPlugin as Plugin } from './plugin'; + +export function plugin(initializerContext: PluginInitializerContext) { + return new Plugin(initializerContext); +} diff --git a/src/legacy/core_plugins/metrics/server/plugin.ts b/src/legacy/core_plugins/metrics/server/plugin.ts new file mode 100644 index 0000000000000..027354d6181a2 --- /dev/null +++ b/src/legacy/core_plugins/metrics/server/plugin.ts @@ -0,0 +1,52 @@ +/* + * 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 { Legacy } from 'kibana'; +import { PluginInitializerContext, CoreSetup } from 'kibana/server'; + +// @ts-ignore +import { fieldsRoutes } from './routes/fields'; +// @ts-ignore +import { visDataRoutes } from './routes/vis'; +// @ts-ignore +import { SearchStrategiesRegister } from './lib/search_strategies/search_strategies_register'; + +// TODO: Remove as CoreSetup is completed. +export interface CustomCoreSetup { + http: { + server: Legacy.Server; + }; +} + +export class MetricsServerPlugin { + public initializerContext: PluginInitializerContext; + + constructor(initializerContext: PluginInitializerContext) { + this.initializerContext = initializerContext; + } + + public setup(core: CoreSetup & CustomCoreSetup) { + const { http } = core; + + fieldsRoutes(http.server); + visDataRoutes(http.server); + + SearchStrategiesRegister.init(http.server); + } +}