From e22d67375e371c1729582e88f46b1c9dd5e02022 Mon Sep 17 00:00:00 2001 From: Liza K Date: Wed, 25 Sep 2019 14:44:53 +0300 Subject: [PATCH 01/32] Bind search bar --- src/legacy/core_plugins/data/public/legacy.ts | 4 +- src/legacy/core_plugins/data/public/plugin.ts | 23 +++++- .../components/query_bar_top_row.tsx | 12 +-- .../search_bar/components/bind_search_bar.tsx | 78 +++++++++++++++++++ .../search/search_bar/components/index.tsx | 1 + .../search_bar/components/search_bar.tsx | 61 +++++++-------- .../public/shim/legacy_dependencies_plugin.ts | 13 +++- .../data/public/timefilter/timefilter.ts | 14 ++-- .../filter_editor/filter_editor.js | 3 +- .../join_editor/resources/where_expression.js | 8 +- 10 files changed, 157 insertions(+), 60 deletions(-) create mode 100644 src/legacy/core_plugins/data/public/search/search_bar/components/bind_search_bar.tsx diff --git a/src/legacy/core_plugins/data/public/legacy.ts b/src/legacy/core_plugins/data/public/legacy.ts index c3618d412f425..9c9fa7b9d198b 100644 --- a/src/legacy/core_plugins/data/public/legacy.ts +++ b/src/legacy/core_plugins/data/public/legacy.ts @@ -45,4 +45,6 @@ export const setup = dataPlugin.setup(npSetup.core, { __LEGACY: legacyPlugin.setup(), }); -export const start = dataPlugin.start(npStart.core); +export const start = dataPlugin.start(npStart.core, { + __LEGACY: legacyPlugin.start(), +}); diff --git a/src/legacy/core_plugins/data/public/plugin.ts b/src/legacy/core_plugins/data/public/plugin.ts index aec97b02bc2b9..78983245d1000 100644 --- a/src/legacy/core_plugins/data/public/plugin.ts +++ b/src/legacy/core_plugins/data/public/plugin.ts @@ -18,12 +18,15 @@ */ import { CoreSetup, CoreStart, Plugin } from '../../../../core/public'; -import { SearchService, SearchSetup } from './search'; +import { SearchService, SearchSetup, createSearchBar } from './search'; import { QueryService, QuerySetup } from './query'; import { FilterService, FilterSetup } from './filter'; import { TimefilterService, TimefilterSetup } from './timefilter'; import { IndexPatternsService, IndexPatternsSetup } from './index_patterns'; -import { LegacyDependenciesPluginSetup } from './shim/legacy_dependencies_plugin'; +import { + LegacyDependenciesPluginSetup, + LegacyDependenciesPluginStart, +} from './shim/legacy_dependencies_plugin'; /** * Interface for any dependencies on other plugins' `setup` contracts. @@ -34,6 +37,10 @@ export interface DataPluginSetupDependencies { __LEGACY: LegacyDependenciesPluginSetup; } +export interface DataPluginStartDependencies { + __LEGACY: LegacyDependenciesPluginStart; +} + /** * Interface for this plugin's returned `setup` contract. * @@ -96,9 +103,19 @@ export class DataPlugin implements Plugin void; - onChange: (payload: { dateRange: DateRange; query?: Query }) => void; + onSubmit: (payload: { dateRange: TimeRange; query?: Query }) => void; + onChange: (payload: { dateRange: TimeRange; query?: Query }) => void; disableAutoFocus?: boolean; appName: string; screenTitle?: string; @@ -131,7 +127,7 @@ function QueryBarTopRowUI(props: Props) { } } - function onSubmit({ query, dateRange }: { query?: Query; dateRange: DateRange }) { + function onSubmit({ query, dateRange }: { query?: Query; dateRange: TimeRange }) { handleLuceneSyntaxWarning(); if (props.timeHistory) { diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/bind_search_bar.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/bind_search_bar.tsx new file mode 100644 index 0000000000000..392211ae10a5a --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/bind_search_bar.tsx @@ -0,0 +1,78 @@ +/* + * 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 React from 'react'; +import { Filter } from '@kbn/es-query'; +import { CoreStart } from 'src/core/public'; +import { Storage } from 'ui/storage'; +import { KibanaContextProvider } from '../../../../../../../../src/plugins/kibana_react/public'; +import { TimefilterSetup } from '../../../timefilter'; +import { FilterManager, SearchBar } from '../../../'; +import { SearchBarOwnProps } from '.'; + +interface StatefulSearchBarDeps { + core: CoreStart; + storage: Storage; + timefilter: TimefilterSetup; + filterManager: FilterManager; +} + +const defaultFiltersUpdated = (filterManager: FilterManager) => { + return (filters: Filter[]) => { + filterManager.setFilters(filters); + }; +}; + +const defaultOnRefreshChange = (timefilter: TimefilterSetup) => { + return (options: { isPaused: boolean; refreshInterval: number }) => { + timefilter.timefilter.setRefreshInterval({ + value: options.refreshInterval, + pause: options.isPaused, + }); + }; +}; + +export function createSearchBar({ + core, + storage, + timefilter, + filterManager, +}: StatefulSearchBarDeps) { + const timeRange = timefilter.timefilter.getTime(); + const refreshInterval = timefilter.timefilter.getRefreshInterval(); + + return (props: SearchBarOwnProps) => ( + + + + ); +} diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/index.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/index.tsx index 24ffa939a746e..fc2e0e42d73f8 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/index.tsx +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/index.tsx @@ -18,3 +18,4 @@ */ export * from './search_bar'; +export * from './bind_search_bar'; diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx index 6c73fa3614cc3..3f9a68fdc4be3 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx @@ -26,6 +26,7 @@ import { Storage } from 'ui/storage'; import { get, isEqual } from 'lodash'; import { CoreStart } from 'src/core/public'; +import { TimeRange } from 'src/plugins/data/common/types'; import { IndexPattern, Query, FilterBar } from '../../../../../data/public'; import { QueryBarTopRow } from '../../../query'; import { SavedQuery, SavedQueryAttributes } from '../index'; @@ -35,53 +36,51 @@ import { SavedQueryService } from '../lib/saved_query_service'; import { createSavedQueryService } from '../lib/saved_query_service'; import { TimeHistoryContract } from '../../../timefilter'; -interface DateRange { - from: string; - to: string; -} - -/** - * NgReact lib requires that changes to the props need to be made in the directive config as well - * See [search_bar\directive\index.js] file - */ -export interface SearchBarProps { - appName: string; +interface SearchBarInjectedDeps { intl: InjectedIntl; - indexPatterns?: IndexPattern[]; - - // Query bar - showQueryBar?: boolean; - showQueryInput?: boolean; - screenTitle?: string; store?: Storage; - query?: Query; - savedQuery?: SavedQuery; - onQuerySubmit?: (payload: { dateRange: DateRange; query?: Query }) => void; timeHistory: TimeHistoryContract; // Filter bar - showFilterBar?: boolean; - filters?: Filter[]; onFiltersUpdated?: (filters: Filter[]) => void; + filters?: Filter[]; // Date picker - showDatePicker?: boolean; dateRangeFrom?: string; dateRangeTo?: string; // Autorefresh + onRefreshChange?: (options: { isPaused: boolean; refreshInterval: number }) => void; isRefreshPaused?: boolean; refreshInterval?: number; + + // TODO: deprecate by using context + savedObjects: CoreStart['savedObjects']; + notifications: CoreStart['notifications']; +} + +export interface SearchBarOwnProps { + appName: string; + indexPatterns?: IndexPattern[]; + customSubmitButton?: React.ReactNode; + screenTitle?: string; + + // Togglers + showQueryBar?: boolean; + showQueryInput?: boolean; + showFilterBar?: boolean; + showDatePicker?: boolean; showAutoRefreshOnly?: boolean; showSaveQuery?: boolean; - onRefreshChange?: (options: { isPaused: boolean; refreshInterval: number }) => void; + + // Query bar - should be in SearchBarInjectedDeps + query?: Query; + savedQuery?: SavedQuery; + onQuerySubmit?: (payload: { dateRange: TimeRange; query?: Query }) => void; onSaved?: (savedQuery: SavedQuery) => void; onSavedQueryUpdated?: (savedQuery: SavedQuery) => void; onClearSavedQuery?: () => void; - customSubmitButton?: React.ReactNode; - - // TODO: deprecate - savedObjects: CoreStart['savedObjects']; - notifications: CoreStart['notifications']; } +export type SearchBarProps = SearchBarOwnProps & SearchBarInjectedDeps; + interface State { isFiltersVisible: boolean; showSaveQueryModal: boolean; @@ -285,7 +284,7 @@ class SearchBarUI extends Component { }); }; - public onQueryBarChange = (queryAndDateRange: { dateRange: DateRange; query?: Query }) => { + public onQueryBarChange = (queryAndDateRange: { dateRange: TimeRange; query?: Query }) => { this.setState({ query: queryAndDateRange.query, dateRangeFrom: queryAndDateRange.dateRange.from, @@ -293,7 +292,7 @@ class SearchBarUI extends Component { }); }; - public onQueryBarSubmit = (queryAndDateRange: { dateRange?: DateRange; query?: Query }) => { + public onQueryBarSubmit = (queryAndDateRange: { dateRange?: TimeRange; query?: Query }) => { this.setState( { query: queryAndDateRange.query, diff --git a/src/legacy/core_plugins/data/public/shim/legacy_dependencies_plugin.ts b/src/legacy/core_plugins/data/public/shim/legacy_dependencies_plugin.ts index 4289d56b33c60..126754388f13f 100644 --- a/src/legacy/core_plugins/data/public/shim/legacy_dependencies_plugin.ts +++ b/src/legacy/core_plugins/data/public/shim/legacy_dependencies_plugin.ts @@ -18,7 +18,8 @@ */ import chrome from 'ui/chrome'; -import { CoreStart, Plugin } from '../../../../../../src/core/public'; +import { Storage } from 'ui/storage'; +import { Plugin } from '../../../../../../src/core/public'; import { initLegacyModule } from './legacy_module'; /** @internal */ @@ -26,6 +27,10 @@ export interface LegacyDependenciesPluginSetup { savedObjectsClient: any; } +export interface LegacyDependenciesPluginStart { + storage: Storage; +} + export class LegacyDependenciesPlugin implements Plugin { public setup() { initLegacyModule(); @@ -35,7 +40,9 @@ export class LegacyDependenciesPlugin implements Plugin { } as LegacyDependenciesPluginSetup; } - public start(core: CoreStart) { - // nothing to do here yet + public start() { + return { + storage: new Storage(window.localStorage), + } as LegacyDependenciesPluginStart; } } diff --git a/src/legacy/core_plugins/data/public/timefilter/timefilter.ts b/src/legacy/core_plugins/data/public/timefilter/timefilter.ts index c08ea9043da92..64129ea2af5ff 100644 --- a/src/legacy/core_plugins/data/public/timefilter/timefilter.ts +++ b/src/legacy/core_plugins/data/public/timefilter/timefilter.ts @@ -25,7 +25,7 @@ import { IndexPattern, TimeHistoryContract } from '../index'; import { areRefreshIntervalsDifferent, areTimeRangesDifferent } from './lib/diff_time_picker_vals'; import { parseQueryString } from './lib/parse_querystring'; import { calculateBounds, getTime } from './get_time'; -import { TimefilterConfig, InputTimeRange } from './types'; +import { TimefilterConfig, InputTimeRange, TimeRangeBounds } from './types'; export class Timefilter { // Fired when isTimeRangeSelectorEnabled \ isAutoRefreshSelectorEnabled are toggled @@ -148,19 +148,19 @@ export class Timefilter { return getTime(indexPattern, timeRange ? timeRange : this._time, this.getForceNow()); }; - public getBounds = () => { + public getBounds(): TimeRangeBounds { return this.calculateBounds(this._time); - }; + } - public calculateBounds = (timeRange: TimeRange) => { + public calculateBounds(timeRange: TimeRange): TimeRangeBounds { return calculateBounds(timeRange, { forceNow: this.getForceNow() }); - }; + } - public getActiveBounds = () => { + public getActiveBounds(): TimeRangeBounds | undefined { if (this.isTimeRangeSelectorEnabled) { return this.getBounds(); } - }; + } /** * Show the time bounds selector part of the time filter diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js index c534583ddb58f..53ba039b4ea8b 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js @@ -23,7 +23,8 @@ import { i18n } from '@kbn/i18n'; import { indexPatternService } from '../../../kibana_services'; import { Storage } from 'ui/storage'; -import { SearchBar } from 'plugins/data'; +import { start as data } from '../../../../../../../../src/legacy/core_plugins/data/public/legacy'; +const { SearchBar } = data.ui; import { npStart } from 'ui/new_platform'; import { KibanaContextProvider } from '../../../../../../../../src/plugins/kibana_react/public'; diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/where_expression.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/where_expression.js index 74ec80c0765e8..c8852cf74e28b 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/where_expression.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/where_expression.js @@ -14,12 +14,11 @@ import { } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { SearchBar } from 'plugins/data'; -import { Storage } from 'ui/storage'; import { npStart } from 'ui/new_platform'; import { KibanaContextProvider } from '../../../../../../../../../src/plugins/kibana_react/public'; +import { Storage } from 'ui/storage'; const localStorage = new Storage(window.localStorage); - export class WhereExpression extends Component { state = { @@ -82,10 +81,7 @@ export class WhereExpression extends Component { Date: Wed, 25 Sep 2019 20:05:20 +0300 Subject: [PATCH 02/32] create prewired data components --- .../query_bar_input.test.tsx.snap | 3052 +++++++++++------ .../components/query_bar_input.test.tsx | 206 +- .../query_bar/components/query_bar_input.tsx | 42 +- .../components/query_bar_top_row.test.tsx | 184 +- .../components/query_bar_top_row.tsx | 17 +- .../search_bar/components/search_bar.test.tsx | 140 +- .../search_bar/components/search_bar.tsx | 27 +- src/legacy/core_plugins/data/public/types.ts | 28 + .../public/top_nav_menu/top_nav_menu.test.tsx | 15 +- .../public/top_nav_menu/top_nav_menu.tsx | 37 +- .../ui/public/kbn_top_nav/kbn_top_nav.js | 19 - 11 files changed, 2340 insertions(+), 1427 deletions(-) create mode 100644 src/legacy/core_plugins/data/public/types.ts diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/__snapshots__/query_bar_input.test.tsx.snap b/src/legacy/core_plugins/data/public/query/query_bar/components/__snapshots__/query_bar_input.test.tsx.snap index 8a0347875d778..9d97c3aca4e1e 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/__snapshots__/query_bar_input.test.tsx.snap +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/__snapshots__/query_bar_input.test.tsx.snap @@ -1,63 +1,11 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`QueryBarInput Should disable autoFocus on EuiFieldText when disableAutoFocus prop is true 1`] = ` - + - -
+ -
-
- + - + -
- - - - -
- - - - + aria-controls="kbnTypeahead__items" + aria-expanded={false} + aria-haspopup="true" + aria-owns="kbnTypeahead__items" + onMouseDown={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchStart={[Function]} + role="combobox" + style={ + Object { + "position": "relative", } - closePopover={[Function]} - display="inlineBlock" - hasArrow={true} - id="popover" - isOpen={false} - ownFocus={true} - panelPaddingSize="m" - withTitle={true} + } + > +
- -
+ } + aria-activedescendant="" + aria-autocomplete="list" + aria-controls="kbnTypeahead__items" + aria-label="You are on search box of Another Screen page. Start typing to search and filter the test" + autoComplete="off" + autoFocus={false} + compressed={false} + data-test-subj="queryInput" + fullWidth={true} + inputRef={[Function]} + isLoading={false} + onChange={[Function]} + onClick={[Function]} onKeyDown={[Function]} - onMouseDown={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchStart={[Function]} + onKeyUp={[Function]} + placeholder="Search" + role="textbox" + spellCheck={false} + type="text" + value="response:200" > -
+ } + compressed={false} + fullWidth={true} + isLoading={false} > - -
+ + + + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + id="popover" + isOpen={false} + ownFocus={true} + panelPaddingSize="m" + withTitle={true} > - - - KQL - - - - - -
-
- -
-
-
-
-
-
-
- -
-
-
+
+ + + +
+ + + + + + + + + + + + + + + + + + + `; exports[`QueryBarInput Should pass the query language to the language switcher 1`] = ` - + - -
+ -
-
- + - + -
- - - - -
- - - - + aria-controls="kbnTypeahead__items" + aria-expanded={false} + aria-haspopup="true" + aria-owns="kbnTypeahead__items" + onMouseDown={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchStart={[Function]} + role="combobox" + style={ + Object { + "position": "relative", } - closePopover={[Function]} - display="inlineBlock" - hasArrow={true} - id="popover" - isOpen={false} - ownFocus={true} - panelPaddingSize="m" - withTitle={true} + } + > +
- -
+ } + aria-activedescendant="" + aria-autocomplete="list" + aria-controls="kbnTypeahead__items" + aria-label="You are on search box of Another Screen page. Start typing to search and filter the test" + autoComplete="off" + autoFocus={true} + compressed={false} + data-test-subj="queryInput" + fullWidth={true} + inputRef={[Function]} + isLoading={false} + onChange={[Function]} + onClick={[Function]} onKeyDown={[Function]} - onMouseDown={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchStart={[Function]} + onKeyUp={[Function]} + placeholder="Search" + role="textbox" + spellCheck={false} + type="text" + value="response:200" > -
+ } + compressed={false} + fullWidth={true} + isLoading={false} > - -
+ - + + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + id="popover" + isOpen={false} + ownFocus={true} + panelPaddingSize="m" + withTitle={true} > - - - Lucene - - - - - -
-
- -
-
-
-
-
-
-
- -
-
-
+
+ + + +
+ + + + + + + + + + + + + + + + + + + `; exports[`QueryBarInput Should render the given query 1`] = ` - + - -
+ -
-
- + - + -
- - - - -
- - - - + aria-controls="kbnTypeahead__items" + aria-expanded={false} + aria-haspopup="true" + aria-owns="kbnTypeahead__items" + onMouseDown={[Function]} + onMouseUp={[Function]} + onTouchEnd={[Function]} + onTouchStart={[Function]} + role="combobox" + style={ + Object { + "position": "relative", } - closePopover={[Function]} - display="inlineBlock" - hasArrow={true} - id="popover" - isOpen={false} - ownFocus={true} - panelPaddingSize="m" - withTitle={true} + } + > +
- -
+ } + aria-activedescendant="" + aria-autocomplete="list" + aria-controls="kbnTypeahead__items" + aria-label="You are on search box of Another Screen page. Start typing to search and filter the test" + autoComplete="off" + autoFocus={true} + compressed={false} + data-test-subj="queryInput" + fullWidth={true} + inputRef={[Function]} + isLoading={false} + onChange={[Function]} + onClick={[Function]} onKeyDown={[Function]} - onMouseDown={[Function]} - onMouseUp={[Function]} - onTouchEnd={[Function]} - onTouchStart={[Function]} + onKeyUp={[Function]} + placeholder="Search" + role="textbox" + spellCheck={false} + type="text" + value="response:200" > -
+ } + compressed={false} + fullWidth={true} + isLoading={false} > - -
+ + + + + } + closePopover={[Function]} + display="inlineBlock" + hasArrow={true} + id="popover" + isOpen={false} + ownFocus={true} + panelPaddingSize="m" + withTitle={true} > - - - KQL - - - - - -
-
- -
-
-
-
-
-
-
- -
-
-
+
+ + + +
+ + + + + + + + + + + + + + + + + + + `; diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.tsx index e66d71b9b08b4..e0bb8677e32cc 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.tsx @@ -25,12 +25,14 @@ import { import { EuiFieldText } from '@elastic/eui'; import React from 'react'; -import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { QueryLanguageSwitcher } from './language_switcher'; import { QueryBarInput, QueryBarInputUI } from './query_bar_input'; import { coreMock } from '../../../../../../../core/public/mocks'; const startMock = coreMock.createStart(); import { IndexPattern } from '../../../index'; +import { KibanaContextProvider } from 'src/plugins/kibana_react/public'; +import { I18nProvider } from '@kbn/i18n/react'; +import { mount } from 'enzyme'; const noop = () => { return; @@ -78,64 +80,67 @@ const mockIndexPattern = { ], } as IndexPattern; +function wrapQueryBarInputInContext(testProps: any, store?: any) { + const defaultOptions = { + appName: 'test', + screenTitle: 'Another Screen', + intl: null as any, + }; + + const services = { + uiSettings: startMock.uiSettings, + savedObjects: startMock.savedObjects, + notifications: startMock.notifications, + http: startMock.http, + store: store || createMockStorage(), + }; + + return ( + + + + + + ); +} + describe('QueryBarInput', () => { beforeEach(() => { jest.clearAllMocks(); }); it('Should render the given query', () => { - const component = mountWithIntl( - + const component = mount( + wrapQueryBarInputInContext({ + query: kqlQuery, + onSubmit: noop, + indexPatterns: [mockIndexPattern], + }) ); expect(component).toMatchSnapshot(); }); it('Should pass the query language to the language switcher', () => { - const component = mountWithIntl( - + const component = mount( + wrapQueryBarInputInContext({ + query: luceneQuery, + onSubmit: noop, + indexPatterns: [mockIndexPattern], + }) ); expect(component).toMatchSnapshot(); }); it('Should disable autoFocus on EuiFieldText when disableAutoFocus prop is true', () => { - const component = mountWithIntl( - + const component = mount( + wrapQueryBarInputInContext({ + query: kqlQuery, + onSubmit: noop, + indexPatterns: [mockIndexPattern], + disableAutoFocus: true, + }) ); expect(component).toMatchSnapshot(); @@ -144,43 +149,32 @@ describe('QueryBarInput', () => { it('Should create a unique PersistedLog based on the appName and query language', () => { mockPersistedLogFactory.mockClear(); - mountWithIntl( - + mount( + wrapQueryBarInputInContext({ + query: kqlQuery, + onSubmit: noop, + indexPatterns: [mockIndexPattern], + disableAutoFocus: true, + appName: 'discover', + }) ); - expect(mockPersistedLogFactory.mock.calls[0][0]).toBe('typeahead:discover-kuery'); }); it("On language selection, should store the user's preference in localstorage and reset the query", () => { const mockStorage = createMockStorage(); const mockCallback = jest.fn(); - - const component = mountWithIntl( - + const component = mount( + wrapQueryBarInputInContext( + { + query: kqlQuery, + onSubmit: mockCallback, + indexPatterns: [mockIndexPattern], + disableAutoFocus: true, + appName: 'discover', + }, + mockStorage + ) ); component @@ -194,23 +188,16 @@ describe('QueryBarInput', () => { it('Should call onSubmit when the user hits enter inside the query bar', () => { const mockCallback = jest.fn(); - const component = mountWithIntl( - + const component = mount( + wrapQueryBarInputInContext({ + query: kqlQuery, + onSubmit: mockCallback, + indexPatterns: [mockIndexPattern], + disableAutoFocus: true, + }) ); - const instance = component.instance() as QueryBarInputUI; + const instance = component.find('QueryBarInputUI').instance() as QueryBarInputUI; const input = instance.inputRef; const inputWrapper = component.find(EuiFieldText).find('input'); inputWrapper.simulate('keyDown', { target: input, keyCode: 13, key: 'Enter', metaKey: true }); @@ -220,23 +207,17 @@ describe('QueryBarInput', () => { }); it('Should use PersistedLog for recent search suggestions', async () => { - const component = mountWithIntl( - + const component = mount( + wrapQueryBarInputInContext({ + query: kqlQuery, + onSubmit: noop, + indexPatterns: [mockIndexPattern], + disableAutoFocus: true, + persistedLog: mockPersistedLog, + }) ); - const instance = component.instance() as QueryBarInputUI; + const instance = component.find('QueryBarInputUI').instance() as QueryBarInputUI; const input = instance.inputRef; const inputWrapper = component.find(EuiFieldText).find('input'); inputWrapper.simulate('keyDown', { target: input, keyCode: 13, key: 'Enter', metaKey: true }); @@ -250,22 +231,15 @@ describe('QueryBarInput', () => { it('Should accept index pattern strings and fetch the full object', () => { mockFetchIndexPatterns.mockClear(); - - mountWithIntl( - + mount( + wrapQueryBarInputInContext({ + query: kqlQuery, + onSubmit: noop, + indexPatterns: ['logstash-*'], + disableAutoFocus: true, + }) ); + expect(mockFetchIndexPatterns).toHaveBeenCalledWith( startMock.savedObjects.client, ['logstash-*'], diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx index 7a972a6068f6f..d54912c30c6bd 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx @@ -25,17 +25,16 @@ import { EuiFieldText, EuiOutsideClickDetector, PopoverAnchorPosition } from '@e import { InjectedIntl, injectI18n } from '@kbn/i18n/react'; import { debounce, compact, isEqual, omit } from 'lodash'; import { PersistedLog } from 'ui/persisted_log'; -import { Storage } from 'ui/storage'; import { npStart } from 'ui/new_platform'; -import { - UiSettingsClientContract, - SavedObjectsClientContract, - HttpServiceBase, -} from 'src/core/public'; + import { AutocompleteSuggestion, AutocompleteSuggestionType, } from '../../../../../../../plugins/data/public'; +import { + withKibana, + KibanaReactContextValue, +} from '../../../../../../../plugins/kibana_react/public'; import { IndexPattern, StaticIndexPattern } from '../../../index_patterns'; import { Query } from '../index'; import { fromUser, matchPairs, toUser } from '../lib'; @@ -43,6 +42,7 @@ import { QueryLanguageSwitcher } from './language_switcher'; import { SuggestionsComponent } from './typeahead/suggestions_component'; import { getQueryLog } from '../lib/get_query_log'; import { fetchIndexPatterns } from '../lib/fetch_index_patterns'; +import { IDataPluginServices } from '../../../types'; // todo: related to https://github.com/elastic/kibana/pull/45762/files // Will be refactored after merge of related PR @@ -50,12 +50,9 @@ const getAutocompleteProvider = (language: string) => npStart.plugins.data.autocomplete.getProvider(language); interface Props { - uiSettings: UiSettingsClientContract; - indexPatterns: Array; - savedObjectsClient: SavedObjectsClientContract; - http: HttpServiceBase; - store: Storage; + kibana: KibanaReactContextValue; intl: InjectedIntl; + indexPatterns: Array; query: Query; appName: string; disableAutoFocus?: boolean; @@ -107,6 +104,7 @@ export class QueryBarInputUI extends Component { public inputRef: HTMLInputElement | null = null; private persistedLog: PersistedLog | undefined; + private services!: IDataPluginServices; private componentIsUnmounting = false; private getQueryString = () => { @@ -122,9 +120,9 @@ export class QueryBarInputUI extends Component { ) as IndexPattern[]; const objectPatternsFromStrings = (await fetchIndexPatterns( - this.props.savedObjectsClient, + this.services.savedObjects!.client, stringPatterns, - this.props.uiSettings + this.services.uiSettings! )) as IndexPattern[]; this.setState({ @@ -137,7 +135,7 @@ export class QueryBarInputUI extends Component { return; } - const uiSettings = this.props.uiSettings; + const uiSettings = this.services.uiSettings; const language = this.props.query.language; const queryString = this.getQueryString(); @@ -369,11 +367,11 @@ export class QueryBarInputUI extends Component { // Send telemetry info every time the user opts in or out of kuery // As a result it is important this function only ever gets called in the // UI component's change handler. - this.props.http.post('/api/kibana/kql_opt_in_telemetry', { + this.services.http.post('/api/kibana/kql_opt_in_telemetry', { body: JSON.stringify({ opt_in: language === 'kuery' }), }); - this.props.store.set('kibana.userQueryLanguage', language); + this.services.store.set('kibana.userQueryLanguage', language); const newQuery = { query: '', language }; this.onChange(newQuery); @@ -399,6 +397,8 @@ export class QueryBarInputUI extends Component { }; public componentDidMount() { + this.services = this.props.kibana.services; + const parsedQuery = fromUser(toUser(this.props.query.query)); if (!isEqual(this.props.query.query, parsedQuery)) { this.onChange({ ...this.props.query, query: parsedQuery }); @@ -406,7 +406,7 @@ export class QueryBarInputUI extends Component { this.persistedLog = this.props.persistedLog ? this.props.persistedLog - : getQueryLog(this.props.uiSettings, this.props.appName, this.props.query.language); + : getQueryLog(this.services.uiSettings, this.props.appName, this.props.query.language); this.fetchIndexPatterns().then(this.updateSuggestions); } @@ -419,7 +419,7 @@ export class QueryBarInputUI extends Component { this.persistedLog = this.props.persistedLog ? this.props.persistedLog - : getQueryLog(this.props.uiSettings, this.props.appName, this.props.query.language); + : getQueryLog(this.services.uiSettings, this.props.appName, this.props.query.language); if (!isEqual(prevProps.indexPatterns, this.props.indexPatterns)) { this.fetchIndexPatterns().then(this.updateSuggestions); @@ -449,19 +449,17 @@ export class QueryBarInputUI extends Component { const rest = omit(this.props, [ 'indexPatterns', 'intl', + 'kibana', 'query', 'appName', 'disableAutoFocus', 'screenTitle', 'prepend', - 'store', 'persistedLog', 'bubbleSubmitEvent', 'languageSwitcherPopoverAnchorPosition', 'onChange', 'onSubmit', - 'uiSettings', - 'savedObjectsClient', ]); return ( @@ -548,4 +546,4 @@ export class QueryBarInputUI extends Component { } } -export const QueryBarInput = injectI18n(QueryBarInputUI); +export const QueryBarInput = injectI18n(withKibana(QueryBarInputUI)); diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.tsx index 0926af7b30ef7..5ed28ec409b25 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.tsx @@ -97,42 +97,49 @@ const mockIndexPattern = { ], } as IndexPattern; -describe('QueryBarTopRowTopRow', () => { - const QUERY_INPUT_SELECTOR = 'InjectIntl(QueryBarInputUI)'; - const TIMEPICKER_SELECTOR = 'EuiSuperDatePicker'; - const services = { - uiSettings: startMock.uiSettings, - savedObjects: startMock.savedObjects, - notifications: startMock.notifications, - http: startMock.http, - }; +function wrapQueryBarTopRowInContext(testProps: any) { const defaultOptions = { appName: 'discover', screenTitle: 'Another Screen', onSubmit: noop, onChange: noop, - store: createMockStorage(), intl: null as any, }; + const services = { + uiSettings: startMock.uiSettings, + savedObjects: startMock.savedObjects, + notifications: startMock.notifications, + http: startMock.http, + store: createMockStorage(), + }; + + return ( + + + + + + ); +} + +describe('QueryBarTopRowTopRow', () => { + const QUERY_INPUT_SELECTOR = 'QueryBarInputUI'; + const TIMEPICKER_SELECTOR = 'EuiSuperDatePicker'; + beforeEach(() => { jest.clearAllMocks(); }); it('Should render the given query', () => { const component = mount( - - - - - + wrapQueryBarTopRowInContext({ + query: kqlQuery, + screenTitle: 'Another Screen', + isDirty: false, + indexPatterns: [mockIndexPattern], + timeHistory: timefilterSetupMock.history, + }) ); expect(component.find(QUERY_INPUT_SELECTOR).length).toBe(1); @@ -141,19 +148,14 @@ describe('QueryBarTopRowTopRow', () => { it('Should create a unique PersistedLog based on the appName and query language', () => { mount( - - - - - + wrapQueryBarTopRowInContext({ + query: kqlQuery, + screenTitle: 'Another Screen', + indexPatterns: [mockIndexPattern], + timeHistory: timefilterSetupMock.history, + disableAutoFocus: true, + isDirty: false, + }) ); expect(mockPersistedLogFactory.mock.calls[0][0]).toBe('typeahead:discover-kuery'); @@ -161,15 +163,10 @@ describe('QueryBarTopRowTopRow', () => { it('Should render only timepicker when no options provided', () => { const component = mount( - - - - - + wrapQueryBarTopRowInContext({ + isDirty: false, + timeHistory: timefilterSetupMock.history, + }) ); expect(component.find(QUERY_INPUT_SELECTOR).length).toBe(0); @@ -178,16 +175,11 @@ describe('QueryBarTopRowTopRow', () => { it('Should not show timepicker when asked', () => { const component = mount( - - - - - + wrapQueryBarTopRowInContext({ + showDatePicker: false, + timeHistory: timefilterSetupMock.history, + isDirty: false, + }) ); expect(component.find(QUERY_INPUT_SELECTOR).length).toBe(0); @@ -196,19 +188,14 @@ describe('QueryBarTopRowTopRow', () => { it('Should render timepicker with options', () => { const component = mount( - - - - - + wrapQueryBarTopRowInContext({ + isDirty: false, + screenTitle: 'Another Screen', + showDatePicker: true, + dateRangeFrom: 'now-7d', + dateRangeTo: 'now', + timeHistory: timefilterSetupMock.history, + }) ); expect(component.find(QUERY_INPUT_SELECTOR).length).toBe(0); @@ -217,19 +204,16 @@ describe('QueryBarTopRowTopRow', () => { it('Should render only query input bar', () => { const component = mount( - - - - - + wrapQueryBarTopRowInContext({ + query: kqlQuery, + indexPatterns: [mockIndexPattern], + isDirty: false, + screenTitle: 'Another Screen', + showDatePicker: false, + dateRangeFrom: 'now-7d', + dateRangeTo: 'now', + timeHistory: timefilterSetupMock.history, + }) ); expect(component.find(QUERY_INPUT_SELECTOR).length).toBe(1); @@ -238,20 +222,15 @@ describe('QueryBarTopRowTopRow', () => { it('Should NOT render query input bar if disabled', () => { const component = mount( - - - - - + wrapQueryBarTopRowInContext({ + query: kqlQuery, + isDirty: false, + screenTitle: 'Another Screen', + indexPatterns: [mockIndexPattern], + showQueryInput: false, + showDatePicker: false, + timeHistory: timefilterSetupMock.history, + }) ); expect(component.find(QUERY_INPUT_SELECTOR).length).toBe(0); @@ -260,17 +239,12 @@ describe('QueryBarTopRowTopRow', () => { it('Should NOT render query input bar if missing options', () => { const component = mount( - - - - - + wrapQueryBarTopRowInContext({ + isDirty: false, + screenTitle: 'Another Screen', + showDatePicker: false, + timeHistory: timefilterSetupMock.history, + }) ); expect(component.find(QUERY_INPUT_SELECTOR).length).toBe(0); diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.tsx index 288442c704452..45708639e03a4 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.tsx @@ -47,7 +47,6 @@ interface Props { appName: string; screenTitle?: string; indexPatterns?: Array; - store?: Storage; intl: InjectedIntl; prepend?: React.ReactNode; showQueryInput?: boolean; @@ -66,8 +65,8 @@ interface Props { function QueryBarTopRowUI(props: Props) { const [isDateRangeInvalid, setIsDateRangeInvalid] = useState(false); - const kibana = useKibana(); - const { uiSettings, http, notifications, savedObjects } = kibana.services; + const kibana = useKibana<{ store: Storage }>(); + const { uiSettings, notifications, store } = kibana.services; const queryLanguage = props.query && props.query.language; let persistedLog: PersistedLog | undefined; @@ -155,13 +154,9 @@ function QueryBarTopRowUI(props: Props) { prepend={props.prepend} query={props.query!} screenTitle={props.screenTitle} - store={props.store!} onChange={onQueryChange} onSubmit={onInputSubmit} persistedLog={persistedLog} - uiSettings={uiSettings!} - savedObjectsClient={savedObjects!.client} - http={http!} /> ); @@ -172,7 +167,7 @@ function QueryBarTopRowUI(props: Props) { } function shouldRenderQueryInput(): boolean { - return Boolean(props.showQueryInput && props.indexPatterns && props.query && props.store); + return Boolean(props.showQueryInput && props.indexPatterns && props.query && store); } function renderUpdateButton() { @@ -247,7 +242,7 @@ function QueryBarTopRowUI(props: Props) { function handleLuceneSyntaxWarning() { if (!props.query) return; - const { intl, store } = props; + const { intl } = props; const { query, language } = props.query; if ( language === 'kuery' && @@ -296,8 +291,8 @@ function QueryBarTopRowUI(props: Props) { } function onLuceneSyntaxWarningOptOut(toast: Toast) { - if (!props.store) return; - props.store.set('kibana.luceneSyntaxWarningOptOut', true); + if (!store) return; + store.set('kibana.luceneSyntaxWarningOptOut', true); notifications!.toasts.remove(toast); } diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx index 7d48977fab8a5..f404962272085 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx @@ -18,14 +18,17 @@ */ import React from 'react'; -import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { SearchBar } from './search_bar'; import { IndexPattern } from '../../../index_patterns'; +import { KibanaContextProvider } from 'src/plugins/kibana_react/public'; +import { I18nProvider } from '@kbn/i18n/react'; + import { coreMock } from '../../../../../../../../src/core/public/mocks'; const startMock = coreMock.createStart(); import { timefilterServiceMock } from '../../../timefilter/timefilter_service.mock'; +import { mount } from 'enzyme'; const timefilterSetupMock = timefilterServiceMock.createSetupContract(); jest.mock('../../../../../data/public', () => { @@ -87,26 +90,44 @@ const kqlQuery = { language: 'kuery', }; -describe('SearchBar', () => { - const SEARCH_BAR_ROOT = '.globalQueryBar'; - const FILTER_BAR = '.filterBar'; - const QUERY_BAR = '.queryBar'; - - const options = { +function wrapSearchBarInContext(testProps: any) { + const defaultOptions = { appName: 'test', - savedObjects: startMock.savedObjects, - notifications: startMock.notifications, timeHistory: timefilterSetupMock.history, intl: null as any, }; + const services = { + uiSettings: startMock.uiSettings, + savedObjects: startMock.savedObjects, + notifications: startMock.notifications, + http: startMock.http, + store: createMockStorage(), + }; + + return ( + + + + + + ); +} + +describe('SearchBar', () => { + const SEARCH_BAR_ROOT = '.globalQueryBar'; + const FILTER_BAR = '.filterBar'; + const QUERY_BAR = '.queryBar'; + beforeEach(() => { jest.clearAllMocks(); }); it('Should render query bar when no options provided (in reality - timepicker)', () => { - const component = mountWithIntl( - + const component = mount( + wrapSearchBarInContext({ + indexPatterns: [mockIndexPattern], + }) ); expect(component.find(SEARCH_BAR_ROOT).length).toBe(1); @@ -115,12 +136,11 @@ describe('SearchBar', () => { }); it('Should render empty when timepicker is off and no options provided', () => { - const component = mountWithIntl( - + const component = mount( + wrapSearchBarInContext({ + indexPatterns: [mockIndexPattern], + showDatePicker: false, + }) ); expect(component.find(SEARCH_BAR_ROOT).length).toBe(1); @@ -129,14 +149,13 @@ describe('SearchBar', () => { }); it('Should render filter bar, when required fields are provided', () => { - const component = mountWithIntl( - + const component = mount( + wrapSearchBarInContext({ + indexPatterns: [mockIndexPattern], + showDatePicker: false, + onFiltersUpdated: noop, + filters: [], + }) ); expect(component.find(SEARCH_BAR_ROOT).length).toBe(1); @@ -145,15 +164,14 @@ describe('SearchBar', () => { }); it('Should NOT render filter bar, if disabled', () => { - const component = mountWithIntl( - + const component = mount( + wrapSearchBarInContext({ + indexPatterns: [mockIndexPattern], + showFilterBar: false, + filters: [], + onFiltersUpdated: noop, + showDatePicker: false, + }) ); expect(component.find(SEARCH_BAR_ROOT).length).toBe(1); @@ -162,15 +180,13 @@ describe('SearchBar', () => { }); it('Should render query bar, when required fields are provided', () => { - const component = mountWithIntl( - + const component = mount( + wrapSearchBarInContext({ + indexPatterns: [mockIndexPattern], + screenTitle: 'test screen', + onQuerySubmit: noop, + query: kqlQuery, + }) ); expect(component.find(SEARCH_BAR_ROOT).length).toBe(1); @@ -179,16 +195,14 @@ describe('SearchBar', () => { }); it('Should NOT render query bar, if disabled', () => { - const component = mountWithIntl( - + const component = mount( + wrapSearchBarInContext({ + indexPatterns: [mockIndexPattern], + screenTitle: 'test screen', + onQuerySubmit: noop, + query: kqlQuery, + showQueryBar: false, + }) ); expect(component.find(SEARCH_BAR_ROOT).length).toBe(1); @@ -197,17 +211,15 @@ describe('SearchBar', () => { }); it('Should render query bar and filter bar', () => { - const component = mountWithIntl( - + const component = mount( + wrapSearchBarInContext({ + indexPatterns: [mockIndexPattern], + screenTitle: 'test screen', + onQuerySubmit: noop, + query: kqlQuery, + filters: [], + onFiltersUpdated: noop, + }) ); expect(component.find(SEARCH_BAR_ROOT).length).toBe(1); diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx index 3f9a68fdc4be3..e9469d7dd4c4f 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx @@ -22,10 +22,8 @@ import { InjectedIntl, injectI18n } from '@kbn/i18n/react'; import classNames from 'classnames'; import React, { Component } from 'react'; import ResizeObserver from 'resize-observer-polyfill'; -import { Storage } from 'ui/storage'; import { get, isEqual } from 'lodash'; -import { CoreStart } from 'src/core/public'; import { TimeRange } from 'src/plugins/data/common/types'; import { IndexPattern, Query, FilterBar } from '../../../../../data/public'; import { QueryBarTopRow } from '../../../query'; @@ -35,10 +33,15 @@ import { SavedQueryManagementComponent } from './saved_query_management/saved_qu import { SavedQueryService } from '../lib/saved_query_service'; import { createSavedQueryService } from '../lib/saved_query_service'; import { TimeHistoryContract } from '../../../timefilter'; +import { + withKibana, + KibanaReactContextValue, +} from '../../../../../../../plugins/kibana_react/public'; +import { IDataPluginServices } from '../../../types'; interface SearchBarInjectedDeps { + kibana: KibanaReactContextValue; intl: InjectedIntl; - store?: Storage; timeHistory: TimeHistoryContract; // Filter bar onFiltersUpdated?: (filters: Filter[]) => void; @@ -50,10 +53,6 @@ interface SearchBarInjectedDeps { onRefreshChange?: (options: { isPaused: boolean; refreshInterval: number }) => void; isRefreshPaused?: boolean; refreshInterval?: number; - - // TODO: deprecate by using context - savedObjects: CoreStart['savedObjects']; - notifications: CoreStart['notifications']; } export interface SearchBarOwnProps { @@ -101,7 +100,7 @@ class SearchBarUI extends Component { }; private savedQueryService!: SavedQueryService; - + private services!: IDataPluginServices; public filterBarRef: Element | null = null; public filterBarWrapperRef: Element | null = null; @@ -252,7 +251,7 @@ class SearchBarUI extends Component { response = await this.savedQueryService.saveQuery(savedQueryAttributes); } - this.props.notifications.toasts.addSuccess( + this.services.notifications.toasts.addSuccess( `Your query "${response.attributes.title}" was saved` ); @@ -265,7 +264,7 @@ class SearchBarUI extends Component { this.props.onSaved(response); } } catch (error) { - this.props.notifications.toasts.addDanger( + this.services.notifications.toasts.addDanger( `An error occured while saving your query: ${error.message}` ); throw error; @@ -336,8 +335,9 @@ class SearchBarUI extends Component { this.setFilterBarHeight(); this.ro.observe(this.filterBarRef); } - if (this.props.savedObjects) { - this.savedQueryService = createSavedQueryService(this.props.savedObjects!.client); + this.services = this.props.kibana.services; + if (this.services.savedObjects) { + this.savedQueryService = createSavedQueryService(this.services.savedObjects.client); } } @@ -371,7 +371,6 @@ class SearchBarUI extends Component { onSubmit={this.onQueryBarSubmit} appName={this.props.appName} indexPatterns={this.props.indexPatterns} - store={this.props.store} prepend={this.props.showFilterBar ? savedQueryManagement : undefined} showDatePicker={this.props.showDatePicker} dateRangeFrom={this.state.dateRangeFrom} @@ -448,4 +447,4 @@ class SearchBarUI extends Component { } } -export const SearchBar = injectI18n(SearchBarUI); +export const SearchBar = injectI18n(withKibana(SearchBarUI)); diff --git a/src/legacy/core_plugins/data/public/types.ts b/src/legacy/core_plugins/data/public/types.ts new file mode 100644 index 0000000000000..314ecafd85f1b --- /dev/null +++ b/src/legacy/core_plugins/data/public/types.ts @@ -0,0 +1,28 @@ +/* + * 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 { UiSettingsClientContract, CoreStart } from 'src/core/public'; + +export interface IDataPluginServices extends Partial { + uiSettings: UiSettingsClientContract; + savedObjects: CoreStart['savedObjects']; + notifications: CoreStart['notifications']; + http: CoreStart['http']; + store: Storage; +} diff --git a/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.test.tsx b/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.test.tsx index 39bf299cd8d12..421a01933ea27 100644 --- a/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.test.tsx +++ b/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.test.tsx @@ -22,12 +22,11 @@ import { TopNavMenu } from './top_nav_menu'; import { TopNavMenuData } from './top_nav_menu_data'; import { shallowWithIntl } from 'test_utils/enzyme_helpers'; -import { coreMock } from '../../../../../core/public/mocks'; -const startMock = coreMock.createStart(); - import { timefilterServiceMock } from '../../../../core_plugins/data/public/timefilter/timefilter_service.mock'; const timefilterSetupMock = timefilterServiceMock.createSetupContract(); +jest.mock('ui/new_platform'); + jest.mock('../../../../core_plugins/data/public', () => { return { SearchBar: () =>
, @@ -76,15 +75,7 @@ describe('TopNavMenu', () => { it('Should render search bar', () => { const component = shallowWithIntl( - + ); expect(component.find(TOP_NAV_ITEM_SELECTOR).length).toBe(0); diff --git a/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.tsx b/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.tsx index c99c71f97e1af..53d3199639714 100644 --- a/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.tsx +++ b/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.tsx @@ -21,27 +21,17 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { I18nProvider } from '@kbn/i18n/react'; -import { UiSettingsClientContract, CoreStart } from 'src/core/public'; +import { Storage } from 'ui/storage'; +import { npStart } from 'ui/new_platform'; import { TopNavMenuData } from './top_nav_menu_data'; import { TopNavMenuItem } from './top_nav_menu_item'; import { KibanaContextProvider } from '../../../../../plugins/kibana_react/public'; -import { - SearchBar, - SearchBarProps, - TimeHistoryContract, -} from '../../../../core_plugins/data/public'; +import { SearchBar, SearchBarProps } from '../../../../core_plugins/data/public'; type Props = Partial & { name: string; config?: TopNavMenuData[]; showSearchBar?: boolean; - - // Search Bar dependencies - uiSettings?: UiSettingsClientContract; - savedObjects?: CoreStart['savedObjects']; - notifications?: CoreStart['notifications']; - timeHistory?: TimeHistoryContract; - http?: CoreStart['http']; }; /* @@ -67,26 +57,18 @@ export function TopNavMenu(props: Props) { function renderSearchBar() { // Validate presense of all required fields - if ( - !props.showSearchBar || - !props.savedObjects || - !props.http || - !props.notifications || - !props.timeHistory - ) - return; + if (!props.showSearchBar || !props.timeHistory) return; return ( { child.setAttribute('disabled-buttons', 'disabledButtons'); // Pass in storage - const localStorage = new Storage(window.localStorage); - child.setAttribute('http', 'http'); - child.setAttribute('store', 'store'); child.setAttribute('time-history', 'timeHistory'); - child.setAttribute('ui-settings', 'uiSettings'); - child.setAttribute('saved-objects', 'savedObjects'); - child.setAttribute('notifications', 'notifications'); // Append helper directive elem.append(child); const linkFn = ($scope, _, $attr) => { - $scope.store = localStorage; - $scope.http = npStart.core.http; - $scope.uiSettings = npStart.core.uiSettings; - $scope.savedObjects = npStart.core.savedObjects; - $scope.notifications = npStart.core.notifications; $scope.timeHistory = data.timefilter.history; // Watch config changes @@ -101,14 +88,8 @@ module.directive('kbnTopNavHelper', (reactDirective) => { ['query', { watchDepth: 'reference' }], ['savedQuery', { watchDepth: 'reference' }], - ['store', { watchDepth: 'reference' }], - ['uiSettings', { watchDepth: 'reference' }], - ['savedObjects', { watchDepth: 'reference' }], - ['notifications', { watchDepth: 'reference' }], ['intl', { watchDepth: 'reference' }], ['timeHistory', { watchDepth: 'reference' }], - ['store', { watchDepth: 'reference' }], - ['http', { watchDepth: 'reference' }], ['onQuerySubmit', { watchDepth: 'reference' }], ['onFiltersUpdated', { watchDepth: 'reference' }], From 41dd2ef5abb79f4e577a1fbfb43e6e0ca3f7ceb9 Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 26 Sep 2019 13:56:09 +0300 Subject: [PATCH 03/32] Pass NP data plugin to shim plugin, to access autocomplete Pass storage and autocomplete to createSearchBar method Add appName and autocomplete to IDataPluginServices QueryBarInput to consume autocomplete and appName from context QueryBarTopRow to consume appName from context Remove appName from SearchBar Added AutocompletePublicPluginSetup and AutocompletePublicPluginStart types --- src/legacy/core_plugins/data/public/legacy.ts | 2 +- src/legacy/core_plugins/data/public/plugin.ts | 10 ++++++-- .../query_bar/components/query_bar_input.tsx | 13 +++-------- .../components/query_bar_top_row.tsx | 10 ++++---- .../search_bar/components/bind_search_bar.tsx | 23 +++++++++++++------ .../search_bar/components/search_bar.tsx | 2 -- src/legacy/core_plugins/data/public/types.ts | 3 +++ .../public/autocomplete_provider/types.ts | 7 ++++++ src/plugins/data/public/index.ts | 3 ++- src/plugins/data/public/plugin.ts | 9 +------- src/plugins/data/public/types.ts | 9 ++++++++ 11 files changed, 54 insertions(+), 37 deletions(-) diff --git a/src/legacy/core_plugins/data/public/legacy.ts b/src/legacy/core_plugins/data/public/legacy.ts index 9c9fa7b9d198b..4e311b401c544 100644 --- a/src/legacy/core_plugins/data/public/legacy.ts +++ b/src/legacy/core_plugins/data/public/legacy.ts @@ -45,6 +45,6 @@ export const setup = dataPlugin.setup(npSetup.core, { __LEGACY: legacyPlugin.setup(), }); -export const start = dataPlugin.start(npStart.core, { +export const start = dataPlugin.start(npStart.core, npStart.plugins.data, { __LEGACY: legacyPlugin.start(), }); diff --git a/src/legacy/core_plugins/data/public/plugin.ts b/src/legacy/core_plugins/data/public/plugin.ts index 78983245d1000..62af2de3c7571 100644 --- a/src/legacy/core_plugins/data/public/plugin.ts +++ b/src/legacy/core_plugins/data/public/plugin.ts @@ -27,6 +27,7 @@ import { LegacyDependenciesPluginSetup, LegacyDependenciesPluginStart, } from './shim/legacy_dependencies_plugin'; +import { DataPublicPluginStart } from '../../../../plugins/data/public'; /** * Interface for any dependencies on other plugins' `setup` contracts. @@ -103,12 +104,17 @@ export class DataPlugin implements Plugin - npStart.plugins.data.autocomplete.getProvider(language); - interface Props { kibana: KibanaReactContextValue; intl: InjectedIntl; indexPatterns: Array; query: Query; - appName: string; disableAutoFocus?: boolean; screenTitle?: string; prepend?: React.ReactNode; @@ -141,7 +134,7 @@ export class QueryBarInputUI extends Component { const recentSearchSuggestions = this.getRecentSearchSuggestions(queryString); - const autocompleteProvider = getAutocompleteProvider(language); + const autocompleteProvider = this.services.autocomplete.getProvider(language); if ( !autocompleteProvider || !Array.isArray(this.state.indexPatterns) || @@ -406,7 +399,7 @@ export class QueryBarInputUI extends Component { this.persistedLog = this.props.persistedLog ? this.props.persistedLog - : getQueryLog(this.services.uiSettings, this.props.appName, this.props.query.language); + : getQueryLog(this.services.uiSettings, this.services.appName, this.props.query.language); this.fetchIndexPatterns().then(this.updateSuggestions); } @@ -419,7 +412,7 @@ export class QueryBarInputUI extends Component { this.persistedLog = this.props.persistedLog ? this.props.persistedLog - : getQueryLog(this.services.uiSettings, this.props.appName, this.props.query.language); + : getQueryLog(this.services.uiSettings, this.services.appName, this.props.query.language); if (!isEqual(prevProps.indexPatterns, this.props.indexPatterns)) { this.fetchIndexPatterns().then(this.updateSuggestions); diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.tsx index 45708639e03a4..6895c9ecd018c 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.tsx @@ -21,7 +21,6 @@ import { doesKueryExpressionHaveLuceneSyntaxError } from '@kbn/es-query'; import classNames from 'classnames'; import React, { useState, useEffect } from 'react'; -import { Storage } from 'ui/storage'; import { documentationLinks } from 'ui/documentation_links'; import { PersistedLog } from 'ui/persisted_log'; @@ -38,13 +37,13 @@ import { QueryBarInput } from './query_bar_input'; import { getQueryLog } from '../lib/get_query_log'; import { Query } from '../index'; import { TimeHistoryContract } from '../../../timefilter'; +import { IDataPluginServices } from '../../../types'; interface Props { query?: Query; onSubmit: (payload: { dateRange: TimeRange; query?: Query }) => void; onChange: (payload: { dateRange: TimeRange; query?: Query }) => void; disableAutoFocus?: boolean; - appName: string; screenTitle?: string; indexPatterns?: Array; intl: InjectedIntl; @@ -65,15 +64,15 @@ interface Props { function QueryBarTopRowUI(props: Props) { const [isDateRangeInvalid, setIsDateRangeInvalid] = useState(false); - const kibana = useKibana<{ store: Storage }>(); - const { uiSettings, notifications, store } = kibana.services; + const kibana = useKibana(); + const { uiSettings, notifications, store, appName } = kibana.services; const queryLanguage = props.query && props.query.language; let persistedLog: PersistedLog | undefined; useEffect(() => { if (!props.query) return; - persistedLog = getQueryLog(uiSettings!, props.appName, props.query.language); + persistedLog = getQueryLog(uiSettings!, appName, props.query.language); }, [queryLanguage]); function onClickSubmitButton(event: React.MouseEvent) { @@ -148,7 +147,6 @@ function QueryBarTopRowUI(props: Props) { return ( { @@ -50,19 +52,26 @@ const defaultOnRefreshChange = (timefilter: TimefilterSetup) => { export function createSearchBar({ core, - storage, + store, timefilter, filterManager, + autocomplete, }: StatefulSearchBarDeps) { const timeRange = timefilter.timefilter.getTime(); const refreshInterval = timefilter.timefilter.getRefreshInterval(); - return (props: SearchBarOwnProps) => ( - + // App name should come from the core application service. + // Until it's available, we'll ask the user to provide it for the pre-wired component. + return (props: SearchBarOwnProps & { appName: string }) => ( + { query={this.state.query} screenTitle={this.props.screenTitle} onSubmit={this.onQueryBarSubmit} - appName={this.props.appName} indexPatterns={this.props.indexPatterns} prepend={this.props.showFilterBar ? savedQueryManagement : undefined} showDatePicker={this.props.showDatePicker} diff --git a/src/legacy/core_plugins/data/public/types.ts b/src/legacy/core_plugins/data/public/types.ts index 314ecafd85f1b..4b7a5c1402ea7 100644 --- a/src/legacy/core_plugins/data/public/types.ts +++ b/src/legacy/core_plugins/data/public/types.ts @@ -18,11 +18,14 @@ */ import { UiSettingsClientContract, CoreStart } from 'src/core/public'; +import { AutocompletePublicPluginStart } from 'src/plugins/data/public'; export interface IDataPluginServices extends Partial { + appName: string; uiSettings: UiSettingsClientContract; savedObjects: CoreStart['savedObjects']; notifications: CoreStart['notifications']; http: CoreStart['http']; store: Storage; + autocomplete: AutocompletePublicPluginStart; } diff --git a/src/plugins/data/public/autocomplete_provider/types.ts b/src/plugins/data/public/autocomplete_provider/types.ts index f168533679ecd..4b1c5dfbd3528 100644 --- a/src/plugins/data/public/autocomplete_provider/types.ts +++ b/src/plugins/data/public/autocomplete_provider/types.ts @@ -18,6 +18,13 @@ */ import { StaticIndexPattern } from 'ui/index_patterns'; +import { AutocompleteProviderRegister } from '.'; + +export type AutocompletePublicPluginSetup = Pick< + AutocompleteProviderRegister, + 'addProvider' | 'getProvider' +>; +export type AutocompletePublicPluginStart = Pick; /** @public **/ export type AutocompleteProvider = (args: { diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 0580c41113ceb..7696b4a85426e 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -18,13 +18,14 @@ */ import { PluginInitializerContext } from '../../../core/public'; -import { DataPublicPlugin } from './plugin'; +import { DataPublicPlugin, DataPublicPluginSetup, DataPublicPluginStart } from './plugin'; export function plugin(initializerContext: PluginInitializerContext) { return new DataPublicPlugin(initializerContext); } export { DataPublicPlugin as Plugin }; +export { DataPublicPluginSetup, DataPublicPluginStart }; export * from '../common'; diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index d1670ccb645db..eb31647767360 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -19,14 +19,7 @@ import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../../core/public'; import { AutocompleteProviderRegister } from './autocomplete_provider'; - -export interface DataPublicPluginSetup { - autocomplete: Pick; -} - -export interface DataPublicPluginStart { - autocomplete: Pick; -} +import { DataPublicPluginSetup, DataPublicPluginStart } from './types'; export class DataPublicPlugin implements Plugin { private readonly autocomplete = new AutocompleteProviderRegister(); diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index 370b8d3ff5ea2..857cf1ba3219c 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -19,3 +19,12 @@ export * from '../common/types'; export * from './autocomplete_provider/types'; + +import { AutocompletePublicPluginSetup, AutocompletePublicPluginStart } from '.'; +export interface DataPublicPluginSetup { + autocomplete: AutocompletePublicPluginSetup; +} + +export interface DataPublicPluginStart { + autocomplete: AutocompletePublicPluginStart; +} From c4525e966d330ff07a03e84586ed5423aa3735d2 Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 26 Sep 2019 14:08:12 +0300 Subject: [PATCH 04/32] Use KibanaContextProvider in vis editor and graph --- .../vis/editors/default/controls/filter.tsx | 33 ++++++++++-------- .../graph/public/angular/templates/index.html | 4 --- x-pack/legacy/plugins/graph/public/app.js | 8 +---- .../plugins/graph/public/components/app.tsx | 34 +++++++++++++------ .../graph/public/components/search_bar.tsx | 29 ++++++++-------- 5 files changed, 58 insertions(+), 50 deletions(-) diff --git a/src/legacy/ui/public/vis/editors/default/controls/filter.tsx b/src/legacy/ui/public/vis/editors/default/controls/filter.tsx index f81734f537426..c0e100b3d1c05 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/filter.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/filter.tsx @@ -24,6 +24,7 @@ import { Query, QueryBarInput } from 'plugins/data'; import { AggConfig } from '../../..'; import { npStart } from '../../../../new_platform'; import { Storage } from '../../../../storage'; +import { KibanaContextProvider } from '../../../../../../../plugins/kibana_react/public'; const localStorage = new Storage(window.localStorage); interface FilterRowProps { @@ -89,20 +90,24 @@ function FilterRow({ labelAppend={FilterControl} fullWidth={true} > - onChangeValue(id, query, customLabel)} - disableAutoFocus={!autoFocus} - data-test-subj={dataTestSubj} - bubbleSubmitEvent={true} - languageSwitcherPopoverAnchorPosition="leftDown" - store={localStorage} - uiSettings={npStart.core.uiSettings} - http={npStart.core.http} - savedObjectsClient={npStart.core.savedObjects.client} - /> + + onChangeValue(id, query, customLabel)} + disableAutoFocus={!autoFocus} + data-test-subj={dataTestSubj} + bubbleSubmitEvent={true} + languageSwitcherPopoverAnchorPosition="leftDown" + /> + {showCustomLabel ? ( { diff --git a/x-pack/legacy/plugins/graph/public/components/app.tsx b/x-pack/legacy/plugins/graph/public/components/app.tsx index 7e75a13bb39e3..48812e1d89a6a 100644 --- a/x-pack/legacy/plugins/graph/public/components/app.tsx +++ b/x-pack/legacy/plugins/graph/public/components/app.tsx @@ -6,22 +6,36 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React from 'react'; +import { Storage } from 'ui/storage'; +import { npStart } from 'ui/new_platform'; import { FieldManagerProps, FieldManager } from './field_manager'; import { SearchBarProps, SearchBar } from './search_bar'; +import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; +const localStorage = new Storage(window.localStorage); + export interface GraphAppProps extends FieldManagerProps, SearchBarProps {} export function GraphApp(props: GraphAppProps) { return ( -
- - - - - - - - -
+ +
+ + + + + + + + +
+
); } diff --git a/x-pack/legacy/plugins/graph/public/components/search_bar.tsx b/x-pack/legacy/plugins/graph/public/components/search_bar.tsx index 358d7d23d9ed4..651c4294ca438 100644 --- a/x-pack/legacy/plugins/graph/public/components/search_bar.tsx +++ b/x-pack/legacy/plugins/graph/public/components/search_bar.tsx @@ -7,11 +7,11 @@ import { EuiFlexGroup, EuiFlexItem, EuiButton, EuiButtonEmpty, EuiToolTip } from '@elastic/eui'; import React, { useState } from 'react'; -import { Storage } from 'ui/storage'; import { CoreStart } from 'src/core/public'; import { i18n } from '@kbn/i18n'; import { I18nProvider } from '@kbn/i18n/react'; import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; +import { IDataPluginServices } from 'src/legacy/core_plugins/data/public/types'; import { QueryBarInput, Query, @@ -19,8 +19,7 @@ import { } from '../../../../../../src/legacy/core_plugins/data/public'; import { IndexPatternSavedObject } from '../types/app_state'; import { openSourceModal } from '../services/source_modal'; - -const localStorage = new Storage(window.localStorage); +import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; export interface SearchBarProps { isLoading: boolean; @@ -28,9 +27,6 @@ export interface SearchBarProps { initialQuery?: string; onIndexPatternSelected: (indexPattern: IndexPatternSavedObject) => void; onQuerySubmit: (query: string) => void; - savedObjects: CoreStart['savedObjects']; - uiSettings: CoreStart['uiSettings']; - http: CoreStart['http']; overlays: CoreStart['overlays']; } @@ -56,12 +52,13 @@ export function SearchBar(props: SearchBarProps) { onQuerySubmit, isLoading, onIndexPatternSelected, - uiSettings, - savedObjects, - http, initialQuery, } = props; const [query, setQuery] = useState({ language: 'kuery', query: initialQuery || '' }); + const kibana = useKibana(); + const { overlays, uiSettings, savedObjects } = kibana.services; + if (!overlays) return; + return (
{ - openSourceModal(props, onIndexPatternSelected); + openSourceModal( + { + overlays, + savedObjects, + uiSettings, + }, + onIndexPatternSelected + ); }} > {currentIndexPattern From 995bfeb5f0cd0d7bbc32c3b5de42f4ce01c7f0f5 Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 26 Sep 2019 14:11:38 +0300 Subject: [PATCH 05/32] Use KibanaContextProvider in maps --- .../filter_editor/filter_editor.js | 52 +++----- .../join_editor/resources/where_expression.js | 48 +++---- .../connected_components/layer_panel/view.js | 126 ++++++++++-------- 3 files changed, 110 insertions(+), 116 deletions(-) diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js index 53ba039b4ea8b..f736f87dc46e1 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/filter_editor/filter_editor.js @@ -21,14 +21,11 @@ import { import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; import { indexPatternService } from '../../../kibana_services'; -import { Storage } from 'ui/storage'; import { start as data } from '../../../../../../../../src/legacy/core_plugins/data/public/legacy'; const { SearchBar } = data.ui; import { npStart } from 'ui/new_platform'; -import { KibanaContextProvider } from '../../../../../../../../src/plugins/kibana_react/public'; -const localStorage = new Storage(window.localStorage); export class FilterEditor extends Component { state = { @@ -94,35 +91,26 @@ export class FilterEditor extends Component { anchorPosition="leftCenter" >
- - - - - } - /> - + + + + } + />
); diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/where_expression.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/where_expression.js index c8852cf74e28b..fb09ed342b8d3 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/where_expression.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/join_editor/resources/where_expression.js @@ -15,10 +15,7 @@ import { import { FormattedMessage } from '@kbn/i18n/react'; import { SearchBar } from 'plugins/data'; import { npStart } from 'ui/new_platform'; -import { KibanaContextProvider } from '../../../../../../../../../src/plugins/kibana_react/public'; -import { Storage } from 'ui/storage'; -const localStorage = new Storage(window.localStorage); export class WhereExpression extends Component { state = { @@ -79,32 +76,25 @@ export class WhereExpression extends Component { defaultMessage="Use a query to narrow right source." /> - - - - - - } - /> - + + + + } + /> ); diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.js b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.js index f7e242a82b89d..9efbfe45da29c 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.js +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/view.js @@ -29,6 +29,13 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import { KibanaContextProvider } from '../../../../../../../src/plugins/kibana_react/public'; + +import { Storage } from 'ui/storage'; +const localStorage = new Storage(window.localStorage); + +// This import will eventually become a dependency injected by the fully deangularized NP plugin. +import { npStart } from 'ui/new_platform'; export class LayerPanel extends React.Component { @@ -144,75 +151,84 @@ export class LayerPanel extends React.Component { } return ( - - - - - + + + + + + + + + + +

{this.state.displayName}

+
+
+
+ +
+ - - - - - - -

{this.state.displayName}

-
-
- - -
- - - - {this._renderSourceProperties()} - - -
- + + + {this._renderSourceProperties()} + +
+
+
-
-
+
+
- + - + - + - {this._renderFilterSection()} + {this._renderFilterSection()} - {this._renderJoinSection()} + {this._renderJoinSection()} - + +
-
- - - - + + + + + ); } } From 1d09108cbc83e4ba7ec5b778a82e8c6008570ced Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 26 Sep 2019 14:30:51 +0300 Subject: [PATCH 06/32] Use prewirted SearchBar in TopNavMenu --- .../public/top_nav_menu/top_nav_menu.tsx | 55 ++++--------------- 1 file changed, 10 insertions(+), 45 deletions(-) diff --git a/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.tsx b/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.tsx index 53d3199639714..b16ef352784aa 100644 --- a/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.tsx +++ b/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.tsx @@ -21,15 +21,15 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { I18nProvider } from '@kbn/i18n/react'; -import { Storage } from 'ui/storage'; -import { npStart } from 'ui/new_platform'; +import { start as data } from '../../../data/public/legacy'; import { TopNavMenuData } from './top_nav_menu_data'; import { TopNavMenuItem } from './top_nav_menu_item'; -import { KibanaContextProvider } from '../../../../../plugins/kibana_react/public'; -import { SearchBar, SearchBarProps } from '../../../../core_plugins/data/public'; +import { SearchBarProps } from '../../../../core_plugins/data/public'; + +const { SearchBar } = data.ui; type Props = Partial & { - name: string; + appName: string; config?: TopNavMenuData[]; showSearchBar?: boolean; }; @@ -44,9 +44,10 @@ type Props = Partial & { **/ export function TopNavMenu(props: Props) { + const { config, showSearchBar, ...searchBarProps } = props; function renderItems() { - if (!props.config) return; - return props.config.map((menuItem: TopNavMenuData, i: number) => { + if (!config) return; + return config.map((menuItem: TopNavMenuData, i: number) => { return ( @@ -57,44 +58,8 @@ export function TopNavMenu(props: Props) { function renderSearchBar() { // Validate presense of all required fields - if (!props.showSearchBar || !props.timeHistory) return; - return ( - - - - ); + if (!showSearchBar) return; + return ; } function renderLayout() { From 08fed2f6c3a9580a0de32cddfc63634566f533b8 Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 26 Sep 2019 16:33:29 +0300 Subject: [PATCH 07/32] Use KibanaContextProbider in Lens --- src/legacy/core_plugins/data/public/legacy.ts | 3 ++- src/legacy/core_plugins/data/public/plugin.ts | 25 ++++++++++++++----- .../ui/public/kbn_top_nav/kbn_top_nav.js | 7 ------ .../vis/editors/default/controls/filter.tsx | 2 +- .../plugins/graph/public/components/app.tsx | 2 +- .../graph/public/components/search_bar.tsx | 1 - .../plugins/lens/public/app_plugin/app.tsx | 13 +++++----- .../plugins/lens/public/app_plugin/plugin.tsx | 9 +++++-- .../operations/definitions/filter_ratio.tsx | 23 +---------------- 9 files changed, 38 insertions(+), 47 deletions(-) diff --git a/src/legacy/core_plugins/data/public/legacy.ts b/src/legacy/core_plugins/data/public/legacy.ts index 4e311b401c544..80104fc1991b0 100644 --- a/src/legacy/core_plugins/data/public/legacy.ts +++ b/src/legacy/core_plugins/data/public/legacy.ts @@ -45,6 +45,7 @@ export const setup = dataPlugin.setup(npSetup.core, { __LEGACY: legacyPlugin.setup(), }); -export const start = dataPlugin.start(npStart.core, npStart.plugins.data, { +export const start = dataPlugin.start(npStart.core, { + data: npStart.plugins.data, __LEGACY: legacyPlugin.start(), }); diff --git a/src/legacy/core_plugins/data/public/plugin.ts b/src/legacy/core_plugins/data/public/plugin.ts index 62af2de3c7571..36544ae1902b8 100644 --- a/src/legacy/core_plugins/data/public/plugin.ts +++ b/src/legacy/core_plugins/data/public/plugin.ts @@ -39,6 +39,7 @@ export interface DataPluginSetupDependencies { } export interface DataPluginStartDependencies { + data: DataPublicPluginStart; __LEGACY: LegacyDependenciesPluginStart; } @@ -55,6 +56,20 @@ export interface DataSetup { timefilter: TimefilterSetup; } +/** + * Interface for this plugin's returned `start` contract. + * + * @public + */ +export interface DataStart { + indexPatterns: IndexPatternsSetup; + filter: FilterSetup; + query: QuerySetup; + search: SearchSetup; + timefilter: TimefilterSetup; + ui: any; +} + /** * Data Plugin - public * @@ -66,7 +81,9 @@ export interface DataSetup { * in the setup/start interfaces. The remaining items exported here are either types, * or static code. */ -export class DataPlugin implements Plugin { +export class DataPlugin + implements + Plugin { // Exposed services, sorted alphabetically private readonly filter: FilterService = new FilterService(); private readonly indexPatterns: IndexPatternsService = new IndexPatternsService(); @@ -104,11 +121,7 @@ export class DataPlugin implements Plugin { // of the config array's disableButton function return value changes. child.setAttribute('disabled-buttons', 'disabledButtons'); - // Pass in storage - child.setAttribute('time-history', 'timeHistory'); - // Append helper directive elem.append(child); const linkFn = ($scope, _, $attr) => { - $scope.timeHistory = data.timefilter.history; // Watch config changes $scope.$watch(() => { @@ -82,14 +77,12 @@ module.directive('kbnTopNavHelper', (reactDirective) => { return reactDirective( wrapInI18nContext(TopNavMenu), [ - ['name', { watchDepth: 'reference' }], ['config', { watchDepth: 'value' }], ['disabledButtons', { watchDepth: 'reference' }], ['query', { watchDepth: 'reference' }], ['savedQuery', { watchDepth: 'reference' }], ['intl', { watchDepth: 'reference' }], - ['timeHistory', { watchDepth: 'reference' }], ['onQuerySubmit', { watchDepth: 'reference' }], ['onFiltersUpdated', { watchDepth: 'reference' }], diff --git a/src/legacy/ui/public/vis/editors/default/controls/filter.tsx b/src/legacy/ui/public/vis/editors/default/controls/filter.tsx index c0e100b3d1c05..29c26500be694 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/filter.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/filter.tsx @@ -94,7 +94,7 @@ function FilterRow({ services={{ appName: 'filtersAgg', store: localStorage, - autcomplete: npStart.plugins.data.autocomplete, + autocomplete: npStart.plugins.data.autocomplete, ...npStart.core, }} > diff --git a/x-pack/legacy/plugins/graph/public/components/app.tsx b/x-pack/legacy/plugins/graph/public/components/app.tsx index 48812e1d89a6a..3d8ec17228930 100644 --- a/x-pack/legacy/plugins/graph/public/components/app.tsx +++ b/x-pack/legacy/plugins/graph/public/components/app.tsx @@ -22,7 +22,7 @@ export function GraphApp(props: GraphAppProps) { services={{ appName: 'graph', store: localStorage, - autcomplete: npStart.plugins.data.autocomplete, + autocomplete: npStart.plugins.data.autocomplete, ...npStart.core, }} > diff --git a/x-pack/legacy/plugins/graph/public/components/search_bar.tsx b/x-pack/legacy/plugins/graph/public/components/search_bar.tsx index 651c4294ca438..c1c0e56dac6a1 100644 --- a/x-pack/legacy/plugins/graph/public/components/search_bar.tsx +++ b/x-pack/legacy/plugins/graph/public/components/search_bar.tsx @@ -27,7 +27,6 @@ export interface SearchBarProps { initialQuery?: string; onIndexPatternSelected: (indexPattern: IndexPatternSavedObject) => void; onQuerySubmit: (query: string) => void; - overlays: CoreStart['overlays']; } function queryToString(query: Query, indexPattern: IndexPattern) { diff --git a/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx b/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx index 3e157fc394d30..9c484e19789e9 100644 --- a/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx +++ b/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx @@ -11,6 +11,7 @@ import { i18n } from '@kbn/i18n'; import { EuiLink, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { Storage } from 'ui/storage'; import { CoreStart } from 'src/core/public'; +import { DataPublicPluginStart } from 'src/plugins/data/public'; import { Query } from '../../../../../../src/legacy/core_plugins/data/public'; import { QueryBarTopRow } from '../../../../../../src/legacy/core_plugins/data/public/query/query_bar'; import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; @@ -51,6 +52,7 @@ function isLocalStateDirty( export function App({ editorFrame, + data, core, store, docId, @@ -58,6 +60,7 @@ export function App({ redirectTo, }: { editorFrame: EditorFrameInstance; + data: DataPublicPluginStart; core: CoreStart; store: Storage; docId?: string; @@ -156,10 +159,10 @@ export function App({
@@ -224,9 +227,7 @@ export function App({ setState({ ...state, localQueryBarState }); }} isDirty={isLocalStateDirty(state.localQueryBarState, state.query, state.dateRange)} - appName={'lens'} indexPatterns={state.indexPatternTitles} - store={store} showDatePicker={true} showQueryInput={true} query={state.localQueryBarState.query} diff --git a/x-pack/legacy/plugins/lens/public/app_plugin/plugin.tsx b/x-pack/legacy/plugins/lens/public/app_plugin/plugin.tsx index 9504e0b6e1752..5e81785132616 100644 --- a/x-pack/legacy/plugins/lens/public/app_plugin/plugin.tsx +++ b/x-pack/legacy/plugins/lens/public/app_plugin/plugin.tsx @@ -11,6 +11,7 @@ import chrome from 'ui/chrome'; import { Storage } from 'ui/storage'; import { CoreSetup, CoreStart } from 'src/core/public'; import { npSetup, npStart } from 'ui/new_platform'; +import { DataPublicPluginStart } from 'src/plugins/data/public'; import { editorFrameSetup, editorFrameStart, editorFrameStop } from '../editor_frame_plugin'; import { indexPatternDatasourceSetup, indexPatternDatasourceStop } from '../indexpattern_plugin'; import { SavedObjectIndexStore } from '../persistence'; @@ -23,6 +24,9 @@ import { import { App } from './app'; import { EditorFrameInstance } from '../types'; +export interface LensPluginStartDependencies { + data: DataPublicPluginStart; +} export class AppPlugin { private instance: EditorFrameInstance | null = null; private store: SavedObjectIndexStore | null = null; @@ -45,7 +49,7 @@ export class AppPlugin { editorFrameSetupInterface.registerVisualization(metricVisualization); } - start(core: CoreStart) { + start(core: CoreStart, { data }: LensPluginStartDependencies) { if (this.store === null) { throw new Error('Start lifecycle called before setup lifecycle'); } @@ -60,6 +64,7 @@ export class AppPlugin { return ( app.setup(npSetup.core); -export const appStart = () => app.start(npStart.core); +export const appStart = () => app.start(npStart.core, { data: npStart.plugins.data }); export const appStop = () => app.stop(); diff --git a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/filter_ratio.tsx b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/filter_ratio.tsx index 32da61a95beb8..63c6398e93997 100644 --- a/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/filter_ratio.tsx +++ b/x-pack/legacy/plugins/lens/public/indexpattern_plugin/operations/definitions/filter_ratio.tsx @@ -80,16 +80,7 @@ export const filterRatioOperation: OperationDefinition { + paramEditor: ({ state, setState, currentColumn, layerId }) => { const [hasDenominator, setDenominator] = useState( !isEqual(currentColumn.params.denominator, initialQuery) ); @@ -102,14 +93,8 @@ export const filterRatioOperation: OperationDefinition { setState( updateColumnParam({ @@ -168,14 +153,8 @@ export const filterRatioOperation: OperationDefinition {hasDenominator ? ( { setState( updateColumnParam({ From b4ce1f22b71e46635d0e6d59e13f3d2276968e0e Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 26 Sep 2019 16:36:11 +0300 Subject: [PATCH 08/32] Fix appName usage in query bar input --- .../public/query/query_bar/components/query_bar_input.test.tsx | 2 +- .../data/public/query/query_bar/components/query_bar_input.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.tsx index e0bb8677e32cc..fdf9988fb5444 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.test.tsx @@ -82,12 +82,12 @@ const mockIndexPattern = { function wrapQueryBarInputInContext(testProps: any, store?: any) { const defaultOptions = { - appName: 'test', screenTitle: 'Another Screen', intl: null as any, }; const services = { + appName: 'test', uiSettings: startMock.uiSettings, savedObjects: startMock.savedObjects, notifications: startMock.notifications, diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx index 3a598ee75ab6d..af7949ce6fdd2 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx @@ -499,7 +499,7 @@ export class QueryBarInputUI extends Component { }, { previouslyTranslatedPageTitle: this.props.screenTitle, - pageType: this.props.appName, + pageType: this.services.appName, } ) : undefined From 7e2740c9d2e7728afe98aa26c17f4169721896f1 Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 26 Sep 2019 16:38:27 +0300 Subject: [PATCH 09/32] fixed query bar top row appName --- .../query/query_bar/components/query_bar_top_row.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.tsx index 5ed28ec409b25..d77c248a7552d 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.tsx @@ -99,7 +99,6 @@ const mockIndexPattern = { function wrapQueryBarTopRowInContext(testProps: any) { const defaultOptions = { - appName: 'discover', screenTitle: 'Another Screen', onSubmit: noop, onChange: noop, @@ -107,6 +106,7 @@ function wrapQueryBarTopRowInContext(testProps: any) { }; const services = { + appName: 'discover', uiSettings: startMock.uiSettings, savedObjects: startMock.savedObjects, notifications: startMock.notifications, From 35d365edafed0a2e2c5c39e7322607939fd65b15 Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 26 Sep 2019 17:12:40 +0300 Subject: [PATCH 10/32] update tests --- .../__snapshots__/query_bar_input.test.tsx.snap | 15 ++++++--------- .../query_bar/components/query_bar_input.test.tsx | 2 +- .../query_bar/components/query_bar_input.tsx | 4 +++- .../search/search_bar/components/search_bar.tsx | 2 +- .../public/top_nav_menu/top_nav_menu.test.tsx | 8 ++++---- .../public/top_nav_menu/top_nav_menu.tsx | 3 +-- 6 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/__snapshots__/query_bar_input.test.tsx.snap b/src/legacy/core_plugins/data/public/query/query_bar/components/__snapshots__/query_bar_input.test.tsx.snap index 9d97c3aca4e1e..da756275a83e9 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/__snapshots__/query_bar_input.test.tsx.snap +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/__snapshots__/query_bar_input.test.tsx.snap @@ -90,6 +90,7 @@ exports[`QueryBarInput Should disable autoFocus on EuiFieldText when disableAuto { this.setState({ index }); }; - public componentDidMount() { + public componentWillMount() { this.services = this.props.kibana.services; + } + public componentDidMount() { const parsedQuery = fromUser(toUser(this.props.query.query)); if (!isEqual(this.props.query.query, parsedQuery)) { this.onChange({ ...this.props.query, query: parsedQuery }); diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx index 94a40dd5296d8..3bbde007629ed 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx @@ -330,11 +330,11 @@ class SearchBarUI extends Component { }; public componentDidMount() { + this.services = this.props.kibana.services; if (this.filterBarRef) { this.setFilterBarHeight(); this.ro.observe(this.filterBarRef); } - this.services = this.props.kibana.services; if (this.services.savedObjects) { this.savedQueryService = createSavedQueryService(this.services.savedObjects.client); } diff --git a/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.test.tsx b/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.test.tsx index 421a01933ea27..8dbfda53b17cc 100644 --- a/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.test.tsx +++ b/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.test.tsx @@ -56,26 +56,26 @@ describe('TopNavMenu', () => { ]; it('Should render nothing when no config is provided', () => { - const component = shallowWithIntl(); + const component = shallowWithIntl(); expect(component.find(TOP_NAV_ITEM_SELECTOR).length).toBe(0); expect(component.find(SEARCH_BAR_SELECTOR).length).toBe(0); }); it('Should render 1 menu item', () => { - const component = shallowWithIntl(); + const component = shallowWithIntl(); expect(component.find(TOP_NAV_ITEM_SELECTOR).length).toBe(1); expect(component.find(SEARCH_BAR_SELECTOR).length).toBe(0); }); it('Should render multiple menu items', () => { - const component = shallowWithIntl(); + const component = shallowWithIntl(); expect(component.find(TOP_NAV_ITEM_SELECTOR).length).toBe(menuItems.length); expect(component.find(SEARCH_BAR_SELECTOR).length).toBe(0); }); it('Should render search bar', () => { const component = shallowWithIntl( - + ); expect(component.find(TOP_NAV_ITEM_SELECTOR).length).toBe(0); diff --git a/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.tsx b/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.tsx index b16ef352784aa..abe17a32116cb 100644 --- a/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.tsx +++ b/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.tsx @@ -26,8 +26,6 @@ import { TopNavMenuData } from './top_nav_menu_data'; import { TopNavMenuItem } from './top_nav_menu_item'; import { SearchBarProps } from '../../../../core_plugins/data/public'; -const { SearchBar } = data.ui; - type Props = Partial & { appName: string; config?: TopNavMenuData[]; @@ -44,6 +42,7 @@ type Props = Partial & { **/ export function TopNavMenu(props: Props) { + const { SearchBar } = data.ui; const { config, showSearchBar, ...searchBarProps } = props; function renderItems() { if (!config) return; From 4dd148dcc4bcae8d2d05e1ec2b44b50d9b0ce364 Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 26 Sep 2019 17:39:17 +0300 Subject: [PATCH 11/32] fixed bind search bar bug --- .../search_bar/components/bind_search_bar.tsx | 52 ++++++++++--------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/bind_search_bar.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/bind_search_bar.tsx index a77a6ad25d34f..fa0b2dbac462b 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/bind_search_bar.tsx +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/bind_search_bar.tsx @@ -57,31 +57,33 @@ export function createSearchBar({ filterManager, autocomplete, }: StatefulSearchBarDeps) { - const timeRange = timefilter.timefilter.getTime(); - const refreshInterval = timefilter.timefilter.getRefreshInterval(); - // App name should come from the core application service. // Until it's available, we'll ask the user to provide it for the pre-wired component. - return (props: SearchBarOwnProps & { appName: string }) => ( - - - - ); + return (props: SearchBarOwnProps & { appName: string }) => { + const timeRange = timefilter.timefilter.getTime(); + const refreshInterval = timefilter.timefilter.getRefreshInterval(); + + return ( + + + + ); + }; } From 49135485e5a5b1f8efa0dd3ba5004254513ff05c Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 26 Sep 2019 17:49:16 +0300 Subject: [PATCH 12/32] mock SearchBar --- .../public/top_nav_menu/top_nav_menu.test.tsx | 9 +++++++++ .../kibana_react/public/top_nav_menu/top_nav_menu.tsx | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.test.tsx b/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.test.tsx index 8dbfda53b17cc..21c5cef4ae925 100644 --- a/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.test.tsx +++ b/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.test.tsx @@ -27,6 +27,15 @@ const timefilterSetupMock = timefilterServiceMock.createSetupContract(); jest.mock('ui/new_platform'); +jest.mock('../../../../../../src/legacy/core_plugins/data/public/legacy', () => ({ + start: { + ui: { + SearchBar: () => {}, + }, + }, + setup: {}, +})); + jest.mock('../../../../core_plugins/data/public', () => { return { SearchBar: () =>
, diff --git a/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.tsx b/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.tsx index abe17a32116cb..aec91c2aa6bc6 100644 --- a/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.tsx +++ b/src/legacy/core_plugins/kibana_react/public/top_nav_menu/top_nav_menu.tsx @@ -21,10 +21,11 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { I18nProvider } from '@kbn/i18n/react'; -import { start as data } from '../../../data/public/legacy'; + import { TopNavMenuData } from './top_nav_menu_data'; import { TopNavMenuItem } from './top_nav_menu_item'; import { SearchBarProps } from '../../../../core_plugins/data/public'; +import { start as data } from '../../../data/public/legacy'; type Props = Partial & { appName: string; From c8366791f1779922c761454aa71aaebb44e0c431 Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 26 Sep 2019 17:54:50 +0300 Subject: [PATCH 13/32] Removed unnecessary mocks --- .../search_bar/components/search_bar.test.tsx | 7 ----- .../data/public/timefilter/get_time.ts | 2 +- .../timefilter/timefilter.test.mocks.ts | 28 ------------------- 3 files changed, 1 insertion(+), 36 deletions(-) delete mode 100644 src/legacy/core_plugins/data/public/timefilter/timefilter.test.mocks.ts diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx index f404962272085..73e81a38572c3 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.test.tsx @@ -44,13 +44,6 @@ jest.mock('../../../query/query_bar', () => { }; }); -jest.mock('ui/notify', () => ({ - toastNotifications: { - addSuccess: () => {}, - addDanger: () => {}, - }, -})); - const noop = jest.fn(); const createMockWebStorage = () => ({ diff --git a/src/legacy/core_plugins/data/public/timefilter/get_time.ts b/src/legacy/core_plugins/data/public/timefilter/get_time.ts index e54725dd9ba48..18a43d789714d 100644 --- a/src/legacy/core_plugins/data/public/timefilter/get_time.ts +++ b/src/legacy/core_plugins/data/public/timefilter/get_time.ts @@ -18,8 +18,8 @@ */ import dateMath from '@elastic/datemath'; -import { Field, IndexPattern } from 'ui/index_patterns'; import { TimeRange } from 'src/plugins/data/public'; +import { IndexPattern, Field } from '../index_patterns'; interface CalculateBoundsOptions { forceNow?: Date; diff --git a/src/legacy/core_plugins/data/public/timefilter/timefilter.test.mocks.ts b/src/legacy/core_plugins/data/public/timefilter/timefilter.test.mocks.ts deleted file mode 100644 index 7354916c3fc35..0000000000000 --- a/src/legacy/core_plugins/data/public/timefilter/timefilter.test.mocks.ts +++ /dev/null @@ -1,28 +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 { chromeServiceMock } from '../../../../../core/public/mocks'; - -jest.doMock('ui/new_platform', () => ({ - npStart: { - core: { - chrome: chromeServiceMock.createStartContract(), - }, - }, -})); From 65b592e3d1f5e78836338bab1eadb59aae473d17 Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 26 Sep 2019 18:38:24 +0300 Subject: [PATCH 14/32] Delete unused mock --- .../query_bar_top_row.test.mocks.tsx | 32 ------------------- .../components/query_bar_top_row.test.tsx | 1 - 2 files changed, 33 deletions(-) delete mode 100644 src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.mocks.tsx diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.mocks.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.mocks.tsx deleted file mode 100644 index 585fad0e058b7..0000000000000 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.mocks.tsx +++ /dev/null @@ -1,32 +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 { - fatalErrorsServiceMock, - notificationServiceMock, -} from '../../../../../../../core/public/mocks'; - -jest.doMock('ui/new_platform', () => ({ - npSetup: { - core: { - fatalErrors: fatalErrorsServiceMock.createSetupContract(), - notifications: notificationServiceMock.createSetupContract(), - }, - }, -})); diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.tsx index d77c248a7552d..337bb9f4861c3 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.tsx @@ -21,7 +21,6 @@ import { mockPersistedLogFactory } from './query_bar_input.test.mocks'; import React from 'react'; import { mount } from 'enzyme'; -import './query_bar_top_row.test.mocks'; import { QueryBarTopRow } from './query_bar_top_row'; import { IndexPattern } from '../../../index'; From 8dbf16440047afedacb21e4d41825a3ae3f0be8c Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 26 Sep 2019 19:08:22 +0300 Subject: [PATCH 15/32] Fixed exporting of data plugin types --- src/plugins/data/public/index.ts | 4 +- .../public/components/search_bar.test.tsx | 80 +++++++++++-------- 2 files changed, 47 insertions(+), 37 deletions(-) diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 7696b4a85426e..9f7a4cb92666d 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -18,14 +18,14 @@ */ import { PluginInitializerContext } from '../../../core/public'; -import { DataPublicPlugin, DataPublicPluginSetup, DataPublicPluginStart } from './plugin'; +import { DataPublicPlugin } from './plugin'; export function plugin(initializerContext: PluginInitializerContext) { return new DataPublicPlugin(initializerContext); } export { DataPublicPlugin as Plugin }; -export { DataPublicPluginSetup, DataPublicPluginStart }; +export { DataPublicPluginSetup, DataPublicPluginStart } from './types'; export * from '../common'; 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 eb97d63a33395..c871d75d650a6 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 @@ -4,32 +4,49 @@ * you may not use this file except in compliance with the Elastic License. */ -import { SearchBar } from './search_bar'; -import { shallowWithIntl } from 'test_utils/enzyme_helpers'; +import { SearchBar, SearchBarProps } from './search_bar'; import React, { ReactElement } from 'react'; import { CoreStart } from 'src/core/public'; import { act } from 'react-dom/test-utils'; import { IndexPattern, QueryBarInput } from 'src/legacy/core_plugins/data/public'; +import { KibanaContextProvider } from 'src/plugins/kibana_react/public'; +import { I18nProvider } from '@kbn/i18n/react'; + jest.mock('ui/new_platform'); import { openSourceModal } from '../services/source_modal'; +import { mount } from 'enzyme'; jest.mock('../services/source_modal', () => ({ openSourceModal: jest.fn() })); +function wrapSearchBarInContext(testProps: SearchBarProps) { + const services = { + uiSettings: {} as CoreStart['uiSettings'], + savedObjects: {} as CoreStart['savedObjects'], + notifications: {} as CoreStart['notifications'], + http: {} as CoreStart['http'], + overlays: {} as CoreStart['overlays'], + }; + + return ( + + + + + + ); +} + describe('search_bar', () => { it('should render search bar and submit queryies', () => { const querySubmit = jest.fn(); - const instance = shallowWithIntl( - {}} - onQuerySubmit={querySubmit} - savedObjects={{} as CoreStart['savedObjects']} - uiSettings={{} as CoreStart['uiSettings']} - http={{} as CoreStart['http']} - overlays={{} as CoreStart['overlays']} - currentIndexPattern={{ title: 'Testpattern' } as IndexPattern} - /> + const instance = mount( + wrapSearchBarInContext({ + isLoading: false, + onIndexPatternSelected: () => {}, + onQuerySubmit: querySubmit, + currentIndexPattern: { title: 'Testpattern' } as IndexPattern, + }) ); act(() => { instance.find(QueryBarInput).prop('onChange')!({ language: 'lucene', query: 'testQuery' }); @@ -44,17 +61,13 @@ describe('search_bar', () => { it('should translate kql query into JSON dsl', () => { const querySubmit = jest.fn(); - const instance = shallowWithIntl( - {}} - onQuerySubmit={querySubmit} - savedObjects={{} as CoreStart['savedObjects']} - uiSettings={{} as CoreStart['uiSettings']} - http={{} as CoreStart['http']} - overlays={{} as CoreStart['overlays']} - currentIndexPattern={{ title: 'Testpattern', fields: [{ name: 'test' }] } as IndexPattern} - /> + const instance = mount( + wrapSearchBarInContext({ + isLoading: false, + onIndexPatternSelected: () => {}, + onQuerySubmit: querySubmit, + currentIndexPattern: { title: 'Testpattern', fields: [{ name: 'test' }] } as IndexPattern, + }) ); act(() => { instance.find(QueryBarInput).prop('onChange')!({ language: 'kuery', query: 'test: abc' }); @@ -72,17 +85,14 @@ describe('search_bar', () => { it('should open index pattern picker', () => { const indexPatternSelected = jest.fn(); - const instance = shallowWithIntl( - {}} - savedObjects={{} as CoreStart['savedObjects']} - uiSettings={{} as CoreStart['uiSettings']} - http={{} as CoreStart['http']} - overlays={{} as CoreStart['overlays']} - currentIndexPattern={{ title: 'Testpattern' } as IndexPattern} - /> + + const instance = mount( + wrapSearchBarInContext({ + isLoading: false, + onIndexPatternSelected: indexPatternSelected, + onQuerySubmit: () => {}, + currentIndexPattern: { title: 'Testpattern' } as IndexPattern, + }) ); // pick the button component out of the tree because From 1f8460648fefc1a83ac7c2f256716a031344dde0 Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 26 Sep 2019 19:40:15 +0300 Subject: [PATCH 16/32] Updated maps snapshot --- .../__snapshots__/view.test.js.snap | 186 ++++++++++-------- 1 file changed, 101 insertions(+), 85 deletions(-) diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap index 49439fa9d64e6..4c9ef61478ab4 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap @@ -1,103 +1,119 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`LayerPanel is rendered 1`] = ` - - - - - - - - - - + + + + + +

+ layer 1 +

+
+
+
+ +
+ -

- layer 1 -

- - - - + + +

+ + source prop1 + + + + you get one chance to set me + +

+
+
+
+
- - + + + + + + - -

- - source prop1 - - - - you get one chance to set me - -

-
-
+ /> + +
- -
-
- - - - - - - - -
-
- - - - + + + + `; exports[`LayerPanel should render empty panel when selectedLayer is null 1`] = `""`; From 0f60094f31ffd4b21d3eb35b880c3f33235677dc Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 26 Sep 2019 20:00:12 +0300 Subject: [PATCH 17/32] Fixed some TS issues --- .../plugins/graph/public/components/search_bar.tsx | 3 +-- .../legacy/plugins/lens/public/app_plugin/app.test.tsx | 9 ++++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/x-pack/legacy/plugins/graph/public/components/search_bar.tsx b/x-pack/legacy/plugins/graph/public/components/search_bar.tsx index c1c0e56dac6a1..226f6f829d8a4 100644 --- a/x-pack/legacy/plugins/graph/public/components/search_bar.tsx +++ b/x-pack/legacy/plugins/graph/public/components/search_bar.tsx @@ -7,7 +7,6 @@ import { EuiFlexGroup, EuiFlexItem, EuiButton, EuiButtonEmpty, EuiToolTip } from '@elastic/eui'; import React, { useState } from 'react'; -import { CoreStart } from 'src/core/public'; import { i18n } from '@kbn/i18n'; import { I18nProvider } from '@kbn/i18n/react'; import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query'; @@ -56,7 +55,7 @@ export function SearchBar(props: SearchBarProps) { const [query, setQuery] = useState({ language: 'kuery', query: initialQuery || '' }); const kibana = useKibana(); const { overlays, uiSettings, savedObjects } = kibana.services; - if (!overlays) return; + if (!overlays) return null; return ( diff --git a/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx b/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx index 1e5d9eb39c578..12ff7b74c7021 100644 --- a/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx +++ b/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx @@ -11,9 +11,11 @@ import { Storage } from 'ui/storage'; import { Document, SavedObjectStore } from '../persistence'; import { mount } from 'enzyme'; import { QueryBarTopRow } from '../../../../../../src/legacy/core_plugins/data/public/query/query_bar'; -import { SavedObjectsClientContract } from 'src/core/public'; +import { dataPluginMock } from 'src/plugins/data/public/mocks'; import { coreMock } from 'src/core/public/mocks'; +const dataStartMock = dataPluginMock.createStartContract(); + jest.mock('../../../../../../src/legacy/core_plugins/data/public/query/query_bar', () => ({ QueryBarTopRow: jest.fn(() => null), })); @@ -37,16 +39,17 @@ describe('Lens App', () => { function makeDefaultArgs(): jest.Mocked<{ editorFrame: EditorFrameInstance; + data: typeof dataStartMock; core: typeof core; store: Storage; docId?: string; docStorage: SavedObjectStore; redirectTo: (id?: string) => void; - savedObjectsClient: SavedObjectsClientContract; }> { return ({ editorFrame: createMockFrame(), core, + data: dataStartMock, store: { get: jest.fn(), }, @@ -59,12 +62,12 @@ describe('Lens App', () => { savedObjectsClient: jest.fn(), } as unknown) as jest.Mocked<{ editorFrame: EditorFrameInstance; + data: typeof dataStartMock; core: typeof core; store: Storage; docId?: string; docStorage: SavedObjectStore; redirectTo: (id?: string) => void; - savedObjectsClient: SavedObjectsClientContract; }>; } From 64b9ec6039cf62c77b58119168859b588b42a6bb Mon Sep 17 00:00:00 2001 From: Liza K Date: Sun, 29 Sep 2019 13:23:42 +0300 Subject: [PATCH 18/32] Fixed jest tests --- .../public/markdown_vis_controller.test.tsx | 2 +- .../plugins/graph/public/components/search_bar.test.tsx | 9 +++++++-- .../legacy/plugins/lens/public/app_plugin/app.test.tsx | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/legacy/core_plugins/vis_type_markdown/public/markdown_vis_controller.test.tsx b/src/legacy/core_plugins/vis_type_markdown/public/markdown_vis_controller.test.tsx index 9d2f68ddb7446..5bcb2961c42de 100644 --- a/src/legacy/core_plugins/vis_type_markdown/public/markdown_vis_controller.test.tsx +++ b/src/legacy/core_plugins/vis_type_markdown/public/markdown_vis_controller.test.tsx @@ -22,7 +22,7 @@ import { render, mount } from 'enzyme'; import { MarkdownVisWrapper } from './markdown_vis_controller'; // We need Markdown to do these tests, so mock data plugin -jest.mock('../../data/public', () => { +jest.mock('../../data/public/legacy', () => { return {}; }); 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 c871d75d650a6..80b1c3c343942 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 @@ -10,10 +10,11 @@ import { CoreStart } from 'src/core/public'; import { act } from 'react-dom/test-utils'; import { IndexPattern, QueryBarInput } from 'src/legacy/core_plugins/data/public'; -import { KibanaContextProvider } from 'src/plugins/kibana_react/public'; +import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; import { I18nProvider } from '@kbn/i18n/react'; jest.mock('ui/new_platform'); + import { openSourceModal } from '../services/source_modal'; import { mount } from 'enzyme'; @@ -21,7 +22,11 @@ jest.mock('../services/source_modal', () => ({ openSourceModal: jest.fn() })); function wrapSearchBarInContext(testProps: SearchBarProps) { const services = { - uiSettings: {} as CoreStart['uiSettings'], + uiSettings: { + get: (key: string) => { + return 10; + }, + } as CoreStart['uiSettings'], savedObjects: {} as CoreStart['savedObjects'], notifications: {} as CoreStart['notifications'], http: {} as CoreStart['http'], diff --git a/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx b/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx index 12ff7b74c7021..a8df5eafe71ff 100644 --- a/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx +++ b/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx @@ -11,7 +11,7 @@ import { Storage } from 'ui/storage'; import { Document, SavedObjectStore } from '../persistence'; import { mount } from 'enzyme'; import { QueryBarTopRow } from '../../../../../../src/legacy/core_plugins/data/public/query/query_bar'; -import { dataPluginMock } from 'src/plugins/data/public/mocks'; +import { dataPluginMock } from '../../../../../../src/plugins/data/public/mocks'; import { coreMock } from 'src/core/public/mocks'; const dataStartMock = dataPluginMock.createStartContract(); From 1fe975c00e3af5eec24d5e2432f4ef6afe46f269 Mon Sep 17 00:00:00 2001 From: Liza K Date: Sun, 29 Sep 2019 14:28:16 +0300 Subject: [PATCH 19/32] Context adjustments in TSVB --- .../query_bar/components/query_bar_input.tsx | 22 +----- .../public/components/vis_editor.js | 71 +++++++++++-------- .../vis/editors/default/controls/filter.tsx | 1 + 3 files changed, 45 insertions(+), 49 deletions(-) diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx index 76365dda2d43e..4d1d671c25a46 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx @@ -23,7 +23,7 @@ import React from 'react'; import { EuiFieldText, EuiOutsideClickDetector, PopoverAnchorPosition } from '@elastic/eui'; import { InjectedIntl, injectI18n } from '@kbn/i18n/react'; -import { debounce, compact, isEqual, omit } from 'lodash'; +import { debounce, compact, isEqual } from 'lodash'; import { PersistedLog } from 'ui/persisted_log'; import { @@ -389,11 +389,12 @@ export class QueryBarInputUI extends Component { this.setState({ index }); }; - public componentWillMount() { + public componentWillReceiveProps() { this.services = this.props.kibana.services; } public componentDidMount() { + this.services = this.props.kibana.services; const parsedQuery = fromUser(toUser(this.props.query.query)); if (!isEqual(this.props.query.query, parsedQuery)) { this.onChange({ ...this.props.query, query: parsedQuery }); @@ -441,22 +442,6 @@ export class QueryBarInputUI extends Component { } public render() { - const rest = omit(this.props, [ - 'indexPatterns', - 'intl', - 'kibana', - 'query', - 'appName', - 'disableAutoFocus', - 'screenTitle', - 'prepend', - 'persistedLog', - 'bubbleSubmitEvent', - 'languageSwitcherPopoverAnchorPosition', - 'onChange', - 'onSubmit', - ]); - return (
{ onSelectLanguage={this.onSelectLanguage} /> } - {...rest} />
diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js index a6c52d8760666..389a84babae87 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js @@ -34,6 +34,7 @@ import { extractIndexPatterns } from '../../common/extract_index_patterns'; import { npStart } from 'ui/new_platform'; import { Storage } from 'ui/storage'; import { CoreStartContextProvider } from '../contexts/query_input_bar_context'; +import { KibanaContextProvider } from '../../../../../plugins/kibana_react/public'; const localStorage = new Storage(window.localStorage); import { timefilter } from 'ui/timefilter'; @@ -163,38 +164,48 @@ export class VisEditor extends Component { const { model } = this.state; if (model) { + //TODO: Remove CoreStartContextProvider, KibanaContextProvider should be raised to the top of the plugin. return ( -
-
- + +
+
+ +
+ +
+ + + +
- -
- - - -
-
+ ); } diff --git a/src/legacy/ui/public/vis/editors/default/controls/filter.tsx b/src/legacy/ui/public/vis/editors/default/controls/filter.tsx index 06e9d87b694de..81991c8c5b2a2 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/filter.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/filter.tsx @@ -83,6 +83,7 @@ function FilterRow({
); + // TODO: KibanaContextProvider should be raised to the top of the vis plugin return ( Date: Sun, 29 Sep 2019 14:48:29 +0300 Subject: [PATCH 20/32] componentWillMount --- .../data/public/query/query_bar/components/query_bar_input.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx index 4d1d671c25a46..42bb59adbfd13 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx @@ -389,7 +389,7 @@ export class QueryBarInputUI extends Component { this.setState({ index }); }; - public componentWillReceiveProps() { + public componentWillMount() { this.services = this.props.kibana.services; } From 0ca40af74e03612eb14bab75d80f26b317699559 Mon Sep 17 00:00:00 2001 From: Liza K Date: Wed, 2 Oct 2019 12:22:46 +0300 Subject: [PATCH 21/32] Code review fixes --- src/legacy/core_plugins/data/public/plugin.ts | 6 ++++-- .../public/query/query_bar/components/query_bar_input.tsx | 7 +------ .../{bind_search_bar.tsx => create_search_bar.tsx} | 6 +++++- .../data/public/search/search_bar/components/index.tsx | 2 +- .../public/search/search_bar/components/search_bar.tsx | 3 +-- 5 files changed, 12 insertions(+), 12 deletions(-) rename src/legacy/core_plugins/data/public/search/search_bar/components/{bind_search_bar.tsx => create_search_bar.tsx} (95%) diff --git a/src/legacy/core_plugins/data/public/plugin.ts b/src/legacy/core_plugins/data/public/plugin.ts index 36544ae1902b8..a5aa55673cac6 100644 --- a/src/legacy/core_plugins/data/public/plugin.ts +++ b/src/legacy/core_plugins/data/public/plugin.ts @@ -18,7 +18,7 @@ */ import { CoreSetup, CoreStart, Plugin } from '../../../../core/public'; -import { SearchService, SearchSetup, createSearchBar } from './search'; +import { SearchService, SearchSetup, createSearchBar, StatetfulSearchBarProps } from './search'; import { QueryService, QuerySetup } from './query'; import { FilterService, FilterSetup } from './filter'; import { TimefilterService, TimefilterSetup } from './timefilter'; @@ -67,7 +67,9 @@ export interface DataStart { query: QuerySetup; search: SearchSetup; timefilter: TimefilterSetup; - ui: any; + ui: { + SearchBar: React.ComponentType; + }; } /** diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx index 42bb59adbfd13..ad1d9af4fbe6c 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx @@ -97,7 +97,7 @@ export class QueryBarInputUI extends Component { public inputRef: HTMLInputElement | null = null; private persistedLog: PersistedLog | undefined; - private services!: IDataPluginServices; + private services = this.props.kibana.services; private componentIsUnmounting = false; private getQueryString = () => { @@ -389,12 +389,7 @@ export class QueryBarInputUI extends Component { this.setState({ index }); }; - public componentWillMount() { - this.services = this.props.kibana.services; - } - public componentDidMount() { - this.services = this.props.kibana.services; const parsedQuery = fromUser(toUser(this.props.query.query)); if (!isEqual(this.props.query.query, parsedQuery)) { this.onChange({ ...this.props.query, query: parsedQuery }); diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/bind_search_bar.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx similarity index 95% rename from src/legacy/core_plugins/data/public/search/search_bar/components/bind_search_bar.tsx rename to src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx index fa0b2dbac462b..add49e47971d3 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/bind_search_bar.tsx +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx @@ -35,6 +35,10 @@ interface StatefulSearchBarDeps { autocomplete: AutocompletePublicPluginStart; } +export type StatetfulSearchBarProps = SearchBarOwnProps & { + appName: string; +}; + const defaultFiltersUpdated = (filterManager: FilterManager) => { return (filters: Filter[]) => { filterManager.setFilters(filters); @@ -59,7 +63,7 @@ export function createSearchBar({ }: StatefulSearchBarDeps) { // App name should come from the core application service. // Until it's available, we'll ask the user to provide it for the pre-wired component. - return (props: SearchBarOwnProps & { appName: string }) => { + return (props: StatetfulSearchBarProps) => { const timeRange = timefilter.timefilter.getTime(); const refreshInterval = timefilter.timefilter.getRefreshInterval(); diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/index.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/index.tsx index fc2e0e42d73f8..accaac163acfc 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/index.tsx +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/index.tsx @@ -18,4 +18,4 @@ */ export * from './search_bar'; -export * from './bind_search_bar'; +export * from './create_search_bar'; diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx index 3bbde007629ed..ed2a6638aba11 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/search_bar.tsx @@ -99,7 +99,7 @@ class SearchBarUI extends Component { }; private savedQueryService!: SavedQueryService; - private services!: IDataPluginServices; + private services = this.props.kibana.services; public filterBarRef: Element | null = null; public filterBarWrapperRef: Element | null = null; @@ -330,7 +330,6 @@ class SearchBarUI extends Component { }; public componentDidMount() { - this.services = this.props.kibana.services; if (this.filterBarRef) { this.setFilterBarHeight(); this.ro.observe(this.filterBarRef); From eaac39c7136041977d8a83836231caf1e05dae20 Mon Sep 17 00:00:00 2001 From: Liza K Date: Wed, 2 Oct 2019 13:31:19 +0300 Subject: [PATCH 22/32] Pass dataTestSubj to query bar input --- .../data/public/query/query_bar/components/query_bar_input.tsx | 3 ++- src/legacy/ui/public/vis/editors/default/controls/filter.tsx | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx index ad1d9af4fbe6c..6c91da7c28135 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx @@ -57,6 +57,7 @@ interface Props { languageSwitcherPopoverAnchorPosition?: PopoverAnchorPosition; onChange?: (query: Query) => void; onSubmit?: (query: Query) => void; + dataTestSubj?: string; } interface State { @@ -487,7 +488,6 @@ export class QueryBarInputUI extends Component { : undefined } type="text" - data-test-subj="queryInput" aria-autocomplete="list" aria-controls="kbnTypeahead__items" aria-activedescendant={ @@ -502,6 +502,7 @@ export class QueryBarInputUI extends Component { onSelectLanguage={this.onSelectLanguage} /> } + data-test-subj={this.props.dataTestSubj || 'queryInput'} /> diff --git a/src/legacy/ui/public/vis/editors/default/controls/filter.tsx b/src/legacy/ui/public/vis/editors/default/controls/filter.tsx index 81991c8c5b2a2..cceaf86b5d85c 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/filter.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/filter.tsx @@ -104,7 +104,7 @@ function FilterRow({ indexPatterns={[agg.getIndexPattern()]} onChange={(query: Query) => onChangeValue(id, query, customLabel)} disableAutoFocus={!autoFocus} - data-test-subj={dataTestSubj} + dataTestSubj={dataTestSubj} bubbleSubmitEvent={true} languageSwitcherPopoverAnchorPosition="leftDown" /> From cc39f891b9760e6db826d67d3f23c52c7d028b08 Mon Sep 17 00:00:00 2001 From: Liza K Date: Wed, 2 Oct 2019 14:43:44 +0300 Subject: [PATCH 23/32] Graph data --- .../graph/public/angular/templates/index.html | 3 +++ x-pack/legacy/plugins/graph/public/app.js | 10 +++++++++- .../plugins/graph/public/components/app.tsx | 16 ++++++++++------ 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/x-pack/legacy/plugins/graph/public/angular/templates/index.html b/x-pack/legacy/plugins/graph/public/angular/templates/index.html index 8d55d4080241c..89a0e237b34b7 100644 --- a/x-pack/legacy/plugins/graph/public/angular/templates/index.html +++ b/x-pack/legacy/plugins/graph/public/angular/templates/index.html @@ -15,6 +15,9 @@ initial-query="initialQuery" state="reduxState" dispatch="reduxDispatch" + autocomplete-start="autocompleteStart" + core-start="coreStart" + store="store" >
diff --git a/x-pack/legacy/plugins/graph/public/app.js b/x-pack/legacy/plugins/graph/public/app.js index 77d2aa413cfca..d5894f170cdaa 100644 --- a/x-pack/legacy/plugins/graph/public/app.js +++ b/x-pack/legacy/plugins/graph/public/app.js @@ -33,6 +33,7 @@ import { npStart } from 'ui/new_platform'; import { SavedObjectRegistryProvider } from 'ui/saved_objects/saved_object_registry'; import { capabilities } from 'ui/capabilities'; import { showSaveModal } from 'ui/saved_objects/show_saved_object_save_modal'; +import { Storage } from 'ui/storage'; import { xpackInfo } from 'plugins/xpack_main/services/xpack_info'; @@ -114,7 +115,10 @@ app.directive('graphApp', function (reactDirective) { ['isLoading', { watchDepth: 'reference' }], ['onIndexPatternSelected', { watchDepth: 'reference' }], ['onQuerySubmit', { watchDepth: 'reference' }], - ['initialQuery', { watchDepth: 'reference' }] + ['initialQuery', { watchDepth: 'reference' }], + ['autocompleteStart', { watchDepth: 'reference' }], + ['coreStart', { watchDepth: 'reference' }], + ['store', { watchDepth: 'reference' }] ]); }); @@ -293,6 +297,10 @@ app.controller('graphuiPlugin', function ( } }; + + $scope.store = new Storage(window.localStorage); + $scope.coreStart = npStart.core; + $scope.autocompleteStart = npStart.plugins.data.autocomplete; $scope.loading = false; const updateScope = () => { diff --git a/x-pack/legacy/plugins/graph/public/components/app.tsx b/x-pack/legacy/plugins/graph/public/components/app.tsx index 3d8ec17228930..907e7e4cecdcd 100644 --- a/x-pack/legacy/plugins/graph/public/components/app.tsx +++ b/x-pack/legacy/plugins/graph/public/components/app.tsx @@ -7,23 +7,27 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React from 'react'; import { Storage } from 'ui/storage'; -import { npStart } from 'ui/new_platform'; +import { CoreStart } from 'kibana/public'; +import { AutocompletePublicPluginStart } from 'src/plugins/data/public'; import { FieldManagerProps, FieldManager } from './field_manager'; import { SearchBarProps, SearchBar } from './search_bar'; import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; -const localStorage = new Storage(window.localStorage); -export interface GraphAppProps extends FieldManagerProps, SearchBarProps {} +export interface GraphAppProps extends FieldManagerProps, SearchBarProps { + coreStart: CoreStart; + autocompleteStart: AutocompletePublicPluginStart; + store: Storage; +} export function GraphApp(props: GraphAppProps) { return (
From 89b72c7e86079f0068a88bc8c0f1ee411e2c4137 Mon Sep 17 00:00:00 2001 From: Liza K Date: Wed, 2 Oct 2019 17:24:53 +0300 Subject: [PATCH 24/32] - Pass NP data plugin to KibanaReactContext - Move value_suggestions to NP --- .../filter/filter_bar/filter_editor/index.tsx | 4 --- .../filter_editor/phrase_suggestor.tsx | 18 +++++++---- .../filter_editor/phrase_value_input.tsx | 7 ++-- .../filter_editor/phrases_values_input.tsx | 7 ++-- src/legacy/core_plugins/data/public/plugin.ts | 2 +- .../query_bar/components/query_bar_input.tsx | 2 +- .../components/create_search_bar.tsx | 8 ++--- src/legacy/core_plugins/data/public/types.ts | 4 +-- .../public/components/vis_editor.js | 2 +- .../vis/editors/default/controls/filter.tsx | 2 +- src/plugins/data/public/plugin.ts | 2 ++ .../public/suggestions_provider}/index.ts | 6 +--- .../data/public/suggestions_provider/types.ts | 23 +++++++++++++ .../value_suggestions.test.ts | 32 ++++++++++--------- .../value_suggestions.ts | 15 +++++---- src/plugins/data/public/types.ts | 4 +++ .../graph/public/angular/templates/index.html | 2 +- x-pack/legacy/plugins/graph/public/app.js | 4 +-- .../plugins/graph/public/components/app.tsx | 7 ++-- .../public/autocomplete_providers/value.js | 4 +-- .../plugins/lens/public/app_plugin/app.tsx | 2 +- .../connected_components/layer_panel/view.js | 2 +- 22 files changed, 96 insertions(+), 63 deletions(-) rename src/{legacy/ui/public/value_suggestions => plugins/data/public/suggestions_provider}/index.ts (78%) create mode 100644 src/plugins/data/public/suggestions_provider/types.ts rename src/{legacy/ui/public/value_suggestions => plugins/data/public/suggestions_provider}/value_suggestions.test.ts (83%) rename src/{legacy/ui/public/value_suggestions => plugins/data/public/suggestions_provider}/value_suggestions.ts (82%) diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx index 64487df5b22d4..5b295a759d694 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx @@ -36,7 +36,6 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; import { get } from 'lodash'; import React, { Component } from 'react'; -import { UiSettingsClientContract } from 'src/core/public'; import { Field, IndexPattern } from '../../../index_patterns'; import { GenericComboBox, GenericComboBoxProps } from './generic_combo_box'; import { @@ -62,7 +61,6 @@ interface Props { onSubmit: (filter: Filter) => void; onCancel: () => void; intl: InjectedIntl; - uiSettings: UiSettingsClientContract; } interface State { @@ -343,7 +341,6 @@ class FilterEditorUI extends Component { value={this.state.params} onChange={this.onParamsChange} data-test-subj="phraseValueInput" - uiSettings={this.props.uiSettings} /> ); case 'phrases': @@ -353,7 +350,6 @@ class FilterEditorUI extends Component { field={this.state.selectedField} values={this.state.params} onChange={this.onParamsChange} - uiSettings={this.props.uiSettings} /> ); case 'range': diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_suggestor.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_suggestor.tsx index 6b262c66402f2..9ef5f546c0be0 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_suggestor.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_suggestor.tsx @@ -18,14 +18,17 @@ */ import { Component } from 'react'; -import { getSuggestions } from 'ui/value_suggestions'; -import { UiSettingsClientContract } from 'src/core/public'; import { Field, IndexPattern } from '../../../index_patterns'; +import { + withKibana, + KibanaReactContextValue, +} from '../../../../../../../plugins/kibana_react/public'; +import { IDataPluginServices } from '../../../types'; export interface PhraseSuggestorProps { + kibana: KibanaReactContextValue; indexPattern: IndexPattern; field?: Field; - uiSettings: UiSettingsClientContract; } export interface PhraseSuggestorState { @@ -38,10 +41,11 @@ export interface PhraseSuggestorState { * aggregatable), we pull out the common logic for requesting suggestions into this component * which both of them extend. */ -export class PhraseSuggestor extends Component< +export class PhraseSuggestorUI extends Component< T, PhraseSuggestorState > { + private services = this.props.kibana.services; public state: PhraseSuggestorState = { suggestions: [], isLoading: false, @@ -52,7 +56,7 @@ export class PhraseSuggestor extends Component< } protected isSuggestingValues() { - const shouldSuggestValues = this.props.uiSettings.get('filterEditor:suggestValues'); + const shouldSuggestValues = this.services.uiSettings.get('filterEditor:suggestValues'); const { field } = this.props; return shouldSuggestValues && field && field.aggregatable && field.type === 'string'; } @@ -67,7 +71,9 @@ export class PhraseSuggestor extends Component< return; } this.setState({ isLoading: true }); - const suggestions = await getSuggestions(indexPattern.title, field, value); + const suggestions = await this.services.data.getSuggestions(indexPattern.title, field, value); this.setState({ suggestions, isLoading: false }); } } + +export const PhraseSuggestor = withKibana(PhraseSuggestorUI); diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_value_input.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_value_input.tsx index 0696bacc568b5..7ef51f88ba57e 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_value_input.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_value_input.tsx @@ -22,8 +22,9 @@ import { InjectedIntl, injectI18n } from '@kbn/i18n/react'; import { uniq } from 'lodash'; import React from 'react'; import { GenericComboBox, GenericComboBoxProps } from './generic_combo_box'; -import { PhraseSuggestor, PhraseSuggestorProps } from './phrase_suggestor'; +import { PhraseSuggestorUI, PhraseSuggestorProps } from './phrase_suggestor'; import { ValueInputType } from './value_input_type'; +import { withKibana } from '../../../../../../../plugins/kibana_react/public'; interface Props extends PhraseSuggestorProps { value?: string; @@ -31,7 +32,7 @@ interface Props extends PhraseSuggestorProps { intl: InjectedIntl; } -class PhraseValueInputUI extends PhraseSuggestor { +class PhraseValueInputUI extends PhraseSuggestorUI { public render() { return ( ) { return GenericComboBox(props); } -export const PhraseValueInput = injectI18n(PhraseValueInputUI); +export const PhraseValueInput = injectI18n(withKibana(PhraseValueInputUI)); diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrases_values_input.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrases_values_input.tsx index d35e49b6b07ce..f3b30e2ad5fd9 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrases_values_input.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrases_values_input.tsx @@ -22,7 +22,8 @@ import { InjectedIntl, injectI18n } from '@kbn/i18n/react'; import { uniq } from 'lodash'; import React from 'react'; import { GenericComboBox, GenericComboBoxProps } from './generic_combo_box'; -import { PhraseSuggestor, PhraseSuggestorProps } from './phrase_suggestor'; +import { PhraseSuggestorUI, PhraseSuggestorProps } from './phrase_suggestor'; +import { withKibana } from '../../../../../../../plugins/kibana_react/public'; interface Props extends PhraseSuggestorProps { values?: string[]; @@ -30,7 +31,7 @@ interface Props extends PhraseSuggestorProps { intl: InjectedIntl; } -class PhrasesValuesInputUI extends PhraseSuggestor { +class PhrasesValuesInputUI extends PhraseSuggestorUI { public render() { const { suggestions } = this.state; const { values, intl, onChange } = this.props; @@ -64,4 +65,4 @@ function StringComboBox(props: GenericComboBoxProps) { return GenericComboBox(props); } -export const PhrasesValuesInput = injectI18n(PhrasesValuesInputUI); +export const PhrasesValuesInput = injectI18n(withKibana(PhrasesValuesInputUI)); diff --git a/src/legacy/core_plugins/data/public/plugin.ts b/src/legacy/core_plugins/data/public/plugin.ts index a5aa55673cac6..0ccd80c777d41 100644 --- a/src/legacy/core_plugins/data/public/plugin.ts +++ b/src/legacy/core_plugins/data/public/plugin.ts @@ -126,10 +126,10 @@ export class DataPlugin public start(core: CoreStart, { __LEGACY, data }: DataPluginStartDependencies) { const SearchBar = createSearchBar({ core, + data, store: __LEGACY.storage, timefilter: this.setupApi.timefilter, filterManager: this.setupApi.filter.filterManager, - autocomplete: data.autocomplete, }); return { diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx index 6c91da7c28135..3086aa2c29f48 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx @@ -135,7 +135,7 @@ export class QueryBarInputUI extends Component { const recentSearchSuggestions = this.getRecentSearchSuggestions(queryString); - const autocompleteProvider = this.services.autocomplete.getProvider(language); + const autocompleteProvider = this.services.data.autocomplete.getProvider(language); if ( !autocompleteProvider || !Array.isArray(this.state.indexPatterns) || diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx index add49e47971d3..84b40d34d474f 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx @@ -21,7 +21,7 @@ import React from 'react'; import { Filter } from '@kbn/es-query'; import { CoreStart } from 'src/core/public'; import { Storage } from 'ui/storage'; -import { AutocompletePublicPluginStart } from 'src/plugins/data/public'; +import { DataPublicPluginStart } from 'src/plugins/data/public'; import { KibanaContextProvider } from '../../../../../../../../src/plugins/kibana_react/public'; import { TimefilterSetup } from '../../../timefilter'; import { FilterManager, SearchBar } from '../../../'; @@ -29,10 +29,10 @@ import { SearchBarOwnProps } from '.'; interface StatefulSearchBarDeps { core: CoreStart; + data: DataPublicPluginStart; store: Storage; timefilter: TimefilterSetup; filterManager: FilterManager; - autocomplete: AutocompletePublicPluginStart; } export type StatetfulSearchBarProps = SearchBarOwnProps & { @@ -59,7 +59,7 @@ export function createSearchBar({ store, timefilter, filterManager, - autocomplete, + data, }: StatefulSearchBarDeps) { // App name should come from the core application service. // Until it's available, we'll ask the user to provide it for the pre-wired component. @@ -71,7 +71,7 @@ export function createSearchBar({ { appName: string; @@ -27,5 +27,5 @@ export interface IDataPluginServices extends Partial { notifications: CoreStart['notifications']; http: CoreStart['http']; store: Storage; - autocomplete: AutocompletePublicPluginStart; + data: DataPublicPluginStart; } diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js index 389a84babae87..3497a35f5c99d 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js @@ -170,7 +170,7 @@ export class VisEditor extends Component { services={{ appName: APP_NAME, store: localStorage, - autocomplete: npStart.plugins.data.autocomplete, + data: npStart.plugins.data, ...npStart.core, }} > diff --git a/src/legacy/ui/public/vis/editors/default/controls/filter.tsx b/src/legacy/ui/public/vis/editors/default/controls/filter.tsx index cceaf86b5d85c..2c0a2b6be37f8 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/filter.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/filter.tsx @@ -95,7 +95,7 @@ function FilterRow({ services={{ appName: 'filtersAgg', store: localStorage, - autocomplete: npStart.plugins.data.autocomplete, + data: npStart.plugins.data, ...npStart.core, }} > diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index eb31647767360..a3fa8005560ae 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -20,6 +20,7 @@ import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../../core/public'; import { AutocompleteProviderRegister } from './autocomplete_provider'; import { DataPublicPluginSetup, DataPublicPluginStart } from './types'; +import { getSuggestionsProvider } from './suggestions_provider'; export class DataPublicPlugin implements Plugin { private readonly autocomplete = new AutocompleteProviderRegister(); @@ -35,6 +36,7 @@ export class DataPublicPlugin implements Plugin any; diff --git a/src/legacy/ui/public/value_suggestions/value_suggestions.test.ts b/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts similarity index 83% rename from src/legacy/ui/public/value_suggestions/value_suggestions.test.ts rename to src/plugins/data/public/suggestions_provider/value_suggestions.test.ts index d6d0a7dc003e6..13ccbbd9f3dde 100644 --- a/src/legacy/ui/public/value_suggestions/value_suggestions.test.ts +++ b/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts @@ -17,21 +17,23 @@ * under the License. */ +// TODO: remove when index patterns are moved here. jest.mock('ui/new_platform'); jest.mock('ui/index_patterns'); import { mockFields, mockIndexPattern } from 'ui/index_patterns'; import { getSuggestionsProvider } from './value_suggestions'; +import { UiSettingsClientContract } from 'kibana/public'; describe('getSuggestions', () => { let getSuggestions: any; - let fetch: any; + let http: any; describe('with value suggestions disabled', () => { beforeEach(() => { - const config = { get: () => false }; - fetch = jest.fn(); - getSuggestions = getSuggestionsProvider(config, fetch); + const config = { get: (key: string) => false } as UiSettingsClientContract; + http = { fetch: jest.fn() }; + getSuggestions = getSuggestionsProvider(config, http); }); it('should return an empty array', async () => { @@ -40,15 +42,15 @@ describe('getSuggestions', () => { const query = ''; const suggestions = await getSuggestions(index, field, query); expect(suggestions).toEqual([]); - expect(fetch).not.toHaveBeenCalled(); + expect(http.fetch).not.toHaveBeenCalled(); }); }); describe('with value suggestions enabled', () => { beforeEach(() => { - const config = { get: () => true }; - fetch = jest.fn(); - getSuggestions = getSuggestionsProvider(config, fetch); + const config = { get: (key: string) => true } as UiSettingsClientContract; + http = { fetch: jest.fn() }; + getSuggestions = getSuggestionsProvider(config, http); }); it('should return true/false for boolean fields', async () => { @@ -57,7 +59,7 @@ describe('getSuggestions', () => { const query = ''; const suggestions = await getSuggestions(index, field, query); expect(suggestions).toEqual([true, false]); - expect(fetch).not.toHaveBeenCalled(); + expect(http.fetch).not.toHaveBeenCalled(); }); it('should return an empty array if the field type is not a string or boolean', async () => { @@ -66,7 +68,7 @@ describe('getSuggestions', () => { const query = ''; const suggestions = await getSuggestions(index, field, query); expect(suggestions).toEqual([]); - expect(fetch).not.toHaveBeenCalled(); + expect(http.fetch).not.toHaveBeenCalled(); }); it('should return an empty array if the field is not aggregatable', async () => { @@ -75,7 +77,7 @@ describe('getSuggestions', () => { const query = ''; const suggestions = await getSuggestions(index, field, query); expect(suggestions).toEqual([]); - expect(fetch).not.toHaveBeenCalled(); + expect(http.fetch).not.toHaveBeenCalled(); }); it('should otherwise request suggestions', async () => { @@ -85,7 +87,7 @@ describe('getSuggestions', () => { ); const query = ''; await getSuggestions(index, field, query); - expect(fetch).toHaveBeenCalled(); + expect(http.fetch).toHaveBeenCalled(); }); it('should cache results if using the same index/field/query/filter', async () => { @@ -96,7 +98,7 @@ describe('getSuggestions', () => { const query = ''; await getSuggestions(index, field, query); await getSuggestions(index, field, query); - expect(fetch).toHaveBeenCalledTimes(1); + expect(http.fetch).toHaveBeenCalledTimes(1); }); it('should cache results for only one minute', async () => { @@ -113,7 +115,7 @@ describe('getSuggestions', () => { await getSuggestions(index, field, query); Date.now = now; - expect(fetch).toHaveBeenCalledTimes(2); + expect(http.fetch).toHaveBeenCalledTimes(2); }); it('should not cache results if using a different index/field/query', async () => { @@ -128,7 +130,7 @@ describe('getSuggestions', () => { await getSuggestions('logstash-*', fields[0], 'query'); await getSuggestions('logstash-*', fields[1], ''); await getSuggestions('logstash-*', fields[1], 'query'); - expect(fetch).toHaveBeenCalledTimes(8); + expect(http.fetch).toHaveBeenCalledTimes(8); }); }); }); diff --git a/src/legacy/ui/public/value_suggestions/value_suggestions.ts b/src/plugins/data/public/suggestions_provider/value_suggestions.ts similarity index 82% rename from src/legacy/ui/public/value_suggestions/value_suggestions.ts rename to src/plugins/data/public/suggestions_provider/value_suggestions.ts index 31e42e9945ede..03eaa5d9594d2 100644 --- a/src/legacy/ui/public/value_suggestions/value_suggestions.ts +++ b/src/plugins/data/public/suggestions_provider/value_suggestions.ts @@ -18,16 +18,17 @@ */ import { memoize } from 'lodash'; -import { Field } from 'ui/index_patterns'; + +import { UiSettingsClientContract, HttpServiceBase } from 'src/core/public'; +import { IGetSuggestions, Field } from './types'; export function getSuggestionsProvider( - config: { get: (key: string) => any }, - fetch: (...options: any[]) => any -) { + uiSettings: UiSettingsClientContract, + http: HttpServiceBase +): IGetSuggestions { const requestSuggestions = memoize( (index: string, field: Field, query: string, boolFilter: any = []) => { - return fetch({ - pathname: `/api/kibana/suggestions/values/${index}`, + return http.fetch(`/api/kibana/suggestions/values/${index}`, { method: 'POST', body: JSON.stringify({ query, field: field.name, boolFilter }), }); @@ -36,7 +37,7 @@ export function getSuggestionsProvider( ); return async (index: string, field: Field, query: string, boolFilter?: any) => { - const shouldSuggestValues = config.get('filterEditor:suggestValues'); + const shouldSuggestValues = uiSettings.get('filterEditor:suggestValues'); if (field.type === 'boolean') { return [true, false]; } else if (!shouldSuggestValues || !field.aggregatable || field.type !== 'string') { diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index 23308304b8ff8..70406b4dc0c0a 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -20,10 +20,14 @@ export * from './autocomplete_provider/types'; import { AutocompletePublicPluginSetup, AutocompletePublicPluginStart } from '.'; +import { IGetSuggestions } from './suggestions_provider/types'; export interface DataPublicPluginSetup { autocomplete: AutocompletePublicPluginSetup; } export interface DataPublicPluginStart { autocomplete: AutocompletePublicPluginStart; + getSuggestions: IGetSuggestions; } + +export { IGetSuggestions } from './suggestions_provider/types'; diff --git a/x-pack/legacy/plugins/graph/public/angular/templates/index.html b/x-pack/legacy/plugins/graph/public/angular/templates/index.html index 89a0e237b34b7..85e47c7c2cad5 100644 --- a/x-pack/legacy/plugins/graph/public/angular/templates/index.html +++ b/x-pack/legacy/plugins/graph/public/angular/templates/index.html @@ -15,7 +15,7 @@ initial-query="initialQuery" state="reduxState" dispatch="reduxDispatch" - autocomplete-start="autocompleteStart" + plugin-data-start="pluginDataStart" core-start="coreStart" store="store" > diff --git a/x-pack/legacy/plugins/graph/public/app.js b/x-pack/legacy/plugins/graph/public/app.js index d5894f170cdaa..c824fde3ce7eb 100644 --- a/x-pack/legacy/plugins/graph/public/app.js +++ b/x-pack/legacy/plugins/graph/public/app.js @@ -116,7 +116,7 @@ app.directive('graphApp', function (reactDirective) { ['onIndexPatternSelected', { watchDepth: 'reference' }], ['onQuerySubmit', { watchDepth: 'reference' }], ['initialQuery', { watchDepth: 'reference' }], - ['autocompleteStart', { watchDepth: 'reference' }], + ['pluginDataStart', { watchDepth: 'reference' }], ['coreStart', { watchDepth: 'reference' }], ['store', { watchDepth: 'reference' }] ]); @@ -300,7 +300,7 @@ app.controller('graphuiPlugin', function ( $scope.store = new Storage(window.localStorage); $scope.coreStart = npStart.core; - $scope.autocompleteStart = npStart.plugins.data.autocomplete; + $scope.pluginDataStart = npStart.plugins.data; $scope.loading = false; const updateScope = () => { diff --git a/x-pack/legacy/plugins/graph/public/components/app.tsx b/x-pack/legacy/plugins/graph/public/components/app.tsx index 907e7e4cecdcd..fe17e6c3f587b 100644 --- a/x-pack/legacy/plugins/graph/public/components/app.tsx +++ b/x-pack/legacy/plugins/graph/public/components/app.tsx @@ -8,7 +8,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React from 'react'; import { Storage } from 'ui/storage'; import { CoreStart } from 'kibana/public'; -import { AutocompletePublicPluginStart } from 'src/plugins/data/public'; +import { DataPublicPluginStart } from 'src/plugins/data/public'; import { FieldManagerProps, FieldManager } from './field_manager'; import { SearchBarProps, SearchBar } from './search_bar'; @@ -16,7 +16,8 @@ import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_reac export interface GraphAppProps extends FieldManagerProps, SearchBarProps { coreStart: CoreStart; - autocompleteStart: AutocompletePublicPluginStart; + // This is not named dataStart because of Angular treating data- prefix differently + pluginDataStart: DataPublicPluginStart; store: Storage; } @@ -26,7 +27,7 @@ export function GraphApp(props: GraphAppProps) { services={{ appName: 'graph', store: props.store, - autocomplete: props.autocompleteStart, + data: props.pluginDataStart, ...props.coreStart, }} > diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.js b/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.js index 36fb77a30acd0..c870c899a3151 100644 --- a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.js +++ b/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.js @@ -6,7 +6,7 @@ import { flatten } from 'lodash'; import { escapeQuotes } from './escape_kuery'; -import { getSuggestions } from 'ui/value_suggestions'; +import { npStart } from 'ui/new_platform'; const type = 'value'; @@ -31,7 +31,7 @@ export function getSuggestionsProvider({ indexPatterns, boolFilter }) { const query = `${prefix}${suffix}`; const suggestionsByField = fields.map(field => { - return getSuggestions(field.indexPatternTitle, field, query, boolFilter).then(data => { + return npStart.data.getSuggestions(field.indexPatternTitle, field, query, boolFilter).then(data => { const quotedValues = data.map(value => typeof value === 'string' ? `"${escapeQuotes(value)}"` : `${value}`); return wrapAsSuggestions(start, end, query, quotedValues); }); diff --git a/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx b/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx index 9c484e19789e9..a91462171abf7 100644 --- a/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx +++ b/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx @@ -160,7 +160,7 @@ export function App({ From b225dc56cb2bb377287c69551132b1c5f92c62d7 Mon Sep 17 00:00:00 2001 From: Liza K Date: Wed, 2 Oct 2019 17:24:53 +0300 Subject: [PATCH 25/32] - Pass NP data plugin to KibanaReactContext - Move value_suggestions to NP --- .../filter/filter_bar/filter_editor/index.tsx | 4 --- .../filter_editor/phrase_suggestor.tsx | 18 +++++++---- .../filter_editor/phrase_value_input.tsx | 7 ++-- .../filter_editor/phrases_values_input.tsx | 7 ++-- src/legacy/core_plugins/data/public/plugin.ts | 2 +- .../query_bar/components/query_bar_input.tsx | 2 +- .../components/create_search_bar.tsx | 8 ++--- src/legacy/core_plugins/data/public/types.ts | 4 +-- .../public/components/vis_editor.js | 2 +- .../vis/editors/default/controls/filter.tsx | 2 +- src/plugins/data/public/plugin.ts | 2 ++ .../public/suggestions_provider}/index.ts | 6 +--- .../data/public/suggestions_provider/types.ts | 23 +++++++++++++ .../value_suggestions.test.ts | 32 ++++++++++--------- .../value_suggestions.ts | 15 +++++---- src/plugins/data/public/types.ts | 4 +++ .../graph/public/angular/templates/index.html | 2 +- x-pack/legacy/plugins/graph/public/app.js | 4 +-- .../plugins/graph/public/components/app.tsx | 7 ++-- .../public/autocomplete_providers/value.js | 4 +-- .../plugins/lens/public/app_plugin/app.tsx | 2 +- .../connected_components/layer_panel/view.js | 2 +- 22 files changed, 96 insertions(+), 63 deletions(-) rename src/{legacy/ui/public/value_suggestions => plugins/data/public/suggestions_provider}/index.ts (78%) create mode 100644 src/plugins/data/public/suggestions_provider/types.ts rename src/{legacy/ui/public/value_suggestions => plugins/data/public/suggestions_provider}/value_suggestions.test.ts (83%) rename src/{legacy/ui/public/value_suggestions => plugins/data/public/suggestions_provider}/value_suggestions.ts (82%) diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx index 64487df5b22d4..5b295a759d694 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/index.tsx @@ -36,7 +36,6 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; import { get } from 'lodash'; import React, { Component } from 'react'; -import { UiSettingsClientContract } from 'src/core/public'; import { Field, IndexPattern } from '../../../index_patterns'; import { GenericComboBox, GenericComboBoxProps } from './generic_combo_box'; import { @@ -62,7 +61,6 @@ interface Props { onSubmit: (filter: Filter) => void; onCancel: () => void; intl: InjectedIntl; - uiSettings: UiSettingsClientContract; } interface State { @@ -343,7 +341,6 @@ class FilterEditorUI extends Component { value={this.state.params} onChange={this.onParamsChange} data-test-subj="phraseValueInput" - uiSettings={this.props.uiSettings} /> ); case 'phrases': @@ -353,7 +350,6 @@ class FilterEditorUI extends Component { field={this.state.selectedField} values={this.state.params} onChange={this.onParamsChange} - uiSettings={this.props.uiSettings} /> ); case 'range': diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_suggestor.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_suggestor.tsx index 6b262c66402f2..9ef5f546c0be0 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_suggestor.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_suggestor.tsx @@ -18,14 +18,17 @@ */ import { Component } from 'react'; -import { getSuggestions } from 'ui/value_suggestions'; -import { UiSettingsClientContract } from 'src/core/public'; import { Field, IndexPattern } from '../../../index_patterns'; +import { + withKibana, + KibanaReactContextValue, +} from '../../../../../../../plugins/kibana_react/public'; +import { IDataPluginServices } from '../../../types'; export interface PhraseSuggestorProps { + kibana: KibanaReactContextValue; indexPattern: IndexPattern; field?: Field; - uiSettings: UiSettingsClientContract; } export interface PhraseSuggestorState { @@ -38,10 +41,11 @@ export interface PhraseSuggestorState { * aggregatable), we pull out the common logic for requesting suggestions into this component * which both of them extend. */ -export class PhraseSuggestor extends Component< +export class PhraseSuggestorUI extends Component< T, PhraseSuggestorState > { + private services = this.props.kibana.services; public state: PhraseSuggestorState = { suggestions: [], isLoading: false, @@ -52,7 +56,7 @@ export class PhraseSuggestor extends Component< } protected isSuggestingValues() { - const shouldSuggestValues = this.props.uiSettings.get('filterEditor:suggestValues'); + const shouldSuggestValues = this.services.uiSettings.get('filterEditor:suggestValues'); const { field } = this.props; return shouldSuggestValues && field && field.aggregatable && field.type === 'string'; } @@ -67,7 +71,9 @@ export class PhraseSuggestor extends Component< return; } this.setState({ isLoading: true }); - const suggestions = await getSuggestions(indexPattern.title, field, value); + const suggestions = await this.services.data.getSuggestions(indexPattern.title, field, value); this.setState({ suggestions, isLoading: false }); } } + +export const PhraseSuggestor = withKibana(PhraseSuggestorUI); diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_value_input.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_value_input.tsx index 0696bacc568b5..7ef51f88ba57e 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_value_input.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrase_value_input.tsx @@ -22,8 +22,9 @@ import { InjectedIntl, injectI18n } from '@kbn/i18n/react'; import { uniq } from 'lodash'; import React from 'react'; import { GenericComboBox, GenericComboBoxProps } from './generic_combo_box'; -import { PhraseSuggestor, PhraseSuggestorProps } from './phrase_suggestor'; +import { PhraseSuggestorUI, PhraseSuggestorProps } from './phrase_suggestor'; import { ValueInputType } from './value_input_type'; +import { withKibana } from '../../../../../../../plugins/kibana_react/public'; interface Props extends PhraseSuggestorProps { value?: string; @@ -31,7 +32,7 @@ interface Props extends PhraseSuggestorProps { intl: InjectedIntl; } -class PhraseValueInputUI extends PhraseSuggestor { +class PhraseValueInputUI extends PhraseSuggestorUI { public render() { return ( ) { return GenericComboBox(props); } -export const PhraseValueInput = injectI18n(PhraseValueInputUI); +export const PhraseValueInput = injectI18n(withKibana(PhraseValueInputUI)); diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrases_values_input.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrases_values_input.tsx index d35e49b6b07ce..f3b30e2ad5fd9 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrases_values_input.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_editor/phrases_values_input.tsx @@ -22,7 +22,8 @@ import { InjectedIntl, injectI18n } from '@kbn/i18n/react'; import { uniq } from 'lodash'; import React from 'react'; import { GenericComboBox, GenericComboBoxProps } from './generic_combo_box'; -import { PhraseSuggestor, PhraseSuggestorProps } from './phrase_suggestor'; +import { PhraseSuggestorUI, PhraseSuggestorProps } from './phrase_suggestor'; +import { withKibana } from '../../../../../../../plugins/kibana_react/public'; interface Props extends PhraseSuggestorProps { values?: string[]; @@ -30,7 +31,7 @@ interface Props extends PhraseSuggestorProps { intl: InjectedIntl; } -class PhrasesValuesInputUI extends PhraseSuggestor { +class PhrasesValuesInputUI extends PhraseSuggestorUI { public render() { const { suggestions } = this.state; const { values, intl, onChange } = this.props; @@ -64,4 +65,4 @@ function StringComboBox(props: GenericComboBoxProps) { return GenericComboBox(props); } -export const PhrasesValuesInput = injectI18n(PhrasesValuesInputUI); +export const PhrasesValuesInput = injectI18n(withKibana(PhrasesValuesInputUI)); diff --git a/src/legacy/core_plugins/data/public/plugin.ts b/src/legacy/core_plugins/data/public/plugin.ts index a5aa55673cac6..0ccd80c777d41 100644 --- a/src/legacy/core_plugins/data/public/plugin.ts +++ b/src/legacy/core_plugins/data/public/plugin.ts @@ -126,10 +126,10 @@ export class DataPlugin public start(core: CoreStart, { __LEGACY, data }: DataPluginStartDependencies) { const SearchBar = createSearchBar({ core, + data, store: __LEGACY.storage, timefilter: this.setupApi.timefilter, filterManager: this.setupApi.filter.filterManager, - autocomplete: data.autocomplete, }); return { diff --git a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx index 6c91da7c28135..3086aa2c29f48 100644 --- a/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx +++ b/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_input.tsx @@ -135,7 +135,7 @@ export class QueryBarInputUI extends Component { const recentSearchSuggestions = this.getRecentSearchSuggestions(queryString); - const autocompleteProvider = this.services.autocomplete.getProvider(language); + const autocompleteProvider = this.services.data.autocomplete.getProvider(language); if ( !autocompleteProvider || !Array.isArray(this.state.indexPatterns) || diff --git a/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx index add49e47971d3..84b40d34d474f 100644 --- a/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx @@ -21,7 +21,7 @@ import React from 'react'; import { Filter } from '@kbn/es-query'; import { CoreStart } from 'src/core/public'; import { Storage } from 'ui/storage'; -import { AutocompletePublicPluginStart } from 'src/plugins/data/public'; +import { DataPublicPluginStart } from 'src/plugins/data/public'; import { KibanaContextProvider } from '../../../../../../../../src/plugins/kibana_react/public'; import { TimefilterSetup } from '../../../timefilter'; import { FilterManager, SearchBar } from '../../../'; @@ -29,10 +29,10 @@ import { SearchBarOwnProps } from '.'; interface StatefulSearchBarDeps { core: CoreStart; + data: DataPublicPluginStart; store: Storage; timefilter: TimefilterSetup; filterManager: FilterManager; - autocomplete: AutocompletePublicPluginStart; } export type StatetfulSearchBarProps = SearchBarOwnProps & { @@ -59,7 +59,7 @@ export function createSearchBar({ store, timefilter, filterManager, - autocomplete, + data, }: StatefulSearchBarDeps) { // App name should come from the core application service. // Until it's available, we'll ask the user to provide it for the pre-wired component. @@ -71,7 +71,7 @@ export function createSearchBar({ { appName: string; @@ -27,5 +27,5 @@ export interface IDataPluginServices extends Partial { notifications: CoreStart['notifications']; http: CoreStart['http']; store: Storage; - autocomplete: AutocompletePublicPluginStart; + data: DataPublicPluginStart; } diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js index 389a84babae87..3497a35f5c99d 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js @@ -170,7 +170,7 @@ export class VisEditor extends Component { services={{ appName: APP_NAME, store: localStorage, - autocomplete: npStart.plugins.data.autocomplete, + data: npStart.plugins.data, ...npStart.core, }} > diff --git a/src/legacy/ui/public/vis/editors/default/controls/filter.tsx b/src/legacy/ui/public/vis/editors/default/controls/filter.tsx index cceaf86b5d85c..2c0a2b6be37f8 100644 --- a/src/legacy/ui/public/vis/editors/default/controls/filter.tsx +++ b/src/legacy/ui/public/vis/editors/default/controls/filter.tsx @@ -95,7 +95,7 @@ function FilterRow({ services={{ appName: 'filtersAgg', store: localStorage, - autocomplete: npStart.plugins.data.autocomplete, + data: npStart.plugins.data, ...npStart.core, }} > diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index eb31647767360..a3fa8005560ae 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -20,6 +20,7 @@ import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../../core/public'; import { AutocompleteProviderRegister } from './autocomplete_provider'; import { DataPublicPluginSetup, DataPublicPluginStart } from './types'; +import { getSuggestionsProvider } from './suggestions_provider'; export class DataPublicPlugin implements Plugin { private readonly autocomplete = new AutocompleteProviderRegister(); @@ -35,6 +36,7 @@ export class DataPublicPlugin implements Plugin any; diff --git a/src/legacy/ui/public/value_suggestions/value_suggestions.test.ts b/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts similarity index 83% rename from src/legacy/ui/public/value_suggestions/value_suggestions.test.ts rename to src/plugins/data/public/suggestions_provider/value_suggestions.test.ts index d6d0a7dc003e6..13ccbbd9f3dde 100644 --- a/src/legacy/ui/public/value_suggestions/value_suggestions.test.ts +++ b/src/plugins/data/public/suggestions_provider/value_suggestions.test.ts @@ -17,21 +17,23 @@ * under the License. */ +// TODO: remove when index patterns are moved here. jest.mock('ui/new_platform'); jest.mock('ui/index_patterns'); import { mockFields, mockIndexPattern } from 'ui/index_patterns'; import { getSuggestionsProvider } from './value_suggestions'; +import { UiSettingsClientContract } from 'kibana/public'; describe('getSuggestions', () => { let getSuggestions: any; - let fetch: any; + let http: any; describe('with value suggestions disabled', () => { beforeEach(() => { - const config = { get: () => false }; - fetch = jest.fn(); - getSuggestions = getSuggestionsProvider(config, fetch); + const config = { get: (key: string) => false } as UiSettingsClientContract; + http = { fetch: jest.fn() }; + getSuggestions = getSuggestionsProvider(config, http); }); it('should return an empty array', async () => { @@ -40,15 +42,15 @@ describe('getSuggestions', () => { const query = ''; const suggestions = await getSuggestions(index, field, query); expect(suggestions).toEqual([]); - expect(fetch).not.toHaveBeenCalled(); + expect(http.fetch).not.toHaveBeenCalled(); }); }); describe('with value suggestions enabled', () => { beforeEach(() => { - const config = { get: () => true }; - fetch = jest.fn(); - getSuggestions = getSuggestionsProvider(config, fetch); + const config = { get: (key: string) => true } as UiSettingsClientContract; + http = { fetch: jest.fn() }; + getSuggestions = getSuggestionsProvider(config, http); }); it('should return true/false for boolean fields', async () => { @@ -57,7 +59,7 @@ describe('getSuggestions', () => { const query = ''; const suggestions = await getSuggestions(index, field, query); expect(suggestions).toEqual([true, false]); - expect(fetch).not.toHaveBeenCalled(); + expect(http.fetch).not.toHaveBeenCalled(); }); it('should return an empty array if the field type is not a string or boolean', async () => { @@ -66,7 +68,7 @@ describe('getSuggestions', () => { const query = ''; const suggestions = await getSuggestions(index, field, query); expect(suggestions).toEqual([]); - expect(fetch).not.toHaveBeenCalled(); + expect(http.fetch).not.toHaveBeenCalled(); }); it('should return an empty array if the field is not aggregatable', async () => { @@ -75,7 +77,7 @@ describe('getSuggestions', () => { const query = ''; const suggestions = await getSuggestions(index, field, query); expect(suggestions).toEqual([]); - expect(fetch).not.toHaveBeenCalled(); + expect(http.fetch).not.toHaveBeenCalled(); }); it('should otherwise request suggestions', async () => { @@ -85,7 +87,7 @@ describe('getSuggestions', () => { ); const query = ''; await getSuggestions(index, field, query); - expect(fetch).toHaveBeenCalled(); + expect(http.fetch).toHaveBeenCalled(); }); it('should cache results if using the same index/field/query/filter', async () => { @@ -96,7 +98,7 @@ describe('getSuggestions', () => { const query = ''; await getSuggestions(index, field, query); await getSuggestions(index, field, query); - expect(fetch).toHaveBeenCalledTimes(1); + expect(http.fetch).toHaveBeenCalledTimes(1); }); it('should cache results for only one minute', async () => { @@ -113,7 +115,7 @@ describe('getSuggestions', () => { await getSuggestions(index, field, query); Date.now = now; - expect(fetch).toHaveBeenCalledTimes(2); + expect(http.fetch).toHaveBeenCalledTimes(2); }); it('should not cache results if using a different index/field/query', async () => { @@ -128,7 +130,7 @@ describe('getSuggestions', () => { await getSuggestions('logstash-*', fields[0], 'query'); await getSuggestions('logstash-*', fields[1], ''); await getSuggestions('logstash-*', fields[1], 'query'); - expect(fetch).toHaveBeenCalledTimes(8); + expect(http.fetch).toHaveBeenCalledTimes(8); }); }); }); diff --git a/src/legacy/ui/public/value_suggestions/value_suggestions.ts b/src/plugins/data/public/suggestions_provider/value_suggestions.ts similarity index 82% rename from src/legacy/ui/public/value_suggestions/value_suggestions.ts rename to src/plugins/data/public/suggestions_provider/value_suggestions.ts index 31e42e9945ede..03eaa5d9594d2 100644 --- a/src/legacy/ui/public/value_suggestions/value_suggestions.ts +++ b/src/plugins/data/public/suggestions_provider/value_suggestions.ts @@ -18,16 +18,17 @@ */ import { memoize } from 'lodash'; -import { Field } from 'ui/index_patterns'; + +import { UiSettingsClientContract, HttpServiceBase } from 'src/core/public'; +import { IGetSuggestions, Field } from './types'; export function getSuggestionsProvider( - config: { get: (key: string) => any }, - fetch: (...options: any[]) => any -) { + uiSettings: UiSettingsClientContract, + http: HttpServiceBase +): IGetSuggestions { const requestSuggestions = memoize( (index: string, field: Field, query: string, boolFilter: any = []) => { - return fetch({ - pathname: `/api/kibana/suggestions/values/${index}`, + return http.fetch(`/api/kibana/suggestions/values/${index}`, { method: 'POST', body: JSON.stringify({ query, field: field.name, boolFilter }), }); @@ -36,7 +37,7 @@ export function getSuggestionsProvider( ); return async (index: string, field: Field, query: string, boolFilter?: any) => { - const shouldSuggestValues = config.get('filterEditor:suggestValues'); + const shouldSuggestValues = uiSettings.get('filterEditor:suggestValues'); if (field.type === 'boolean') { return [true, false]; } else if (!shouldSuggestValues || !field.aggregatable || field.type !== 'string') { diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index 23308304b8ff8..70406b4dc0c0a 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -20,10 +20,14 @@ export * from './autocomplete_provider/types'; import { AutocompletePublicPluginSetup, AutocompletePublicPluginStart } from '.'; +import { IGetSuggestions } from './suggestions_provider/types'; export interface DataPublicPluginSetup { autocomplete: AutocompletePublicPluginSetup; } export interface DataPublicPluginStart { autocomplete: AutocompletePublicPluginStart; + getSuggestions: IGetSuggestions; } + +export { IGetSuggestions } from './suggestions_provider/types'; diff --git a/x-pack/legacy/plugins/graph/public/angular/templates/index.html b/x-pack/legacy/plugins/graph/public/angular/templates/index.html index 3ed9b390c6a78..bbb1eb161f839 100644 --- a/x-pack/legacy/plugins/graph/public/angular/templates/index.html +++ b/x-pack/legacy/plugins/graph/public/angular/templates/index.html @@ -15,7 +15,7 @@ initial-query="initialQuery" state="reduxState" dispatch="reduxDispatch" - autocomplete-start="autocompleteStart" + plugin-data-start="pluginDataStart" core-start="coreStart" store="store" > diff --git a/x-pack/legacy/plugins/graph/public/app.js b/x-pack/legacy/plugins/graph/public/app.js index aa8f0be6231df..0b902dfe6a9d3 100644 --- a/x-pack/legacy/plugins/graph/public/app.js +++ b/x-pack/legacy/plugins/graph/public/app.js @@ -116,7 +116,7 @@ app.directive('graphApp', function (reactDirective) { ['onIndexPatternSelected', { watchDepth: 'reference' }], ['onQuerySubmit', { watchDepth: 'reference' }], ['initialQuery', { watchDepth: 'reference' }], - ['autocompleteStart', { watchDepth: 'reference' }], + ['pluginDataStart', { watchDepth: 'reference' }], ['coreStart', { watchDepth: 'reference' }], ['store', { watchDepth: 'reference' }] ]); @@ -305,7 +305,7 @@ app.controller('graphuiPlugin', function ( $scope.store = new Storage(window.localStorage); $scope.coreStart = npStart.core; - $scope.autocompleteStart = npStart.plugins.data.autocomplete; + $scope.pluginDataStart = npStart.plugins.data; $scope.loading = false; const updateScope = () => { diff --git a/x-pack/legacy/plugins/graph/public/components/app.tsx b/x-pack/legacy/plugins/graph/public/components/app.tsx index 907e7e4cecdcd..fe17e6c3f587b 100644 --- a/x-pack/legacy/plugins/graph/public/components/app.tsx +++ b/x-pack/legacy/plugins/graph/public/components/app.tsx @@ -8,7 +8,7 @@ import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import React from 'react'; import { Storage } from 'ui/storage'; import { CoreStart } from 'kibana/public'; -import { AutocompletePublicPluginStart } from 'src/plugins/data/public'; +import { DataPublicPluginStart } from 'src/plugins/data/public'; import { FieldManagerProps, FieldManager } from './field_manager'; import { SearchBarProps, SearchBar } from './search_bar'; @@ -16,7 +16,8 @@ import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_reac export interface GraphAppProps extends FieldManagerProps, SearchBarProps { coreStart: CoreStart; - autocompleteStart: AutocompletePublicPluginStart; + // This is not named dataStart because of Angular treating data- prefix differently + pluginDataStart: DataPublicPluginStart; store: Storage; } @@ -26,7 +27,7 @@ export function GraphApp(props: GraphAppProps) { services={{ appName: 'graph', store: props.store, - autocomplete: props.autocompleteStart, + data: props.pluginDataStart, ...props.coreStart, }} > diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.js b/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.js index 36fb77a30acd0..c870c899a3151 100644 --- a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.js +++ b/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.js @@ -6,7 +6,7 @@ import { flatten } from 'lodash'; import { escapeQuotes } from './escape_kuery'; -import { getSuggestions } from 'ui/value_suggestions'; +import { npStart } from 'ui/new_platform'; const type = 'value'; @@ -31,7 +31,7 @@ export function getSuggestionsProvider({ indexPatterns, boolFilter }) { const query = `${prefix}${suffix}`; const suggestionsByField = fields.map(field => { - return getSuggestions(field.indexPatternTitle, field, query, boolFilter).then(data => { + return npStart.data.getSuggestions(field.indexPatternTitle, field, query, boolFilter).then(data => { const quotedValues = data.map(value => typeof value === 'string' ? `"${escapeQuotes(value)}"` : `${value}`); return wrapAsSuggestions(start, end, query, quotedValues); }); diff --git a/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx b/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx index 9c484e19789e9..a91462171abf7 100644 --- a/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx +++ b/x-pack/legacy/plugins/lens/public/app_plugin/app.tsx @@ -160,7 +160,7 @@ export function App({ From d08b938dae8d96e31b18be1fbf3f5ae23c55bc76 Mon Sep 17 00:00:00 2001 From: Liza K Date: Wed, 2 Oct 2019 23:27:54 +0300 Subject: [PATCH 26/32] ts fixes --- .../core_plugins/data/public/filter/filter_bar/filter_bar.tsx | 1 - .../core_plugins/data/public/filter/filter_bar/filter_item.tsx | 1 - src/plugins/data/public/mocks.ts | 1 + 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_bar.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_bar.tsx index 90dec12fb814d..0d00b7eca40e1 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_bar.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_bar.tsx @@ -120,7 +120,6 @@ function FilterBarUI(props: Props) { onSubmit={onAdd} onCancel={() => setIsAddFilterPopoverOpen(false)} key={JSON.stringify(newFilter)} - uiSettings={uiSettings!} />
diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_item.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_item.tsx index 250f6ad209fa7..21259cec51d3a 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_item.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_item.tsx @@ -171,7 +171,6 @@ class FilterItemUI extends Component { indexPatterns={this.props.indexPatterns} onSubmit={this.onSubmit} onCancel={this.closePopover} - uiSettings={this.props.uiSettings} />
), diff --git a/src/plugins/data/public/mocks.ts b/src/plugins/data/public/mocks.ts index df5b68ac409a0..b2d311912b982 100644 --- a/src/plugins/data/public/mocks.ts +++ b/src/plugins/data/public/mocks.ts @@ -38,6 +38,7 @@ const createSetupContract = (): Setup => { const createStartContract = (): Start => { const startContract: Start = { autocomplete: autocompleteMock as Start['autocomplete'], + getSuggestions: jest.fn(), }; return startContract; }; From fff2186de676a7ffa066efbc5a60b2ceac177d03 Mon Sep 17 00:00:00 2001 From: Liza K Date: Wed, 2 Oct 2019 23:51:34 +0300 Subject: [PATCH 27/32] Added karma getSuggestions fake --- src/legacy/ui/public/new_platform/new_platform.karma_mock.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js index 29868dc9767dc..bbfa8bd329c65 100644 --- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js +++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js @@ -65,7 +65,9 @@ export const npStart = { registerRenderer: sinon.fake(), registerType: sinon.fake(), }, - data: {}, + data: { + getSuggestions: sinon.fake(), + }, inspector: { isAvailable: () => false, open: () => ({ From 64f4566ee24b863f4d71bc212d78a951fdba4a8b Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 3 Oct 2019 13:50:52 +0300 Subject: [PATCH 28/32] Refactored kuery autocomplete tests to jest --- .../autocomplete_providers/__tests__/value.js | 103 -------------- .../public/autocomplete_providers/value.js | 3 +- .../autocomplete_providers/value.test.js | 131 ++++++++++++++++++ 3 files changed, 133 insertions(+), 104 deletions(-) delete mode 100644 x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/__tests__/value.js create mode 100644 x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.test.js diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/__tests__/value.js b/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/__tests__/value.js deleted file mode 100644 index 8524b1c890f5f..0000000000000 --- a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/__tests__/value.js +++ /dev/null @@ -1,103 +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 expect from '@kbn/expect'; -import sinon from 'sinon'; -import fetchMock from 'fetch-mock'; -import { getSuggestionsProvider } from '../value'; -import indexPatternResponse from '../__fixtures__/index_pattern_response.json'; - -describe('Kuery value suggestions', function () { - let config; - let indexPatterns; - let getSuggestions; - - const mockValues = ['foo', 'bar']; - const fetchUrlMatcher = /\/api\/kibana\/suggestions\/values\/*/; - - beforeEach(() => fetchMock.post(fetchUrlMatcher, mockValues)); - afterEach(() => fetchMock.restore()); - - beforeEach(() => { - config = getConfigStub(true); - indexPatterns = [indexPatternResponse]; - getSuggestions = getSuggestionsProvider({ config, indexPatterns }); - }); - - it('should return a function', function () { - expect(typeof getSuggestions).to.be('function'); - }); - - it('should return boolean suggestions for boolean fields', async () => { - const fieldName = 'ssl'; - const prefix = ''; - const suffix = ''; - const suggestions = await getSuggestions({ fieldName, prefix, suffix }); - expect(suggestions.map(({ text }) => text)).to.eql(['true ', 'false ']); - }); - - it('should filter boolean suggestions for boolean fields', async () => { - const fieldName = 'ssl'; - const prefix = 'fa'; - const suffix = ''; - const suggestions = await getSuggestions({ fieldName, prefix, suffix }); - expect(suggestions.map(({ text }) => text)).to.eql(['false ']); - }); - - it('should not make a request for non-aggregatable fields', async () => { - const fieldName = 'non-sortable'; - const prefix = ''; - const suffix = ''; - const suggestions = await getSuggestions({ fieldName, prefix, suffix }); - expect(fetchMock.called(fetchUrlMatcher)).to.be(false); - expect(suggestions).to.eql([]); - }); - - it('should not make a request for non-string fields', async () => { - const fieldName = 'bytes'; - const prefix = ''; - const suffix = ''; - const suggestions = await getSuggestions({ fieldName, prefix, suffix }); - expect(fetchMock.called(fetchUrlMatcher)).to.be(false); - expect(suggestions).to.eql([]); - }); - - it('should make a request for string fields', async () => { - const fieldName = 'machine.os.raw'; - const prefix = ''; - const suffix = ''; - const suggestions = await getSuggestions({ fieldName, prefix, suffix }); - - const lastCall = fetchMock.lastCall(fetchUrlMatcher, 'POST'); - - expect(lastCall.request._bodyInit, '{"query":"","field":"machine.os.raw","boolFilter":[]}'); - expect(lastCall[0]).to.match(/\/api\/kibana\/suggestions\/values\/logstash-\*/); - expect(lastCall[1]).to.eql({ - method: 'POST', - headers: { - 'content-type': 'application/json', - 'kbn-version': '1.2.3', - }, - }); - expect(suggestions.map(({ text }) => text)).to.eql(['"foo" ', '"bar" ']); - }); - - it('should not have descriptions', async () => { - const fieldName = 'ssl'; - const prefix = ''; - const suffix = ''; - const suggestions = await getSuggestions({ fieldName, prefix, suffix }); - expect(suggestions.length).to.be.greaterThan(0); - suggestions.forEach(suggestion => { - expect(suggestion.description).to.not.be.ok(); - }); - }); -}); - -function getConfigStub(suggestValues) { - const get = sinon.stub().returns(suggestValues); - return { get }; -} diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.js b/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.js index c870c899a3151..66e62e884e9b3 100644 --- a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.js +++ b/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.js @@ -29,9 +29,10 @@ export function getSuggestionsProvider({ indexPatterns, boolFilter }) { }) { const fields = allFields.filter(field => field.name === fieldName); const query = `${prefix}${suffix}`; + const { getSuggestions } = npStart.plugins.data; const suggestionsByField = fields.map(field => { - return npStart.data.getSuggestions(field.indexPatternTitle, field, query, boolFilter).then(data => { + return getSuggestions(field.indexPatternTitle, field, query, boolFilter).then(data => { const quotedValues = data.map(value => typeof value === 'string' ? `"${escapeQuotes(value)}"` : `${value}`); return wrapAsSuggestions(start, end, query, quotedValues); }); diff --git a/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.test.js b/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.test.js new file mode 100644 index 0000000000000..c59917ebdc3bf --- /dev/null +++ b/x-pack/legacy/plugins/kuery_autocomplete/public/autocomplete_providers/value.test.js @@ -0,0 +1,131 @@ +/* + * 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 { getSuggestionsProvider } from './value'; +import indexPatternResponse from './__fixtures__/index_pattern_response.json'; + +import { npStart } from 'ui/new_platform'; + +jest.mock('ui/new_platform', () => ({ + npStart: { + plugins: { + data: { + getSuggestions: (_, field) => { + let res; + if (field.type === 'boolean') { + res = [true, false]; + } else if (field.name === 'machine.os') { + res = ['Windo"ws', 'Mac\'', 'Linux']; + } else { + res = []; + } + return Promise.resolve(res); + } + }, + } + } +})); + + +describe('Kuery value suggestions', function () { + let indexPatterns; + let getSuggestions; + + beforeEach(() => { + indexPatterns = [indexPatternResponse]; + getSuggestions = getSuggestionsProvider({ indexPatterns }); + jest.clearAllMocks(); + }); + + test('should return a function', function () { + expect(typeof getSuggestions).toBe('function'); + }); + + test('should not search for non existing field', async () => { + const fieldName = 'i_dont_exist'; + const prefix = ''; + const suffix = ''; + const spy = jest.spyOn(npStart.plugins.data, 'getSuggestions'); + const suggestions = await getSuggestions({ fieldName, prefix, suffix }); + expect(suggestions.map(({ text }) => text)).toEqual([]); + expect(spy).toHaveBeenCalledTimes(0); + }); + + + test('should format suggestions', async () => { + const fieldName = 'ssl'; // Has results with quotes in mock + const prefix = ''; + const suffix = ''; + const start = 1; + const end = 5; + const suggestions = await getSuggestions({ fieldName, prefix, suffix, start, end }); + expect(suggestions[0].type).toEqual('value'); + expect(suggestions[0].start).toEqual(start); + expect(suggestions[0].end).toEqual(end); + }); + + describe('Boolean suggestions', function () { + test('should stringify boolean fields', async () => { + const fieldName = 'ssl'; + const prefix = ''; + const suffix = ''; + const spy = jest.spyOn(npStart.plugins.data, 'getSuggestions'); + const suggestions = await getSuggestions({ fieldName, prefix, suffix }); + expect(suggestions.map(({ text }) => text)).toEqual(['true ', 'false ']); + expect(spy).toHaveBeenCalledTimes(1); + }); + + test('should filter out boolean suggestions', async () => { + const fieldName = 'ssl'; // Has results with quotes in mock + const prefix = 'fa'; + const suffix = ''; + const suggestions = await getSuggestions({ fieldName, prefix, suffix }); + expect(suggestions.length).toEqual(1); + }); + + }); + + + describe('String suggestions', function () { + test('should merge prefix and suffix', async () => { + const fieldName = 'machine.os.raw'; + const prefix = 'he'; + const suffix = 'llo'; + const spy = jest.spyOn(npStart.plugins.data, 'getSuggestions'); + await getSuggestions({ fieldName, prefix, suffix }); + expect(spy).toHaveBeenCalledTimes(1); + expect(spy).toBeCalledWith(expect.any(String), expect.any(Object), prefix + suffix, undefined); + }); + + test('should escape quotes in suggestions', async () => { + const fieldName = 'machine.os'; // Has results with quotes in mock + const prefix = ''; + const suffix = ''; + const suggestions = await getSuggestions({ fieldName, prefix, suffix }); + expect(suggestions[0].text).toEqual('"Windo\\"ws" '); + expect(suggestions[1].text).toEqual('"Mac\'" '); + expect(suggestions[2].text).toEqual('"Linux" '); + }); + + test('should filter out string suggestions', async () => { + const fieldName = 'machine.os'; // Has results with quotes in mock + const prefix = 'banana'; + const suffix = ''; + const suggestions = await getSuggestions({ fieldName, prefix, suffix }); + expect(suggestions.length).toEqual(0); + }); + + test('should partially filter out string suggestions - case insensitive', async () => { + const fieldName = 'machine.os'; // Has results with quotes in mock + const prefix = 'ma'; + const suffix = ''; + const suggestions = await getSuggestions({ fieldName, prefix, suffix }); + expect(suggestions.length).toEqual(1); + }); + }); + + +}); From a992310d7cd598b033aa17949c8eb9b5d697f614 Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 3 Oct 2019 14:35:26 +0300 Subject: [PATCH 29/32] Filter bar context for directives --- .../public/filter/filter_bar/filter_bar.tsx | 46 +++++++++++++++---- .../data/public/shim/legacy_module.ts | 13 ++++-- 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_bar.tsx b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_bar.tsx index 0d00b7eca40e1..066adb1e3275e 100644 --- a/src/legacy/core_plugins/data/public/filter/filter_bar/filter_bar.tsx +++ b/src/legacy/core_plugins/data/public/filter/filter_bar/filter_bar.tsx @@ -31,12 +31,13 @@ import { import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; import classNames from 'classnames'; import React, { useState } from 'react'; -import { UiSettingsClientContract } from 'src/core/public'; +import { CoreStart } from 'src/core/public'; +import { DataPublicPluginStart } from 'src/plugins/data/public'; import { IndexPattern } from '../../index_patterns'; import { FilterEditor } from './filter_editor'; import { FilterItem } from './filter_item'; import { FilterOptions } from './filter_options'; -import { useKibana } from '../../../../../../plugins/kibana_react/public'; +import { useKibana, KibanaContextProvider } from '../../../../../../plugins/kibana_react/public'; interface Props { filters: Filter[]; @@ -45,18 +46,45 @@ interface Props { indexPatterns: IndexPattern[]; intl: InjectedIntl; - // Only for directives! - uiSettings?: UiSettingsClientContract; + // TODO: Only for filter-bar directive! + uiSettings?: CoreStart['uiSettings']; + docLinks?: CoreStart['docLinks']; + pluginDataStart?: DataPublicPluginStart; } function FilterBarUI(props: Props) { const [isAddFilterPopoverOpen, setIsAddFilterPopoverOpen] = useState(false); const kibana = useKibana(); - let { uiSettings } = kibana.services; - if (!uiSettings) { - // Only for directives! - uiSettings = props.uiSettings; + const uiSettings = kibana.services.uiSettings || props.uiSettings; + if (!uiSettings) return null; + + function hasContext() { + return Boolean(kibana.services.uiSettings); + } + + function wrapInContextIfMissing(content: JSX.Element) { + // TODO: Relevant only as long as directives are used! + if (!hasContext()) { + if (props.docLinks && props.uiSettings && props.pluginDataStart) { + return ( + + {content} + + ); + } else { + throw new Error( + 'Rending filter bar requires providing sufficient context: uiSettings, docLinks and NP data plugin' + ); + } + } + return content; } function onFiltersUpdated(filters: Filter[]) { @@ -100,7 +128,7 @@ function FilterBarUI(props: Props) { ); - return ( + return wrapInContextIfMissing( { } child.setAttribute('ui-settings', 'uiSettings'); - child.setAttribute('http', 'http'); + child.setAttribute('doc-links', 'docLinks'); + child.setAttribute('plugin-data-start', 'pluginDataStart'); // Append helper directive elem.append(child); const linkFn = ($scope: any) => { - $scope.uiSettings = npSetup.core.uiSettings; - $scope.http = npSetup.core.http; + $scope.uiSettings = npStart.core.uiSettings; + $scope.docLinks = npStart.core.docLinks; + $scope.pluginDataStart = npStart.plugins.data; }; return linkFn; @@ -66,11 +68,12 @@ export const initLegacyModule = once((): void => { .directive('filterBarHelper', (reactDirective: any) => { return reactDirective(wrapInI18nContext(FilterBar), [ ['uiSettings', { watchDepth: 'reference' }], - ['http', { watchDepth: 'reference' }], + ['docLinks', { watchDepth: 'reference' }], ['onFiltersUpdated', { watchDepth: 'reference' }], ['indexPatterns', { watchDepth: 'collection' }], ['filters', { watchDepth: 'collection' }], ['className', { watchDepth: 'reference' }], + ['pluginDataStart', { watchDepth: 'reference' }], ]); }) .directive('applyFiltersPopoverComponent', (reactDirective: any) => From 03cd33c8c5c2b3cc969ab383507fca3e240b9d91 Mon Sep 17 00:00:00 2001 From: Liza K Date: Thu, 3 Oct 2019 16:21:38 +0300 Subject: [PATCH 30/32] updated snapshot --- .../layer_panel/__snapshots__/view.test.js.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap index 4c9ef61478ab4..c3d4ff673e3d5 100644 --- a/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap +++ b/x-pack/legacy/plugins/maps/public/connected_components/layer_panel/__snapshots__/view.test.js.snap @@ -5,7 +5,7 @@ exports[`LayerPanel is rendered 1`] = ` services={ Object { "appName": "maps", - "autocomplete": undefined, + "data": undefined, "store": Storage { "clear": [Function], "get": [Function], From d7e3cd43e51343ccc7e0f63effe33553d592e091 Mon Sep 17 00:00:00 2001 From: Liza K Date: Sun, 6 Oct 2019 15:23:39 +0300 Subject: [PATCH 31/32] fix diffs --- .../legacy/plugins/graph/public/angular/templates/index.html | 4 +--- x-pack/legacy/plugins/graph/public/app.js | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/x-pack/legacy/plugins/graph/public/angular/templates/index.html b/x-pack/legacy/plugins/graph/public/angular/templates/index.html index 1066046029528..e291271bb1d6c 100644 --- a/x-pack/legacy/plugins/graph/public/angular/templates/index.html +++ b/x-pack/legacy/plugins/graph/public/angular/templates/index.html @@ -16,10 +16,8 @@ is-loading="loading" is-initialized="workspaceInitialized || savedWorkspace.id" initial-query="initialQuery" - state="reduxState" - dispatch="reduxDispatch" - plugin-data-start="pluginDataStart" on-fill-workspace="fillWorkspace" + plugin-data-start="pluginDataStart" core-start="coreStart" store="store" > diff --git a/x-pack/legacy/plugins/graph/public/app.js b/x-pack/legacy/plugins/graph/public/app.js index 5bbabaf03c330..4e33d0995cbc8 100644 --- a/x-pack/legacy/plugins/graph/public/app.js +++ b/x-pack/legacy/plugins/graph/public/app.js @@ -105,10 +105,10 @@ app.directive('graphApp', function (reactDirective) { ['isLoading', { watchDepth: 'reference' }], ['onQuerySubmit', { watchDepth: 'reference' }], ['initialQuery', { watchDepth: 'reference' }], - ['pluginDataStart', { watchDepth: 'reference' }], - ['store', { watchDepth: 'reference' }], ['confirmWipeWorkspace', { watchDepth: 'reference' }], ['coreStart', { watchDepth: 'reference' }], + ['pluginDataStart', { watchDepth: 'reference' }], + ['store', { watchDepth: 'reference' }], ['reduxStore', { watchDepth: 'reference' }], ]); }); From 0d983f5b780a829fecee9484baa55ab84184a9ed Mon Sep 17 00:00:00 2001 From: Liza K Date: Sun, 6 Oct 2019 16:04:04 +0300 Subject: [PATCH 32/32] fixed lens test --- x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx b/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx index af44325c6e570..9c4b0fa737428 100644 --- a/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx +++ b/x-pack/legacy/plugins/lens/public/app_plugin/app.test.tsx @@ -230,7 +230,7 @@ describe('Lens App', () => { await waitForPromises(); expect(args.docStorage.load).toHaveBeenCalledWith('1234'); - expect(args.data.indexPatterns.indexPatterns.get).toHaveBeenCalledWith('1'); + expect(args.dataShim.indexPatterns.indexPatterns.get).toHaveBeenCalledWith('1'); expect(TopNavMenu).toHaveBeenCalledWith( expect.objectContaining({ query: 'fake query', @@ -498,7 +498,7 @@ describe('Lens App', () => { const instance = mount(); - args.data.filter.filterManager.setFilters([ + args.dataShim.filter.filterManager.setFilters([ buildExistsFilter({ name: 'myfield' }, { id: 'index1' }), ]); @@ -629,7 +629,7 @@ describe('Lens App', () => { query: { query: 'new', language: 'lucene' }, }); - args.data.filter.filterManager.setFilters([ + args.dataShim.filter.filterManager.setFilters([ buildExistsFilter({ name: 'myfield' }, { id: 'index1' }), ]); instance.update();