mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
backport
This commit is contained in:
parent
99c174111a
commit
e884ebcbcb
8 changed files with 142 additions and 11 deletions
|
@ -18,3 +18,4 @@
|
|||
*/
|
||||
|
||||
export { QueryBar } from './query_bar';
|
||||
export { QueryBarInput } from './query_bar_input';
|
||||
|
|
|
@ -59,7 +59,7 @@ interface Props {
|
|||
disableAutoFocus?: boolean;
|
||||
appName: string;
|
||||
screenTitle: string;
|
||||
indexPatterns: IndexPattern[];
|
||||
indexPatterns: Array<IndexPattern | string>;
|
||||
store: Storage;
|
||||
intl: InjectedIntl;
|
||||
prepend?: any;
|
||||
|
|
|
@ -20,6 +20,21 @@
|
|||
import { createKfetch } from 'ui/kfetch/kfetch';
|
||||
import { setup } from 'test_utils/kfetch_test_setup';
|
||||
|
||||
const mockIndexPattern = {
|
||||
id: '1234',
|
||||
title: 'logstash-*',
|
||||
fields: [
|
||||
{
|
||||
name: 'response',
|
||||
type: 'number',
|
||||
esTypes: ['integer'],
|
||||
aggregatable: true,
|
||||
filterable: true,
|
||||
searchable: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const mockChromeFactory = jest.fn(() => {
|
||||
return {
|
||||
getBasePath: () => `foo`,
|
||||
|
@ -52,6 +67,10 @@ const mockAutocompleteProvider = jest.fn(() => mockGetAutocompleteSuggestions);
|
|||
export const mockGetAutocompleteProvider = jest.fn(() => mockAutocompleteProvider);
|
||||
const mockKfetch = jest.fn(() => createKfetch(setup().http));
|
||||
|
||||
export const mockFetchIndexPatterns = jest
|
||||
.fn()
|
||||
.mockReturnValue(Promise.resolve([mockIndexPattern]));
|
||||
|
||||
jest.mock('ui/chrome', () => mockChromeFactory());
|
||||
jest.mock('ui/kfetch', () => ({
|
||||
kfetch: () => {},
|
||||
|
@ -72,6 +91,10 @@ jest.mock('ui/kfetch', () => ({
|
|||
kfetch: mockKfetch,
|
||||
}));
|
||||
|
||||
jest.mock('../lib/fetch_index_patterns', () => ({
|
||||
fetchIndexPatterns: mockFetchIndexPatterns,
|
||||
}));
|
||||
|
||||
import _ from 'lodash';
|
||||
// Using doMock to avoid hoisting so that I can override only the debounce method in lodash
|
||||
jest.doMock('lodash', () => ({
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
import {
|
||||
mockFetchIndexPatterns,
|
||||
mockGetAutocompleteProvider,
|
||||
mockGetAutocompleteSuggestions,
|
||||
mockPersistedLog,
|
||||
|
@ -131,6 +132,8 @@ describe('QueryBarInput', () => {
|
|||
});
|
||||
|
||||
it('Should create a unique PersistedLog based on the appName and query language', () => {
|
||||
mockPersistedLogFactory.mockClear();
|
||||
|
||||
mountWithIntl(
|
||||
<QueryBarInput.WrappedComponent
|
||||
query={kqlQuery}
|
||||
|
@ -240,4 +243,23 @@ describe('QueryBarInput', () => {
|
|||
expect(mockGetAutocompleteProvider).toHaveBeenCalledWith('kuery');
|
||||
expect(mockGetAutocompleteSuggestions).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Should accept index pattern strings and fetch the full object', () => {
|
||||
mockFetchIndexPatterns.mockClear();
|
||||
|
||||
mountWithIntl(
|
||||
<QueryBarInput.WrappedComponent
|
||||
query={kqlQuery}
|
||||
onSubmit={noop}
|
||||
appName={'discover'}
|
||||
screenTitle={'Another Screen'}
|
||||
indexPatterns={['logstash-*']}
|
||||
store={createMockStorage()}
|
||||
disableAutoFocus={true}
|
||||
intl={null as any}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(mockFetchIndexPatterns).toHaveBeenCalledWith(['logstash-*']);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -28,8 +28,8 @@ import {
|
|||
AutocompleteSuggestionType,
|
||||
getAutocompleteProvider,
|
||||
} from 'ui/autocomplete_providers';
|
||||
import { debounce, compact } from 'lodash';
|
||||
import { IndexPattern } from 'ui/index_patterns';
|
||||
import { debounce, compact, isEqual } from 'lodash';
|
||||
import { IndexPattern, StaticIndexPattern } from 'ui/index_patterns';
|
||||
import { PersistedLog } from 'ui/persisted_log';
|
||||
import chrome from 'ui/chrome';
|
||||
import { kfetch } from 'ui/kfetch';
|
||||
|
@ -38,6 +38,7 @@ import { fromUser, matchPairs, toUser } from '../lib';
|
|||
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';
|
||||
|
||||
interface Query {
|
||||
query: string;
|
||||
|
@ -45,7 +46,7 @@ interface Query {
|
|||
}
|
||||
|
||||
interface Props {
|
||||
indexPatterns: IndexPattern[];
|
||||
indexPatterns: Array<IndexPattern | string>;
|
||||
intl: InjectedIntl;
|
||||
query: Query;
|
||||
appName: string;
|
||||
|
@ -65,6 +66,7 @@ interface State {
|
|||
suggestionLimit: number;
|
||||
selectionStart: number | null;
|
||||
selectionEnd: number | null;
|
||||
indexPatterns: StaticIndexPattern[];
|
||||
}
|
||||
|
||||
const KEY_CODES = {
|
||||
|
@ -90,6 +92,7 @@ export class QueryBarInputUI extends Component<Props, State> {
|
|||
suggestionLimit: 50,
|
||||
selectionStart: null,
|
||||
selectionEnd: null,
|
||||
indexPatterns: [],
|
||||
};
|
||||
|
||||
public inputRef: HTMLInputElement | null = null;
|
||||
|
@ -101,6 +104,21 @@ export class QueryBarInputUI extends Component<Props, State> {
|
|||
return toUser(this.props.query.query);
|
||||
};
|
||||
|
||||
private fetchIndexPatterns = async () => {
|
||||
const stringPatterns = this.props.indexPatterns.filter(
|
||||
indexPattern => typeof indexPattern === 'string'
|
||||
) as string[];
|
||||
const objectPatterns = this.props.indexPatterns.filter(
|
||||
indexPattern => typeof indexPattern !== 'string'
|
||||
) as IndexPattern[];
|
||||
|
||||
const objectPatternsFromStrings = await fetchIndexPatterns(stringPatterns);
|
||||
|
||||
this.setState({
|
||||
indexPatterns: [...objectPatterns, ...objectPatternsFromStrings],
|
||||
});
|
||||
};
|
||||
|
||||
private getSuggestions = async () => {
|
||||
if (!this.inputRef) {
|
||||
return;
|
||||
|
@ -114,13 +132,13 @@ export class QueryBarInputUI extends Component<Props, State> {
|
|||
const autocompleteProvider = getAutocompleteProvider(language);
|
||||
if (
|
||||
!autocompleteProvider ||
|
||||
!Array.isArray(this.props.indexPatterns) ||
|
||||
compact(this.props.indexPatterns).length === 0
|
||||
!Array.isArray(this.state.indexPatterns) ||
|
||||
compact(this.state.indexPatterns).length === 0
|
||||
) {
|
||||
return recentSearchSuggestions;
|
||||
}
|
||||
|
||||
const indexPatterns = this.props.indexPatterns;
|
||||
const indexPatterns = this.state.indexPatterns;
|
||||
const getAutocompleteSuggestions = autocompleteProvider({ config, indexPatterns });
|
||||
|
||||
const { selectionStart, selectionEnd } = this.inputRef;
|
||||
|
@ -368,14 +386,20 @@ export class QueryBarInputUI extends Component<Props, State> {
|
|||
this.persistedLog = this.props.persistedLog
|
||||
? this.props.persistedLog
|
||||
: getQueryLog(this.props.appName, this.props.query.language);
|
||||
this.updateSuggestions();
|
||||
|
||||
this.fetchIndexPatterns().then(this.updateSuggestions);
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: Props) {
|
||||
this.persistedLog = this.props.persistedLog
|
||||
? this.props.persistedLog
|
||||
: getQueryLog(this.props.appName, this.props.query.language);
|
||||
this.updateSuggestions();
|
||||
|
||||
if (!isEqual(prevProps.indexPatterns, this.props.indexPatterns)) {
|
||||
this.fetchIndexPatterns().then(this.updateSuggestions);
|
||||
} else {
|
||||
this.updateSuggestions();
|
||||
}
|
||||
|
||||
if (this.state.selectionStart !== null && this.state.selectionEnd !== null) {
|
||||
if (this.inputRef) {
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export { QueryBar } from './components';
|
||||
export { QueryBar, QueryBarInput } from './components';
|
||||
export { fromUser } from './lib/from_user';
|
||||
export { toUser } from './lib/to_user';
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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 chrome from 'ui/chrome';
|
||||
import { getFromSavedObject } from 'ui/index_patterns/static_utils';
|
||||
|
||||
const config = chrome.getUiSettingsClient();
|
||||
|
||||
export async function fetchIndexPatterns(indexPatternStrings: string[]) {
|
||||
const quotedIndexPatternStrings = indexPatternStrings.map(
|
||||
indexPatternString => `"${indexPatternString}"`
|
||||
);
|
||||
const searchString = quotedIndexPatternStrings.join(' | ');
|
||||
const indexPatternsFromSavedObjects = await chrome.getSavedObjectsClient().find({
|
||||
type: 'index-pattern',
|
||||
fields: ['title', 'fields'],
|
||||
search: `"${searchString}"`,
|
||||
searchFields: ['title'],
|
||||
});
|
||||
|
||||
const exactMatches = indexPatternsFromSavedObjects.savedObjects.filter(savedObject => {
|
||||
return indexPatternStrings.includes(savedObject.attributes.title as string);
|
||||
});
|
||||
|
||||
const allMatches =
|
||||
exactMatches.length === indexPatternStrings.length
|
||||
? exactMatches
|
||||
: [...exactMatches, await fetchDefaultIndexPattern()];
|
||||
|
||||
return allMatches.map(getFromSavedObject);
|
||||
}
|
||||
|
||||
const fetchDefaultIndexPattern = async () => {
|
||||
const savedObjectsClient = chrome.getSavedObjectsClient();
|
||||
const indexPattern = await savedObjectsClient.get('index-pattern', config.get('defaultIndex'));
|
||||
|
||||
return getFromSavedObject(indexPattern);
|
||||
};
|
|
@ -18,7 +18,13 @@
|
|||
*/
|
||||
|
||||
import { once } from 'lodash';
|
||||
import { QueryBar, fromUser, toUser, setupDirective as setupQueryBarDirective } from './query_bar';
|
||||
import {
|
||||
QueryBar,
|
||||
QueryBarInput,
|
||||
fromUser,
|
||||
toUser,
|
||||
setupDirective as setupQueryBarDirective,
|
||||
} from './query_bar';
|
||||
|
||||
/**
|
||||
* Query Service
|
||||
|
@ -35,6 +41,7 @@ export class QueryService {
|
|||
},
|
||||
ui: {
|
||||
QueryBar,
|
||||
QueryBarInput,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue