Timelion: Move datemath parsing to the client (#47813)

This commit is contained in:
Joe Reuter 2019-10-22 11:47:33 +02:00 committed by GitHub
parent 65ab1dd403
commit 6c5c6ef5b3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 30 additions and 135 deletions

View file

@ -1,7 +1,6 @@
.kuiLocalTitle {
display: flex;
align-items: center;
height: 100%;
padding: ($localNavSideSpacing * 1.5) $localNavSideSpacing;
font-size: $kuiFontSize;
font-weight: bold;

View file

@ -407,9 +407,15 @@ app.controller('timelion', function (
$scope.state.save();
$scope.running = true;
// parse the time range client side to make sure it behaves like other charts
const timeRangeBounds = timefilter.getBounds();
const httpResult = $http.post('../api/timelion/run', {
sheet: $scope.state.sheet,
time: _.extend(timefilter.getTime(), {
time: _.extend({
from: timeRangeBounds.min,
to: timeRangeBounds.max,
}, {
interval: $scope.state.interval,
timezone: timezone
}),

View file

@ -21,11 +21,13 @@ import { PluginInitializerContext } from 'kibana/public';
import { npSetup, npStart } from 'ui/new_platform';
import { plugin } from '.';
import { setup as visualizations } from '../../visualizations/public/np_ready/public/legacy';
import { setup as data } from '../../data/public/legacy';
import { TimelionPluginSetupDependencies } from './plugin';
import { LegacyDependenciesPlugin } from './shim';
const setupPlugins: Readonly<TimelionPluginSetupDependencies> = {
visualizations,
data,
expressions: npSetup.plugins.expressions,
// Temporary solution

View file

@ -29,6 +29,8 @@ import { VisualizationsSetup } from '../../visualizations/public/np_ready/public
import { getTimelionVisualizationConfig } from './timelion_vis_fn';
import { getTimelionVisualization } from './vis';
import { getTimeChart } from './panels/timechart/timechart';
import { DataSetup } from '../../data/public';
import { TimefilterSetup } from '../../data/public/timefilter';
import { Panel } from './panels/panel';
import { LegacyDependenciesPlugin, LegacyDependenciesPluginSetup } from './shim';
@ -37,12 +39,14 @@ export interface TimelionVisualizationDependencies extends LegacyDependenciesPlu
uiSettings: UiSettingsClientContract;
http: HttpSetup;
timelionPanels: Map<string, Panel>;
timefilter: TimefilterSetup;
}
/** @internal */
export interface TimelionPluginSetupDependencies {
expressions: ReturnType<ExpressionsPlugin['setup']>;
visualizations: VisualizationsSetup;
data: DataSetup;
// Temporary solution
__LEGACY: LegacyDependenciesPlugin;
@ -58,13 +62,14 @@ export class TimelionPlugin implements Plugin<Promise<void>, void> {
public async setup(
core: CoreSetup,
{ __LEGACY, expressions, visualizations }: TimelionPluginSetupDependencies
{ __LEGACY, expressions, visualizations, data }: TimelionPluginSetupDependencies
) {
const timelionPanels: Map<string, Panel> = new Map();
const dependencies: TimelionVisualizationDependencies = {
uiSettings: core.uiSettings,
http: core.http,
timefilter: data.timefilter,
timelionPanels,
...(await __LEGACY.setup(core, timelionPanels)),
};

View file

@ -50,7 +50,7 @@ export interface TimelionSuccessResponse {
}
export function getTimelionRequestHandler(dependencies: TimelionVisualizationDependencies) {
const { uiSettings, http } = dependencies;
const { uiSettings, http, timefilter } = dependencies;
const timezone = timezoneProvider(uiSettings)();
return async function({
@ -77,6 +77,9 @@ export function getTimelionRequestHandler(dependencies: TimelionVisualizationDep
const esQueryConfigs = getEsQueryConfig(uiSettings);
// parse the time range client side to make sure it behaves like other charts
const timeRangeBounds = timefilter.timefilter.calculateBounds(timeRange);
try {
return await http.post('../api/timelion/run', {
body: JSON.stringify({
@ -86,7 +89,12 @@ export function getTimelionRequestHandler(dependencies: TimelionVisualizationDep
filter: buildEsQuery(undefined, query, filters, esQueryConfigs),
},
},
time: { ...timeRange, interval: visParams.interval, timezone },
time: {
from: timeRangeBounds.min,
to: timeRangeBounds.max,
interval: visParams.interval,
timezone,
},
}),
});
} catch (e) {

View file

@ -21,9 +21,9 @@
import _ from 'lodash';
import Bluebird from 'bluebird';
import { i18n } from '@kbn/i18n';
import moment from 'moment';
import parseSheet from './lib/parse_sheet.js';
import parseDateMath from '../lib/date_math.js';
import repositionArguments from './lib/reposition_arguments.js';
import indexArguments from './lib/index_arguments.js';
import validateTime from './lib/validate_time.js';
@ -191,8 +191,8 @@ export default function chainRunner(tlConfig) {
validateTime(request.time, tlConfig);
tlConfig.time = request.time;
tlConfig.time.to = parseDateMath(request.time.to, true).valueOf();
tlConfig.time.from = parseDateMath(request.time.from).valueOf();
tlConfig.time.to = moment(request.time.to).valueOf();
tlConfig.time.from = moment(request.time.from).valueOf();
tlConfig.time.interval = calculateInterval(
tlConfig.time.from,
tlConfig.time.to,

View file

@ -18,12 +18,12 @@
*/
import { i18n } from '@kbn/i18n';
import moment from 'moment';
import parseDateMath from '../../lib/date_math.js';
import toMS from '../../lib/to_milliseconds.js';
export default function validateTime(time, tlConfig) {
const span = parseDateMath(time.to, true) - parseDateMath(time.from);
const span = moment.duration(moment(time.to).diff(moment(time.from))).asMilliseconds();
const interval = toMS(time.interval);
const bucketCount = span / interval;
const maxBuckets = tlConfig.settings['timelion:max_buckets'];

View file

@ -1,123 +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 moment from 'moment';
const units = ['y', 'M', 'w', 'd', 'h', 'm', 's'];
/* This is a simplified version of elasticsearch's date parser */
export default function parse(text, roundUp) {
if (!text) {
return undefined;
}
if (moment.isMoment(text)) {
return text;
}
if (_.isDate(text)) {
return moment(text);
}
let time;
let mathString = '';
let index;
let parseString;
if (text.substring(0, 3) === 'now') {
time = moment();
mathString = text.substring('now'.length);
} else {
index = text.indexOf('||');
if (index === -1) {
parseString = text;
mathString = ''; // nothing else
} else {
parseString = text.substring(0, index);
mathString = text.substring(index + 2);
}
// We're going to just require ISO8601 timestamps, k?
time = moment(parseString);
}
if (!mathString.length) {
return time;
}
return parseDateMath(mathString, time, roundUp);
}
function parseDateMath(mathString, time, roundUp) {
const dateTime = time;
for (let i = 0; i < mathString.length;) {
const c = mathString.charAt(i++);
let type;
let num;
if (c === '/') {
type = 0;
} else if (c === '+') {
type = 1;
} else if (c === '-') {
type = 2;
} else {
return undefined;
}
if (isNaN(mathString.charAt(i))) {
num = 1;
} else if (mathString.length === 2) {
num = mathString.charAt(i);
} else {
const numFrom = i;
while (!isNaN(mathString.charAt(i))) {
i++;
if (i > 10) {
return undefined;
}
}
num = parseInt(mathString.substring(numFrom, i), 10);
}
if (type === 0) {
// rounding is only allowed on whole, single, units (eg M or 1M, not 0.5M or 2M)
if (num !== 1) {
return undefined;
}
}
const unit = mathString.charAt(i++);
if (!_.contains(units, unit)) {
return undefined;
} else {
if (type === 0) {
if (roundUp) {
dateTime.endOf(unit);
} else {
dateTime.startOf(unit);
}
} else if (type === 1) {
dateTime.add(num, unit);
} else if (type === 2) {
dateTime.subtract(num, unit);
}
}
}
return dateTime;
}

View file

@ -23,8 +23,6 @@ import fetch from 'node-fetch';
import moment from 'moment';
fetch.Promise = require('bluebird');
//var parseDateMath = require('../utils/date_math.js');
import Datasource from '../lib/classes/datasource';
export default new Datasource ('quandl', {