diff --git a/src/platform/packages/private/kbn-esql-editor/src/esql_editor.tsx b/src/platform/packages/private/kbn-esql-editor/src/esql_editor.tsx index b5f075fb2f095..6cbef7086fa76 100644 --- a/src/platform/packages/private/kbn-esql-editor/src/esql_editor.tsx +++ b/src/platform/packages/private/kbn-esql-editor/src/esql_editor.tsx @@ -406,7 +406,16 @@ export const ESQLEditor = memo(function ESQLEditor({ const { cache: esqlFieldsCache, memoizedFieldsFromESQL } = useMemo(() => { // need to store the timing of the first request so we can atomically clear the cache per query const fn = memoize( - (...args: [{ esql: string }, ExpressionsStart, TimeRange, AbortController?]) => ({ + ( + ...args: [ + { esql: string }, + ExpressionsStart, + TimeRange, + AbortController?, + string?, + ESQLControlVariable[]? + ] + ) => ({ timestamp: Date.now(), result: fetchFieldsFromESQL(...args), }), @@ -446,7 +455,9 @@ export const ESQLEditor = memo(function ESQLEditor({ esqlQuery, expressions, timeRange, - abortController + abortController, + undefined, + esqlVariables ).result; const columns: ESQLRealField[] = table?.columns.map((c) => { @@ -478,8 +489,8 @@ export const ESQLEditor = memo(function ESQLEditor({ }, // @ts-expect-error To prevent circular type import, type defined here is partial of full client getFieldsMetadata: fieldsMetadata?.getClient(), - getVariablesByType: (type: ESQLVariableType) => { - return variablesService?.esqlVariables.filter((variable) => variable.type === type); + getVariables: () => { + return variablesService?.esqlVariables; }, canSuggestVariables: () => { return variablesService?.areSuggestionsEnabled ?? false; @@ -489,6 +500,7 @@ export const ESQLEditor = memo(function ESQLEditor({ return callbacks; }, [ fieldsMetadata, + esqlVariables, kibana.services?.esql?.getJoinIndicesAutocomplete, dataSourcesCache, query.esql, diff --git a/src/platform/packages/private/kbn-esql-editor/src/fetch_fields_from_esql.ts b/src/platform/packages/private/kbn-esql-editor/src/fetch_fields_from_esql.ts index 9098ef2bd9edd..6899eef1cbc91 100644 --- a/src/platform/packages/private/kbn-esql-editor/src/fetch_fields_from_esql.ts +++ b/src/platform/packages/private/kbn-esql-editor/src/fetch_fields_from_esql.ts @@ -11,6 +11,7 @@ import { pluck } from 'rxjs'; import { lastValueFrom } from 'rxjs'; import { Query, AggregateQuery, TimeRange } from '@kbn/es-query'; import type { ExpressionsStart } from '@kbn/expressions-plugin/public'; +import type { ESQLControlVariable } from '@kbn/esql-types'; import type { Datatable } from '@kbn/expressions-plugin/public'; import { textBasedQueryStateToAstWithValidation } from '@kbn/data-plugin/common'; @@ -26,7 +27,8 @@ export function fetchFieldsFromESQL( expressions: ExpressionsStart, time?: TimeRange, abortController?: AbortController, - timeFieldName?: string + timeFieldName?: string, + esqlVariables?: ESQLControlVariable[] ) { return textBasedQueryStateToAstWithValidation({ query, @@ -38,6 +40,7 @@ export function fetchFieldsFromESQL( const executionContract = expressions.execute(ast, null, { searchContext: { timeRange: time, + esqlVariables, }, }); diff --git a/src/platform/packages/shared/kbn-esql-ast/index.ts b/src/platform/packages/shared/kbn-esql-ast/index.ts index e98e025fef3b9..1e9271fadd11d 100644 --- a/src/platform/packages/shared/kbn-esql-ast/index.ts +++ b/src/platform/packages/shared/kbn-esql-ast/index.ts @@ -60,7 +60,7 @@ export { ESQLErrorListener, } from './src/parser'; -export { Walker, type WalkerOptions, walk } from './src/walker'; +export { Walker, type WalkerOptions, walk, type WalkerAstNode } from './src/walker'; export * as synth from './src/synth'; export { diff --git a/src/platform/packages/shared/kbn-esql-ast/src/walker/index.ts b/src/platform/packages/shared/kbn-esql-ast/src/walker/index.ts index 71212257c6771..0135a3aa11fdc 100644 --- a/src/platform/packages/shared/kbn-esql-ast/src/walker/index.ts +++ b/src/platform/packages/shared/kbn-esql-ast/src/walker/index.ts @@ -7,4 +7,4 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -export { Walker, type WalkerOptions, walk } from './walker'; +export { Walker, type WalkerOptions, walk, type WalkerAstNode } from './walker'; diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.stats.test.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.stats.test.ts index 5d158eda45e01..1882096090df1 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.stats.test.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.stats.test.ts @@ -378,7 +378,7 @@ describe('autocomplete.suggest', () => { const suggestions = await suggest('FROM a | STATS /', { callbacks: { canSuggestVariables: () => true, - getVariablesByType: () => [], + getVariables: () => [], getColumnsFor: () => Promise.resolve([{ name: 'clientip', type: 'ip' }]), }, }); @@ -399,7 +399,7 @@ describe('autocomplete.suggest', () => { const suggestions = await suggest('FROM a | STATS var0 = /', { callbacks: { canSuggestVariables: () => true, - getVariablesByType: () => [ + getVariables: () => [ { key: 'function', value: 'avg', @@ -426,7 +426,7 @@ describe('autocomplete.suggest', () => { const suggestions = await suggest('FROM a | STATS BY /', { callbacks: { canSuggestVariables: () => true, - getVariablesByType: () => [], + getVariables: () => [], getColumnsFor: () => Promise.resolve([{ name: 'clientip', type: 'ip' }]), }, }); @@ -447,7 +447,7 @@ describe('autocomplete.suggest', () => { const suggestions = await suggest('FROM a | STATS BY /', { callbacks: { canSuggestVariables: () => true, - getVariablesByType: () => [ + getVariables: () => [ { key: 'field', value: 'clientip', @@ -474,7 +474,7 @@ describe('autocomplete.suggest', () => { const suggestions = await suggest('FROM a | STATS BY BUCKET(@timestamp, /)', { callbacks: { canSuggestVariables: () => true, - getVariablesByType: () => [ + getVariables: () => [ { key: 'interval', value: '1 hour', diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.where.test.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.where.test.ts index 1fdc6fa2ae769..35e3315849bd7 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.where.test.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/__tests__/autocomplete.command.where.test.ts @@ -399,7 +399,7 @@ describe('WHERE ', () => { const suggestions = await suggest('FROM a | WHERE agent.name == /', { callbacks: { canSuggestVariables: () => true, - getVariablesByType: () => [], + getVariables: () => [], getColumnsFor: () => Promise.resolve([{ name: 'agent.name', type: 'keyword' }]), }, }); @@ -421,7 +421,7 @@ describe('WHERE ', () => { const suggestions = await suggest('FROM a | WHERE agent.name == /', { callbacks: { canSuggestVariables: () => true, - getVariablesByType: () => [ + getVariables: () => [ { key: 'value', value: 'java', diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts index 4f74b0c0c5a72..1961c7e8c49c4 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/autocomplete.ts @@ -16,7 +16,7 @@ import { type ESQLFunction, type ESQLSingleAstItem, } from '@kbn/esql-ast'; -import { ESQLVariableType, type ESQLControlVariable } from '@kbn/esql-types'; +import type { ESQLControlVariable } from '@kbn/esql-types'; import { ESQL_NUMBER_TYPES, isNumericType } from '../shared/esql_types'; import type { EditorContext, ItemKind, SuggestionRawDefinition, GetColumnsByTypeFn } from './types'; import { @@ -138,7 +138,7 @@ export async function suggest( resourceRetriever ); const supportsControls = resourceRetriever?.canSuggestVariables?.() ?? false; - const getVariablesByType = resourceRetriever?.getVariablesByType; + const getVariables = resourceRetriever?.getVariables; const getSources = getSourcesHelper(resourceRetriever); const { getPolicies, getPolicyMetadata } = getPolicyRetriever(resourceRetriever); @@ -188,7 +188,7 @@ export async function suggest( getFieldsMap, getPolicies, getPolicyMetadata, - getVariablesByType, + getVariables, resourceRetriever?.getPreferences, resourceRetriever, supportsControls @@ -217,7 +217,7 @@ export async function suggest( getFieldsMap, fullText, offset, - getVariablesByType, + getVariables, supportsControls ); } @@ -239,7 +239,7 @@ export function getFieldsByTypeRetriever( resourceRetriever?: ESQLCallbacks ): { getFieldsByType: GetColumnsByTypeFn; getFieldsMap: GetFieldsMapFn } { const helpers = getFieldsByTypeHelper(queryString, resourceRetriever); - const getVariablesByType = resourceRetriever?.getVariablesByType; + const getVariables = resourceRetriever?.getVariables; const supportsControls = resourceRetriever?.canSuggestVariables?.() ?? false; return { getFieldsByType: async ( @@ -252,7 +252,7 @@ export function getFieldsByTypeRetriever( supportsControls, }; const fields = await helpers.getFieldsByType(expectedType, ignored); - return buildFieldsDefinitionsWithMetadata(fields, updatedOptions, getVariablesByType); + return buildFieldsDefinitionsWithMetadata(fields, updatedOptions, getVariables); }, getFieldsMap: helpers.getFieldsMap, }; @@ -355,7 +355,7 @@ async function getSuggestionsWithinCommandExpression( getFieldsMap: GetFieldsMapFn, getPolicies: GetPoliciesFn, getPolicyMetadata: GetPolicyMetadataFn, - getVariablesByType?: (type: ESQLVariableType) => ESQLControlVariable[] | undefined, + getVariables?: () => ESQLControlVariable[] | undefined, getPreferences?: () => Promise<{ histogramBarTarget: number } | undefined>, callbacks?: ESQLCallbacks, supportsControls?: boolean @@ -396,7 +396,7 @@ async function getSuggestionsWithinCommandExpression( getSourcesFromQuery: (type) => getSourcesFromCommands(commands, type), previousCommands: commands, callbacks, - getVariablesByType, + getVariables, supportsControls, getPolicies, getPolicyMetadata, @@ -907,7 +907,7 @@ async function getFunctionArgsSuggestions( getFieldsMap: GetFieldsMapFn, fullText: string, offset: number, - getVariablesByType?: (type: ESQLVariableType) => ESQLControlVariable[] | undefined, + getVariables?: () => ESQLControlVariable[] | undefined, supportsControls?: boolean ): Promise { const fnDefinition = getFunctionDefinition(node.name); @@ -1038,7 +1038,7 @@ async function getFunctionArgsSuggestions( advanceCursorAndOpenSuggestions: hasMoreMandatoryArgs, supportsControls, }, - getVariablesByType + getVariables ) ); diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/commands/join/index.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/commands/join/index.ts index 5fb82556819b8..a3e71437eb002 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/commands/join/index.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/commands/join/index.ts @@ -59,11 +59,11 @@ const suggestFields = async ( ]); const supportsControls = callbacks?.canSuggestVariables?.() ?? false; - const getVariablesByType = callbacks?.getVariablesByType; + const getVariables = callbacks?.getVariables; const joinFields = buildFieldsDefinitionsWithMetadata( lookupIndexFields!, { supportsControls }, - getVariablesByType + getVariables ); const intersection = suggestionIntersection(joinFields, sourceFields); diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/commands/stats/index.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/commands/stats/index.ts index 5fb905629d55b..6ce3522526b57 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/commands/stats/index.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/commands/stats/index.ts @@ -25,7 +25,7 @@ export async function suggest({ getColumnsByType, getSuggestedVariableName, getPreferences, - getVariablesByType, + getVariables, supportsControls, }: CommandSuggestParams<'stats'>): Promise { const pos = getPosition(innerText, command); @@ -37,7 +37,7 @@ export async function suggest({ const controlSuggestions = getControlSuggestionIfSupported( Boolean(supportsControls), ESQLVariableType.FUNCTIONS, - getVariablesByType + getVariables ); switch (pos) { diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts index 0b6b9ff401df2..6361e72224c88 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts @@ -209,7 +209,7 @@ export const buildFieldsDefinitionsWithMetadata = ( variableType?: ESQLVariableType; supportsControls?: boolean; }, - getVariablesByType?: (type: ESQLVariableType) => ESQLControlVariable[] | undefined + getVariables?: () => ESQLControlVariable[] | undefined ): SuggestionRawDefinition[] => { const fieldsSuggestions = fields.map((field) => { const titleCaseType = field.type.charAt(0).toUpperCase() + field.type.slice(1); @@ -230,7 +230,7 @@ export const buildFieldsDefinitionsWithMetadata = ( const suggestions = [...fieldsSuggestions]; if (options?.supportsControls) { const variableType = options?.variableType ?? ESQLVariableType.FIELDS; - const variables = getVariablesByType?.(variableType) ?? []; + const variables = getVariables?.()?.filter((variable) => variable.type === variableType) ?? []; const controlSuggestions = fields.length ? getControlSuggestion( @@ -418,7 +418,7 @@ export function getCompatibleLiterals( addComma?: boolean; supportsControls?: boolean; }, - getVariablesByType?: (type: ESQLVariableType) => ESQLControlVariable[] | undefined + getVariables?: () => ESQLControlVariable[] | undefined ) { const suggestions: SuggestionRawDefinition[] = []; if (types.some(isNumericType)) { @@ -436,7 +436,9 @@ export function getCompatibleLiterals( ...buildConstantsDefinitions(getUnitDuration(1), undefined, undefined, options), ]; if (options?.supportsControls) { - const variables = getVariablesByType?.(ESQLVariableType.TIME_LITERAL) ?? []; + const variables = + getVariables?.()?.filter((variable) => variable.type === ESQLVariableType.TIME_LITERAL) ?? + []; timeLiteralSuggestions.push( ...getControlSuggestion( ESQLVariableType.TIME_LITERAL, @@ -520,13 +522,13 @@ export function getDateLiterals(options?: { export function getControlSuggestionIfSupported( supportsControls: boolean, type: ESQLVariableType, - getVariablesByType?: (type: ESQLVariableType) => ESQLControlVariable[] | undefined + getVariables?: () => ESQLControlVariable[] | undefined ) { if (!supportsControls) { return []; } const variableType = type; - const variables = getVariablesByType?.(variableType) ?? []; + const variables = getVariables?.()?.filter((variable) => variable.type === variableType) ?? []; const controlSuggestion = getControlSuggestion( variableType, variables?.map((v) => `?${v.key}`) diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/types.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/types.ts index e71b915a044ca..8034862bc3b3e 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/types.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/definitions/types.ts @@ -14,7 +14,7 @@ import type { ESQLMessage, ESQLSource, } from '@kbn/esql-ast'; -import { ESQLControlVariable, ESQLVariableType } from '@kbn/esql-types'; +import { ESQLControlVariable } from '@kbn/esql-types'; import { GetColumnsByTypeFn, SuggestionRawDefinition } from '../autocomplete/types'; import type { ESQLPolicy } from '../validation/types'; import { ESQLCallbacks, ESQLSourceResult } from '../shared/types'; @@ -272,7 +272,7 @@ export interface CommandSuggestParams { */ previousCommands?: ESQLCommand[]; callbacks?: ESQLCallbacks; - getVariablesByType?: (type: ESQLVariableType) => ESQLControlVariable[] | undefined; + getVariables?: () => ESQLControlVariable[] | undefined; supportsControls?: boolean; } diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/types.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/types.ts index aafd56ff9c579..91daf27d70cdd 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/types.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/shared/types.ts @@ -6,7 +6,7 @@ * your election, the "Elastic License 2.0", the "GNU Affero General Public * License v3.0 only", or the "Server Side Public License, v 1". */ -import { ESQLVariableType, type ESQLControlVariable } from '@kbn/esql-types'; +import type { ESQLControlVariable } from '@kbn/esql-types'; import type { ESQLRealField, JoinIndexAutocompleteItem } from '../validation/types'; /** @internal **/ @@ -46,7 +46,7 @@ export interface ESQLCallbacks { >; getPreferences?: () => Promise<{ histogramBarTarget: number }>; getFieldsMetadata?: Promise; - getVariablesByType?: (type: ESQLVariableType) => ESQLControlVariable[] | undefined; + getVariables?: () => ESQLControlVariable[] | undefined; canSuggestVariables?: () => boolean; getJoinIndices?: () => Promise<{ indices: JoinIndexAutocompleteItem[] }>; } diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/validation.test.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/validation.test.ts index 8d4b47c89370c..68db07096eaaa 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/validation.test.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/validation.test.ts @@ -1733,7 +1733,7 @@ describe('validation logic', () => { getColumnsFor: /Unknown column|Argument of|it is unsupported or not indexed/, getPreferences: /Unknown/, getFieldsMetadata: /Unknown/, - getVariablesByType: /Unknown/, + getVariables: /Unknown/, canSuggestVariables: /Unknown/, }; return excludedCallback.map((callback) => (contentByCallback as any)[callback]) || []; diff --git a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/validation.ts b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/validation.ts index 8da29c1cc9679..51d731336923e 100644 --- a/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/validation.ts +++ b/src/platform/packages/shared/kbn-esql-validation-autocomplete/src/validation/validation.ts @@ -1352,7 +1352,7 @@ export const ignoreErrorsMap: Record = { getPolicies: ['unknownPolicy'], getPreferences: [], getFieldsMetadata: [], - getVariablesByType: [], + getVariables: [], canSuggestVariables: [], getJoinIndices: [], }; diff --git a/src/platform/packages/shared/kbn-monaco/src/languages/esql/lib/hover/helpers.test.ts b/src/platform/packages/shared/kbn-monaco/src/languages/esql/lib/hover/helpers.test.ts new file mode 100644 index 0000000000000..495628aa1d4c3 --- /dev/null +++ b/src/platform/packages/shared/kbn-monaco/src/languages/esql/lib/hover/helpers.test.ts @@ -0,0 +1,86 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ +import type { WalkerAstNode } from '@kbn/esql-ast'; +import { ESQLVariableType } from '@kbn/esql-types'; +import { getVariablesHoverContent } from './helpers'; + +describe('getVariablesHoverContent', () => { + test('should return empty array if no variables are used in the query', async () => { + const node = { + type: 'source', + cluster: '', + index: 'logst*', + name: 'logst*', + sourceType: 'index', + location: { + min: 5, + max: 10, + }, + incomplete: false, + text: 'logst*', + } as WalkerAstNode; + + const variables = [ + { + key: 'var', + value: 'value', + type: ESQLVariableType.VALUES, + }, + ]; + + expect(getVariablesHoverContent(node, variables)).toEqual([]); + }); + + test('should return empty array if no variables are given', () => { + const node = { + type: 'source', + cluster: '', + index: 'logst*', + name: 'logst*', + sourceType: 'index', + location: { + min: 5, + max: 10, + }, + incomplete: false, + text: 'logst*', + } as WalkerAstNode; + + expect(getVariablesHoverContent(node)).toEqual([]); + }); + + test('should return the variable content if user is hovering over a variable', () => { + const node = { + value: 'field', + location: { + min: 96, + max: 101, + }, + text: '?field', + incomplete: false, + name: '', + type: 'literal', + literalType: 'param', + paramType: 'named', + } as WalkerAstNode; + const variables = [ + { + key: 'field', + value: 'agent', + type: ESQLVariableType.FIELDS, + }, + ]; + + expect(getVariablesHoverContent(node, variables)).toEqual([ + { + value: '**field**: agent', + }, + ]); + }); +}); diff --git a/src/platform/packages/shared/kbn-monaco/src/languages/esql/lib/hover/helpers.ts b/src/platform/packages/shared/kbn-monaco/src/languages/esql/lib/hover/helpers.ts new file mode 100644 index 0000000000000..018540590d4ba --- /dev/null +++ b/src/platform/packages/shared/kbn-monaco/src/languages/esql/lib/hover/helpers.ts @@ -0,0 +1,30 @@ +/* + * 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", the "GNU Affero General Public License v3.0 only", 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", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ +import { Walker, type WalkerAstNode } from '@kbn/esql-ast'; +import type { ESQLControlVariable } from '@kbn/esql-types'; + +export const getVariablesHoverContent = ( + node?: WalkerAstNode, + variables?: ESQLControlVariable[] +) => { + const usedVariablesInNode = node ? Walker.params(node).map((v) => v.text.replace('?', '')) : []; + const usedVariables = variables?.filter((v) => usedVariablesInNode.includes(v.key)); + + const hoverContents: Array<{ value: string }> = []; + + if (usedVariables?.length) { + usedVariables.forEach((variable) => { + hoverContents.push({ + value: `**${variable.key}**: ${variable.value}`, + }); + }); + } + + return hoverContents; +}; diff --git a/src/platform/packages/shared/kbn-monaco/src/languages/esql/lib/hover/hover.ts b/src/platform/packages/shared/kbn-monaco/src/languages/esql/lib/hover/hover.ts index 006156f172f2d..1c06c22b088e4 100644 --- a/src/platform/packages/shared/kbn-monaco/src/languages/esql/lib/hover/hover.ts +++ b/src/platform/packages/shared/kbn-monaco/src/languages/esql/lib/hover/hover.ts @@ -36,6 +36,7 @@ import { import { isESQLFunction, isESQLNamedParamLiteral } from '@kbn/esql-ast/src/types'; import { monacoPositionToOffset } from '../shared/utils'; import { monaco } from '../../../../monaco_imports'; +import { getVariablesHoverContent } from './helpers'; const ACCEPTABLE_TYPES_HOVER = i18n.translate('monaco.esql.hover.acceptableTypes', { defaultMessage: 'Acceptable types', @@ -148,12 +149,19 @@ export async function getHoverItem( const { ast } = await astProvider(fullText); const astContext = getAstContext(fullText, ast, offset); - const { getPolicyMetadata } = getPolicyHelper(resourceRetriever); - let hoverContent: monaco.languages.Hover = { + const variables = resourceRetriever?.getVariables?.(); + const variablesContent = getVariablesHoverContent(astContext.node, variables); + + const hoverContent: monaco.languages.Hover = { contents: [], }; + + if (variablesContent.length) { + hoverContent.contents.push(...variablesContent); + } + const hoverItemsForFunction = await getHoverItemForFunction( model, position, @@ -162,7 +170,8 @@ export async function getHoverItem( resourceRetriever ); if (hoverItemsForFunction) { - hoverContent = hoverItemsForFunction; + hoverContent.contents.push(...hoverItemsForFunction.contents); + hoverContent.range = hoverItemsForFunction.range; } if (['newCommand', 'list'].includes(astContext.type)) { diff --git a/src/platform/packages/shared/kbn-monaco/tsconfig.json b/src/platform/packages/shared/kbn-monaco/tsconfig.json index 36eb2fcb56915..5c54c4d8720fa 100644 --- a/src/platform/packages/shared/kbn-monaco/tsconfig.json +++ b/src/platform/packages/shared/kbn-monaco/tsconfig.json @@ -9,7 +9,8 @@ "@kbn/i18n", "@kbn/repo-info", "@kbn/esql-ast", - "@kbn/esql-validation-autocomplete" + "@kbn/esql-validation-autocomplete", + "@kbn/esql-types" ], "exclude": ["target/**/*"] }