From cff60f8a76a9538cf8e6645e6c432a4920d5a590 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Fri, 10 Jan 2020 16:34:01 +0300 Subject: [PATCH 01/11] [Data Plugin] combine autocomplete provider and suggestions provider Closes: #52843 --- .../autocomplete_provider_register.ts | 56 +++++++++++++++++++ .../public/autocomplete_provider/index.ts | 23 +------- .../public/autocomplete_provider/types.ts | 10 +--- src/plugins/data/public/index.ts | 13 +++-- src/plugins/data/public/plugin.ts | 5 +- src/plugins/data/public/types.ts | 7 +-- .../filter_editor/phrase_suggestor.tsx | 1 + .../query_string_input/query_string_input.tsx | 23 ++++---- .../typeahead/suggestion_component.test.tsx | 4 +- .../ui/typeahead/suggestion_component.tsx | 6 +- .../typeahead/suggestions_component.test.tsx | 4 +- .../ui/typeahead/suggestions_component.tsx | 6 +- .../components/shared/KueryBar/index.tsx | 11 +--- .../components/autocomplete_field/index.tsx | 4 +- .../autocomplete_field/suggestion_item.tsx | 4 +- .../public/components/table/table.tsx | 4 +- .../containers/with_kuery_autocompletion.tsx | 6 +- .../adapters/elasticsearch/adapter_types.ts | 7 ++- .../lib/adapters/elasticsearch/memory.ts | 6 +- .../public/lib/adapters/elasticsearch/rest.ts | 8 +-- .../public/lib/compose/memory.ts | 4 +- .../public/lib/elasticsearch.ts | 4 +- .../autocomplete_field/autocomplete_field.tsx | 4 +- .../autocomplete_field/suggestion_item.tsx | 4 +- .../containers/with_kuery_autocompletion.tsx | 10 +--- .../public/autocomplete_providers/index.js | 12 ++-- .../kuery_autocomplete/public/plugin.ts | 4 +- .../components/kql_filter_bar/utils.js | 4 -- .../autocomplete_field/index.test.tsx | 4 +- .../components/autocomplete_field/index.tsx | 4 +- .../autocomplete_field/suggestion_item.tsx | 4 +- .../containers/kuery_autocompletion/index.tsx | 14 ++--- .../components/functional/kuery_bar/index.tsx | 18 +++--- .../plugins/uptime/public/pages/overview.tsx | 7 ++- 34 files changed, 162 insertions(+), 143 deletions(-) create mode 100644 src/plugins/data/public/autocomplete_provider/autocomplete_provider_register.ts diff --git a/src/plugins/data/public/autocomplete_provider/autocomplete_provider_register.ts b/src/plugins/data/public/autocomplete_provider/autocomplete_provider_register.ts new file mode 100644 index 0000000000000..033716793c28b --- /dev/null +++ b/src/plugins/data/public/autocomplete_provider/autocomplete_provider_register.ts @@ -0,0 +1,56 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { AutocompleteProvider } from './types'; + +export class AutocompleteProviderRegister { + private readonly registeredProviders: Map = new Map(); + + /** @internal **/ + public clearProviders(): void { + this.registeredProviders.clear(); + } + + private addProvider = (language: string, provider: AutocompleteProvider): void => { + if (language && provider) { + this.registeredProviders.set(language, provider); + } + }; + + private getProvider = (language: string): AutocompleteProvider | undefined => + this.registeredProviders.get(language); + + /** @public **/ + public setup() { + return { + addProvider: this.addProvider, + + /** @obsolete **/ + /** please use "getProvider" only from the start contract **/ + getProvider: this.getProvider, + }; + } + + /** @public **/ + public start() { + return { + getProvider: this.getProvider, + }; + } +} diff --git a/src/plugins/data/public/autocomplete_provider/index.ts b/src/plugins/data/public/autocomplete_provider/index.ts index 6758bd7f379c1..81c6ae6a7dccd 100644 --- a/src/plugins/data/public/autocomplete_provider/index.ts +++ b/src/plugins/data/public/autocomplete_provider/index.ts @@ -16,25 +16,6 @@ * specific language governing permissions and limitations * under the License. */ -import { AutocompleteProvider } from './types'; -export class AutocompleteProviderRegister { - private readonly registeredProviders: Map = new Map(); - - /** @public **/ - public addProvider(language: string, provider: AutocompleteProvider): void { - if (language && provider) { - this.registeredProviders.set(language, provider); - } - } - - /** @public **/ - public getProvider(language: string): AutocompleteProvider | undefined { - return this.registeredProviders.get(language); - } - - /** @internal **/ - public clearProviders(): void { - this.registeredProviders.clear(); - } -} +export * from './autocomplete_provider_register'; +export * from './types'; diff --git a/src/plugins/data/public/autocomplete_provider/types.ts b/src/plugins/data/public/autocomplete_provider/types.ts index 389057f94144d..a06f09732a20d 100644 --- a/src/plugins/data/public/autocomplete_provider/types.ts +++ b/src/plugins/data/public/autocomplete_provider/types.ts @@ -20,17 +20,11 @@ import { AutocompleteProviderRegister } from '.'; import { IIndexPattern, IFieldType } from '../../common'; -export type AutocompletePublicPluginSetup = Pick< - AutocompleteProviderRegister, - 'addProvider' | 'getProvider' ->; -export type AutocompletePublicPluginStart = Pick; +export type AutocompletePublicPluginSetup = ReturnType; +export type AutocompletePublicPluginStart = ReturnType; /** @public **/ export type AutocompleteProvider = (args: { - config: { - get(configKey: string): any; - }; indexPatterns: IIndexPattern[]; boolFilter?: any; }) => GetSuggestions; diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 4b330600417e7..4e1e9c2b99698 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -18,6 +18,8 @@ */ import { PluginInitializerContext } from '../../../core/public'; +import * as autocomplete from './autocomplete_provider'; + export function plugin(initializerContext: PluginInitializerContext) { return new DataPublicPlugin(initializerContext); } @@ -49,11 +51,6 @@ export { TimeRange, } from '../common'; -/** - * Static code to be shared externally - * @public - */ -export * from './autocomplete_provider'; export * from './field_formats_provider'; export * from './index_patterns'; export * from './search'; @@ -97,3 +94,9 @@ export { // Export plugin after all other imports import { DataPublicPlugin } from './plugin'; export { DataPublicPlugin as Plugin }; + +/** + * Static code to be shared externally + * @public + */ +export { autocomplete }; diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index cd55048ca527f..5cca52a79036f 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -62,7 +62,7 @@ export class DataPublicPlugin implements Plugin { diff --git a/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx b/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx index 61290cc16b8a8..7875fbaa9cdc2 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx +++ b/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx @@ -69,6 +69,7 @@ export class PhraseSuggestorUI extends Component return; } this.setState({ isLoading: true }); + // todo: value suggestions const suggestions = await this.services.data.getSuggestions(indexPattern.title, field, value); this.setState({ suggestions, isLoading: false }); }, 500); diff --git a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx index 16b22a164f2f0..463fd5b4c4de3 100644 --- a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx +++ b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx @@ -35,8 +35,7 @@ import { InjectedIntl, injectI18n, FormattedMessage } from '@kbn/i18n/react'; import { debounce, compact, isEqual } from 'lodash'; import { Toast } from 'src/core/public'; import { - AutocompleteSuggestion, - AutocompleteSuggestionType, + autocomplete, IDataPluginServices, IIndexPattern, PersistedLog, @@ -71,7 +70,7 @@ interface Props { interface State { isSuggestionsVisible: boolean; index: number | null; - suggestions: AutocompleteSuggestion[]; + suggestions: autocomplete.AutocompleteSuggestion[]; suggestionLimit: number; selectionStart: number | null; selectionEnd: number | null; @@ -90,7 +89,7 @@ const KEY_CODES = { END: 35, }; -const recentSearchType: AutocompleteSuggestionType = 'recentSearch'; +const recentSearchType: autocomplete.AutocompleteSuggestionType = 'recentSearch'; export class QueryStringInputUI extends Component { public state: State = { @@ -138,7 +137,6 @@ export class QueryStringInputUI extends Component { return; } - const uiSettings = this.services.uiSettings; const language = this.props.query.language; const queryString = this.getQueryString(); @@ -154,10 +152,7 @@ export class QueryStringInputUI extends Component { } const indexPatterns = this.state.indexPatterns; - const getAutocompleteSuggestions = autocompleteProvider({ - config: uiSettings, - indexPatterns, - }); + const getAutocompleteSuggestions = autocompleteProvider({ indexPatterns }); const { selectionStart, selectionEnd } = this.inputRef; if (selectionStart === null || selectionEnd === null) { @@ -167,7 +162,7 @@ export class QueryStringInputUI extends Component { try { if (this.abortController) this.abortController.abort(); this.abortController = new AbortController(); - const suggestions: AutocompleteSuggestion[] = await getAutocompleteSuggestions({ + const suggestions: autocomplete.AutocompleteSuggestion[] = await getAutocompleteSuggestions({ query: queryString, selectionStart, selectionEnd, @@ -321,7 +316,7 @@ export class QueryStringInputUI extends Component { } }; - private selectSuggestion = (suggestion: AutocompleteSuggestion) => { + private selectSuggestion = (suggestion: autocomplete.AutocompleteSuggestion) => { if (!this.inputRef) { return; } @@ -351,7 +346,9 @@ export class QueryStringInputUI extends Component { } }; - private handleNestedFieldSyntaxNotification = (suggestion: AutocompleteSuggestion) => { + private handleNestedFieldSyntaxNotification = ( + suggestion: autocomplete.AutocompleteSuggestion + ) => { if ( 'field' in suggestion && suggestion.field.subType && @@ -453,7 +450,7 @@ export class QueryStringInputUI extends Component { } }; - private onClickSuggestion = (suggestion: AutocompleteSuggestion) => { + private onClickSuggestion = (suggestion: autocomplete.AutocompleteSuggestion) => { if (!this.inputRef) { return; } diff --git a/src/plugins/data/public/ui/typeahead/suggestion_component.test.tsx b/src/plugins/data/public/ui/typeahead/suggestion_component.test.tsx index 591176bf133fa..7b3d61e2f0186 100644 --- a/src/plugins/data/public/ui/typeahead/suggestion_component.test.tsx +++ b/src/plugins/data/public/ui/typeahead/suggestion_component.test.tsx @@ -19,14 +19,14 @@ import { mount, shallow } from 'enzyme'; import React from 'react'; -import { AutocompleteSuggestion } from '../..'; +import { autocomplete } from '../..'; import { SuggestionComponent } from './suggestion_component'; const noop = () => { return; }; -const mockSuggestion: AutocompleteSuggestion = { +const mockSuggestion: autocomplete.AutocompleteSuggestion = { description: 'This is not a helpful suggestion', end: 0, start: 42, diff --git a/src/plugins/data/public/ui/typeahead/suggestion_component.tsx b/src/plugins/data/public/ui/typeahead/suggestion_component.tsx index fd29de4573ff0..027faff11dac8 100644 --- a/src/plugins/data/public/ui/typeahead/suggestion_component.tsx +++ b/src/plugins/data/public/ui/typeahead/suggestion_component.tsx @@ -20,7 +20,7 @@ import { EuiIcon } from '@elastic/eui'; import classNames from 'classnames'; import React, { FunctionComponent } from 'react'; -import { AutocompleteSuggestion } from '../..'; +import { autocomplete } from '../..'; function getEuiIconType(type: string) { switch (type) { @@ -40,10 +40,10 @@ function getEuiIconType(type: string) { } interface Props { - onClick: (suggestion: AutocompleteSuggestion) => void; + onClick: (suggestion: autocomplete.AutocompleteSuggestion) => void; onMouseEnter: () => void; selected: boolean; - suggestion: AutocompleteSuggestion; + suggestion: autocomplete.AutocompleteSuggestion; innerRef: (node: HTMLDivElement) => void; ariaId: string; } diff --git a/src/plugins/data/public/ui/typeahead/suggestions_component.test.tsx b/src/plugins/data/public/ui/typeahead/suggestions_component.test.tsx index 7fb2fdf25104a..fcd750ee65a45 100644 --- a/src/plugins/data/public/ui/typeahead/suggestions_component.test.tsx +++ b/src/plugins/data/public/ui/typeahead/suggestions_component.test.tsx @@ -19,7 +19,7 @@ import { mount, shallow } from 'enzyme'; import React from 'react'; -import { AutocompleteSuggestion } from '../..'; +import { autocomplete } from '../..'; import { SuggestionComponent } from './suggestion_component'; import { SuggestionsComponent } from './suggestions_component'; @@ -27,7 +27,7 @@ const noop = () => { return; }; -const mockSuggestions: AutocompleteSuggestion[] = [ +const mockSuggestions: autocomplete.AutocompleteSuggestion[] = [ { description: 'This is not a helpful suggestion', end: 0, diff --git a/src/plugins/data/public/ui/typeahead/suggestions_component.tsx b/src/plugins/data/public/ui/typeahead/suggestions_component.tsx index e4cccbcde4fb8..099f914824641 100644 --- a/src/plugins/data/public/ui/typeahead/suggestions_component.tsx +++ b/src/plugins/data/public/ui/typeahead/suggestions_component.tsx @@ -19,15 +19,15 @@ import { isEmpty } from 'lodash'; import React, { Component } from 'react'; -import { AutocompleteSuggestion } from '../..'; +import { autocomplete } from '../..'; import { SuggestionComponent } from './suggestion_component'; interface Props { index: number | null; - onClick: (suggestion: AutocompleteSuggestion) => void; + onClick: (suggestion: autocomplete.AutocompleteSuggestion) => void; onMouseEnter: (index: number) => void; show: boolean; - suggestions: AutocompleteSuggestion[]; + suggestions: autocomplete.AutocompleteSuggestion[]; loadMore: () => void; } diff --git a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx index 67bff86c8ccdf..c7a120bc269d8 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx @@ -18,8 +18,7 @@ import { history } from '../../../utils/history'; import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; import { useDynamicIndexPattern } from '../../../hooks/useDynamicIndexPattern'; import { - AutocompleteProvider, - AutocompleteSuggestion, + autocomplete as autocompleteNamespace, esKuery, IIndexPattern } from '../../../../../../../../src/plugins/data/public'; @@ -29,7 +28,7 @@ const Container = styled.div` `; interface State { - suggestions: AutocompleteSuggestion[]; + suggestions: autocompleteNamespace.AutocompleteSuggestion[]; isLoadingSuggestions: boolean; } @@ -43,17 +42,13 @@ function getSuggestions( selectionStart: number, indexPattern: IIndexPattern, boolFilter: unknown, - autocompleteProvider?: AutocompleteProvider + autocompleteProvider?: autocompleteNamespace.AutocompleteProvider ) { if (!autocompleteProvider) { return []; } - const config = { - get: () => true - }; const getAutocompleteSuggestions = autocompleteProvider({ - config, indexPatterns: [indexPattern], boolFilter }); diff --git a/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/index.tsx b/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/index.tsx index 1f49711ae5e4a..c36020f7921c8 100644 --- a/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/index.tsx +++ b/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/index.tsx @@ -13,7 +13,7 @@ import { import React from 'react'; import styled from 'styled-components'; -import { AutocompleteSuggestion } from '../../../../../../../src/plugins/data/public'; +import { autocomplete } from '../../../../../../../src/plugins/data/public'; import { composeStateUpdaters } from '../../utils/typed_react'; import { SuggestionItem } from './suggestion_item'; @@ -25,7 +25,7 @@ interface AutocompleteFieldProps { onSubmit?: (value: string) => void; onChange?: (value: string) => void; placeholder?: string; - suggestions: AutocompleteSuggestion[]; + suggestions: autocomplete.AutocompleteSuggestion[]; value: string; } diff --git a/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/suggestion_item.tsx b/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/suggestion_item.tsx index a753a944a2ecb..a1c24d65beda6 100644 --- a/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/suggestion_item.tsx +++ b/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/suggestion_item.tsx @@ -9,13 +9,13 @@ import { tint } from 'polished'; import React from 'react'; import styled from 'styled-components'; -import { AutocompleteSuggestion } from '../../../../../../../src/plugins/data/public'; +import { autocomplete } from '../../../../../../../src/plugins/data/public'; interface SuggestionItemProps { isSelected?: boolean; onClick?: React.MouseEventHandler; onMouseEnter?: React.MouseEventHandler; - suggestion: AutocompleteSuggestion; + suggestion: autocomplete.AutocompleteSuggestion; } export const SuggestionItem: React.FC = props => { diff --git a/x-pack/legacy/plugins/beats_management/public/components/table/table.tsx b/x-pack/legacy/plugins/beats_management/public/components/table/table.tsx index 26ddd682405cb..7370c057f8317 100644 --- a/x-pack/legacy/plugins/beats_management/public/components/table/table.tsx +++ b/x-pack/legacy/plugins/beats_management/public/components/table/table.tsx @@ -8,7 +8,7 @@ import { EuiBasicTable, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eu import { i18n } from '@kbn/i18n'; import React from 'react'; import styled from 'styled-components'; -import { AutocompleteSuggestion } from '../../../../../../../src/plugins/data/public'; +import { autocomplete } from '../../../../../../../src/plugins/data/public'; import { TABLE_CONFIG } from '../../../common/constants'; import { AutocompleteField } from '../autocomplete_field/index'; import { ControlSchema } from './action_schema'; @@ -31,7 +31,7 @@ export interface KueryBarProps { loadSuggestions: (value: string, cursorPosition: number, maxCount?: number) => void; onChange?: (value: string) => void; onSubmit?: (value: string) => void; - suggestions: AutocompleteSuggestion[]; + suggestions: autocomplete.AutocompleteSuggestion[]; value: string; } diff --git a/x-pack/legacy/plugins/beats_management/public/containers/with_kuery_autocompletion.tsx b/x-pack/legacy/plugins/beats_management/public/containers/with_kuery_autocompletion.tsx index 2ac20438536c8..25d5bd78f9b70 100644 --- a/x-pack/legacy/plugins/beats_management/public/containers/with_kuery_autocompletion.tsx +++ b/x-pack/legacy/plugins/beats_management/public/containers/with_kuery_autocompletion.tsx @@ -6,7 +6,7 @@ import React from 'react'; -import { AutocompleteSuggestion } from '../../../../../../src/plugins/data/public'; +import { autocomplete } from '../../../../../../src/plugins/data/public'; import { FrontendLibs } from '../lib/types'; import { RendererFunction } from '../utils/typed_react'; @@ -17,7 +17,7 @@ interface WithKueryAutocompletionLifecycleProps { children: RendererFunction<{ isLoadingSuggestions: boolean; loadSuggestions: (expression: string, cursorPosition: number, maxSuggestions?: number) => void; - suggestions: AutocompleteSuggestion[]; + suggestions: autocomplete.AutocompleteSuggestion[]; }>; } @@ -28,7 +28,7 @@ interface WithKueryAutocompletionLifecycleState { expression: string; cursorPosition: number; } | null; - suggestions: AutocompleteSuggestion[]; + suggestions: autocomplete.AutocompleteSuggestion[]; } export class WithKueryAutocompletion extends React.Component< diff --git a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/adapter_types.ts b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/adapter_types.ts index 4f4ce70e817c6..e261d87a71d03 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/adapter_types.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/adapter_types.ts @@ -3,10 +3,13 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ -import { AutocompleteSuggestion } from '../../../../../../../../src/plugins/data/public'; +import { autocomplete } from '../../../../../../../../src/plugins/data/public'; export interface ElasticsearchAdapter { convertKueryToEsQuery: (kuery: string) => Promise; - getSuggestions: (kuery: string, selectionStart: any) => Promise; + getSuggestions: ( + kuery: string, + selectionStart: any + ) => Promise; isKueryValid(kuery: string): boolean; } diff --git a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/memory.ts b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/memory.ts index e001bf6c6e844..e357bbec1c793 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/memory.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/memory.ts @@ -4,14 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { AutocompleteSuggestion } from '../../../../../../../../src/plugins/data/public'; +import { autocomplete } from '../../../../../../../../src/plugins/data/public'; import { ElasticsearchAdapter } from './adapter_types'; export class MemoryElasticsearchAdapter implements ElasticsearchAdapter { constructor( private readonly mockIsKueryValid: (kuery: string) => boolean, private readonly mockKueryToEsQuery: (kuery: string) => string, - private readonly suggestions: AutocompleteSuggestion[] + private readonly suggestions: autocomplete.AutocompleteSuggestion[] ) {} public isKueryValid(kuery: string): boolean { @@ -23,7 +23,7 @@ export class MemoryElasticsearchAdapter implements ElasticsearchAdapter { public async getSuggestions( kuery: string, selectionStart: any - ): Promise { + ): Promise { return this.suggestions; } } diff --git a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts index 8771181639f4d..92a115148e35d 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts @@ -7,7 +7,7 @@ import { isEmpty } from 'lodash'; import { npStart } from 'ui/new_platform'; import { ElasticsearchAdapter } from './adapter_types'; -import { AutocompleteSuggestion, esKuery } from '../../../../../../../../src/plugins/data/public'; +import { autocomplete, esKuery } from '../../../../../../../../src/plugins/data/public'; const getAutocompleteProvider = (language: string) => npStart.plugins.data.autocomplete.getProvider(language); @@ -36,18 +36,14 @@ export class RestElasticsearchAdapter implements ElasticsearchAdapter { public async getSuggestions( kuery: string, selectionStart: any - ): Promise { + ): Promise { const autocompleteProvider = getAutocompleteProvider('kuery'); if (!autocompleteProvider) { return []; } - const config = { - get: () => true, - }; const indexPattern = await this.getIndexPattern(); const getAutocompleteSuggestions = autocompleteProvider({ - config, indexPatterns: [indexPattern], boolFilter: null, }); diff --git a/x-pack/legacy/plugins/beats_management/public/lib/compose/memory.ts b/x-pack/legacy/plugins/beats_management/public/lib/compose/memory.ts index f357e698afc3a..9d4db2f7feed3 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/compose/memory.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/compose/memory.ts @@ -24,14 +24,14 @@ import { TagsLib } from '../tags'; import { FrontendLibs } from '../types'; import { MemoryElasticsearchAdapter } from './../adapters/elasticsearch/memory'; import { ElasticsearchLib } from './../elasticsearch'; -import { AutocompleteSuggestion } from '../../../../../../../src/plugins/data/public'; +import { autocomplete } from '../../../../../../../src/plugins/data/public'; const onKibanaReady = uiModules.get('kibana').run; export function compose( mockIsKueryValid: (kuery: string) => boolean, mockKueryToEsQuery: (kuery: string) => string, - suggestions: AutocompleteSuggestion[] + suggestions: autocomplete.AutocompleteSuggestion[] ): FrontendLibs { const esAdapter = new MemoryElasticsearchAdapter( mockIsKueryValid, diff --git a/x-pack/legacy/plugins/beats_management/public/lib/elasticsearch.ts b/x-pack/legacy/plugins/beats_management/public/lib/elasticsearch.ts index 0897dfd9c1392..4310cfe1647dd 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/elasticsearch.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/elasticsearch.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { AutocompleteSuggestion } from '../../../../../../src/plugins/data/public'; +import { autocomplete } from '../../../../../../src/plugins/data/public'; import { ElasticsearchAdapter } from './adapters/elasticsearch/adapter_types'; interface HiddenFields { @@ -35,7 +35,7 @@ export class ElasticsearchLib { kuery: string, selectionStart: any, fieldPrefix?: string - ): Promise { + ): Promise { const suggestions = await this.adapter.getSuggestions(kuery, selectionStart); const filteredSuggestions = suggestions.filter(suggestion => { diff --git a/x-pack/legacy/plugins/infra/public/components/autocomplete_field/autocomplete_field.tsx b/x-pack/legacy/plugins/infra/public/components/autocomplete_field/autocomplete_field.tsx index 4c215835ca240..70f0d56a1996f 100644 --- a/x-pack/legacy/plugins/infra/public/components/autocomplete_field/autocomplete_field.tsx +++ b/x-pack/legacy/plugins/infra/public/components/autocomplete_field/autocomplete_field.tsx @@ -12,7 +12,7 @@ import { } from '@elastic/eui'; import React from 'react'; -import { AutocompleteSuggestion } from '../../../../../../../src/plugins/data/public'; +import { autocomplete } from '../../../../../../../src/plugins/data/public'; import euiStyled from '../../../../../common/eui_styled_components'; import { composeStateUpdaters } from '../../utils/typed_react'; @@ -25,7 +25,7 @@ interface AutocompleteFieldProps { onSubmit?: (value: string) => void; onChange?: (value: string) => void; placeholder?: string; - suggestions: AutocompleteSuggestion[]; + suggestions: autocomplete.AutocompleteSuggestion[]; value: string; autoFocus?: boolean; 'aria-label'?: string; diff --git a/x-pack/legacy/plugins/infra/public/components/autocomplete_field/suggestion_item.tsx b/x-pack/legacy/plugins/infra/public/components/autocomplete_field/suggestion_item.tsx index 0c29b1f51b07e..4b69ec238c328 100644 --- a/x-pack/legacy/plugins/infra/public/components/autocomplete_field/suggestion_item.tsx +++ b/x-pack/legacy/plugins/infra/public/components/autocomplete_field/suggestion_item.tsx @@ -8,14 +8,14 @@ import { EuiIcon } from '@elastic/eui'; import { transparentize } from 'polished'; import React from 'react'; -import { AutocompleteSuggestion } from '../../../../../../../src/plugins/data/public'; +import { autocomplete } from '../../../../../../../src/plugins/data/public'; import euiStyled from '../../../../../common/eui_styled_components'; interface Props { isSelected?: boolean; onClick?: React.MouseEventHandler; onMouseEnter?: React.MouseEventHandler; - suggestion: AutocompleteSuggestion; + suggestion: autocomplete.AutocompleteSuggestion; } export const SuggestionItem: React.FC = props => { diff --git a/x-pack/legacy/plugins/infra/public/containers/with_kuery_autocompletion.tsx b/x-pack/legacy/plugins/infra/public/containers/with_kuery_autocompletion.tsx index ba072b754b957..f03ddc6dd6a8d 100644 --- a/x-pack/legacy/plugins/infra/public/containers/with_kuery_autocompletion.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/with_kuery_autocompletion.tsx @@ -6,7 +6,7 @@ import React from 'react'; import { npStart } from 'ui/new_platform'; -import { AutocompleteSuggestion, IIndexPattern } from 'src/plugins/data/public'; +import { autocomplete, IIndexPattern } from 'src/plugins/data/public'; import { RendererFunction } from '../utils/typed_react'; const getAutocompleteProvider = (language: string) => @@ -16,7 +16,7 @@ interface WithKueryAutocompletionLifecycleProps { children: RendererFunction<{ isLoadingSuggestions: boolean; loadSuggestions: (expression: string, cursorPosition: number, maxSuggestions?: number) => void; - suggestions: AutocompleteSuggestion[]; + suggestions: autocomplete.AutocompleteSuggestion[]; }>; indexPattern: IIndexPattern; } @@ -28,7 +28,7 @@ interface WithKueryAutocompletionLifecycleState { expression: string; cursorPosition: number; } | null; - suggestions: AutocompleteSuggestion[]; + suggestions: autocomplete.AutocompleteSuggestion[]; } export class WithKueryAutocompletion extends React.Component< @@ -57,16 +57,12 @@ export class WithKueryAutocompletion extends React.Component< ) => { const { indexPattern } = this.props; const autocompletionProvider = getAutocompleteProvider('kuery'); - const config = { - get: () => true, - }; if (!autocompletionProvider) { return; } const getSuggestions = autocompletionProvider({ - config, indexPatterns: [indexPattern], boolFilter: [], }); diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/index.js b/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/index.js index a5fb4eff388f7..289d1f24702f3 100644 --- a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/index.js +++ b/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/index.js @@ -17,10 +17,14 @@ function dedup(suggestions) { return uniq(suggestions, ({ type, text, start, end }) => [type, text, start, end].join('|')); } -export const kueryProvider = ({ config, indexPatterns, boolFilter }) => { - const getSuggestionsByType = mapValues({ field, value, operator, conjunction }, provider => { - return provider({ config, indexPatterns, boolFilter }); - }); +export const setupKueryProvider = ({ uiSettings }) => ({ indexPatterns, boolFilter }) => { + const getSuggestionsByType = mapValues({ field, value, operator, conjunction }, provider => + provider({ + config: uiSettings, + indexPatterns, + boolFilter, + }) + ); return function getSuggestions({ query, selectionStart, selectionEnd, signal }) { const cursoredQuery = `${query.substr(0, selectionStart)}${cursorSymbol}${query.substr( diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/plugin.ts b/x-pack/legacy/plugins/kuery_autocomplete/public/plugin.ts index ded66a7c6e8f0..c4b75cd9dfcf8 100644 --- a/x-pack/legacy/plugins/kuery_autocomplete/public/plugin.ts +++ b/x-pack/legacy/plugins/kuery_autocomplete/public/plugin.ts @@ -8,7 +8,7 @@ import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'src/core import { Plugin as DataPublicPlugin } from '../../../../../src/plugins/data/public'; // @ts-ignore -import { kueryProvider } from './autocomplete_providers'; +import { setupKueryProvider } from './autocomplete_providers'; /** @internal */ export interface KueryAutocompletePluginSetupDependencies { @@ -26,6 +26,8 @@ export class KueryAutocompletePlugin implements Plugin, void> { } public async setup(core: CoreSetup, { data }: KueryAutocompletePluginSetupDependencies) { + const kueryProvider = setupKueryProvider(core); + data.autocomplete.addProvider(KUERY_LANGUAGE_NAME, kueryProvider); } diff --git a/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/utils.js b/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/utils.js index c007e8bd05c5e..419a4d31e344b 100644 --- a/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/utils.js +++ b/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/utils.js @@ -13,12 +13,8 @@ export async function getSuggestions(query, selectionStart, indexPattern, boolFi if (!autocompleteProvider) { return []; } - const config = { - get: () => true, - }; const getAutocompleteSuggestions = autocompleteProvider({ - config, indexPatterns: [indexPattern], boolFilter, }); diff --git a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.test.tsx index 27e87d25e286f..4a320b72490ad 100644 --- a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.test.tsx @@ -10,13 +10,13 @@ import { mount, shallow } from 'enzyme'; import { noop } from 'lodash/fp'; import React from 'react'; import { ThemeProvider } from 'styled-components'; -import { AutocompleteSuggestion } from '../../../../../../../src/plugins/data/public'; +import { autocomplete } from '../../../../../../../src/plugins/data/public'; import { TestProviders } from '../../mock'; import { AutocompleteField } from '.'; -const mockAutoCompleteData: AutocompleteSuggestion[] = [ +const mockAutoCompleteData: autocomplete.AutocompleteSuggestion[] = [ { type: 'field', text: 'agent.ephemeral_id ', diff --git a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.tsx b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.tsx index 124ef26602f35..c733702312fa8 100644 --- a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.tsx @@ -11,7 +11,7 @@ import { EuiPanel, } from '@elastic/eui'; import React from 'react'; -import { AutocompleteSuggestion } from '../../../../../../../src/plugins/data/public'; +import { autocomplete } from '../../../../../../../src/plugins/data/public'; import euiStyled from '../../../../../common/eui_styled_components'; @@ -25,7 +25,7 @@ interface AutocompleteFieldProps { onSubmit?: (value: string) => void; onChange?: (value: string) => void; placeholder?: string; - suggestions: AutocompleteSuggestion[]; + suggestions: autocomplete.AutocompleteSuggestion[]; value: string; } diff --git a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/suggestion_item.tsx b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/suggestion_item.tsx index aaf7be2f7f5a6..a67c921e87998 100644 --- a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/suggestion_item.tsx +++ b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/suggestion_item.tsx @@ -9,13 +9,13 @@ import { transparentize } from 'polished'; import React from 'react'; import styled from 'styled-components'; import euiStyled from '../../../../../common/eui_styled_components'; -import { AutocompleteSuggestion } from '../../../../../../../src/plugins/data/public'; +import { autocomplete } from '../../../../../../../src/plugins/data/public'; interface SuggestionItemProps { isSelected?: boolean; onClick?: React.MouseEventHandler; onMouseEnter?: React.MouseEventHandler; - suggestion: AutocompleteSuggestion; + suggestion: autocomplete.AutocompleteSuggestion; } export const SuggestionItem = React.memo( diff --git a/x-pack/legacy/plugins/siem/public/containers/kuery_autocompletion/index.tsx b/x-pack/legacy/plugins/siem/public/containers/kuery_autocompletion/index.tsx index 6361f7abcf977..5e2106bf44a69 100644 --- a/x-pack/legacy/plugins/siem/public/containers/kuery_autocompletion/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/kuery_autocompletion/index.tsx @@ -5,10 +5,7 @@ */ import React, { useState } from 'react'; -import { - AutocompleteSuggestion, - IIndexPattern, -} from '../../../../../../../src/plugins/data/public'; +import { autocomplete, IIndexPattern } from '../../../../../../../src/plugins/data/public'; import { useKibana } from '../../lib/kibana'; type RendererResult = React.ReactElement | null; @@ -18,7 +15,7 @@ interface KueryAutocompletionLifecycleProps { children: RendererFunction<{ isLoadingSuggestions: boolean; loadSuggestions: (expression: string, cursorPosition: number, maxSuggestions?: number) => void; - suggestions: AutocompleteSuggestion[]; + suggestions: autocomplete.AutocompleteSuggestion[]; }>; indexPattern: IIndexPattern; } @@ -33,7 +30,7 @@ export const KueryAutocompletion = React.memo const [currentRequest, setCurrentRequest] = useState( null ); - const [suggestions, setSuggestions] = useState([]); + const [suggestions, setSuggestions] = useState([]); const kibana = useKibana(); const loadSuggestions = async ( expression: string, @@ -41,15 +38,12 @@ export const KueryAutocompletion = React.memo maxSuggestions?: number ) => { const autocompletionProvider = kibana.services.data.autocomplete.getProvider('kuery'); - const config = { - get: () => true, - }; + if (!autocompletionProvider) { return; } const getSuggestions = autocompletionProvider({ - config, indexPatterns: [indexPattern], boolFilter: [], }); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx index 731f560d315d6..b0d57e5c3da97 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx @@ -13,10 +13,9 @@ import { Typeahead } from './typeahead'; import { useUrlParams } from '../../../hooks'; import { toStaticIndexPattern } from '../../../lib/helper'; import { - AutocompleteProviderRegister, - AutocompleteSuggestion, esKuery, IIndexPattern, + autocomplete as autocompleteNamespace, } from '../../../../../../../../src/plugins/data/public'; import { useIndexPattern } from '../../../hooks'; @@ -25,7 +24,7 @@ const Container = styled.div` `; interface State { - suggestions: AutocompleteSuggestion[]; + suggestions: autocompleteNamespace.AutocompleteSuggestion[]; isLoadingIndexPattern: boolean; } @@ -38,18 +37,14 @@ function getSuggestions( query: string, selectionStart: number, apmIndexPattern: IIndexPattern, - autocomplete: Pick + autocomplete: autocompleteNamespace.AutocompletePublicPluginStart ) { const autocompleteProvider = autocomplete.getProvider('kuery'); if (!autocompleteProvider) { return []; } - const config = { - get: () => true, - }; const getAutocompleteSuggestions = autocompleteProvider({ - config, indexPatterns: [apmIndexPattern], }); @@ -62,7 +57,7 @@ function getSuggestions( } interface Props { - autocomplete: Pick; + autocomplete: autocompleteNamespace.AutocompletePublicPluginStart; } export function KueryBar({ autocomplete }: Props) { @@ -106,7 +101,10 @@ export function KueryBar({ autocomplete }: Props) { autocomplete ); suggestions = suggestions - .filter((suggestion: AutocompleteSuggestion) => !startsWith(suggestion.text, 'span.')) + .filter( + (suggestion: autocompleteNamespace.AutocompleteSuggestion) => + !startsWith(suggestion.text, 'span.') + ) .slice(0, 15); if (currentRequest !== currentRequestCheck) { diff --git a/x-pack/legacy/plugins/uptime/public/pages/overview.tsx b/x-pack/legacy/plugins/uptime/public/pages/overview.tsx index 34bcfb994cd48..6fa425a329827 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/overview.tsx +++ b/x-pack/legacy/plugins/uptime/public/pages/overview.tsx @@ -23,11 +23,14 @@ import { useIndexPattern, useUrlParams, useUptimeTelemetry, UptimePage } from '. import { stringifyUrlParams } from '../lib/helper/stringify_url_params'; import { useTrackPageview } from '../../../infra/public'; import { combineFiltersAndUserSearch, stringifyKueries, toStaticIndexPattern } from '../lib/helper'; -import { AutocompleteProviderRegister, esKuery } from '../../../../../../src/plugins/data/public'; +import { + autocomplete as autocompleteNamespace, + esKuery, +} from '../../../../../../src/plugins/data/public'; interface OverviewPageProps { basePath: string; - autocomplete: Pick; + autocomplete: autocompleteNamespace.AutocompletePublicPluginStart; history: any; location: { pathname: string; From ca2bd9348ab453534a36f56c74a50ceb4ff3b2c3 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Fri, 10 Jan 2020 19:09:37 +0300 Subject: [PATCH 02/11] [Data Plugin] combine autocomplete provider and suggestions provider - add skeleton for SuggestionsProvider --- .../autocomplete_provider_register.ts | 24 ++++---- .../providers/query_syntax_provider.ts | 59 +++++++++++++++++++ .../providers/suggestions_provider.ts | 21 +++++++ .../public/autocomplete_provider/types.ts | 54 ++++++----------- .../query_string_input/query_string_input.tsx | 14 ++--- .../typeahead/suggestion_component.test.tsx | 2 +- .../ui/typeahead/suggestion_component.tsx | 4 +- .../typeahead/suggestions_component.test.tsx | 2 +- .../ui/typeahead/suggestions_component.tsx | 4 +- .../components/shared/KueryBar/index.tsx | 12 ++-- .../components/autocomplete_field/index.tsx | 2 +- .../autocomplete_field/suggestion_item.tsx | 2 +- .../public/components/table/table.tsx | 2 +- .../containers/with_kuery_autocompletion.tsx | 4 +- .../adapters/elasticsearch/adapter_types.ts | 2 +- .../lib/adapters/elasticsearch/memory.ts | 4 +- .../public/lib/adapters/elasticsearch/rest.ts | 4 +- .../public/lib/compose/memory.ts | 2 +- .../public/lib/elasticsearch.ts | 2 +- .../autocomplete_field/autocomplete_field.tsx | 2 +- .../autocomplete_field/suggestion_item.tsx | 2 +- .../containers/with_kuery_autocompletion.tsx | 6 +- .../kuery_autocomplete/public/plugin.ts | 2 +- .../components/kql_filter_bar/utils.js | 3 +- .../autocomplete_field/index.test.tsx | 2 +- .../components/autocomplete_field/index.tsx | 2 +- .../autocomplete_field/suggestion_item.tsx | 2 +- .../containers/kuery_autocompletion/index.tsx | 8 ++- .../components/functional/kuery_bar/index.tsx | 6 +- .../legacy/plugins/uptime/public/routes.tsx | 4 +- 30 files changed, 165 insertions(+), 94 deletions(-) create mode 100644 src/plugins/data/public/autocomplete_provider/providers/query_syntax_provider.ts create mode 100644 src/plugins/data/public/autocomplete_provider/providers/suggestions_provider.ts diff --git a/src/plugins/data/public/autocomplete_provider/autocomplete_provider_register.ts b/src/plugins/data/public/autocomplete_provider/autocomplete_provider_register.ts index 033716793c28b..485aa8ae07c7e 100644 --- a/src/plugins/data/public/autocomplete_provider/autocomplete_provider_register.ts +++ b/src/plugins/data/public/autocomplete_provider/autocomplete_provider_register.ts @@ -17,40 +17,44 @@ * under the License. */ -import { AutocompleteProvider } from './types'; +import { QuerySyntaxProvider, SuggestionsProvider } from './types'; export class AutocompleteProviderRegister { - private readonly registeredProviders: Map = new Map(); + private readonly querySyntaxProviders: Map = new Map(); /** @internal **/ public clearProviders(): void { - this.registeredProviders.clear(); + this.querySyntaxProviders.clear(); } - private addProvider = (language: string, provider: AutocompleteProvider): void => { + private addQuerySyntaxProvider = (language: string, provider: QuerySyntaxProvider): void => { if (language && provider) { - this.registeredProviders.set(language, provider); + this.querySyntaxProviders.set(language, provider); } }; - private getProvider = (language: string): AutocompleteProvider | undefined => - this.registeredProviders.get(language); + private getQuerySyntaxProvider = (language: string): QuerySyntaxProvider | undefined => + this.querySyntaxProviders.get(language); + + private getSuggestionsProvider = (): SuggestionsProvider => + (() => 'todo' as unknown) as SuggestionsProvider; /** @public **/ public setup() { return { - addProvider: this.addProvider, + addQuerySyntaxProvider: this.addQuerySyntaxProvider, /** @obsolete **/ /** please use "getProvider" only from the start contract **/ - getProvider: this.getProvider, + getQuerySyntaxProvider: this.getQuerySyntaxProvider, }; } /** @public **/ public start() { return { - getProvider: this.getProvider, + getQuerySyntaxProvider: this.getQuerySyntaxProvider, + getSuggestionsProvider: this.getSuggestionsProvider, }; } } diff --git a/src/plugins/data/public/autocomplete_provider/providers/query_syntax_provider.ts b/src/plugins/data/public/autocomplete_provider/providers/query_syntax_provider.ts new file mode 100644 index 0000000000000..931bdd0470071 --- /dev/null +++ b/src/plugins/data/public/autocomplete_provider/providers/query_syntax_provider.ts @@ -0,0 +1,59 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { IFieldType, IIndexPattern } from '../../../common/index_patterns'; + +export type QuerySyntaxSuggestionType = + | 'field' + | 'value' + | 'operator' + | 'conjunction' + | 'recentSearch'; + +export type QuerySyntaxProvider = (args: { + indexPatterns: IIndexPattern[]; + boolFilter?: any; +}) => QuerySyntaxGetSuggestions; + +export type QuerySyntaxGetSuggestions = (args: { + query: string; + selectionStart: number; + selectionEnd: number; + signal?: AbortSignal; +}) => Promise; + +interface BasicQuerySyntaxSuggestion { + type: QuerySyntaxSuggestionType; + description?: string; + end: number; + start: number; + text: string; + cursorIndex?: number; +} + +type FieldQuerySyntaxSuggestion = BasicQuerySyntaxSuggestion & { + type: 'field'; + field: IFieldType; +}; + +// A union type allows us to do easy type guards in the code. For example, if I want to ensure I'm +// working with a FieldAutocompleteSuggestion, I can just do `if ('field' in suggestion)` and the +// TypeScript compiler will narrow the type to the parts of the union that have a field prop. +/** @public **/ +export type QuerySyntaxSuggestion = BasicQuerySyntaxSuggestion | FieldQuerySyntaxSuggestion; diff --git a/src/plugins/data/public/autocomplete_provider/providers/suggestions_provider.ts b/src/plugins/data/public/autocomplete_provider/providers/suggestions_provider.ts new file mode 100644 index 0000000000000..16862c1a965e5 --- /dev/null +++ b/src/plugins/data/public/autocomplete_provider/providers/suggestions_provider.ts @@ -0,0 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import { IIndexPattern } from '../../../common/index_patterns'; + +export type SuggestionsProvider = (args: { indexPatterns: IIndexPattern[] }) => Function; diff --git a/src/plugins/data/public/autocomplete_provider/types.ts b/src/plugins/data/public/autocomplete_provider/types.ts index a06f09732a20d..1fbbb2716394b 100644 --- a/src/plugins/data/public/autocomplete_provider/types.ts +++ b/src/plugins/data/public/autocomplete_provider/types.ts @@ -18,49 +18,29 @@ */ import { AutocompleteProviderRegister } from '.'; -import { IIndexPattern, IFieldType } from '../../common'; -export type AutocompletePublicPluginSetup = ReturnType; -export type AutocompletePublicPluginStart = ReturnType; +import { + QuerySyntaxSuggestionType, + QuerySyntaxGetSuggestions, + QuerySyntaxSuggestion, + QuerySyntaxProvider, +} from './providers/query_syntax_provider'; -/** @public **/ -export type AutocompleteProvider = (args: { - indexPatterns: IIndexPattern[]; - boolFilter?: any; -}) => GetSuggestions; +import { SuggestionsProvider } from './providers/suggestions_provider'; /** @public **/ -export type GetSuggestions = (args: { - query: string; - selectionStart: number; - selectionEnd: number; - signal?: AbortSignal; -}) => Promise; +export type AutocompletePublicPluginSetup = ReturnType; /** @public **/ -export type AutocompleteSuggestionType = - | 'field' - | 'value' - | 'operator' - | 'conjunction' - | 'recentSearch'; +export type AutocompletePublicPluginStart = ReturnType; -// A union type allows us to do easy type guards in the code. For example, if I want to ensure I'm -// working with a FieldAutocompleteSuggestion, I can just do `if ('field' in suggestion)` and the -// TypeScript compiler will narrow the type to the parts of the union that have a field prop. /** @public **/ -export type AutocompleteSuggestion = BasicAutocompleteSuggestion | FieldAutocompleteSuggestion; - -interface BasicAutocompleteSuggestion { - description?: string; - end: number; - start: number; - text: string; - type: AutocompleteSuggestionType; - cursorIndex?: number; -} - -export type FieldAutocompleteSuggestion = BasicAutocompleteSuggestion & { - type: 'field'; - field: IFieldType; +export { + QuerySyntaxSuggestionType, + QuerySyntaxSuggestion, + QuerySyntaxGetSuggestions, + QuerySyntaxProvider, }; + +/** @public **/ +export { SuggestionsProvider }; diff --git a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx index 463fd5b4c4de3..6b9136f1b339f 100644 --- a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx +++ b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx @@ -70,7 +70,7 @@ interface Props { interface State { isSuggestionsVisible: boolean; index: number | null; - suggestions: autocomplete.AutocompleteSuggestion[]; + suggestions: autocomplete.QuerySyntaxSuggestion[]; suggestionLimit: number; selectionStart: number | null; selectionEnd: number | null; @@ -89,7 +89,7 @@ const KEY_CODES = { END: 35, }; -const recentSearchType: autocomplete.AutocompleteSuggestionType = 'recentSearch'; +const recentSearchType: autocomplete.QuerySyntaxSuggestionType = 'recentSearch'; export class QueryStringInputUI extends Component { public state: State = { @@ -141,7 +141,7 @@ export class QueryStringInputUI extends Component { const queryString = this.getQueryString(); const recentSearchSuggestions = this.getRecentSearchSuggestions(queryString); - const autocompleteProvider = this.services.data.autocomplete.getProvider(language); + const autocompleteProvider = this.services.data.autocomplete.getQuerySyntaxProvider(language); if ( !autocompleteProvider || @@ -162,7 +162,7 @@ export class QueryStringInputUI extends Component { try { if (this.abortController) this.abortController.abort(); this.abortController = new AbortController(); - const suggestions: autocomplete.AutocompleteSuggestion[] = await getAutocompleteSuggestions({ + const suggestions = await getAutocompleteSuggestions({ query: queryString, selectionStart, selectionEnd, @@ -316,7 +316,7 @@ export class QueryStringInputUI extends Component { } }; - private selectSuggestion = (suggestion: autocomplete.AutocompleteSuggestion) => { + private selectSuggestion = (suggestion: autocomplete.QuerySyntaxSuggestion) => { if (!this.inputRef) { return; } @@ -347,7 +347,7 @@ export class QueryStringInputUI extends Component { }; private handleNestedFieldSyntaxNotification = ( - suggestion: autocomplete.AutocompleteSuggestion + suggestion: autocomplete.QuerySyntaxSuggestion ) => { if ( 'field' in suggestion && @@ -450,7 +450,7 @@ export class QueryStringInputUI extends Component { } }; - private onClickSuggestion = (suggestion: autocomplete.AutocompleteSuggestion) => { + private onClickSuggestion = (suggestion: autocomplete.QuerySyntaxSuggestion) => { if (!this.inputRef) { return; } diff --git a/src/plugins/data/public/ui/typeahead/suggestion_component.test.tsx b/src/plugins/data/public/ui/typeahead/suggestion_component.test.tsx index 7b3d61e2f0186..d8c9f4860addd 100644 --- a/src/plugins/data/public/ui/typeahead/suggestion_component.test.tsx +++ b/src/plugins/data/public/ui/typeahead/suggestion_component.test.tsx @@ -26,7 +26,7 @@ const noop = () => { return; }; -const mockSuggestion: autocomplete.AutocompleteSuggestion = { +const mockSuggestion: autocomplete.QuerySyntaxSuggestion = { description: 'This is not a helpful suggestion', end: 0, start: 42, diff --git a/src/plugins/data/public/ui/typeahead/suggestion_component.tsx b/src/plugins/data/public/ui/typeahead/suggestion_component.tsx index 027faff11dac8..35003a7ffd0a4 100644 --- a/src/plugins/data/public/ui/typeahead/suggestion_component.tsx +++ b/src/plugins/data/public/ui/typeahead/suggestion_component.tsx @@ -40,10 +40,10 @@ function getEuiIconType(type: string) { } interface Props { - onClick: (suggestion: autocomplete.AutocompleteSuggestion) => void; + onClick: (suggestion: autocomplete.QuerySyntaxSuggestion) => void; onMouseEnter: () => void; selected: boolean; - suggestion: autocomplete.AutocompleteSuggestion; + suggestion: autocomplete.QuerySyntaxSuggestion; innerRef: (node: HTMLDivElement) => void; ariaId: string; } diff --git a/src/plugins/data/public/ui/typeahead/suggestions_component.test.tsx b/src/plugins/data/public/ui/typeahead/suggestions_component.test.tsx index fcd750ee65a45..0822900604639 100644 --- a/src/plugins/data/public/ui/typeahead/suggestions_component.test.tsx +++ b/src/plugins/data/public/ui/typeahead/suggestions_component.test.tsx @@ -27,7 +27,7 @@ const noop = () => { return; }; -const mockSuggestions: autocomplete.AutocompleteSuggestion[] = [ +const mockSuggestions: autocomplete.QuerySyntaxSuggestion[] = [ { description: 'This is not a helpful suggestion', end: 0, diff --git a/src/plugins/data/public/ui/typeahead/suggestions_component.tsx b/src/plugins/data/public/ui/typeahead/suggestions_component.tsx index 099f914824641..a06026e70fbd4 100644 --- a/src/plugins/data/public/ui/typeahead/suggestions_component.tsx +++ b/src/plugins/data/public/ui/typeahead/suggestions_component.tsx @@ -24,10 +24,10 @@ import { SuggestionComponent } from './suggestion_component'; interface Props { index: number | null; - onClick: (suggestion: autocomplete.AutocompleteSuggestion) => void; + onClick: (suggestion: autocomplete.QuerySyntaxSuggestion) => void; onMouseEnter: (index: number) => void; show: boolean; - suggestions: autocomplete.AutocompleteSuggestion[]; + suggestions: autocomplete.QuerySyntaxSuggestion[]; loadMore: () => void; } diff --git a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx index c7a120bc269d8..0375ff8cdf108 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx @@ -28,7 +28,7 @@ const Container = styled.div` `; interface State { - suggestions: autocompleteNamespace.AutocompleteSuggestion[]; + suggestions: autocompleteNamespace.QuerySyntaxSuggestion[]; isLoadingSuggestions: boolean; } @@ -42,7 +42,7 @@ function getSuggestions( selectionStart: number, indexPattern: IIndexPattern, boolFilter: unknown, - autocompleteProvider?: autocompleteNamespace.AutocompleteProvider + autocompleteProvider?: autocompleteNamespace.QuerySyntaxProvider ) { if (!autocompleteProvider) { return []; @@ -67,7 +67,9 @@ export function KueryBar() { const { urlParams } = useUrlParams(); const location = useLocation(); const { data } = useApmPluginContext().plugins; - const autocompleteProvider = data.autocomplete.getProvider('kuery'); + const autocompleteProvider = data.autocomplete.getQuerySyntaxProvider( + 'kuery' + ); let currentRequestCheck; @@ -106,7 +108,9 @@ export function KueryBar() { autocompleteProvider ) ) - .filter(suggestion => !startsWith(suggestion.text, 'span.')) + .filter( + suggestion => suggestion && !startsWith(suggestion.text, 'span.') + ) .slice(0, 15); if (currentRequest !== currentRequestCheck) { diff --git a/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/index.tsx b/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/index.tsx index c36020f7921c8..5ddbd1660e9b7 100644 --- a/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/index.tsx +++ b/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/index.tsx @@ -25,7 +25,7 @@ interface AutocompleteFieldProps { onSubmit?: (value: string) => void; onChange?: (value: string) => void; placeholder?: string; - suggestions: autocomplete.AutocompleteSuggestion[]; + suggestions: autocomplete.QuerySyntaxSuggestion[]; value: string; } diff --git a/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/suggestion_item.tsx b/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/suggestion_item.tsx index a1c24d65beda6..994ad4834afc7 100644 --- a/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/suggestion_item.tsx +++ b/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/suggestion_item.tsx @@ -15,7 +15,7 @@ interface SuggestionItemProps { isSelected?: boolean; onClick?: React.MouseEventHandler; onMouseEnter?: React.MouseEventHandler; - suggestion: autocomplete.AutocompleteSuggestion; + suggestion: autocomplete.QuerySyntaxSuggestion; } export const SuggestionItem: React.FC = props => { diff --git a/x-pack/legacy/plugins/beats_management/public/components/table/table.tsx b/x-pack/legacy/plugins/beats_management/public/components/table/table.tsx index 7370c057f8317..a3d9a4f7daa54 100644 --- a/x-pack/legacy/plugins/beats_management/public/components/table/table.tsx +++ b/x-pack/legacy/plugins/beats_management/public/components/table/table.tsx @@ -31,7 +31,7 @@ export interface KueryBarProps { loadSuggestions: (value: string, cursorPosition: number, maxCount?: number) => void; onChange?: (value: string) => void; onSubmit?: (value: string) => void; - suggestions: autocomplete.AutocompleteSuggestion[]; + suggestions: autocomplete.QuerySyntaxSuggestion[]; value: string; } diff --git a/x-pack/legacy/plugins/beats_management/public/containers/with_kuery_autocompletion.tsx b/x-pack/legacy/plugins/beats_management/public/containers/with_kuery_autocompletion.tsx index 25d5bd78f9b70..dca8df7d193a7 100644 --- a/x-pack/legacy/plugins/beats_management/public/containers/with_kuery_autocompletion.tsx +++ b/x-pack/legacy/plugins/beats_management/public/containers/with_kuery_autocompletion.tsx @@ -17,7 +17,7 @@ interface WithKueryAutocompletionLifecycleProps { children: RendererFunction<{ isLoadingSuggestions: boolean; loadSuggestions: (expression: string, cursorPosition: number, maxSuggestions?: number) => void; - suggestions: autocomplete.AutocompleteSuggestion[]; + suggestions: autocomplete.QuerySyntaxSuggestion[]; }>; } @@ -28,7 +28,7 @@ interface WithKueryAutocompletionLifecycleState { expression: string; cursorPosition: number; } | null; - suggestions: autocomplete.AutocompleteSuggestion[]; + suggestions: autocomplete.QuerySyntaxSuggestion[]; } export class WithKueryAutocompletion extends React.Component< diff --git a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/adapter_types.ts b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/adapter_types.ts index e261d87a71d03..1f026fcbcf85f 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/adapter_types.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/adapter_types.ts @@ -10,6 +10,6 @@ export interface ElasticsearchAdapter { getSuggestions: ( kuery: string, selectionStart: any - ) => Promise; + ) => Promise; isKueryValid(kuery: string): boolean; } diff --git a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/memory.ts b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/memory.ts index e357bbec1c793..59061006a037d 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/memory.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/memory.ts @@ -11,7 +11,7 @@ export class MemoryElasticsearchAdapter implements ElasticsearchAdapter { constructor( private readonly mockIsKueryValid: (kuery: string) => boolean, private readonly mockKueryToEsQuery: (kuery: string) => string, - private readonly suggestions: autocomplete.AutocompleteSuggestion[] + private readonly suggestions: autocomplete.QuerySyntaxSuggestion[] ) {} public isKueryValid(kuery: string): boolean { @@ -23,7 +23,7 @@ export class MemoryElasticsearchAdapter implements ElasticsearchAdapter { public async getSuggestions( kuery: string, selectionStart: any - ): Promise { + ): Promise { return this.suggestions; } } diff --git a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts index 92a115148e35d..a3945c4bd0445 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts @@ -10,7 +10,7 @@ import { ElasticsearchAdapter } from './adapter_types'; import { autocomplete, esKuery } from '../../../../../../../../src/plugins/data/public'; const getAutocompleteProvider = (language: string) => - npStart.plugins.data.autocomplete.getProvider(language); + npStart.plugins.data.autocomplete.getQuerySyntaxProvider(language); export class RestElasticsearchAdapter implements ElasticsearchAdapter { private cachedIndexPattern: any = null; @@ -36,7 +36,7 @@ export class RestElasticsearchAdapter implements ElasticsearchAdapter { public async getSuggestions( kuery: string, selectionStart: any - ): Promise { + ): Promise { const autocompleteProvider = getAutocompleteProvider('kuery'); if (!autocompleteProvider) { return []; diff --git a/x-pack/legacy/plugins/beats_management/public/lib/compose/memory.ts b/x-pack/legacy/plugins/beats_management/public/lib/compose/memory.ts index 9d4db2f7feed3..ab7f72d2a5bb7 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/compose/memory.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/compose/memory.ts @@ -31,7 +31,7 @@ const onKibanaReady = uiModules.get('kibana').run; export function compose( mockIsKueryValid: (kuery: string) => boolean, mockKueryToEsQuery: (kuery: string) => string, - suggestions: autocomplete.AutocompleteSuggestion[] + suggestions: autocomplete.QuerySyntaxSuggestion[] ): FrontendLibs { const esAdapter = new MemoryElasticsearchAdapter( mockIsKueryValid, diff --git a/x-pack/legacy/plugins/beats_management/public/lib/elasticsearch.ts b/x-pack/legacy/plugins/beats_management/public/lib/elasticsearch.ts index 4310cfe1647dd..c885129c27ee3 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/elasticsearch.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/elasticsearch.ts @@ -35,7 +35,7 @@ export class ElasticsearchLib { kuery: string, selectionStart: any, fieldPrefix?: string - ): Promise { + ): Promise { const suggestions = await this.adapter.getSuggestions(kuery, selectionStart); const filteredSuggestions = suggestions.filter(suggestion => { diff --git a/x-pack/legacy/plugins/infra/public/components/autocomplete_field/autocomplete_field.tsx b/x-pack/legacy/plugins/infra/public/components/autocomplete_field/autocomplete_field.tsx index 70f0d56a1996f..9418fb8ee9510 100644 --- a/x-pack/legacy/plugins/infra/public/components/autocomplete_field/autocomplete_field.tsx +++ b/x-pack/legacy/plugins/infra/public/components/autocomplete_field/autocomplete_field.tsx @@ -25,7 +25,7 @@ interface AutocompleteFieldProps { onSubmit?: (value: string) => void; onChange?: (value: string) => void; placeholder?: string; - suggestions: autocomplete.AutocompleteSuggestion[]; + suggestions: autocomplete.QuerySyntaxSuggestion[]; value: string; autoFocus?: boolean; 'aria-label'?: string; diff --git a/x-pack/legacy/plugins/infra/public/components/autocomplete_field/suggestion_item.tsx b/x-pack/legacy/plugins/infra/public/components/autocomplete_field/suggestion_item.tsx index 4b69ec238c328..c63ca56a022bb 100644 --- a/x-pack/legacy/plugins/infra/public/components/autocomplete_field/suggestion_item.tsx +++ b/x-pack/legacy/plugins/infra/public/components/autocomplete_field/suggestion_item.tsx @@ -15,7 +15,7 @@ interface Props { isSelected?: boolean; onClick?: React.MouseEventHandler; onMouseEnter?: React.MouseEventHandler; - suggestion: autocomplete.AutocompleteSuggestion; + suggestion: autocomplete.QuerySyntaxSuggestion; } export const SuggestionItem: React.FC = props => { diff --git a/x-pack/legacy/plugins/infra/public/containers/with_kuery_autocompletion.tsx b/x-pack/legacy/plugins/infra/public/containers/with_kuery_autocompletion.tsx index f03ddc6dd6a8d..16fcbcfc9708b 100644 --- a/x-pack/legacy/plugins/infra/public/containers/with_kuery_autocompletion.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/with_kuery_autocompletion.tsx @@ -10,13 +10,13 @@ import { autocomplete, IIndexPattern } from 'src/plugins/data/public'; import { RendererFunction } from '../utils/typed_react'; const getAutocompleteProvider = (language: string) => - npStart.plugins.data.autocomplete.getProvider(language); + npStart.plugins.data.autocomplete.getQuerySyntaxProvider(language); interface WithKueryAutocompletionLifecycleProps { children: RendererFunction<{ isLoadingSuggestions: boolean; loadSuggestions: (expression: string, cursorPosition: number, maxSuggestions?: number) => void; - suggestions: autocomplete.AutocompleteSuggestion[]; + suggestions: autocomplete.QuerySyntaxSuggestion[]; }>; indexPattern: IIndexPattern; } @@ -28,7 +28,7 @@ interface WithKueryAutocompletionLifecycleState { expression: string; cursorPosition: number; } | null; - suggestions: autocomplete.AutocompleteSuggestion[]; + suggestions: autocomplete.QuerySyntaxSuggestion[]; } export class WithKueryAutocompletion extends React.Component< diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/plugin.ts b/x-pack/legacy/plugins/kuery_autocomplete/public/plugin.ts index c4b75cd9dfcf8..15c923513027f 100644 --- a/x-pack/legacy/plugins/kuery_autocomplete/public/plugin.ts +++ b/x-pack/legacy/plugins/kuery_autocomplete/public/plugin.ts @@ -28,7 +28,7 @@ export class KueryAutocompletePlugin implements Plugin, void> { public async setup(core: CoreSetup, { data }: KueryAutocompletePluginSetupDependencies) { const kueryProvider = setupKueryProvider(core); - data.autocomplete.addProvider(KUERY_LANGUAGE_NAME, kueryProvider); + data.autocomplete.addQuerySyntaxProvider(KUERY_LANGUAGE_NAME, kueryProvider); } public start(core: CoreStart) { diff --git a/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/utils.js b/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/utils.js index 419a4d31e344b..581ab20a627f0 100644 --- a/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/utils.js +++ b/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/utils.js @@ -6,7 +6,8 @@ import { npStart } from 'ui/new_platform'; import { esKuery } from '../../../../../../../../src/plugins/data/public'; -const getAutocompleteProvider = language => npStart.plugins.data.autocomplete.getProvider(language); +const getAutocompleteProvider = language => + npStart.plugins.data.autocomplete.getQuerySyntaxProvider(language); export async function getSuggestions(query, selectionStart, indexPattern, boolFilter) { const autocompleteProvider = getAutocompleteProvider('kuery'); diff --git a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.test.tsx index 4a320b72490ad..57f18dcdaf8f7 100644 --- a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.test.tsx @@ -16,7 +16,7 @@ import { TestProviders } from '../../mock'; import { AutocompleteField } from '.'; -const mockAutoCompleteData: autocomplete.AutocompleteSuggestion[] = [ +const mockAutoCompleteData: autocomplete.QuerySyntaxSuggestion[] = [ { type: 'field', text: 'agent.ephemeral_id ', diff --git a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.tsx b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.tsx index c733702312fa8..6cf9736d333d1 100644 --- a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.tsx @@ -25,7 +25,7 @@ interface AutocompleteFieldProps { onSubmit?: (value: string) => void; onChange?: (value: string) => void; placeholder?: string; - suggestions: autocomplete.AutocompleteSuggestion[]; + suggestions: autocomplete.QuerySyntaxSuggestion[]; value: string; } diff --git a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/suggestion_item.tsx b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/suggestion_item.tsx index a67c921e87998..80cc05578511d 100644 --- a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/suggestion_item.tsx +++ b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/suggestion_item.tsx @@ -15,7 +15,7 @@ interface SuggestionItemProps { isSelected?: boolean; onClick?: React.MouseEventHandler; onMouseEnter?: React.MouseEventHandler; - suggestion: autocomplete.AutocompleteSuggestion; + suggestion: autocomplete.QuerySyntaxSuggestion; } export const SuggestionItem = React.memo( diff --git a/x-pack/legacy/plugins/siem/public/containers/kuery_autocompletion/index.tsx b/x-pack/legacy/plugins/siem/public/containers/kuery_autocompletion/index.tsx index 5e2106bf44a69..8c2cb335029bd 100644 --- a/x-pack/legacy/plugins/siem/public/containers/kuery_autocompletion/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/kuery_autocompletion/index.tsx @@ -15,7 +15,7 @@ interface KueryAutocompletionLifecycleProps { children: RendererFunction<{ isLoadingSuggestions: boolean; loadSuggestions: (expression: string, cursorPosition: number, maxSuggestions?: number) => void; - suggestions: autocomplete.AutocompleteSuggestion[]; + suggestions: autocomplete.QuerySyntaxSuggestion[]; }>; indexPattern: IIndexPattern; } @@ -30,14 +30,16 @@ export const KueryAutocompletion = React.memo const [currentRequest, setCurrentRequest] = useState( null ); - const [suggestions, setSuggestions] = useState([]); + const [suggestions, setSuggestions] = useState([]); const kibana = useKibana(); const loadSuggestions = async ( expression: string, cursorPosition: number, maxSuggestions?: number ) => { - const autocompletionProvider = kibana.services.data.autocomplete.getProvider('kuery'); + const autocompletionProvider = kibana.services.data.autocomplete.getQuerySyntaxProvider( + 'kuery' + ); if (!autocompletionProvider) { return; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx index b0d57e5c3da97..76a326dbf0236 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx @@ -24,7 +24,7 @@ const Container = styled.div` `; interface State { - suggestions: autocompleteNamespace.AutocompleteSuggestion[]; + suggestions: autocompleteNamespace.QuerySyntaxSuggestion[]; isLoadingIndexPattern: boolean; } @@ -39,7 +39,7 @@ function getSuggestions( apmIndexPattern: IIndexPattern, autocomplete: autocompleteNamespace.AutocompletePublicPluginStart ) { - const autocompleteProvider = autocomplete.getProvider('kuery'); + const autocompleteProvider = autocomplete.getQuerySyntaxProvider('kuery'); if (!autocompleteProvider) { return []; } @@ -102,7 +102,7 @@ export function KueryBar({ autocomplete }: Props) { ); suggestions = suggestions .filter( - (suggestion: autocompleteNamespace.AutocompleteSuggestion) => + (suggestion: autocompleteNamespace.QuerySyntaxSuggestion) => !startsWith(suggestion.text, 'span.') ) .slice(0, 15); diff --git a/x-pack/legacy/plugins/uptime/public/routes.tsx b/x-pack/legacy/plugins/uptime/public/routes.tsx index 08d752f5b32ab..454e29ceecf65 100644 --- a/x-pack/legacy/plugins/uptime/public/routes.tsx +++ b/x-pack/legacy/plugins/uptime/public/routes.tsx @@ -7,14 +7,14 @@ import React, { FC } from 'react'; import { Route, Switch } from 'react-router-dom'; import { MonitorPage, OverviewPage, NotFoundPage } from './pages'; -import { AutocompleteProviderRegister } from '../../../../../src/plugins/data/public'; +import { autocomplete as autocompleteNamespace } from '../../../../../src/plugins/data/public'; import { UMUpdateBreadcrumbs } from './lib/lib'; export const MONITOR_ROUTE = '/monitor/:monitorId/:location?'; export const OVERVIEW_ROUTE = '/'; interface RouterProps { - autocomplete: Pick; + autocomplete: autocompleteNamespace.AutocompletePublicPluginStart; basePath: string; setBreadcrumbs: UMUpdateBreadcrumbs; } From eb8250ffad6aa3eab1972c458d4470b136be0da6 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Mon, 13 Jan 2020 12:52:53 +0300 Subject: [PATCH 03/11] autocomplete_provider -> autocomplete --- .../autocomplete_provider_register.ts | 0 .../public/{autocomplete_provider => autocomplete}/index.ts | 0 .../providers/query_syntax_provider.ts | 0 .../providers/suggestions_provider.ts | 0 .../public/{autocomplete_provider => autocomplete}/types.ts | 0 src/plugins/data/public/index.ts | 2 +- src/plugins/data/public/mocks.ts | 5 ++--- src/plugins/data/public/plugin.ts | 2 +- 8 files changed, 4 insertions(+), 5 deletions(-) rename src/plugins/data/public/{autocomplete_provider => autocomplete}/autocomplete_provider_register.ts (100%) rename src/plugins/data/public/{autocomplete_provider => autocomplete}/index.ts (100%) rename src/plugins/data/public/{autocomplete_provider => autocomplete}/providers/query_syntax_provider.ts (100%) rename src/plugins/data/public/{autocomplete_provider => autocomplete}/providers/suggestions_provider.ts (100%) rename src/plugins/data/public/{autocomplete_provider => autocomplete}/types.ts (100%) diff --git a/src/plugins/data/public/autocomplete_provider/autocomplete_provider_register.ts b/src/plugins/data/public/autocomplete/autocomplete_provider_register.ts similarity index 100% rename from src/plugins/data/public/autocomplete_provider/autocomplete_provider_register.ts rename to src/plugins/data/public/autocomplete/autocomplete_provider_register.ts diff --git a/src/plugins/data/public/autocomplete_provider/index.ts b/src/plugins/data/public/autocomplete/index.ts similarity index 100% rename from src/plugins/data/public/autocomplete_provider/index.ts rename to src/plugins/data/public/autocomplete/index.ts diff --git a/src/plugins/data/public/autocomplete_provider/providers/query_syntax_provider.ts b/src/plugins/data/public/autocomplete/providers/query_syntax_provider.ts similarity index 100% rename from src/plugins/data/public/autocomplete_provider/providers/query_syntax_provider.ts rename to src/plugins/data/public/autocomplete/providers/query_syntax_provider.ts diff --git a/src/plugins/data/public/autocomplete_provider/providers/suggestions_provider.ts b/src/plugins/data/public/autocomplete/providers/suggestions_provider.ts similarity index 100% rename from src/plugins/data/public/autocomplete_provider/providers/suggestions_provider.ts rename to src/plugins/data/public/autocomplete/providers/suggestions_provider.ts diff --git a/src/plugins/data/public/autocomplete_provider/types.ts b/src/plugins/data/public/autocomplete/types.ts similarity index 100% rename from src/plugins/data/public/autocomplete_provider/types.ts rename to src/plugins/data/public/autocomplete/types.ts diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 4e1e9c2b99698..2ff230abc19ed 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -18,7 +18,7 @@ */ import { PluginInitializerContext } from '../../../core/public'; -import * as autocomplete from './autocomplete_provider'; +import * as autocomplete from './autocomplete'; export function plugin(initializerContext: PluginInitializerContext) { return new DataPublicPlugin(initializerContext); diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index 03d3dad61ed05..353b160c5f38d 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -30,9 +30,8 @@ export type Setup = jest.Mocked>; export type Start = jest.Mocked>; const autocompleteMock: any = { - addProvider: jest.fn(), - getProvider: jest.fn(), - clearProviders: jest.fn(), + addQuerySyntaxProvider: jest.fn(), + getQuerySyntaxProvider: jest.fn(), }; const fieldFormatsMock: PublicMethodsOf = { diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 5cca52a79036f..5f29131df9309 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -25,7 +25,7 @@ import { DataSetupDependencies, DataStartDependencies, } from './types'; -import { AutocompleteProviderRegister } from './autocomplete_provider'; +import { AutocompleteProviderRegister } from './autocomplete'; import { getSuggestionsProvider } from './suggestions_provider'; import { SearchService } from './search/search_service'; import { FieldFormatsService } from './field_formats_provider'; From 6ee7644d5beda7c90f304ec26f3aeb82ad7f8851 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Mon, 13 Jan 2020 13:52:47 +0300 Subject: [PATCH 04/11] value_suggestions.ts - change getSuggestions method --- .../suggestions_provider/value_suggestions.ts | 6 ++-- .../filter_editor/phrase_suggestor.tsx | 2 +- .../query_string_input.test.tsx.snap | 30 ++++++++----------- .../public/components/search_bar.test.tsx | 2 +- 4 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/plugins/data/public/suggestions_provider/value_suggestions.ts b/src/plugins/data/public/suggestions_provider/value_suggestions.ts index e64156c290db1..c5de18c63b32d 100644 --- a/src/plugins/data/public/suggestions_provider/value_suggestions.ts +++ b/src/plugins/data/public/suggestions_provider/value_suggestions.ts @@ -21,7 +21,7 @@ import { memoize } from 'lodash'; import { IUiSettingsClient, HttpSetup } from 'src/core/public'; import { IGetSuggestions } from './types'; -import { IFieldType } from '../../common'; +import { IIndexPattern, IFieldType } from '../../common'; export function getSuggestionsProvider( uiSettings: IUiSettingsClient, @@ -45,13 +45,15 @@ export function getSuggestionsProvider( ); return async ( - index: string, + indexPattern: IIndexPattern, field: IFieldType, query: string, boolFilter?: any, signal?: AbortSignal ) => { const shouldSuggestValues = uiSettings.get('filterEditor:suggestValues'); + const index = indexPattern.title; + if (field.type === 'boolean') { return [true, false]; } else if (!shouldSuggestValues || !field.aggregatable || field.type !== 'string') { diff --git a/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx b/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx index 7875fbaa9cdc2..5ace6412eff39 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx +++ b/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx @@ -70,7 +70,7 @@ export class PhraseSuggestorUI extends Component } this.setState({ isLoading: true }); // todo: value suggestions - const suggestions = await this.services.data.getSuggestions(indexPattern.title, field, value); + const suggestions = await this.services.data.getSuggestions(indexPattern, field, value); this.setState({ suggestions, isLoading: false }); }, 500); } diff --git a/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap b/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap index 6f5f9b3956187..8178b1c9ed7c1 100644 --- a/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap +++ b/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap @@ -151,9 +151,8 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA }, "data": Object { "autocomplete": Object { - "addProvider": [MockFunction], - "clearProviders": [MockFunction], - "getProvider": [MockFunction], + "addQuerySyntaxProvider": [MockFunction], + "getQuerySyntaxProvider": [MockFunction], }, "fieldFormats": Object { "getByFieldType": [MockFunction], @@ -771,9 +770,8 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA }, "data": Object { "autocomplete": Object { - "addProvider": [MockFunction], - "clearProviders": [MockFunction], - "getProvider": [MockFunction], + "addQuerySyntaxProvider": [MockFunction], + "getQuerySyntaxProvider": [MockFunction], }, "fieldFormats": Object { "getByFieldType": [MockFunction], @@ -1379,9 +1377,8 @@ exports[`QueryStringInput Should pass the query language to the language switche }, "data": Object { "autocomplete": Object { - "addProvider": [MockFunction], - "clearProviders": [MockFunction], - "getProvider": [MockFunction], + "addQuerySyntaxProvider": [MockFunction], + "getQuerySyntaxProvider": [MockFunction], }, "fieldFormats": Object { "getByFieldType": [MockFunction], @@ -1996,9 +1993,8 @@ exports[`QueryStringInput Should pass the query language to the language switche }, "data": Object { "autocomplete": Object { - "addProvider": [MockFunction], - "clearProviders": [MockFunction], - "getProvider": [MockFunction], + "addQuerySyntaxProvider": [MockFunction], + "getQuerySyntaxProvider": [MockFunction], }, "fieldFormats": Object { "getByFieldType": [MockFunction], @@ -2604,9 +2600,8 @@ exports[`QueryStringInput Should render the given query 1`] = ` }, "data": Object { "autocomplete": Object { - "addProvider": [MockFunction], - "clearProviders": [MockFunction], - "getProvider": [MockFunction], + "addQuerySyntaxProvider": [MockFunction], + "getQuerySyntaxProvider": [MockFunction], }, "fieldFormats": Object { "getByFieldType": [MockFunction], @@ -3221,9 +3216,8 @@ exports[`QueryStringInput Should render the given query 1`] = ` }, "data": Object { "autocomplete": Object { - "addProvider": [MockFunction], - "clearProviders": [MockFunction], - "getProvider": [MockFunction], + "addQuerySyntaxProvider": [MockFunction], + "getQuerySyntaxProvider": [MockFunction], }, "fieldFormats": Object { "getByFieldType": [MockFunction], diff --git a/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx b/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx index 360561df71957..98916a19bebdb 100644 --- a/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx +++ b/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx @@ -51,7 +51,7 @@ function wrapSearchBarInContext(testProps: OuterSearchBarProps) { savedQueries: {}, }, autocomplete: { - getProvider: () => undefined, + getQuerySyntaxProvider: () => undefined, }, }, }; From 336de38b0bf846d133a314b519c41246f1d05829 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Mon, 13 Jan 2020 18:58:39 +0300 Subject: [PATCH 05/11] remove suggestions_provider folder --- ...er_register.ts => autocomplete_service.ts} | 24 +++--- src/plugins/data/public/autocomplete/index.ts | 2 +- .../providers/suggestions_provider.test.ts} | 84 ++++++++++--------- .../providers/suggestions_provider.ts | 49 ++++++++++- src/plugins/data/public/autocomplete/types.ts | 6 +- src/plugins/data/public/plugin.ts | 9 +- .../data/public/suggestions_provider/index.ts | 20 ----- .../data/public/suggestions_provider/types.ts | 26 ------ .../suggestions_provider/value_suggestions.ts | 70 ---------------- src/plugins/data/public/types.ts | 4 - .../filter_editor/phrase_suggestor.tsx | 7 +- 11 files changed, 118 insertions(+), 183 deletions(-) rename src/plugins/data/public/autocomplete/{autocomplete_provider_register.ts => autocomplete_service.ts} (79%) rename src/plugins/data/public/{suggestions_provider/value_suggestions.test.ts => autocomplete/providers/suggestions_provider.test.ts} (60%) delete mode 100644 src/plugins/data/public/suggestions_provider/index.ts delete mode 100644 src/plugins/data/public/suggestions_provider/types.ts delete mode 100644 src/plugins/data/public/suggestions_provider/value_suggestions.ts diff --git a/src/plugins/data/public/autocomplete/autocomplete_provider_register.ts b/src/plugins/data/public/autocomplete/autocomplete_service.ts similarity index 79% rename from src/plugins/data/public/autocomplete/autocomplete_provider_register.ts rename to src/plugins/data/public/autocomplete/autocomplete_service.ts index 485aa8ae07c7e..9a81015048215 100644 --- a/src/plugins/data/public/autocomplete/autocomplete_provider_register.ts +++ b/src/plugins/data/public/autocomplete/autocomplete_service.ts @@ -17,15 +17,13 @@ * under the License. */ -import { QuerySyntaxProvider, SuggestionsProvider } from './types'; +import { CoreSetup } from 'src/core/public'; +import { QuerySyntaxProvider } from './types'; +import { SuggestionsProvider } from './providers/suggestions_provider'; -export class AutocompleteProviderRegister { +export class AutocompleteService { private readonly querySyntaxProviders: Map = new Map(); - - /** @internal **/ - public clearProviders(): void { - this.querySyntaxProviders.clear(); - } + private suggestionsProvider: SuggestionsProvider = new SuggestionsProvider(); private addQuerySyntaxProvider = (language: string, provider: QuerySyntaxProvider): void => { if (language && provider) { @@ -36,11 +34,12 @@ export class AutocompleteProviderRegister { private getQuerySyntaxProvider = (language: string): QuerySyntaxProvider | undefined => this.querySyntaxProviders.get(language); - private getSuggestionsProvider = (): SuggestionsProvider => - (() => 'todo' as unknown) as SuggestionsProvider; + private getSuggestionsProvider = (): SuggestionsProvider => this.suggestionsProvider; /** @public **/ - public setup() { + public setup(core: CoreSetup) { + this.suggestionsProvider.setup(core); + return { addQuerySyntaxProvider: this.addQuerySyntaxProvider, @@ -57,4 +56,9 @@ export class AutocompleteProviderRegister { getSuggestionsProvider: this.getSuggestionsProvider, }; } + + /** @internal **/ + public clearProviders(): void { + this.querySyntaxProviders.clear(); + } } diff --git a/src/plugins/data/public/autocomplete/index.ts b/src/plugins/data/public/autocomplete/index.ts index 81c6ae6a7dccd..26ea9bdaeacc3 100644 --- a/src/plugins/data/public/autocomplete/index.ts +++ b/src/plugins/data/public/autocomplete/index.ts @@ -17,5 +17,5 @@ * under the License. */ -export * from './autocomplete_provider_register'; +export * from './autocomplete_service'; export * from './types'; diff --git a/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts b/src/plugins/data/public/autocomplete/providers/suggestions_provider.test.ts similarity index 60% rename from src/plugins/data/public/suggestions_provider/value_suggestions.test.ts rename to src/plugins/data/public/autocomplete/providers/suggestions_provider.test.ts index 9089105b4e3a8..407c4ddec5a46 100644 --- a/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts +++ b/src/plugins/data/public/autocomplete/providers/suggestions_provider.test.ts @@ -17,88 +17,87 @@ * under the License. */ -import { stubIndexPattern, stubFields } from '../stubs'; -import { getSuggestionsProvider } from './value_suggestions'; -import { IUiSettingsClient } from 'kibana/public'; +import { stubIndexPattern, stubFields } from '../../stubs'; +import { SuggestionsProvider } from './suggestions_provider'; +import { IUiSettingsClient, CoreSetup } from 'kibana/public'; describe('getSuggestions', () => { - let getSuggestions: any; + let suggestionsProvider: SuggestionsProvider; let http: any; + let shouldSuggestValues: boolean; - describe('with value suggestions disabled', () => { - beforeEach(() => { - const config = { get: (key: string) => false } as IUiSettingsClient; - http = { fetch: jest.fn() }; - getSuggestions = getSuggestionsProvider(config, http); - }); + beforeEach(() => { + const uiSettings = { get: (key: string) => shouldSuggestValues } as IUiSettingsClient; + http = { fetch: jest.fn() }; + + suggestionsProvider = new SuggestionsProvider(); + suggestionsProvider.setup({ http, uiSettings } as CoreSetup); + }); + describe('with value suggestions disabled', () => { it('should return an empty array', async () => { - const index = stubIndexPattern.id; const [field] = stubFields; const query = ''; - const suggestions = await getSuggestions(index, field, query); + const suggestions = await suggestionsProvider.getSuggestions(stubIndexPattern, field, query); + expect(suggestions).toEqual([]); expect(http.fetch).not.toHaveBeenCalled(); }); }); describe('with value suggestions enabled', () => { - beforeEach(() => { - const config = { get: (key: string) => true } as IUiSettingsClient; - http = { fetch: jest.fn() }; - getSuggestions = getSuggestionsProvider(config, http); - }); + shouldSuggestValues = true; it('should return true/false for boolean fields', async () => { - const index = stubIndexPattern.id; const [field] = stubFields.filter(({ type }) => type === 'boolean'); const query = ''; - const suggestions = await getSuggestions(index, field, query); + const suggestions = await suggestionsProvider.getSuggestions(stubIndexPattern, field, query); + expect(suggestions).toEqual([true, false]); expect(http.fetch).not.toHaveBeenCalled(); }); it('should return an empty array if the field type is not a string or boolean', async () => { - const index = stubIndexPattern.id; const [field] = stubFields.filter(({ type }) => type !== 'string' && type !== 'boolean'); const query = ''; - const suggestions = await getSuggestions(index, field, query); + const suggestions = await suggestionsProvider.getSuggestions(stubIndexPattern, field, query); + expect(suggestions).toEqual([]); expect(http.fetch).not.toHaveBeenCalled(); }); it('should return an empty array if the field is not aggregatable', async () => { - const index = stubIndexPattern.id; const [field] = stubFields.filter(({ aggregatable }) => !aggregatable); const query = ''; - const suggestions = await getSuggestions(index, field, query); + const suggestions = await suggestionsProvider.getSuggestions(stubIndexPattern, field, query); + expect(suggestions).toEqual([]); expect(http.fetch).not.toHaveBeenCalled(); }); it('should otherwise request suggestions', async () => { - const index = stubIndexPattern.id; const [field] = stubFields.filter( ({ type, aggregatable }) => type === 'string' && aggregatable ); const query = ''; - await getSuggestions(index, field, query); + + await suggestionsProvider.getSuggestions(stubIndexPattern, field, query); expect(http.fetch).toHaveBeenCalled(); }); it('should cache results if using the same index/field/query/filter', async () => { - const index = stubIndexPattern.id; const [field] = stubFields.filter( ({ type, aggregatable }) => type === 'string' && aggregatable ); const query = ''; - await getSuggestions(index, field, query); - await getSuggestions(index, field, query); + + await suggestionsProvider.getSuggestions(stubIndexPattern, field, query); + await suggestionsProvider.getSuggestions(stubIndexPattern, field, query); + expect(http.fetch).toHaveBeenCalledTimes(1); }); it('should cache results for only one minute', async () => { - const index = stubIndexPattern.id; const [field] = stubFields.filter( ({ type, aggregatable }) => type === 'string' && aggregatable ); @@ -106,9 +105,9 @@ describe('getSuggestions', () => { const { now } = Date; Date.now = jest.fn(() => 0); - await getSuggestions(index, field, query); + await suggestionsProvider.getSuggestions(stubIndexPattern, field, query); Date.now = jest.fn(() => 60 * 1000); - await getSuggestions(index, field, query); + await suggestionsProvider.getSuggestions(stubIndexPattern, field, query); Date.now = now; expect(http.fetch).toHaveBeenCalledTimes(2); @@ -118,14 +117,21 @@ describe('getSuggestions', () => { const fields = stubFields.filter( ({ type, aggregatable }) => type === 'string' && aggregatable ); - await getSuggestions('index', fields[0], ''); - await getSuggestions('index', fields[0], 'query'); - await getSuggestions('index', fields[1], ''); - await getSuggestions('index', fields[1], 'query'); - await getSuggestions('logstash-*', fields[0], ''); - await getSuggestions('logstash-*', fields[0], 'query'); - await getSuggestions('logstash-*', fields[1], ''); - await getSuggestions('logstash-*', fields[1], 'query'); + const customIndexPattern = { + ...stubIndexPattern, + title: 'customIndexPattern', + }; + + await suggestionsProvider.getSuggestions(stubIndexPattern, fields[0], ''); + await suggestionsProvider.getSuggestions(stubIndexPattern, fields[0], 'query'); + await suggestionsProvider.getSuggestions(stubIndexPattern, fields[1], ''); + await suggestionsProvider.getSuggestions(stubIndexPattern, fields[1], 'query'); + + await suggestionsProvider.getSuggestions(customIndexPattern, fields[0], ''); + await suggestionsProvider.getSuggestions(customIndexPattern, fields[0], 'query'); + await suggestionsProvider.getSuggestions(customIndexPattern, fields[1], ''); + await suggestionsProvider.getSuggestions(customIndexPattern, fields[1], 'query'); + expect(http.fetch).toHaveBeenCalledTimes(8); }); }); diff --git a/src/plugins/data/public/autocomplete/providers/suggestions_provider.ts b/src/plugins/data/public/autocomplete/providers/suggestions_provider.ts index 16862c1a965e5..ee4054174eeec 100644 --- a/src/plugins/data/public/autocomplete/providers/suggestions_provider.ts +++ b/src/plugins/data/public/autocomplete/providers/suggestions_provider.ts @@ -16,6 +16,51 @@ * specific language governing permissions and limitations * under the License. */ -import { IIndexPattern } from '../../../common/index_patterns'; -export type SuggestionsProvider = (args: { indexPatterns: IIndexPattern[] }) => Function; +import { memoize } from 'lodash'; +import { CoreSetup } from 'src/core/public'; +import { IIndexPattern, IFieldType } from '../../../common'; + +function resolver(title: string, field: IFieldType, query: string, boolFilter: any) { + // Only cache results for a minute + const ttl = Math.floor(Date.now() / 1000 / 60); + + return [ttl, query, title, field.name, JSON.stringify(boolFilter)].join('|'); +} + +export class SuggestionsProvider { + private core?: CoreSetup; + + setup(core: CoreSetup) { + this.core = core; + } + + async getSuggestions( + indexPattern: IIndexPattern, + field: IFieldType, + query: string, + boolFilter?: any, + signal?: AbortSignal + ): Promise { + const shouldSuggestValues = this.core!.uiSettings.get('filterEditor:suggestValues'); + const { title } = indexPattern; + + if (field.type === 'boolean') { + return [true, false]; + } else if (!shouldSuggestValues || !field.aggregatable || field.type !== 'string') { + return []; + } + + return await this.requestSuggestions(title, field, query, boolFilter, signal); + } + + private requestSuggestions = memoize( + (index: string, field: IFieldType, query: string, boolFilter: any = [], signal?: AbortSignal) => + this.core!.http.fetch(`/api/kibana/suggestions/values/${index}`, { + method: 'POST', + body: JSON.stringify({ query, field: field.name, boolFilter }), + signal, + }), + resolver + ); +} diff --git a/src/plugins/data/public/autocomplete/types.ts b/src/plugins/data/public/autocomplete/types.ts index 1fbbb2716394b..99545073a32f9 100644 --- a/src/plugins/data/public/autocomplete/types.ts +++ b/src/plugins/data/public/autocomplete/types.ts @@ -17,7 +17,7 @@ * under the License. */ -import { AutocompleteProviderRegister } from '.'; +import { AutocompleteService } from '.'; import { QuerySyntaxSuggestionType, @@ -29,10 +29,10 @@ import { import { SuggestionsProvider } from './providers/suggestions_provider'; /** @public **/ -export type AutocompletePublicPluginSetup = ReturnType; +export type AutocompletePublicPluginSetup = ReturnType; /** @public **/ -export type AutocompletePublicPluginStart = ReturnType; +export type AutocompletePublicPluginStart = ReturnType; /** @public **/ export { diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 5f29131df9309..78abcbcfec467 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -25,8 +25,7 @@ import { DataSetupDependencies, DataStartDependencies, } from './types'; -import { AutocompleteProviderRegister } from './autocomplete'; -import { getSuggestionsProvider } from './suggestions_provider'; +import { AutocompleteService } from './autocomplete'; import { SearchService } from './search/search_service'; import { FieldFormatsService } from './field_formats_provider'; import { QueryService } from './query'; @@ -38,7 +37,7 @@ import { APPLY_FILTER_TRIGGER } from '../../embeddable/public'; import { createSearchBar } from './ui/search_bar/create_search_bar'; export class DataPublicPlugin implements Plugin { - private readonly autocomplete = new AutocompleteProviderRegister(); + private readonly autocomplete = new AutocompleteService(); private readonly searchService: SearchService; private readonly fieldFormatsService: FieldFormatsService; private readonly queryService: QueryService; @@ -62,7 +61,7 @@ export class DataPublicPlugin implements Plugin any; diff --git a/src/plugins/data/public/suggestions_provider/value_suggestions.ts b/src/plugins/data/public/suggestions_provider/value_suggestions.ts deleted file mode 100644 index c5de18c63b32d..0000000000000 --- a/src/plugins/data/public/suggestions_provider/value_suggestions.ts +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { memoize } from 'lodash'; - -import { IUiSettingsClient, HttpSetup } from 'src/core/public'; -import { IGetSuggestions } from './types'; -import { IIndexPattern, IFieldType } from '../../common'; - -export function getSuggestionsProvider( - uiSettings: IUiSettingsClient, - http: HttpSetup -): IGetSuggestions { - const requestSuggestions = memoize( - ( - index: string, - field: IFieldType, - query: string, - boolFilter: any = [], - signal?: AbortSignal - ) => { - return http.fetch(`/api/kibana/suggestions/values/${index}`, { - method: 'POST', - body: JSON.stringify({ query, field: field.name, boolFilter }), - signal, - }); - }, - resolver - ); - - return async ( - indexPattern: IIndexPattern, - field: IFieldType, - query: string, - boolFilter?: any, - signal?: AbortSignal - ) => { - const shouldSuggestValues = uiSettings.get('filterEditor:suggestValues'); - const index = indexPattern.title; - - if (field.type === 'boolean') { - return [true, false]; - } else if (!shouldSuggestValues || !field.aggregatable || field.type !== 'string') { - return []; - } - return await requestSuggestions(index, field, query, boolFilter, signal); - }; -} - -function resolver(index: string, field: IFieldType, query: string, boolFilter: any) { - // Only cache results for a minute - const ttl = Math.floor(Date.now() / 1000 / 60); - return [ttl, query, index, field.name, JSON.stringify(boolFilter)].join('|'); -} diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index 364d62fcbcaf5..bfe1a14b57546 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -23,7 +23,6 @@ import { IUiActionsSetup, IUiActionsStart } from 'src/plugins/ui_actions/public' import { autocomplete } from '.'; import { FieldFormatsSetup, FieldFormatsStart } from './field_formats_provider'; import { ISearchSetup, ISearchStart } from './search'; -import { IGetSuggestions } from './suggestions_provider/types'; import { QuerySetup, QueryStart } from './query'; import { IndexPatternSelectProps } from './ui/index_pattern_select'; import { IndexPatternsContract } from './index_patterns'; @@ -46,7 +45,6 @@ export interface DataPublicPluginSetup { export interface DataPublicPluginStart { autocomplete: autocomplete.AutocompletePublicPluginStart; - getSuggestions: IGetSuggestions; indexPatterns: IndexPatternsContract; search: ISearchStart; fieldFormats: FieldFormatsStart; @@ -57,8 +55,6 @@ export interface DataPublicPluginStart { }; } -export { IGetSuggestions } from './suggestions_provider/types'; - export interface IDataPluginServices extends Partial { appName: string; uiSettings: CoreStart['uiSettings']; diff --git a/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx b/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx index 5ace6412eff39..1e3285d308b0e 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx +++ b/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx @@ -69,8 +69,11 @@ export class PhraseSuggestorUI extends Component return; } this.setState({ isLoading: true }); - // todo: value suggestions - const suggestions = await this.services.data.getSuggestions(indexPattern, field, value); + + const suggestions = await this.services.data.autocomplete + .getSuggestionsProvider() + .getSuggestions(indexPattern, field, value); + this.setState({ suggestions, isLoading: false }); }, 500); } From 8e2d6ae215f318e8a75c034d03156e5187d4b47f Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Tue, 14 Jan 2020 15:07:28 +0300 Subject: [PATCH 06/11] fix PR comments --- .../autocomplete/autocomplete_service.ts | 33 ++--- src/plugins/data/public/autocomplete/index.ts | 4 +- ...t.ts => field_suggestion_provider.test.ts} | 119 +++++++++++++----- ...ovider.ts => field_suggestion_provider.ts} | 56 +++++---- ...ovider.ts => query_suggestion_provider.ts} | 28 ++--- src/plugins/data/public/autocomplete/types.ts | 27 ++-- src/plugins/data/public/mocks.ts | 5 +- src/plugins/data/public/types.ts | 6 +- .../filter_editor/phrase_suggestor.tsx | 10 +- .../query_string_input.test.tsx.snap | 30 +++-- .../query_string_input/query_string_input.tsx | 22 ++-- .../typeahead/suggestion_component.test.tsx | 2 +- .../ui/typeahead/suggestion_component.tsx | 4 +- .../typeahead/suggestions_component.test.tsx | 2 +- .../ui/typeahead/suggestions_component.tsx | 4 +- .../components/shared/KueryBar/index.tsx | 61 ++++----- .../components/autocomplete_field/index.tsx | 2 +- .../autocomplete_field/suggestion_item.tsx | 2 +- .../public/components/table/table.tsx | 2 +- .../containers/with_kuery_autocompletion.tsx | 4 +- .../adapters/elasticsearch/adapter_types.ts | 5 +- .../lib/adapters/elasticsearch/memory.ts | 4 +- .../public/lib/adapters/elasticsearch/rest.ts | 15 +-- .../public/lib/compose/memory.ts | 2 +- .../public/lib/elasticsearch.ts | 2 +- .../public/components/search_bar.test.tsx | 2 +- .../autocomplete_field/autocomplete_field.tsx | 2 +- .../autocomplete_field/suggestion_item.tsx | 2 +- .../containers/with_kuery_autocompletion.tsx | 21 ++-- .../public/autocomplete_providers/index.js | 49 -------- .../__fixtures__/index_pattern_response.json | 0 .../__tests__/conjunction.js | 0 .../__tests__/escape_kuery.js | 0 .../__tests__/field.js | 0 .../__tests__/operator.js | 0 .../conjunction.js | 0 .../escape_kuery.js | 0 .../field.js | 0 .../public/kql_query_suggestion/index.js | 58 +++++++++ .../operator.js | 0 .../sort_prefix_first.test.ts | 0 .../sort_prefix_first.ts | 0 .../value.js | 24 ++-- .../value.test.js | 0 .../kuery_autocomplete/public/plugin.ts | 6 +- .../components/kql_filter_bar/utils.js | 13 +- .../autocomplete_field/index.test.tsx | 2 +- .../components/autocomplete_field/index.tsx | 2 +- .../autocomplete_field/suggestion_item.tsx | 2 +- .../containers/kuery_autocompletion/index.tsx | 16 ++- .../components/functional/kuery_bar/index.tsx | 51 +++----- .../plugins/uptime/public/pages/overview.tsx | 7 +- .../legacy/plugins/uptime/public/routes.tsx | 4 +- 53 files changed, 372 insertions(+), 340 deletions(-) rename src/plugins/data/public/autocomplete/providers/{suggestions_provider.test.ts => field_suggestion_provider.test.ts} (59%) rename src/plugins/data/public/autocomplete/providers/{suggestions_provider.ts => field_suggestion_provider.ts} (68%) rename src/plugins/data/public/autocomplete/providers/{query_syntax_provider.ts => query_suggestion_provider.ts} (73%) delete mode 100644 x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/index.js rename x-pack/legacy/plugins/kuery_autocomplete/public/{autocomplete_providers => kql_query_suggestion}/__fixtures__/index_pattern_response.json (100%) rename x-pack/legacy/plugins/kuery_autocomplete/public/{autocomplete_providers => kql_query_suggestion}/__tests__/conjunction.js (100%) rename x-pack/legacy/plugins/kuery_autocomplete/public/{autocomplete_providers => kql_query_suggestion}/__tests__/escape_kuery.js (100%) rename x-pack/legacy/plugins/kuery_autocomplete/public/{autocomplete_providers => kql_query_suggestion}/__tests__/field.js (100%) rename x-pack/legacy/plugins/kuery_autocomplete/public/{autocomplete_providers => kql_query_suggestion}/__tests__/operator.js (100%) rename x-pack/legacy/plugins/kuery_autocomplete/public/{autocomplete_providers => kql_query_suggestion}/conjunction.js (100%) rename x-pack/legacy/plugins/kuery_autocomplete/public/{autocomplete_providers => kql_query_suggestion}/escape_kuery.js (100%) rename x-pack/legacy/plugins/kuery_autocomplete/public/{autocomplete_providers => kql_query_suggestion}/field.js (100%) create mode 100644 x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/index.js rename x-pack/legacy/plugins/kuery_autocomplete/public/{autocomplete_providers => kql_query_suggestion}/operator.js (100%) rename x-pack/legacy/plugins/kuery_autocomplete/public/{autocomplete_providers => kql_query_suggestion}/sort_prefix_first.test.ts (100%) rename x-pack/legacy/plugins/kuery_autocomplete/public/{autocomplete_providers => kql_query_suggestion}/sort_prefix_first.ts (100%) rename x-pack/legacy/plugins/kuery_autocomplete/public/{autocomplete_providers => kql_query_suggestion}/value.js (73%) rename x-pack/legacy/plugins/kuery_autocomplete/public/{autocomplete_providers => kql_query_suggestion}/value.test.js (100%) diff --git a/src/plugins/data/public/autocomplete/autocomplete_service.ts b/src/plugins/data/public/autocomplete/autocomplete_service.ts index 9a81015048215..a0f1317e218dd 100644 --- a/src/plugins/data/public/autocomplete/autocomplete_service.ts +++ b/src/plugins/data/public/autocomplete/autocomplete_service.ts @@ -18,47 +18,48 @@ */ import { CoreSetup } from 'src/core/public'; -import { QuerySyntaxProvider } from './types'; -import { SuggestionsProvider } from './providers/suggestions_provider'; +import { QuerySuggestionsGet } from './providers/query_suggestion_provider'; +import { + setupFieldSuggestionProvider, + FieldSuggestionsGet, +} from './providers/field_suggestion_provider'; export class AutocompleteService { - private readonly querySyntaxProviders: Map = new Map(); - private suggestionsProvider: SuggestionsProvider = new SuggestionsProvider(); + private readonly querySuggestionProviders: Map = new Map(); + private getFieldSuggestions?: FieldSuggestionsGet; - private addQuerySyntaxProvider = (language: string, provider: QuerySyntaxProvider): void => { + private addQuerySuggestionProvider = (language: string, provider: QuerySuggestionsGet): void => { if (language && provider) { - this.querySyntaxProviders.set(language, provider); + this.querySuggestionProviders.set(language, provider); } }; - private getQuerySyntaxProvider = (language: string): QuerySyntaxProvider | undefined => - this.querySyntaxProviders.get(language); - - private getSuggestionsProvider = (): SuggestionsProvider => this.suggestionsProvider; + private getQuerySuggestionProvider = (language: string) => + this.querySuggestionProviders.get(language); /** @public **/ public setup(core: CoreSetup) { - this.suggestionsProvider.setup(core); + this.getFieldSuggestions = setupFieldSuggestionProvider(core); return { - addQuerySyntaxProvider: this.addQuerySyntaxProvider, + addQuerySuggestionProvider: this.addQuerySuggestionProvider, /** @obsolete **/ /** please use "getProvider" only from the start contract **/ - getQuerySyntaxProvider: this.getQuerySyntaxProvider, + getQuerySuggestionProvider: this.getQuerySuggestionProvider, }; } /** @public **/ public start() { return { - getQuerySyntaxProvider: this.getQuerySyntaxProvider, - getSuggestionsProvider: this.getSuggestionsProvider, + getQuerySuggestionProvider: this.getQuerySuggestionProvider, + getFieldSuggestions: this.getFieldSuggestions!, }; } /** @internal **/ public clearProviders(): void { - this.querySyntaxProviders.clear(); + this.querySuggestionProviders.clear(); } } diff --git a/src/plugins/data/public/autocomplete/index.ts b/src/plugins/data/public/autocomplete/index.ts index 26ea9bdaeacc3..d4d9c708be37a 100644 --- a/src/plugins/data/public/autocomplete/index.ts +++ b/src/plugins/data/public/autocomplete/index.ts @@ -17,5 +17,5 @@ * under the License. */ -export * from './autocomplete_service'; -export * from './types'; +export { AutocompleteService } from './autocomplete_service'; +export { QuerySuggestion, QuerySuggestionType, QuerySuggestionsGet } from './types'; diff --git a/src/plugins/data/public/autocomplete/providers/suggestions_provider.test.ts b/src/plugins/data/public/autocomplete/providers/field_suggestion_provider.test.ts similarity index 59% rename from src/plugins/data/public/autocomplete/providers/suggestions_provider.test.ts rename to src/plugins/data/public/autocomplete/providers/field_suggestion_provider.test.ts index 407c4ddec5a46..dd323038e7630 100644 --- a/src/plugins/data/public/autocomplete/providers/suggestions_provider.test.ts +++ b/src/plugins/data/public/autocomplete/providers/field_suggestion_provider.test.ts @@ -18,11 +18,11 @@ */ import { stubIndexPattern, stubFields } from '../../stubs'; -import { SuggestionsProvider } from './suggestions_provider'; +import { setupFieldSuggestionProvider, FieldSuggestionsGet } from './field_suggestion_provider'; import { IUiSettingsClient, CoreSetup } from 'kibana/public'; -describe('getSuggestions', () => { - let suggestionsProvider: SuggestionsProvider; +describe('FieldSuggestions', () => { + let getFieldSuggestions: FieldSuggestionsGet; let http: any; let shouldSuggestValues: boolean; @@ -30,15 +30,16 @@ describe('getSuggestions', () => { const uiSettings = { get: (key: string) => shouldSuggestValues } as IUiSettingsClient; http = { fetch: jest.fn() }; - suggestionsProvider = new SuggestionsProvider(); - suggestionsProvider.setup({ http, uiSettings } as CoreSetup); + getFieldSuggestions = setupFieldSuggestionProvider({ http, uiSettings } as CoreSetup); }); describe('with value suggestions disabled', () => { it('should return an empty array', async () => { - const [field] = stubFields; - const query = ''; - const suggestions = await suggestionsProvider.getSuggestions(stubIndexPattern, field, query); + const suggestions = await getFieldSuggestions({ + indexPattern: stubIndexPattern, + field: stubFields[0], + query: '', + }); expect(suggestions).toEqual([]); expect(http.fetch).not.toHaveBeenCalled(); @@ -50,8 +51,11 @@ describe('getSuggestions', () => { it('should return true/false for boolean fields', async () => { const [field] = stubFields.filter(({ type }) => type === 'boolean'); - const query = ''; - const suggestions = await suggestionsProvider.getSuggestions(stubIndexPattern, field, query); + const suggestions = await getFieldSuggestions({ + indexPattern: stubIndexPattern, + field, + query: '', + }); expect(suggestions).toEqual([true, false]); expect(http.fetch).not.toHaveBeenCalled(); @@ -59,8 +63,11 @@ describe('getSuggestions', () => { it('should return an empty array if the field type is not a string or boolean', async () => { const [field] = stubFields.filter(({ type }) => type !== 'string' && type !== 'boolean'); - const query = ''; - const suggestions = await suggestionsProvider.getSuggestions(stubIndexPattern, field, query); + const suggestions = await getFieldSuggestions({ + indexPattern: stubIndexPattern, + field, + query: '', + }); expect(suggestions).toEqual([]); expect(http.fetch).not.toHaveBeenCalled(); @@ -68,8 +75,11 @@ describe('getSuggestions', () => { it('should return an empty array if the field is not aggregatable', async () => { const [field] = stubFields.filter(({ aggregatable }) => !aggregatable); - const query = ''; - const suggestions = await suggestionsProvider.getSuggestions(stubIndexPattern, field, query); + const suggestions = await getFieldSuggestions({ + indexPattern: stubIndexPattern, + field, + query: '', + }); expect(suggestions).toEqual([]); expect(http.fetch).not.toHaveBeenCalled(); @@ -79,9 +89,13 @@ describe('getSuggestions', () => { const [field] = stubFields.filter( ({ type, aggregatable }) => type === 'string' && aggregatable ); - const query = ''; - await suggestionsProvider.getSuggestions(stubIndexPattern, field, query); + await getFieldSuggestions({ + indexPattern: stubIndexPattern, + field, + query: '', + }); + expect(http.fetch).toHaveBeenCalled(); }); @@ -89,10 +103,14 @@ describe('getSuggestions', () => { const [field] = stubFields.filter( ({ type, aggregatable }) => type === 'string' && aggregatable ); - const query = ''; + const args = { + indexPattern: stubIndexPattern, + field, + query: '', + }; - await suggestionsProvider.getSuggestions(stubIndexPattern, field, query); - await suggestionsProvider.getSuggestions(stubIndexPattern, field, query); + await getFieldSuggestions(args); + await getFieldSuggestions(args); expect(http.fetch).toHaveBeenCalledTimes(1); }); @@ -101,13 +119,19 @@ describe('getSuggestions', () => { const [field] = stubFields.filter( ({ type, aggregatable }) => type === 'string' && aggregatable ); - const query = ''; + const args = { + indexPattern: stubIndexPattern, + field, + query: '', + }; const { now } = Date; Date.now = jest.fn(() => 0); - await suggestionsProvider.getSuggestions(stubIndexPattern, field, query); + + await getFieldSuggestions(args); + Date.now = jest.fn(() => 60 * 1000); - await suggestionsProvider.getSuggestions(stubIndexPattern, field, query); + await getFieldSuggestions(args); Date.now = now; expect(http.fetch).toHaveBeenCalledTimes(2); @@ -117,20 +141,53 @@ describe('getSuggestions', () => { const fields = stubFields.filter( ({ type, aggregatable }) => type === 'string' && aggregatable ); + + await getFieldSuggestions({ + indexPattern: stubIndexPattern, + field: fields[0], + query: '', + }); + await getFieldSuggestions({ + indexPattern: stubIndexPattern, + field: fields[0], + query: 'query', + }); + await getFieldSuggestions({ + indexPattern: stubIndexPattern, + field: fields[1], + query: '', + }); + await getFieldSuggestions({ + indexPattern: stubIndexPattern, + field: fields[1], + query: 'query', + }); + const customIndexPattern = { ...stubIndexPattern, title: 'customIndexPattern', }; - await suggestionsProvider.getSuggestions(stubIndexPattern, fields[0], ''); - await suggestionsProvider.getSuggestions(stubIndexPattern, fields[0], 'query'); - await suggestionsProvider.getSuggestions(stubIndexPattern, fields[1], ''); - await suggestionsProvider.getSuggestions(stubIndexPattern, fields[1], 'query'); - - await suggestionsProvider.getSuggestions(customIndexPattern, fields[0], ''); - await suggestionsProvider.getSuggestions(customIndexPattern, fields[0], 'query'); - await suggestionsProvider.getSuggestions(customIndexPattern, fields[1], ''); - await suggestionsProvider.getSuggestions(customIndexPattern, fields[1], 'query'); + await getFieldSuggestions({ + indexPattern: customIndexPattern, + field: fields[0], + query: '', + }); + await getFieldSuggestions({ + indexPattern: customIndexPattern, + field: fields[0], + query: 'query', + }); + await getFieldSuggestions({ + indexPattern: customIndexPattern, + field: fields[1], + query: '', + }); + await getFieldSuggestions({ + indexPattern: customIndexPattern, + field: fields[1], + query: 'query', + }); expect(http.fetch).toHaveBeenCalledTimes(8); }); diff --git a/src/plugins/data/public/autocomplete/providers/suggestions_provider.ts b/src/plugins/data/public/autocomplete/providers/field_suggestion_provider.ts similarity index 68% rename from src/plugins/data/public/autocomplete/providers/suggestions_provider.ts rename to src/plugins/data/public/autocomplete/providers/field_suggestion_provider.ts index ee4054174eeec..0d63e47f30750 100644 --- a/src/plugins/data/public/autocomplete/providers/suggestions_provider.ts +++ b/src/plugins/data/public/autocomplete/providers/field_suggestion_provider.ts @@ -28,21 +28,35 @@ function resolver(title: string, field: IFieldType, query: string, boolFilter: a return [ttl, query, title, field.name, JSON.stringify(boolFilter)].join('|'); } -export class SuggestionsProvider { - private core?: CoreSetup; +export type FieldSuggestionsGet = (args: FieldSuggestionsGetArgs) => Promise; - setup(core: CoreSetup) { - this.core = core; - } +interface FieldSuggestionsGetArgs { + indexPattern: IIndexPattern; + field: IFieldType; + query: string; + boolFilter?: any[]; + signal?: AbortSignal; +} + +export const setupFieldSuggestionProvider = (core: CoreSetup): FieldSuggestionsGet => { + const requestSuggestions = memoize( + (index: string, field: IFieldType, query: string, boolFilter: any = [], signal?: AbortSignal) => + core.http.fetch(`/api/kibana/suggestions/values/${index}`, { + method: 'POST', + body: JSON.stringify({ query, field: field.name, boolFilter }), + signal, + }), + resolver + ); - async getSuggestions( - indexPattern: IIndexPattern, - field: IFieldType, - query: string, - boolFilter?: any, - signal?: AbortSignal - ): Promise { - const shouldSuggestValues = this.core!.uiSettings.get('filterEditor:suggestValues'); + return async ({ + indexPattern, + field, + query, + boolFilter, + signal, + }: FieldSuggestionsGetArgs): Promise => { + const shouldSuggestValues = core!.uiSettings.get('filterEditor:suggestValues'); const { title } = indexPattern; if (field.type === 'boolean') { @@ -51,16 +65,6 @@ export class SuggestionsProvider { return []; } - return await this.requestSuggestions(title, field, query, boolFilter, signal); - } - - private requestSuggestions = memoize( - (index: string, field: IFieldType, query: string, boolFilter: any = [], signal?: AbortSignal) => - this.core!.http.fetch(`/api/kibana/suggestions/values/${index}`, { - method: 'POST', - body: JSON.stringify({ query, field: field.name, boolFilter }), - signal, - }), - resolver - ); -} + return await requestSuggestions(title, field, query, boolFilter, signal); + }; +}; diff --git a/src/plugins/data/public/autocomplete/providers/query_syntax_provider.ts b/src/plugins/data/public/autocomplete/providers/query_suggestion_provider.ts similarity index 73% rename from src/plugins/data/public/autocomplete/providers/query_syntax_provider.ts rename to src/plugins/data/public/autocomplete/providers/query_suggestion_provider.ts index 931bdd0470071..9799ff87feb97 100644 --- a/src/plugins/data/public/autocomplete/providers/query_syntax_provider.ts +++ b/src/plugins/data/public/autocomplete/providers/query_suggestion_provider.ts @@ -19,27 +19,21 @@ import { IFieldType, IIndexPattern } from '../../../common/index_patterns'; -export type QuerySyntaxSuggestionType = - | 'field' - | 'value' - | 'operator' - | 'conjunction' - | 'recentSearch'; +export type QuerySuggestionType = 'field' | 'value' | 'operator' | 'conjunction' | 'recentSearch'; -export type QuerySyntaxProvider = (args: { - indexPatterns: IIndexPattern[]; - boolFilter?: any; -}) => QuerySyntaxGetSuggestions; +export type QuerySuggestionsGet = (args: QuerySuggestionsGetArgs) => Promise; -export type QuerySyntaxGetSuggestions = (args: { +interface QuerySuggestionsGetArgs { + indexPatterns: IIndexPattern[]; query: string; selectionStart: number; selectionEnd: number; signal?: AbortSignal; -}) => Promise; + boolFilter?: any; +} -interface BasicQuerySyntaxSuggestion { - type: QuerySyntaxSuggestionType; +interface BasicQuerySuggestion { + type: QuerySuggestionType; description?: string; end: number; start: number; @@ -47,13 +41,13 @@ interface BasicQuerySyntaxSuggestion { cursorIndex?: number; } -type FieldQuerySyntaxSuggestion = BasicQuerySyntaxSuggestion & { +interface FieldQuerySuggestion extends BasicQuerySuggestion { type: 'field'; field: IFieldType; -}; +} // A union type allows us to do easy type guards in the code. For example, if I want to ensure I'm // working with a FieldAutocompleteSuggestion, I can just do `if ('field' in suggestion)` and the // TypeScript compiler will narrow the type to the parts of the union that have a field prop. /** @public **/ -export type QuerySyntaxSuggestion = BasicQuerySyntaxSuggestion | FieldQuerySyntaxSuggestion; +export type QuerySuggestion = BasicQuerySuggestion | FieldQuerySuggestion; diff --git a/src/plugins/data/public/autocomplete/types.ts b/src/plugins/data/public/autocomplete/types.ts index 99545073a32f9..d604f800536d6 100644 --- a/src/plugins/data/public/autocomplete/types.ts +++ b/src/plugins/data/public/autocomplete/types.ts @@ -17,30 +17,17 @@ * under the License. */ -import { AutocompleteService } from '.'; - -import { - QuerySyntaxSuggestionType, - QuerySyntaxGetSuggestions, - QuerySyntaxSuggestion, - QuerySyntaxProvider, -} from './providers/query_syntax_provider'; - -import { SuggestionsProvider } from './providers/suggestions_provider'; +import { AutocompleteService } from './autocomplete_service'; /** @public **/ -export type AutocompletePublicPluginSetup = ReturnType; +export type AutocompleteSetup = ReturnType; /** @public **/ -export type AutocompletePublicPluginStart = ReturnType; +export type AutocompleteStart = ReturnType; /** @public **/ export { - QuerySyntaxSuggestionType, - QuerySyntaxSuggestion, - QuerySyntaxGetSuggestions, - QuerySyntaxProvider, -}; - -/** @public **/ -export { SuggestionsProvider }; + QuerySuggestion, + QuerySuggestionsGet, + QuerySuggestionType, +} from './providers/query_suggestion_provider'; diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index 353b160c5f38d..2d68ef663d84d 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -30,8 +30,9 @@ export type Setup = jest.Mocked>; export type Start = jest.Mocked>; const autocompleteMock: any = { - addQuerySyntaxProvider: jest.fn(), - getQuerySyntaxProvider: jest.fn(), + addQuerySuggestionProvider: jest.fn(), + getQuerySuggestionProvider: jest.fn(), + getFieldSuggestions: jest.fn(), }; const fieldFormatsMock: PublicMethodsOf = { diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index bfe1a14b57546..d2af256302248 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -20,7 +20,7 @@ import { CoreStart } from 'src/core/public'; import { IStorageWrapper } from 'src/plugins/kibana_utils/public'; import { IUiActionsSetup, IUiActionsStart } from 'src/plugins/ui_actions/public'; -import { autocomplete } from '.'; +import { AutocompleteSetup, AutocompleteStart } from './autocomplete/types'; import { FieldFormatsSetup, FieldFormatsStart } from './field_formats_provider'; import { ISearchSetup, ISearchStart } from './search'; import { QuerySetup, QueryStart } from './query'; @@ -37,14 +37,14 @@ export interface DataStartDependencies { } export interface DataPublicPluginSetup { - autocomplete: autocomplete.AutocompletePublicPluginSetup; + autocomplete: AutocompleteSetup; search: ISearchSetup; fieldFormats: FieldFormatsSetup; query: QuerySetup; } export interface DataPublicPluginStart { - autocomplete: autocomplete.AutocompletePublicPluginStart; + autocomplete: AutocompleteStart; indexPatterns: IndexPatternsContract; search: ISearchStart; fieldFormats: FieldFormatsStart; diff --git a/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx b/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx index 1e3285d308b0e..bec610cb904c6 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx +++ b/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx @@ -63,16 +63,18 @@ export class PhraseSuggestorUI extends Component this.updateSuggestions(`${value}`); }; - protected updateSuggestions = debounce(async (value: string = '') => { + protected updateSuggestions = debounce(async (query: string = '') => { const { indexPattern, field } = this.props as PhraseSuggestorProps; if (!field || !this.isSuggestingValues()) { return; } this.setState({ isLoading: true }); - const suggestions = await this.services.data.autocomplete - .getSuggestionsProvider() - .getSuggestions(indexPattern, field, value); + const suggestions = await this.services.data.autocomplete.getFieldSuggestions({ + indexPattern, + field, + query, + }); this.setState({ suggestions, isLoading: false }); }, 500); diff --git a/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap b/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap index 51e1f132be13c..e7c6d6b940431 100644 --- a/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap +++ b/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap @@ -151,8 +151,9 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA }, "data": Object { "autocomplete": Object { - "addQuerySyntaxProvider": [MockFunction], - "getQuerySyntaxProvider": [MockFunction], + "addQuerySuggestionProvider": [MockFunction], + "getFieldSuggestions": [MockFunction], + "getQuerySuggestionProvider": [MockFunction], }, "fieldFormats": Object { "getByFieldType": [MockFunction], @@ -773,8 +774,9 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA }, "data": Object { "autocomplete": Object { - "addQuerySyntaxProvider": [MockFunction], - "getQuerySyntaxProvider": [MockFunction], + "addQuerySuggestionProvider": [MockFunction], + "getFieldSuggestions": [MockFunction], + "getQuerySuggestionProvider": [MockFunction], }, "fieldFormats": Object { "getByFieldType": [MockFunction], @@ -1383,8 +1385,9 @@ exports[`QueryStringInput Should pass the query language to the language switche }, "data": Object { "autocomplete": Object { - "addQuerySyntaxProvider": [MockFunction], - "getQuerySyntaxProvider": [MockFunction], + "addQuerySuggestionProvider": [MockFunction], + "getFieldSuggestions": [MockFunction], + "getQuerySuggestionProvider": [MockFunction], }, "fieldFormats": Object { "getByFieldType": [MockFunction], @@ -2002,8 +2005,9 @@ exports[`QueryStringInput Should pass the query language to the language switche }, "data": Object { "autocomplete": Object { - "addQuerySyntaxProvider": [MockFunction], - "getQuerySyntaxProvider": [MockFunction], + "addQuerySuggestionProvider": [MockFunction], + "getFieldSuggestions": [MockFunction], + "getQuerySuggestionProvider": [MockFunction], }, "fieldFormats": Object { "getByFieldType": [MockFunction], @@ -2612,8 +2616,9 @@ exports[`QueryStringInput Should render the given query 1`] = ` }, "data": Object { "autocomplete": Object { - "addQuerySyntaxProvider": [MockFunction], - "getQuerySyntaxProvider": [MockFunction], + "addQuerySuggestionProvider": [MockFunction], + "getFieldSuggestions": [MockFunction], + "getQuerySuggestionProvider": [MockFunction], }, "fieldFormats": Object { "getByFieldType": [MockFunction], @@ -3231,8 +3236,9 @@ exports[`QueryStringInput Should render the given query 1`] = ` }, "data": Object { "autocomplete": Object { - "addQuerySyntaxProvider": [MockFunction], - "getQuerySyntaxProvider": [MockFunction], + "addQuerySuggestionProvider": [MockFunction], + "getFieldSuggestions": [MockFunction], + "getQuerySuggestionProvider": [MockFunction], }, "fieldFormats": Object { "getByFieldType": [MockFunction], diff --git a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx index 6b9136f1b339f..c34dc2dea3d54 100644 --- a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx +++ b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx @@ -70,7 +70,7 @@ interface Props { interface State { isSuggestionsVisible: boolean; index: number | null; - suggestions: autocomplete.QuerySyntaxSuggestion[]; + suggestions: autocomplete.QuerySuggestion[]; suggestionLimit: number; selectionStart: number | null; selectionEnd: number | null; @@ -89,7 +89,7 @@ const KEY_CODES = { END: 35, }; -const recentSearchType: autocomplete.QuerySyntaxSuggestionType = 'recentSearch'; +const recentSearchType: autocomplete.QuerySuggestionType = 'recentSearch'; export class QueryStringInputUI extends Component { public state: State = { @@ -141,10 +141,12 @@ export class QueryStringInputUI extends Component { const queryString = this.getQueryString(); const recentSearchSuggestions = this.getRecentSearchSuggestions(queryString); - const autocompleteProvider = this.services.data.autocomplete.getQuerySyntaxProvider(language); + const getQuerySuggestions = this.services.data.autocomplete.getQuerySuggestionProvider( + language + ); if ( - !autocompleteProvider || + !getQuerySuggestions || !Array.isArray(this.state.indexPatterns) || compact(this.state.indexPatterns).length === 0 ) { @@ -152,7 +154,6 @@ export class QueryStringInputUI extends Component { } const indexPatterns = this.state.indexPatterns; - const getAutocompleteSuggestions = autocompleteProvider({ indexPatterns }); const { selectionStart, selectionEnd } = this.inputRef; if (selectionStart === null || selectionEnd === null) { @@ -162,7 +163,8 @@ export class QueryStringInputUI extends Component { try { if (this.abortController) this.abortController.abort(); this.abortController = new AbortController(); - const suggestions = await getAutocompleteSuggestions({ + const suggestions = await getQuerySuggestions({ + indexPatterns, query: queryString, selectionStart, selectionEnd, @@ -316,7 +318,7 @@ export class QueryStringInputUI extends Component { } }; - private selectSuggestion = (suggestion: autocomplete.QuerySyntaxSuggestion) => { + private selectSuggestion = (suggestion: autocomplete.QuerySuggestion) => { if (!this.inputRef) { return; } @@ -346,9 +348,7 @@ export class QueryStringInputUI extends Component { } }; - private handleNestedFieldSyntaxNotification = ( - suggestion: autocomplete.QuerySyntaxSuggestion - ) => { + private handleNestedFieldSyntaxNotification = (suggestion: autocomplete.QuerySuggestion) => { if ( 'field' in suggestion && suggestion.field.subType && @@ -450,7 +450,7 @@ export class QueryStringInputUI extends Component { } }; - private onClickSuggestion = (suggestion: autocomplete.QuerySyntaxSuggestion) => { + private onClickSuggestion = (suggestion: autocomplete.QuerySuggestion) => { if (!this.inputRef) { return; } diff --git a/src/plugins/data/public/ui/typeahead/suggestion_component.test.tsx b/src/plugins/data/public/ui/typeahead/suggestion_component.test.tsx index d8c9f4860addd..0c5c701642757 100644 --- a/src/plugins/data/public/ui/typeahead/suggestion_component.test.tsx +++ b/src/plugins/data/public/ui/typeahead/suggestion_component.test.tsx @@ -26,7 +26,7 @@ const noop = () => { return; }; -const mockSuggestion: autocomplete.QuerySyntaxSuggestion = { +const mockSuggestion: autocomplete.QuerySuggestion = { description: 'This is not a helpful suggestion', end: 0, start: 42, diff --git a/src/plugins/data/public/ui/typeahead/suggestion_component.tsx b/src/plugins/data/public/ui/typeahead/suggestion_component.tsx index 35003a7ffd0a4..1d2ac8dee1a8a 100644 --- a/src/plugins/data/public/ui/typeahead/suggestion_component.tsx +++ b/src/plugins/data/public/ui/typeahead/suggestion_component.tsx @@ -40,10 +40,10 @@ function getEuiIconType(type: string) { } interface Props { - onClick: (suggestion: autocomplete.QuerySyntaxSuggestion) => void; + onClick: (suggestion: autocomplete.QuerySuggestion) => void; onMouseEnter: () => void; selected: boolean; - suggestion: autocomplete.QuerySyntaxSuggestion; + suggestion: autocomplete.QuerySuggestion; innerRef: (node: HTMLDivElement) => void; ariaId: string; } diff --git a/src/plugins/data/public/ui/typeahead/suggestions_component.test.tsx b/src/plugins/data/public/ui/typeahead/suggestions_component.test.tsx index 0822900604639..b84f612b6d13a 100644 --- a/src/plugins/data/public/ui/typeahead/suggestions_component.test.tsx +++ b/src/plugins/data/public/ui/typeahead/suggestions_component.test.tsx @@ -27,7 +27,7 @@ const noop = () => { return; }; -const mockSuggestions: autocomplete.QuerySyntaxSuggestion[] = [ +const mockSuggestions: autocomplete.QuerySuggestion[] = [ { description: 'This is not a helpful suggestion', end: 0, diff --git a/src/plugins/data/public/ui/typeahead/suggestions_component.tsx b/src/plugins/data/public/ui/typeahead/suggestions_component.tsx index a06026e70fbd4..b37a2e479e874 100644 --- a/src/plugins/data/public/ui/typeahead/suggestions_component.tsx +++ b/src/plugins/data/public/ui/typeahead/suggestions_component.tsx @@ -24,10 +24,10 @@ import { SuggestionComponent } from './suggestion_component'; interface Props { index: number | null; - onClick: (suggestion: autocomplete.QuerySyntaxSuggestion) => void; + onClick: (suggestion: autocomplete.QuerySuggestion) => void; onMouseEnter: (index: number) => void; show: boolean; - suggestions: autocomplete.QuerySyntaxSuggestion[]; + suggestions: autocomplete.QuerySuggestion[]; loadMore: () => void; } diff --git a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx index 0375ff8cdf108..af2a5593c616f 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx @@ -18,7 +18,7 @@ import { history } from '../../../utils/history'; import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; import { useDynamicIndexPattern } from '../../../hooks/useDynamicIndexPattern'; import { - autocomplete as autocompleteNamespace, + autocomplete, esKuery, IIndexPattern } from '../../../../../../../../src/plugins/data/public'; @@ -28,7 +28,7 @@ const Container = styled.div` `; interface State { - suggestions: autocompleteNamespace.QuerySyntaxSuggestion[]; + suggestions: autocomplete.QuerySuggestion[]; isLoadingSuggestions: boolean; } @@ -37,28 +37,6 @@ function convertKueryToEsQuery(kuery: string, indexPattern: IIndexPattern) { return esKuery.toElasticsearchQuery(ast, indexPattern); } -function getSuggestions( - query: string, - selectionStart: number, - indexPattern: IIndexPattern, - boolFilter: unknown, - autocompleteProvider?: autocompleteNamespace.QuerySyntaxProvider -) { - if (!autocompleteProvider) { - return []; - } - - const getAutocompleteSuggestions = autocompleteProvider({ - indexPatterns: [indexPattern], - boolFilter - }); - return getAutocompleteSuggestions({ - query, - selectionStart, - selectionEnd: selectionStart - }); -} - export function KueryBar() { const [state, setState] = useState({ suggestions: [], @@ -66,10 +44,6 @@ export function KueryBar() { }); const { urlParams } = useUrlParams(); const location = useLocation(); - const { data } = useApmPluginContext().plugins; - const autocompleteProvider = data.autocomplete.getQuerySyntaxProvider( - 'kuery' - ); let currentRequestCheck; @@ -83,6 +57,28 @@ export function KueryBar() { 'transaction.duration.us > 300000 AND http.response.status_code >= 400' }; + const getSuggestions = ( + query: string, + selectionStart: number, + indexPattern: IIndexPattern, + boolFilter: unknown, + ): Promise | undefined => { + const { data } = useApmPluginContext().plugins; + const getQuerySuggestions = data.autocomplete.getQuerySuggestionProvider( + 'kuery' + ); + + if (getQuerySuggestions) { + return getQuerySuggestions({ + indexPatterns: [indexPattern], + boolFilter, + query, + selectionStart, + selectionEnd: selectionStart + }); + } + } + const example = examples[processorEvent || 'defaults']; const { indexPattern } = useDynamicIndexPattern(processorEvent); @@ -104,13 +100,10 @@ export function KueryBar() { inputValue, selectionStart, indexPattern, - boolFilter, - autocompleteProvider - ) + boolFilter + ) || [] ) - .filter( - suggestion => suggestion && !startsWith(suggestion.text, 'span.') - ) + .filter(suggestion => !startsWith(suggestion.text, 'span.')) .slice(0, 15); if (currentRequest !== currentRequestCheck) { diff --git a/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/index.tsx b/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/index.tsx index 5ddbd1660e9b7..f3e0f3dfbdae7 100644 --- a/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/index.tsx +++ b/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/index.tsx @@ -25,7 +25,7 @@ interface AutocompleteFieldProps { onSubmit?: (value: string) => void; onChange?: (value: string) => void; placeholder?: string; - suggestions: autocomplete.QuerySyntaxSuggestion[]; + suggestions: autocomplete.QuerySuggestion[]; value: string; } diff --git a/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/suggestion_item.tsx b/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/suggestion_item.tsx index 994ad4834afc7..0132667b9e510 100644 --- a/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/suggestion_item.tsx +++ b/x-pack/legacy/plugins/beats_management/public/components/autocomplete_field/suggestion_item.tsx @@ -15,7 +15,7 @@ interface SuggestionItemProps { isSelected?: boolean; onClick?: React.MouseEventHandler; onMouseEnter?: React.MouseEventHandler; - suggestion: autocomplete.QuerySyntaxSuggestion; + suggestion: autocomplete.QuerySuggestion; } export const SuggestionItem: React.FC = props => { diff --git a/x-pack/legacy/plugins/beats_management/public/components/table/table.tsx b/x-pack/legacy/plugins/beats_management/public/components/table/table.tsx index a3d9a4f7daa54..d1cbc0888dca8 100644 --- a/x-pack/legacy/plugins/beats_management/public/components/table/table.tsx +++ b/x-pack/legacy/plugins/beats_management/public/components/table/table.tsx @@ -31,7 +31,7 @@ export interface KueryBarProps { loadSuggestions: (value: string, cursorPosition: number, maxCount?: number) => void; onChange?: (value: string) => void; onSubmit?: (value: string) => void; - suggestions: autocomplete.QuerySyntaxSuggestion[]; + suggestions: autocomplete.QuerySuggestion[]; value: string; } diff --git a/x-pack/legacy/plugins/beats_management/public/containers/with_kuery_autocompletion.tsx b/x-pack/legacy/plugins/beats_management/public/containers/with_kuery_autocompletion.tsx index dca8df7d193a7..db73a7cb38c11 100644 --- a/x-pack/legacy/plugins/beats_management/public/containers/with_kuery_autocompletion.tsx +++ b/x-pack/legacy/plugins/beats_management/public/containers/with_kuery_autocompletion.tsx @@ -17,7 +17,7 @@ interface WithKueryAutocompletionLifecycleProps { children: RendererFunction<{ isLoadingSuggestions: boolean; loadSuggestions: (expression: string, cursorPosition: number, maxSuggestions?: number) => void; - suggestions: autocomplete.QuerySyntaxSuggestion[]; + suggestions: autocomplete.QuerySuggestion[]; }>; } @@ -28,7 +28,7 @@ interface WithKueryAutocompletionLifecycleState { expression: string; cursorPosition: number; } | null; - suggestions: autocomplete.QuerySyntaxSuggestion[]; + suggestions: autocomplete.QuerySuggestion[]; } export class WithKueryAutocompletion extends React.Component< diff --git a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/adapter_types.ts b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/adapter_types.ts index 1f026fcbcf85f..12898027d5fb5 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/adapter_types.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/adapter_types.ts @@ -7,9 +7,6 @@ import { autocomplete } from '../../../../../../../../src/plugins/data/public'; export interface ElasticsearchAdapter { convertKueryToEsQuery: (kuery: string) => Promise; - getSuggestions: ( - kuery: string, - selectionStart: any - ) => Promise; + getSuggestions: (kuery: string, selectionStart: any) => Promise; isKueryValid(kuery: string): boolean; } diff --git a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/memory.ts b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/memory.ts index 59061006a037d..111255b55c99b 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/memory.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/memory.ts @@ -11,7 +11,7 @@ export class MemoryElasticsearchAdapter implements ElasticsearchAdapter { constructor( private readonly mockIsKueryValid: (kuery: string) => boolean, private readonly mockKueryToEsQuery: (kuery: string) => string, - private readonly suggestions: autocomplete.QuerySyntaxSuggestion[] + private readonly suggestions: autocomplete.QuerySuggestion[] ) {} public isKueryValid(kuery: string): boolean { @@ -23,7 +23,7 @@ export class MemoryElasticsearchAdapter implements ElasticsearchAdapter { public async getSuggestions( kuery: string, selectionStart: any - ): Promise { + ): Promise { return this.suggestions; } } diff --git a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts index a3945c4bd0445..768e700e23041 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts @@ -9,8 +9,8 @@ import { npStart } from 'ui/new_platform'; import { ElasticsearchAdapter } from './adapter_types'; import { autocomplete, esKuery } from '../../../../../../../../src/plugins/data/public'; -const getAutocompleteProvider = (language: string) => - npStart.plugins.data.autocomplete.getQuerySyntaxProvider(language); +const getQuerySuggestionProvider = (language: string) => + npStart.plugins.data.autocomplete.getQuerySuggestionProvider(language); export class RestElasticsearchAdapter implements ElasticsearchAdapter { private cachedIndexPattern: any = null; @@ -36,23 +36,20 @@ export class RestElasticsearchAdapter implements ElasticsearchAdapter { public async getSuggestions( kuery: string, selectionStart: any - ): Promise { - const autocompleteProvider = getAutocompleteProvider('kuery'); - if (!autocompleteProvider) { + ): Promise { + const getQuerySuggestions = getQuerySuggestionProvider('kuery'); + if (!getQuerySuggestions) { return []; } const indexPattern = await this.getIndexPattern(); - const getAutocompleteSuggestions = autocompleteProvider({ + return getQuerySuggestions({ indexPatterns: [indexPattern], boolFilter: null, - }); - const results = getAutocompleteSuggestions({ query: kuery || '', selectionStart, selectionEnd: selectionStart, }); - return results; } private async getIndexPattern() { diff --git a/x-pack/legacy/plugins/beats_management/public/lib/compose/memory.ts b/x-pack/legacy/plugins/beats_management/public/lib/compose/memory.ts index ab7f72d2a5bb7..47df51dea8620 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/compose/memory.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/compose/memory.ts @@ -31,7 +31,7 @@ const onKibanaReady = uiModules.get('kibana').run; export function compose( mockIsKueryValid: (kuery: string) => boolean, mockKueryToEsQuery: (kuery: string) => string, - suggestions: autocomplete.QuerySyntaxSuggestion[] + suggestions: autocomplete.QuerySuggestion[] ): FrontendLibs { const esAdapter = new MemoryElasticsearchAdapter( mockIsKueryValid, diff --git a/x-pack/legacy/plugins/beats_management/public/lib/elasticsearch.ts b/x-pack/legacy/plugins/beats_management/public/lib/elasticsearch.ts index c885129c27ee3..d71512e80d3d5 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/elasticsearch.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/elasticsearch.ts @@ -35,7 +35,7 @@ export class ElasticsearchLib { kuery: string, selectionStart: any, fieldPrefix?: string - ): Promise { + ): Promise { const suggestions = await this.adapter.getSuggestions(kuery, selectionStart); const filteredSuggestions = suggestions.filter(suggestion => { diff --git a/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx b/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx index 98916a19bebdb..3f5e53f6f45f3 100644 --- a/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx +++ b/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx @@ -51,7 +51,7 @@ function wrapSearchBarInContext(testProps: OuterSearchBarProps) { savedQueries: {}, }, autocomplete: { - getQuerySyntaxProvider: () => undefined, + getQuerySuggestionProvider: () => undefined, }, }, }; diff --git a/x-pack/legacy/plugins/infra/public/components/autocomplete_field/autocomplete_field.tsx b/x-pack/legacy/plugins/infra/public/components/autocomplete_field/autocomplete_field.tsx index 9418fb8ee9510..dc6eabb325d16 100644 --- a/x-pack/legacy/plugins/infra/public/components/autocomplete_field/autocomplete_field.tsx +++ b/x-pack/legacy/plugins/infra/public/components/autocomplete_field/autocomplete_field.tsx @@ -25,7 +25,7 @@ interface AutocompleteFieldProps { onSubmit?: (value: string) => void; onChange?: (value: string) => void; placeholder?: string; - suggestions: autocomplete.QuerySyntaxSuggestion[]; + suggestions: autocomplete.QuerySuggestion[]; value: string; autoFocus?: boolean; 'aria-label'?: string; diff --git a/x-pack/legacy/plugins/infra/public/components/autocomplete_field/suggestion_item.tsx b/x-pack/legacy/plugins/infra/public/components/autocomplete_field/suggestion_item.tsx index c63ca56a022bb..79b18f5888bd5 100644 --- a/x-pack/legacy/plugins/infra/public/components/autocomplete_field/suggestion_item.tsx +++ b/x-pack/legacy/plugins/infra/public/components/autocomplete_field/suggestion_item.tsx @@ -15,7 +15,7 @@ interface Props { isSelected?: boolean; onClick?: React.MouseEventHandler; onMouseEnter?: React.MouseEventHandler; - suggestion: autocomplete.QuerySyntaxSuggestion; + suggestion: autocomplete.QuerySuggestion; } export const SuggestionItem: React.FC = props => { diff --git a/x-pack/legacy/plugins/infra/public/containers/with_kuery_autocompletion.tsx b/x-pack/legacy/plugins/infra/public/containers/with_kuery_autocompletion.tsx index 16fcbcfc9708b..4cc5b476d86dd 100644 --- a/x-pack/legacy/plugins/infra/public/containers/with_kuery_autocompletion.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/with_kuery_autocompletion.tsx @@ -9,14 +9,14 @@ import { npStart } from 'ui/new_platform'; import { autocomplete, IIndexPattern } from 'src/plugins/data/public'; import { RendererFunction } from '../utils/typed_react'; -const getAutocompleteProvider = (language: string) => - npStart.plugins.data.autocomplete.getQuerySyntaxProvider(language); +const getQuerySuggestionProvider = (language: string) => + npStart.plugins.data.autocomplete.getQuerySuggestionProvider(language); interface WithKueryAutocompletionLifecycleProps { children: RendererFunction<{ isLoadingSuggestions: boolean; loadSuggestions: (expression: string, cursorPosition: number, maxSuggestions?: number) => void; - suggestions: autocomplete.QuerySyntaxSuggestion[]; + suggestions: autocomplete.QuerySuggestion[]; }>; indexPattern: IIndexPattern; } @@ -28,7 +28,7 @@ interface WithKueryAutocompletionLifecycleState { expression: string; cursorPosition: number; } | null; - suggestions: autocomplete.QuerySyntaxSuggestion[]; + suggestions: autocomplete.QuerySuggestion[]; } export class WithKueryAutocompletion extends React.Component< @@ -56,17 +56,12 @@ export class WithKueryAutocompletion extends React.Component< maxSuggestions?: number ) => { const { indexPattern } = this.props; - const autocompletionProvider = getAutocompleteProvider('kuery'); + const getQuerySuggestions = getQuerySuggestionProvider('kuery'); - if (!autocompletionProvider) { + if (!getQuerySuggestions) { return; } - const getSuggestions = autocompletionProvider({ - indexPatterns: [indexPattern], - boolFilter: [], - }); - this.setState({ currentRequest: { expression, @@ -75,10 +70,12 @@ export class WithKueryAutocompletion extends React.Component< suggestions: [], }); - const suggestions = await getSuggestions({ + const suggestions = await getQuerySuggestions({ query: expression, selectionStart: cursorPosition, selectionEnd: cursorPosition, + indexPatterns: [indexPattern], + boolFilter: [], }); this.setState(state => diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/index.js b/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/index.js deleted file mode 100644 index 289d1f24702f3..0000000000000 --- a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/index.js +++ /dev/null @@ -1,49 +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; - * you may not use this file except in compliance with the Elastic License. - */ - -import { flatten, mapValues, uniq } from 'lodash'; -import { getSuggestionsProvider as field } from './field'; -import { getSuggestionsProvider as value } from './value'; -import { getSuggestionsProvider as operator } from './operator'; -import { getSuggestionsProvider as conjunction } from './conjunction'; -import { esKuery } from '../../../../../../src/plugins/data/public'; - -const cursorSymbol = '@kuery-cursor@'; - -function dedup(suggestions) { - return uniq(suggestions, ({ type, text, start, end }) => [type, text, start, end].join('|')); -} - -export const setupKueryProvider = ({ uiSettings }) => ({ indexPatterns, boolFilter }) => { - const getSuggestionsByType = mapValues({ field, value, operator, conjunction }, provider => - provider({ - config: uiSettings, - indexPatterns, - boolFilter, - }) - ); - - return function getSuggestions({ query, selectionStart, selectionEnd, signal }) { - const cursoredQuery = `${query.substr(0, selectionStart)}${cursorSymbol}${query.substr( - selectionEnd - )}`; - - let cursorNode; - try { - cursorNode = esKuery.fromKueryExpression(cursoredQuery, { cursorSymbol, parseCursor: true }); - } catch (e) { - cursorNode = {}; - } - - const { suggestionTypes = [] } = cursorNode; - const suggestionsByType = suggestionTypes.map(type => { - return getSuggestionsByType[type](cursorNode, signal); - }); - return Promise.all(suggestionsByType).then(suggestionsByType => - dedup(flatten(suggestionsByType)) - ); - }; -}; diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/__fixtures__/index_pattern_response.json b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/__fixtures__/index_pattern_response.json similarity index 100% rename from x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/__fixtures__/index_pattern_response.json rename to x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/__fixtures__/index_pattern_response.json diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/__tests__/conjunction.js b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/__tests__/conjunction.js similarity index 100% rename from x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/__tests__/conjunction.js rename to x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/__tests__/conjunction.js diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/__tests__/escape_kuery.js b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/__tests__/escape_kuery.js similarity index 100% rename from x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/__tests__/escape_kuery.js rename to x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/__tests__/escape_kuery.js diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/__tests__/field.js b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/__tests__/field.js similarity index 100% rename from x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/__tests__/field.js rename to x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/__tests__/field.js diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/__tests__/operator.js b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/__tests__/operator.js similarity index 100% rename from x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/__tests__/operator.js rename to x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/__tests__/operator.js diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/conjunction.js b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/conjunction.js similarity index 100% rename from x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/conjunction.js rename to x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/conjunction.js diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/escape_kuery.js b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/escape_kuery.js similarity index 100% rename from x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/escape_kuery.js rename to x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/escape_kuery.js diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/field.js b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/field.js similarity index 100% rename from x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/field.js rename to x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/field.js diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/index.js b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/index.js new file mode 100644 index 0000000000000..024667e8e813b --- /dev/null +++ b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/index.js @@ -0,0 +1,58 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { flatten, uniq } from 'lodash'; +import { getSuggestionsProvider as field } from './field'; +import { getSuggestionsProvider as value } from './value'; +import { getSuggestionsProvider as operator } from './operator'; +import { getSuggestionsProvider as conjunction } from './conjunction'; +import { esKuery } from '../../../../../../src/plugins/data/public'; + +const cursorSymbol = '@kuery-cursor@'; +const providers = { + field, + value, + operator, + conjunction, +}; + +function dedup(suggestions) { + return uniq(suggestions, ({ type, text, start, end }) => [type, text, start, end].join('|')); +} + +const getProviderByType = (type, args) => providers[type] && providers[type](args); + +export const setupKqlQuerySuggestionProvider = ({ uiSettings }) => ({ + indexPatterns, + boolFilter, + query, + selectionStart, + selectionEnd, + signal, +}) => { + const cursoredQuery = `${query.substr(0, selectionStart)}${cursorSymbol}${query.substr( + selectionEnd + )}`; + + let cursorNode; + try { + cursorNode = esKuery.fromKueryExpression(cursoredQuery, { cursorSymbol, parseCursor: true }); + } catch (e) { + cursorNode = {}; + } + + const { suggestionTypes = [] } = cursorNode; + const suggestionsByType = suggestionTypes.map(type => + getProviderByType(type, { + config: uiSettings, + indexPatterns, + boolFilter, + })(cursorNode, signal) + ); + return Promise.all(suggestionsByType).then(suggestionsByType => + dedup(flatten(suggestionsByType)) + ); +}; diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/operator.js b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/operator.js similarity index 100% rename from x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/operator.js rename to x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/operator.js diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/sort_prefix_first.test.ts b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/sort_prefix_first.test.ts similarity index 100% rename from x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/sort_prefix_first.test.ts rename to x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/sort_prefix_first.test.ts diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/sort_prefix_first.ts b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/sort_prefix_first.ts similarity index 100% rename from x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/sort_prefix_first.ts rename to x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/sort_prefix_first.ts diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.js b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.js similarity index 73% rename from x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.js rename to x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.js index f44a3d9d658f3..3d6353a52bc90 100644 --- a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.js +++ b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.js @@ -15,7 +15,7 @@ export function getSuggestionsProvider({ indexPatterns, boolFilter }) { indexPatterns.map(indexPattern => { return indexPattern.fields.map(field => ({ ...field, - indexPatternTitle: indexPattern.title, + indexPattern, })); }) ); @@ -27,17 +27,21 @@ export function getSuggestionsProvider({ indexPatterns, boolFilter }) { const fullFieldName = nestedPath ? `${nestedPath}.${fieldName}` : fieldName; const fields = allFields.filter(field => field.name === fullFieldName); const query = `${prefix}${suffix}`.trim(); - const { getSuggestions } = npStart.plugins.data; + const { getFieldSuggestions } = npStart.plugins.data.autocomplete; const suggestionsByField = fields.map(field => { - return getSuggestions(field.indexPatternTitle, field, query, boolFilter, signal).then( - data => { - const quotedValues = data.map(value => - typeof value === 'string' ? `"${escapeQuotes(value)}"` : `${value}` - ); - return wrapAsSuggestions(start, end, query, quotedValues); - } - ); + return getFieldSuggestions({ + indexPattern: field.indexPattern, + field, + query, + boolFilter, + signal, + }).then(data => { + const quotedValues = data.map(value => + typeof value === 'string' ? `"${escapeQuotes(value)}"` : `${value}` + ); + return wrapAsSuggestions(start, end, query, quotedValues); + }); }); return Promise.all(suggestionsByField).then(suggestions => flatten(suggestions)); diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.test.js b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.test.js similarity index 100% rename from x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.test.js rename to x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.test.js diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/plugin.ts b/x-pack/legacy/plugins/kuery_autocomplete/public/plugin.ts index 15c923513027f..a662f61bf686b 100644 --- a/x-pack/legacy/plugins/kuery_autocomplete/public/plugin.ts +++ b/x-pack/legacy/plugins/kuery_autocomplete/public/plugin.ts @@ -8,7 +8,7 @@ import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'src/core import { Plugin as DataPublicPlugin } from '../../../../../src/plugins/data/public'; // @ts-ignore -import { setupKueryProvider } from './autocomplete_providers'; +import { setupKqlQuerySuggestionProvider } from './kql_query_suggestion'; /** @internal */ export interface KueryAutocompletePluginSetupDependencies { @@ -26,9 +26,9 @@ export class KueryAutocompletePlugin implements Plugin, void> { } public async setup(core: CoreSetup, { data }: KueryAutocompletePluginSetupDependencies) { - const kueryProvider = setupKueryProvider(core); + const kueryProvider = setupKqlQuerySuggestionProvider(core); - data.autocomplete.addQuerySyntaxProvider(KUERY_LANGUAGE_NAME, kueryProvider); + data.autocomplete.addQuerySuggestionProvider(KUERY_LANGUAGE_NAME, kueryProvider); } public start(core: CoreStart) { diff --git a/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/utils.js b/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/utils.js index 581ab20a627f0..d0ff23e984022 100644 --- a/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/utils.js +++ b/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/utils.js @@ -6,20 +6,19 @@ import { npStart } from 'ui/new_platform'; import { esKuery } from '../../../../../../../../src/plugins/data/public'; -const getAutocompleteProvider = language => - npStart.plugins.data.autocomplete.getQuerySyntaxProvider(language); +const getQuerySuggestionProvider = language => + npStart.plugins.data.autocomplete.getQuerySuggestionProvider(language); export async function getSuggestions(query, selectionStart, indexPattern, boolFilter) { - const autocompleteProvider = getAutocompleteProvider('kuery'); - if (!autocompleteProvider) { + const getQuerySuggestions = getQuerySuggestionProvider('kuery'); + + if (!getQuerySuggestions) { return []; } - const getAutocompleteSuggestions = autocompleteProvider({ + return getQuerySuggestions({ indexPatterns: [indexPattern], boolFilter, - }); - return getAutocompleteSuggestions({ query, selectionStart, selectionEnd: selectionStart, diff --git a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.test.tsx b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.test.tsx index 57f18dcdaf8f7..ef16f79a4b83c 100644 --- a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.test.tsx @@ -16,7 +16,7 @@ import { TestProviders } from '../../mock'; import { AutocompleteField } from '.'; -const mockAutoCompleteData: autocomplete.QuerySyntaxSuggestion[] = [ +const mockAutoCompleteData: autocomplete.QuerySuggestion[] = [ { type: 'field', text: 'agent.ephemeral_id ', diff --git a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.tsx b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.tsx index 6cf9736d333d1..2f76ae21944be 100644 --- a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.tsx +++ b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/index.tsx @@ -25,7 +25,7 @@ interface AutocompleteFieldProps { onSubmit?: (value: string) => void; onChange?: (value: string) => void; placeholder?: string; - suggestions: autocomplete.QuerySyntaxSuggestion[]; + suggestions: autocomplete.QuerySuggestion[]; value: string; } diff --git a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/suggestion_item.tsx b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/suggestion_item.tsx index 80cc05578511d..44bc65bb0dc15 100644 --- a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/suggestion_item.tsx +++ b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/suggestion_item.tsx @@ -15,7 +15,7 @@ interface SuggestionItemProps { isSelected?: boolean; onClick?: React.MouseEventHandler; onMouseEnter?: React.MouseEventHandler; - suggestion: autocomplete.QuerySyntaxSuggestion; + suggestion: autocomplete.QuerySuggestion; } export const SuggestionItem = React.memo( diff --git a/x-pack/legacy/plugins/siem/public/containers/kuery_autocompletion/index.tsx b/x-pack/legacy/plugins/siem/public/containers/kuery_autocompletion/index.tsx index 8c2cb335029bd..e86d4379b695a 100644 --- a/x-pack/legacy/plugins/siem/public/containers/kuery_autocompletion/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/kuery_autocompletion/index.tsx @@ -15,7 +15,7 @@ interface KueryAutocompletionLifecycleProps { children: RendererFunction<{ isLoadingSuggestions: boolean; loadSuggestions: (expression: string, cursorPosition: number, maxSuggestions?: number) => void; - suggestions: autocomplete.QuerySyntaxSuggestion[]; + suggestions: autocomplete.QuerySuggestion[]; }>; indexPattern: IIndexPattern; } @@ -30,25 +30,21 @@ export const KueryAutocompletion = React.memo const [currentRequest, setCurrentRequest] = useState( null ); - const [suggestions, setSuggestions] = useState([]); + const [suggestions, setSuggestions] = useState([]); const kibana = useKibana(); const loadSuggestions = async ( expression: string, cursorPosition: number, maxSuggestions?: number ) => { - const autocompletionProvider = kibana.services.data.autocomplete.getQuerySyntaxProvider( + const getQuerySuggestions = kibana.services.data.autocomplete.getQuerySuggestionProvider( 'kuery' ); - if (!autocompletionProvider) { + if (!getQuerySuggestions) { return; } - const getSuggestions = autocompletionProvider({ - indexPatterns: [indexPattern], - boolFilter: [], - }); const futureRequest = { expression, cursorPosition, @@ -58,7 +54,9 @@ export const KueryAutocompletion = React.memo cursorPosition, }); setSuggestions([]); - const newSuggestions = await getSuggestions({ + const newSuggestions = await getQuerySuggestions({ + indexPatterns: [indexPattern], + boolFilter: [], query: expression, selectionStart: cursorPosition, selectionEnd: cursorPosition, diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx index 76a326dbf0236..6cd558359534c 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx @@ -15,7 +15,8 @@ import { toStaticIndexPattern } from '../../../lib/helper'; import { esKuery, IIndexPattern, - autocomplete as autocompleteNamespace, + autocomplete, + DataPublicPluginStart, } from '../../../../../../../../src/plugins/data/public'; import { useIndexPattern } from '../../../hooks'; @@ -24,7 +25,7 @@ const Container = styled.div` `; interface State { - suggestions: autocompleteNamespace.QuerySyntaxSuggestion[]; + suggestions: autocomplete.QuerySuggestion[]; isLoadingIndexPattern: boolean; } @@ -37,30 +38,25 @@ function getSuggestions( query: string, selectionStart: number, apmIndexPattern: IIndexPattern, - autocomplete: autocompleteNamespace.AutocompletePublicPluginStart -) { - const autocompleteProvider = autocomplete.getQuerySyntaxProvider('kuery'); - if (!autocompleteProvider) { - return []; + autocompleteService: DataPublicPluginStart['autocomplete'] +): Promise | undefined { + const getQuerySuggestions = autocompleteService.getQuerySuggestionProvider('kuery'); + + if (getQuerySuggestions) { + return getQuerySuggestions({ + query, + selectionStart, + selectionEnd: selectionStart, + indexPatterns: [apmIndexPattern], + }); } - - const getAutocompleteSuggestions = autocompleteProvider({ - indexPatterns: [apmIndexPattern], - }); - - const suggestions = getAutocompleteSuggestions({ - query, - selectionStart, - selectionEnd: selectionStart, - }); - return suggestions; } interface Props { - autocomplete: autocompleteNamespace.AutocompletePublicPluginStart; + autocomplete: DataPublicPluginStart['autocomplete']; } -export function KueryBar({ autocomplete }: Props) { +export function KueryBar({ autocomplete: autocompleteService }: Props) { const [state, setState] = useState({ suggestions: [], isLoadingIndexPattern: true, @@ -94,17 +90,10 @@ export function KueryBar({ autocomplete }: Props) { currentRequestCheck = currentRequest; try { - let suggestions = await getSuggestions( - inputValue, - selectionStart, - indexPattern, - autocomplete - ); - suggestions = suggestions - .filter( - (suggestion: autocompleteNamespace.QuerySyntaxSuggestion) => - !startsWith(suggestion.text, 'span.') - ) + const suggestions = ( + (await getSuggestions(inputValue, selectionStart, indexPattern, autocompleteService)) || [] + ) + .filter(suggestion => !startsWith(suggestion.text, 'span.')) .slice(0, 15); if (currentRequest !== currentRequestCheck) { diff --git a/x-pack/legacy/plugins/uptime/public/pages/overview.tsx b/x-pack/legacy/plugins/uptime/public/pages/overview.tsx index caf09fe30e22e..fa54539c01c27 100644 --- a/x-pack/legacy/plugins/uptime/public/pages/overview.tsx +++ b/x-pack/legacy/plugins/uptime/public/pages/overview.tsx @@ -24,13 +24,10 @@ import { combineFiltersAndUserSearch, stringifyKueries, toStaticIndexPattern } f import { store } from '../state'; import { setEsKueryString } from '../state/actions'; import { PageHeader } from './page_header'; -import { - autocomplete as autocompleteNamespace, - esKuery, -} from '../../../../../../src/plugins/data/public'; +import { esKuery, DataPublicPluginStart } from '../../../../../../src/plugins/data/public'; interface OverviewPageProps { - autocomplete: autocompleteNamespace.AutocompletePublicPluginStart; + autocomplete: DataPublicPluginStart['autocomplete']; setBreadcrumbs: UMUpdateBreadcrumbs; } diff --git a/x-pack/legacy/plugins/uptime/public/routes.tsx b/x-pack/legacy/plugins/uptime/public/routes.tsx index 454e29ceecf65..028f2d5958325 100644 --- a/x-pack/legacy/plugins/uptime/public/routes.tsx +++ b/x-pack/legacy/plugins/uptime/public/routes.tsx @@ -7,14 +7,14 @@ import React, { FC } from 'react'; import { Route, Switch } from 'react-router-dom'; import { MonitorPage, OverviewPage, NotFoundPage } from './pages'; -import { autocomplete as autocompleteNamespace } from '../../../../../src/plugins/data/public'; +import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; import { UMUpdateBreadcrumbs } from './lib/lib'; export const MONITOR_ROUTE = '/monitor/:monitorId/:location?'; export const OVERVIEW_ROUTE = '/'; interface RouterProps { - autocomplete: autocompleteNamespace.AutocompletePublicPluginStart; + autocomplete: DataPublicPluginStart['autocomplete']; basePath: string; setBreadcrumbs: UMUpdateBreadcrumbs; } From ffc07ac0f3a345eb40ac778a42051641faf6ba61 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Wed, 15 Jan 2020 16:07:50 +0300 Subject: [PATCH 07/11] fix PR comments --- .../autocomplete/autocomplete_service.ts | 17 +++++++--- .../providers/query_suggestion_provider.ts | 5 ++- src/plugins/data/public/mocks.ts | 4 +-- .../query_string_input.test.tsx.snap | 24 +++++++------- .../query_string_input/query_string_input.tsx | 23 ++++++------- .../components/shared/KueryBar/index.tsx | 20 +++++------ .../public/lib/adapters/elasticsearch/rest.ts | 25 +++++++------- .../public/components/search_bar.test.tsx | 2 +- .../containers/with_kuery_autocompletion.tsx | 24 +++++++------- .../public/kql_query_suggestion/index.js | 5 ++- .../public/kql_query_suggestion/value.js | 6 ++-- .../public/kql_query_suggestion/value.test.js | 33 +++++++++++-------- .../kql_filter_bar/kql_filter_bar.js | 8 ++--- .../components/kql_filter_bar/utils.js | 14 ++------ .../containers/kuery_autocompletion/index.tsx | 24 +++++++------- .../components/functional/kuery_bar/index.tsx | 16 ++++----- 16 files changed, 125 insertions(+), 125 deletions(-) diff --git a/src/plugins/data/public/autocomplete/autocomplete_service.ts b/src/plugins/data/public/autocomplete/autocomplete_service.ts index a0f1317e218dd..3675c5ddf9d0a 100644 --- a/src/plugins/data/public/autocomplete/autocomplete_service.ts +++ b/src/plugins/data/public/autocomplete/autocomplete_service.ts @@ -34,8 +34,16 @@ export class AutocompleteService { } }; - private getQuerySuggestionProvider = (language: string) => - this.querySuggestionProviders.get(language); + private getQuerySuggestions: QuerySuggestionsGet = args => { + const { language } = args; + const provider = this.querySuggestionProviders.get(language); + + if (provider) { + return provider(args); + } + }; + + private hasQuerySuggestions = (language: string) => this.querySuggestionProviders.has(language); /** @public **/ public setup(core: CoreSetup) { @@ -46,14 +54,15 @@ export class AutocompleteService { /** @obsolete **/ /** please use "getProvider" only from the start contract **/ - getQuerySuggestionProvider: this.getQuerySuggestionProvider, + getQuerySuggestions: this.getQuerySuggestions, }; } /** @public **/ public start() { return { - getQuerySuggestionProvider: this.getQuerySuggestionProvider, + getQuerySuggestions: this.getQuerySuggestions, + hasQuerySuggestions: this.hasQuerySuggestions, getFieldSuggestions: this.getFieldSuggestions!, }; } diff --git a/src/plugins/data/public/autocomplete/providers/query_suggestion_provider.ts b/src/plugins/data/public/autocomplete/providers/query_suggestion_provider.ts index 9799ff87feb97..34f5eefafe618 100644 --- a/src/plugins/data/public/autocomplete/providers/query_suggestion_provider.ts +++ b/src/plugins/data/public/autocomplete/providers/query_suggestion_provider.ts @@ -21,9 +21,12 @@ import { IFieldType, IIndexPattern } from '../../../common/index_patterns'; export type QuerySuggestionType = 'field' | 'value' | 'operator' | 'conjunction' | 'recentSearch'; -export type QuerySuggestionsGet = (args: QuerySuggestionsGetArgs) => Promise; +export type QuerySuggestionsGet = ( + args: QuerySuggestionsGetArgs +) => Promise | undefined; interface QuerySuggestionsGetArgs { + language: string; indexPatterns: IIndexPattern[]; query: string; selectionStart: number; diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index 2d68ef663d84d..82ebe6ec5d1bf 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -30,9 +30,9 @@ export type Setup = jest.Mocked>; export type Start = jest.Mocked>; const autocompleteMock: any = { - addQuerySuggestionProvider: jest.fn(), - getQuerySuggestionProvider: jest.fn(), getFieldSuggestions: jest.fn(), + getQuerySuggestions: jest.fn(), + hasQuerySuggestions: jest.fn(), }; const fieldFormatsMock: PublicMethodsOf = { diff --git a/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap b/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap index e7f0f43f21456..64707c3c287ca 100644 --- a/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap +++ b/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap @@ -151,9 +151,9 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA }, "data": Object { "autocomplete": Object { - "addQuerySuggestionProvider": [MockFunction], "getFieldSuggestions": [MockFunction], - "getQuerySuggestionProvider": [MockFunction], + "getQuerySuggestions": [MockFunction], + "hasQuerySuggestions": [MockFunction], }, "fieldFormats": Object { "getByFieldType": [MockFunction], @@ -777,9 +777,9 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA }, "data": Object { "autocomplete": Object { - "addQuerySuggestionProvider": [MockFunction], "getFieldSuggestions": [MockFunction], - "getQuerySuggestionProvider": [MockFunction], + "getQuerySuggestions": [MockFunction], + "hasQuerySuggestions": [MockFunction], }, "fieldFormats": Object { "getByFieldType": [MockFunction], @@ -1385,9 +1385,9 @@ exports[`QueryStringInput Should pass the query language to the language switche }, "data": Object { "autocomplete": Object { - "addQuerySuggestionProvider": [MockFunction], "getFieldSuggestions": [MockFunction], - "getQuerySuggestionProvider": [MockFunction], + "getQuerySuggestions": [MockFunction], + "hasQuerySuggestions": [MockFunction], }, "fieldFormats": Object { "getByFieldType": [MockFunction], @@ -2008,9 +2008,9 @@ exports[`QueryStringInput Should pass the query language to the language switche }, "data": Object { "autocomplete": Object { - "addQuerySuggestionProvider": [MockFunction], "getFieldSuggestions": [MockFunction], - "getQuerySuggestionProvider": [MockFunction], + "getQuerySuggestions": [MockFunction], + "hasQuerySuggestions": [MockFunction], }, "fieldFormats": Object { "getByFieldType": [MockFunction], @@ -2616,9 +2616,9 @@ exports[`QueryStringInput Should render the given query 1`] = ` }, "data": Object { "autocomplete": Object { - "addQuerySuggestionProvider": [MockFunction], "getFieldSuggestions": [MockFunction], - "getQuerySuggestionProvider": [MockFunction], + "getQuerySuggestions": [MockFunction], + "hasQuerySuggestions": [MockFunction], }, "fieldFormats": Object { "getByFieldType": [MockFunction], @@ -3239,9 +3239,9 @@ exports[`QueryStringInput Should render the given query 1`] = ` }, "data": Object { "autocomplete": Object { - "addQuerySuggestionProvider": [MockFunction], "getFieldSuggestions": [MockFunction], - "getQuerySuggestionProvider": [MockFunction], + "getQuerySuggestions": [MockFunction], + "hasQuerySuggestions": [MockFunction], }, "fieldFormats": Object { "getByFieldType": [MockFunction], diff --git a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx index 483251915cb32..cf219c35bcced 100644 --- a/src/plugins/data/public/ui/query_string_input/query_string_input.tsx +++ b/src/plugins/data/public/ui/query_string_input/query_string_input.tsx @@ -141,12 +141,10 @@ export class QueryStringInputUI extends Component { const queryString = this.getQueryString(); const recentSearchSuggestions = this.getRecentSearchSuggestions(queryString); - const getQuerySuggestions = this.services.data.autocomplete.getQuerySuggestionProvider( - language - ); + const hasQuerySuggestions = this.services.data.autocomplete.hasQuerySuggestions(language); if ( - !getQuerySuggestions || + !hasQuerySuggestions || !Array.isArray(this.state.indexPatterns) || compact(this.state.indexPatterns).length === 0 ) { @@ -163,13 +161,16 @@ export class QueryStringInputUI extends Component { try { if (this.abortController) this.abortController.abort(); this.abortController = new AbortController(); - const suggestions = await getQuerySuggestions({ - indexPatterns, - query: queryString, - selectionStart, - selectionEnd, - signal: this.abortController.signal, - }); + const suggestions = + (await this.services.data.autocomplete.getQuerySuggestions({ + language, + indexPatterns, + query: queryString, + selectionStart, + selectionEnd, + signal: this.abortController.signal, + })) || []; + return [...suggestions, ...recentSearchSuggestions]; } catch (e) { // TODO: Waiting on https://github.com/elastic/kibana/issues/51406 for a properly typed error diff --git a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx index 81ab88197b79e..32432b7b85ef6 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx +++ b/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx @@ -45,9 +45,6 @@ export function KueryBar() { const { urlParams } = useUrlParams(); const location = useLocation(); const { data } = useApmPluginContext().plugins; - const getQuerySuggestions = data.autocomplete.getQuerySuggestionProvider( - 'kuery' - ); let currentRequestCheck; @@ -77,15 +74,14 @@ export function KueryBar() { try { const suggestions = ( - (getQuerySuggestions && - (await getQuerySuggestions({ - indexPatterns: [indexPattern], - boolFilter: getBoolFilter(urlParams), - query: inputValue, - selectionStart, - selectionEnd: selectionStart - }))) || - [] + (await data.autocomplete.getQuerySuggestions({ + language: 'kuery', + indexPatterns: [indexPattern], + boolFilter: getBoolFilter(urlParams), + query: inputValue, + selectionStart, + selectionEnd: selectionStart + })) || [] ) .filter(suggestion => !startsWith(suggestion.text, 'span.')) .slice(0, 15); diff --git a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts index 768e700e23041..6277e1b77191e 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts @@ -9,9 +9,6 @@ import { npStart } from 'ui/new_platform'; import { ElasticsearchAdapter } from './adapter_types'; import { autocomplete, esKuery } from '../../../../../../../../src/plugins/data/public'; -const getQuerySuggestionProvider = (language: string) => - npStart.plugins.data.autocomplete.getQuerySuggestionProvider(language); - export class RestElasticsearchAdapter implements ElasticsearchAdapter { private cachedIndexPattern: any = null; constructor(private readonly indexPatternName: string) {} @@ -33,23 +30,23 @@ export class RestElasticsearchAdapter implements ElasticsearchAdapter { const indexPattern = await this.getIndexPattern(); return JSON.stringify(esKuery.toElasticsearchQuery(ast, indexPattern)); } + public async getSuggestions( kuery: string, selectionStart: any ): Promise { - const getQuerySuggestions = getQuerySuggestionProvider('kuery'); - if (!getQuerySuggestions) { - return []; - } const indexPattern = await this.getIndexPattern(); - return getQuerySuggestions({ - indexPatterns: [indexPattern], - boolFilter: null, - query: kuery || '', - selectionStart, - selectionEnd: selectionStart, - }); + return ( + (await npStart.plugins.data.autocomplete.getQuerySuggestions({ + language: 'kuery', + indexPatterns: [indexPattern], + boolFilter: null, + query: kuery || '', + selectionStart, + selectionEnd: selectionStart, + })) || [] + ); } private async getIndexPattern() { diff --git a/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx b/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx index 3f5e53f6f45f3..33042077eb630 100644 --- a/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx +++ b/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx @@ -51,7 +51,7 @@ function wrapSearchBarInContext(testProps: OuterSearchBarProps) { savedQueries: {}, }, autocomplete: { - getQuerySuggestionProvider: () => undefined, + getQuerySuggestions: () => undefined, }, }, }; diff --git a/x-pack/legacy/plugins/infra/public/containers/with_kuery_autocompletion.tsx b/x-pack/legacy/plugins/infra/public/containers/with_kuery_autocompletion.tsx index 4cc5b476d86dd..c92e2ecec9261 100644 --- a/x-pack/legacy/plugins/infra/public/containers/with_kuery_autocompletion.tsx +++ b/x-pack/legacy/plugins/infra/public/containers/with_kuery_autocompletion.tsx @@ -9,9 +9,6 @@ import { npStart } from 'ui/new_platform'; import { autocomplete, IIndexPattern } from 'src/plugins/data/public'; import { RendererFunction } from '../utils/typed_react'; -const getQuerySuggestionProvider = (language: string) => - npStart.plugins.data.autocomplete.getQuerySuggestionProvider(language); - interface WithKueryAutocompletionLifecycleProps { children: RendererFunction<{ isLoadingSuggestions: boolean; @@ -56,9 +53,10 @@ export class WithKueryAutocompletion extends React.Component< maxSuggestions?: number ) => { const { indexPattern } = this.props; - const getQuerySuggestions = getQuerySuggestionProvider('kuery'); + const language = 'kuery'; + const hasQuerySuggestions = npStart.plugins.data.autocomplete.hasQuerySuggestions(language); - if (!getQuerySuggestions) { + if (!hasQuerySuggestions) { return; } @@ -70,13 +68,15 @@ export class WithKueryAutocompletion extends React.Component< suggestions: [], }); - const suggestions = await getQuerySuggestions({ - query: expression, - selectionStart: cursorPosition, - selectionEnd: cursorPosition, - indexPatterns: [indexPattern], - boolFilter: [], - }); + const suggestions = + (await npStart.plugins.data.autocomplete.getQuerySuggestions({ + language, + query: expression, + selectionStart: cursorPosition, + selectionEnd: cursorPosition, + indexPatterns: [indexPattern], + boolFilter: [], + })) || []; this.setState(state => state.currentRequest && diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/index.js b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/index.js index 221e447e9c0c5..b877f9eb852d5 100644 --- a/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/index.js +++ b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/index.js @@ -23,9 +23,9 @@ function dedup(suggestions) { return uniq(suggestions, ({ type, text, start, end }) => [type, text, start, end].join('|')); } -const getProviderByType = (type, args) => providers[type] && providers[type](args); +const getProviderByType = (type, args) => providers[type](args); -export const setupKqlQuerySuggestionProvider = ({ uiSettings }, plugins) => ({ +export const setupKqlQuerySuggestionProvider = ({ uiSettings }) => ({ indexPatterns, boolFilter, query, @@ -50,7 +50,6 @@ export const setupKqlQuerySuggestionProvider = ({ uiSettings }, plugins) => ({ config: uiSettings, indexPatterns, boolFilter, - plugins, })(cursorNode, signal) ); return Promise.all(suggestionsByType).then(suggestionsByType => diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.js b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.js index 19653e6599fe2..d9523fe196d9a 100644 --- a/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.js +++ b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.js @@ -6,10 +6,11 @@ import { flatten } from 'lodash'; import { escapeQuotes } from './escape_kuery'; +import { npStart } from 'ui/new_platform'; const type = 'value'; -export function getSuggestionsProvider({ indexPatterns, boolFilter }, plugins) { +export function getSuggestionsProvider({ indexPatterns, boolFilter }) { const allFields = flatten( indexPatterns.map(indexPattern => { return indexPattern.fields.map(field => ({ @@ -26,7 +27,8 @@ export function getSuggestionsProvider({ indexPatterns, boolFilter }, plugins) { const fullFieldName = nestedPath ? `${nestedPath}.${fieldName}` : fieldName; const fields = allFields.filter(field => field.name === fullFieldName); const query = `${prefix}${suffix}`.trim(); - const { getFieldSuggestions } = plugins.data.autocomplete; + const { getFieldSuggestions } = npStart.plugins.data.autocomplete; + const suggestionsByField = fields.map(field => getFieldSuggestions({ indexPattern: field.indexPattern, diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.test.js b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.test.js index f81e92cfe1d44..f910cd14be68e 100644 --- a/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.test.js +++ b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.test.js @@ -6,15 +6,11 @@ import { getSuggestionsProvider } from './value'; import indexPatternResponse from './__fixtures__/index_pattern_response.json'; +import { npStart } from 'ui/new_platform'; -describe('Kuery value suggestions', function() { - let indexPatterns; - let getSuggestions; - let plugins; - - beforeEach(() => { - indexPatterns = [indexPatternResponse]; - plugins = { +jest.mock('ui/new_platform', () => ({ + npStart: { + plugins: { data: { autocomplete: { getFieldSuggestions: jest.fn(({ field }) => { @@ -32,8 +28,17 @@ describe('Kuery value suggestions', function() { }), }, }, - }; - getSuggestions = getSuggestionsProvider({ indexPatterns }, plugins); + }, + }, +})); + +describe('Kuery value suggestions', function() { + let indexPatterns; + let getSuggestions; + + beforeEach(() => { + indexPatterns = [indexPatternResponse]; + getSuggestions = getSuggestionsProvider({ indexPatterns }); jest.clearAllMocks(); }); @@ -49,7 +54,7 @@ describe('Kuery value suggestions', function() { const suggestions = await getSuggestions({ fieldName, prefix, suffix }); expect(suggestions.map(({ text }) => text)).toEqual([]); - expect(plugins.data.autocomplete.getFieldSuggestions).toHaveBeenCalledTimes(0); + expect(npStart.plugins.data.autocomplete.getFieldSuggestions).toHaveBeenCalledTimes(0); }); test('should format suggestions', async () => { @@ -84,7 +89,7 @@ describe('Kuery value suggestions', function() { const suggestions = await getSuggestions({ fieldName: 'ssl', prefix: '', suffix: '' }); expect(suggestions.map(({ text }) => text)).toEqual(['true ', 'false ']); - expect(plugins.data.autocomplete.getFieldSuggestions).toHaveBeenCalledTimes(1); + expect(npStart.plugins.data.autocomplete.getFieldSuggestions).toHaveBeenCalledTimes(1); }); test('should filter out boolean suggestions', async () => { @@ -101,8 +106,8 @@ describe('Kuery value suggestions', function() { await getSuggestions({ fieldName: 'machine.os.raw', prefix, suffix }); - expect(plugins.data.autocomplete.getFieldSuggestions).toHaveBeenCalledTimes(1); - expect(plugins.data.autocomplete.getFieldSuggestions).toBeCalledWith( + expect(npStart.plugins.data.autocomplete.getFieldSuggestions).toHaveBeenCalledTimes(1); + expect(npStart.plugins.data.autocomplete.getFieldSuggestions).toBeCalledWith( expect.objectContaining({ field: expect.any(Object), query: prefix + suffix, diff --git a/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/kql_filter_bar.js b/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/kql_filter_bar.js index 3591b0907ebb1..e604c101a9994 100644 --- a/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/kql_filter_bar.js +++ b/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/kql_filter_bar.js @@ -46,12 +46,8 @@ export class KqlFilterBar extends Component { const boolFilter = []; try { - const suggestions = await getSuggestions( - inputValue, - selectionStart, - indexPattern, - boolFilter - ); + const suggestions = + (await getSuggestions(inputValue, selectionStart, indexPattern, boolFilter)) || []; if (currentRequest !== this.currentRequest) { return; diff --git a/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/utils.js b/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/utils.js index d0ff23e984022..bb7b143c948d8 100644 --- a/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/utils.js +++ b/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/utils.js @@ -6,17 +6,9 @@ import { npStart } from 'ui/new_platform'; import { esKuery } from '../../../../../../../../src/plugins/data/public'; -const getQuerySuggestionProvider = language => - npStart.plugins.data.autocomplete.getQuerySuggestionProvider(language); - -export async function getSuggestions(query, selectionStart, indexPattern, boolFilter) { - const getQuerySuggestions = getQuerySuggestionProvider('kuery'); - - if (!getQuerySuggestions) { - return []; - } - - return getQuerySuggestions({ +export function getSuggestions(query, selectionStart, indexPattern, boolFilter) { + return npStart.plugins.data.autocomplete.getQuerySuggestions({ + language: 'kuery', indexPatterns: [indexPattern], boolFilter, query, diff --git a/x-pack/legacy/plugins/siem/public/containers/kuery_autocompletion/index.tsx b/x-pack/legacy/plugins/siem/public/containers/kuery_autocompletion/index.tsx index e86d4379b695a..4eb51dfe6407c 100644 --- a/x-pack/legacy/plugins/siem/public/containers/kuery_autocompletion/index.tsx +++ b/x-pack/legacy/plugins/siem/public/containers/kuery_autocompletion/index.tsx @@ -37,11 +37,9 @@ export const KueryAutocompletion = React.memo cursorPosition: number, maxSuggestions?: number ) => { - const getQuerySuggestions = kibana.services.data.autocomplete.getQuerySuggestionProvider( - 'kuery' - ); + const language = 'kuery'; - if (!getQuerySuggestions) { + if (!kibana.services.data.autocomplete.hasQuerySuggestions(language)) { return; } @@ -54,18 +52,22 @@ export const KueryAutocompletion = React.memo cursorPosition, }); setSuggestions([]); - const newSuggestions = await getQuerySuggestions({ - indexPatterns: [indexPattern], - boolFilter: [], - query: expression, - selectionStart: cursorPosition, - selectionEnd: cursorPosition, - }); + if ( futureRequest && futureRequest.expression !== (currentRequest && currentRequest.expression) && futureRequest.cursorPosition !== (currentRequest && currentRequest.cursorPosition) ) { + const newSuggestions = + (await kibana.services.data.autocomplete.getQuerySuggestions({ + language: 'kuery', + indexPatterns: [indexPattern], + boolFilter: [], + query: expression, + selectionStart: cursorPosition, + selectionEnd: cursorPosition, + })) || []; + setCurrentRequest(null); setSuggestions(maxSuggestions ? newSuggestions.slice(0, maxSuggestions) : newSuggestions); } diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx index c9591294fc57d..679106f7e19b4 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/kuery_bar/index.tsx @@ -46,7 +46,6 @@ export function KueryBar({ autocomplete: autocompleteService }: Props) { const [indexPattern, setIndexPattern] = useState(undefined); const [isLoadingIndexPattern, setIsLoadingIndexPattern] = useState(true); const [isLoadingSuggestions, setIsLoadingSuggestions] = useState(false); - const getQuerySuggestions = autocompleteService.getQuerySuggestionProvider('kuery'); let currentRequestCheck: string; useIndexPattern((result: any) => setIndexPattern(toStaticIndexPattern(result))); @@ -74,14 +73,13 @@ export function KueryBar({ autocomplete: autocompleteService }: Props) { try { const suggestions = ( - (getQuerySuggestions && - (await getQuerySuggestions({ - indexPatterns: [indexPattern], - query: inputValue, - selectionStart, - selectionEnd: selectionStart, - }))) || - [] + (await autocompleteService.getQuerySuggestions({ + language: 'kuery', + indexPatterns: [indexPattern], + query: inputValue, + selectionStart, + selectionEnd: selectionStart, + })) || [] ) .filter(suggestion => !startsWith(suggestion.text, 'span.')) .slice(0, 15); From 403e5daea8c8ae5e026d1d77a84a5ac18d51a48c Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Wed, 15 Jan 2020 17:10:36 +0300 Subject: [PATCH 08/11] fix CI --- .../beats_management/public/lib/adapters/elasticsearch/rest.ts | 2 +- .../legacy/plugins/graph/public/components/search_bar.test.tsx | 3 ++- .../components/kql_filter_bar/kql_filter_bar.test.js | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts index 6277e1b77191e..fc400c600e575 100644 --- a/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts +++ b/x-pack/legacy/plugins/beats_management/public/lib/adapters/elasticsearch/rest.ts @@ -41,7 +41,7 @@ export class RestElasticsearchAdapter implements ElasticsearchAdapter { (await npStart.plugins.data.autocomplete.getQuerySuggestions({ language: 'kuery', indexPatterns: [indexPattern], - boolFilter: null, + boolFilter: [], query: kuery || '', selectionStart, selectionEnd: selectionStart, diff --git a/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx b/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx index 33042077eb630..95b7dd22e9fcf 100644 --- a/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx +++ b/x-pack/legacy/plugins/graph/public/components/search_bar.test.tsx @@ -21,6 +21,7 @@ import { ReactWrapper } from 'enzyme'; import { createMockGraphStore } from '../state_management/mocks'; import { Provider } from 'react-redux'; +jest.mock('ui/new_platform'); jest.mock('../services/source_modal', () => ({ openSourceModal: jest.fn() })); const waitForIndexPatternFetch = () => new Promise(r => setTimeout(r)); @@ -51,7 +52,7 @@ function wrapSearchBarInContext(testProps: OuterSearchBarProps) { savedQueries: {}, }, autocomplete: { - getQuerySuggestions: () => undefined, + hasQuerySuggestions: () => false, }, }, }; diff --git a/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/kql_filter_bar.test.js b/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/kql_filter_bar.test.js index b1e79cbf55925..4e74a4bd545a3 100644 --- a/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/kql_filter_bar.test.js +++ b/x-pack/legacy/plugins/ml/public/application/components/kql_filter_bar/kql_filter_bar.test.js @@ -8,6 +8,8 @@ import React from 'react'; import { shallow } from 'enzyme'; import { KqlFilterBar } from './kql_filter_bar'; +jest.mock('ui/new_platform'); + const defaultProps = { indexPattern: { title: '.ml-anomalies-*', From 0fbaf164dc537970c343ebca900279b8a608c29d Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Thu, 16 Jan 2020 10:59:56 +0300 Subject: [PATCH 09/11] fix CI --- .../autocomplete_field/__examples__/index.stories.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/__examples__/index.stories.tsx b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/__examples__/index.stories.tsx index 86d003bf577f3..4d92e8cb1335d 100644 --- a/x-pack/legacy/plugins/siem/public/components/autocomplete_field/__examples__/index.stories.tsx +++ b/x-pack/legacy/plugins/siem/public/components/autocomplete_field/__examples__/index.stories.tsx @@ -8,10 +8,10 @@ import * as React from 'react'; import { storiesOf } from '@storybook/react'; import { ThemeProvider } from 'styled-components'; import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; -import { AutocompleteSuggestion } from '../../../../../../../../src/plugins/data/public'; +import { autocomplete } from '../../../../../../../../src/plugins/data/public'; import { SuggestionItem } from '../suggestion_item'; -const suggestion: AutocompleteSuggestion = { +const suggestion: autocomplete.QuerySuggestion = { description: 'Description...', end: 3, start: 1, From de397d3451f9c75b7b97129c7fcccd84487543f5 Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Fri, 17 Jan 2020 13:02:49 +0300 Subject: [PATCH 10/11] getFieldSuggestions -> getValueSuggestions --- .../autocomplete/autocomplete_service.ts | 23 ++++++----- src/plugins/data/public/autocomplete/index.ts | 2 +- .../providers/query_suggestion_provider.ts | 6 +-- ...t.ts => value_suggestion_provider.test.ts} | 40 +++++++++---------- ...ovider.ts => value_suggestion_provider.ts} | 8 ++-- src/plugins/data/public/autocomplete/types.ts | 2 +- src/plugins/data/public/mocks.ts | 2 +- .../filter_editor/phrase_suggestor.tsx | 2 +- .../query_string_input.test.tsx.snap | 12 +++--- .../public/kql_query_suggestion/value.js | 4 +- .../public/kql_query_suggestion/value.test.js | 10 ++--- 11 files changed, 57 insertions(+), 54 deletions(-) rename src/plugins/data/public/autocomplete/providers/{field_suggestion_provider.test.ts => value_suggestion_provider.test.ts} (84%) rename src/plugins/data/public/autocomplete/providers/{field_suggestion_provider.ts => value_suggestion_provider.ts} (88%) diff --git a/src/plugins/data/public/autocomplete/autocomplete_service.ts b/src/plugins/data/public/autocomplete/autocomplete_service.ts index 3675c5ddf9d0a..0527f833b0f8c 100644 --- a/src/plugins/data/public/autocomplete/autocomplete_service.ts +++ b/src/plugins/data/public/autocomplete/autocomplete_service.ts @@ -18,23 +18,26 @@ */ import { CoreSetup } from 'src/core/public'; -import { QuerySuggestionsGet } from './providers/query_suggestion_provider'; +import { QuerySuggestionsGetFn } from './providers/query_suggestion_provider'; import { - setupFieldSuggestionProvider, - FieldSuggestionsGet, -} from './providers/field_suggestion_provider'; + setupValueSuggestionProvider, + ValueSuggestionsGetFn, +} from './providers/value_suggestion_provider'; export class AutocompleteService { - private readonly querySuggestionProviders: Map = new Map(); - private getFieldSuggestions?: FieldSuggestionsGet; + private readonly querySuggestionProviders: Map = new Map(); + private getValueSuggestions?: ValueSuggestionsGetFn; - private addQuerySuggestionProvider = (language: string, provider: QuerySuggestionsGet): void => { + private addQuerySuggestionProvider = ( + language: string, + provider: QuerySuggestionsGetFn + ): void => { if (language && provider) { this.querySuggestionProviders.set(language, provider); } }; - private getQuerySuggestions: QuerySuggestionsGet = args => { + private getQuerySuggestions: QuerySuggestionsGetFn = args => { const { language } = args; const provider = this.querySuggestionProviders.get(language); @@ -47,7 +50,7 @@ export class AutocompleteService { /** @public **/ public setup(core: CoreSetup) { - this.getFieldSuggestions = setupFieldSuggestionProvider(core); + this.getValueSuggestions = setupValueSuggestionProvider(core); return { addQuerySuggestionProvider: this.addQuerySuggestionProvider, @@ -63,7 +66,7 @@ export class AutocompleteService { return { getQuerySuggestions: this.getQuerySuggestions, hasQuerySuggestions: this.hasQuerySuggestions, - getFieldSuggestions: this.getFieldSuggestions!, + getValueSuggestions: this.getValueSuggestions!, }; } diff --git a/src/plugins/data/public/autocomplete/index.ts b/src/plugins/data/public/autocomplete/index.ts index d4d9c708be37a..5b8f3ae510bfd 100644 --- a/src/plugins/data/public/autocomplete/index.ts +++ b/src/plugins/data/public/autocomplete/index.ts @@ -18,4 +18,4 @@ */ export { AutocompleteService } from './autocomplete_service'; -export { QuerySuggestion, QuerySuggestionType, QuerySuggestionsGet } from './types'; +export { QuerySuggestion, QuerySuggestionType, QuerySuggestionsGetFn } from './types'; diff --git a/src/plugins/data/public/autocomplete/providers/query_suggestion_provider.ts b/src/plugins/data/public/autocomplete/providers/query_suggestion_provider.ts index 34f5eefafe618..53abdd44c0c3f 100644 --- a/src/plugins/data/public/autocomplete/providers/query_suggestion_provider.ts +++ b/src/plugins/data/public/autocomplete/providers/query_suggestion_provider.ts @@ -21,11 +21,11 @@ import { IFieldType, IIndexPattern } from '../../../common/index_patterns'; export type QuerySuggestionType = 'field' | 'value' | 'operator' | 'conjunction' | 'recentSearch'; -export type QuerySuggestionsGet = ( - args: QuerySuggestionsGetArgs +export type QuerySuggestionsGetFn = ( + args: QuerySuggestionsGetFnArgs ) => Promise | undefined; -interface QuerySuggestionsGetArgs { +interface QuerySuggestionsGetFnArgs { language: string; indexPatterns: IIndexPattern[]; query: string; diff --git a/src/plugins/data/public/autocomplete/providers/field_suggestion_provider.test.ts b/src/plugins/data/public/autocomplete/providers/value_suggestion_provider.test.ts similarity index 84% rename from src/plugins/data/public/autocomplete/providers/field_suggestion_provider.test.ts rename to src/plugins/data/public/autocomplete/providers/value_suggestion_provider.test.ts index dd323038e7630..6b0c0f07cf6c9 100644 --- a/src/plugins/data/public/autocomplete/providers/field_suggestion_provider.test.ts +++ b/src/plugins/data/public/autocomplete/providers/value_suggestion_provider.test.ts @@ -18,11 +18,11 @@ */ import { stubIndexPattern, stubFields } from '../../stubs'; -import { setupFieldSuggestionProvider, FieldSuggestionsGet } from './field_suggestion_provider'; +import { setupValueSuggestionProvider, ValueSuggestionsGetFn } from './value_suggestion_provider'; import { IUiSettingsClient, CoreSetup } from 'kibana/public'; describe('FieldSuggestions', () => { - let getFieldSuggestions: FieldSuggestionsGet; + let getValueSuggestions: ValueSuggestionsGetFn; let http: any; let shouldSuggestValues: boolean; @@ -30,12 +30,12 @@ describe('FieldSuggestions', () => { const uiSettings = { get: (key: string) => shouldSuggestValues } as IUiSettingsClient; http = { fetch: jest.fn() }; - getFieldSuggestions = setupFieldSuggestionProvider({ http, uiSettings } as CoreSetup); + getValueSuggestions = setupValueSuggestionProvider({ http, uiSettings } as CoreSetup); }); describe('with value suggestions disabled', () => { it('should return an empty array', async () => { - const suggestions = await getFieldSuggestions({ + const suggestions = await getValueSuggestions({ indexPattern: stubIndexPattern, field: stubFields[0], query: '', @@ -51,7 +51,7 @@ describe('FieldSuggestions', () => { it('should return true/false for boolean fields', async () => { const [field] = stubFields.filter(({ type }) => type === 'boolean'); - const suggestions = await getFieldSuggestions({ + const suggestions = await getValueSuggestions({ indexPattern: stubIndexPattern, field, query: '', @@ -63,7 +63,7 @@ describe('FieldSuggestions', () => { it('should return an empty array if the field type is not a string or boolean', async () => { const [field] = stubFields.filter(({ type }) => type !== 'string' && type !== 'boolean'); - const suggestions = await getFieldSuggestions({ + const suggestions = await getValueSuggestions({ indexPattern: stubIndexPattern, field, query: '', @@ -75,7 +75,7 @@ describe('FieldSuggestions', () => { it('should return an empty array if the field is not aggregatable', async () => { const [field] = stubFields.filter(({ aggregatable }) => !aggregatable); - const suggestions = await getFieldSuggestions({ + const suggestions = await getValueSuggestions({ indexPattern: stubIndexPattern, field, query: '', @@ -90,7 +90,7 @@ describe('FieldSuggestions', () => { ({ type, aggregatable }) => type === 'string' && aggregatable ); - await getFieldSuggestions({ + await getValueSuggestions({ indexPattern: stubIndexPattern, field, query: '', @@ -109,8 +109,8 @@ describe('FieldSuggestions', () => { query: '', }; - await getFieldSuggestions(args); - await getFieldSuggestions(args); + await getValueSuggestions(args); + await getValueSuggestions(args); expect(http.fetch).toHaveBeenCalledTimes(1); }); @@ -128,10 +128,10 @@ describe('FieldSuggestions', () => { const { now } = Date; Date.now = jest.fn(() => 0); - await getFieldSuggestions(args); + await getValueSuggestions(args); Date.now = jest.fn(() => 60 * 1000); - await getFieldSuggestions(args); + await getValueSuggestions(args); Date.now = now; expect(http.fetch).toHaveBeenCalledTimes(2); @@ -142,22 +142,22 @@ describe('FieldSuggestions', () => { ({ type, aggregatable }) => type === 'string' && aggregatable ); - await getFieldSuggestions({ + await getValueSuggestions({ indexPattern: stubIndexPattern, field: fields[0], query: '', }); - await getFieldSuggestions({ + await getValueSuggestions({ indexPattern: stubIndexPattern, field: fields[0], query: 'query', }); - await getFieldSuggestions({ + await getValueSuggestions({ indexPattern: stubIndexPattern, field: fields[1], query: '', }); - await getFieldSuggestions({ + await getValueSuggestions({ indexPattern: stubIndexPattern, field: fields[1], query: 'query', @@ -168,22 +168,22 @@ describe('FieldSuggestions', () => { title: 'customIndexPattern', }; - await getFieldSuggestions({ + await getValueSuggestions({ indexPattern: customIndexPattern, field: fields[0], query: '', }); - await getFieldSuggestions({ + await getValueSuggestions({ indexPattern: customIndexPattern, field: fields[0], query: 'query', }); - await getFieldSuggestions({ + await getValueSuggestions({ indexPattern: customIndexPattern, field: fields[1], query: '', }); - await getFieldSuggestions({ + await getValueSuggestions({ indexPattern: customIndexPattern, field: fields[1], query: 'query', diff --git a/src/plugins/data/public/autocomplete/providers/field_suggestion_provider.ts b/src/plugins/data/public/autocomplete/providers/value_suggestion_provider.ts similarity index 88% rename from src/plugins/data/public/autocomplete/providers/field_suggestion_provider.ts rename to src/plugins/data/public/autocomplete/providers/value_suggestion_provider.ts index 0d63e47f30750..5df88000edbd5 100644 --- a/src/plugins/data/public/autocomplete/providers/field_suggestion_provider.ts +++ b/src/plugins/data/public/autocomplete/providers/value_suggestion_provider.ts @@ -28,9 +28,9 @@ function resolver(title: string, field: IFieldType, query: string, boolFilter: a return [ttl, query, title, field.name, JSON.stringify(boolFilter)].join('|'); } -export type FieldSuggestionsGet = (args: FieldSuggestionsGetArgs) => Promise; +export type ValueSuggestionsGetFn = (args: ValueSuggestionsGetFnArgs) => Promise; -interface FieldSuggestionsGetArgs { +interface ValueSuggestionsGetFnArgs { indexPattern: IIndexPattern; field: IFieldType; query: string; @@ -38,7 +38,7 @@ interface FieldSuggestionsGetArgs { signal?: AbortSignal; } -export const setupFieldSuggestionProvider = (core: CoreSetup): FieldSuggestionsGet => { +export const setupValueSuggestionProvider = (core: CoreSetup): ValueSuggestionsGetFn => { const requestSuggestions = memoize( (index: string, field: IFieldType, query: string, boolFilter: any = [], signal?: AbortSignal) => core.http.fetch(`/api/kibana/suggestions/values/${index}`, { @@ -55,7 +55,7 @@ export const setupFieldSuggestionProvider = (core: CoreSetup): FieldSuggestionsG query, boolFilter, signal, - }: FieldSuggestionsGetArgs): Promise => { + }: ValueSuggestionsGetFnArgs): Promise => { const shouldSuggestValues = core!.uiSettings.get('filterEditor:suggestValues'); const { title } = indexPattern; diff --git a/src/plugins/data/public/autocomplete/types.ts b/src/plugins/data/public/autocomplete/types.ts index d604f800536d6..759e2dd25a5bc 100644 --- a/src/plugins/data/public/autocomplete/types.ts +++ b/src/plugins/data/public/autocomplete/types.ts @@ -28,6 +28,6 @@ export type AutocompleteStart = ReturnType; /** @public **/ export { QuerySuggestion, - QuerySuggestionsGet, + QuerySuggestionsGetFn, QuerySuggestionType, } from './providers/query_suggestion_provider'; diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index 82ebe6ec5d1bf..08a7a3ef11537 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -30,7 +30,7 @@ export type Setup = jest.Mocked>; export type Start = jest.Mocked>; const autocompleteMock: any = { - getFieldSuggestions: jest.fn(), + getValueSuggestions: jest.fn(), getQuerySuggestions: jest.fn(), hasQuerySuggestions: jest.fn(), }; diff --git a/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx b/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx index bec610cb904c6..2b2d83c9f5a8b 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx +++ b/src/plugins/data/public/ui/filter_bar/filter_editor/phrase_suggestor.tsx @@ -70,7 +70,7 @@ export class PhraseSuggestorUI extends Component } this.setState({ isLoading: true }); - const suggestions = await this.services.data.autocomplete.getFieldSuggestions({ + const suggestions = await this.services.data.autocomplete.getValueSuggestions({ indexPattern, field, query, diff --git a/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap b/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap index 64707c3c287ca..101069c7ef0b1 100644 --- a/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap +++ b/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap @@ -151,7 +151,7 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA }, "data": Object { "autocomplete": Object { - "getFieldSuggestions": [MockFunction], + "getValueSuggestions": [MockFunction], "getQuerySuggestions": [MockFunction], "hasQuerySuggestions": [MockFunction], }, @@ -777,7 +777,7 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA }, "data": Object { "autocomplete": Object { - "getFieldSuggestions": [MockFunction], + "getValueSuggestions": [MockFunction], "getQuerySuggestions": [MockFunction], "hasQuerySuggestions": [MockFunction], }, @@ -1385,7 +1385,7 @@ exports[`QueryStringInput Should pass the query language to the language switche }, "data": Object { "autocomplete": Object { - "getFieldSuggestions": [MockFunction], + "getValueSuggestions": [MockFunction], "getQuerySuggestions": [MockFunction], "hasQuerySuggestions": [MockFunction], }, @@ -2008,7 +2008,7 @@ exports[`QueryStringInput Should pass the query language to the language switche }, "data": Object { "autocomplete": Object { - "getFieldSuggestions": [MockFunction], + "getValueSuggestions": [MockFunction], "getQuerySuggestions": [MockFunction], "hasQuerySuggestions": [MockFunction], }, @@ -2616,7 +2616,7 @@ exports[`QueryStringInput Should render the given query 1`] = ` }, "data": Object { "autocomplete": Object { - "getFieldSuggestions": [MockFunction], + "getValueSuggestions": [MockFunction], "getQuerySuggestions": [MockFunction], "hasQuerySuggestions": [MockFunction], }, @@ -3239,7 +3239,7 @@ exports[`QueryStringInput Should render the given query 1`] = ` }, "data": Object { "autocomplete": Object { - "getFieldSuggestions": [MockFunction], + "getValueSuggestions": [MockFunction], "getQuerySuggestions": [MockFunction], "hasQuerySuggestions": [MockFunction], }, diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.js b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.js index d9523fe196d9a..9d0d70fd95747 100644 --- a/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.js +++ b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.js @@ -27,10 +27,10 @@ export function getSuggestionsProvider({ indexPatterns, boolFilter }) { const fullFieldName = nestedPath ? `${nestedPath}.${fieldName}` : fieldName; const fields = allFields.filter(field => field.name === fullFieldName); const query = `${prefix}${suffix}`.trim(); - const { getFieldSuggestions } = npStart.plugins.data.autocomplete; + const { getValueSuggestions } = npStart.plugins.data.autocomplete; const suggestionsByField = fields.map(field => - getFieldSuggestions({ + getValueSuggestions({ indexPattern: field.indexPattern, field, query, diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.test.js b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.test.js index f910cd14be68e..f5b652d2e2164 100644 --- a/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.test.js +++ b/x-pack/legacy/plugins/kuery_autocomplete/public/kql_query_suggestion/value.test.js @@ -13,7 +13,7 @@ jest.mock('ui/new_platform', () => ({ plugins: { data: { autocomplete: { - getFieldSuggestions: jest.fn(({ field }) => { + getValueSuggestions: jest.fn(({ field }) => { let res; if (field.type === 'boolean') { res = [true, false]; @@ -54,7 +54,7 @@ describe('Kuery value suggestions', function() { const suggestions = await getSuggestions({ fieldName, prefix, suffix }); expect(suggestions.map(({ text }) => text)).toEqual([]); - expect(npStart.plugins.data.autocomplete.getFieldSuggestions).toHaveBeenCalledTimes(0); + expect(npStart.plugins.data.autocomplete.getValueSuggestions).toHaveBeenCalledTimes(0); }); test('should format suggestions', async () => { @@ -89,7 +89,7 @@ describe('Kuery value suggestions', function() { const suggestions = await getSuggestions({ fieldName: 'ssl', prefix: '', suffix: '' }); expect(suggestions.map(({ text }) => text)).toEqual(['true ', 'false ']); - expect(npStart.plugins.data.autocomplete.getFieldSuggestions).toHaveBeenCalledTimes(1); + expect(npStart.plugins.data.autocomplete.getValueSuggestions).toHaveBeenCalledTimes(1); }); test('should filter out boolean suggestions', async () => { @@ -106,8 +106,8 @@ describe('Kuery value suggestions', function() { await getSuggestions({ fieldName: 'machine.os.raw', prefix, suffix }); - expect(npStart.plugins.data.autocomplete.getFieldSuggestions).toHaveBeenCalledTimes(1); - expect(npStart.plugins.data.autocomplete.getFieldSuggestions).toBeCalledWith( + expect(npStart.plugins.data.autocomplete.getValueSuggestions).toHaveBeenCalledTimes(1); + expect(npStart.plugins.data.autocomplete.getValueSuggestions).toBeCalledWith( expect.objectContaining({ field: expect.any(Object), query: prefix + suffix, From 5bc1213e0ba8aa814d8bf1b0ab11e57db11c25ec Mon Sep 17 00:00:00 2001 From: Alexey Antonov Date: Fri, 17 Jan 2020 14:15:03 +0300 Subject: [PATCH 11/11] update Jest snaphots --- .../__snapshots__/query_string_input.test.tsx.snap | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap b/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap index 101069c7ef0b1..bc08c87304fca 100644 --- a/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap +++ b/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap @@ -151,8 +151,8 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA }, "data": Object { "autocomplete": Object { - "getValueSuggestions": [MockFunction], "getQuerySuggestions": [MockFunction], + "getValueSuggestions": [MockFunction], "hasQuerySuggestions": [MockFunction], }, "fieldFormats": Object { @@ -777,8 +777,8 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA }, "data": Object { "autocomplete": Object { - "getValueSuggestions": [MockFunction], "getQuerySuggestions": [MockFunction], + "getValueSuggestions": [MockFunction], "hasQuerySuggestions": [MockFunction], }, "fieldFormats": Object { @@ -1385,8 +1385,8 @@ exports[`QueryStringInput Should pass the query language to the language switche }, "data": Object { "autocomplete": Object { - "getValueSuggestions": [MockFunction], "getQuerySuggestions": [MockFunction], + "getValueSuggestions": [MockFunction], "hasQuerySuggestions": [MockFunction], }, "fieldFormats": Object { @@ -2008,8 +2008,8 @@ exports[`QueryStringInput Should pass the query language to the language switche }, "data": Object { "autocomplete": Object { - "getValueSuggestions": [MockFunction], "getQuerySuggestions": [MockFunction], + "getValueSuggestions": [MockFunction], "hasQuerySuggestions": [MockFunction], }, "fieldFormats": Object { @@ -2616,8 +2616,8 @@ exports[`QueryStringInput Should render the given query 1`] = ` }, "data": Object { "autocomplete": Object { - "getValueSuggestions": [MockFunction], "getQuerySuggestions": [MockFunction], + "getValueSuggestions": [MockFunction], "hasQuerySuggestions": [MockFunction], }, "fieldFormats": Object { @@ -3239,8 +3239,8 @@ exports[`QueryStringInput Should render the given query 1`] = ` }, "data": Object { "autocomplete": Object { - "getValueSuggestions": [MockFunction], "getQuerySuggestions": [MockFunction], + "getValueSuggestions": [MockFunction], "hasQuerySuggestions": [MockFunction], }, "fieldFormats": Object {