Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master' into lint-import-paths
Browse files Browse the repository at this point in the history
  • Loading branch information
flash1293 committed Dec 20, 2019
2 parents 8ffba7c + 60660fc commit 29af8ad
Show file tree
Hide file tree
Showing 36 changed files with 593 additions and 802 deletions.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* 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 { i18n } from '@kbn/i18n';
import React, { useState } from 'react';
import {
EuiButtonEmpty,
EuiPopover,
EuiPopoverTitle,
EuiSelectable,
EuiButtonEmptyProps,
} from '@elastic/eui';
import { EuiSelectableProps } from '@elastic/eui/src/components/selectable/selectable';
import { IndexPatternRef } from './types';

export type ChangeIndexPatternTriggerProps = EuiButtonEmptyProps & {
label: string;
title?: string;
};

// TODO: refactor to shared component with ../../../../../../../../x-pack/legacy/plugins/lens/public/indexpattern_plugin/change_indexpattern

export function ChangeIndexPattern({
indexPatternRefs,
indexPatternId,
onChangeIndexPattern,
trigger,
selectableProps,
}: {
trigger: ChangeIndexPatternTriggerProps;
indexPatternRefs: IndexPatternRef[];
onChangeIndexPattern: (newId: string) => void;
indexPatternId?: string;
selectableProps?: EuiSelectableProps;
}) {
const [isPopoverOpen, setPopoverIsOpen] = useState(false);

const createTrigger = function() {
const { label, title, ...rest } = trigger;
return (
<EuiButtonEmpty
className="eui-textTruncate"
flush="left"
color="text"
iconSide="right"
iconType="arrowDown"
title={title}
onClick={() => setPopoverIsOpen(!isPopoverOpen)}
{...rest}
>
{label}
</EuiButtonEmpty>
);
};

return (
<EuiPopover
button={createTrigger()}
isOpen={isPopoverOpen}
closePopover={() => setPopoverIsOpen(false)}
className="eui-textTruncate"
anchorClassName="eui-textTruncate"
display="block"
panelPaddingSize="s"
ownFocus
>
<div style={{ width: 320 }}>
<EuiPopoverTitle>
{i18n.translate('kbn.discover.fieldChooser.indexPattern.changeIndexPatternTitle', {
defaultMessage: 'Change index pattern',
})}
</EuiPopoverTitle>
<EuiSelectable
data-test-subj="indexPattern-switcher"
{...selectableProps}
searchable
singleSelection="always"
options={indexPatternRefs.map(({ title, id }) => ({
label: title,
key: id,
value: id,
checked: id === indexPatternId ? 'on' : undefined,
}))}
onChange={choices => {
const choice = (choices.find(({ checked }) => checked) as unknown) as {
value: string;
};
onChangeIndexPattern(choice.value);
setPopoverIsOpen(false);
}}
searchProps={{
compressed: true,
...(selectableProps ? selectableProps.searchProps : undefined),
}}
>
{(list, search) => (
<>
{search}
{list}
</>
)}
</EuiSelectable>
</div>
</EuiPopover>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,61 @@
* under the License.
*/
import React from 'react';
import { shallowWithIntl, mountWithIntl } from 'test_utils/enzyme_helpers';
import { shallowWithIntl as shallow } from 'test_utils/enzyme_helpers';

// @ts-ignore
import { findTestSubject } from '@elastic/eui/lib/test';
import { ShallowWrapper } from 'enzyme';
import { ChangeIndexPattern } from './change_indexpattern';
import { SavedObject } from 'kibana/server';
import { DiscoverIndexPattern, DiscoverIndexPatternProps } from './discover_index_pattern';
import { comboBoxKeyCodes } from '@elastic/eui';
import { DiscoverIndexPattern } from './discover_index_pattern';
import { EuiSelectable, EuiSelectableList } from '@elastic/eui';

const indexPattern1 = {
id: 'test1',
attributes: {
title: 'test1',
title: 'test1 title',
},
} as SavedObject;

const indexPattern2 = {
id: 'test2',
attributes: {
title: 'test2',
title: 'test2 title',
},
} as SavedObject;

const defaultProps = {
indexPatternList: [indexPattern1, indexPattern2],
selectedIndexPattern: indexPattern1,
setIndexPattern: jest.fn(async () => {}),
};

function getIndexPatternPickerList(instance: ShallowWrapper) {
return instance
.find(ChangeIndexPattern)
.first()
.dive()
.find(EuiSelectable);
}

function getIndexPatternPickerOptions(instance: ShallowWrapper) {
return getIndexPatternPickerList(instance)
.dive()
.find(EuiSelectableList)
.prop('options');
}

function selectIndexPatternPickerOption(instance: ShallowWrapper, selectedLabel: string) {
const options: Array<{ label: string; checked?: 'on' | 'off' }> = getIndexPatternPickerOptions(
instance
).map((option: any) =>
option.label === selectedLabel
? { ...option, checked: 'on' }
: { ...option, checked: undefined }
);
return getIndexPatternPickerList(instance).prop('onChange')!(options);
}

describe('DiscoverIndexPattern', () => {
test('Invalid props dont cause an exception', () => {
const props = {
Expand All @@ -46,30 +80,21 @@ describe('DiscoverIndexPattern', () => {
setIndexPattern: jest.fn(),
} as any;

expect(shallowWithIntl(<DiscoverIndexPattern {...props} />)).toMatchSnapshot(`""`);
expect(shallow(<DiscoverIndexPattern {...props} />)).toMatchSnapshot(`""`);
});
test('A single index pattern is just displayed', () => {
const props = {
indexPatternList: [indexPattern1],
selectedIndexPattern: indexPattern1,
setIndexPattern: jest.fn(),
} as DiscoverIndexPatternProps;
test('should list all index patterns', () => {
const instance = shallow(<DiscoverIndexPattern {...defaultProps} />);

expect(shallowWithIntl(<DiscoverIndexPattern {...props} />)).toMatchSnapshot();
expect(getIndexPatternPickerOptions(instance)!.map((option: any) => option.label)).toEqual([
'test1 title',
'test2 title',
]);
});

test('Multiple index patterns are selectable', () => {
const props = {
indexPatternList: [indexPattern1, indexPattern2],
selectedIndexPattern: indexPattern2,
setIndexPattern: jest.fn(),
} as DiscoverIndexPatternProps;
const component = mountWithIntl(<DiscoverIndexPattern {...props} />);
findTestSubject(component, 'indexPattern-switch-link').simulate('click');
test('should switch data panel to target index pattern', () => {
const instance = shallow(<DiscoverIndexPattern {...defaultProps} />);

const searchInput = findTestSubject(component, 'comboBoxSearchInput');
searchInput.simulate('change', { target: { value: 'test1' } });
searchInput.simulate('keyDown', { keyCode: comboBoxKeyCodes.ENTER });
expect(props.setIndexPattern).toBeCalledWith('test1');
selectIndexPatternPickerOption(instance, 'test2 title');
expect(defaultProps.setIndexPattern).toHaveBeenCalledWith('test2');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@
* 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';
import { I18nProvider } from '@kbn/i18n/react';

import { IndexPatternRef } from './types';
import { ChangeIndexPattern } from './change_indexpattern';
export interface DiscoverIndexPatternProps {
/**
* list of available index patterns, if length > 1, component offers a "change" link
Expand Down Expand Up @@ -48,60 +49,37 @@ export function DiscoverIndexPattern({
// 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 options: IndexPatternRef[] = indexPatternList.map(entity => ({
id: entity.id,
title: 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 (
<DiscoverIndexPatternTitle
isChangeable={indexPatternList.length > 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);
}
const [selected, setSelected] = useState({
id: selectedIndexPattern.id,
title: selectedIndexPattern.attributes!.title,
});

return (
<EuiComboBox
className="index-pattern-selection"
data-test-subj="index-pattern-selection"
fullWidth={true}
isClearable={false}
onBlur={() => 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 }}
/>
<div className="indexPattern__container">
<I18nProvider>
<ChangeIndexPattern
trigger={{
label: selected.title,
title: selected.title,
'data-test-subj': 'indexPattern-switch-link',
className: 'indexPattern__triggerButton',
}}
indexPatternId={selected.id}
indexPatternRefs={options}
onChangeIndexPattern={id => {
const indexPattern = options.find(pattern => pattern.id === id);
if (indexPattern) {
setIndexPattern(id);
setSelected(indexPattern);
}
}}
/>
</I18nProvider>
</div>
);
}
Loading

0 comments on commit 29af8ad

Please sign in to comment.