[Lens] fix FieldPicker passes the prop to the DOM when it shouldn't (#159930)

## Summary

When opening the field picker, the error in the console appears:
<img width="837" alt="Screenshot 2023-06-19 at 15 45 39"
src="10fbc0e6-ae59-4c3b-ab94-80dd86805ca6">

That's because we pass `exists` props to the `styledOptions` which are
passed to the dom.
The thing is we don't need to pass this prop. We assign the classname
based on `exists` value at the same level and then do the styling but
then don't use it in any level deeper, so no need to pass it. So I
removed it to fix this error.

fixes errors that show in tests too:
<img width="605" alt="Screenshot 2023-06-19 at 20 54 58"
src="1583070f-8e18-4494-9892-585bef584588">
<img width="761" alt="Screenshot 2023-06-19 at 20 55 39"
src="23aab03b-0204-478b-aa01-fab801d02e78">
<img width="730" alt="Screenshot 2023-06-19 at 20 56 49"
src="cae606f5-54a8-4da9-99cf-e5151302acae">
This commit is contained in:
Marta Bondyra 2023-06-20 09:36:09 +02:00 committed by GitHub
parent 58ec0a486f
commit 2fd8f04abe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 102 additions and 82 deletions

View file

@ -44,13 +44,11 @@ export function FieldPicker<T extends FieldOptionValue = FieldOptionValue>({
if (otherAttr.options) {
return {
...otherAttr,
compatible,
exists,
options: otherAttr.options.map((fieldOption) => ({
options: otherAttr.options.map(({ exists: fieldOptionExists, ...fieldOption }) => ({
...fieldOption,
className: classNames({
'lnFieldPicker__option--incompatible': !fieldOption.compatible,
'lnFieldPicker__option--nonExistant': !fieldOption.exists,
'lnFieldPicker__option--nonExistant': !fieldOptionExists,
}),
})),
};
@ -58,7 +56,6 @@ export function FieldPicker<T extends FieldOptionValue = FieldOptionValue>({
return {
...otherAttr,
compatible,
exists,
className: classNames({
'lnFieldPicker__option--incompatible': !compatible,
'lnFieldPicker__option--nonExistant': !exists,

View file

@ -547,7 +547,7 @@ describe('FormBasedDimensionEditor', () => {
);
});
it('should keep the operation when switching to another field compatible with this operation', () => {
it('should keep the operation when switching to another field compatible with this operation', async () => {
const initialState: FormBasedPrivateState = getStateWithColumns({ col1: bytesColumn });
wrapper = mountWithServices(
@ -559,8 +559,8 @@ describe('FormBasedDimensionEditor', () => {
.filter('[data-test-subj="indexPattern-dimension-field"]')!;
const option = comboBox.prop('options')![1].options!.find(({ label }) => label === 'memory')!;
act(() => {
comboBox.prop('onChange')!([option]);
await act(async () => {
await comboBox.prop('onChange')!([option]);
});
expect(setState.mock.calls[0]).toEqual([
@ -586,7 +586,7 @@ describe('FormBasedDimensionEditor', () => {
});
});
it('should switch operations when selecting a field that requires another operation', () => {
it('should switch operations when selecting a field that requires another operation', async () => {
wrapper = mountWithServices(<FormBasedDimensionEditorComponent {...defaultProps} />);
const comboBox = wrapper
@ -594,8 +594,8 @@ describe('FormBasedDimensionEditor', () => {
.filter('[data-test-subj="indexPattern-dimension-field"]')!;
const option = comboBox.prop('options')![1].options!.find(({ label }) => label === 'source')!;
act(() => {
comboBox.prop('onChange')!([option]);
await act(async () => {
await comboBox.prop('onChange')!([option]);
});
expect(setState.mock.calls[0]).toEqual([
@ -797,11 +797,11 @@ describe('FormBasedDimensionEditor', () => {
});
describe('transient invalid state', () => {
it('should set the state if selecting an operation incompatible with the current field', () => {
it('should set the state if selecting an operation incompatible with the current field', async () => {
wrapper = mountWithServices(<FormBasedDimensionEditorComponent {...defaultProps} />);
act(() => {
wrapper
await act(async () => {
await wrapper
.find('button[data-test-subj="lns-indexPatternDimension-terms incompatible"]')
.simulate('click');
});
@ -873,19 +873,16 @@ describe('FormBasedDimensionEditor', () => {
expect(wrapper.find('[data-test-subj="indexPattern-invalid-operation"]')).toHaveLength(0);
});
it('should leave error state when switching from incomplete state to fieldless operation', () => {
it('should leave error state when switching from incomplete state to fieldless operation', async () => {
// @ts-expect-error
window['__react-beautiful-dnd-disable-dev-warnings'] = true; // issue with enzyme & react-beautiful-dnd throwing errors: https://github.com/atlassian/react-beautiful-dnd/issues/1593
wrapper = mountWithServices(<FormBasedDimensionEditorComponent {...defaultProps} />);
act(() => {
wrapper
await act(async () => {
await wrapper
.find('button[data-test-subj="lns-indexPatternDimension-terms incompatible"]')
.simulate('click');
});
act(() => {
wrapper
await wrapper
.find('button[data-test-subj="lns-indexPatternDimension-filters"]')
.simulate('click');
});
@ -925,11 +922,11 @@ describe('FormBasedDimensionEditor', () => {
expect(wrapper.find('[data-test-subj="indexPattern-invalid-operation"]')).toHaveLength(0);
});
it('should indicate fields compatible with selected operation', () => {
it('should indicate fields compatible with selected operation', async () => {
wrapper = mountWithServices(<FormBasedDimensionEditorComponent {...defaultProps} />);
act(() => {
wrapper
await act(async () => {
await wrapper
.find('button[data-test-subj="lns-indexPatternDimension-terms incompatible"]')
.simulate('click');
});
@ -949,13 +946,13 @@ describe('FormBasedDimensionEditor', () => {
).not.toContain('Incompatible');
});
it('should select compatible operation if field not compatible with selected operation', () => {
it('should select compatible operation if field not compatible with selected operation', async () => {
wrapper = mountWithServices(
<FormBasedDimensionEditorComponent {...defaultProps} columnId={'col2'} />
);
act(() => {
wrapper
await act(async () => {
await wrapper
.find('button[data-test-subj="lns-indexPatternDimension-average"]')
.simulate('click');
});
@ -964,7 +961,11 @@ describe('FormBasedDimensionEditor', () => {
expect.any(Function),
{ isDimensionComplete: false },
]);
expect(setState.mock.calls[0][0](state)).toEqual({
let returnedState: FormBasedPrivateState = {} as FormBasedPrivateState;
act(() => {
returnedState = setState.mock.calls[0][0](state);
});
expect(returnedState).toEqual({
...state,
layers: {
first: {
@ -982,8 +983,8 @@ describe('FormBasedDimensionEditor', () => {
const options = comboBox.prop('options');
// options[1][2] is a `source` field of type `string` which doesn't support `average` operation
act(() => {
comboBox.prop('onChange')!([options![1].options![2]]);
await act(async () => {
await comboBox.prop('onChange')!([options![1].options![2]]);
});
expect(setState.mock.calls[1][0](state)).toEqual({
@ -1042,7 +1043,7 @@ describe('FormBasedDimensionEditor', () => {
});
});
it('should select the Records field when count is selected on non-existing column', () => {
it('should select the Records field when count is selected on non-existing column', async () => {
wrapper = mountWithServices(
<FormBasedDimensionEditorComponent
{...defaultProps}
@ -1051,8 +1052,10 @@ describe('FormBasedDimensionEditor', () => {
/>
);
act(() => {
wrapper.find('button[data-test-subj="lns-indexPatternDimension-count"]').simulate('click');
await act(async () => {
await wrapper
.find('button[data-test-subj="lns-indexPatternDimension-count"]')
.simulate('click');
});
const newColumnState = setState.mock.calls[0][0](state).layers.first.columns.col2;
@ -1060,7 +1063,7 @@ describe('FormBasedDimensionEditor', () => {
expect(newColumnState.sourceField).toEqual('___records___');
});
it('should indicate document and field compatibility with selected document operation', () => {
it('should indicate document and field compatibility with selected document operation', async () => {
wrapper = mountWithServices(
<FormBasedDimensionEditorComponent
{...defaultProps}
@ -1076,20 +1079,17 @@ describe('FormBasedDimensionEditor', () => {
columnId="col2"
/>
);
act(() => {
wrapper
.find('button[data-test-subj="lns-indexPatternDimension-terms incompatible"]')
.simulate('click');
const terms = wrapper.find(
'button[data-test-subj="lns-indexPatternDimension-terms incompatible"]'
);
await act(async () => {
await terms.simulate('click');
});
const options = wrapper
.find(EuiComboBox)
.filter('[data-test-subj="indexPattern-dimension-field"]')
.prop('options');
expect(options![0]['data-test-subj']).toContain('Incompatible');
expect(
options![1].options!.filter(({ label }) => label === 'timestampLabel')[0]['data-test-subj']
).toContain('Incompatible');
@ -1098,24 +1098,20 @@ describe('FormBasedDimensionEditor', () => {
).not.toContain('Incompatible');
});
it('should set datasource state if compatible field is selected for operation', () => {
it('should set datasource state if compatible field is selected for operation', async () => {
wrapper = mountWithServices(<FormBasedDimensionEditorComponent {...defaultProps} />);
act(() => {
wrapper
await act(async () => {
await wrapper
.find('button[data-test-subj="lns-indexPatternDimension-terms incompatible"]')
.simulate('click');
});
const comboBox = wrapper
.find(EuiComboBox)
.filter('[data-test-subj="indexPattern-dimension-field"]')!;
const option = comboBox.prop('options')![1].options!.find(({ label }) => label === 'source')!;
act(() => {
comboBox.prop('onChange')!([option]);
await act(async () => {
await comboBox.prop('onChange')!([option]);
});
expect(setState.mock.calls.length).toEqual(2);
expect(setState.mock.calls[1]).toEqual([
expect.any(Function),
@ -1471,7 +1467,9 @@ describe('FormBasedDimensionEditor', () => {
timeShift: '1d',
});
wrapper = mountWithServices(<FormBasedDimensionEditorComponent {...props} />);
wrapper.find(ReducedTimeRange).find(EuiComboBox).prop('onCreateOption')!('7m', []);
act(() => {
wrapper.find(ReducedTimeRange).find(EuiComboBox).prop('onCreateOption')!('7m', []);
});
expect((props.setState as jest.Mock).mock.calls[0][0](props.state)).toEqual({
...props.state,
layers: {
@ -1643,7 +1641,9 @@ describe('FormBasedDimensionEditor', () => {
timeShift: '1d',
});
wrapper = mountWithServices(<FormBasedDimensionEditorComponent {...props} />);
wrapper.find(TimeShift).find(EuiComboBox).prop('onCreateOption')!('1h', []);
act(() => {
wrapper.find(TimeShift).find(EuiComboBox).prop('onCreateOption')!('1h', []);
});
expect((props.setState as jest.Mock).mock.calls[0][0](props.state)).toEqual({
...props.state,
layers: {
@ -1856,15 +1856,21 @@ describe('FormBasedDimensionEditor', () => {
]);
});
it('should support selecting the operation before the field', () => {
it('should support selecting the operation before the field', async () => {
wrapper = mountWithServices(
<FormBasedDimensionEditorComponent {...defaultProps} columnId={'col2'} />
);
act(() => {
wrapper.find('button[data-test-subj="lns-indexPatternDimension-average"]').simulate('click');
await act(async () => {
await wrapper
.find('button[data-test-subj="lns-indexPatternDimension-average"]')
.simulate('click');
});
expect(setState.mock.calls[0]).toEqual([expect.any(Function), { isDimensionComplete: false }]);
expect(setState.mock.calls[0][0](defaultProps.state)).toEqual({
let returnedState: FormBasedPrivateState = {} as FormBasedPrivateState;
act(() => {
returnedState = setState.mock.calls[0][0](defaultProps.state);
});
expect(returnedState).toEqual({
...state,
layers: {
first: {
@ -1883,8 +1889,8 @@ describe('FormBasedDimensionEditor', () => {
.filter('[data-test-subj="indexPattern-dimension-field"]');
const options = comboBox.prop('options');
act(() => {
comboBox.prop('onChange')!([options![1].options![0]]);
await act(async () => {
await comboBox.prop('onChange')!([options![1].options![0]]);
});
expect(setState.mock.calls[1][0](defaultProps.state)).toEqual({
@ -1906,7 +1912,7 @@ describe('FormBasedDimensionEditor', () => {
});
});
it('should select operation directly if only one field is possible', () => {
it('should select operation directly if only one field is possible', async () => {
wrapper = mountWithServices(
<FormBasedDimensionEditorComponent
{...defaultProps}
@ -1921,11 +1927,17 @@ describe('FormBasedDimensionEditor', () => {
}}
/>
);
act(() => {
wrapper.find('button[data-test-subj="lns-indexPatternDimension-average"]').simulate('click');
await act(async () => {
await wrapper
.find('button[data-test-subj="lns-indexPatternDimension-average"]')
.simulate('click');
});
expect(setState.mock.calls[0]).toEqual([expect.any(Function), { isDimensionComplete: true }]);
expect(setState.mock.calls[0][0](state)).toEqual({
let returnedState: FormBasedPrivateState = {} as FormBasedPrivateState;
act(() => {
returnedState = setState.mock.calls[0][0](state);
});
expect(returnedState).toEqual({
...state,
layers: {
first: {
@ -1944,15 +1956,21 @@ describe('FormBasedDimensionEditor', () => {
});
});
it('should select operation directly if only document is possible', () => {
it('should select operation directly if only document is possible', async () => {
wrapper = mountWithServices(
<FormBasedDimensionEditorComponent {...defaultProps} columnId={'col2'} />
);
act(() => {
wrapper.find('button[data-test-subj="lns-indexPatternDimension-count"]').simulate('click');
await act(async () => {
await wrapper
.find('button[data-test-subj="lns-indexPatternDimension-count"]')
.simulate('click');
});
expect(setState.mock.calls[0]).toEqual([expect.any(Function), { isDimensionComplete: true }]);
expect(setState.mock.calls[0][0](state)).toEqual({
let returnedState: FormBasedPrivateState = {} as FormBasedPrivateState;
act(() => {
returnedState = setState.mock.calls[0][0](state);
});
expect(returnedState).toEqual({
...state,
layers: {
first: {
@ -2022,7 +2040,7 @@ describe('FormBasedDimensionEditor', () => {
expect(options![0]['data-test-subj']).not.toContain('Incompatible');
});
it('should not update when selecting the current field again', () => {
it('should not update when selecting the current field again', async () => {
wrapper = mountWithServices(<FormBasedDimensionEditorComponent {...defaultProps} />);
const comboBox = wrapper
@ -2033,8 +2051,8 @@ describe('FormBasedDimensionEditor', () => {
.prop('options')![1]
.options!.find(({ label }) => label === 'timestampLabel')!;
act(() => {
comboBox.prop('onChange')!([option]);
await act(async () => {
await comboBox.prop('onChange')!([option]);
});
expect(setState).not.toHaveBeenCalled();
@ -2070,7 +2088,7 @@ describe('FormBasedDimensionEditor', () => {
]);
});
it('should add a column on selection of a field', () => {
it('should add a column on selection of a field', async () => {
// Prevents field format from being loaded
setState.mockImplementation(() => {});
@ -2083,15 +2101,20 @@ describe('FormBasedDimensionEditor', () => {
.filter('[data-test-subj="indexPattern-dimension-field"]')!;
const option = comboBox.prop('options')![1].options![0];
act(() => {
comboBox.prop('onChange')!([option]);
await act(async () => {
await comboBox.prop('onChange')!([option]);
});
expect(setState.mock.calls[0]).toEqual([
expect.any(Function),
{ isDimensionComplete: true, forceRender: false },
]);
expect(setState.mock.calls[0][0](defaultProps.state)).toEqual({
let returnedState: FormBasedPrivateState | null = null;
act(() => {
returnedState = setState.mock.calls[0][0](defaultProps.state);
});
expect(returnedState).toEqual({
...state,
layers: {
first: {
@ -2273,14 +2296,14 @@ describe('FormBasedDimensionEditor', () => {
});
});
it('should hide the top level field selector when switching from non-reference to reference', () => {
it('should hide the top level field selector when switching from non-reference to reference', async () => {
(generateId as jest.Mock).mockReturnValue(`second`);
wrapper = mountWithServices(<FormBasedDimensionEditorComponent {...defaultProps} />);
expect(wrapper.find('ReferenceEditor')).toHaveLength(0);
act(() => {
wrapper
await act(async () => {
await wrapper
.find('button[data-test-subj="lns-indexPatternDimension-differences incompatible"]')
.simulate('click');
});

View file

@ -6,7 +6,7 @@
*/
import { i18n } from '@kbn/i18n';
import React from 'react';
import React, { Fragment } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import type { IndexPattern, IndexPatternField } from '../../../../types';
import {
@ -103,10 +103,10 @@ export const generateMissingFieldMessage = (
missingFields: (
<>
{missingFields.map((field, index) => (
<>
<Fragment key={field}>
<strong>{field}</strong>
{index + 1 === missingFields.length ? '' : ', '}
</>
</Fragment>
))}
</>
),

View file

@ -267,8 +267,8 @@ describe('LayerPanel', () => {
dimensionsTooMany: 1,
},
{
groupLabel: 'A',
groupId: 'a',
groupLabel: 'C',
groupId: 'c',
accessors: [{ columnId: 'x' }],
filterOperations: () => true,
supportsMoreColumns: false,