Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Lens] Use accordion menus in field list for available and empty fields #68871

Merged
merged 35 commits into from
Jun 26, 2020
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
faee220
feat: accordion with state external
mbondyra Jun 10, 2020
3b3af95
accordion with no external state
mbondyra Jun 10, 2020
88290a4
correct pagination
mbondyra Jun 11, 2020
da13172
test removing
mbondyra Jun 11, 2020
d8e3cec
fix i18n
mbondyra Jun 11, 2020
d13b2bc
Design PR
Jun 11, 2020
039d9b7
Merge pull request #1 from cchaos/mbondyra-lens/fielditems_empty_acco…
mbondyra Jun 12, 2020
9bff7c8
fix: aligning the field-select
mbondyra Jun 12, 2020
f4036c0
refactor: group fields & add proper selecting of filtered groups
mbondyra Jun 12, 2020
651d412
More spacing fixes
Jun 12, 2020
9442649
Merge pull request #2 from cchaos/mbondyra-lens/fielditems_empty_acco…
mbondyra Jun 15, 2020
6b56c09
refactor: extract NoFieldsCallout
mbondyra Jun 15, 2020
4277633
test added to no fields callout
mbondyra Jun 15, 2020
563f821
tests updated
mbondyra Jun 15, 2020
f582e23
Merge branch 'master' into lens/fielditems_empty_accordion
elasticmachine Jun 15, 2020
09cb8b5
test: remove not needed
mbondyra Jun 15, 2020
72188a6
Merge branch 'master' into lens/fielditems_empty_accordion
elasticmachine Jun 17, 2020
157c7d4
copy
mbondyra Jun 17, 2020
5cb1b3b
fix: correct pagination bug
mbondyra Jun 17, 2020
c19c0e8
fixes pagination_size and always displays affectedbyTimerange
mbondyra Jun 17, 2020
683a0e3
updating tests
mbondyra Jun 17, 2020
6a64c64
update copy in snapshots
mbondyra Jun 17, 2020
b0e9cfa
Merge commit 'a077fdea32ee63668ac545e28ad8db1fef587308' into lens/fie…
mbondyra Jun 18, 2020
1f6908b
perf improvements
mbondyra Jun 18, 2020
84647fe
controversial spinner?
mbondyra Jun 18, 2020
c20d982
Merge commit '4ce91b342c42b7798778d8d180206639876046b7' into lens/fie…
mbondyra Jun 18, 2020
78d0582
spinner tests
mbondyra Jun 18, 2020
6112e7a
feat: test of FieldItem without debounced hoc
mbondyra Jun 18, 2020
0063dbd
types
mbondyra Jun 18, 2020
bbca942
Merge branch 'master' into lens/fielditems_empty_accordion
elasticmachine Jun 25, 2020
c2d8c16
fix: spinner in right place, hooks rules
mbondyra Jun 25, 2020
0ad4772
perf: extracting fields_accordion & speeding up datapanel
mbondyra Jun 25, 2020
65451f0
tests added
mbondyra Jun 25, 2020
572d9a1
don't show callout if not loaded
mbondyra Jun 26, 2020
d609e6a
removing flexgroup
mbondyra Jun 26, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ export function loadInitialState() {
[restricted.id]: restricted,
},
layers: {},
showEmptyFields: false,
};
return result;
}

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
@@ -1,2 +1 @@
@import 'datapanel';
@import 'field_item';
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@
line-height: $euiSizeXXL;
}

.lnsInnerIndexPatternDataPanel__filterWrapper {
flex-grow: 0;
}

/**
* 1. Don't cut off the shadow of the field items
*/
Expand All @@ -41,11 +37,9 @@
right: $euiSizeXS; /* 1 */
}

