diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts index b33d705711f05..a6d23dafa056a 100644 --- a/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/factories.ts @@ -140,8 +140,6 @@ export const buildFieldsDefinitionsWithMetadata = ( options?: { advanceCursor?: boolean; openSuggestions?: boolean; addComma?: boolean } ): SuggestionRawDefinition[] => { return fields.map((field) => { - const description = field.metadata?.description; - const titleCaseType = field.type.charAt(0).toUpperCase() + field.type.slice(1); return { label: field.name, @@ -151,16 +149,8 @@ export const buildFieldsDefinitionsWithMetadata = ( (options?.advanceCursor ? ' ' : ''), kind: 'Variable', detail: titleCaseType, - documentation: description - ? { - value: ` ---- - -${description}`, - } - : undefined, - // If there is a description, it is a field from ECS, so it should be sorted to the top - sortText: description ? '1D' : 'D', + // If detected to be an ECS field, push it up to the top of the list + sortText: field.isEcs ? '1D' : 'D', command: options?.openSuggestions ? TRIGGER_SUGGESTION_COMMAND : undefined, }; }); diff --git a/packages/kbn-text-based-editor/src/ecs_metadata_helper.test.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/utils/ecs_metadata_helper.test.ts similarity index 73% rename from packages/kbn-text-based-editor/src/ecs_metadata_helper.test.ts rename to packages/kbn-esql-validation-autocomplete/src/autocomplete/utils/ecs_metadata_helper.test.ts index 71f954109b910..2f1fe9e6d29c3 100644 --- a/packages/kbn-text-based-editor/src/ecs_metadata_helper.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/utils/ecs_metadata_helper.test.ts @@ -7,11 +7,10 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { getColumnsWithMetadata } from './ecs_metadata_helper'; -import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public'; -import { ESQLRealField } from '@kbn/esql-validation-autocomplete'; +import type { ESQLRealField } from '../../validation/types'; +import { type ECSMetadata, enrichFieldsWithECSInfo } from './ecs_metadata_helper'; -describe('getColumnsWithMetadata', () => { +describe('enrichFieldsWithECSInfo', () => { it('should return original columns if fieldsMetadata is not provided', async () => { const columns: ESQLRealField[] = [ { name: 'ecs.version', type: 'keyword' }, @@ -19,7 +18,7 @@ describe('getColumnsWithMetadata', () => { { name: 'field2', type: 'double' }, ]; - const result = await getColumnsWithMetadata(columns); + const result = await enrichFieldsWithECSInfo(columns); expect(result).toEqual(columns); }); @@ -42,15 +41,23 @@ describe('getColumnsWithMetadata', () => { }, }), }), - } as unknown as FieldsMetadataPublicStart; + }; + const fieldsMetadataCache = await ( + await fieldsMetadata.getClient() + ).find({ + attributes: ['type'], + }); - const result = await getColumnsWithMetadata(columns, fieldsMetadata); + const result = await enrichFieldsWithECSInfo( + columns, + fieldsMetadataCache.fields as ECSMetadata + ); expect(result).toEqual([ { name: 'ecs.field', type: 'text', - metadata: { description: 'ECS field description' }, + isEcs: true, }, { name: 'ecs.fakeBooleanField', type: 'boolean' }, { name: 'field2', type: 'double' }, @@ -68,19 +75,27 @@ describe('getColumnsWithMetadata', () => { find: jest.fn().mockResolvedValue({ fields: { 'ecs.version': { description: 'ECS version field', type: 'keyword' }, - }, + } as unknown as ECSMetadata, }), }), - } as unknown as FieldsMetadataPublicStart; + }; - const result = await getColumnsWithMetadata(columns, fieldsMetadata); + const fieldsMetadataCache = await ( + await fieldsMetadata.getClient() + ).find({ + attributes: ['type'], + }); + const result = await enrichFieldsWithECSInfo( + columns, + fieldsMetadataCache.fields as ECSMetadata + ); expect(result).toEqual([ - { name: 'ecs.version', type: 'keyword', metadata: { description: 'ECS version field' } }, + { name: 'ecs.version', type: 'keyword', isEcs: true }, { name: 'ecs.version.keyword', type: 'keyword', - metadata: { description: 'ECS version field' }, + isEcs: true, }, { name: 'field2', type: 'double' }, ]); diff --git a/packages/kbn-esql-validation-autocomplete/src/autocomplete/utils/ecs_metadata_helper.ts b/packages/kbn-esql-validation-autocomplete/src/autocomplete/utils/ecs_metadata_helper.ts new file mode 100644 index 0000000000000..adf3e3a98a56a --- /dev/null +++ b/packages/kbn-esql-validation-autocomplete/src/autocomplete/utils/ecs_metadata_helper.ts @@ -0,0 +1,60 @@ +/* + * 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 { ESQLRealField } from '../../validation/types'; + +const removeKeywordSuffix = (name: string) => { + return name.endsWith('.keyword') ? name.slice(0, -8) : name; +}; + +export interface ECSMetadata { + [key: string]: { + type?: string; + source?: string; + description?: string; + }; +} +/** + * Returns columns with the metadata/description (e.g ECS info) + * if available + * + * @param columns + * @param fieldsMetadata + * @returns + */ +export function enrichFieldsWithECSInfo( + columns: Array>, + ecsMetadataCache?: ECSMetadata +): ESQLRealField[] { + if (!ecsMetadataCache) return columns; + + try { + if (ecsMetadataCache) { + return columns.map((c) => { + // Metadata services gives description for + // 'ecs.version' but not 'ecs.version.keyword' + // but both should show description if available + const metadata = ecsMetadataCache[removeKeywordSuffix(c.name)]; + + // Need to convert metadata's type (e.g. keyword) to ES|QL type (e.g. string) to check if they are the same + if (!metadata || (metadata?.type && metadata.type !== c.type)) return c; + return { + ...c, + isEcs: true, + }; + }); + } + + return columns; + } catch (error) { + // eslint-disable-next-line no-console + console.error('Unable to fetch field metadata', error); + } + return columns; +} diff --git a/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.test.ts b/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.test.ts index f0f40df7e108f..b608570854950 100644 --- a/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/code_actions/actions.test.ts @@ -11,11 +11,12 @@ import { getActions } from './actions'; import { validateQuery } from '../validation/validation'; import { getAllFunctions } from '../shared/helpers'; import { getAstAndSyntaxErrors } from '@kbn/esql-ast'; -import { CodeActionOptions } from './types'; -import { ESQLRealField } from '../validation/types'; -import { FieldType } from '../definitions/types'; +import type { CodeActionOptions } from './types'; +import type { ESQLRealField } from '../validation/types'; +import type { FieldType } from '../definitions/types'; +import type { ESQLCallbacks, PartialFieldsMetadataClient } from '../shared/types'; -function getCallbackMocks() { +function getCallbackMocks(): jest.Mocked { return { getFieldsFor: jest.fn, any>(async ({ query }) => { if (/enrich/.test(query)) { @@ -65,6 +66,11 @@ function getCallbackMocks() { enrichFields: ['other-field', 'yetAnotherField'], }, ]), + getFieldsMetadata: jest.fn(async () => ({ + find: jest.fn(async () => ({ + fields: {}, + })), + })) as unknown as Promise, }; } @@ -395,6 +401,7 @@ describe('quick fixes logic', () => { const { errors } = await validateQuery(statement, getAstAndSyntaxErrors, undefined, { ...callbackMocks, getFieldsFor: undefined, + getFieldsMetadata: undefined, }); const actions = await getActions( statement, @@ -403,7 +410,11 @@ describe('quick fixes logic', () => { { relaxOnMissingCallbacks: true, }, - { ...callbackMocks, getFieldsFor: undefined } + { + ...callbackMocks, + getFieldsFor: undefined, + getFieldsMetadata: undefined, + } ); const edits = actions.map(({ edits: actionEdits }) => actionEdits[0].text); expect(edits).toEqual(['`any#Char$Field`']); @@ -452,6 +463,7 @@ describe('quick fixes logic', () => { getFieldsFor: undefined, getSources: undefined, getPolicies: undefined, + getFieldsMetadata: undefined, } ); } catch { diff --git a/packages/kbn-esql-validation-autocomplete/src/shared/resources_helpers.ts b/packages/kbn-esql-validation-autocomplete/src/shared/resources_helpers.ts index 84648e73cf6cb..a4da3907a4d6b 100644 --- a/packages/kbn-esql-validation-autocomplete/src/shared/resources_helpers.ts +++ b/packages/kbn-esql-validation-autocomplete/src/shared/resources_helpers.ts @@ -10,6 +10,7 @@ import type { ESQLAst } from '@kbn/esql-ast'; import type { ESQLCallbacks } from './types'; import type { ESQLRealField } from '../validation/types'; +import { enrichFieldsWithECSInfo } from '../autocomplete/utils/ecs_metadata_helper'; export function buildQueryUntilPreviousCommand(ast: ESQLAst, queryString: string) { const prevCommand = ast[Math.max(ast.length - 2, 0)]; @@ -18,14 +19,31 @@ export function buildQueryUntilPreviousCommand(ast: ESQLAst, queryString: string export function getFieldsByTypeHelper(queryText: string, resourceRetriever?: ESQLCallbacks) { const cacheFields = new Map(); + + const getEcsMetadata = async () => { + if (!resourceRetriever?.getFieldsMetadata) { + return undefined; + } + const client = await resourceRetriever?.getFieldsMetadata; + if (client.find) { + // Fetch full list of ECS field + // This list should be cached already by fieldsMetadataClient + const results = await client.find({ attributes: ['type'] }); + return results?.fields; + } + }; + const getFields = async () => { + const metadata = await getEcsMetadata(); if (!cacheFields.size && queryText) { const fieldsOfType = await resourceRetriever?.getFieldsFor?.({ query: queryText }); - for (const field of fieldsOfType || []) { + const fieldsWithMetadata = enrichFieldsWithECSInfo(fieldsOfType || [], metadata); + for (const field of fieldsWithMetadata || []) { cacheFields.set(field.name, field); } } }; + return { getFieldsByType: async ( expectedType: string | string[] = 'any', diff --git a/packages/kbn-esql-validation-autocomplete/src/shared/types.ts b/packages/kbn-esql-validation-autocomplete/src/shared/types.ts index d27b84dc4cb27..bc1e1d337e4b3 100644 --- a/packages/kbn-esql-validation-autocomplete/src/shared/types.ts +++ b/packages/kbn-esql-validation-autocomplete/src/shared/types.ts @@ -12,6 +12,22 @@ import type { ESQLRealField } from '../validation/types'; /** @internal **/ type CallbackFn = (ctx?: Options) => Result[] | Promise; +/** + * Partial fields metadata client, used to avoid circular dependency with @kbn/monaco +/** @internal **/ +export interface PartialFieldsMetadataClient { + find: ({ fieldNames, attributes }: { fieldNames?: string[]; attributes: string[] }) => Promise<{ + fields: Record< + string, + { + type: string; + source: string; + description?: string; + } + >; + }>; +} + /** @public **/ export interface ESQLSourceResult { name: string; @@ -29,6 +45,7 @@ export interface ESQLCallbacks { { name: string; sourceIndices: string[]; matchField: string; enrichFields: string[] } >; getPreferences?: () => Promise<{ histogramBarTarget: number }>; + getFieldsMetadata?: Promise; } export type ReasonTypes = 'missingCommand' | 'unsupportedFunction' | 'unknownFunction'; diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/types.ts b/packages/kbn-esql-validation-autocomplete/src/validation/types.ts index e81225d5ec7c2..99ce0f8ac5196 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/types.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/types.ts @@ -20,6 +20,7 @@ export interface ESQLVariable { export interface ESQLRealField { name: string; type: FieldType; + isEcs?: boolean; metadata?: { description?: string; }; diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts b/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts index 8d78851f8c17b..6e009d081c33a 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/validation.test.ts @@ -1709,6 +1709,7 @@ describe('validation logic', () => { getPolicies: /Unknown policy/, getFieldsFor: /Unknown column|Argument of|it is unsupported or not indexed/, getPreferences: /Unknown/, + getFieldsMetadata: /Unknown/, }; return excludedCallback.map((callback) => contentByCallback[callback]) || []; } diff --git a/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts b/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts index 468d5bb6e5233..428a2d1fcd4f5 100644 --- a/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts +++ b/packages/kbn-esql-validation-autocomplete/src/validation/validation.ts @@ -1097,6 +1097,7 @@ export const ignoreErrorsMap: Record = { getSources: ['unknownIndex'], getPolicies: ['unknownPolicy'], getPreferences: [], + getFieldsMetadata: [], }; /** diff --git a/packages/kbn-esql-validation-autocomplete/tsconfig.json b/packages/kbn-esql-validation-autocomplete/tsconfig.json index 3c87e005c394f..edbd153338a5f 100644 --- a/packages/kbn-esql-validation-autocomplete/tsconfig.json +++ b/packages/kbn-esql-validation-autocomplete/tsconfig.json @@ -14,7 +14,7 @@ "kbn_references": [ "@kbn/i18n", "@kbn/esql-ast", - "@kbn/utility-types", + "@kbn/utility-types" ], "exclude": [ "target/**/*", diff --git a/packages/kbn-monaco/src/esql/language.test.ts b/packages/kbn-monaco/src/esql/language.test.ts new file mode 100644 index 0000000000000..d368ec66fcea1 --- /dev/null +++ b/packages/kbn-monaco/src/esql/language.test.ts @@ -0,0 +1,133 @@ +/* + * 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 { PartialFieldsMetadataClient } from '@kbn/esql-validation-autocomplete/src/shared/types'; +import { monaco } from '../monaco_imports'; +import { ESQLLang } from './language'; + +describe('ESQLLang', () => { + describe('getSuggestionProvider', () => { + describe('resolveCompletionItem', () => { + it('should resolve completion item with field metadata', async () => { + const mockGetFieldsMetadata: Promise = Promise.resolve({ + find: jest.fn().mockResolvedValue({ + fields: { + 'test.field': { + type: 'keyword', + description: 'Test field description', + }, + }, + }), + }); + + const suggestionProvider = ESQLLang.getSuggestionProvider({ + getFieldsMetadata: mockGetFieldsMetadata, + }); + + const ecsItem: monaco.languages.CompletionItem = { + label: 'test.field', + kind: 4, + insertText: 'test.field', + range: new monaco.Range(0, 0, 0, 0), + }; + + const resolvedItem = await suggestionProvider.resolveCompletionItem!(ecsItem, {} as any); + + expect(resolvedItem).toEqual({ + ...ecsItem, + documentation: { + value: 'Test field description', + }, + }); + + const ecsItemWithKeywordSuffix: monaco.languages.CompletionItem = { + label: 'test.field.keyword', + kind: 4, + insertText: 'test.field.keyword', + range: new monaco.Range(0, 0, 0, 0), + }; + + const resolvedItemWithKeywordSuffix = await suggestionProvider.resolveCompletionItem!( + ecsItemWithKeywordSuffix, + {} as any + ); + + expect(resolvedItemWithKeywordSuffix).toEqual({ + ...ecsItemWithKeywordSuffix, + documentation: { + value: 'Test field description', + }, + }); + }); + + it('should return original item if field metadata is not available', async () => { + const mockGetFieldsMetadata: Promise = Promise.resolve({ + find: jest.fn().mockResolvedValue({ + fields: {}, + }), + }); + + const suggestionProvider = ESQLLang.getSuggestionProvider({ + getFieldsMetadata: mockGetFieldsMetadata, + }); + + const item: monaco.languages.CompletionItem = { + label: 'test.field', + kind: 4, + insertText: 'test.field', + range: new monaco.Range(0, 0, 0, 0), + }; + const resolvedItem = await suggestionProvider.resolveCompletionItem!(item, {} as any); + + expect(resolvedItem).toEqual(item); + }); + + it('should never call metadata find API if not needed', async () => { + const mockFind = jest.fn().mockResolvedValue({ + fields: {}, + }); + const mockGetFieldsMetadata: Promise = Promise.resolve({ + find: mockFind, + }); + + const suggestionProvider = ESQLLang.getSuggestionProvider({ + getFieldsMetadata: mockGetFieldsMetadata, + }); + + const notFieldItem: monaco.languages.CompletionItem = { + label: 'CASE', + kind: 1, + insertText: 'CASE', + range: new monaco.Range(0, 0, 0, 0), + }; + + const notFieldResolvedItem = await suggestionProvider.resolveCompletionItem!( + notFieldItem, + {} as any + ); + expect(mockFind).toBeCalledTimes(1); + expect(notFieldResolvedItem).toEqual(notFieldItem); + + mockFind.mockClear(); + const notECSFieldItem: monaco.languages.CompletionItem = { + label: 'not.ecs.field', + kind: 4, + insertText: 'not.ecs.field', + range: new monaco.Range(0, 0, 0, 0), + }; + const notECSFieldResolvedItem = await suggestionProvider.resolveCompletionItem!( + notECSFieldItem, + {} as any + ); + expect(mockFind).toBeCalledTimes(1); + expect(notECSFieldResolvedItem).toEqual(notECSFieldItem); + }); + }); + }); +}); diff --git a/packages/kbn-monaco/src/esql/language.ts b/packages/kbn-monaco/src/esql/language.ts index 424b4a5a13592..b94f38d697fcf 100644 --- a/packages/kbn-monaco/src/esql/language.ts +++ b/packages/kbn-monaco/src/esql/language.ts @@ -21,6 +21,9 @@ import { wrapAsMonacoSuggestions } from './lib/converters/suggestions'; import { wrapAsMonacoCodeActions } from './lib/converters/actions'; const workerProxyService = new WorkerProxyService(); +const removeKeywordSuffix = (name: string) => { + return name.endsWith('.keyword') ? name.slice(0, -8) : name; +}; export const ESQLLang: CustomLangModuleType = { ID: ESQL_LANG_ID, @@ -107,6 +110,42 @@ export const ESQLLang: CustomLangModuleType = { suggestions: wrapAsMonacoSuggestions(suggestions), }; }, + async resolveCompletionItem(item, token): Promise { + if (!callbacks?.getFieldsMetadata) return item; + const fieldsMetadataClient = await callbacks?.getFieldsMetadata; + + const fullEcsMetadataList = await fieldsMetadataClient?.find({ + attributes: ['type'], + }); + if (!fullEcsMetadataList || !fieldsMetadataClient || typeof item.label !== 'string') + return item; + + const strippedFieldName = removeKeywordSuffix(item.label); + if ( + // If item is not a field, no need to fetch metadata + item.kind === monaco.languages.CompletionItemKind.Variable && + // If not ECS, no need to fetch description + Object.hasOwn(fullEcsMetadataList?.fields, strippedFieldName) + ) { + const ecsMetadata = await fieldsMetadataClient.find({ + fieldNames: [strippedFieldName], + attributes: ['description'], + }); + + const fieldMetadata = ecsMetadata.fields[strippedFieldName]; + if (fieldMetadata && fieldMetadata.description) { + const completionItem: monaco.languages.CompletionItem = { + ...item, + documentation: { + value: fieldMetadata.description, + }, + }; + return completionItem; + } + } + + return item; + }, }; }, diff --git a/packages/kbn-text-based-editor/src/ecs_metadata_helper.ts b/packages/kbn-text-based-editor/src/ecs_metadata_helper.ts deleted file mode 100644 index 702c998738e46..0000000000000 --- a/packages/kbn-text-based-editor/src/ecs_metadata_helper.ts +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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 { ESQLRealField } from '@kbn/esql-validation-autocomplete'; -import type { FieldsMetadataPublicStart } from '@kbn/fields-metadata-plugin/public'; -import { chunk } from 'lodash'; - -const removeKeywordSuffix = (name: string) => { - return name.endsWith('.keyword') ? name.slice(0, -8) : name; -}; - -/** - * Returns columns with the metadata/description (e.g ECS info) - * if available - * - * @param columns - * @param fieldsMetadata - * @returns - */ -export async function getColumnsWithMetadata( - columns: Array>, - fieldsMetadata?: FieldsMetadataPublicStart -): Promise { - if (!fieldsMetadata) return columns; - - try { - const fieldsMetadataClient = await fieldsMetadata?.getClient(); - if (fieldsMetadataClient) { - const fields = await fieldsMetadataClient.find({ - fieldNames: columns.map((c) => c.name), - attributes: ['description', 'type'], - }); - - if (fields?.fields) { - return columns.map((c) => { - // Metadata services gives description for - // 'ecs.version' but not 'ecs.version.keyword' - // but both should show description if available - const metadata = fields.fields[removeKeywordSuffix(c.name)]; - - // Need to convert metadata's type (e.g. keyword) to ES|QL type (e.g. string) to check if they are the same - if (!metadata || (metadata?.type && metadata.type !== c.type)) return c; - return { - ...c, - metadata: { description: metadata.description }, - }; - }); - } - } - } catch (error) { - // eslint-disable-next-line no-console - console.error('Unable to fetch field metadata', error); - } - return columns; -} -/** - * Returns columns with the metadata/description (e.g ECS info) - * if available. Safely partition the requests to avoid 400 payload too big errors. - * - * @param columns - * @param fieldsMetadata - * @returns - */ -export async function getRateLimitedColumnsWithMetadata( - columns: Array>, - fieldsMetadata?: FieldsMetadataPublicStart, - maxFieldsPerRequest = 250, - maxConcurrentRequests = 10 -): Promise { - if (!fieldsMetadata) return columns; - - try { - // Chunking requests here since we are calling fieldsMetadata.find with list of fields, - // and we need to make sure payload is not too big, or else get 400 error - const chunkedColumns = chunk(columns, maxFieldsPerRequest); - const result: Array> = []; - // Also only make max of n at a time to avoid too many concurrent requests - for (let i = 0; i < chunkedColumns.length; i += maxConcurrentRequests) { - const cols = chunkedColumns.slice(i, i + maxConcurrentRequests); - const chunkResult = await Promise.allSettled( - cols.map((c) => getColumnsWithMetadata(c, fieldsMetadata)) - ); - result.push(...chunkResult); - } - - return result.flatMap((r, idx) => (r.status === 'fulfilled' ? r.value : chunkedColumns[idx])); - } catch (error) { - // eslint-disable-next-line no-console - console.error('Unable to fetch field metadata', error); - } - return columns; -} diff --git a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx index a01b452b378b1..d6936bde6fcbe 100644 --- a/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx +++ b/packages/kbn-text-based-editor/src/text_based_languages_editor.tsx @@ -51,7 +51,6 @@ import { EDITOR_MIN_HEIGHT, textBasedLanguageEditorStyles, } from './text_based_languages_editor.styles'; -import { getRateLimitedColumnsWithMetadata } from './ecs_metadata_helper'; import type { TextBasedLanguagesEditorProps, TextBasedEditorDeps } from './types'; import './overwrite.scss'; @@ -112,6 +111,7 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ const [isLanguagePopoverOpen, setIsLanguagePopoverOpen] = useState(false); const [isQueryLoading, setIsQueryLoading] = useState(true); const [abortController, setAbortController] = useState(new AbortController()); + // contains both client side validation and server messages const [editorMessages, setEditorMessages] = useState<{ errors: MonacoMessage[]; @@ -353,7 +353,8 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ type: c.meta.esType as FieldType, }; }) || []; - return await getRateLimitedColumnsWithMetadata(columns, fieldsMetadata); + + return columns; } catch (e) { // no action yet } @@ -373,6 +374,8 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ histogramBarTarget, }; }, + // @ts-expect-error To prevent circular type import, type defined here is partial of full client + getFieldsMetadata: fieldsMetadata?.getClient(), }; return callbacks; }, [ @@ -386,8 +389,8 @@ export const TextBasedLanguagesEditor = memo(function TextBasedLanguagesEditor({ expressions, abortController, indexManagementApiService, - fieldsMetadata, histogramBarTarget, + fieldsMetadata, ]); const queryRunButtonProperties = useMemo(() => {