Create re-usable IndexPatternSelect component (#23335)

* Migrate index pattern select to ui/public/index_patterns

* get rest of jest tests working

* migrate remaining part of IndexPatternSelect to IndexPatternSelectFormRow
This commit is contained in:
Nathan Reese 2018-09-21 09:00:41 -06:00 committed by GitHub
parent eb1cfaf0f8
commit e8bebedf8c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 124 additions and 121 deletions

View file

@ -20,7 +20,6 @@ exports[`renders ControlsTab 1`] = `
}
}
getIndexPattern={[Function]}
getIndexPatterns={[Function]}
handleCheckboxOptionChange={[Function]}
handleFieldNameChange={[Function]}
handleIndexPatternChange={[Function]}
@ -54,7 +53,6 @@ exports[`renders ControlsTab 1`] = `
}
}
getIndexPattern={[Function]}
getIndexPatterns={[Function]}
handleCheckboxOptionChange={[Function]}
handleFieldNameChange={[Function]}
handleIndexPatternChange={[Function]}

View file

@ -2,10 +2,8 @@
exports[`renders dynamic options should display disabled dynamic options with tooltip for non-string fields 1`] = `
<div>
<InjectIntl(IndexPatternSelectUi)
<InjectIntl(IndexPatternSelectFormRowUi)
controlIndex={0}
getIndexPattern={[Function]}
getIndexPatterns={[Function]}
indexPatternId="mockIndexPattern"
onChange={[Function]}
/>
@ -72,10 +70,8 @@ exports[`renders dynamic options should display disabled dynamic options with to
exports[`renders dynamic options should display dynamic options for string fields 1`] = `
<div>
<InjectIntl(IndexPatternSelectUi)
<InjectIntl(IndexPatternSelectFormRowUi)
controlIndex={0}
getIndexPattern={[Function]}
getIndexPatterns={[Function]}
indexPatternId="mockIndexPattern"
onChange={[Function]}
/>
@ -123,10 +119,8 @@ exports[`renders dynamic options should display dynamic options for string field
exports[`renders dynamic options should display size field when dynamic options is disabled 1`] = `
<div>
<InjectIntl(IndexPatternSelectUi)
<InjectIntl(IndexPatternSelectFormRowUi)
controlIndex={0}
getIndexPattern={[Function]}
getIndexPatterns={[Function]}
indexPatternId="mockIndexPattern"
onChange={[Function]}
/>
@ -193,10 +187,8 @@ exports[`renders dynamic options should display size field when dynamic options
exports[`renders should display chaining input when parents are provided 1`] = `
<div>
<InjectIntl(IndexPatternSelectUi)
<InjectIntl(IndexPatternSelectFormRowUi)
controlIndex={0}
getIndexPattern={[Function]}
getIndexPatterns={[Function]}
indexPatternId="indexPattern1"
onChange={[Function]}
/>
@ -296,10 +288,8 @@ exports[`renders should display chaining input when parents are provided 1`] = `
exports[`renders should not display any options until field is selected 1`] = `
<div>
<InjectIntl(IndexPatternSelectUi)
<InjectIntl(IndexPatternSelectFormRowUi)
controlIndex={0}
getIndexPattern={[Function]}
getIndexPatterns={[Function]}
indexPatternId="mockIndexPattern"
onChange={[Function]}
/>

View file

@ -2,10 +2,8 @@
exports[`renders RangeControlEditor 1`] = `
<div>
<InjectIntl(IndexPatternSelectUi)
<InjectIntl(IndexPatternSelectFormRowUi)
controlIndex={0}
getIndexPattern={[Function]}
getIndexPatterns={[Function]}
indexPatternId="indexPattern1"
onChange={[Function]}
/>

View file

