Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 16 additions & 14 deletions src/platform/packages/private/kbn-esql-editor/src/esql_editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import type { CodeEditorProps } from '@kbn/code-editor';
import { CodeEditor } from '@kbn/code-editor';
import type { CoreStart } from '@kbn/core/public';
import type { AggregateQuery, TimeRange } from '@kbn/es-query';
import type { FieldType } from '@kbn/esql-ast';
import { type FieldType } from '@kbn/esql-ast';
import type { ESQLFieldWithMetadata } from '@kbn/esql-ast/src/commands_registry/types';
import type { ESQLTelemetryCallbacks } from '@kbn/esql-types';
import {
Expand Down Expand Up @@ -303,20 +303,22 @@ const ESQLEditorInternal = function ESQLEditor({
}
}, [code, fixedQuery]);

// Enable the variables service if the feature is supported in the consumer app
// If variables are passed to the editor, sync them with the variables service.
// This ensures that the latest variables are always available for suggestions.
// The "Create control" suggestion is also enabled/disabled here based on the supportsControls flag
useEffect(() => {
const variables = variablesService?.esqlVariables;
if (!isEqual(variables, esqlVariables)) {
variablesService?.clearVariables();
esqlVariables?.forEach((variable) => {
variablesService?.addVariable(variable);
});
}
// Enable or disable suggestions based on whether Create control suggestion is supported
if (controlsContext?.supportsControls) {
variablesService?.enableSuggestions();

const variables = variablesService?.esqlVariables;
if (!isEqual(variables, esqlVariables)) {
variablesService?.clearVariables();
esqlVariables?.forEach((variable) => {
variablesService?.addVariable(variable);
});
}
variablesService?.enableCreateControlSuggestion();
} else {
variablesService?.disableSuggestions();
variablesService?.disableCreateControlSuggestion();
}
}, [variablesService, controlsContext, esqlVariables]);

