diff --git a/packages/grafana-ui/src/slate-plugins/suggestions.tsx b/packages/grafana-ui/src/slate-plugins/suggestions.tsx index 2d74ab061b9..c11b6ffde95 100644 --- a/packages/grafana-ui/src/slate-plugins/suggestions.tsx +++ b/packages/grafana-ui/src/slate-plugins/suggestions.tsx @@ -295,8 +295,8 @@ const handleTypeahead = async ( } } - // Filter out the already typed value (prefix) unless it inserts custom text - newGroup.items = newGroup.items.filter(c => c.insertText || (c.filterText || c.label) !== prefix); + // Filter out the already typed value (prefix) unless it inserts custom text not matching the prefix + newGroup.items = newGroup.items.filter(c => !(c.insertText === prefix || (c.filterText ?? c.label) === prefix)); } if (!group.skipSort) { diff --git a/public/app/plugins/datasource/cloudwatch/language_provider.test.ts b/public/app/plugins/datasource/cloudwatch/language_provider.test.ts index 5168b8990b8..494aa465874 100644 --- a/public/app/plugins/datasource/cloudwatch/language_provider.test.ts +++ b/public/app/plugins/datasource/cloudwatch/language_provider.test.ts @@ -8,11 +8,11 @@ import { AGGREGATION_FUNCTIONS_STATS, BOOLEAN_FUNCTIONS, DATETIME_FUNCTIONS, - FUNCTIONS, IP_FUNCTIONS, NUMERIC_OPERATORS, QUERY_COMMANDS, STRING_FUNCTIONS, + FIELD_AND_FILTER_FUNCTIONS, } from './syntax'; const fields = ['field1', '@message']; @@ -33,19 +33,19 @@ describe('CloudWatchLanguageProvider', () => { }); it('should suggest fields and functions after field command', async () => { - await runSuggestionTest('fields \\', [fields, FUNCTIONS.map(v => v.label)]); + await runSuggestionTest('fields \\', [fields, FIELD_AND_FILTER_FUNCTIONS.map(v => v.label)]); }); it('should suggest fields and functions after comma', async () => { - await runSuggestionTest('fields field1, \\', [fields, FUNCTIONS.map(v => v.label)]); + await runSuggestionTest('fields field1, \\', [fields, FIELD_AND_FILTER_FUNCTIONS.map(v => v.label)]); }); it('should suggest fields and functions after comma with prefix', async () => { - await runSuggestionTest('fields field1, @mess\\', [fields, FUNCTIONS.map(v => v.label)]); + await runSuggestionTest('fields field1, @mess\\', [fields, FIELD_AND_FILTER_FUNCTIONS.map(v => v.label)]); }); it('should suggest fields and functions after display command', async () => { - await runSuggestionTest('display \\', [fields, FUNCTIONS.map(v => v.label)]); + await runSuggestionTest('display \\', [fields, FIELD_AND_FILTER_FUNCTIONS.map(v => v.label)]); }); it('should suggest functions after stats command', async () => { @@ -62,8 +62,7 @@ describe('CloudWatchLanguageProvider', () => { it('should suggest fields and some functions after comparison operator', async () => { await runSuggestionTest('filter field1 >= \\', [ fields, - BOOLEAN_FUNCTIONS.map(v => v.label), - NUMERIC_OPERATORS.map(v => v.label), + [...NUMERIC_OPERATORS.map(v => v.label), ...BOOLEAN_FUNCTIONS.map(v => v.label)], ]); }); diff --git a/public/app/plugins/datasource/cloudwatch/language_provider.ts b/public/app/plugins/datasource/cloudwatch/language_provider.ts index d650efaefd9..dbe8068bec6 100644 --- a/public/app/plugins/datasource/cloudwatch/language_provider.ts +++ b/public/app/plugins/datasource/cloudwatch/language_provider.ts @@ -4,13 +4,13 @@ import _ from 'lodash'; // Services & Utils import syntax, { QUERY_COMMANDS, - FUNCTIONS, AGGREGATION_FUNCTIONS_STATS, STRING_FUNCTIONS, DATETIME_FUNCTIONS, IP_FUNCTIONS, BOOLEAN_FUNCTIONS, NUMERIC_OPERATORS, + FIELD_AND_FILTER_FUNCTIONS, } from './syntax'; // Types @@ -210,7 +210,7 @@ export class CloudWatchLanguageProvider extends LanguageProvider { if (['display', 'fields'].includes(queryCommand)) { const typeaheadOutput = await this.getFieldCompletionItems(context.logGroupNames ?? []); - typeaheadOutput.suggestions.push(...this.getFunctionCompletionItems().suggestions); + typeaheadOutput.suggestions.push(...this.getFieldAndFilterFunctionCompletionItems().suggestions); return typeaheadOutput; } @@ -264,10 +264,8 @@ export class CloudWatchLanguageProvider extends LanguageProvider { private handleComparison = async (context?: TypeaheadContext) => { const fieldsSuggestions = await this.getFieldCompletionItems(context?.logGroupNames ?? []); - const boolFuncSuggestions = this.getBoolFuncCompletionItems(); - const numFuncSuggestions = this.getNumericFuncCompletionItems(); - - fieldsSuggestions.suggestions.push(...boolFuncSuggestions.suggestions, ...numFuncSuggestions.suggestions); + const comparisonSuggestions = this.getComparisonCompletionItems(); + fieldsSuggestions.suggestions.push(...comparisonSuggestions.suggestions); return fieldsSuggestions; }; @@ -275,8 +273,8 @@ export class CloudWatchLanguageProvider extends LanguageProvider { return { suggestions: [{ prefixMatch: true, label: 'Commands', items: QUERY_COMMANDS }] }; }; - private getFunctionCompletionItems = (): TypeaheadOutput => { - return { suggestions: [{ prefixMatch: true, label: 'Functions', items: FUNCTIONS }] }; + private getFieldAndFilterFunctionCompletionItems = (): TypeaheadOutput => { + return { suggestions: [{ prefixMatch: true, label: 'Functions', items: FIELD_AND_FILTER_FUNCTIONS }] }; }; private getStatsAggCompletionItems = (): TypeaheadOutput => { @@ -295,13 +293,13 @@ export class CloudWatchLanguageProvider extends LanguageProvider { }; }; - private getNumericFuncCompletionItems = (): TypeaheadOutput => { + private getComparisonCompletionItems = (): TypeaheadOutput => { return { suggestions: [ { prefixMatch: true, label: 'Functions', - items: NUMERIC_OPERATORS, + items: NUMERIC_OPERATORS.concat(BOOLEAN_FUNCTIONS), }, ], }; diff --git a/public/app/plugins/datasource/cloudwatch/syntax.ts b/public/app/plugins/datasource/cloudwatch/syntax.ts index 73bcee4d0e0..5dcda235341 100644 --- a/public/app/plugins/datasource/cloudwatch/syntax.ts +++ b/public/app/plugins/datasource/cloudwatch/syntax.ts @@ -9,12 +9,10 @@ export const QUERY_COMMANDS: CompletionItem[] = [ { label: 'display', documentation: 'Specifies which fields to display in the query results' }, { label: 'filter', - insertText: 'filter', documentation: 'Filters the results of a query based on one or more conditions', }, { label: 'stats', - insertText: 'stats', documentation: 'Calculates aggregate statistics based on the values of log fields', }, { label: 'sort', documentation: 'Sorts the retrieved log events' }, @@ -205,7 +203,6 @@ export const IP_FUNCTIONS = [ }, { label: 'isIpv6InSubnet', - insertText: 'isIpv6InSubnet', detail: 'isIpv6InSubnet(fieldname, string)', documentation: 'Returns true if the field is a valid v6 IP address within the specified v6 subnet.', }, @@ -306,15 +303,16 @@ export const NON_AGGREGATION_FUNCS_STATS = [ export const STATS_FUNCS = [...AGGREGATION_FUNCTIONS_STATS, ...NON_AGGREGATION_FUNCS_STATS]; export const KEYWORDS = ['as', 'like', 'by', 'in', 'desc', 'asc']; -export const FUNCTIONS = [ +export const FIELD_AND_FILTER_FUNCTIONS = [ ...NUMERIC_OPERATORS, ...GENERAL_FUNCTIONS, ...STRING_FUNCTIONS, ...DATETIME_FUNCTIONS, ...IP_FUNCTIONS, - ...STATS_FUNCS, ]; +export const FUNCTIONS = [...FIELD_AND_FILTER_FUNCTIONS, ...STATS_FUNCS]; + const tokenizer: Grammar = { comment: { pattern: /^#.*/,