Skip to content

Commit

Permalink
[Timelion] Communicate the index pattern to the dashboard (#90623) (#…
Browse files Browse the repository at this point in the history
…91112)

* [Timelion] Communicate the index pattern to the dashboard

Closes #86418

* update types / limits.yml

* Update timelion_vis_type.tsx

* fix typo

* remove extra await

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
# Conflicts:
#	packages/kbn-optimizer/limits.yml
  • Loading branch information
alexwizp authored Feb 11, 2021
1 parent 240415e commit 7247e9f
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 61 deletions.
2 changes: 1 addition & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ snapshots.js
/src/core/lib/kbn_internal_native_observable
/src/legacy/plugin_discovery/plugin_pack/__tests__/fixtures/plugins/broken
/src/plugins/data/common/es_query/kuery/ast/_generated_/**
/src/plugins/vis_type_timelion/public/_generated_/**
/src/plugins/vis_type_timelion/common/_generated_/**
/x-pack/legacy/plugins/**/__tests__/fixtures/**
/x-pack/plugins/apm/e2e/tmp/*
/x-pack/plugins/canvas/canvas_plugin
Expand Down
2 changes: 1 addition & 1 deletion packages/kbn-optimizer/limits.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ pageLoadAssetSize:
visTypeMetric: 42790
visTypeTable: 95078
visTypeTagcloud: 37575
visTypeTimelion: 51933
visTypeTimelion: 68883
visTypeTimeseries: 155347
visTypeVega: 153861
visTypeVislib: 242982
Expand Down
50 changes: 50 additions & 0 deletions src/plugins/vis_type_timelion/common/parser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

// @ts-ignore
import { parse } from './_generated_/chain';

export interface ExpressionLocation {
min: number;
max: number;
}

interface ExpressionItem {
name: string;
function: string;
location: ExpressionLocation;
text: string;
type: string;
}

export interface TimelionExpressionArgument extends ExpressionItem {
value: {
location: ExpressionLocation;
type: string;
value: string;
text: string;
};
}

export interface TimelionExpressionFunction extends ExpressionItem {
arguments: TimelionExpressionArgument[];
}

export interface TimelionExpressionChain {
chain: TimelionExpressionFunction[];
type: 'chain';
}

export interface ParsedExpression {
args: TimelionExpressionArgument[];
functions: TimelionExpressionFunction[];
tree: TimelionExpressionChain[];
variables: Record<string, any>;
}

export const parseTimelionExpression = (input: string): ParsedExpression => parse(input);
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@
* Side Public License, v 1.
*/

import { get, startsWith } from 'lodash';
import { startsWith } from 'lodash';
import { i18n } from '@kbn/i18n';
import { monaco } from '@kbn/monaco';
import {
parseTimelionExpression,
ParsedExpression,
TimelionExpressionArgument,
ExpressionLocation,
} from '../../common/parser';

import { Parser } from 'pegjs';

// @ts-ignore
import { parse } from '../_generated_/chain';

import { ArgValueSuggestions, FunctionArg, Location } from '../helpers/arg_value_suggestions';
import { ArgValueSuggestions } from '../helpers/arg_value_suggestions';
import { ITimelionFunction, TimelionFunctionArgs } from '../../common/types';

