[Canvas] Misc NP Stuff (#63703)

* Timelion function -> np

* embeddable renderer -> np i18n context

* ui_metric -> np

* Fix timelion issue

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
Corey Robertson 2020-04-24 10:39:54 -04:00 committed by GitHub
parent 103a3cd11c
commit dfddcdd903
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 143 additions and 99 deletions

View file

@ -6,7 +6,6 @@
import React from 'react';
import ReactDOM from 'react-dom';
import { I18nContext } from 'ui/i18n';
import { CoreStart } from '../../../../../../../src/core/public';
import { StartDeps } from '../../plugin';
import {
@ -30,6 +29,8 @@ const embeddablesRegistry: {
} = {};
const renderEmbeddableFactory = (core: CoreStart, plugins: StartDeps) => {
const I18nContext = core.i18n.Context;
return (embeddableObject: IEmbeddable, domNode: HTMLElement) => {
return (
<div

View file

@ -5,12 +5,12 @@
*/
import { i18n } from '@kbn/i18n';
import { timelion } from '../../../public/functions/timelion';
import { timelionFunctionFactory } from '../../../public/functions/timelion';
import { FunctionHelp } from '../function_help';
import { FunctionFactory } from '../../../types';
import { ELASTICSEARCH, DATEMATH, MOMENTJS_TIMEZONE_URL } from '../../constants';
export const help: FunctionHelp<FunctionFactory<typeof timelion>> = {
export const help: FunctionHelp<FunctionFactory<ReturnType<typeof timelionFunctionFactory>>> = {
help: i18n.translate('xpack.canvas.functions.timelionHelpText', {
defaultMessage: 'Use Timelion to extract one or more timeseries from many sources.',
}),

View file

@ -30,6 +30,7 @@ import { VALUE_CLICK_TRIGGER, ActionByType } from '../../../../../src/plugins/ui
/* eslint-disable */
import { ACTION_VALUE_CLICK } from '../../../../../src/plugins/data/public/actions/value_click_action';
/* eslint-enable */
import { init as initStatsReporter } from './lib/ui_metric';
import { CapabilitiesStrings } from '../i18n';
const { ReadOnlyBadge: strings } = CapabilitiesStrings;
@ -121,6 +122,10 @@ export const initializeCanvas = async (
startPlugins.uiActions.attachAction(VALUE_CLICK_TRIGGER, emptyAction);
}
if (setupPlugins.usageCollection) {
initStatsReporter(setupPlugins.usageCollection.reportUiStats);
}
return canvasStore;
};

View file

@ -4,16 +4,23 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { ExpressionsSetup } from 'src/plugins/expressions/public';
import { asset } from './asset';
import { filtersFunctionFactory } from './filters';
import { timelion } from './timelion';
import { timelionFunctionFactory } from './timelion';
import { toFunctionFactory } from './to';
import { CanvasSetupDeps, CoreSetup } from '../plugin';
export interface InitializeArguments {
typesRegistry: ExpressionsSetup['__LEGACY']['types'];
prependBasePath: CoreSetup['http']['basePath']['prepend'];
typesRegistry: CanvasSetupDeps['expressions']['__LEGACY']['types'];
timefilter: CanvasSetupDeps['data']['query']['timefilter']['timefilter'];
}
export function initFunctions(initialize: InitializeArguments) {
return [asset, filtersFunctionFactory(initialize), timelion, toFunctionFactory(initialize)];
return [
asset,
filtersFunctionFactory(initialize),
timelionFunctionFactory(initialize),
toFunctionFactory(initialize),
];
}

View file

@ -6,8 +6,6 @@
import { flatten } from 'lodash';
import moment from 'moment-timezone';
import chrome from 'ui/chrome';
import { npStart } from 'ui/new_platform';
import { TimeRange } from 'src/plugins/data/common';
import { ExpressionFunctionDefinition, DatatableRow } from 'src/plugins/expressions/public';
import { fetch } from '../../common/lib/fetch';
@ -15,6 +13,7 @@ import { fetch } from '../../common/lib/fetch';
import { buildBoolArray } from '../../server/lib/build_bool_array';
import { Datatable, Filter } from '../../types';
import { getFunctionHelp } from '../../i18n';
import { InitializeArguments } from './';
interface Arguments {
query: string;
@ -30,13 +29,17 @@ interface Arguments {
* @param timeRange time range to parse
* @param timeZone time zone to do the parsing in
*/
function parseDateMath(timeRange: TimeRange, timeZone: string) {
function parseDateMath(
timeRange: TimeRange,
timeZone: string,
timefilter: InitializeArguments['timefilter']
) {
// the datemath plugin always parses dates by using the current default moment time zone.
// to use the configured time zone, we are switching just for the bounds calculation.
const defaultTimezone = moment().zoneName();
moment.tz.setDefault(timeZone);
const parsedRange = npStart.plugins.data.query.timefilter.timefilter.calculateBounds(timeRange);
const parsedRange = timefilter.calculateBounds(timeRange);
// reset default moment timezone
moment.tz.setDefault(defaultTimezone);
@ -44,96 +47,100 @@ function parseDateMath(timeRange: TimeRange, timeZone: string) {
return parsedRange;
}
export function timelion(): ExpressionFunctionDefinition<
type TimelionFunction = ExpressionFunctionDefinition<
'timelion',
Filter,
Arguments,
Promise<Datatable>
> {
const { help, args: argHelp } = getFunctionHelp().timelion;
>;
return {
name: 'timelion',
type: 'datatable',
inputTypes: ['filter'],
help,
args: {
query: {
types: ['string'],
aliases: ['_', 'q'],
help: argHelp.query,
default: '".es(*)"',
},
interval: {
types: ['string'],
help: argHelp.interval,
default: 'auto',
},
from: {
types: ['string'],
help: argHelp.from,
default: 'now-1y',
},
to: {
types: ['string'],
help: argHelp.to,
default: 'now',
},
timezone: {
types: ['string'],
help: argHelp.timezone,
default: 'UTC',
},
},
fn: (input, args): Promise<Datatable> => {
// Timelion requires a time range. Use the time range from the timefilter element in the
// workpad, if it exists. Otherwise fall back on the function args.
const timeFilter = input.and.find(and => and.type === 'time');
const range = timeFilter
? { min: timeFilter.from, max: timeFilter.to }
: parseDateMath({ from: args.from, to: args.to }, args.timezone);
export function timelionFunctionFactory(initialize: InitializeArguments): () => TimelionFunction {
return () => {
const { help, args: argHelp } = getFunctionHelp().timelion;
const body = {
extended: {
es: {
filter: {
bool: {
must: buildBoolArray(input.and),
return {
name: 'timelion',
type: 'datatable',
inputTypes: ['filter'],
help,
args: {
query: {
types: ['string'],
aliases: ['_', 'q'],
help: argHelp.query,
default: '".es(*)"',
},
interval: {
types: ['string'],
help: argHelp.interval,
default: 'auto',
},
from: {
types: ['string'],
help: argHelp.from,
default: 'now-1y',
},
to: {
types: ['string'],
help: argHelp.to,
default: 'now',
},
timezone: {
types: ['string'],
help: argHelp.timezone,
default: 'UTC',
},
},
fn: (input, args): Promise<Datatable> => {
// Timelion requires a time range. Use the time range from the timefilter element in the
// workpad, if it exists. Otherwise fall back on the function args.
const timeFilter = input.and.find(and => and.type === 'time');
const range = timeFilter
? { min: timeFilter.from, max: timeFilter.to }
: parseDateMath({ from: args.from, to: args.to }, args.timezone, initialize.timefilter);
const body = {
extended: {
es: {
filter: {
bool: {
must: buildBoolArray(input.and),
},
},
},
},
},
sheet: [args.query],
time: {
from: range.min,
to: range.max,
interval: args.interval,
timezone: args.timezone,
},
};
return fetch(chrome.addBasePath(`/api/timelion/run`), {
method: 'POST',
responseType: 'json',
data: body,
}).then(resp => {
const seriesList = resp.data.sheet[0].list;
const rows = flatten(
seriesList.map((series: { data: any[]; label: string }) =>
series.data.map(row => ({ '@timestamp': row[0], value: row[1], label: series.label }))
)
) as DatatableRow[];
return {
type: 'datatable',
columns: [
{ name: '@timestamp', type: 'date' },
{ name: 'value', type: 'number' },
{ name: 'label', type: 'string' },
],
rows,
sheet: [args.query],
time: {
from: range.min,
to: range.max,
interval: args.interval,
timezone: args.timezone,
},
};
});
},
return fetch(initialize.prependBasePath(`/api/timelion/run`), {
method: 'POST',
responseType: 'json',
data: body,
}).then(resp => {
const seriesList = resp.data.sheet[0].list;
const rows = flatten(
seriesList.map((series: { data: any[]; label: string }) =>
series.data.map(row => ({ '@timestamp': row[0], value: row[1], label: series.label }))
)
) as DatatableRow[];
return {
type: 'datatable',
columns: [
{ name: '@timestamp', type: 'date' },
{ name: 'value', type: 'number' },
{ name: 'label', type: 'string' },
],
rows,
};
});
},
};
};
}

View file

@ -21,8 +21,10 @@ const shimCoreStart = {
};
const shimSetupPlugins: CanvasSetupDeps = {
data: npSetup.plugins.data,
expressions: npSetup.plugins.expressions,
home: npSetup.plugins.home,
usageCollection: npSetup.plugins.usageCollection,
};
const shimStartPlugins: CanvasStartDeps = {
...npStart.plugins,

View file

@ -4,10 +4,21 @@
* you may not use this file except in compliance with the Elastic License.
*/
import {
createUiStatsReporter,
METRIC_TYPE,
} from '../../../../../../src/legacy/core_plugins/ui_metric/public';
import { UiStatsMetricType, METRIC_TYPE } from '@kbn/analytics';
import { UsageCollectionSetup } from 'src/plugins/usage_collection/public';
export const trackCanvasUiMetric = createUiStatsReporter('canvas');
export { METRIC_TYPE };
export let reportUiStats: UsageCollectionSetup['reportUiStats'] | undefined;
export function init(_reportUiStats: UsageCollectionSetup['reportUiStats']): void {
reportUiStats = _reportUiStats;
}
export function trackCanvasUiMetric(metricType: UiStatsMetricType, name: string | string[]) {
if (!reportUiStats) {
return;
}
reportUiStats('canvas', metricType, name);
}

View file

@ -10,8 +10,10 @@ import { HomePublicPluginSetup } from '../../../../../src/plugins/home/public';
import { initLoadingIndicator } from './lib/loading_indicator';
import { featureCatalogueEntry } from './feature_catalogue_entry';
import { ExpressionsSetup, ExpressionsStart } from '../../../../../src/plugins/expressions/public';
import { DataPublicPluginSetup } from '../../../../../src/plugins/data/public';
import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public';
import { EmbeddableStart } from '../../../../../src/plugins/embeddable/public';
import { UsageCollectionSetup } from '../../../../../src/plugins/usage_collection/public';
import { Start as InspectorStart } from '../../../../../src/plugins/inspector/public';
// @ts-ignore untyped local
import { argTypeSpecs } from './expression_types/arg_types';
@ -20,7 +22,7 @@ import { legacyRegistries } from './legacy_plugin_support';
import { getPluginApi, CanvasApi } from './plugin_api';
import { initFunctions } from './functions';
import { CanvasSrcPlugin } from '../canvas_plugin_src/plugin';
export { CoreStart };
export { CoreStart, CoreSetup };
/**
* These are the private interfaces for the services your plugin depends on.
@ -28,14 +30,17 @@ export { CoreStart };
*/
// This interface will be built out as we require other plugins for setup
export interface CanvasSetupDeps {
data: DataPublicPluginSetup;
expressions: ExpressionsSetup;
home: HomePublicPluginSetup;
usageCollection?: UsageCollectionSetup;
}
export interface CanvasStartDeps {
embeddable: EmbeddableStart;
expressions: ExpressionsStart;
inspector: InspectorStart;
uiActions: UiActionsStart;
__LEGACY: {
absoluteToParsedUrl: (url: string, basePath: string) => any;
@ -94,7 +99,13 @@ export class CanvasPlugin
canvasApi.addTypes(legacyRegistries.types.getOriginalFns());
// Register core canvas stuff
canvasApi.addFunctions(initFunctions({ typesRegistry: plugins.expressions.__LEGACY.types }));
canvasApi.addFunctions(
initFunctions({
timefilter: plugins.data.query.timefilter.timefilter,
prependBasePath: core.http.basePath.prepend,
typesRegistry: plugins.expressions.__LEGACY.types,
})
);
canvasApi.addArgumentUIs(argTypeSpecs);
canvasApi.addTransitions(transitions);