mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
# Backport This will backport the following commits from `main` to `8.x`: - [[ES|QL] Separate `GROK` and `DISSECT` autocomplete routines (#211101)](https://github.com/elastic/kibana/pull/211101) <!--- Backport version: 9.6.4 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sorenlouv/backport) <!--BACKPORT [{"author":{"name":"Drew Tate","email":"drew.tate@elastic.co"},"sourceCommit":{"committedDate":"2025-02-14T14:44:46Z","message":"[ES|QL] Separate `GROK` and `DISSECT` autocomplete routines (#211101)\n\n## Summary\n\nPart of https://github.com/elastic/kibana/issues/195418\n\nGives `GROK` and `DISSECT` autocomplete logic its own home 🏡\n\n### Checklist\n\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n\n### Identify risks\n\n- [ ] As with any refactor, there's a possibility this will introduce a\nregression in the behavior of commands. However, all automated tests are\npassing and I have tested the behavior manually and can detect no\nregression.","sha":"1223926450736fba5f67d17279ccf650d8b3ff2a","branchLabelMapping":{"^v9.1.0$":"main","^v8.19.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Feature:ES|QL","Team:ESQL","backport:version","v9.1.0","v8.19.0"],"title":"[ES|QL] Separate `GROK` and `DISSECT` autocomplete routines","number":211101,"url":"https://github.com/elastic/kibana/pull/211101","mergeCommit":{"message":"[ES|QL] Separate `GROK` and `DISSECT` autocomplete routines (#211101)\n\n## Summary\n\nPart of https://github.com/elastic/kibana/issues/195418\n\nGives `GROK` and `DISSECT` autocomplete logic its own home 🏡\n\n### Checklist\n\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n\n### Identify risks\n\n- [ ] As with any refactor, there's a possibility this will introduce a\nregression in the behavior of commands. However, all automated tests are\npassing and I have tested the behavior manually and can detect no\nregression.","sha":"1223926450736fba5f67d17279ccf650d8b3ff2a"}},"sourceBranch":"main","suggestedTargetBranches":["8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.1.0","branchLabelMappingKey":"^v9.1.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/211101","number":211101,"mergeCommit":{"message":"[ES|QL] Separate `GROK` and `DISSECT` autocomplete routines (#211101)\n\n## Summary\n\nPart of https://github.com/elastic/kibana/issues/195418\n\nGives `GROK` and `DISSECT` autocomplete logic its own home 🏡\n\n### Checklist\n\n- [x] [Unit or functional\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\nwere updated or added to match the most common scenarios\n\n### Identify risks\n\n- [ ] As with any refactor, there's a possibility this will introduce a\nregression in the behavior of commands. However, all automated tests are\npassing and I have tested the behavior manually and can detect no\nregression.","sha":"1223926450736fba5f67d17279ccf650d8b3ff2a"}},{"branch":"8.x","label":"v8.19.0","branchLabelMappingKey":"^v8.19.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}] BACKPORT-->
This commit is contained in:
parent
855d9fd55d
commit
c2797a3208
12 changed files with 261 additions and 126 deletions
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* 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 { ESQL_STRING_TYPES } from '../../shared/esql_types';
|
||||
import { attachTriggerCommand, getFieldNamesByType, setup } from './helpers';
|
||||
|
||||
describe('autocomplete.suggest', () => {
|
||||
describe('DISSECT', () => {
|
||||
it('suggests fields after DISSECT', async () => {
|
||||
const { assertSuggestions } = await setup();
|
||||
await assertSuggestions(
|
||||
'from a | DISSECT /',
|
||||
getFieldNamesByType(ESQL_STRING_TYPES).map((name) => `${name} `)
|
||||
);
|
||||
await assertSuggestions(
|
||||
'from a | DISSECT /',
|
||||
getFieldNamesByType(ESQL_STRING_TYPES).map((name) => `${name} `),
|
||||
{ triggerCharacter: ' ' }
|
||||
);
|
||||
await assertSuggestions(
|
||||
'from a | DISSECT key/',
|
||||
getFieldNamesByType(ESQL_STRING_TYPES).map((name) => `${name} `)
|
||||
);
|
||||
await assertSuggestions(
|
||||
'from a | DISSECT keywordField/',
|
||||
['keywordField ', 'textField '].map(attachTriggerCommand)
|
||||
);
|
||||
});
|
||||
|
||||
const constantPattern = '"%{firstWord}" ';
|
||||
it('suggests a pattern after a field name', async () => {
|
||||
const { assertSuggestions } = await setup();
|
||||
await assertSuggestions('from a | DISSECT keywordField /', [constantPattern]);
|
||||
});
|
||||
|
||||
it('suggests an append separator or pipe after a pattern', async () => {
|
||||
const { assertSuggestions } = await setup();
|
||||
assertSuggestions(
|
||||
`from a | DISSECT keywordField ${constantPattern} /`,
|
||||
['APPEND_SEPARATOR = ', '| '].map(attachTriggerCommand),
|
||||
{ triggerCharacter: ' ' }
|
||||
);
|
||||
assertSuggestions(
|
||||
`from a | DISSECT keywordField ${constantPattern} /`,
|
||||
['APPEND_SEPARATOR = ', '| '].map(attachTriggerCommand)
|
||||
);
|
||||
});
|
||||
|
||||
it('suggests append separators', async () => {
|
||||
const { assertSuggestions } = await setup();
|
||||
await assertSuggestions(
|
||||
`from a | DISSECT keywordField ${constantPattern} append_separator = /`,
|
||||
['":" ', '";" '].map(attachTriggerCommand)
|
||||
);
|
||||
});
|
||||
|
||||
it('suggests a pipe after an append separator', async () => {
|
||||
const { assertSuggestions } = await setup();
|
||||
await assertSuggestions(
|
||||
`from a | DISSECT keywordField ${constantPattern} append_separator = ":" /`,
|
||||
['| ']
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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 { ESQL_STRING_TYPES } from '../../shared/esql_types';
|
||||
import { attachTriggerCommand, getFieldNamesByType, setup } from './helpers';
|
||||
|
||||
describe('autocomplete.suggest', () => {
|
||||
describe('GROK', () => {
|
||||
it('suggests fields after GROK', async () => {
|
||||
const { assertSuggestions } = await setup();
|
||||
await assertSuggestions(
|
||||
'from a | grok /',
|
||||
getFieldNamesByType(ESQL_STRING_TYPES).map((name) => `${name} `)
|
||||
);
|
||||
await assertSuggestions(
|
||||
'from a | grok key/',
|
||||
getFieldNamesByType(ESQL_STRING_TYPES).map((name) => `${name} `)
|
||||
);
|
||||
await assertSuggestions(
|
||||
'from a | grok keywordField/',
|
||||
['keywordField ', 'textField '].map(attachTriggerCommand)
|
||||
);
|
||||
});
|
||||
|
||||
const constantPattern = '"%{WORD:firstWord}"';
|
||||
it('suggests a pattern after a field name', async () => {
|
||||
const { assertSuggestions } = await setup();
|
||||
await assertSuggestions('from a | grok keywordField /', [constantPattern + ' ']);
|
||||
});
|
||||
|
||||
it('suggests a pipe after a pattern', async () => {
|
||||
const { assertSuggestions } = await setup();
|
||||
await assertSuggestions(`from a | grok keywordField ${constantPattern} /`, ['| ']);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -113,88 +113,6 @@ describe('autocomplete', () => {
|
|||
testSuggestions('from a metadata _id | eval var0 = a | /', commands);
|
||||
});
|
||||
|
||||
describe('show', () => {
|
||||
testSuggestions('show /', ['INFO']);
|
||||
for (const fn of ['info']) {
|
||||
testSuggestions(`show ${fn} /`, ['| ']);
|
||||
}
|
||||
});
|
||||
|
||||
describe('grok', () => {
|
||||
const constantPattern = '"%{WORD:firstWord}"';
|
||||
const subExpressions = [
|
||||
'',
|
||||
`grok keywordField |`,
|
||||
`grok keywordField ${constantPattern} |`,
|
||||
`dissect keywordField ${constantPattern} append_separator = ":" |`,
|
||||
`dissect keywordField ${constantPattern} |`,
|
||||
];
|
||||
for (const subExpression of subExpressions) {
|
||||
testSuggestions(
|
||||
`from a | ${subExpression} grok /`,
|
||||
getFieldNamesByType(ESQL_STRING_TYPES).map((name) => `${name} `)
|
||||
);
|
||||
testSuggestions(`from a | ${subExpression} grok keywordField /`, [constantPattern], ' ');
|
||||
testSuggestions(`from a | ${subExpression} grok keywordField ${constantPattern} /`, ['| ']);
|
||||
}
|
||||
|
||||
testSuggestions(
|
||||
'from a | grok /',
|
||||
getFieldNamesByType(ESQL_STRING_TYPES).map((name) => `${name} `)
|
||||
);
|
||||
testSuggestions(
|
||||
'from a | grok key/',
|
||||
getFieldNamesByType(ESQL_STRING_TYPES).map((name) => `${name} `)
|
||||
);
|
||||
testSuggestions(
|
||||
'from a | grok keywordField/',
|
||||
['keywordField ', 'textField '].map(attachTriggerCommand)
|
||||
);
|
||||
});
|
||||
|
||||
describe('dissect', () => {
|
||||
const constantPattern = '"%{firstWord}"';
|
||||
const subExpressions = [
|
||||
'',
|
||||
`dissect keywordField |`,
|
||||
`dissect keywordField ${constantPattern} |`,
|
||||
`dissect keywordField ${constantPattern} append_separator = ":" |`,
|
||||
];
|
||||
for (const subExpression of subExpressions) {
|
||||
testSuggestions(
|
||||
`from a | ${subExpression} dissect /`,
|
||||
getFieldNamesByType(ESQL_STRING_TYPES).map((name) => `${name} `)
|
||||
);
|
||||
testSuggestions(`from a | ${subExpression} dissect keywordField /`, [constantPattern], ' ');
|
||||
testSuggestions(
|
||||
`from a | ${subExpression} dissect keywordField ${constantPattern} /`,
|
||||
['APPEND_SEPARATOR = $0', '| '],
|
||||
' '
|
||||
);
|
||||
testSuggestions(
|
||||
`from a | ${subExpression} dissect keywordField ${constantPattern} append_separator = /`,
|
||||
['":"', '";"']
|
||||
);
|
||||
testSuggestions(
|
||||
`from a | ${subExpression} dissect keywordField ${constantPattern} append_separator = ":" /`,
|
||||
['| ']
|
||||
);
|
||||
}
|
||||
|
||||
testSuggestions(
|
||||
'from a | dissect /',
|
||||
getFieldNamesByType(ESQL_STRING_TYPES).map((name) => `${name} `)
|
||||
);
|
||||
testSuggestions(
|
||||
'from a | dissect key/',
|
||||
getFieldNamesByType(ESQL_STRING_TYPES).map((name) => `${name} `)
|
||||
);
|
||||
testSuggestions(
|
||||
'from a | dissect keywordField/',
|
||||
['keywordField ', 'textField '].map(attachTriggerCommand)
|
||||
);
|
||||
});
|
||||
|
||||
describe('limit', () => {
|
||||
testSuggestions('from a | limit /', ['10 ', '100 ', '1000 ']);
|
||||
testSuggestions('from a | limit 4 /', ['| ']);
|
||||
|
|
|
@ -52,12 +52,10 @@ import { collectVariables, excludeVariablesFromCurrentCommand } from '../shared/
|
|||
import type { ESQLPolicy, ESQLRealField, ESQLVariable, ReferenceMaps } from '../validation/types';
|
||||
import {
|
||||
allStarConstant,
|
||||
colonCompleteItem,
|
||||
commaCompleteItem,
|
||||
getAssignmentDefinitionCompletitionItem,
|
||||
getCommandAutocompleteDefinitions,
|
||||
pipeCompleteItem,
|
||||
semiColonCompleteItem,
|
||||
} from './complete_items';
|
||||
import {
|
||||
buildFieldsDefinitions,
|
||||
|
@ -210,6 +208,7 @@ export async function suggest(
|
|||
if (
|
||||
astContext.type === 'expression' ||
|
||||
(astContext.type === 'option' && astContext.command?.name === 'join') ||
|
||||
(astContext.type === 'option' && astContext.command?.name === 'dissect') ||
|
||||
(astContext.type === 'option' && astContext.command?.name === 'from')
|
||||
) {
|
||||
return getSuggestionsWithinCommandExpression(
|
||||
|
@ -285,7 +284,7 @@ export function getFieldsByTypeRetriever(
|
|||
const supportsControls = resourceRetriever?.canSuggestVariables?.() ?? false;
|
||||
return {
|
||||
getFieldsByType: async (
|
||||
expectedType: string | string[] = 'any',
|
||||
expectedType: Readonly<string> | Readonly<string[]> = 'any',
|
||||
ignored: string[] = [],
|
||||
options
|
||||
) => {
|
||||
|
@ -791,7 +790,7 @@ async function getExpressionSuggestionsByType(
|
|||
// it can be just literal values (i.e. "string")
|
||||
if (argDef.constantOnly) {
|
||||
// ... | <COMMAND> ... <suggest>
|
||||
suggestions.push(...getCompatibleLiterals(command.name, [argDef.type], [argDef.name]));
|
||||
suggestions.push(...getCompatibleLiterals(command.name, [argDef.type]));
|
||||
} else {
|
||||
// or it can be anything else as long as it is of the right type and the end (i.e. column or function)
|
||||
if (!nodeArg) {
|
||||
|
@ -1078,7 +1077,6 @@ async function getFunctionArgsSuggestions(
|
|||
...getCompatibleLiterals(
|
||||
command.name,
|
||||
getTypesFromParamDefs(constantOnlyParamDefs) as string[],
|
||||
undefined,
|
||||
{
|
||||
addComma: shouldAddComma,
|
||||
advanceCursorAndOpenSuggestions: hasMoreMandatoryArgs,
|
||||
|
@ -1151,7 +1149,7 @@ async function getFunctionArgsSuggestions(
|
|||
if (isLiteralItem(arg) && isNumericType(arg.literalType)) {
|
||||
// ... | EVAL fn(2 <suggest>)
|
||||
suggestions.push(
|
||||
...getCompatibleLiterals(command.name, ['time_literal_unit'], undefined, {
|
||||
...getCompatibleLiterals(command.name, ['time_literal_unit'], {
|
||||
addComma: shouldAddComma,
|
||||
advanceCursorAndOpenSuggestions: hasMoreMandatoryArgs,
|
||||
})
|
||||
|
@ -1403,15 +1401,6 @@ async function getOptionArgsSuggestions(
|
|||
}
|
||||
}
|
||||
|
||||
if (command.name === 'dissect') {
|
||||
if (
|
||||
option.args.filter((arg) => !(isSingleItem(arg) && arg.type === 'unknown')).length < 1 &&
|
||||
optionDef
|
||||
) {
|
||||
suggestions.push(colonCompleteItem, semiColonCompleteItem);
|
||||
}
|
||||
}
|
||||
|
||||
if (optionDef) {
|
||||
if (!suggestions.length) {
|
||||
const argDefIndex = optionDef.signature.multipleParams
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
import { EDITOR_MARKER } from '../../../shared/constants';
|
||||
import { isSingleItem } from '../../../..';
|
||||
import { ESQL_STRING_TYPES } from '../../../shared/esql_types';
|
||||
import { CommandSuggestParams } from '../../../definitions/types';
|
||||
|
||||
import type { SuggestionRawDefinition } from '../../types';
|
||||
import { TRIGGER_SUGGESTION_COMMAND, buildConstantsDefinitions } from '../../factories';
|
||||
import { colonCompleteItem, pipeCompleteItem, semiColonCompleteItem } from '../../complete_items';
|
||||
|
||||
export async function suggest({
|
||||
command,
|
||||
innerText,
|
||||
getColumnsByType,
|
||||
}: CommandSuggestParams<'dissect'>): Promise<SuggestionRawDefinition[]> {
|
||||
const commandArgs = command.args.filter(
|
||||
(arg) => isSingleItem(arg) && arg.text !== EDITOR_MARKER && arg.text !== ''
|
||||
);
|
||||
|
||||
// DISSECT field /
|
||||
if (commandArgs.length === 1) {
|
||||
return buildConstantsDefinitions(
|
||||
['"%{firstWord}"'],
|
||||
i18n.translate('kbn-esql-validation-autocomplete.esql.autocomplete.aPatternString', {
|
||||
defaultMessage: 'A pattern string',
|
||||
}),
|
||||
undefined,
|
||||
{
|
||||
advanceCursorAndOpenSuggestions: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
// DISSECT field pattern /
|
||||
else if (commandArgs.length === 2) {
|
||||
return [
|
||||
{ ...pipeCompleteItem, command: TRIGGER_SUGGESTION_COMMAND },
|
||||
appendSeparatorCompletionItem,
|
||||
];
|
||||
}
|
||||
// DISSECT field APPEND_SEPARATOR = /
|
||||
else if (/append_separator\s*=\s*$/i.test(innerText)) {
|
||||
return [colonCompleteItem, semiColonCompleteItem];
|
||||
}
|
||||
// DISSECT field APPEND_SEPARATOR = ":" /
|
||||
else if (commandArgs.some((arg) => isSingleItem(arg) && arg.type === 'option')) {
|
||||
return [{ ...pipeCompleteItem, command: TRIGGER_SUGGESTION_COMMAND }];
|
||||
}
|
||||
|
||||
// DISSECT /
|
||||
const fieldSuggestions = await getColumnsByType(ESQL_STRING_TYPES);
|
||||
return fieldSuggestions.map((sug) => ({
|
||||
...sug,
|
||||
text: `${sug.text} `,
|
||||
command: TRIGGER_SUGGESTION_COMMAND,
|
||||
}));
|
||||
}
|
||||
|
||||
const appendSeparatorCompletionItem: SuggestionRawDefinition = {
|
||||
command: TRIGGER_SUGGESTION_COMMAND,
|
||||
detail: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.appendSeparatorDoc', {
|
||||
defaultMessage:
|
||||
'The character(s) that separate the appended fields. Default to empty string ("").',
|
||||
}),
|
||||
kind: 'Reference',
|
||||
label: 'APPEND_SEPARATOR',
|
||||
sortText: '1',
|
||||
text: 'APPEND_SEPARATOR = ',
|
||||
};
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
import { CommandSuggestParams } from '../../../definitions/types';
|
||||
|
||||
import type { SuggestionRawDefinition } from '../../types';
|
||||
import { ESQL_STRING_TYPES } from '../../../shared/esql_types';
|
||||
import { TRIGGER_SUGGESTION_COMMAND, buildConstantsDefinitions } from '../../factories';
|
||||
import { pipeCompleteItem } from '../../complete_items';
|
||||
|
||||
export async function suggest({
|
||||
command,
|
||||
getColumnsByType,
|
||||
}: CommandSuggestParams<'grok'>): Promise<SuggestionRawDefinition[]> {
|
||||
// GROK field /
|
||||
if (command.args.length === 1) {
|
||||
return buildConstantsDefinitions(
|
||||
['"%{WORD:firstWord}"'],
|
||||
i18n.translate('kbn-esql-validation-autocomplete.esql.autocomplete.aPatternString', {
|
||||
defaultMessage: 'A pattern string',
|
||||
}),
|
||||
undefined,
|
||||
{
|
||||
advanceCursorAndOpenSuggestions: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
// GROK field pattern /
|
||||
else if (command.args.length === 2) {
|
||||
return [{ ...pipeCompleteItem, command: TRIGGER_SUGGESTION_COMMAND }];
|
||||
}
|
||||
|
||||
// GROK /
|
||||
const fieldSuggestions = await getColumnsByType(ESQL_STRING_TYPES);
|
||||
return fieldSuggestions.map((sug) => ({
|
||||
...sug,
|
||||
text: `${sug.text} `,
|
||||
command: TRIGGER_SUGGESTION_COMMAND,
|
||||
}));
|
||||
}
|
|
@ -20,7 +20,7 @@ export async function suggest({
|
|||
if (/INFO\s+$/i.test(innerText)) {
|
||||
return [{ ...pipeCompleteItem, command: TRIGGER_SUGGESTION_COMMAND }];
|
||||
}
|
||||
// SHOW INSOF /
|
||||
// SHOW LOLZ /
|
||||
else if (/SHOW\s+\S+\s+$/i.test(innerText)) {
|
||||
return [];
|
||||
}
|
||||
|
|
|
@ -79,14 +79,21 @@ export const getCommandAutocompleteDefinitions = (
|
|||
function buildCharCompleteItem(
|
||||
label: string,
|
||||
detail: string,
|
||||
{ sortText, quoted }: { sortText?: string; quoted: boolean } = { quoted: false }
|
||||
{
|
||||
sortText,
|
||||
quoted,
|
||||
advanceCursorAndOpenSuggestions,
|
||||
}: { sortText?: string; quoted: boolean; advanceCursorAndOpenSuggestions?: boolean } = {
|
||||
quoted: false,
|
||||
}
|
||||
): SuggestionRawDefinition {
|
||||
return {
|
||||
label,
|
||||
text: quoted ? `"${label}"` : label,
|
||||
text: (quoted ? `"${label}"` : label) + (advanceCursorAndOpenSuggestions ? ' ' : ''),
|
||||
kind: 'Keyword',
|
||||
detail,
|
||||
sortText,
|
||||
command: advanceCursorAndOpenSuggestions ? TRIGGER_SUGGESTION_COMMAND : undefined,
|
||||
};
|
||||
}
|
||||
export const pipeCompleteItem: SuggestionRawDefinition = {
|
||||
|
@ -113,14 +120,14 @@ export const colonCompleteItem = buildCharCompleteItem(
|
|||
i18n.translate('kbn-esql-validation-autocomplete.esql.autocomplete.colonDoc', {
|
||||
defaultMessage: 'Colon (:)',
|
||||
}),
|
||||
{ sortText: 'A', quoted: true }
|
||||
{ sortText: 'A', quoted: true, advanceCursorAndOpenSuggestions: true }
|
||||
);
|
||||
export const semiColonCompleteItem = buildCharCompleteItem(
|
||||
';',
|
||||
i18n.translate('kbn-esql-validation-autocomplete.esql.autocomplete.semiColonDoc', {
|
||||
defaultMessage: 'Semi colon (;)',
|
||||
}),
|
||||
{ sortText: 'A', quoted: true }
|
||||
{ sortText: 'A', quoted: true, advanceCursorAndOpenSuggestions: true }
|
||||
);
|
||||
|
||||
export const listCompleteItem: SuggestionRawDefinition = {
|
||||
|
|
|
@ -459,7 +459,6 @@ export function getUnitDuration(unit: number = 1) {
|
|||
export function getCompatibleLiterals(
|
||||
commandName: string,
|
||||
types: string[],
|
||||
names?: string[],
|
||||
options?: {
|
||||
advanceCursorAndOpenSuggestions?: boolean;
|
||||
addComma?: boolean;
|
||||
|
@ -505,25 +504,6 @@ export function getCompatibleLiterals(
|
|||
)
|
||||
); // i.e. year, month, ...
|
||||
}
|
||||
if (types.includes('string')) {
|
||||
if (names) {
|
||||
const index = types.indexOf('string');
|
||||
if (/pattern/.test(names[index])) {
|
||||
suggestions.push(
|
||||
...buildConstantsDefinitions(
|
||||
[commandName === 'grok' ? '"%{WORD:firstWord}"' : '"%{firstWord}"'],
|
||||
i18n.translate('kbn-esql-validation-autocomplete.esql.autocomplete.aPatternString', {
|
||||
defaultMessage: 'A pattern string',
|
||||
}),
|
||||
undefined,
|
||||
options
|
||||
)
|
||||
);
|
||||
} else {
|
||||
suggestions.push(...buildConstantsDefinitions(['string'], '', undefined, options));
|
||||
}
|
||||
}
|
||||
}
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ export interface EditorContext {
|
|||
}
|
||||
|
||||
export type GetColumnsByTypeFn = (
|
||||
type: string | string[],
|
||||
type: Readonly<string> | Readonly<string[]>,
|
||||
ignored?: string[],
|
||||
options?: {
|
||||
advanceCursor?: boolean;
|
||||
|
|
|
@ -46,6 +46,8 @@ import { suggest as suggestForJoin } from '../autocomplete/commands/join';
|
|||
import { suggest as suggestForFrom } from '../autocomplete/commands/from';
|
||||
import { suggest as suggestForRow } from '../autocomplete/commands/row';
|
||||
import { suggest as suggestForShow } from '../autocomplete/commands/show';
|
||||
import { suggest as suggestForGrok } from '../autocomplete/commands/grok';
|
||||
import { suggest as suggestForDissect } from '../autocomplete/commands/dissect';
|
||||
|
||||
const statsValidator = (command: ESQLCommand) => {
|
||||
const messages: ESQLMessage[] = [];
|
||||
|
@ -454,7 +456,7 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
defaultMessage:
|
||||
'Extracts multiple string values from a single string input, based on a pattern',
|
||||
}),
|
||||
examples: ['… | dissect a "%{b} %{c}"'],
|
||||
examples: ['… | DISSECT a "%{b} %{c}" APPEND_SEPARATOR = ":"'],
|
||||
options: [appendSeparatorOption],
|
||||
modes: [],
|
||||
signature: {
|
||||
|
@ -464,6 +466,7 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
{ name: 'pattern', type: 'string', constantOnly: true },
|
||||
],
|
||||
},
|
||||
suggest: suggestForDissect,
|
||||
},
|
||||
{
|
||||
name: 'grok',
|
||||
|
@ -471,7 +474,7 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
defaultMessage:
|
||||
'Extracts multiple string values from a single string input, based on a pattern',
|
||||
}),
|
||||
examples: ['… | grok a "%{IP:b} %{NUMBER:c}"'],
|
||||
examples: ['… | GROK a "%{IP:b} %{NUMBER:c}"'],
|
||||
options: [],
|
||||
modes: [],
|
||||
signature: {
|
||||
|
@ -481,6 +484,7 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
|
|||
{ name: 'pattern', type: 'string', constantOnly: true },
|
||||
],
|
||||
},
|
||||
suggest: suggestForGrok,
|
||||
},
|
||||
{
|
||||
name: 'mv_expand',
|
||||
|
|
|
@ -48,7 +48,7 @@ export function getFieldsByTypeHelper(queryText: string, resourceRetriever?: ESQ
|
|||
|
||||
return {
|
||||
getFieldsByType: async (
|
||||
expectedType: string | string[] = 'any',
|
||||
expectedType: Readonly<string> | Readonly<string[]> = 'any',
|
||||
ignored: string[] = []
|
||||
): Promise<ESQLRealField[]> => {
|
||||
const types = Array.isArray(expectedType) ? expectedType : [expectedType];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue