From 65e61a1e38d51e63aee022f97b89323c8be2a4e3 Mon Sep 17 00:00:00 2001 From: dej611 Date: Wed, 19 May 2021 17:39:21 +0200 Subject: [PATCH] :sparkles: Improve the signatures with better documentation and examples --- .../definitions/calculations/counter_rate.tsx | 4 + .../calculations/cumulative_sum.tsx | 4 + .../definitions/calculations/differences.tsx | 4 + .../calculations/moving_average.tsx | 11 +- .../operations/definitions/cardinality.tsx | 4 + .../operations/definitions/count.tsx | 3 + .../formula/editor/formula_help.tsx | 170 +++++++++++++--- .../formula/editor/math_completion.ts | 187 +++++++++--------- .../operations/definitions/formula/util.ts | 38 ++-- .../definitions/formula/validation.ts | 6 +- .../operations/definitions/index.ts | 5 + .../operations/definitions/last_value.tsx | 4 + .../operations/definitions/metrics.tsx | 23 +++ .../operations/definitions/percentile.tsx | 11 +- 14 files changed, 337 insertions(+), 137 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/counter_rate.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/counter_rate.tsx index fc9504f003198..cffd3a610987b 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/counter_rate.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/counter_rate.tsx @@ -47,6 +47,10 @@ export const counterRateOperation: OperationDefinition< defaultMessage: 'Counter rate', }), input: 'fullReference', + description: i18n.translate('xpack.lens.indexPattern.counterRate.description', { + defaultMessage: + 'An aggregation that calculates a rate of documents or a field in each date_histogram bucket.', + }), selectionStyle: 'field', requiredReferences: [ { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/cumulative_sum.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/cumulative_sum.tsx index 2adb9a1376f60..e2b9141accd5d 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/cumulative_sum.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/cumulative_sum.tsx @@ -45,6 +45,10 @@ export const cumulativeSumOperation: OperationDefinition< defaultMessage: 'Cumulative sum', }), input: 'fullReference', + description: i18n.translate('xpack.lens.indexPattern.cumulativeSum.description', { + defaultMessage: + 'An aggregation that calculates the cumulative sum of a specified field in each date_histogram bucket. Cumulative sums always start with 0.', + }), selectionStyle: 'field', requiredReferences: [ { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/differences.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/differences.tsx index 06555a9b41c2f..4e0b59cda6a0e 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/differences.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/differences.tsx @@ -49,6 +49,10 @@ export const derivativeOperation: OperationDefinition< defaultMessage: 'Differences', }), input: 'fullReference', + description: i18n.translate('xpack.lens.indexPattern.derivative.description', { + defaultMessage: + 'An aggregation that calculates the difference over numeric values of a specified field between each pair of date_histogram buckets. Derivative always start with an undefined value for the first bucket, and it requires a minimum of two buckets.', + }), selectionStyle: 'full', requiredReferences: [ { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/moving_average.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/moving_average.tsx index 8d18a2752fd7e..19ad66630dc63 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/moving_average.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/calculations/moving_average.tsx @@ -63,13 +63,22 @@ export const movingAverageOperation: OperationDefinition< }), input: 'fullReference', selectionStyle: 'full', + description: i18n.translate('xpack.lens.indexPattern.movingAverage.description', { + defaultMessage: + 'Given an ordered series of data, the aggregation will slide a window across the data and emit the average value of that window. The default window value is {defaultValue}', + values: { + defaultValue: WINDOW_DEFAULT_VALUE, + }, + }), requiredReferences: [ { input: ['field', 'managedReference'], validateMetadata: (meta) => meta.dataType === 'number' && !meta.isBucketed, }, ], - operationParams: [{ name: 'window', type: 'number', required: true }], + operationParams: [ + { name: 'window', type: 'number', required: false, defaultValue: WINDOW_DEFAULT_VALUE }, + ], getPossibleOperation: (indexPattern) => { if (hasDateField(indexPattern)) { return { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/cardinality.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/cardinality.tsx index e77357a6f441a..d4da7b350349f 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/cardinality.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/cardinality.tsx @@ -54,6 +54,10 @@ export const cardinalityOperation: OperationDefinition { if ( supportedTypes.has(type) && diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/count.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/count.tsx index fd474ea04a165..f79b04a6471e6 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/count.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/count.tsx @@ -33,6 +33,9 @@ export const countOperation: OperationDefinition getInvalidFieldMessage(layer.columns[columnId] as FieldBasedIndexPatternColumn, indexPattern), onFieldChange: (oldColumn, field) => { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/formula_help.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/formula_help.tsx index ef08b6d03a7b7..525abb78682a9 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/formula_help.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/formula_help.tsx @@ -14,14 +14,24 @@ import { EuiText, EuiSelectable, EuiSelectableOption, + EuiCode, + EuiSpacer, + EuiMarkdownFormat, + EuiTitle, } from '@elastic/eui'; import { Markdown } from '../../../../../../../../../src/plugins/kibana_react/public'; -import { GenericOperationDefinition, ParamEditorProps } from '../../index'; -import { IndexPattern } from '../../../../types'; import { tinymathFunctions } from '../util'; import { getPossibleFunctions } from './math_completion'; +import { hasFunctionFieldArgument } from '../validation'; -import { FormulaIndexPatternColumn } from '../formula'; +import type { + GenericOperationDefinition, + IndexPatternColumn, + OperationDefinition, + ParamEditorProps, +} from '../../index'; +import type { IndexPattern } from '../../../../types'; +import type { FormulaIndexPatternColumn } from '../formula'; function FormulaHelp({ indexPattern, @@ -41,7 +51,16 @@ function FormulaHelp({ .filter((key) => key in tinymathFunctions) .map((key) => ({ label: `${key}`, - description: , + description: ( + <> + +

{getFunctionSignatureLabel(key, operationDefinitionMap)}

+
+ + {tinymathFunctions[key].help.replace(/\n/g, '\n\n')} + + + ), checked: selectedFunction === key ? ('on' as const) : undefined, })) ); @@ -65,7 +84,9 @@ function FormulaHelp({ return ( <> - Formula reference + {i18n.translate('xpack.lens.formulaReference', { + defaultMessage: 'Formula reference', + })} @@ -149,36 +170,127 @@ Use the symbols +, -, /, and * to perform basic math. export const MemoizedFormulaHelp = React.memo(FormulaHelp); -// TODO: i18n this whole thing, or move examples into the operation definitions with i18n -function getHelpText( +export function getFunctionSignatureLabel( + name: string, + operationDefinitionMap: ParamEditorProps['operationDefinitionMap'], + firstParam?: { label: string | [number, number] } | null +): string { + if (tinymathFunctions[name]) { + return `${name}(${tinymathFunctions[name].positionalArguments + .map(({ name: argName, optional }) => `${argName}${optional ? '?' : ''}`) + .join(', ')})`; + } + if (operationDefinitionMap[name]) { + const def = operationDefinitionMap[name]; + if ('operationParams' in def && def.operationParams) { + return `${name}(${firstParam ? firstParam.label + ', ' : ''}${def.operationParams.map( + ({ name: argName, type, required }) => `${argName}${required ? '' : '?'}=${type}` + )})`; + } + return `${name}(${firstParam ? firstParam.label : ''})`; + } + return ''; +} + +function getFunctionArgumentsStringified( + params: Required< + OperationDefinition + >['operationParams'] +) { + return params + .map( + ({ name, type: argType, defaultValue = 5 }) => + `${name}=${argType === 'string' ? `"${defaultValue}"` : defaultValue}` + ) + .join(', '); +} + +/** + * Get an array of strings containing all possible information about a specific + * operation type: examples and infos. + */ +export function getHelpTextContent( type: string, operationDefinitionMap: ParamEditorProps['operationDefinitionMap'] -) { +): { description: string; examples: string[] } { const definition = operationDefinitionMap[type]; + const description: string = definition.description ?? ''; + // as for the time being just add examples text. + // Later will enrich with more information taken from the operation definitions. + const examples: string[] = []; - if (type === 'count') { - return ( - -

Example: count()

-
- ); + if (!hasFunctionFieldArgument(type)) { + // ideally this should have the same example automation as the operations below + examples.push(`${type}()`); + return { description, examples }; } + if (definition.input === 'field') { + const mandatoryArgs = definition.operationParams?.filter(({ required }) => required) || []; + if (mandatoryArgs.length === 0) { + examples.push(`${type}(bytes)`); + } + if (mandatoryArgs.length) { + const additionalArgs = getFunctionArgumentsStringified(mandatoryArgs); + examples.push(`${type}(bytes, ${additionalArgs})`); + } + if (definition.operationParams && mandatoryArgs.length !== definition.operationParams.length) { + const additionalArgs = getFunctionArgumentsStringified(definition.operationParams); + examples.push(`${type}(bytes, ${additionalArgs})`); + } + } + if (definition.input === 'fullReference') { + const mandatoryArgs = definition.operationParams?.filter(({ required }) => required) || []; + if (mandatoryArgs.length === 0) { + examples.push(`${type}(sum(bytes))`); + } + if (mandatoryArgs.length) { + const additionalArgs = getFunctionArgumentsStringified(mandatoryArgs); + examples.push(`${type}(sum(bytes), ${additionalArgs})`); + } + if (definition.operationParams && mandatoryArgs.length !== definition.operationParams.length) { + const additionalArgs = getFunctionArgumentsStringified(definition.operationParams); + examples.push(`${type}(sum(bytes), ${additionalArgs})`); + } + } + return { description, examples }; +} +function getHelpText( + type: string, + operationDefinitionMap: ParamEditorProps['operationDefinitionMap'] +) { + const { description, examples } = getHelpTextContent(type, operationDefinitionMap); + const def = operationDefinitionMap[type]; + const firstParam = hasFunctionFieldArgument(type) + ? { + label: def.input === 'field' ? 'field' : def.input === 'fullReference' ? 'function' : '', + } + : null; return ( - - {definition.input === 'field' ?

Example: {type}(bytes)

: null} - {definition.input === 'fullReference' && !('operationParams' in definition) ? ( -

Example: {type}(sum(bytes))

- ) : null} - - {'operationParams' in definition && definition.operationParams ? ( -

-

- Example: {type}(sum(bytes),{' '} - {definition.operationParams.map((p) => `${p.name}=5`).join(', ')}) -

-

- ) : null} -
+ <> + +

{getFunctionSignatureLabel(type, operationDefinitionMap, firstParam)}

+
+ + {description} + {examples.length ? ( + <> + +

+ + {i18n.translate('xpack.lens.formulaExamples', { + defaultMessage: 'Examples', + })} + +

+ {examples.map((example) => ( +

+ {example} +

+ ))} + + ) : null} +
+ ); } diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/math_completion.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/math_completion.ts index e8c16fe64651a..f73600faf4418 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/math_completion.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/editor/math_completion.ts @@ -6,6 +6,7 @@ */ import { uniq, startsWith } from 'lodash'; +import { i18n } from '@kbn/i18n'; import { monaco } from '@kbn/monaco'; import { parse, @@ -19,6 +20,8 @@ import { IndexPattern } from '../../../../types'; import { memoizedGetAvailableOperationsByMetadata } from '../../../operations'; import { tinymathFunctions, groupArgsByType } from '../util'; import type { GenericOperationDefinition } from '../..'; +import { getFunctionSignatureLabel, getHelpTextContent } from './formula_help'; +import { hasFunctionFieldArgument } from '../validation'; export enum SUGGESTION_TYPE { FIELD = 'field', @@ -212,7 +215,7 @@ function getArgumentSuggestions( return { list: [], type: SUGGESTION_TYPE.FIELD }; } - if (position > 0 || operation.type === 'count') { + if (position > 0 || !hasFunctionFieldArgument(operation.type)) { const { namedArguments } = groupArgsByType(ast.args); const list = []; if (operation.filterable) { @@ -357,7 +360,7 @@ export function getSuggestion( } else { const def = operationDefinitionMap[suggestion.label]; kind = monaco.languages.CompletionItemKind.Constant; - if (suggestion.label === 'count' && 'operationParams' in def) { + if (!hasFunctionFieldArgument(suggestion.label) && 'operationParams' in def) { label = `${label}(${def .operationParams!.map((p) => `${p.name}=${p.type}`) .join(', ')})`; @@ -413,6 +416,88 @@ export function getSuggestion( }; } +function getOperationTypeHelp( + name: string, + operationDefinitionMap: Record +) { + const { description, examples } = getHelpTextContent(name, operationDefinitionMap); + const descriptionInMarkdown = description.replace(/\n/g, '\n\n'); + const examplesInMarkdown = `**${i18n.translate('xpack.lens.formulaExampleMarkdown', { + defaultMessage: 'Examples', + })}** + + ${examples.map((example) => `\`${example}\``).join('\n\n')}`; + return { + value: `${descriptionInMarkdown}\n\n${examplesInMarkdown}`, + }; +} + +function getSignaturesForFunction( + name: string, + operationDefinitionMap: Record +) { + if (tinymathFunctions[name]) { + const stringify = getFunctionSignatureLabel(name, operationDefinitionMap); + const documentation = tinymathFunctions[name].help.replace(/\n/g, '\n\n'); + return [ + { + label: stringify, + documentation: { value: documentation }, + parameters: tinymathFunctions[name].positionalArguments.map((arg) => ({ + label: arg.name, + documentation: arg.optional + ? i18n.translate('xpack.lens.formula.optionalArgument', { + defaultMessage: 'Optional. Default value is {defaultValue}', + values: { + defaultValue: arg.defaultValue, + }, + }) + : '', + })), + }, + ]; + } + if (operationDefinitionMap[name]) { + const def = operationDefinitionMap[name]; + + const firstParam: monaco.languages.ParameterInformation | null = hasFunctionFieldArgument(name) + ? { + label: def.input === 'field' ? 'field' : def.input === 'fullReference' ? 'function' : '', + } + : null; + + const functionLabel = getFunctionSignatureLabel(name, operationDefinitionMap, firstParam); + const documentation = getOperationTypeHelp(name, operationDefinitionMap); + if ('operationParams' in def && def.operationParams) { + return [ + { + label: functionLabel, + parameters: [ + ...(firstParam ? [firstParam] : []), + ...def.operationParams.map((arg) => ({ + label: `${arg.name}=${arg.type}`, + documentation: arg.required + ? i18n.translate('xpack.lens.formula.requiredArgument', { + defaultMessage: 'Required', + }) + : '', + })), + ], + documentation, + }, + ]; + } + return [ + { + label: functionLabel, + parameters: firstParam ? [firstParam] : [], + documentation, + }, + ]; + } + return []; +} + export function getSignatureHelp( expression: string, position: number, @@ -429,73 +514,16 @@ export function getSignatureHelp( // reference equality is fine here because of the way the getInfo function works const index = tokenInfo.parent.args.findIndex((arg) => arg === tokenInfo.ast); - if (tinymathFunctions[name]) { - const stringify = `${name}(${tinymathFunctions[name].positionalArguments - .map((arg) => arg.name) - .join(', ')})`; + const signatures = getSignaturesForFunction(name, operationDefinitionMap); + if (signatures.length) { return { value: { - signatures: [ - { - label: stringify, - parameters: tinymathFunctions[name].positionalArguments.map((arg) => ({ - label: arg.name, - documentation: arg.optional ? 'Optional' : '', - })), - }, - ], + signatures, activeParameter: index, activeSignature: 0, }, dispose: () => {}, }; - } else if (operationDefinitionMap[name]) { - const def = operationDefinitionMap[name]; - - const firstParam: monaco.languages.ParameterInformation | null = - name !== 'count' - ? { - label: - def.input === 'field' ? 'field' : def.input === 'fullReference' ? 'function' : '', - } - : null; - if ('operationParams' in def) { - return { - value: { - signatures: [ - { - label: `${name}(${ - firstParam ? firstParam.label + ', ' : '' - }${def.operationParams!.map((arg) => `${arg.name}=${arg.type}`)})`, - parameters: [ - ...(firstParam ? [firstParam] : []), - ...def.operationParams!.map((arg) => ({ - label: `${arg.name}=${arg.type}`, - documentation: arg.required ? 'Required' : '', - })), - ], - }, - ], - activeParameter: index, - activeSignature: 0, - }, - dispose: () => {}, - }; - } else { - return { - value: { - signatures: [ - { - label: `${name}(${firstParam ? firstParam.label : ''})`, - parameters: firstParam ? [firstParam] : [], - }, - ], - activeParameter: index, - activeSignature: 0, - }, - dispose: () => {}, - }; - } } } } catch (e) { @@ -519,37 +547,10 @@ export function getHover( } const name = tokenInfo.ast.name; - - if (tinymathFunctions[name]) { - const stringify = `${name}(${tinymathFunctions[name].positionalArguments - .map((arg) => arg.name) - .join(', ')})`; - return { contents: [{ value: stringify }] }; - } else if (operationDefinitionMap[name]) { - const def = operationDefinitionMap[name]; - - const firstParam: monaco.languages.ParameterInformation | null = - name !== 'count' - ? { - label: - def.input === 'field' ? 'field' : def.input === 'fullReference' ? 'function' : '', - } - : null; - if ('operationParams' in def) { - return { - contents: [ - { - value: `${name}(${ - firstParam ? firstParam.label + ', ' : '' - }${def.operationParams!.map((arg) => `${arg.name}=${arg.type}`)})`, - }, - ], - }; - } else { - return { - contents: [{ value: `${name}(${firstParam ? firstParam.label : ''})` }], - }; - } + const signatures = getSignaturesForFunction(name, operationDefinitionMap); + if (signatures.length) { + const { label, documentation } = signatures[0]; + return { contents: [{ value: label }, documentation] }; } } catch (e) { // do nothing diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/util.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/util.ts index 5d9a8647eb7ab..076afb02a45f8 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/util.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/util.ts @@ -73,6 +73,7 @@ export const tinymathFunctions: Record< positionalArguments: Array<{ name: string; optional?: boolean; + defaultValue?: string | number; }>; // help: React.ReactElement; // Help is in Markdown format @@ -86,8 +87,12 @@ export const tinymathFunctions: Record< ], help: ` Also works with + symbol -Example: ${'`count() + sum(bytes)`'} -Example: ${'`add(count(), 5)`'} + +**Examples**: +\`\`\` +count() + sum(bytes) +add(count(), 5) +\`\`\` `, }, subtract: { @@ -117,7 +122,7 @@ Example: ${'`multiply(sum(bytes), 2)`'} ], help: ` Also works with ${'`/`'} symbol -Example: ${'`ceil(sum(bytes))`'} +Example: ${'`divide(sum(bytes), 2)`'} `, }, abs: { @@ -155,7 +160,7 @@ Example: ${'`ceil(sum(bytes))`'} ], help: ` Limits the value from a minimum to maximum -Example: ${'`ceil(sum(bytes))`'} +Example: ${'`clamp(sum(bytes), 1, 100)`'} `, }, cube: { @@ -164,7 +169,7 @@ Example: ${'`ceil(sum(bytes))`'} ], help: ` Limits the value from a minimum to maximum -Example: ${'`ceil(sum(bytes))`'} +Example: ${'`cube(sum(bytes))`'} `, }, exp: { @@ -172,7 +177,7 @@ Example: ${'`ceil(sum(bytes))`'} { name: i18n.translate('xpack.lens.formula.expression', { defaultMessage: 'expression' }) }, ], help: ` -Raises e to the nth power. +Raises *e* to the nth power. Example: ${'`exp(sum(bytes))`'} `, }, @@ -200,12 +205,17 @@ Example: ${'`floor(sum(bytes))`'} { name: i18n.translate('xpack.lens.formula.base', { defaultMessage: 'base' }), optional: true, + defaultValue: 'e', }, ], help: ` -Logarithm with optional base. The natural base e is used as default. -Example: ${'`log(sum(bytes))`'} -Example: ${'`log(sum(bytes), 2)`'} +Logarithm with optional base. The natural base *e* is used as default. + +**Examples**: +\`\`\` +log(sum(bytes)) +log(sum(bytes), 2) +\`\`\` `, }, // TODO: check if this is valid for Tinymath @@ -223,7 +233,6 @@ Example: ${'`log(sum(bytes), 2)`'} { name: i18n.translate('xpack.lens.formula.expression', { defaultMessage: 'expression' }) }, { name: i18n.translate('xpack.lens.formula.base', { defaultMessage: 'base' }), - optional: true, }, ], help: ` @@ -249,12 +258,17 @@ Example: ${'`pow(sum(bytes), 3)`'} { name: i18n.translate('xpack.lens.formula.decimals', { defaultMessage: 'decimals' }), optional: true, + defaultValue: 0, }, ], help: ` Rounds to a specific number of decimal places, default of 0 -Example: ${'`round(sum(bytes))`'} -Example: ${'`round(sum(bytes), 2)`'} + +**Examples**: +\`\`\` +round(sum(bytes)) +round(sum(bytes), 2) +\`\`\` `, }, sqrt: { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/validation.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/validation.ts index 1dfdbb2910e2a..fa73cb69b20f0 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/validation.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/formula/validation.ts @@ -606,7 +606,11 @@ export function validateParams( } export function shouldHaveFieldArgument(node: TinymathFunction) { - return !['count'].includes(node.name); + return hasFunctionFieldArgument(node.name); +} + +export function hasFunctionFieldArgument(type: string) { + return !['count'].includes(type); } export function isFirstArgumentValidType(arg: TinymathAST, type: TinymathNodeTypes['type']) { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts index 27982243f8c2b..04a600d7e6376 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/index.ts @@ -185,6 +185,10 @@ interface BaseOperationDefinitionProps { * Should be i18n-ified. */ displayName: string; + /** + * A short description of the operation, useful for help or documentation + */ + description?: string; /** * The default label is assigned by the editor */ @@ -273,6 +277,7 @@ interface OperationParam { name: string; type: string; required?: boolean; + defaultValue?: string | number; } interface FieldlessOperationDefinition { diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.tsx index 4632d262c441d..417420a08fe77 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.tsx @@ -98,6 +98,10 @@ export const lastValueOperation: OperationDefinition ofName(getSafeName(column.sourceField, indexPattern)), input: 'field', + description: i18n.translate('xpack.lens.indexPattern.lastValue.description', { + defaultMessage: + 'A single-value metric aggregation that returns the last value (based on time) of the provided field extracted from the aggregated documents.', + }), onFieldChange: (oldColumn, field) => { const newParams = { ...oldColumn.params }; diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx index 725ef93203a43..e4e60a1ba8738 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/metrics.tsx @@ -42,6 +42,7 @@ const supportedTypes = ['number', 'histogram']; function buildMetricOperation>({ type, displayName, + description, ofName, priority, optionalTimeScaling, @@ -51,6 +52,7 @@ function buildMetricOperation>({ ofName: (name: string) => string; priority?: number; optionalTimeScaling?: boolean; + description?: string; }) { const labelLookup = (name: string, column?: BaseIndexPatternColumn) => { const label = ofName(name); @@ -64,6 +66,7 @@ function buildMetricOperation>({ type, priority, displayName, + description, input: 'field', timeScalingMode: optionalTimeScaling ? 'optional' : undefined, getPossibleOperationForField: ({ aggregationRestrictions, aggregatable, type: fieldType }) => { @@ -144,6 +147,10 @@ export const minOperation = buildMetricOperation({ defaultMessage: 'Minimum of {name}', values: { name }, }), + description: i18n.translate('xpack.lens.indexPattern.min.description', { + defaultMessage: + 'A single-value metrics aggregation that returns the minimum value among the numeric values extracted from the aggregated documents.', + }), }); export const maxOperation = buildMetricOperation({ @@ -156,6 +163,10 @@ export const maxOperation = buildMetricOperation({ defaultMessage: 'Maximum of {name}', values: { name }, }), + description: i18n.translate('xpack.lens.indexPattern.max.description', { + defaultMessage: + 'A single-value metrics aggregation that returns the maximum value among the numeric values extracted from the aggregated documents.', + }), }); export const averageOperation = buildMetricOperation({ @@ -169,6 +180,10 @@ export const averageOperation = buildMetricOperation({ defaultMessage: 'Average of {name}', values: { name }, }), + description: i18n.translate('xpack.lens.indexPattern.avg.description', { + defaultMessage: + 'A single-value metric aggregation that computes the average of numeric values that are extracted from the aggregated documents', + }), }); export const sumOperation = buildMetricOperation({ @@ -183,6 +198,10 @@ export const sumOperation = buildMetricOperation({ values: { name }, }), optionalTimeScaling: true, + description: i18n.translate('xpack.lens.indexPattern.sum.description', { + defaultMessage: + 'A single-value metrics aggregation that sums up numeric values that are extracted from the aggregated documents.', + }), }); export const medianOperation = buildMetricOperation({ @@ -196,4 +215,8 @@ export const medianOperation = buildMetricOperation({ defaultMessage: 'Median of {name}', values: { name }, }), + description: i18n.translate('xpack.lens.indexPattern.median.description', { + defaultMessage: + 'A single-value metrics aggregation that computes the median value that are extracted from the aggregated documents.', + }), }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.tsx index 705a1f7172fff..52c9b2d76bab4 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.tsx @@ -52,7 +52,16 @@ export const percentileOperation: OperationDefinition { if (supportedFieldTypes.includes(fieldType) && aggregatable && !aggregationRestrictions) {