diff --git a/src/legacy/core_plugins/data/public/legacy.ts b/src/legacy/core_plugins/data/public/legacy.ts index c3618d412f425..80104fc1991b0 100644 --- a/src/legacy/core_plugins/data/public/legacy.ts +++ b/src/legacy/core_plugins/data/public/legacy.ts @@ -45,4 +45,7 @@ export const setup = dataPlugin.setup(npSetup.core, { __LEGACY: legacyPlugin.setup(), }); -export const start = dataPlugin.start(npStart.core); +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 aec97b02bc2b9..a5aa55673cac6 100644 --- a/src/legacy/core_plugins/data/public/plugin.ts +++ b/src/legacy/core_plugins/data/public/plugin.ts @@ -18,12 +18,16 @@ */ import { CoreSetup, CoreStart, Plugin } from '../../../../core/public'; -import { SearchService, SearchSetup } from './search'; +import { SearchService, SearchSetup, createSearchBar, StatetfulSearchBarProps } 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'; +import { DataPublicPluginStart } from '../../../../plugins/data/public'; /** * Interface for any dependencies on other plugins' `setup` contracts. @@ -34,6 +38,11 @@ export interface DataPluginSetupDependencies { __LEGACY: LegacyDependenciesPluginSetup; } +export interface DataPluginStartDependencies { + data: DataPublicPluginStart; + __LEGACY: LegacyDependenciesPluginStart; +} + /** * Interface for this plugin's returned `setup` contract. * @@ -47,6 +56,22 @@ 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: { + SearchBar: React.ComponentType; + }; +} + /** * Data Plugin - public * @@ -58,7 +83,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(); @@ -96,9 +123,20 @@ export class DataPlugin implements Plugin + - -
+ -
-
- + - + -
- - - - -
- - - - + 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..a66fb682063ec 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 = { + screenTitle: 'Another Screen', + intl: null as any, + }; + + const services = { + appName: testProps.appName || 'test', + 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..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 @@ -23,19 +23,17 @@ 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 { 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,21 +41,13 @@ 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'; - -// todo: related to https://github.com/elastic/kibana/pull/45762/files -// Will be refactored after merge of related PR -const getAutocompleteProvider = (language: string) => - npStart.plugins.data.autocomplete.getProvider(language); +import { IDataPluginServices } from '../../../types'; interface Props { - uiSettings: UiSettingsClientContract; - indexPatterns: Array; - savedObjectsClient: SavedObjectsClientContract; - http: HttpServiceBase; - store: Storage; + kibana: KibanaReactContextValue; intl: InjectedIntl; + indexPatterns: Array; query: Query; - appName: string; disableAutoFocus?: boolean; screenTitle?: string; prepend?: React.ReactNode; @@ -67,6 +57,7 @@ interface Props { languageSwitcherPopoverAnchorPosition?: PopoverAnchorPosition; onChange?: (query: Query) => void; onSubmit?: (query: Query) => void; + dataTestSubj?: string; } interface State { @@ -107,6 +98,7 @@ export class QueryBarInputUI extends Component { public inputRef: HTMLInputElement | null = null; private persistedLog: PersistedLog | undefined; + private services = this.props.kibana.services; private componentIsUnmounting = false; private getQueryString = () => { @@ -122,9 +114,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,13 +129,13 @@ 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(); const recentSearchSuggestions = this.getRecentSearchSuggestions(queryString); - const autocompleteProvider = getAutocompleteProvider(language); + const autocompleteProvider = this.services.autocomplete.getProvider(language); if ( !autocompleteProvider || !Array.isArray(this.state.indexPatterns) || @@ -369,11 +361,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); @@ -406,7 +398,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.services.appName, this.props.query.language); this.fetchIndexPatterns().then(this.updateSuggestions); } @@ -419,7 +411,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.services.appName, this.props.query.language); if (!isEqual(prevProps.indexPatterns, this.props.indexPatterns)) { this.fetchIndexPatterns().then(this.updateSuggestions); @@ -446,24 +438,6 @@ export class QueryBarInputUI extends Component { } public render() { - const rest = omit(this.props, [ - 'indexPatterns', - 'intl', - 'query', - 'appName', - 'disableAutoFocus', - 'screenTitle', - 'prepend', - 'store', - 'persistedLog', - 'bubbleSubmitEvent', - 'languageSwitcherPopoverAnchorPosition', - 'onChange', - 'onSubmit', - 'uiSettings', - 'savedObjectsClient', - ]); - return (
{ }, { previouslyTranslatedPageTitle: this.props.screenTitle, - pageType: this.props.appName, + pageType: this.services.appName, } ) : undefined } type="text" - data-test-subj="queryInput" aria-autocomplete="list" aria-controls="kbnTypeahead__items" aria-activedescendant={ @@ -529,7 +502,7 @@ export class QueryBarInputUI extends Component { onSelectLanguage={this.onSelectLanguage} /> } - {...rest} + data-test-subj={this.props.dataTestSubj || 'queryInput'} />
@@ -548,4 +521,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..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'; @@ -97,42 +96,49 @@ const mockIndexPattern = { ], } as IndexPattern; -describe('QueryBarTopRowTopRow', () => { - const QUERY_INPUT_SELECTOR = 'InjectIntl(QueryBarInputUI)'; - const TIMEPICKER_SELECTOR = 'EuiSuperDatePicker'; +function wrapQueryBarTopRowInContext(testProps: any) { + const defaultOptions = { + screenTitle: 'Another Screen', + onSubmit: noop, + onChange: noop, + intl: null as any, + }; + const services = { + appName: 'discover', uiSettings: startMock.uiSettings, savedObjects: startMock.savedObjects, notifications: startMock.notifications, http: startMock.http, - }; - const defaultOptions = { - appName: 'discover', - screenTitle: 'Another Screen', - onSubmit: noop, - onChange: noop, store: createMockStorage(), - intl: null as any, }; + 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 +147,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 +162,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 +174,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 +187,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 +203,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 +221,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 +238,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 c25b596973174..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'; @@ -30,6 +29,7 @@ import { EuiButton, EuiFlexGroup, EuiFlexItem, EuiLink, EuiSuperDatePicker } fro import { EuiSuperUpdateButton } from '@elastic/eui'; import { FormattedMessage, InjectedIntl, injectI18n } from '@kbn/i18n/react'; import { Toast } from 'src/core/public'; +import { TimeRange } from 'src/plugins/data/public'; import { useKibana } from '../../../../../../../plugins/kibana_react/public'; import { IndexPattern } from '../../../index_patterns'; @@ -37,21 +37,15 @@ import { QueryBarInput } from './query_bar_input'; import { getQueryLog } from '../lib/get_query_log'; import { Query } from '../index'; import { TimeHistoryContract } from '../../../timefilter'; - -interface DateRange { - from: string; - to: string; -} +import { IDataPluginServices } from '../../../types'; interface Props { query?: Query; - onSubmit: (payload: { dateRange: DateRange; query?: Query }) => 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; indexPatterns?: Array; - store?: Storage; intl: InjectedIntl; prepend?: React.ReactNode; showQueryInput?: boolean; @@ -70,15 +64,15 @@ interface Props { function QueryBarTopRowUI(props: Props) { const [isDateRangeInvalid, setIsDateRangeInvalid] = useState(false); - const kibana = useKibana(); - const { uiSettings, http, notifications, savedObjects } = 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) { @@ -131,7 +125,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) { @@ -153,19 +147,14 @@ function QueryBarTopRowUI(props: Props) { return ( ); @@ -176,7 +165,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() { @@ -251,7 +240,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' && @@ -300,8 +289,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/create_search_bar.tsx b/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx new file mode 100644 index 0000000000000..add49e47971d3 --- /dev/null +++ b/src/legacy/core_plugins/data/public/search/search_bar/components/create_search_bar.tsx @@ -0,0 +1,93 @@ +/* + * 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 { AutocompletePublicPluginStart } from 'src/plugins/data/public'; +import { KibanaContextProvider } from '../../../../../../../../src/plugins/kibana_react/public'; +import { TimefilterSetup } from '../../../timefilter'; +import { FilterManager, SearchBar } from '../../../'; +import { SearchBarOwnProps } from '.'; + +interface StatefulSearchBarDeps { + core: CoreStart; + store: Storage; + timefilter: TimefilterSetup; + filterManager: FilterManager; + autocomplete: AutocompletePublicPluginStart; +} + +export type StatetfulSearchBarProps = SearchBarOwnProps & { + appName: string; +}; + +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, + store, + timefilter, + filterManager, + autocomplete, +}: 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: StatetfulSearchBarProps) => { + const timeRange = timefilter.timefilter.getTime(); + const refreshInterval = timefilter.timefilter.getRefreshInterval(); + + return ( + + + + ); + }; +} 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..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,3 +18,4 @@ */ export * from './search_bar'; +export * from './create_search_bar'; 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..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 @@ -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', () => { @@ -41,13 +44,6 @@ jest.mock('../../../query/query_bar', () => { }; }); -jest.mock('ui/notify', () => ({ - toastNotifications: { - addSuccess: () => {}, - addDanger: () => {}, - }, -})); - const noop = jest.fn(); const createMockWebStorage = () => ({ @@ -87,26 +83,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 +129,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 +142,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 +157,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 +173,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 +188,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 +204,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 6c73fa3614cc3..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 @@ -22,10 +22,9 @@ 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'; import { SavedQuery, SavedQueryAttributes } from '../index'; @@ -34,54 +33,52 @@ 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'; - -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; +import { + withKibana, + KibanaReactContextValue, +} from '../../../../../../../plugins/kibana_react/public'; +import { IDataPluginServices } from '../../../types'; + +interface SearchBarInjectedDeps { + kibana: KibanaReactContextValue; 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; +} + +export interface SearchBarOwnProps { + 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; @@ -102,7 +99,7 @@ class SearchBarUI extends Component { }; private savedQueryService!: SavedQueryService; - + private services = this.props.kibana.services; public filterBarRef: Element | null = null; public filterBarWrapperRef: Element | null = null; @@ -253,7 +250,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` ); @@ -266,7 +263,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; @@ -285,7 +282,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 +290,7 @@ class SearchBarUI extends Component { }); }; - public onQueryBarSubmit = (queryAndDateRange: { dateRange?: DateRange; query?: Query }) => { + public onQueryBarSubmit = (queryAndDateRange: { dateRange?: TimeRange; query?: Query }) => { this.setState( { query: queryAndDateRange.query, @@ -337,8 +334,8 @@ class SearchBarUI extends Component { this.setFilterBarHeight(); this.ro.observe(this.filterBarRef); } - if (this.props.savedObjects) { - this.savedQueryService = createSavedQueryService(this.props.savedObjects!.client); + if (this.services.savedObjects) { + this.savedQueryService = createSavedQueryService(this.services.savedObjects.client); } } @@ -370,9 +367,7 @@ class SearchBarUI extends Component { query={this.state.query} screenTitle={this.props.screenTitle} 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} @@ -449,4 +444,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/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/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(), - }, - }, -})); 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/src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.mocks.tsx b/src/legacy/core_plugins/data/public/types.ts similarity index 63% rename from src/legacy/core_plugins/data/public/query/query_bar/components/query_bar_top_row.test.mocks.tsx rename to src/legacy/core_plugins/data/public/types.ts index 585fad0e058b7..4b7a5c1402ea7 100644 --- 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/types.ts @@ -17,16 +17,15 @@ * under the License. */ -import { - fatalErrorsServiceMock, - notificationServiceMock, -} from '../../../../../../../core/public/mocks'; +import { UiSettingsClientContract, CoreStart } from 'src/core/public'; +import { AutocompletePublicPluginStart } from 'src/plugins/data/public'; -jest.doMock('ui/new_platform', () => ({ - npSetup: { - core: { - fatalErrors: fatalErrorsServiceMock.createSetupContract(), - notifications: notificationServiceMock.createSetupContract(), - }, - }, -})); +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/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..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 @@ -22,12 +22,20 @@ 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('../../../../../../src/legacy/core_plugins/data/public/legacy', () => ({ + start: { + ui: { + SearchBar: () => {}, + }, + }, + setup: {}, +})); + jest.mock('../../../../core_plugins/data/public', () => { return { SearchBar: () =>
, @@ -57,34 +65,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 c99c71f97e1af..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,27 +21,16 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { I18nProvider } from '@kbn/i18n/react'; -import { UiSettingsClientContract, CoreStart } from 'src/core/public'; + 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 { SearchBarProps } from '../../../../core_plugins/data/public'; +import { start as data } from '../../../data/public/legacy'; type Props = Partial & { - name: string; + appName: string; config?: TopNavMenuData[]; showSearchBar?: boolean; - - // Search Bar dependencies - uiSettings?: UiSettingsClientContract; - savedObjects?: CoreStart['savedObjects']; - notifications?: CoreStart['notifications']; - timeHistory?: TimeHistoryContract; - http?: CoreStart['http']; }; /* @@ -54,9 +43,11 @@ type Props = Partial & { **/ export function TopNavMenu(props: Props) { + const { SearchBar } = data.ui; + 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 ( @@ -67,53 +58,8 @@ 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; - return ( - - - - ); + if (!showSearchBar) return; + return ; } function renderLayout() { 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/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/kbn_top_nav/kbn_top_nav.js b/src/legacy/ui/public/kbn_top_nav/kbn_top_nav.js index f2faeee75810e..79365eb5cf1cc 100644 --- a/src/legacy/ui/public/kbn_top_nav/kbn_top_nav.js +++ b/src/legacy/ui/public/kbn_top_nav/kbn_top_nav.js @@ -21,9 +21,6 @@ import 'ngreact'; import { wrapInI18nContext } from 'ui/i18n'; import { uiModules } from 'ui/modules'; import { TopNavMenu } from '../../../core_plugins/kibana_react/public'; -import { Storage } from 'ui/storage'; -import { npStart } from 'ui/new_platform'; -import { start as data } from '../../../core_plugins/data/public/legacy'; const module = uiModules.get('kibana'); @@ -43,25 +40,10 @@ module.directive('kbnTopNav', () => { // of the config array's disableButton function return value changes. 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 $scope.$watch(() => { @@ -95,20 +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' }], - ['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' }], 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 779d5acf5b411..cceaf86b5d85c 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 { @@ -82,6 +83,7 @@ function FilterRow({
); + // TODO: KibanaContextProvider should be raised to the top of the vis plugin return ( - 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} + dataTestSubj={dataTestSubj} + bubbleSubmitEvent={true} + languageSwitcherPopoverAnchorPosition="leftDown" + /> + {showCustomLabel ? ( ; +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 110ca3e68a97e..91b94e09607ee 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -25,6 +25,7 @@ export function plugin(initializerContext: PluginInitializerContext) { } export { DataPublicPlugin as Plugin }; +export { DataPublicPluginSetup, DataPublicPluginStart } from './types'; export * from '../common'; export * from './autocomplete_provider'; 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 ea160d34dc154..23308304b8ff8 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -18,3 +18,12 @@ */ export * from './autocomplete_provider/types'; + +import { AutocompletePublicPluginSetup, AutocompletePublicPluginStart } from '.'; +export interface DataPublicPluginSetup { + autocomplete: AutocompletePublicPluginSetup; +} + +export interface DataPublicPluginStart { + autocomplete: AutocompletePublicPluginStart; +} 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 267e7564fb830..3ed9b390c6a78 100644 --- a/x-pack/legacy/plugins/graph/public/angular/templates/index.html +++ b/x-pack/legacy/plugins/graph/public/angular/templates/index.html @@ -11,14 +11,13 @@ current-index-pattern="selectedIndex" on-index-pattern-selected="uiSelectIndex" on-query-submit="submit" - saved-objects="pluginDependencies.savedObjects" - ui-settings="pluginDependencies.uiSettings" - http="pluginDependencies.http" - overlays="pluginDependencies.overlays" is-loading="loading" 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 32fd24b8bed6d..aa8f0be6231df 100644 --- a/x-pack/legacy/plugins/graph/public/app.js +++ b/x-pack/legacy/plugins/graph/public/app.js @@ -32,6 +32,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,11 +115,10 @@ app.directive('graphApp', function (reactDirective) { ['isLoading', { watchDepth: 'reference' }], ['onIndexPatternSelected', { watchDepth: 'reference' }], ['onQuerySubmit', { watchDepth: 'reference' }], - ['savedObjects', { watchDepth: 'reference' }], - ['uiSettings', { watchDepth: 'reference' }], - ['http', { watchDepth: 'reference' }], ['initialQuery', { watchDepth: 'reference' }], - ['overlays', { watchDepth: 'reference' }] + ['autocompleteStart', { watchDepth: 'reference' }], + ['coreStart', { watchDepth: 'reference' }], + ['store', { watchDepth: 'reference' }] ]); }); @@ -302,8 +302,10 @@ app.controller('graphuiPlugin', function ( } }; - $scope.pluginDependencies = npStart.core; + $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 7e75a13bb39e3..907e7e4cecdcd 100644 --- a/x-pack/legacy/plugins/graph/public/components/app.tsx +++ b/x-pack/legacy/plugins/graph/public/components/app.tsx @@ -6,22 +6,40 @@ 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 { FieldManagerProps, FieldManager } from './field_manager'; import { SearchBarProps, SearchBar } from './search_bar'; -export interface GraphAppProps extends FieldManagerProps, SearchBarProps {} +import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; + +export interface GraphAppProps extends FieldManagerProps, SearchBarProps { + coreStart: CoreStart; + autocompleteStart: AutocompletePublicPluginStart; + store: Storage; +} export function GraphApp(props: GraphAppProps) { 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 eb97d63a33395..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 @@ -4,32 +4,54 @@ * 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: { + get: (key: string) => { + return 10; + }, + } 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 +66,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 +90,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 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..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,11 +7,10 @@ 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 +18,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,10 +26,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']; } function queryToString(query: Query, indexPattern: IndexPattern) { @@ -56,12 +50,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 null; + return (
{ - openSourceModal(props, onIndexPatternSelected); + openSourceModal( + { + overlays, + savedObjects, + uiSettings, + }, + onIndexPatternSelected + ); }} > {currentIndexPattern 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..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,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; }>; } 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({ 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`] = `""`; 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..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,13 +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 { 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'; -const localStorage = new Storage(window.localStorage); export class FilterEditor extends Component { state = { @@ -93,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 74ec80c0765e8..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 @@ -14,11 +14,7 @@ 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'; - -const localStorage = new Storage(window.localStorage); export class WhereExpression extends Component { @@ -80,35 +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()} - + +
-
- - - - + + + + + ); } }