@ -71,7 +71,6 @@ class ControlEditorUi extends Component {
controlParams={this.props.controlParams}
handleIndexPatternChange={this.changeIndexPattern}
handleFieldNameChange={this.changeFieldName}
getIndexPatterns={this.props.getIndexPatterns}
getIndexPattern={this.props.getIndexPattern}
handleNumberOptionChange={this.props.handleNumberOptionChange}
handleCheckboxOptionChange={this.props.handleCheckboxOptionChange}
@ -87,7 +86,6 @@ class ControlEditorUi extends Component {
controlParams={this.props.controlParams}
handleIndexPatternChange={this.changeIndexPattern}
handleFieldNameChange={this.changeFieldName}
getIndexPatterns={this.props.getIndexPatterns}
getIndexPattern={this.props.getIndexPattern}
handleNumberOptionChange={this.props.handleNumberOptionChange}
/>
@ -179,7 +177,6 @@ ControlEditorUi.propTypes = {
handleRemoveControl: PropTypes.func.isRequired,
handleIndexPatternChange: PropTypes.func.isRequired,
handleFieldNameChange: PropTypes.func.isRequired,
getIndexPatterns: PropTypes.func.isRequired,
getIndexPattern: PropTypes.func.isRequired,
handleCheckboxOptionChange: PropTypes.func.isRequired,
handleNumberOptionChange: PropTypes.func.isRequired,

View file

@ -40,17 +40,6 @@ class ControlsTabUi extends Component {
type: 'list'
}
getIndexPatterns = async (search) => {
const resp = await this.props.scope.vis.API.savedObjectsClient.find({
type: 'index-pattern',
fields: ['title'],
search: `${search}*`,
search_fields: ['title'],
perPage: 100
});
return resp.savedObjects;
}
getIndexPattern = async (indexPatternId) => {
return await this.props.scope.vis.API.indexPatterns.get(indexPatternId);
}
@ -127,7 +116,6 @@ class ControlsTabUi extends Component {
handleRemoveControl={this.handleRemoveControl}
handleIndexPatternChange={this.handleIndexPatternChange}
handleFieldNameChange={this.handleFieldNameChange}
getIndexPatterns={this.getIndexPatterns}
getIndexPattern={this.getIndexPattern}
handleCheckboxOptionChange={this.handleCheckboxOptionChange}
handleNumberOptionChange={this.handleNumberOptionChange}

View file

@ -26,27 +26,12 @@ import {
ControlsTab,
} from './controls_tab';
const savedObjectsClientMock = {
find: () => {
return Promise.resolve({
savedObjects: [
{
id: 'indexPattern1',
attributes: {
title: 'title1'
}
}
]
});
}
};
const indexPatternsMock = {
get: getIndexPatternMock
};
const scopeMock = {
vis: {
API: {
savedObjectsClient: savedObjectsClientMock,
indexPatterns: indexPatternsMock
},
},

View file

@ -0,0 +1,65 @@
/*
* 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 PropTypes from 'prop-types';
import React from 'react';
import { injectI18n } from '@kbn/i18n/react';
import { IndexPatternSelect } from 'ui/index_patterns/components/index_pattern_select';
import {
EuiFormRow,
} from '@elastic/eui';
function IndexPatternSelectFormRowUi(props) {
const {
controlIndex,
indexPatternId,
intl,
onChange,
} = props;
const selectId = `indexPatternSelect-${controlIndex}`;
return (
<EuiFormRow
id={selectId}
label={intl.formatMessage({
id: 'inputControl.editor.indexPatternSelect.patternLabel',
defaultMessage: 'Index Pattern'
})}
>
<IndexPatternSelect
placeholder={intl.formatMessage({
id: 'inputControl.editor.indexPatternSelect.patternPlaceholder',
defaultMessage: 'Select index pattern...'
})}
indexPatternId={indexPatternId}
onChange={onChange}
data-test-subj={selectId}
/>
</EuiFormRow>
);
}
IndexPatternSelectFormRowUi.propTypes = {
onChange: PropTypes.func.isRequired,
indexPatternId: PropTypes.string,
controlIndex: PropTypes.number.isRequired,
};
export const IndexPatternSelectFormRow = injectI18n(IndexPatternSelectFormRowUi);

View file

@ -19,7 +19,7 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { IndexPatternSelect } from './index_pattern_select';
import { IndexPatternSelectFormRow } from './index_pattern_select_form_row';
import { FieldSelect } from './field_select';
import { injectI18n } from '@kbn/i18n/react';
@ -220,11 +220,9 @@ class ListControlEditorUi extends Component {
return (
<div>
<IndexPatternSelect
<IndexPatternSelectFormRow
indexPatternId={this.props.controlParams.indexPattern}
onChange={this.props.handleIndexPatternChange}
getIndexPatterns={this.props.getIndexPatterns}
getIndexPattern={this.props.getIndexPattern}
controlIndex={this.props.controlIndex}
/>
@ -245,7 +243,6 @@ class ListControlEditorUi extends Component {
}
ListControlEditorUi.propTypes = {
getIndexPatterns: PropTypes.func.isRequired,
getIndexPattern: PropTypes.func.isRequired,
controlIndex: PropTypes.number.isRequired,
controlParams: PropTypes.object.isRequired,

View file

@ -22,7 +22,6 @@ import sinon from 'sinon';
import { shallowWithIntl, mountWithIntl } from 'test_utils/enzyme_helpers';
import { findTestSubject } from '@elastic/eui/lib/test';
import { getIndexPatternMock } from './__tests__/get_index_pattern_mock';
import { getIndexPatternsMock } from './__tests__/get_index_patterns_mock';
import {
ListControlEditor,
@ -68,7 +67,6 @@ describe('renders', () => {
}
};
const component = shallowWithIntl(<ListControlEditor.WrappedComponent
getIndexPatterns={getIndexPatternsMock}
getIndexPattern={getIndexPatternMock}
controlIndex={0}
controlParams={controlParams}
@ -94,7 +92,6 @@ describe('renders', () => {
{ value: '2', text: 'fieldB' }
];
const component = shallowWithIntl(<ListControlEditor.WrappedComponent
getIndexPatterns={getIndexPatternsMock}
getIndexPattern={getIndexPatternMock}
controlIndex={0}
controlParams={controlParams}
@ -129,7 +126,6 @@ describe('renders', () => {
}
};
const component = shallowWithIntl(<ListControlEditor.WrappedComponent
getIndexPatterns={getIndexPatternsMock}
getIndexPattern={getIndexPatternMock}
controlIndex={0}
controlParams={controlParams}
@ -163,7 +159,6 @@ describe('renders', () => {
}
};
const component = shallowWithIntl(<ListControlEditor.WrappedComponent
getIndexPatterns={getIndexPatternsMock}
getIndexPattern={getIndexPatternMock}
controlIndex={0}
controlParams={controlParams}
@ -197,7 +192,6 @@ describe('renders', () => {
}
};
const component = shallowWithIntl(<ListControlEditor.WrappedComponent
getIndexPatterns={getIndexPatternsMock}
getIndexPattern={getIndexPatternMock}
controlIndex={0}
controlParams={controlParams}
@ -221,7 +215,6 @@ describe('renders', () => {
test('handleCheckboxOptionChange - multiselect', async () => {
const component = mountWithIntl(<ListControlEditor.WrappedComponent
getIndexPatterns={getIndexPatternsMock}
getIndexPattern={getIndexPatternMock}
controlIndex={0}
controlParams={controlParams}
@ -259,7 +252,6 @@ test('handleCheckboxOptionChange - multiselect', async () => {
test('handleNumberOptionChange - size', async () => {
const component = mountWithIntl(<ListControlEditor.WrappedComponent
getIndexPatterns={getIndexPatternsMock}
getIndexPattern={getIndexPatternMock}
controlIndex={0}
controlParams={controlParams}

View file

@ -19,7 +19,7 @@
import PropTypes from 'prop-types';
import React from 'react';
import { IndexPatternSelect } from './index_pattern_select';
import { IndexPatternSelectFormRow } from './index_pattern_select_form_row';
import { FieldSelect } from './field_select';
import {
@ -45,11 +45,9 @@ export function RangeControlEditor(props) {
return (
<div>
<IndexPatternSelect
<IndexPatternSelectFormRow
indexPatternId={props.controlParams.indexPattern}
onChange={props.handleIndexPatternChange}
getIndexPatterns={props.getIndexPatterns}
getIndexPattern={props.getIndexPattern}
controlIndex={props.controlIndex}
/>
@ -96,7 +94,6 @@ export function RangeControlEditor(props) {
}
RangeControlEditor.propTypes = {
getIndexPatterns: PropTypes.func.isRequired,
getIndexPattern: PropTypes.func.isRequired,
controlIndex: PropTypes.number.isRequired,
controlParams: PropTypes.object.isRequired,

View file

@ -23,7 +23,6 @@ import { shallow } from 'enzyme';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { findTestSubject } from '@elastic/eui/lib/test';
import { getIndexPatternMock } from './__tests__/get_index_pattern_mock';
import { getIndexPatternsMock } from './__tests__/get_index_patterns_mock';
import {
RangeControlEditor,
@ -52,7 +51,6 @@ beforeEach(() => {
test('renders RangeControlEditor', () => {
const component = shallow(<RangeControlEditor
getIndexPatterns={getIndexPatternsMock}
getIndexPattern={getIndexPatternMock}
controlIndex={0}
controlParams={controlParams}
@ -65,7 +63,6 @@ test('renders RangeControlEditor', () => {
test('handleNumberOptionChange - step', () => {
const component = mountWithIntl(<RangeControlEditor
getIndexPatterns={getIndexPatternsMock}
getIndexPattern={getIndexPatternMock}
controlIndex={0}
controlParams={controlParams}
@ -92,7 +89,6 @@ test('handleNumberOptionChange - step', () => {
test('handleNumberOptionChange - decimalPlaces', () => {
const component = mountWithIntl(<RangeControlEditor
getIndexPatterns={getIndexPatternsMock}
getIndexPattern={getIndexPatternMock}
controlIndex={0}
controlParams={controlParams}

View file

@ -20,14 +20,30 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { injectI18n } from '@kbn/i18n/react';
import chrome from 'ui/chrome';
import {
EuiFormRow,
EuiComboBox,
} from '@elastic/eui';
import { EuiComboBox } from '@elastic/eui';
class IndexPatternSelectUi extends Component {
const getIndexPatterns = async (search) => {
const resp = await chrome.getSavedObjectsClient().find({
type: 'index-pattern',
fields: ['title'],
search: `${search}*`,
search_fields: ['title'],
perPage: 100
});
return resp.savedObjects;
};
const getIndexPatternTitle = async (indexPatternId) => {
const savedObject = await chrome.getSavedObjectsClient().get('index-pattern', indexPatternId);
if (savedObject.error) {
throw new Error(`Unable to get index-pattern title: ${savedObject.error.message}`);
}
return savedObject.attributes.title;
};
export class IndexPatternSelect extends Component {
constructor(props) {
super(props);
@ -38,16 +54,13 @@ class IndexPatternSelectUi extends Component {
};
}
componentWillMount() {
this._isMounted = true;
}
componentWillUnmount() {
this._isMounted = false;
this.debouncedFetch.cancel();
}
componentDidMount() {
this._isMounted = true;
this.fetchOptions();
this.fetchSelectedIndexPattern(this.props.indexPatternId);
}
@ -66,9 +79,9 @@ class IndexPatternSelectUi extends Component {
return;
}
let indexPattern;
let indexPatternTitle;
try {
indexPattern = await this.props.getIndexPattern(indexPatternId);
indexPatternTitle = await getIndexPatternTitle(indexPatternId);
} catch (err) {
// index pattern no longer exists
return;
@ -80,14 +93,14 @@ class IndexPatternSelectUi extends Component {
this.setState({
selectedIndexPattern: {
value: indexPattern.id,
label: indexPattern.title,
value: indexPatternId,
label: indexPatternTitle,
}
});
}
debouncedFetch = _.debounce(async (searchValue) => {
const indexPatternSavedObjects = await this.props.getIndexPatterns(searchValue);
const savedObjects = await getIndexPatterns(searchValue);
if (!this._isMounted) {
return;
@ -96,7 +109,7 @@ class IndexPatternSelectUi extends Component {
// We need this check to handle the case where search results come back in a different
// order than they were sent out. Only load results for the most recent search.
if (searchValue === this.state.searchValue) {
const options = indexPatternSavedObjects.map((indexPatternSavedObject) => {
const options = savedObjects.map((indexPatternSavedObject) => {
return {
label: indexPatternSavedObject.attributes.title,
value: indexPatternSavedObject.id
@ -121,45 +134,30 @@ class IndexPatternSelectUi extends Component {
}
render() {
const selectId = `indexPatternSelect-${this.props.controlIndex}`;
const selectedOptions = [];
const { intl } = this.props;
if (this.state.selectedIndexPattern) {
selectedOptions.push(this.state.selectedIndexPattern);
}
const {
onChange, // eslint-disable-line no-unused-vars
indexPatternId, // eslint-disable-line no-unused-vars
placeholder,
...rest
} = this.props;
return (
<EuiFormRow
id={selectId}
label={intl.formatMessage({
id: 'inputControl.editor.indexPatternSelect.patternLabel',
defaultMessage: 'Index Pattern'
})}
>
<EuiComboBox
placeholder={intl.formatMessage({
id: 'inputControl.editor.indexPatternSelect.patternPlaceholder',
defaultMessage: 'Select index pattern...'
})}
singleSelection={true}
isLoading={this.state.isLoading}
onSearchChange={this.fetchOptions}
options={this.state.options}
selectedOptions={selectedOptions}
onChange={this.onChange}
data-test-subj={selectId}
/>
</EuiFormRow>
<EuiComboBox
placeholder={placeholder}
singleSelection={true}
isLoading={this.state.isLoading}
onSearchChange={this.fetchOptions}
options={this.state.options}
selectedOptions={this.state.selectedIndexPattern ? [this.state.selectedIndexPattern] : []}
onChange={this.onChange}
{...rest}
/>
);
}
}
IndexPatternSelectUi.propTypes = {
getIndexPatterns: PropTypes.func.isRequired,
getIndexPattern: PropTypes.func.isRequired,
IndexPatternSelect.propTypes = {
onChange: PropTypes.func.isRequired,
indexPatternId: PropTypes.string,
controlIndex: PropTypes.number.isRequired,
placeholder: PropTypes.string,
};
export const IndexPatternSelect = injectI18n(IndexPatternSelectUi);

View file

@ -17,6 +17,8 @@
* under the License.
*/
export { IndexPatternSelect } from './components/index_pattern_select';
export { IndexPatternsProvider } from './index_patterns';
export {