export enum SUGGESTION_TYPE {
Expand All @@ -24,13 +25,13 @@ export enum SUGGESTION_TYPE {
FUNCTIONS = 'functions',
}

function inLocation(cursorPosition: number, location: Location) {
function inLocation(cursorPosition: number, location: ExpressionLocation) {
return cursorPosition >= location.min && cursorPosition <= location.max;
}

function getArgumentsHelp(
functionHelp: ITimelionFunction | undefined,
functionArgs: FunctionArg[] = []
functionArgs: TimelionExpressionArgument[] = []
) {
if (!functionHelp) {
return [];
Expand All @@ -45,14 +46,12 @@ function getArgumentsHelp(
}

async function extractSuggestionsFromParsedResult(
result: ReturnType<Parser['parse']>,
result: ParsedExpression,
cursorPosition: number,
functionList: ITimelionFunction[],
argValueSuggestions: ArgValueSuggestions
) {
const activeFunc = result.functions.find(({ location }: { location: Location }) =>
inLocation(cursorPosition, location)
);
const activeFunc = result.functions.find(({ location }) => inLocation(cursorPosition, location));

if (!activeFunc) {
return;
Expand All @@ -72,7 +71,7 @@ async function extractSuggestionsFromParsedResult(
}

// return argument value suggestions when cursor is inside argument value
const activeArg = activeFunc.arguments.find((argument: FunctionArg) => {
const activeArg = activeFunc.arguments.find((argument) => {
return inLocation(cursorPosition, argument.location);
});
if (
Expand Down Expand Up @@ -112,7 +111,7 @@ async function extractSuggestionsFromParsedResult(
// return argument suggestions
const argsHelp = getArgumentsHelp(functionHelp, activeFunc.arguments);
const argumentSuggestions = argsHelp.filter((arg) => {
if (get(activeArg, 'type') === 'namedArg') {
if (activeArg?.type === 'namedArg') {
return startsWith(arg.name, activeArg.name);
} else if (activeArg) {
return startsWith(arg.name, activeArg.text);
Expand All @@ -129,7 +128,7 @@ export async function suggest(
argValueSuggestions: ArgValueSuggestions
) {
try {
const result = await parse(expression);
const result = parseTimelionExpression(expression);

return await extractSuggestionsFromParsedResult(
result,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,37 +9,19 @@
import { get } from 'lodash';
import { getIndexPatterns } from './plugin_services';
import { TimelionFunctionArgs } from '../../common/types';
import { TimelionExpressionFunction, TimelionExpressionArgument } from '../../common/parser';
import {
IndexPatternField,
indexPatterns as indexPatternsUtils,
KBN_FIELD_TYPES,
} from '../../../data/public';

export interface Location {
min: number;
max: number;
}

export interface FunctionArg {
function: string;
location: Location;
name: string;
text: string;
type: string;
value: {
location: Location;
text: string;
type: string;
value: string;
};
}

const isRuntimeField = (field: IndexPatternField) => Boolean(field.runtimeField);

export function getArgValueSuggestions() {
const indexPatterns = getIndexPatterns();

async function getIndexPattern(functionArgs: FunctionArg[]) {
async function getIndexPattern(functionArgs: TimelionExpressionFunction[]) {
const indexPatternArg = functionArgs.find(({ name }) => name === 'index');
if (!indexPatternArg) {
// index argument not provided
Expand All @@ -61,7 +43,7 @@ export function getArgValueSuggestions() {

// Argument value suggestion handlers requiring custom client side code
// Could not put with function definition since functions are defined on server
const customHandlers = {
const customHandlers: Record<string, any> = {
es: {
async index(partial: string) {
const search = partial ? `${partial}*` : '*';
Expand All @@ -71,7 +53,7 @@ export function getArgValueSuggestions() {
name: title,
}));
},
async metric(partial: string, functionArgs: FunctionArg[]) {
async metric(partial: string, functionArgs: TimelionExpressionFunction[]) {
if (!partial || !partial.includes(':')) {
return [
{ name: 'avg:' },
Expand Down Expand Up @@ -101,7 +83,7 @@ export function getArgValueSuggestions() {
)
.map((field) => ({ name: `${valueSplit[0]}:${field.name}`, help: field.type }));
},
async split(partial: string, functionArgs: FunctionArg[]) {
async split(partial: string, functionArgs: TimelionExpressionFunction[]) {
const indexPattern = await getIndexPattern(functionArgs);
if (!indexPattern) {
return [];
Expand All @@ -125,7 +107,7 @@ export function getArgValueSuggestions() {
)
.map((field) => ({ name: field.name, help: field.type }));
},
async timefield(partial: string, functionArgs: FunctionArg[]) {
async timefield(partial: string, functionArgs: TimelionExpressionFunction[]) {
const indexPattern = await getIndexPattern(functionArgs);
if (!indexPattern) {
return [];
Expand All @@ -150,10 +132,7 @@ export function getArgValueSuggestions() {
* @param {string} argName - user provided argument name
* @return {boolean} true when dynamic suggestion handler provided for function argument
*/
hasDynamicSuggestionsForArgument: <T extends keyof typeof customHandlers>(
functionName: T,
argName: keyof typeof customHandlers[T]
) => {
hasDynamicSuggestionsForArgument: (functionName: string, argName: string) => {
return customHandlers[functionName] && customHandlers[functionName][argName];
},

Expand All @@ -164,10 +143,10 @@ export function getArgValueSuggestions() {
* @param {string} partial - user provided argument value
* @return {array} array of dynamic suggestions matching partial
*/
getDynamicSuggestionsForArgument: async <T extends keyof typeof customHandlers>(
functionName: T,
argName: keyof typeof customHandlers[T],
functionArgs: FunctionArg[],
getDynamicSuggestionsForArgument: async (
functionName: string,
argName: string,
functionArgs: TimelionExpressionArgument[],
partialInput = ''
) => {
// @ts-ignore
Expand Down
20 changes: 19 additions & 1 deletion src/plugins/vis_type_timelion/public/timelion_vis_type.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ import { DefaultEditorSize } from '../../vis_default_editor/public';
import { TimelionOptionsProps } from './timelion_options';
import { TimelionVisDependencies } from './plugin';
import { toExpressionAst } from './to_ast';
import { getIndexPatterns } from './helpers/plugin_services';

import { VIS_EVENT_TO_TRIGGER } from '../../visualizations/public';
import { parseTimelionExpression } from '../common/parser';

import { VIS_EVENT_TO_TRIGGER, VisParams } from '../../visualizations/public';

const TimelionOptions = lazy(() => import('./timelion_options'));

Expand Down Expand Up @@ -47,6 +50,21 @@ export function getTimelionVisDefinition(dependencies: TimelionVisDependencies)
getSupportedTriggers: () => {
return [VIS_EVENT_TO_TRIGGER.applyFilter];
},
getUsedIndexPattern: (params: VisParams) => {
try {
const args = parseTimelionExpression(params.expression)?.args ?? [];
const indexArg = args.find(
({ type, name, function: fn }) => type === 'namedArg' && fn === 'es' && name === 'index'
);

if (indexArg?.value.text) {
return getIndexPatterns().find(indexArg.value.text);
}
} catch {
// timelion expression is invalid
}
return [];
},
options: {
showIndexSelection: false,
showQueryBar: false,
Expand Down
11 changes: 3 additions & 8 deletions src/plugins/vis_type_timelion/server/handlers/lib/parse_sheet.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,12 @@
*/

import { i18n } from '@kbn/i18n';
import fs from 'fs';
import path from 'path';
import _ from 'lodash';
const grammar = fs.readFileSync(path.resolve(__dirname, '../../../common/chain.peg'), 'utf8');
import PEG from 'pegjs';
const Parser = PEG.generate(grammar);
import { parseTimelionExpression } from '../../../common/parser';

export default function parseSheet(sheet) {
return _.map(sheet, function (plot) {
return sheet.map(function (plot) {
try {
return Parser.parse(plot).tree;
return parseTimelionExpression(plot).tree;
} catch (e) {
if (e.expected) {
throw new Error(
Expand Down
4 changes: 2 additions & 2 deletions tasks/config/peg.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ module.exports = {
},
},
timelion_chain: {
src: 'src/plugins/vis_type_timelion/public/chain.peg',
dest: 'src/plugins/vis_type_timelion/public/_generated_/chain.js',
src: 'src/plugins/vis_type_timelion/common/chain.peg',
dest: 'src/plugins/vis_type_timelion/common/_generated_/chain.js',
},
};

0 comments on commit 7247e9f

Please sign in to comment.