.lnsInnerIndexPatternDataPanel__filterButton {
width: 100%;
color: $euiColorPrimary;
padding-left: $euiSizeS;
padding-right: $euiSizeS;
.lnsInnerIndexPatternDataPanel__fieldItems {
// Quick fix for making sure the shadow and focus rings are visible outside the accordion bounds
padding: $euiSizeXS $euiSizeXS 0;
}

.lnsInnerIndexPatternDataPanel__textField {
Expand All @@ -54,7 +48,9 @@
}

.lnsInnerIndexPatternDataPanel__filterType {
font-size: $euiFontSizeS;
padding: $euiSizeS;
border-bottom: 1px solid $euiColorLightestShade;
}

.lnsInnerIndexPatternDataPanel__filterTypeInner {
Expand Down
203 changes: 99 additions & 104 deletions x-pack/plugins/lens/public/indexpattern_datasource/datapanel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ import { createMockedDragDropContext } from './mocks';
import { dataPluginMock } from '../../../../../src/plugins/data/public/mocks';
import { InnerIndexPatternDataPanel, IndexPatternDataPanel, MemoizedDataPanel } from './datapanel';
import { FieldItem } from './field_item';
import { NoFieldsCallout } from './no_fields_callout';
import { act } from 'react-dom/test-utils';
import { coreMock } from 'src/core/public/mocks';
import { IndexPatternPrivateState } from './types';
import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers';
import { ChangeIndexPattern } from './change_indexpattern';
import { EuiProgress } from '@elastic/eui';
import { EuiProgress, EuiLoadingSpinner } from '@elastic/eui';
import { documentField } from './document_field';

const initialState: IndexPatternPrivateState = {
indexPatternRefs: [],
existingFields: {},
currentIndexPatternId: '1',
showEmptyFields: false,
layers: {
first: {
indexPatternId: '1',
Expand Down Expand Up @@ -229,8 +229,6 @@ describe('IndexPattern Data Panel', () => {
},
query: { query: '', language: 'lucene' },
filters: [],
showEmptyFields: false,
onToggleEmptyFields: jest.fn(),
};
});

Expand Down Expand Up @@ -303,7 +301,6 @@ describe('IndexPattern Data Panel', () => {
state: {
indexPatternRefs: [],
existingFields: {},
showEmptyFields: false,
currentIndexPatternId: 'a',
indexPatterns: {
a: { id: 'a', title: 'aaa', timeFieldName: 'atime', fields: [] },
Expand Down Expand Up @@ -534,42 +531,97 @@ describe('IndexPattern Data Panel', () => {
});
});

describe('while showing empty fields', () => {
it('should list all supported fields in the pattern sorted alphabetically', async () => {
const wrapper = shallowWithIntl(
<InnerIndexPatternDataPanel {...defaultProps} showEmptyFields={true} />
describe('displaying field list', () => {
let props: Parameters<typeof InnerIndexPatternDataPanel>[0];
beforeEach(() => {
props = {
...defaultProps,
existingFields: {
idx1: {
bytes: true,
memory: true,
},
},
};
});
it('should list all supported fields in the pattern sorted alphabetically in groups', async () => {
const wrapper = mountWithIntl(<InnerIndexPatternDataPanel {...props} />);
expect(wrapper.find(FieldItem).first().prop('field').name).toEqual('Records');
expect(
wrapper
.find('[data-test-subj="lnsIndexPatternAvailableFields"]')
.find(FieldItem)
.map((fieldItem) => fieldItem.prop('field').name)
).toEqual(['bytes', 'memory']);
wrapper
.find('[data-test-subj="lnsIndexPatternEmptyFields"]')
.find('button')
.first()
.simulate('click');
expect(
wrapper
.find('[data-test-subj="lnsIndexPatternEmptyFields"]')
.find(FieldItem)
.map((fieldItem) => fieldItem.prop('field').name)
).toEqual(['client', 'source', 'timestamp']);
});

it('should display NoFieldsCallout when all fields are empty', async () => {
const wrapper = mountWithIntl(
<InnerIndexPatternDataPanel {...defaultProps} existingFields={{ idx1: {} }} />
);
expect(wrapper.find(NoFieldsCallout).length).toEqual(1);
expect(
wrapper
.find('[data-test-subj="lnsIndexPatternAvailableFields"]')
.find(FieldItem)
.map((fieldItem) => fieldItem.prop('field').name)
).toEqual([]);
wrapper
.find('[data-test-subj="lnsIndexPatternEmptyFields"]')
.find('button')
.first()
.simulate('click');
expect(
wrapper
.find('[data-test-subj="lnsIndexPatternEmptyFields"]')
.find(FieldItem)
.map((fieldItem) => fieldItem.prop('field').name)
).toEqual(['bytes', 'client', 'memory', 'source', 'timestamp']);
});

expect(wrapper.find(FieldItem).map((fieldItem) => fieldItem.prop('field').name)).toEqual([
'Records',
'bytes',
'client',
'memory',
'source',
'timestamp',
]);
it('should display spinner for available fields accordion if existing fields are not loaded yet', async () => {
const wrapper = mountWithIntl(<InnerIndexPatternDataPanel {...defaultProps} />);
expect(
wrapper.find('[data-test-subj="lnsIndexPatternAvailableFields"]').find(EuiLoadingSpinner)
.length
).toEqual(1);
wrapper.setProps({ existingFields: { idx1: {} } });
expect(wrapper.find(NoFieldsCallout).length).toEqual(1);
});

it('should filter down by name', () => {
const wrapper = shallowWithIntl(
<InnerIndexPatternDataPanel {...defaultProps} showEmptyFields={true} />
);

const wrapper = mountWithIntl(<InnerIndexPatternDataPanel {...props} />);
act(() => {
wrapper.find('[data-test-subj="lnsIndexPatternFieldSearch"]').prop('onChange')!({
target: { value: 'mem' },
target: { value: 'me' },
} as ChangeEvent<HTMLInputElement>);
});

wrapper
.find('[data-test-subj="lnsIndexPatternEmptyFields"]')
.find('button')
.first()
.simulate('click');

expect(wrapper.find(FieldItem).map((fieldItem) => fieldItem.prop('field').name)).toEqual([
'memory',
'timestamp',
]);
});

it('should filter down by type', () => {
const wrapper = mountWithIntl(
<InnerIndexPatternDataPanel {...defaultProps} showEmptyFields={true} />
);
const wrapper = mountWithIntl(<InnerIndexPatternDataPanel {...props} />);

wrapper.find('[data-test-subj="lnsIndexPatternFiltersToggle"]').first().simulate('click');

Expand All @@ -581,112 +633,55 @@ describe('IndexPattern Data Panel', () => {
]);
});

it('should toggle type if clicked again', () => {
const wrapper = mountWithIntl(
<InnerIndexPatternDataPanel {...defaultProps} showEmptyFields={true} />
);
it('should display no fields in groups when filtered by type Record', () => {
const wrapper = mountWithIntl(<InnerIndexPatternDataPanel {...props} />);

wrapper.find('[data-test-subj="lnsIndexPatternFiltersToggle"]').first().simulate('click');

wrapper.find('[data-test-subj="typeFilter-number"]').first().simulate('click');
wrapper.find('[data-test-subj="typeFilter-number"]').first().simulate('click');
wrapper.find('[data-test-subj="typeFilter-document"]').first().simulate('click');

expect(wrapper.find(FieldItem).map((fieldItem) => fieldItem.prop('field').name)).toEqual([
'Records',
'bytes',
'client',
'memory',
'source',
'timestamp',
]);
expect(wrapper.find(NoFieldsCallout).length).toEqual(2);
});

it('should filter down by type and by name', () => {
const wrapper = mountWithIntl(
<InnerIndexPatternDataPanel {...defaultProps} showEmptyFields={true} />
);

act(() => {
wrapper.find('[data-test-subj="lnsIndexPatternFieldSearch"]').prop('onChange')!({
target: { value: 'mem' },
} as ChangeEvent<HTMLInputElement>);
});

it('should toggle type if clicked again', () => {
const wrapper = mountWithIntl(<InnerIndexPatternDataPanel {...props} />);
wrapper.find('[data-test-subj="lnsIndexPatternFiltersToggle"]').first().simulate('click');

wrapper.find('[data-test-subj="typeFilter-number"]').first().simulate('click');

expect(wrapper.find(FieldItem).map((fieldItem) => fieldItem.prop('field').name)).toEqual([
'memory',
]);
});
});

describe('filtering out empty fields', () => {
let emptyFieldsTestProps: typeof defaultProps;

beforeEach(() => {
emptyFieldsTestProps = {
...defaultProps,
indexPatterns: {
...defaultProps.indexPatterns,
'1': {
...defaultProps.indexPatterns['1'],
fields: defaultProps.indexPatterns['1'].fields.map((field) => ({
...field,
exists: field.type === 'number',
})),
},
},
onToggleEmptyFields: jest.fn(),
};
});

it('should list all supported fields in the pattern sorted alphabetically', async () => {
const props = {
...emptyFieldsTestProps,
existingFields: {
idx1: {
bytes: true,
memory: true,
},
},
};
const wrapper = shallowWithIntl(<InnerIndexPatternDataPanel {...props} />);

wrapper.find('[data-test-subj="typeFilter-number"]').first().simulate('click');
wrapper
.find('[data-test-subj="lnsIndexPatternEmptyFields"]')
.find('button')
.first()
.simulate('click');
expect(wrapper.find(FieldItem).map((fieldItem) => fieldItem.prop('field').name)).toEqual([
'Records',
'bytes',
'memory',
'client',
'source',
'timestamp',
]);
});

it('should filter down by name', () => {
const wrapper = shallowWithIntl(
<InnerIndexPatternDataPanel {...emptyFieldsTestProps} showEmptyFields={true} />
);

it('should filter down by type and by name', () => {
const wrapper = mountWithIntl(<InnerIndexPatternDataPanel {...props} />);
act(() => {
wrapper.find('[data-test-subj="lnsIndexPatternFieldSearch"]').prop('onChange')!({
target: { value: 'mem' },
target: { value: 'me' },
} as ChangeEvent<HTMLInputElement>);
});

expect(wrapper.find(FieldItem).map((fieldItem) => fieldItem.prop('field').name)).toEqual([
'memory',
]);
});

it('should allow removing the filter for data', () => {
const wrapper = mountWithIntl(<InnerIndexPatternDataPanel {...emptyFieldsTestProps} />);

wrapper.find('[data-test-subj="lnsIndexPatternFiltersToggle"]').first().simulate('click');

wrapper.find('[data-test-subj="lnsEmptyFilter"]').first().prop('onChange')!(
{} as ChangeEvent
);
wrapper.find('[data-test-subj="typeFilter-number"]').first().simulate('click');

expect(emptyFieldsTestProps.onToggleEmptyFields).toHaveBeenCalled();
expect(wrapper.find(FieldItem).map((fieldItem) => fieldItem.prop('field').name)).toEqual([
'memory',
]);
});
});
});
Loading