Expand Down Expand Up @@ -652,7 +654,7 @@ const ESQLEditorInternal = function ESQLEditor({
return variablesService?.esqlVariables;
},
canSuggestVariables: () => {
return variablesService?.areSuggestionsEnabled ?? false;
return variablesService?.isCreateControlSuggestionEnabled ?? false;
},
getJoinIndices,
getTimeseriesIndices: kibana.services?.esql?.getTimeseriesIndicesAutocomplete,
Expand Down Expand Up @@ -707,7 +709,7 @@ const ESQLEditorInternal = function ESQLEditor({
memoizedFieldsFromESQL,
abortController,
variablesService?.esqlVariables,
variablesService?.areSuggestionsEnabled,
variablesService?.isCreateControlSuggestionEnabled,
histogramBarTarget,
activeSolutionId,
canCreateLookupIndex,
Expand Down
6 changes: 3 additions & 3 deletions src/platform/packages/private/kbn-esql-editor/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,10 @@ export interface ESQLEditorProps {
}

interface ESQLVariableService {
areSuggestionsEnabled: boolean;
isCreateControlSuggestionEnabled: boolean;
esqlVariables: ESQLControlVariable[];
enableSuggestions: () => void;
disableSuggestions: () => void;
enableCreateControlSuggestion: () => void;
disableCreateControlSuggestion: () => void;
clearVariables: () => void;
addVariable: (variable: ESQLControlVariable) => void;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -276,26 +276,25 @@ async function handleDefaultContext(ctx: ExpressionContext): Promise<ISuggestion
suggestions.push(...builder.build());
}

// Suggest control variables (e.g., "?fieldName", "$valueName") if supported and not already present
if (context?.supportsControls) {
const hasControl = suggestions.some((suggestion) =>
suggestion.command?.id?.includes('esql.control')
);
// Suggest control variables (e.g., "??fieldName", "?valueName") if supported and not already present
const hasControl = suggestions.some((suggestion) =>
suggestion.command?.id?.includes('esql.control')
);

if (!hasControl) {
const prefix = getVariablePrefix(controlType);
const variableNames =
context.variables
?.filter(({ type }) => type === controlType)
.map(({ key }) => `${prefix}${key}`) ?? [];

const controlSuggestions = getControlSuggestion(
controlType,
ControlTriggerSource.SMART_SUGGESTION,
variableNames
);
suggestions.push(...controlSuggestions);
}
if (!hasControl) {
const prefix = getVariablePrefix(controlType);
const variableNames =
context?.variables
?.filter(({ type }) => type === controlType)
.map(({ key }) => `${prefix}${key}`) ?? [];

const controlSuggestions = getControlSuggestion(
controlType,
ControlTriggerSource.SMART_SUGGESTION,
variableNames,
Boolean(context?.supportsControls)
);
suggestions.push(...controlSuggestions);
}

return suggestions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,28 +316,33 @@ export const columnExists = (col: string, context?: ICommandContext) =>
export function getControlSuggestion(
type: ESQLVariableType,
triggerSource: ControlTriggerSource,
variables?: string[]
variables?: string[],
suggestCreation = true
): ISuggestionItem[] {
return [
{
label: i18n.translate('kbn-esql-ast.esql.autocomplete.createControlLabel', {
defaultMessage: 'Create control',
}),
text: '',
kind: 'Issue',
detail: i18n.translate('kbn-esql-ast.esql.autocomplete.createControlDetailLabel', {
defaultMessage: 'Click to create',
}),
sortText: '1',
category: SuggestionCategory.CUSTOM_ACTION,
command: {
id: `esql.control.${type}.create`,
title: i18n.translate('kbn-esql-ast.esql.autocomplete.createControlDetailLabel', {
defaultMessage: 'Click to create',
}),
arguments: [{ triggerSource }],
},
} as ISuggestionItem,
...(suggestCreation
? [
{
label: i18n.translate('kbn-esql-ast.esql.autocomplete.createControlLabel', {
defaultMessage: 'Create control',
}),
text: '',
kind: 'Issue',
detail: i18n.translate('kbn-esql-ast.esql.autocomplete.createControlDetailLabel', {
defaultMessage: 'Click to create',
}),
sortText: '1',
category: SuggestionCategory.CUSTOM_ACTION,
command: {
id: `esql.control.${type}.create`,
title: i18n.translate('kbn-esql-ast.esql.autocomplete.createControlDetailLabel', {
defaultMessage: 'Click to create',
}),
arguments: [{ triggerSource }],
},
} as ISuggestionItem,
]
: []),
...(variables?.length
? buildConstantsDefinitions(
variables,
Expand Down Expand Up @@ -365,17 +370,14 @@ export function getControlSuggestionIfSupported(
variables?: ESQLControlVariable[],
shouldBePrefixed = true
) {
if (!supportsControls) {
return [];
}

const prefix = shouldBePrefixed ? getVariablePrefix(type) : '';
const filteredVariables = variables?.filter((variable) => variable.type === type) ?? [];

const controlSuggestion = getControlSuggestion(
type,
triggerSource,
filteredVariables?.map((v) => `${prefix}${v.key}`)
filteredVariables?.map((v) => `${prefix}${v.key}`),
supportsControls
);

return controlSuggestion;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -466,20 +466,18 @@ export const buildColumnSuggestions = (
});

const suggestions = [...fieldsSuggestions];
if (options?.supportsControls) {
const variableType = options?.variableType ?? ESQLVariableType.FIELDS;
const userDefinedColumns =
variables?.filter((variable) => variable.type === variableType) ?? [];

const controlSuggestions = columns.length
? getControlSuggestion(
variableType,
ControlTriggerSource.SMART_SUGGESTION,
userDefinedColumns?.map((v) => `${getVariablePrefix(variableType)}${v.key}`)
)
: [];
suggestions.push(...controlSuggestions);
}
const variableType = options?.variableType ?? ESQLVariableType.FIELDS;
const userDefinedColumns = variables?.filter((variable) => variable.type === variableType) ?? [];

const controlSuggestions = columns.length
? getControlSuggestion(
variableType,
ControlTriggerSource.SMART_SUGGESTION,
userDefinedColumns?.map((v) => `${getVariablePrefix(variableType)}${v.key}`),
Boolean(options?.supportsControls)
)
: [];
suggestions.push(...controlSuggestions);

return [...suggestions];
};
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ describe('EsqlVariablesService', () => {
esqlVariablesService = new EsqlVariablesService();
});

describe('enableSuggestions', () => {
describe('enableCreateControlSuggestion', () => {
it('should enable suggestions', () => {
esqlVariablesService.enableSuggestions();
expect(esqlVariablesService.areSuggestionsEnabled).toBe(true);
esqlVariablesService.enableCreateControlSuggestion();
expect(esqlVariablesService.isCreateControlSuggestionEnabled).toBe(true);
});
});

describe('disableSuggestions', () => {
describe('disableCreateControlSuggestion', () => {
it('should disable suggestions', () => {
esqlVariablesService.disableSuggestions();
expect(esqlVariablesService.areSuggestionsEnabled).toBe(false);
esqlVariablesService.disableCreateControlSuggestion();
expect(esqlVariablesService.isCreateControlSuggestionEnabled).toBe(false);
});
});

Expand Down
16 changes: 11 additions & 5 deletions src/platform/plugins/shared/esql/public/variables_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,22 @@

import type { ESQLControlVariable } from '@kbn/esql-types';

/**
* Service to manage ESQL variables for controls
* The service allows adding, retrieving and clearing variables
* and enables/disables the creation of control suggestions based on variables.
*/

export class EsqlVariablesService {
esqlVariables: ESQLControlVariable[] = [];
areSuggestionsEnabled: boolean = false;
isCreateControlSuggestionEnabled: boolean = false;

enableSuggestions() {
this.areSuggestionsEnabled = true;
enableCreateControlSuggestion() {
this.isCreateControlSuggestionEnabled = true;
}

disableSuggestions() {
this.areSuggestionsEnabled = false;
disableCreateControlSuggestion() {
this.isCreateControlSuggestionEnabled = false;
}

addVariable(variable: ESQLControlVariable): void {
Expand Down