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 4de7060d18191..8dec6c17caa3d 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 @@ -129,11 +129,10 @@ Calculates the rate of an ever increasing counter. This function will only yield If the value does get smaller, it will interpret this as a counter reset. To get most precise results, \`counter_rate\` should be calculated on the \`max\` of a field. This calculation will be done separately for separate series defined by filters or top values dimensions. +It uses the current interval when used in Formula. Example: Visualize the rate of bytes received over time by a memcached server: -\`\`\` -counter_rate(max(memcached.stats.read.bytes)) -\`\`\` +${'`counter_rate(max(memcached.stats.read.bytes))`'} `, }), }, 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 06e613b62716e..230899143e154 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 @@ -123,9 +123,7 @@ Calculates the cumulative sum of a metric over time, adding all previous values This calculation will be done separately for separate series defined by filters or top values dimensions. Example: Visualize the received bytes accumulated over time: -\`\`\` -cumulative_sum(sum(bytes)) -\`\`\` +${'`cumulative_sum(sum(bytes))`'} `, }), }, 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 7511489bfd10a..5c757bd22b36b 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 @@ -121,9 +121,7 @@ Differences requires the data to be sequential. If your data is empty when using This calculation will be done separately for separate series defined by filters or top values dimensions. Example: Visualize the change in bytes received over time: -\`\`\` -differences(sum(bytes)) -\`\`\` +${'`differences(sum(bytes))`'} `, }), }, 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 0457286545aa5..a5948b6a854be 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 @@ -150,9 +150,7 @@ This calculation will be done separately for separate series defined by filters Takes a named parameter \`window\` which specifies how many last values to include in the average calculation for the current value. Example: Smooth a line of measurements: -\`\`\` -moving_average(sum(bytes), window=5) -\`\`\` +${'`moving_average(sum(bytes), window=5)`'} `, values: { defaultValue: WINDOW_DEFAULT_VALUE, 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 d9ea7926f9ace..e40cb6cb0d7c0 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 @@ -112,21 +112,17 @@ export const cardinalityOperation: OperationDefinition { + return getPossibleFunctions(indexPattern) + .filter((key) => key in tinymathFunctions) + .sort() + .map((key) => { + const [description, examples] = tinymathFunctions[key].help.split(`\`\`\``); + return { + label: key, + description: description.replace(/\n/g, '\n\n'), + examples: examples ? `\`\`\`${examples}\`\`\`` : '', + }; + }); + }, [indexPattern]); + const helpGroups: Array<{ label: string; description?: JSX.Element; @@ -72,22 +85,19 @@ function FormulaHelp({ }); helpGroups[0].items.push( - ...getPossibleFunctions(indexPattern) - .filter((key) => key in tinymathFunctions) - .sort() - .map((key) => ({ - label: `${key}`, + ...tinymathFns.map(({ label, description, examples }) => { + return { + label, description: ( <> -

{getFunctionSignatureLabel(key, operationDefinitionMap)}

+

{getFunctionSignatureLabel(label, operationDefinitionMap)}

- - {tinymathFunctions[key].help.replace(/\n/g, '\n\n')} - + {`${description}${examples}`} ), - })) + }; + }) ); helpGroups.push({ @@ -105,9 +115,11 @@ function FormulaHelp({ items: [], }); + const availableFunctions = getPossibleFunctions(indexPattern); + // Es aggs helpGroups[1].items.push( - ...getPossibleFunctions(indexPattern) + ...availableFunctions .filter( (key) => key in operationDefinitionMap && @@ -123,7 +135,11 @@ function FormulaHelp({ {key}({operationDefinitionMap[key].documentation?.signature}) - + {operationDefinitionMap[key].documentation?.description ? ( + + {operationDefinitionMap[key].documentation!.description} + + ) : null} ), })) @@ -146,7 +162,7 @@ function FormulaHelp({ // Calculations aggs helpGroups[2].items.push( - ...getPossibleFunctions(indexPattern) + ...availableFunctions .filter( (key) => key in operationDefinitionMap && @@ -162,7 +178,11 @@ function FormulaHelp({ {key}({operationDefinitionMap[key].documentation?.signature}) - + {operationDefinitionMap[key].documentation?.description ? ( + + {operationDefinitionMap[key].documentation!.description} + + ) : null} ), checked: @@ -219,10 +239,9 @@ function FormulaHelp({ - - + {i18n.translate('xpack.lens.formulaDocumentation', { + defaultMessage: ` ## How it works Lens formulas let you do math using a combination of Elasticsearch aggregations and @@ -255,45 +274,46 @@ Math functions can take positional arguments, like pow(count(), 3) is the same a Use the symbols +, -, /, and * to perform basic math. `, - description: - 'Text is in markdown. Do not translate function names or field names like sum(bytes)', - })} - /> - - {helpGroups.map((helpGroup, index) => { - return ( -
{ - if (el) { - scrollTargets.current[helpGroup.label] = el; - } - }} - > -

{helpGroup.label}

+ description: + 'Text is in markdown. Do not translate function names or field names like sum(bytes)', + })} + - {helpGroup.description} + {helpGroups.map((helpGroup, index) => { + return ( +
{ + if (el) { + scrollTargets.current[helpGroup.label] = el; + } + }} + > + +

{helpGroup.label}

+
- {helpGroups[index].items.map((helpItem) => { - return ( -
{ - if (el) { - scrollTargets.current[helpItem.label] = el; - } - }} - > - {helpItem.description} -
- ); - })} -
- ); - })} - + {helpGroup.description} + + {helpGroups[index].items.map((helpItem) => { + return ( +
{ + if (el) { + scrollTargets.current[helpItem.label] = el; + } + }} + > + {helpItem.description} +
+ ); + })} +
+ ); + })}
@@ -314,7 +334,14 @@ export function getFunctionSignatureLabel( } if (operationDefinitionMap[name]) { const def = operationDefinitionMap[name]; - return `${name}(${def.documentation?.signature})`; // ${firstParam ? firstParam.label : ''})`; + let extraArgs = ''; + if (def.filterable) { + extraArgs += hasFunctionFieldArgument(name) || 'operationParams' in def ? ',' : ''; + extraArgs += i18n.translate('xpack.lens.formula.kqlExtraArguments', { + defaultMessage: '[kql]?: string, [lucene]?: string', + }); + } + return `${name}(${def.documentation?.signature}${extraArgs})`; } return ''; } @@ -339,45 +366,53 @@ function getFunctionArgumentsStringified( export function getHelpTextContent( type: string, operationDefinitionMap: ParamEditorProps['operationDefinitionMap'] -): { description: JSX.Element | string; examples: string[] } { +): { description: string; examples: string[] } { const definition = operationDefinitionMap[type]; const description = definition.documentation?.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 (!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 the description already contain examples skip it + if (!/Example/.test(description)) { + if (!hasFunctionFieldArgument(type)) { + // ideally this should have the same example automation as the operations below + examples.push(`${type}()`); + return { description, examples }; } - if (mandatoryArgs.length) { - const additionalArgs = getFunctionArgumentsStringified(mandatoryArgs); - examples.push(`${type}(sum(bytes), ${additionalArgs})`); + 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.operationParams && mandatoryArgs.length !== definition.operationParams.length) { - const additionalArgs = getFunctionArgumentsStringified(definition.operationParams); - examples.push(`${type}(sum(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 }; 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 49fc9a06725f2..e76a53b49a7f2 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 @@ -276,8 +276,11 @@ function getArgumentSuggestions( ) { possibleOperationNames.push( ...a.operations - .filter((o) => - operation.requiredReferences.some((requirement) => requirement.input.includes(o.type)) + .filter( + (o) => + operation.requiredReferences.some((requirement) => + requirement.input.includes(o.type) + ) && !o.hidden ) .map((o) => o.operationType) ); @@ -350,27 +353,13 @@ export function getSuggestion( insertTextRules = monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet; if (typeof suggestion !== 'string') { if ('text' in suggestion) break; + label = getFunctionSignatureLabel(suggestion.label, operationDefinitionMap); const tinymathFunction = tinymathFunctions[suggestion.label]; if (tinymathFunction) { - label = `${label}(${tinymathFunction.positionalArguments - .map(({ name }) => name) - .join(', ')})`; detail = 'TinyMath'; kind = monaco.languages.CompletionItemKind.Method; } else { - const def = operationDefinitionMap[suggestion.label]; kind = monaco.languages.CompletionItemKind.Constant; - if (!hasFunctionFieldArgument(suggestion.label) && 'operationParams' in def) { - label = `${label}(${def - .operationParams!.map((p) => `${p.name}=${p.type}`) - .join(', ')})`; - } else if ('operationParams' in def) { - label = `${label}(expression, ${def - .operationParams!.map((p) => `${p.name}=${p.type}`) - .join(', ')})`; - } else { - label = `${label}(expression)`; - } detail = 'Elasticsearch'; // Always put ES functions first sortText = `0${label}`; @@ -420,16 +409,19 @@ function getOperationTypeHelp( name: string, operationDefinitionMap: Record ) { - const { description, examples } = getHelpTextContent(name, operationDefinitionMap); - // const descriptionInMarkdown = description.replace(/\n/g, '\n\n'); - const descriptionInMarkdown = description; - const examplesInMarkdown = `**${i18n.translate('xpack.lens.formulaExampleMarkdown', { - defaultMessage: 'Examples', - })}** - - ${examples.map((example) => `\`${example}\``).join('\n\n')}`; + const { description: descriptionInMarkdown, examples } = getHelpTextContent( + name, + operationDefinitionMap + ); + const examplesInMarkdown = examples.length + ? `\n\n**${i18n.translate('xpack.lens.formulaExampleMarkdown', { + defaultMessage: 'Examples', + })}** + + ${examples.map((example) => `\`${example}\``).join('\n\n')}` + : ''; return { - value: `${descriptionInMarkdown}\n\n${examplesInMarkdown}`, + value: `${descriptionInMarkdown}${examplesInMarkdown}`, }; } @@ -519,7 +511,12 @@ export function getSignatureHelp( if (signatures.length) { return { value: { - signatures, + // remove the documentation + signatures: signatures.map(({ documentation, ...signature }) => ({ + ...signature, + // extract only the first section (usually few lines) + documentation: { value: documentation.value.split('\n\n')[0] }, + })), activeParameter: index, activeSignature: 0, }, 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 bcbdbc53f0a77..179d10dfbab93 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 @@ -130,9 +130,7 @@ Subtracts the first number from the second number. Also works with ${'`-`'} symbol Example: Calculate the range of a field -\`\`\` -subtract(max(bytes), min(bytes)) -\`\`\` +${'`subtract(max(bytes), min(bytes))`'} `, }, multiply: { @@ -151,14 +149,10 @@ Multiplies two numbers. Also works with ${'`*`'} symbol. Example: Calculate price after current tax rate -\`\`\` -sum(bytes) * last_value(tax_rate) -\`\`\` +${'`sum(bytes) * last_value(tax_rate)`'} Example: Calculate price after constant tax rate -\`\`\` -multiply(sum(price), 1.2) -\`\`\` +${'`multiply(sum(price), 1.2)`'} `, }, divide: { @@ -177,9 +171,7 @@ Divides the first number by the second number. Also works with ${'`/`'} symbol Example: Calculate profit margin -\`\`\` -sum(profit) / sum(revenue) -\`\`\` +${'`sum(profit) / sum(revenue)`'} Example: ${'`divide(sum(bytes), 2)`'} `, @@ -208,9 +200,7 @@ Example: Calculate average distance to sea level ${'`abs(average(altitude))`'} Cube root of value. Example: Calculate side length from volume -\`\`\` -cbrt(last_value(volume)) -\`\`\` +${'`cbrt(last_value(volume))`'} `, }, ceil: { @@ -225,9 +215,7 @@ cbrt(last_value(volume)) Ceiling of value, rounds up. Example: Round up price to the next dollar -\`\`\` -ceil(sum(price)) -\`\`\` +${'`ceil(sum(price))`'} `, }, clamp: { @@ -270,9 +258,7 @@ clamp( Calculates the cube of a number. Example: Calculate volume from side length -\`\`\` -cube(last_value(length)) -\`\`\` +${'`cube(last_value(length))`'} `, }, exp: { @@ -301,9 +287,7 @@ ${'`exp(last_value(duration))`'} For positive values, takes the floor. For negative values, takes the ceiling. Example: Rounding towards zero -\`\`\` -fix(sum(profit)) -\`\`\` +${'`fix(sum(profit))`'} `, }, floor: { @@ -317,9 +301,7 @@ fix(sum(profit)) Round down to nearest integer value Example: Round down a price -\`\`\` -floor(sum(price)) -\`\`\` +${'`floor(sum(price))`'} `, }, log: { @@ -370,9 +352,7 @@ log(sum(bytes), 2) Remainder after dividing the function by a number Example: Calculate last three digits of a value -\`\`\` -mod(sum(price), 1000) -\`\`\` +${'`mod(sum(price), 1000)`'} `, }, pow: { @@ -390,9 +370,7 @@ mod(sum(price), 1000) Raises the value to a certain power. The second argument is required Example: Calculate volume based on side length -\`\`\` -pow(last_value(length), 3) -\`\`\` +${'`pow(last_value(length), 3)`'} `, }, round: { @@ -429,9 +407,7 @@ round(sum(bytes), 2) Square root of a positive value only Example: Calculate side length based on area -\`\`\` -sqrt(last_value(area)) -\`\`\` +${'`sqrt(last_value(area))`'} `, }, square: { @@ -445,9 +421,7 @@ sqrt(last_value(area)) Raise the value to the 2nd power Example: Calculate area based on side length -\`\`\` -square(last_value(length)) -\`\`\` +${'`square(last_value(length))`'} `, }, }; 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 97ed6eaf50b69..908dcf8e2bbe6 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 @@ -268,7 +268,7 @@ export const lastValueOperation: OperationDefinition>({ documentation: { section: 'elasticsearch', signature: i18n.translate('xpack.lens.indexPattern.metric.signature', { - defaultMessage: 'field: string, [kql]?: string, [lucene]?: string', + defaultMessage: 'field: string', }), description: i18n.translate('xpack.lens.indexPattern.metric.documentation', { defaultMessage: ` Returns the {metric} of a field. This function only works for number fields. Example: Get the {metric} of price: -\`\`\` -{metric}(price) -\`\`\` +${'`{metric}(price)`'} Example: Get the {metric} of price for orders from the UK: -\`\`\` -{metric}(price, kql="location:UK") -\`\`\` +${"`{metric}(price, kql='location:UK')`"} `, values: { metric: type, 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 6afc9f2f53abb..2ce8818853943 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 @@ -198,16 +198,14 @@ export const percentileOperation: OperationDefinition