* Bind search bar * create prewired data components * 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 * Use KibanaContextProvider in vis editor and graph * Use KibanaContextProvider in maps * Use prewirted SearchBar in TopNavMenu * Use KibanaContextProbider in Lens * Fix appName usage in query bar input * fixed query bar top row appName * update tests * fixed bind search bar bug * mock SearchBar * Removed unnecessary mocks * Delete unused mock * Fixed exporting of data plugin types * Updated maps snapshot * Fixed some TS issues * Fixed jest tests * Context adjustments in TSVB * componentWillMount * Code review fixes * Pass dataTestSubj to query bar input * Graph data * - Pass NP data plugin to KibanaReactContext - Move value_suggestions to NP * - Pass NP data plugin to KibanaReactContext - Move value_suggestions to NP * ts fixes * Added karma getSuggestions fake * Refactored kuery autocomplete tests to jest * Filter bar context for directives * updated snapshot * fix diffs * fixed lens test
This commit is contained in:
parent
c573fd1bf4
commit
8ffd187c99
|
@ -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 (
|
||||
<KibanaContextProvider
|
||||
services={{
|
||||
uiSettings: props.uiSettings,
|
||||
docLinks: props.docLinks,
|
||||
data: props.pluginDataStart,
|
||||
}}
|
||||
>
|
||||
{content}
|
||||
</KibanaContextProvider>
|
||||
);
|
||||
} 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) {
|
|||
</EuiButtonEmpty>
|
||||
);
|
||||
|
||||
return (
|
||||
return wrapInContextIfMissing(
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiPopover
|
||||
id="addFilterPopover"
|
||||
|
@ -120,7 +148,6 @@ function FilterBarUI(props: Props) {
|
|||
onSubmit={onAdd}
|
||||
onCancel={() => setIsAddFilterPopoverOpen(false)}
|
||||
key={JSON.stringify(newFilter)}
|
||||
uiSettings={uiSettings!}
|
||||
/>
|
||||
</div>
|
||||
</EuiFlexItem>
|
||||
|
|
|
@ -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<Props, State> {
|
|||
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<Props, State> {
|
|||
field={this.state.selectedField}
|
||||
values={this.state.params}
|
||||
onChange={this.onParamsChange}
|
||||
uiSettings={this.props.uiSettings}
|
||||
/>
|
||||
);
|
||||
case 'range':
|
||||
|
|
|
@ -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<IDataPluginServices>;
|
||||
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<T extends PhraseSuggestorProps> extends Component<
|
||||
export class PhraseSuggestorUI<T extends PhraseSuggestorProps> extends Component<
|
||||
T,
|
||||
PhraseSuggestorState
|
||||
> {
|
||||
private services = this.props.kibana.services;
|
||||
public state: PhraseSuggestorState = {
|
||||
suggestions: [],
|
||||
isLoading: false,
|
||||
|
@ -52,7 +56,7 @@ export class PhraseSuggestor<T extends PhraseSuggestorProps> 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<T extends PhraseSuggestorProps> 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);
|
||||
|
|
|
@ -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<Props> {
|
||||
class PhraseValueInputUI extends PhraseSuggestorUI<Props> {
|
||||
public render() {
|
||||
return (
|
||||
<EuiFormRow
|
||||
|
@ -87,4 +88,4 @@ function StringComboBox(props: GenericComboBoxProps<string>) {
|
|||
return GenericComboBox(props);
|
||||
}
|
||||
|
||||
export const PhraseValueInput = injectI18n(PhraseValueInputUI);
|
||||
export const PhraseValueInput = injectI18n(withKibana(PhraseValueInputUI));
|
||||
|
|
|
@ -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<Props> {
|
||||
class PhrasesValuesInputUI extends PhraseSuggestorUI<Props> {
|
||||
public render() {
|
||||
const { suggestions } = this.state;
|
||||
const { values, intl, onChange } = this.props;
|
||||
|
@ -64,4 +65,4 @@ function StringComboBox(props: GenericComboBoxProps<string>) {
|
|||
return GenericComboBox(props);
|
||||
}
|
||||
|
||||
export const PhrasesValuesInput = injectI18n(PhrasesValuesInputUI);
|
||||
export const PhrasesValuesInput = injectI18n(withKibana(PhrasesValuesInputUI));
|
||||
|
|
|
@ -171,7 +171,6 @@ class FilterItemUI extends Component<Props, State> {
|
|||
indexPatterns={this.props.indexPatterns}
|
||||
onSubmit={this.onSubmit}
|
||||
onCancel={this.closePopover}
|
||||
uiSettings={this.props.uiSettings}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
|
|
|
@ -127,10 +127,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 {
|
||||
|
|
|
@ -134,8 +134,8 @@ export class QueryBarInputUI extends Component<Props, State> {
|
|||
const queryString = this.getQueryString();
|
||||
|
||||
const recentSearchSuggestions = this.getRecentSearchSuggestions(queryString);
|
||||
const autocompleteProvider = this.services.data.autocomplete.getProvider(language);
|
||||
|
||||
const autocompleteProvider = this.services.autocomplete.getProvider(language);
|
||||
if (
|
||||
!autocompleteProvider ||
|
||||
!Array.isArray(this.state.indexPatterns) ||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
import React from 'react';
|
||||
import { Filter } from '@kbn/es-query';
|
||||
import { CoreStart } from 'src/core/public';
|
||||
import { AutocompletePublicPluginStart } from 'src/plugins/data/public';
|
||||
import { DataPublicPluginStart } from 'src/plugins/data/public';
|
||||
import { Storage } from '../../../types';
|
||||
import { KibanaContextProvider } from '../../../../../../../../src/plugins/kibana_react/public';
|
||||
import { TimefilterSetup } from '../../../timefilter';
|
||||
|
@ -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({
|
|||
<KibanaContextProvider
|
||||
services={{
|
||||
appName: props.appName,
|
||||
autocomplete,
|
||||
data,
|
||||
store,
|
||||
...core,
|
||||
}}
|
||||
|
|
|
@ -66,7 +66,6 @@ export interface SearchBarOwnProps {
|
|||
showFilterBar?: boolean;
|
||||
showDatePicker?: boolean;
|
||||
showAutoRefreshOnly?: boolean;
|
||||
onRefreshChange?: (options: { isPaused: boolean; refreshInterval: number }) => void;
|
||||
// Query bar - should be in SearchBarInjectedDeps
|
||||
query?: Query;
|
||||
// Show when user has privileges to save
|
||||
|
|
|
@ -24,7 +24,7 @@ import { Filter } from '@kbn/es-query';
|
|||
|
||||
// @ts-ignore
|
||||
import { uiModules } from 'ui/modules';
|
||||
import { npSetup, npStart } from 'ui/new_platform';
|
||||
import { npStart } from 'ui/new_platform';
|
||||
import { FilterBar, ApplyFiltersPopover } from '../filter';
|
||||
import template from './apply_filter_directive.html';
|
||||
|
||||
|
@ -49,14 +49,16 @@ export const initLegacyModule = once((): void => {
|
|||
}
|
||||
|
||||
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) =>
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
*/
|
||||
|
||||
import { UiSettingsClientContract, CoreStart } from 'src/core/public';
|
||||
import { AutocompletePublicPluginStart } from 'src/plugins/data/public';
|
||||
import { DataPublicPluginStart } from 'src/plugins/data/public';
|
||||
|
||||
export interface Storage {
|
||||
get: (key: string) => any;
|
||||
|
@ -34,5 +34,5 @@ export interface IDataPluginServices extends Partial<CoreStart> {
|
|||
notifications: CoreStart['notifications'];
|
||||
http: CoreStart['http'];
|
||||
store: Storage;
|
||||
autocomplete: AutocompletePublicPluginStart;
|
||||
data: DataPublicPluginStart;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}}
|
||||
>
|
||||
|
|
|
@ -65,7 +65,9 @@ export const npStart = {
|
|||
registerRenderer: sinon.fake(),
|
||||
registerType: sinon.fake(),
|
||||
},
|
||||
data: {},
|
||||
data: {
|
||||
getSuggestions: sinon.fake(),
|
||||
},
|
||||
inspector: {
|
||||
isAvailable: () => false,
|
||||
open: () => ({
|
||||
|
|
|
@ -95,7 +95,7 @@ function FilterRow({
|
|||
services={{
|
||||
appName: 'filtersAgg',
|
||||
store: localStorage,
|
||||
autocomplete: npStart.plugins.data.autocomplete,
|
||||
data: npStart.plugins.data,
|
||||
...npStart.core,
|
||||
}}
|
||||
>
|
||||
|
|
|
@ -38,6 +38,7 @@ const createSetupContract = (): Setup => {
|
|||
const createStartContract = (): Start => {
|
||||
const startContract: Start = {
|
||||
autocomplete: autocompleteMock as Start['autocomplete'],
|
||||
getSuggestions: jest.fn(),
|
||||
};
|
||||
return startContract;
|
||||
};
|
||||
|
|
|
@ -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<DataPublicPluginSetup, DataPublicPluginStart> {
|
||||
private readonly autocomplete = new AutocompleteProviderRegister();
|
||||
|
@ -35,6 +36,7 @@ export class DataPublicPlugin implements Plugin<DataPublicPluginSetup, DataPubli
|
|||
public start(core: CoreStart): DataPublicPluginStart {
|
||||
return {
|
||||
autocomplete: this.autocomplete,
|
||||
getSuggestions: getSuggestionsProvider(core.uiSettings, core.http),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -17,8 +17,4 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import chrome from 'ui/chrome';
|
||||
import { kfetch } from 'ui/kfetch';
|
||||
import { getSuggestionsProvider } from './value_suggestions';
|
||||
|
||||
export const getSuggestions = getSuggestionsProvider(chrome.getUiSettingsClient(), kfetch);
|
||||
export { getSuggestionsProvider } from './value_suggestions';
|
23
src/plugins/data/public/suggestions_provider/types.ts
Normal file
23
src/plugins/data/public/suggestions_provider/types.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// Should be import { Field } from './index_patterns';
|
||||
export type Field = any;
|
||||
|
||||
export type IGetSuggestions = (index: string, field: Field, query: string, boolFilter?: any) => any;
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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') {
|
|
@ -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';
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
is-initialized="workspaceInitialized || savedWorkspace.id"
|
||||
initial-query="initialQuery"
|
||||
on-fill-workspace="fillWorkspace"
|
||||
autocomplete-start="autocompleteStart"
|
||||
plugin-data-start="pluginDataStart"
|
||||
core-start="coreStart"
|
||||
store="store"
|
||||
></graph-app>
|
||||
|
|
|
@ -106,9 +106,10 @@ app.directive('graphApp', function (reactDirective) {
|
|||
['onQuerySubmit', { watchDepth: 'reference' }],
|
||||
['initialQuery', { watchDepth: 'reference' }],
|
||||
['confirmWipeWorkspace', { watchDepth: 'reference' }],
|
||||
['autocompleteStart', { watchDepth: 'reference' }],
|
||||
['coreStart', { watchDepth: 'reference' }],
|
||||
['reduxStore', { watchDepth: 'reference' }]
|
||||
['pluginDataStart', { watchDepth: 'reference' }],
|
||||
['store', { watchDepth: 'reference' }],
|
||||
['reduxStore', { watchDepth: 'reference' }],
|
||||
]);
|
||||
});
|
||||
|
||||
|
@ -321,9 +322,9 @@ app.controller('graphuiPlugin', function (
|
|||
chrome,
|
||||
});
|
||||
|
||||
$scope.pluginDataStart = npStart.plugins.data;
|
||||
$scope.store = new Storage(window.localStorage);
|
||||
$scope.coreStart = npStart.core;
|
||||
$scope.autocompleteStart = npStart.plugins.data.autocomplete;
|
||||
$scope.loading = false;
|
||||
|
||||
$scope.spymode = 'request';
|
||||
|
|
|
@ -5,12 +5,13 @@
|
|||
*/
|
||||
|
||||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
|
||||
import { DataPublicPluginStart } from 'src/plugins/data/public';
|
||||
import { Provider } from 'react-redux';
|
||||
import React, { useState } from 'react';
|
||||
import { I18nProvider } from '@kbn/i18n/react';
|
||||
import { Storage } from 'ui/storage';
|
||||
import { CoreStart } from 'kibana/public';
|
||||
import { AutocompletePublicPluginStart } from 'src/plugins/data/public';
|
||||
import { FieldManager } from './field_manager';
|
||||
import { SearchBarProps, SearchBar } from './search_bar';
|
||||
import { GraphStore } from '../state_management';
|
||||
|
@ -20,7 +21,8 @@ import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_reac
|
|||
|
||||
export interface GraphAppProps extends SearchBarProps {
|
||||
coreStart: CoreStart;
|
||||
autocompleteStart: AutocompletePublicPluginStart;
|
||||
// This is not named dataStart because of Angular treating data- prefix differently
|
||||
pluginDataStart: DataPublicPluginStart;
|
||||
store: Storage;
|
||||
reduxStore: GraphStore;
|
||||
isInitialized: boolean;
|
||||
|
@ -29,16 +31,16 @@ export interface GraphAppProps extends SearchBarProps {
|
|||
|
||||
export function GraphApp(props: GraphAppProps) {
|
||||
const [pickerOpen, setPickerOpen] = useState(false);
|
||||
const { coreStart, autocompleteStart, store, reduxStore, ...searchBarProps } = props;
|
||||
const { coreStart, pluginDataStart, store, reduxStore, ...searchBarProps } = props;
|
||||
|
||||
return (
|
||||
<I18nProvider>
|
||||
<KibanaContextProvider
|
||||
services={{
|
||||
appName: 'graph',
|
||||
store: props.store,
|
||||
autocomplete: props.autocompleteStart,
|
||||
...props.coreStart,
|
||||
store,
|
||||
data: pluginDataStart,
|
||||
...coreStart,
|
||||
}}
|
||||
>
|
||||
<Provider store={reduxStore}>
|
||||
|
|
|
@ -17,6 +17,7 @@ import { I18nProvider } from '@kbn/i18n/react';
|
|||
jest.mock('ui/new_platform');
|
||||
|
||||
import { openSourceModal } from '../services/source_modal';
|
||||
|
||||
import { GraphStore, setDatasource } from '../state_management';
|
||||
import { ReactWrapper } from 'enzyme';
|
||||
import { createMockGraphStore } from '../state_management/mocks';
|
||||
|
@ -82,6 +83,7 @@ describe('search_bar', () => {
|
|||
function mountSearchBar() {
|
||||
jest.clearAllMocks();
|
||||
const wrappedSearchBar = wrapSearchBarInContext({ ...defaultProps });
|
||||
|
||||
instance = mountWithIntl(<Provider store={store}>{wrappedSearchBar}</Provider>);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
IndexPattern,
|
||||
} from '../../../../../../src/legacy/core_plugins/data/public';
|
||||
import { openSourceModal } from '../services/source_modal';
|
||||
|
||||
import {
|
||||
GraphState,
|
||||
datasourceSelector,
|
||||
|
@ -31,6 +32,7 @@ export interface OuterSearchBarProps {
|
|||
isLoading: boolean;
|
||||
initialQuery?: string;
|
||||
onQuerySubmit: (query: string) => void;
|
||||
|
||||
confirmWipeWorkspace: (onConfirm: () => void) => void;
|
||||
indexPatternProvider: IndexPatternProvider;
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
}
|
|
@ -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';
|
||||
|
||||
|
@ -29,6 +29,7 @@ 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 getSuggestions(field.indexPatternTitle, field, query, boolFilter).then(data => {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
|
@ -13,6 +13,10 @@ import { EditorFrameInstance } from '../types';
|
|||
import { Storage } from 'ui/storage';
|
||||
import { Document, SavedObjectStore } from '../persistence';
|
||||
import { mount } from 'enzyme';
|
||||
|
||||
import { dataPluginMock } from '../../../../../../src/plugins/data/public/mocks';
|
||||
const dataStartMock = dataPluginMock.createStartContract();
|
||||
|
||||
import {
|
||||
TopNavMenu,
|
||||
TopNavMenuData,
|
||||
|
@ -68,8 +72,9 @@ describe('Lens App', () => {
|
|||
|
||||
function makeDefaultArgs(): jest.Mocked<{
|
||||
editorFrame: EditorFrameInstance;
|
||||
data: typeof dataStartMock;
|
||||
core: typeof core;
|
||||
data: DataStart;
|
||||
dataShim: DataStart;
|
||||
store: Storage;
|
||||
docId?: string;
|
||||
docStorage: SavedObjectStore;
|
||||
|
@ -87,7 +92,7 @@ describe('Lens App', () => {
|
|||
},
|
||||
},
|
||||
},
|
||||
data: {
|
||||
dataShim: {
|
||||
indexPatterns: {
|
||||
indexPatterns: {
|
||||
get: jest.fn(id => {
|
||||
|
@ -110,8 +115,9 @@ describe('Lens App', () => {
|
|||
redirectTo: jest.fn(id => {}),
|
||||
} as unknown) as jest.Mocked<{
|
||||
editorFrame: EditorFrameInstance;
|
||||
data: typeof dataStartMock;
|
||||
core: typeof core;
|
||||
data: DataStart;
|
||||
dataShim: DataStart;
|
||||
store: Storage;
|
||||
docId?: string;
|
||||
docStorage: SavedObjectStore;
|
||||
|
@ -224,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',
|
||||
|
@ -492,7 +498,7 @@ describe('Lens App', () => {
|
|||
|
||||
const instance = mount(<App {...args} />);
|
||||
|
||||
args.data.filter.filterManager.setFilters([
|
||||
args.dataShim.filter.filterManager.setFilters([
|
||||
buildExistsFilter({ name: 'myfield' }, { id: 'index1' }),
|
||||
]);
|
||||
|
||||
|
@ -623,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();
|
||||
|
|
|
@ -9,6 +9,8 @@ import React, { useState, useEffect, useCallback, useRef } from 'react';
|
|||
import { I18nProvider } from '@kbn/i18n/react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { Storage } from 'ui/storage';
|
||||
import { DataPublicPluginStart } from 'src/plugins/data/public';
|
||||
|
||||
import { CoreStart, NotificationsStart } from 'src/core/public';
|
||||
import {
|
||||
DataStart,
|
||||
|
@ -43,6 +45,7 @@ interface State {
|
|||
export function App({
|
||||
editorFrame,
|
||||
data,
|
||||
dataShim,
|
||||
core,
|
||||
store,
|
||||
docId,
|
||||
|
@ -50,8 +53,9 @@ export function App({
|
|||
redirectTo,
|
||||
}: {
|
||||
editorFrame: EditorFrameInstance;
|
||||
data: DataPublicPluginStart;
|
||||
core: CoreStart;
|
||||
data: DataStart;
|
||||
dataShim: DataStart;
|
||||
store: Storage;
|
||||
docId?: string;
|
||||
docStorage: SavedObjectStore;
|
||||
|
@ -77,9 +81,9 @@ export function App({
|
|||
const lastKnownDocRef = useRef<Document | undefined>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
const subscription = data.filter.filterManager.getUpdates$().subscribe({
|
||||
const subscription = dataShim.filter.filterManager.getUpdates$().subscribe({
|
||||
next: () => {
|
||||
setState(s => ({ ...s, filters: data.filter.filterManager.getFilters() }));
|
||||
setState(s => ({ ...s, filters: dataShim.filter.filterManager.getFilters() }));
|
||||
},
|
||||
});
|
||||
return () => {
|
||||
|
@ -112,7 +116,7 @@ export function App({
|
|||
.then(doc => {
|
||||
getAllIndexPatterns(
|
||||
doc.state.datasourceMetaData.filterableIndexPatterns,
|
||||
data.indexPatterns.indexPatterns,
|
||||
dataShim.indexPatterns.indexPatterns,
|
||||
core.notifications
|
||||
)
|
||||
.then(indexPatterns => {
|
||||
|
@ -164,6 +168,7 @@ export function App({
|
|||
<KibanaContextProvider
|
||||
services={{
|
||||
appName: 'lens',
|
||||
data,
|
||||
store,
|
||||
...core,
|
||||
}}
|
||||
|
@ -230,7 +235,7 @@ export function App({
|
|||
setState(s => ({ ...s, savedQuery }));
|
||||
}}
|
||||
onSavedQueryUpdated={savedQuery => {
|
||||
data.filter.filterManager.setFilters(
|
||||
dataShim.filter.filterManager.setFilters(
|
||||
savedQuery.attributes.filters || state.filters
|
||||
);
|
||||
setState(s => ({
|
||||
|
@ -245,7 +250,7 @@ export function App({
|
|||
}));
|
||||
}}
|
||||
onClearSavedQuery={() => {
|
||||
data.filter.filterManager.removeAll();
|
||||
dataShim.filter.filterManager.removeAll();
|
||||
setState(s => ({
|
||||
...s,
|
||||
savedQuery: undefined,
|
||||
|
@ -290,7 +295,7 @@ export function App({
|
|||
) {
|
||||
getAllIndexPatterns(
|
||||
filterableIndexPatterns,
|
||||
data.indexPatterns.indexPatterns,
|
||||
dataShim.indexPatterns.indexPatterns,
|
||||
core.notifications
|
||||
).then(indexPatterns => {
|
||||
if (indexPatterns) {
|
||||
|
|
|
@ -11,8 +11,9 @@ 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 { DataStart } from '../../../../../../src/legacy/core_plugins/data/public';
|
||||
import { start as dataStart } from '../../../../../../src/legacy/core_plugins/data/public/legacy';
|
||||
import { start as dataShimStart } from '../../../../../../src/legacy/core_plugins/data/public/legacy';
|
||||
import { editorFrameSetup, editorFrameStart, editorFrameStop } from '../editor_frame_plugin';
|
||||
import { indexPatternDatasourceSetup, indexPatternDatasourceStop } from '../indexpattern_plugin';
|
||||
import { SavedObjectIndexStore } from '../persistence';
|
||||
|
@ -26,7 +27,8 @@ import { App } from './app';
|
|||
import { EditorFrameInstance } from '../types';
|
||||
|
||||
export interface LensPluginStartDependencies {
|
||||
data: DataStart;
|
||||
data: DataPublicPluginStart;
|
||||
dataShim: DataStart;
|
||||
}
|
||||
export class AppPlugin {
|
||||
private instance: EditorFrameInstance | null = null;
|
||||
|
@ -50,7 +52,7 @@ export class AppPlugin {
|
|||
editorFrameSetupInterface.registerDatasource('indexpattern', indexPattern);
|
||||
}
|
||||
|
||||
start(core: CoreStart, { data }: LensPluginStartDependencies) {
|
||||
start(core: CoreStart, { data, dataShim }: LensPluginStartDependencies) {
|
||||
if (this.store === null) {
|
||||
throw new Error('Start lifecycle called before setup lifecycle');
|
||||
}
|
||||
|
@ -66,6 +68,7 @@ export class AppPlugin {
|
|||
<App
|
||||
core={core}
|
||||
data={data}
|
||||
dataShim={dataShim}
|
||||
editorFrame={this.instance!}
|
||||
store={new Storage(localStorage)}
|
||||
docId={routeProps.match.params.id}
|
||||
|
@ -115,5 +118,6 @@ export class AppPlugin {
|
|||
const app = new AppPlugin();
|
||||
|
||||
export const appSetup = () => app.setup(npSetup.core, {});
|
||||
export const appStart = () => app.start(npStart.core, { data: dataStart });
|
||||
export const appStart = () =>
|
||||
app.start(npStart.core, { dataShim: dataShimStart, data: npStart.plugins.data });
|
||||
export const appStop = () => app.stop();
|
||||
|
|
|
@ -5,7 +5,7 @@ exports[`LayerPanel is rendered 1`] = `
|
|||
services={
|
||||
Object {
|
||||
"appName": "maps",
|
||||
"autocomplete": undefined,
|
||||
"data": undefined,
|
||||
"store": Storage {
|
||||
"clear": [Function],
|
||||
"get": [Function],
|
||||
|
|
|
@ -155,7 +155,7 @@ export class LayerPanel extends React.Component {
|
|||
services={{
|
||||
appName: 'maps',
|
||||
store: localStorage,
|
||||
autocomplete: npStart.plugins.autocomplete,
|
||||
data: npStart.plugins.data,
|
||||
...npStart.core,
|
||||
}}
|
||||
>
|
||||
|
|
Loading…
Reference in a new issue