diff --git a/src/legacy/core_plugins/timelion/index.js b/src/legacy/core_plugins/timelion/index.ts
similarity index 80%
rename from src/legacy/core_plugins/timelion/index.js
rename to src/legacy/core_plugins/timelion/index.ts
index 29f538dc9fcd6..77e62ed02718c 100644
--- a/src/legacy/core_plugins/timelion/index.js
+++ b/src/legacy/core_plugins/timelion/index.ts
@@ -19,28 +19,32 @@
import { resolve } from 'path';
import { i18n } from '@kbn/i18n';
+import { Legacy } from 'kibana';
+import { LegacyPluginApi, LegacyPluginInitializer } from 'src/legacy/plugin_discovery/types';
+import { CoreSetup, PluginInitializerContext } from 'src/core/server';
import { plugin } from './server';
+import { CustomCoreSetup } from './server/plugin';
const experimentalLabel = i18n.translate('timelion.uiSettings.experimentalLabel', {
defaultMessage: 'experimental',
});
-export default function (kibana) {
- return new kibana.Plugin({
+const timelionPluginInitializer: LegacyPluginInitializer = ({ Plugin }: LegacyPluginApi) =>
+ new Plugin({
require: ['kibana', 'elasticsearch'],
-
- config(Joi) {
+ config(Joi: any) {
return Joi.object({
enabled: Joi.boolean().default(true),
ui: Joi.object({
enabled: Joi.boolean().default(false),
}).default(),
- graphiteUrls: Joi.array().items(
- Joi.string().uri({ scheme: ['http', 'https'] }),
- ).default([]),
+ graphiteUrls: Joi.array()
+ .items(Joi.string().uri({ scheme: ['http', 'https'] }))
+ .default([]),
}).default();
},
-
+ // @ts-ignore
+ // https://github.com/elastic/kibana/pull/44039#discussion_r326582255
uiCapabilities() {
return {
timelion: {
@@ -48,7 +52,7 @@ export default function (kibana) {
},
};
},
-
+ publicDir: resolve(__dirname, 'public'),
uiExports: {
app: {
title: 'Timelion',
@@ -58,11 +62,7 @@ export default function (kibana) {
main: 'plugins/timelion/app',
},
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
- hacks: [
- 'plugins/timelion/hacks/toggle_app_link_in_nav',
- 'plugins/timelion/lib/panel_registry',
- 'plugins/timelion/panels/timechart/timechart',
- ],
+ hacks: [resolve(__dirname, 'public/legacy')],
injectDefaultVars(server) {
const config = server.config();
@@ -71,13 +71,6 @@ export default function (kibana) {
kbnIndex: config.get('kibana.index'),
};
},
- visTypes: [
- 'plugins/timelion/vis',
- ],
- interpreter: ['plugins/timelion/timelion_vis_fn'],
- home: [
- 'plugins/timelion/register_feature',
- ],
mappings: require('./mappings.json'),
uiSettingDefaults: {
'timelion:showTutorial': {
@@ -159,17 +152,19 @@ export default function (kibana) {
value: '1ms',
description: i18n.translate('timelion.uiSettings.minimumIntervalDescription', {
defaultMessage: 'The smallest interval that will be calculated when using "auto"',
- description: '"auto" is a technical value in that context, that should not be translated.',
+ description:
+ '"auto" is a technical value in that context, that should not be translated.',
}),
category: ['timelion'],
},
'timelion:graphite.url': {
name: i18n.translate('timelion.uiSettings.graphiteURLLabel', {
defaultMessage: 'Graphite URL',
- description: 'The URL should be in the form of https://www.hostedgraphite.com/UID/ACCESS_KEY/graphite',
+ description:
+ 'The URL should be in the form of https://www.hostedgraphite.com/UID/ACCESS_KEY/graphite',
}),
- value: (server) => {
- const urls = server.config().get('timelion.graphiteUrls');
+ value: (server: Legacy.Server) => {
+ const urls = server.config().get('timelion.graphiteUrls') as string[];
if (urls.length === 0) {
return null;
} else {
@@ -177,11 +172,12 @@ export default function (kibana) {
}
},
description: i18n.translate('timelion.uiSettings.graphiteURLDescription', {
- defaultMessage: '{experimentalLabel} The URL of your graphite host',
+ defaultMessage:
+ '{experimentalLabel} The URL of your graphite host',
values: { experimentalLabel: `[${experimentalLabel}]` },
}),
type: 'select',
- options: (server) => (server.config().get('timelion.graphiteUrls')),
+ options: (server: Legacy.Server) => server.config().get('timelion.graphiteUrls'),
category: ['timelion'],
},
'timelion:quandl.key': {
@@ -197,11 +193,13 @@ export default function (kibana) {
},
},
},
- init: (server) => {
- const initializerContext = {};
- const core = { http: { server } };
+ init: (server: Legacy.Server) => {
+ const initializerContext = {} as PluginInitializerContext;
+ const core = { http: { server } } as CoreSetup & CustomCoreSetup;
plugin(initializerContext).setup(core);
},
});
-}
+
+// eslint-disable-next-line import/no-default-export
+export default timelionPluginInitializer;
diff --git a/src/legacy/core_plugins/timelion/public/__tests__/_tick_generator.js b/src/legacy/core_plugins/timelion/public/__tests__/_tick_generator.js
index 508cc5cd856d2..66ac56acc6262 100644
--- a/src/legacy/core_plugins/timelion/public/__tests__/_tick_generator.js
+++ b/src/legacy/core_plugins/timelion/public/__tests__/_tick_generator.js
@@ -18,48 +18,53 @@
*/
import expect from '@kbn/expect';
-import ngMock from 'ng_mock';
-describe('Tick Generator', function () {
+import { generateTicksProvider } from '../panels/timechart/tick_generator';
+describe('Tick Generator', function () {
let generateTicks;
- const axes = [
- {
- min: 0,
- max: 5000,
- delta: 100
- },
- {
- min: 0,
- max: 50000,
- delta: 2000
- },
- {
- min: 4096,
- max: 6000,
- delta: 250
- }
- ];
- beforeEach(ngMock.module('kibana'));
- beforeEach(ngMock.inject(function (Private) {
- generateTicks = Private(require('plugins/timelion/panels/timechart/tick_generator'));
- }));
- it('returns a function', function () {
- expect(generateTicks).to.be.a('function');
+ beforeEach(function () {
+ generateTicks = generateTicksProvider();
+ });
+
+ describe('generateTicksProvider()', function () {
+ it('should return a function', function () {
+ expect(generateTicks).to.be.a('function');
+ });
});
- axes.forEach(axis => {
- it(`generates ticks from ${axis.min} to ${axis.max}`, function () {
- const ticks = generateTicks(axis);
- let n = 1;
- while (Math.pow(2, n) < axis.delta) n++;
- const expectedDelta = Math.pow(2, n);
- const expectedNr = parseInt((axis.max - axis.min) / expectedDelta) + 2;
- expect(ticks instanceof Array).to.be(true);
- expect(ticks.length).to.be(expectedNr);
- expect(ticks[0]).to.equal(axis.min);
- expect(ticks[parseInt(ticks.length / 2)]).to.equal(axis.min + expectedDelta * parseInt(ticks.length / 2));
- expect(ticks[ticks.length - 1]).to.equal(axis.min + expectedDelta * (ticks.length - 1));
+ describe('generateTicks()', function () {
+ const axes = [
+ {
+ min: 0,
+ max: 5000,
+ delta: 100
+ },
+ {
+ min: 0,
+ max: 50000,
+ delta: 2000
+ },
+ {
+ min: 4096,
+ max: 6000,
+ delta: 250
+ }
+ ];
+
+ axes.forEach(axis => {
+ it(`generates ticks from ${axis.min} to ${axis.max}`, function () {
+ const ticks = generateTicks(axis);
+ let n = 1;
+ while (Math.pow(2, n) < axis.delta) n++;
+ const expectedDelta = Math.pow(2, n);
+ const expectedNr = parseInt((axis.max - axis.min) / expectedDelta) + 2;
+ expect(ticks instanceof Array).to.be(true);
+ expect(ticks.length).to.be(expectedNr);
+ expect(ticks[0]).to.equal(axis.min);
+ expect(ticks[parseInt(ticks.length / 2)]).to.equal(axis.min + expectedDelta * parseInt(ticks.length / 2));
+ expect(ticks[ticks.length - 1]).to.equal(axis.min + expectedDelta * (ticks.length - 1));
+ });
});
});
});
diff --git a/src/legacy/core_plugins/timelion/public/__tests__/services/tick_formatters.js b/src/legacy/core_plugins/timelion/public/__tests__/services/tick_formatters.js
index 8e140b9bf992a..cce72773f6b62 100644
--- a/src/legacy/core_plugins/timelion/public/__tests__/services/tick_formatters.js
+++ b/src/legacy/core_plugins/timelion/public/__tests__/services/tick_formatters.js
@@ -18,20 +18,19 @@
*/
import expect from '@kbn/expect';
-import ngMock from 'ng_mock';
-describe('Tick Formatters', function () {
+import { tickFormatters } from '../../services/tick_formatters';
- let tickFormatters;
+describe('Tick Formatters', function () {
+ let formatters;
- beforeEach(ngMock.module('kibana'));
- beforeEach(ngMock.inject(function (Private) {
- tickFormatters = Private(require('plugins/timelion/services/tick_formatters'));
- }));
+ beforeEach(function () {
+ formatters = tickFormatters();
+ });
describe('Bits mode', function () {
let bitFormatter;
beforeEach(function () {
- bitFormatter = tickFormatters.bits;
+ bitFormatter = formatters.bits;
});
it('is a function', function () {
@@ -56,7 +55,7 @@ describe('Tick Formatters', function () {
describe('Bits/s mode', function () {
let bitsFormatter;
beforeEach(function () {
- bitsFormatter = tickFormatters['bits/s'];
+ bitsFormatter = formatters['bits/s'];
});
it('is a function', function () {
@@ -81,7 +80,7 @@ describe('Tick Formatters', function () {
describe('Bytes mode', function () {
let byteFormatter;
beforeEach(function () {
- byteFormatter = tickFormatters.bytes;
+ byteFormatter = formatters.bytes;
});
it('is a function', function () {
@@ -106,7 +105,7 @@ describe('Tick Formatters', function () {
describe('Bytes/s mode', function () {
let bytesFormatter;
beforeEach(function () {
- bytesFormatter = tickFormatters['bytes/s'];
+ bytesFormatter = formatters['bytes/s'];
});
it('is a function', function () {
@@ -131,7 +130,7 @@ describe('Tick Formatters', function () {
describe('Currency mode', function () {
let currencyFormatter;
beforeEach(function () {
- currencyFormatter = tickFormatters.currency;
+ currencyFormatter = formatters.currency;
});
it('is a function', function () {
@@ -163,7 +162,7 @@ describe('Tick Formatters', function () {
describe('Percent mode', function () {
let percentFormatter;
beforeEach(function () {
- percentFormatter = tickFormatters.percent;
+ percentFormatter = formatters.percent;
});
it('is a function', function () {
@@ -197,7 +196,7 @@ describe('Tick Formatters', function () {
describe('Custom mode', function () {
let customFormatter;
beforeEach(function () {
- customFormatter = tickFormatters.custom;
+ customFormatter = formatters.custom;
});
it('is a function', function () {
diff --git a/src/legacy/core_plugins/timelion/public/directives/chart/chart.js b/src/legacy/core_plugins/timelion/public/directives/chart/chart.js
index 7a898d7b3e161..0a95b489aa2e1 100644
--- a/src/legacy/core_plugins/timelion/public/directives/chart/chart.js
+++ b/src/legacy/core_plugins/timelion/public/directives/chart/chart.js
@@ -17,55 +17,52 @@
* under the License.
*/
import panelRegistryProvider from '../../lib/panel_registry';
-
import { i18n } from '@kbn/i18n';
-require('ui/modules')
- .get('apps/timelion', [])
- .directive('chart', function (Private) {
- return {
- restrict: 'A',
- scope: {
- seriesList: '=chart', // The flot object, data, config and all
- search: '=', // The function to execute to kick off a search
- interval: '=', // Required for formatting x-axis ticks
- rerenderTrigger: '=',
- },
- link: function ($scope, $elem) {
-
- const panelRegistry = Private(panelRegistryProvider);
- let panelScope = $scope.$new(true);
-
- function render() {
- panelScope.$destroy();
+export function Chart(Private) {
+ return {
+ restrict: 'A',
+ scope: {
+ seriesList: '=chart', // The flot object, data, config and all
+ search: '=', // The function to execute to kick off a search
+ interval: '=', // Required for formatting x-axis ticks
+ rerenderTrigger: '=',
+ },
+ link: function ($scope, $elem) {
- if (!$scope.seriesList) return;
+ const panelRegistry = Private(panelRegistryProvider);
+ let panelScope = $scope.$new(true);
- $scope.seriesList.render = $scope.seriesList.render || {
- type: 'timechart'
- };
+ function render() {
+ panelScope.$destroy();
- const panelSchema = panelRegistry.byName[$scope.seriesList.render.type];
+ if (!$scope.seriesList) return;
- if (!panelSchema) {
- $elem.text(
- i18n.translate('timelion.chart.seriesList.noSchemaWarning', {
- defaultMessage: 'No such panel type: {renderType}',
- values: { renderType: $scope.seriesList.render.type },
- })
- );
- return;
- }
+ $scope.seriesList.render = $scope.seriesList.render || {
+ type: 'timechart'
+ };
- panelScope = $scope.$new(true);
- panelScope.seriesList = $scope.seriesList;
- panelScope.interval = $scope.interval;
- panelScope.search = $scope.search;
+ const panelSchema = panelRegistry.byName[$scope.seriesList.render.type];
- panelSchema.render(panelScope, $elem);
+ if (!panelSchema) {
+ $elem.text(
+ i18n.translate('timelion.chart.seriesList.noSchemaWarning', {
+ defaultMessage: 'No such panel type: {renderType}',
+ values: { renderType: $scope.seriesList.render.type },
+ })
+ );
+ return;
}
- $scope.$watchGroup(['seriesList', 'rerenderTrigger'], render);
+ panelScope = $scope.$new(true);
+ panelScope.seriesList = $scope.seriesList;
+ panelScope.interval = $scope.interval;
+ panelScope.search = $scope.search;
+
+ panelSchema.render(panelScope, $elem);
}
- };
- });
+
+ $scope.$watchGroup(['seriesList', 'rerenderTrigger'], render);
+ }
+ };
+}
diff --git a/src/legacy/core_plugins/timelion/public/directives/timelion_expression_input.js b/src/legacy/core_plugins/timelion/public/directives/timelion_expression_input.js
index 498636df9250b..f7676d9267a52 100644
--- a/src/legacy/core_plugins/timelion/public/directives/timelion_expression_input.js
+++ b/src/legacy/core_plugins/timelion/public/directives/timelion_expression_input.js
@@ -43,9 +43,7 @@
import _ from 'lodash';
import $ from 'jquery';
import PEG from 'pegjs';
-
import grammar from 'raw-loader!../chain.peg';
-import './timelion_expression_suggestions/timelion_expression_suggestions';
import timelionExpressionInputTemplate from './timelion_expression_input.html';
import {
SUGGESTION_TYPE,
@@ -57,9 +55,8 @@ import { comboBoxKeyCodes } from '@elastic/eui';
import { ArgValueSuggestionsProvider } from './timelion_expression_suggestions/arg_value_suggestions';
const Parser = PEG.generate(grammar);
-const app = require('ui/modules').get('apps/timelion', []);
-app.directive('timelionExpressionInput', function ($http, $timeout, Private) {
+export function TimelionExpInput($http, $timeout, Private) {
return {
restrict: 'E',
scope: {
@@ -276,4 +273,4 @@ app.directive('timelionExpressionInput', function ($http, $timeout, Private) {
init();
}
};
-});
+}
diff --git a/src/legacy/core_plugins/timelion/public/directives/timelion_expression_suggestions/timelion_expression_suggestions.js b/src/legacy/core_plugins/timelion/public/directives/timelion_expression_suggestions/timelion_expression_suggestions.js
index fc2bd094989ff..4ea6d19ff308b 100644
--- a/src/legacy/core_plugins/timelion/public/directives/timelion_expression_suggestions/timelion_expression_suggestions.js
+++ b/src/legacy/core_plugins/timelion/public/directives/timelion_expression_suggestions/timelion_expression_suggestions.js
@@ -19,9 +19,7 @@
import template from './timelion_expression_suggestions.html';
-const app = require('ui/modules').get('apps/timelion', []);
-
-app.directive('timelionExpressionSuggestions', () => {
+export function TimelionExpressionSuggestions() {
return {
restrict: 'E',
scope: {
@@ -38,4 +36,4 @@ app.directive('timelionExpressionSuggestions', () => {
scope.onMouseDown = e => e.preventDefault();
}
};
-});
+}
diff --git a/src/legacy/core_plugins/timelion/public/directives/timelion_interval/timelion_interval.js b/src/legacy/core_plugins/timelion/public/directives/timelion_interval/timelion_interval.js
index 7323874e62f95..24247fd86a2ce 100644
--- a/src/legacy/core_plugins/timelion/public/directives/timelion_interval/timelion_interval.js
+++ b/src/legacy/core_plugins/timelion/public/directives/timelion_interval/timelion_interval.js
@@ -19,11 +19,9 @@
import _ from 'lodash';
import $ from 'jquery';
-
-const app = require('ui/modules').get('apps/timelion', []);
import template from './timelion_interval.html';
-app.directive('timelionInterval', function ($timeout) {
+export function TimelionInterval($timeout) {
return {
restrict: 'E',
scope: {
@@ -81,4 +79,5 @@ app.directive('timelionInterval', function ($timeout) {
});
}
};
-});
+}
+
diff --git a/src/legacy/core_plugins/timelion/public/hacks/toggle_app_link_in_nav.ts b/src/legacy/core_plugins/timelion/public/index.ts
similarity index 76%
rename from src/legacy/core_plugins/timelion/public/hacks/toggle_app_link_in_nav.ts
rename to src/legacy/core_plugins/timelion/public/index.ts
index 6480ea0a69e43..6b42135884655 100644
--- a/src/legacy/core_plugins/timelion/public/hacks/toggle_app_link_in_nav.ts
+++ b/src/legacy/core_plugins/timelion/public/index.ts
@@ -17,9 +17,9 @@
* under the License.
*/
-import { npStart } from 'ui/new_platform';
+import { PluginInitializerContext } from 'kibana/public';
+import { TimelionPlugin as Plugin } from './plugin';
-const timelionUiEnabled = npStart.core.injectedMetadata.getInjectedVar('timelionUiEnabled');
-if (timelionUiEnabled === false) {
- npStart.core.chrome.navLinks.update('timelion', { hidden: true });
+export function plugin(initializerContext: PluginInitializerContext) {
+ return new Plugin(initializerContext);
}
diff --git a/src/legacy/core_plugins/timelion/public/legacy.ts b/src/legacy/core_plugins/timelion/public/legacy.ts
new file mode 100644
index 0000000000000..8b8b5d4330b42
--- /dev/null
+++ b/src/legacy/core_plugins/timelion/public/legacy.ts
@@ -0,0 +1,47 @@
+/*
+ * 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 { plugin } from '.';
+import { setup as visualizations } from '../../visualizations/public/legacy';
+import { TimelionPluginSetupDependencies, TimelionPluginStartDependencies } from './plugin';
+// @ts-ignore
+import panelRegistry from './lib/panel_registry';
+import { LegacyDependenciesPlugin } from './shim';
+
+// Temporary solution
+// It will be removed when all dependent services are migrated to the new platform.
+const __LEGACY = new LegacyDependenciesPlugin();
+
+const setupPlugins: Readonly = {
+ visualizations,
+ expressions: npSetup.plugins.expressions,
+ __LEGACY,
+};
+
+const startPlugins: Readonly = {
+ panelRegistry,
+ __LEGACY,
+};
+
+const pluginInstance = plugin({} as PluginInitializerContext);
+
+export const setup = pluginInstance.setup(npSetup.core, setupPlugins);
+export const start = pluginInstance.start(npStart.core, startPlugins);
diff --git a/src/legacy/core_plugins/timelion/public/panels/panel.ts b/src/legacy/core_plugins/timelion/public/panels/panel.ts
new file mode 100644
index 0000000000000..3512cd96a9596
--- /dev/null
+++ b/src/legacy/core_plugins/timelion/public/panels/panel.ts
@@ -0,0 +1,45 @@
+/*
+ * 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 { i18n } from '@kbn/i18n';
+
+interface PanelConfig {
+ help?: string;
+ render?: Function;
+}
+
+export class Panel {
+ name: string;
+ help: string;
+ render: Function | undefined;
+
+ constructor(name: string, config: PanelConfig) {
+ this.name = name;
+ this.help = config.help || '';
+ this.render = config.render;
+
+ if (!config.render) {
+ throw new Error(
+ i18n.translate('timelion.panels.noRenderFunctionErrorMessage', {
+ defaultMessage: 'Panel must have a rendering function',
+ })
+ );
+ }
+ }
+}
diff --git a/src/legacy/core_plugins/timelion/public/panels/timechart/schema.js b/src/legacy/core_plugins/timelion/public/panels/timechart/schema.ts
similarity index 71%
rename from src/legacy/core_plugins/timelion/public/panels/timechart/schema.js
rename to src/legacy/core_plugins/timelion/public/panels/timechart/schema.ts
index 20e3338ea74fd..a9b788ca93055 100644
--- a/src/legacy/core_plugins/timelion/public/panels/timechart/schema.js
+++ b/src/legacy/core_plugins/timelion/public/panels/timechart/schema.ts
@@ -17,29 +17,36 @@
* under the License.
*/
-require('./flot');
+import './flot';
import _ from 'lodash';
import $ from 'jquery';
import moment from 'moment-timezone';
+import { timefilter } from 'ui/timefilter';
+// @ts-ignore
import observeResize from '../../lib/observe_resize';
+// @ts-ignore
import { calculateInterval, DEFAULT_TIME_FORMAT } from '../../../common/lib';
-import { timefilter } from 'ui/timefilter';
+import { TimelionStartDependencies } from '../../plugin';
+import { tickFormatters } from '../../services/tick_formatters';
+import { xaxisFormatterProvider } from './xaxis_formatter';
+import { generateTicksProvider } from './tick_generator';
const DEBOUNCE_DELAY = 50;
-export default function timechartFn(Private, config, $rootScope, $compile) {
- return function () {
+export function timechartFn(dependencies: TimelionStartDependencies) {
+ const { $rootScope, $compile, uiSettings } = dependencies;
+ return function() {
return {
help: 'Draw a timeseries chart',
- render: function ($scope, $elem) {
+ render($scope: any, $elem: any) {
const template = '';
- const tickFormatters = require('plugins/timelion/services/tick_formatters')();
- const getxAxisFormatter = Private(require('plugins/timelion/panels/timechart/xaxis_formatter'));
- const generateTicks = Private(require('plugins/timelion/panels/timechart/tick_generator'));
+ const formatters = tickFormatters() as any;
+ const getxAxisFormatter = xaxisFormatterProvider(uiSettings);
+ const generateTicks = generateTicksProvider();
// TODO: I wonder if we should supply our own moment that sets this every time?
// could just use angular's injection to provide a moment service?
- moment.tz.setDefault(config.get('dateFormat:tz'));
+ moment.tz.setDefault(uiSettings.get('dateFormat:tz'));
const render = $scope.seriesList.render || {};
@@ -47,12 +54,12 @@ export default function timechartFn(Private, config, $rootScope, $compile) {
$scope.interval = $scope.interval;
$scope.search = $scope.search || _.noop;
- let legendValueNumbers;
- let legendCaption;
+ let legendValueNumbers: any;
+ let legendCaption: any;
const debouncedSetLegendNumbers = _.debounce(setLegendNumbers, DEBOUNCE_DELAY, {
maxWait: DEBOUNCE_DELAY,
leading: true,
- trailing: false
+ trailing: false,
});
// ensure legend is the same height with or without a caption so legend items do not move around
const emptyCaption = '
';
@@ -65,12 +72,12 @@ export default function timechartFn(Private, config, $rootScope, $compile) {
},
selection: {
mode: 'x',
- color: '#ccc'
+ color: '#ccc',
},
crosshair: {
mode: 'x',
color: '#C66',
- lineWidth: 2
+ lineWidth: 2,
},
grid: {
show: render.grid,
@@ -78,13 +85,13 @@ export default function timechartFn(Private, config, $rootScope, $compile) {
borderColor: null,
margin: 10,
hoverable: true,
- autoHighlight: false
+ autoHighlight: false,
},
legend: {
backgroundColor: 'rgb(255,255,255,0)',
position: 'nw',
labelBoxBorderColor: 'rgb(255,255,255,0)',
- labelFormatter: function (label, series) {
+ labelFormatter(label: any, series: any) {
const wrapperSpan = document.createElement('span');
const labelSpan = document.createElement('span');
const numberSpan = document.createElement('span');
@@ -103,13 +110,24 @@ export default function timechartFn(Private, config, $rootScope, $compile) {
wrapperSpan.appendChild(numberSpan);
return wrapperSpan.outerHTML;
- }
+ },
},
- colors: ['#01A4A4', '#C66', '#D0D102', '#616161', '#00A1CB', '#32742C', '#F18D05', '#113F8C', '#61AE24', '#D70060']
+ colors: [
+ '#01A4A4',
+ '#C66',
+ '#D0D102',
+ '#616161',
+ '#00A1CB',
+ '#32742C',
+ '#F18D05',
+ '#113F8C',
+ '#61AE24',
+ '#D70060',
+ ],
};
const originalColorMap = new Map();
- $scope.chart.forEach((series, seriesIndex) => {
+ $scope.chart.forEach((series: any, seriesIndex: any) => {
if (!series.color) {
const colorIndex = seriesIndex % defaultOptions.colors.length;
series.color = defaultOptions.colors[colorIndex];
@@ -117,8 +135,8 @@ export default function timechartFn(Private, config, $rootScope, $compile) {
originalColorMap.set(series, series.color);
});
- let highlightedSeries;
- let focusedSeries;
+ let highlightedSeries: any;
+ let focusedSeries: any;
function unhighlightSeries() {
if (highlightedSeries === null) {
return;
@@ -126,18 +144,18 @@ export default function timechartFn(Private, config, $rootScope, $compile) {
highlightedSeries = null;
focusedSeries = null;
- $scope.chart.forEach((series) => {
+ $scope.chart.forEach((series: any) => {
series.color = originalColorMap.get(series); // reset the colors
});
drawPlot($scope.chart);
}
- $scope.highlightSeries = _.debounce(function (id) {
+ $scope.highlightSeries = _.debounce(function(id: any) {
if (highlightedSeries === id) {
return;
}
highlightedSeries = id;
- $scope.chart.forEach((series, seriesIndex) => {
+ $scope.chart.forEach((series: any, seriesIndex: any) => {
if (seriesIndex !== id) {
series.color = 'rgba(128,128,128,0.1)'; // mark as grey
} else {
@@ -146,58 +164,57 @@ export default function timechartFn(Private, config, $rootScope, $compile) {
});
drawPlot($scope.chart);
}, DEBOUNCE_DELAY);
- $scope.focusSeries = function (id) {
+ $scope.focusSeries = function(id: any) {
focusedSeries = id;
$scope.highlightSeries(id);
};
- $scope.toggleSeries = function (id) {
+ $scope.toggleSeries = function(id: any) {
const series = $scope.chart[id];
series._hide = !series._hide;
drawPlot($scope.chart);
};
- const cancelResize = observeResize($elem, function () {
+ const cancelResize = observeResize($elem, function() {
drawPlot($scope.chart);
});
- $scope.$on('$destroy', function () {
+ $scope.$on('$destroy', function() {
cancelResize();
$elem.off('plothover');
$elem.off('plotselected');
$elem.off('mouseleave');
});
- $elem.on('plothover', function (event, pos, item) {
+ $elem.on('plothover', function(event: any, pos: any, item: any) {
$rootScope.$broadcast('timelionPlotHover', event, pos, item);
});
- $elem.on('plotselected', function (event, ranges) {
+ $elem.on('plotselected', function(event: any, ranges: any) {
timefilter.setTime({
from: moment(ranges.xaxis.from),
to: moment(ranges.xaxis.to),
- mode: 'absolute',
});
});
- $elem.on('mouseleave', function () {
+ $elem.on('mouseleave', function() {
$rootScope.$broadcast('timelionPlotLeave');
});
- $scope.$on('timelionPlotHover', function (angularEvent, flotEvent, pos) {
+ $scope.$on('timelionPlotHover', function(angularEvent: any, flotEvent: any, pos: any) {
if (!$scope.plot) return;
$scope.plot.setCrosshair(pos);
debouncedSetLegendNumbers(pos);
});
- $scope.$on('timelionPlotLeave', function () {
+ $scope.$on('timelionPlotLeave', function() {
if (!$scope.plot) return;
$scope.plot.clearCrosshair();
clearLegendNumbers();
});
// Shamelessly borrowed from the flotCrosshairs example
- function setLegendNumbers(pos) {
+ function setLegendNumbers(pos: any) {
unhighlightSeries();
const plot = $scope.plot;
@@ -211,10 +228,13 @@ export default function timechartFn(Private, config, $rootScope, $compile) {
let j;
const dataset = plot.getData();
if (legendCaption) {
- legendCaption.text(moment(pos.x).format(_.get(dataset, '[0]._global.legend.timeFormat', DEFAULT_TIME_FORMAT)));
+ legendCaption.text(
+ moment(pos.x).format(
+ _.get(dataset, '[0]._global.legend.timeFormat', DEFAULT_TIME_FORMAT)
+ )
+ );
}
for (i = 0; i < dataset.length; ++i) {
-
const series = dataset[i];
const precision = _.get(series, '_meta.precision', 2);
@@ -248,13 +268,13 @@ export default function timechartFn(Private, config, $rootScope, $compile) {
if (legendCaption) {
legendCaption.html(emptyCaption);
}
- _.each(legendValueNumbers, function (num) {
+ _.each(legendValueNumbers, function(num) {
$(num).empty();
});
}
let legendScope = $scope.$new();
- function drawPlot(plotConfig) {
+ function drawPlot(plotConfig: any) {
if (!$('.chart-canvas', $elem).length) $elem.html(template);
const canvasElem = $('.chart-canvas', $elem);
@@ -264,56 +284,63 @@ export default function timechartFn(Private, config, $rootScope, $compile) {
return;
}
- const title = _(plotConfig).map('_title').compact().last();
+ const title = _(plotConfig)
+ .map('_title')
+ .compact()
+ .last() as any;
$('.chart-top-title', $elem).text(title == null ? '' : title);
- const options = _.cloneDeep(defaultOptions);
+ const options = _.cloneDeep(defaultOptions) as any;
// Get the X-axis tick format
- const time = timefilter.getBounds();
+ const time = timefilter.getBounds() as any;
const interval = calculateInterval(
time.min.valueOf(),
time.max.valueOf(),
- config.get('timelion:target_buckets') || 200,
+ uiSettings.get('timelion:target_buckets') || 200,
$scope.interval,
- config.get('timelion:min_interval') || '1ms',
+ uiSettings.get('timelion:min_interval') || '1ms'
);
const format = getxAxisFormatter(interval);
// Use moment to format ticks so we get timezone correction
- options.xaxis.tickFormatter = function (val) {
+ options.xaxis.tickFormatter = function(val: any) {
return moment(val).format(format);
};
// Calculate how many ticks can fit on the axis
const tickLetterWidth = 7;
const tickPadding = 45;
- options.xaxis.ticks = Math.floor($elem.width() / ((format.length * tickLetterWidth) + tickPadding));
-
- const series = _.map(plotConfig, function (series, index) {
- series = _.cloneDeep(_.defaults(series, {
- shadowSize: 0,
- lines: {
- lineWidth: 3
- }
- }));
- series._id = index;
+ options.xaxis.ticks = Math.floor(
+ $elem.width() / (format.length * tickLetterWidth + tickPadding)
+ );
- if (series.color) {
+ const series = _.map(plotConfig, function(serie: any, index) {
+ serie = _.cloneDeep(
+ _.defaults(serie, {
+ shadowSize: 0,
+ lines: {
+ lineWidth: 3,
+ },
+ })
+ );
+ serie._id = index;
+
+ if (serie.color) {
const span = document.createElement('span');
- span.style.color = series.color;
- series.color = span.style.color;
+ span.style.color = serie.color;
+ serie.color = span.style.color;
}
- if (series._hide) {
- series.data = [];
- series.stack = false;
- //series.color = "#ddd";
- series.label = '(hidden) ' + series.label;
+ if (serie._hide) {
+ serie.data = [];
+ serie.stack = false;
+ // serie.color = "#ddd";
+ serie.label = '(hidden) ' + serie.label;
}
- if (series._global) {
- _.merge(options, series._global, function (objVal, srcVal) {
+ if (serie._global) {
+ _.merge(options, serie._global, function(objVal, srcVal) {
// This is kind of gross, it means that you can't replace a global value with a null
// best you can do is an empty string. Deal with it.
if (objVal == null) return srcVal;
@@ -321,13 +348,13 @@ export default function timechartFn(Private, config, $rootScope, $compile) {
});
}
- return series;
+ return serie;
});
if (options.yaxes) {
- options.yaxes.forEach(yaxis => {
+ options.yaxes.forEach((yaxis: any) => {
if (yaxis && yaxis.units) {
- yaxis.tickFormatter = tickFormatters[yaxis.units.type];
+ yaxis.tickFormatter = formatters[yaxis.units.type];
const byteModes = ['bytes', 'bytes/s'];
if (byteModes.includes(yaxis.units.type)) {
yaxis.tickGenerator = generateTicks;
@@ -336,6 +363,7 @@ export default function timechartFn(Private, config, $rootScope, $compile) {
});
}
+ // @ts-ignore
$scope.plot = $.plot(canvasElem, _.compact(series), options);
if ($scope.plot) {
@@ -346,7 +374,7 @@ export default function timechartFn(Private, config, $rootScope, $compile) {
legendScope = $scope.$new();
// Used to toggle the series, and for displaying values on hover
legendValueNumbers = canvasElem.find('.ngLegendValueNumber');
- _.each(canvasElem.find('.ngLegendValue'), function (elem) {
+ _.each(canvasElem.find('.ngLegendValue'), function(elem) {
$compile(elem)(legendScope);
});
@@ -363,7 +391,7 @@ export default function timechartFn(Private, config, $rootScope, $compile) {
}
}
$scope.$watch('chart', drawPlot);
- }
+ },
};
};
}
diff --git a/src/legacy/core_plugins/timelion/public/panels/timechart/tick_generator.js b/src/legacy/core_plugins/timelion/public/panels/timechart/tick_generator.ts
similarity index 81%
rename from src/legacy/core_plugins/timelion/public/panels/timechart/tick_generator.js
rename to src/legacy/core_plugins/timelion/public/panels/timechart/tick_generator.ts
index 5a624964274b1..f7d696a0316db 100644
--- a/src/legacy/core_plugins/timelion/public/panels/timechart/tick_generator.js
+++ b/src/legacy/core_plugins/timelion/public/panels/timechart/tick_generator.ts
@@ -17,13 +17,12 @@
* under the License.
*/
-export default function generateTicksProvider() {
-
- function floorInBase(n, base) {
+export function generateTicksProvider() {
+ function floorInBase(n: any, base: any) {
return base * Math.floor(n / base);
}
- function generateTicks(axis) {
+ function generateTicks(axis: any) {
const returnTicks = [];
let tickSize = 2;
let delta = axis.delta;
@@ -31,13 +30,13 @@ export default function generateTicksProvider() {
let tickVal;
let tickCount = 0;
- //Count the steps
+ // Count the steps
while (Math.abs(delta) >= 1024) {
steps++;
delta /= 1024;
}
- //Set the tick size relative to the remaining delta
+ // Set the tick size relative to the remaining delta
while (tickSize <= 1024) {
if (delta <= tickSize) {
break;
@@ -46,17 +45,17 @@ export default function generateTicksProvider() {
}
axis.tickSize = tickSize * Math.pow(1024, steps);
- //Calculate the new ticks
+ // Calculate the new ticks
const tickMin = floorInBase(axis.min, axis.tickSize);
do {
- tickVal = tickMin + (tickCount++) * axis.tickSize;
+ tickVal = tickMin + tickCount++ * axis.tickSize;
returnTicks.push(tickVal);
} while (tickVal < axis.max);
return returnTicks;
}
- return function (axis) {
+ return function(axis: any) {
return generateTicks(axis);
};
}
diff --git a/src/legacy/core_plugins/timelion/public/panels/timechart/timechart.js b/src/legacy/core_plugins/timelion/public/panels/timechart/timechart.ts
similarity index 77%
rename from src/legacy/core_plugins/timelion/public/panels/timechart/timechart.js
rename to src/legacy/core_plugins/timelion/public/panels/timechart/timechart.ts
index a3bee66f9d4ef..63eabd6cb0edf 100644
--- a/src/legacy/core_plugins/timelion/public/panels/timechart/timechart.js
+++ b/src/legacy/core_plugins/timelion/public/panels/timechart/timechart.ts
@@ -17,12 +17,12 @@
* under the License.
*/
-import Panel from '../panel';
-import { i18n } from '@kbn/i18n';
-import panelRegistry from '../../lib/panel_registry';
+import { timechartFn } from './schema';
+import { Panel } from '../panel';
+import { TimelionStartDependencies } from '../../plugin';
-panelRegistry.register(function timeChartProvider(Private) {
+export function getTimeChart(dependencies: TimelionStartDependencies) {
// Schema is broken out so that it may be extended for use in other plugins
// Its also easier to test.
- return new Panel('timechart', Private(require('./schema'))(), i18n);
-});
+ return new Panel('timechart', timechartFn(dependencies)());
+}
diff --git a/src/legacy/core_plugins/timelion/public/panels/timechart/xaxis_formatter.js b/src/legacy/core_plugins/timelion/public/panels/timechart/xaxis_formatter.ts
similarity index 91%
rename from src/legacy/core_plugins/timelion/public/panels/timechart/xaxis_formatter.js
rename to src/legacy/core_plugins/timelion/public/panels/timechart/xaxis_formatter.ts
index 4e49c4eca6538..db3408dae33db 100644
--- a/src/legacy/core_plugins/timelion/public/panels/timechart/xaxis_formatter.js
+++ b/src/legacy/core_plugins/timelion/public/panels/timechart/xaxis_formatter.ts
@@ -21,13 +21,12 @@ import moment from 'moment';
import { i18n } from '@kbn/i18n';
-export default function xaxisFormatterProvider(config) {
-
- function getFormat(esInterval) {
+export function xaxisFormatterProvider(config: any) {
+ function getFormat(esInterval: any) {
const parts = esInterval.match(/(\d+)(ms|s|m|h|d|w|M|y|)/);
if (parts == null || parts[1] == null || parts[2] == null) {
- throw new Error (
+ throw new Error(
i18n.translate('timelion.panels.timechart.unknownIntervalErrorMessage', {
defaultMessage: 'Unknown interval',
})
@@ -49,7 +48,7 @@ export default function xaxisFormatterProvider(config) {
return config.get('dateFormat');
}
- return function (esInterval) {
+ return function(esInterval: any) {
return getFormat(esInterval);
};
}
diff --git a/src/legacy/core_plugins/timelion/public/plugin.ts b/src/legacy/core_plugins/timelion/public/plugin.ts
new file mode 100644
index 0000000000000..4adfac3726b95
--- /dev/null
+++ b/src/legacy/core_plugins/timelion/public/plugin.ts
@@ -0,0 +1,100 @@
+/*
+ * 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 {
+ CoreSetup,
+ CoreStart,
+ LegacyCoreStart,
+ Plugin,
+ PluginInitializerContext,
+ UiSettingsClientContract,
+ HttpSetup,
+} from 'kibana/public';
+import { Plugin as ExpressionsPlugin } from 'src/plugins/expressions/public';
+import { VisualizationsSetup } from '../../visualizations/public/np_ready';
+import { getTimelionVisualizationConfig } from './timelion_vis_fn';
+import { getTimelionVisualization } from './vis';
+import { getTimeChart } from './panels/timechart/timechart';
+import { LegacyDependenciesPlugin, LegacyDependenciesPluginStart } from './shim';
+
+/** @internal */
+export interface TimelionPluginSetupDependencies {
+ expressions: ReturnType;
+ visualizations: VisualizationsSetup;
+
+ // Temporary solution
+ __LEGACY: LegacyDependenciesPlugin;
+}
+
+/** @internal */
+export interface TimelionPluginStartDependencies {
+ panelRegistry: any;
+
+ // Temporary solution
+ __LEGACY: LegacyDependenciesPlugin;
+}
+
+/** @private */
+export interface TimelionVisualizationDependencies {
+ uiSettings: UiSettingsClientContract;
+ http: HttpSetup;
+}
+
+/** @internal */
+export type TimelionStartDependencies = Pick &
+ LegacyDependenciesPluginStart;
+
+/** @internal */
+export class TimelionPlugin
+ implements
+ Plugin, void, TimelionPluginSetupDependencies, TimelionPluginStartDependencies> {
+ initializerContext: PluginInitializerContext;
+
+ constructor(initializerContext: PluginInitializerContext) {
+ this.initializerContext = initializerContext;
+ }
+
+ public async setup(core: CoreSetup, plugins: TimelionPluginSetupDependencies) {
+ const dependencies: TimelionVisualizationDependencies = {
+ uiSettings: core.uiSettings,
+ http: core.http,
+ };
+
+ plugins.__LEGACY.setup();
+ plugins.expressions.registerFunction(() => getTimelionVisualizationConfig(dependencies));
+ plugins.visualizations.types.registerVisualization(() =>
+ getTimelionVisualization(dependencies)
+ );
+ }
+
+ public async start(core: CoreStart & LegacyCoreStart, plugins: TimelionPluginStartDependencies) {
+ const dependencies: TimelionStartDependencies = {
+ uiSettings: core.uiSettings,
+ ...(await plugins.__LEGACY.start()),
+ };
+ const timelionUiEnabled = core.injectedMetadata.getInjectedVar('timelionUiEnabled');
+
+ if (timelionUiEnabled === false) {
+ core.chrome.navLinks.update('timelion', { hidden: true });
+ }
+
+ plugins.panelRegistry.register(() => getTimeChart(dependencies));
+ }
+
+ public stop(): void {}
+}
diff --git a/src/legacy/core_plugins/timelion/public/register_feature.js b/src/legacy/core_plugins/timelion/public/register_feature.ts
similarity index 87%
rename from src/legacy/core_plugins/timelion/public/register_feature.js
rename to src/legacy/core_plugins/timelion/public/register_feature.ts
index 415ed532f6a34..7dd44b58bd1d7 100644
--- a/src/legacy/core_plugins/timelion/public/register_feature.js
+++ b/src/legacy/core_plugins/timelion/public/register_feature.ts
@@ -17,14 +17,10 @@
* under the License.
*/
-import {
- FeatureCatalogueRegistryProvider,
- FeatureCatalogueCategory,
-} from 'ui/registry/feature_catalogue';
-
+import { FeatureCatalogueCategory } from 'ui/registry/feature_catalogue';
import { i18n } from '@kbn/i18n';
-FeatureCatalogueRegistryProvider.register(() => {
+export const registerFeature = () => {
return {
id: 'timelion',
title: 'Timelion',
@@ -37,4 +33,4 @@ FeatureCatalogueRegistryProvider.register(() => {
showOnHomePage: false,
category: FeatureCatalogueCategory.DATA,
};
-});
+};
diff --git a/src/legacy/core_plugins/timelion/public/services/tick_formatters.js b/src/legacy/core_plugins/timelion/public/services/tick_formatters.ts
similarity index 70%
rename from src/legacy/core_plugins/timelion/public/services/tick_formatters.js
rename to src/legacy/core_plugins/timelion/public/services/tick_formatters.ts
index 2d0a726ad53d0..2c78d2423cc06 100644
--- a/src/legacy/core_plugins/timelion/public/services/tick_formatters.js
+++ b/src/legacy/core_plugins/timelion/public/services/tick_formatters.ts
@@ -19,7 +19,7 @@
import _ from 'lodash';
-function baseTickFormatter(value, axis) {
+function baseTickFormatter(value: any, axis: any) {
const factor = axis.tickDecimals ? Math.pow(10, axis.tickDecimals) : 1;
const formatted = '' + Math.round(value * factor) / factor;
@@ -30,15 +30,18 @@ function baseTickFormatter(value, axis) {
const decimal = formatted.indexOf('.');
const precision = decimal === -1 ? 0 : formatted.length - decimal - 1;
if (precision < axis.tickDecimals) {
- return (precision ? formatted : formatted + '.') + ('' + factor).substr(1, axis.tickDecimals - precision);
+ return (
+ (precision ? formatted : formatted + '.') +
+ ('' + factor).substr(1, axis.tickDecimals - precision)
+ );
}
}
return formatted;
}
-function unitFormatter(divisor, units) {
- return (val) => {
+function unitFormatter(divisor: any, units: any) {
+ return (val: any) => {
let index = 0;
const isNegative = val < 0;
val = Math.abs(val);
@@ -46,22 +49,26 @@ function unitFormatter(divisor, units) {
val /= divisor;
index++;
}
- const value = Math.round(val * 100) / 100 * (isNegative ? -1 : 1);
+ const value = (Math.round(val * 100) / 100) * (isNegative ? -1 : 1);
return `${value}${units[index]}`;
};
}
-export default function tickFormatters() {
- const formatters = {
- 'bits': unitFormatter(1000, ['b', 'kb', 'mb', 'gb', 'tb', 'pb']),
+export function tickFormatters() {
+ const formatters = {
+ bits: unitFormatter(1000, ['b', 'kb', 'mb', 'gb', 'tb', 'pb']),
'bits/s': unitFormatter(1000, ['b/s', 'kb/s', 'mb/s', 'gb/s', 'tb/s', 'pb/s']),
- 'bytes': unitFormatter(1024, ['B', 'KB', 'MB', 'GB', 'TB', 'PB']),
+ bytes: unitFormatter(1024, ['B', 'KB', 'MB', 'GB', 'TB', 'PB']),
'bytes/s': unitFormatter(1024, ['B/s', 'KB/s', 'MB/s', 'GB/s', 'TB/s', 'PB/s']),
- 'currency': function (val, axis) {
- return val.toLocaleString('en', { style: 'currency', currency: axis.options.units.prefix || 'USD' });
+ currency(val: any, axis: any) {
+ return val.toLocaleString('en', {
+ style: 'currency',
+ currency: axis.options.units.prefix || 'USD',
+ });
},
- 'percent': function (val, axis) {
- let precision = _.get(axis, 'tickDecimals', 0) - _.get(axis, 'options.units.tickDecimalsShift', 0);
+ percent(val: any, axis: any) {
+ let precision =
+ _.get(axis, 'tickDecimals', 0) - _.get(axis, 'options.units.tickDecimalsShift', 0);
// toFixed only accepts values between 0 and 20
if (precision < 0) {
precision = 0;
@@ -71,12 +78,12 @@ export default function tickFormatters() {
return (val * 100).toFixed(precision) + '%';
},
- 'custom': function (val, axis) {
+ custom(val: any, axis: any) {
const formattedVal = baseTickFormatter(val, axis);
const prefix = axis.options.units.prefix;
const suffix = axis.options.units.suffix;
return prefix + formattedVal + suffix;
- }
+ },
};
return formatters;
diff --git a/src/legacy/core_plugins/timelion/public/panels/panel.js b/src/legacy/core_plugins/timelion/public/shim/index.ts
similarity index 68%
rename from src/legacy/core_plugins/timelion/public/panels/panel.js
rename to src/legacy/core_plugins/timelion/public/shim/index.ts
index f45aeb08e31fe..cfc7b62ff4f86 100644
--- a/src/legacy/core_plugins/timelion/public/panels/panel.js
+++ b/src/legacy/core_plugins/timelion/public/shim/index.ts
@@ -17,22 +17,4 @@
* under the License.
*/
-import { i18n } from '@kbn/i18n';
-
-export default function Panel(name, config) {
-
- this.name = name;
-
- this.help = config.help || '';
-
- this.render = config.render;
-
- if (!config.render) {
- throw new Error (
- i18n.translate('timelion.panels.noRenderFunctionErrorMessage', {
- defaultMessage: 'Panel must have a rendering function'
- })
- );
- }
-
-}
+export * from './legacy_dependencies_plugin';
diff --git a/src/legacy/core_plugins/timelion/public/vis/timelion_vis_controller.js b/src/legacy/core_plugins/timelion/public/shim/legacy_dependencies_plugin.ts
similarity index 55%
rename from src/legacy/core_plugins/timelion/public/vis/timelion_vis_controller.js
rename to src/legacy/core_plugins/timelion/public/shim/legacy_dependencies_plugin.ts
index d621dd4b9cd8f..82c908e78ce7b 100644
--- a/src/legacy/core_plugins/timelion/public/vis/timelion_vis_controller.js
+++ b/src/legacy/core_plugins/timelion/public/shim/legacy_dependencies_plugin.ts
@@ -17,18 +17,28 @@
* under the License.
*/
+import chrome from 'ui/chrome';
+import { Plugin } from 'kibana/public';
+import { initTimelionLegacyModule } from './timelion_legacy_module';
-import '../directives/chart/chart';
-import '../directives/timelion_interval/timelion_interval';
-import 'ui/state_management/app_state';
+/** @internal */
+export interface LegacyDependenciesPluginStart {
+ $rootScope: any;
+ $compile: any;
+}
-import { uiModules } from 'ui/modules';
+export class LegacyDependenciesPlugin
+ implements Plugin> {
+ public setup() {
+ initTimelionLegacyModule();
+ }
-uiModules
- .get('kibana/timelion_vis', ['kibana'])
- .controller('TimelionVisController', function ($scope) {
- $scope.$on('timelionChartRendered', event => {
- event.stopPropagation();
- $scope.renderComplete();
- });
- });
+ public async start() {
+ const $injector = await chrome.dangerouslyGetActiveInjector();
+
+ return {
+ $rootScope: $injector.get('$rootScope'),
+ $compile: $injector.get('$compile'),
+ } as LegacyDependenciesPluginStart;
+ }
+}
diff --git a/src/legacy/core_plugins/timelion/public/shim/timelion_legacy_module.ts b/src/legacy/core_plugins/timelion/public/shim/timelion_legacy_module.ts
new file mode 100644
index 0000000000000..c461973172865
--- /dev/null
+++ b/src/legacy/core_plugins/timelion/public/shim/timelion_legacy_module.ts
@@ -0,0 +1,54 @@
+/*
+ * 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 'ngreact';
+import 'brace/mode/hjson';
+import 'brace/ext/searchbox';
+import 'ui/accessibility/kbn_ui_ace_keyboard_mode';
+import 'ui/vis/map/service_settings';
+
+import { once } from 'lodash';
+// @ts-ignore
+import { uiModules } from 'ui/modules';
+// @ts-ignore
+import { Chart } from '../directives/chart/chart';
+// @ts-ignore
+import { TimelionInterval } from '../directives/timelion_interval/timelion_interval';
+// @ts-ignore
+import { TimelionExpInput } from '../directives/timelion_expression_input';
+// @ts-ignore
+import { TimelionExpressionSuggestions } from '../directives/timelion_expression_suggestions/timelion_expression_suggestions';
+
+/** @internal */
+export const initTimelionLegacyModule = once((): void => {
+ require('ui/state_management/app_state');
+
+ uiModules
+ .get('apps/timelion', [])
+ .controller('TimelionVisController', function($scope: any) {
+ $scope.$on('timelionChartRendered', (event: any) => {
+ event.stopPropagation();
+ $scope.renderComplete();
+ });
+ })
+ .directive('chart', Chart)
+ .directive('timelionInterval', TimelionInterval)
+ .directive('timelionExpressionSuggestions', TimelionExpressionSuggestions)
+ .directive('timelionExpressionInput', TimelionExpInput);
+});
diff --git a/src/legacy/core_plugins/timelion/public/timelion_vis_fn.js b/src/legacy/core_plugins/timelion/public/timelion_vis_fn.ts
similarity index 55%
rename from src/legacy/core_plugins/timelion/public/timelion_vis_fn.js
rename to src/legacy/core_plugins/timelion/public/timelion_vis_fn.ts
index 9161715d28022..86bc9a8088217 100644
--- a/src/legacy/core_plugins/timelion/public/timelion_vis_fn.js
+++ b/src/legacy/core_plugins/timelion/public/timelion_vis_fn.ts
@@ -17,51 +17,65 @@
* under the License.
*/
-import { functionsRegistry } from 'plugins/interpreter/registries';
import { get } from 'lodash';
import { i18n } from '@kbn/i18n';
-import { TimelionRequestHandlerProvider } from './vis/timelion_request_handler';
+import { ExpressionFunction, KibanaContext, Render } from 'src/plugins/expressions/public';
+import { getTimelionRequestHandler, TimelionSuccessResponse } from './vis/timelion_request_handler';
+import { TimelionVisualizationDependencies } from './plugin';
+const name = 'timelion_vis';
-import chrome from 'ui/chrome';
+interface Arguments {
+ expression: string;
+ interval: any;
+}
-export const timelionVis = () => ({
- name: 'timelion_vis',
+interface RenderValue {
+ visData: Context;
+ visType: typeof name;
+ visParams: VisParams;
+}
+
+type Context = KibanaContext | null;
+type VisParams = Arguments;
+type Return = Promise>;
+
+export const getTimelionVisualizationConfig = (
+ dependencies: TimelionVisualizationDependencies
+): ExpressionFunction => ({
+ name,
type: 'render',
context: {
- types: [
- 'kibana_context',
- 'null',
- ],
+ types: ['kibana_context', 'null'],
},
help: i18n.translate('timelion.function.help', {
- defaultMessage: 'Timelion visualization'
+ defaultMessage: 'Timelion visualization',
}),
args: {
expression: {
types: ['string'],
aliases: ['_'],
default: '".es(*)"',
+ help: '',
},
interval: {
types: ['string', 'null'],
default: 'auto',
- }
+ help: '',
+ },
},
async fn(context, args) {
- const $injector = await chrome.dangerouslyGetActiveInjector();
- const Private = $injector.get('Private');
- const timelionRequestHandler = Private(TimelionRequestHandlerProvider).handler;
+ const timelionRequestHandler = getTimelionRequestHandler(dependencies);
const visParams = { expression: args.expression, interval: args.interval };
- const response = await timelionRequestHandler({
- timeRange: get(context, 'timeRange', null),
- query: get(context, 'query', null),
- filters: get(context, 'filters', null),
+ const response = (await timelionRequestHandler({
+ timeRange: get(context, 'timeRange'),
+ query: get(context, 'query'),
+ filters: get(context, 'filters'),
+ visParams,
forceFetch: true,
- visParams: visParams,
- });
+ })) as TimelionSuccessResponse;
response.visType = 'timelion';
@@ -70,11 +84,9 @@ export const timelionVis = () => ({
as: 'visualization',
value: {
visParams,
- visType: 'timelion',
+ visType: name,
visData: response,
},
};
},
});
-
-functionsRegistry.register(timelionVis);
diff --git a/src/legacy/core_plugins/timelion/public/vis/index.js b/src/legacy/core_plugins/timelion/public/vis/index.ts
similarity index 73%
rename from src/legacy/core_plugins/timelion/public/vis/index.js
rename to src/legacy/core_plugins/timelion/public/vis/index.ts
index f06076a3600a3..e7f1c91a3393d 100644
--- a/src/legacy/core_plugins/timelion/public/vis/index.js
+++ b/src/legacy/core_plugins/timelion/public/vis/index.ts
@@ -17,25 +17,19 @@
* under the License.
*/
-import { visFactory } from 'ui/vis/vis_factory';
import { i18n } from '@kbn/i18n';
-import { VisTypesRegistryProvider } from 'ui/registry/vis_types';
-import { TimelionRequestHandlerProvider } from './timelion_request_handler';
+// @ts-ignore
import { DefaultEditorSize } from 'ui/vis/editor_size';
-import { AngularVisController } from '../../../../ui/public/vis/vis_types/angular_vis_type';
-
-// we also need to load the controller and directive used by the template
-import './timelion_vis_controller';
-import '../directives/timelion_expression_input';
-
+import { visFactory } from '../../../visualizations/public';
+import { getTimelionRequestHandler } from './timelion_request_handler';
import visConfigTemplate from './timelion_vis.html';
import editorConfigTemplate from './timelion_vis_params.html';
+import { TimelionVisualizationDependencies } from '../plugin';
+// @ts-ignore
+import { AngularVisController } from '../../../../ui/public/vis/vis_types/angular_vis_type';
-// register the provider with the visTypes registry so that other know it exists
-VisTypesRegistryProvider.register(TimelionVisProvider);
-
-export default function TimelionVisProvider(Private) {
- const timelionRequestHandler = Private(TimelionRequestHandlerProvider);
+export function getTimelionVisualization(dependencies: TimelionVisualizationDependencies) {
+ const timelionRequestHandler = getTimelionRequestHandler(dependencies);
// return the visType object, which kibana will use to display and configure new
// Vis object of this type.
@@ -50,7 +44,7 @@ export default function TimelionVisProvider(Private) {
visConfig: {
defaults: {
expression: '.es(*)',
- interval: 'auto'
+ interval: 'auto',
},
template: visConfigTemplate,
},
@@ -58,7 +52,7 @@ export default function TimelionVisProvider(Private) {
optionsTemplate: editorConfigTemplate,
defaultSize: DefaultEditorSize.MEDIUM,
},
- requestHandler: timelionRequestHandler.handler,
+ requestHandler: timelionRequestHandler,
responseHandler: 'none',
options: {
showIndexSelection: false,
diff --git a/src/legacy/core_plugins/timelion/public/vis/timelion_request_handler.js b/src/legacy/core_plugins/timelion/public/vis/timelion_request_handler.js
deleted file mode 100644
index 21b6a243e77d9..0000000000000
--- a/src/legacy/core_plugins/timelion/public/vis/timelion_request_handler.js
+++ /dev/null
@@ -1,71 +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 _ from 'lodash';
-import { buildEsQuery, getEsQueryConfig } from '@kbn/es-query';
-import { timezoneProvider } from 'ui/vis/lib/timezone';
-import { toastNotifications } from 'ui/notify';
-import { i18n } from '@kbn/i18n';
-
-const TimelionRequestHandlerProvider = function (Private, $http, config) {
- const timezone = Private(timezoneProvider)();
-
- return {
- name: 'timelion',
- handler: function ({ timeRange, filters, query, visParams }) {
-
- return new Promise((resolve, reject) => {
- const expression = visParams.expression;
- if (!expression) return;
- const esQueryConfigs = getEsQueryConfig(config);
- const httpResult = $http.post('../api/timelion/run', {
- sheet: [expression],
- extended: {
- es: {
- filter: buildEsQuery(undefined, query, filters, esQueryConfigs)
- }
- },
- time: _.extend(timeRange, {
- interval: visParams.interval,
- timezone: timezone
- }),
- })
- .then(resp => resp.data)
- .catch(resp => { throw resp.data; });
-
- httpResult
- .then(function (resp) {
- resolve(resp);
- })
- .catch(function (resp) {
- const err = new Error(resp.message);
- err.stack = resp.stack;
- toastNotifications.addError(err, {
- title: i18n.translate('timelion.requestHandlerErrorTitle', {
- defaultMessage: 'Timelion request error',
- }),
- });
- reject(err);
- });
- });
- }
- };
-};
-
-export { TimelionRequestHandlerProvider };
diff --git a/src/legacy/core_plugins/timelion/public/vis/timelion_request_handler.ts b/src/legacy/core_plugins/timelion/public/vis/timelion_request_handler.ts
new file mode 100644
index 0000000000000..1fbf371c8f91e
--- /dev/null
+++ b/src/legacy/core_plugins/timelion/public/vis/timelion_request_handler.ts
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+// @ts-ignore
+import { buildEsQuery, getEsQueryConfig, Filter } from '@kbn/es-query';
+// @ts-ignore
+import { timezoneProvider } from 'ui/vis/lib/timezone';
+import { KIBANA_CONTEXT_NAME } from 'src/plugins/expressions/public';
+import { Query } from 'src/legacy/core_plugins/data/public';
+import { TimeRange } from 'src/plugins/data/public';
+import { VisParams } from 'ui/vis';
+import { toastNotifications } from 'ui/notify';
+import { i18n } from '@kbn/i18n';
+import { TimelionVisualizationDependencies } from '../plugin';
+
+interface Stats {
+ cacheCount: number;
+ invokeTime: number;
+ queryCount: number;
+ queryTime: number;
+ sheetTime: number;
+}
+
+interface Sheet {
+ list: Array>;
+ render: Record;
+ type: string;
+}
+
+export interface TimelionSuccessResponse {
+ sheet: Sheet[];
+ stats: Stats;
+ visType: string;
+ type: KIBANA_CONTEXT_NAME;
+}
+
+export function getTimelionRequestHandler(dependencies: TimelionVisualizationDependencies) {
+ const { uiSettings, http } = dependencies;
+ const timezone = timezoneProvider(uiSettings)();
+
+ return async function({
+ timeRange,
+ filters,
+ query,
+ visParams,
+ }: {
+ timeRange: TimeRange;
+ filters: Filter[];
+ query: Query;
+ visParams: VisParams;
+ forceFetch?: boolean;
+ }): Promise {
+ const expression = visParams.expression;
+
+ if (!expression) return;
+
+ const esQueryConfigs = getEsQueryConfig(uiSettings);
+
+ try {
+ return await http.post('../api/timelion/run', {
+ body: JSON.stringify({
+ sheet: [expression],
+ extended: {
+ es: {
+ filter: buildEsQuery(undefined, query, filters, esQueryConfigs),
+ },
+ },
+ time: { ...timeRange, interval: visParams.interval, timezone },
+ }),
+ });
+ } catch (e) {
+ const err = new Error(e.data.message);
+
+ err.stack = e.data.stack;
+
+ toastNotifications.addError(err, {
+ title: i18n.translate('timelion.requestHandlerErrorTitle', {
+ defaultMessage: 'Timelion request error',
+ }),
+ });
+ }
+ };
+}
diff --git a/src/legacy/plugin_discovery/types.ts b/src/legacy/plugin_discovery/types.ts
index 6d7c59893dfe6..c14daa37f5706 100644
--- a/src/legacy/plugin_discovery/types.ts
+++ b/src/legacy/plugin_discovery/types.ts
@@ -73,6 +73,7 @@ export interface LegacyPluginOptions {
visTypes: string[];
embeddableActions?: string[];
embeddableFactories?: string[];
+ uiSettingDefaults?: Record;
}>;
uiCapabilities?: Capabilities;
publicDir: any;
diff --git a/src/plugins/expressions/common/expressions/expression_types/kibana_context.ts b/src/plugins/expressions/common/expressions/expression_types/kibana_context.ts
index 92debafded76e..0c76e5e83a5ee 100644
--- a/src/plugins/expressions/common/expressions/expression_types/kibana_context.ts
+++ b/src/plugins/expressions/common/expressions/expression_types/kibana_context.ts
@@ -21,6 +21,7 @@ import { Filter } from '@kbn/es-query';
import { TimeRange, Query } from 'src/plugins/data/public';
const name = 'kibana_context';
+export type KIBANA_CONTEXT_NAME = 'kibana_context';
export interface KibanaContext {
type: typeof name;