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) {