diff --git a/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/field_chooser.js b/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/field_chooser.js index e316dd3254cc0..c2be750ec7f63 100644 --- a/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/field_chooser.js +++ b/src/legacy/core_plugins/kibana/public/discover/__tests__/directives/field_chooser.js @@ -127,13 +127,6 @@ describe('discover field chooser directives', function () { }; }; - describe('Index list', function () { - it('should be in alphabetical order', function () { - $elem.find('.ui-select-toggle').click(); - expect($elem.find('[role=option]').text().replace(/\W+/g, '')).to.be('abc'); - }); - }); - describe('Field listing', function () { it('should have Selected Fields, Fields and Popular Fields sections', function () { const headers = $elem.find('.sidebar-list-header'); diff --git a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/__snapshots__/discover_index_pattern.test.tsx.snap b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/__snapshots__/discover_index_pattern.test.tsx.snap new file mode 100644 index 0000000000000..d7737bbfe4078 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/__snapshots__/discover_index_pattern.test.tsx.snap @@ -0,0 +1,11 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`DiscoverIndexPattern A single index pattern is just displayed 1`] = ` + +`; + +exports[`DiscoverIndexPattern Invalid props dont cause an exception: "" 1`] = `""`; diff --git a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_index_pattern.test.tsx b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_index_pattern.test.tsx new file mode 100644 index 0000000000000..68ef0f5b46694 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_index_pattern.test.tsx @@ -0,0 +1,75 @@ +/* + * 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 { shallowWithIntl, mountWithIntl } from 'test_utils/enzyme_helpers'; +// @ts-ignore +import { findTestSubject } from '@elastic/eui/lib/test'; +import { SavedObject } from 'kibana/server'; +import { DiscoverIndexPattern, DiscoverIndexPatternProps } from './discover_index_pattern'; +import { comboBoxKeyCodes } from '@elastic/eui'; + +const indexPattern1 = { + id: 'test1', + attributes: { + title: 'test1', + }, +} as SavedObject; + +const indexPattern2 = { + id: 'test2', + attributes: { + title: 'test2', + }, +} as SavedObject; + +describe('DiscoverIndexPattern', () => { + test('Invalid props dont cause an exception', () => { + const props = { + indexPatternList: null, + selectedIndexPattern: null, + setIndexPattern: jest.fn(), + } as any; + + expect(shallowWithIntl()).toMatchSnapshot(`""`); + }); + test('A single index pattern is just displayed', () => { + const props = { + indexPatternList: [indexPattern1], + selectedIndexPattern: indexPattern1, + setIndexPattern: jest.fn(), + } as DiscoverIndexPatternProps; + + expect(shallowWithIntl()).toMatchSnapshot(); + }); + + test('Multiple index patterns are selectable', () => { + const props = { + indexPatternList: [indexPattern1, indexPattern2], + selectedIndexPattern: indexPattern2, + setIndexPattern: jest.fn(), + } as DiscoverIndexPatternProps; + const component = mountWithIntl(); + findTestSubject(component, 'indexPattern-switch-link').simulate('click'); + + const searchInput = findTestSubject(component, 'comboBoxSearchInput'); + searchInput.simulate('change', { target: { value: 'test1' } }); + searchInput.simulate('keyDown', { keyCode: comboBoxKeyCodes.ENTER }); + expect(props.setIndexPattern).toBeCalledWith('test1'); + }); +}); diff --git a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_index_pattern.tsx b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_index_pattern.tsx new file mode 100644 index 0000000000000..55f58d352ac23 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_index_pattern.tsx @@ -0,0 +1,107 @@ +/* + * 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, { useState } from 'react'; +import { EuiComboBox } from '@elastic/eui'; +import { SavedObject } from 'kibana/server'; +import { DiscoverIndexPatternTitle } from './discover_index_pattern_title'; + +export interface DiscoverIndexPatternProps { + /** + * list of available index patterns, if length > 1, component offers a "change" link + */ + indexPatternList: SavedObject[]; + /** + * currently selected index pattern, due to angular issues it's undefined at first rendering + */ + selectedIndexPattern: SavedObject; + /** + * triggered when user selects a new index pattern + */ + setIndexPattern: (id: string) => void; +} + +/** + * Component allows you to select an index pattern in discovers side bar + */ +export function DiscoverIndexPattern({ + indexPatternList, + selectedIndexPattern, + setIndexPattern, +}: DiscoverIndexPatternProps) { + if (!indexPatternList || indexPatternList.length === 0 || !selectedIndexPattern) { + // just in case, shouldn't happen + return null; + } + const [selected, setSelected] = useState(selectedIndexPattern); + const [showCombo, setShowCombo] = useState(false); + const options = indexPatternList.map(entity => ({ + value: entity.id, + label: entity.attributes!.title, + })); + const selectedOptions = selected + ? [{ value: selected.id, label: selected.attributes.title }] + : []; + + const findIndexPattern = (id?: string) => indexPatternList.find(entity => entity.id === id); + + if (!showCombo) { + return ( + 1} + onChange={() => setShowCombo(true)} + title={selected.attributes ? selected.attributes.title : ''} + /> + ); + } + + /** + * catches a EuiComboBox related 'Can't perform a React state update on an unmounted component' + * warning in console by delaying the hiding/removal of the EuiComboBox a bit + */ + function hideCombo() { + setTimeout(() => setShowCombo(false), 50); + } + + return ( + hideCombo()} + onChange={choices => { + const newSelected = choices[0] && findIndexPattern(choices[0].value); + if (newSelected) { + setSelected(newSelected); + setIndexPattern(newSelected.id); + } + hideCombo(); + }} + inputRef={el => { + // auto focus input element when combo box is displayed + if (el) { + el.focus(); + } + }} + options={options} + selectedOptions={selectedOptions} + singleSelection={{ asPlainText: true }} + /> + ); +} diff --git a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_index_pattern_directive.ts b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_index_pattern_directive.ts new file mode 100644 index 0000000000000..938d6cc226f2f --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_index_pattern_directive.ts @@ -0,0 +1,32 @@ +/* + * 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. + */ +// @ts-ignore +import { uiModules } from 'ui/modules'; +import { wrapInI18nContext } from 'ui/i18n'; +import { DiscoverIndexPattern } from './discover_index_pattern'; + +const app = uiModules.get('apps/discover'); + +app.directive('discoverIndexPatternSelect', function(reactDirective: any) { + return reactDirective(wrapInI18nContext(DiscoverIndexPattern), [ + ['indexPatternList', { watchDepth: 'reference' }], + ['selectedIndexPattern', { watchDepth: 'reference' }], + ['setIndexPattern', { watchDepth: 'reference' }], + ]); +}); diff --git a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_index_pattern_title.tsx b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_index_pattern_title.tsx new file mode 100644 index 0000000000000..23679c4db5a7f --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/discover_index_pattern_title.tsx @@ -0,0 +1,85 @@ +/* + * 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 { EuiToolTip, EuiFlexItem, EuiFlexGroup, EuiTitle, EuiButtonEmpty } from '@elastic/eui'; + +import { FormattedMessage } from '@kbn/i18n/react'; + +export interface DiscoverIndexPatternTitleProps { + /** + * determines whether the change link is displayed + */ + isChangeable: boolean; + /** + * function triggered when the change link is clicked + */ + onChange: () => void; + /** + * title of the current index pattern + */ + title: string; +} + +/** + * Component displaying the title of the current selected index pattern + * and if changeable is true, a link is provided to change the index pattern + */ +export function DiscoverIndexPatternTitle({ + isChangeable, + onChange, + title, +}: DiscoverIndexPatternTitleProps) { + return ( + + + + +

{title}

+
+
+
+ {isChangeable && ( + + + } + > + onChange()} + > + ( + + ) + + + + )} +
+ ); +} diff --git a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/field_chooser.html b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/field_chooser.html index 55c52baee7ba8..96aa1582b5243 100644 --- a/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/field_chooser.html +++ b/src/legacy/core_plugins/kibana/public/discover/components/field_chooser/field_chooser.html @@ -1,39 +1,14 @@