Skip to content

Commit

Permalink
[Lens] Revisit flyout fields style from column to row compressed (ela…
Browse files Browse the repository at this point in the history
…stic#120103)

* 💄 Revisit form style + spacers

* ✅ Fix tests

* ✨ Replace percentile input with range

* 💄 Fix mobile layout

* 💄 Make searchbar go below flyout

* 🔥 Remove unused jsx

* [Lens] Refactor Flyout Design Updates (#14)

* allow flyout to go full width on small viewports

* remove hiding of layer panel when flyout open

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Michael Marcialis <michael@marcial.is>
  • Loading branch information
3 people committed Dec 14, 2021
1 parent afefefa commit 7176dd5
Show file tree
Hide file tree
Showing 16 changed files with 149 additions and 103 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,15 @@
// Use the EuiFlyout style
@include euiFlyout;
// But with custom positioning to keep it within the sidebar contents
position: absolute;
left: 0;
animation: euiFlyout $euiAnimSpeedNormal $euiAnimSlightResistance;
left: 0;
max-width: none !important;
z-index: $euiZContentMenu;

@include euiBreakpoint('l', 'xl') {
top: 0 !important;
height: 100% !important;
}

@include euiBreakpoint('xs', 's', 'm') {
@include euiFlyout;
position: absolute;
top: 0 !important;
}

.lnsFrameLayout__sidebar-isFullscreen & {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -317,12 +317,7 @@ export function LayerPanel(

return (
<>
<section
tabIndex={-1}
ref={registerLayerRef}
className="lnsLayerPanel"
style={{ visibility: isDimensionPanelOpen ? 'hidden' : 'visible' }}
>
<section tabIndex={-1} ref={registerLayerRef} className="lnsLayerPanel">
<EuiPanel data-test-subj={`lns-layerPanel-${layerIndex}`} paddingSize="none">
<header className="lnsLayerPanel__layerHeader">
<EuiFlexGroup gutterSize="s" responsive={false} alignItems="center">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ export function AdvancedOptions(props: {
<>
{popoverOptions.length > 0 && (
<EuiText textAlign="right">
<EuiSpacer size="s" />
<EuiPopover
ownFocus
button={
Expand Down Expand Up @@ -69,17 +68,12 @@ export function AdvancedOptions(props: {
</EuiPopover>
</EuiText>
)}
{inlineOptions.length > 0 && (
<>
{inlineOptions.map((option) => (
<React.Fragment key={option.dataTestSubj}>
<EuiSpacer size="s" />
{inlineOptions.map((option, index) => (
<React.Fragment key={option.dataTestSubj}>
{option.inlineElement}
{index !== inlineOptions.length - 1 && <EuiSpacer size="s" />}
</React.Fragment>
))}
</>
)}
{option.inlineElement}
</React.Fragment>
))}
</>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ export function DimensionEditor(props: DimensionEditorProps) {
<div className="lnsIndexPatternDimensionEditor__section lnsIndexPatternDimensionEditor__section--padded lnsIndexPatternDimensionEditor__section--shaded">
<EuiFormLabel>
{i18n.translate('xpack.lens.indexPattern.functionsLabel', {
defaultMessage: 'Select a function',
defaultMessage: 'Functions',
})}
</EuiFormLabel>
<EuiSpacer size="s" />
Expand Down Expand Up @@ -474,7 +474,7 @@ export function DimensionEditor(props: DimensionEditorProps) {
/>
);
})}
<EuiSpacer size="s" />
{selectedOperationDefinition.selectionStyle !== 'field' ? <EuiSpacer size="s" /> : null}
</>
) : null}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export function Filtering({

return (
<EuiFormRow
display="columnCompressed"
display="rowCompressed"
label={filterByLabel}
fullWidth
isInvalid={!isInputFilterValid}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export function TimeScaling({

return (
<EuiFormRow
display="columnCompressed"
display="rowCompressed"
fullWidth
label={
<EuiToolTip
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export function TimeShift({
}}
>
<EuiFormRow
display="columnCompressed"
display="rowCompressed"
fullWidth
data-test-subj="indexPattern-dimension-time-shift-row"
label={i18n.translate('xpack.lens.indexPattern.timeShift.label', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ function MovingAverageParamEditor({
label={i18n.translate('xpack.lens.indexPattern.movingAverage.window', {
defaultMessage: 'Window size',
})}
display="columnCompressed"
display="rowCompressed"
fullWidth
isInvalid={!isValidNumber(inputValue)}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ export const lastValueOperation: OperationDefinition<LastValueIndexPatternColumn
label={i18n.translate('xpack.lens.indexPattern.lastValue.sortField', {
defaultMessage: 'Sort by date field',
})}
display="columnCompressed"
display="rowCompressed"
fullWidth
error={i18n.translate('xpack.lens.indexPattern.sortField.invalid', {
defaultMessage: 'Invalid field. Check your data view or pick another field.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import React from 'react';
import React, { ChangeEvent } from 'react';
import { shallow, mount } from 'enzyme';
import { IUiSettingsClient, SavedObjectsClientContract, HttpSetup } from 'kibana/public';
import { IStorageWrapper } from 'src/plugins/kibana_utils/public';
Expand All @@ -14,11 +14,20 @@ import { createMockedIndexPattern } from '../../mocks';
import { percentileOperation } from './index';
import { IndexPattern, IndexPatternLayer } from '../../types';
import { PercentileIndexPatternColumn } from './percentile';
import { EuiFieldNumber } from '@elastic/eui';
import { EuiRange } from '@elastic/eui';
import { act } from 'react-dom/test-utils';
import { EuiFormRow } from '@elastic/eui';
import { TermsIndexPatternColumn } from './terms';

jest.mock('lodash', () => {
const original = jest.requireActual('lodash');

return {
...original,
debounce: (fn: unknown) => fn,
};
});

const uiSettingsMock = {} as IUiSettingsClient;

const defaultProps = {
Expand Down Expand Up @@ -272,8 +281,7 @@ describe('percentile', () => {
expect(input.prop('value')).toEqual('23');
});

it('should update state on change', async () => {
jest.useFakeTimers();
it('should update state on change', () => {
const updateLayerSpy = jest.fn();
const instance = mount(
<InlineOptions
Expand All @@ -285,20 +293,19 @@ describe('percentile', () => {
/>
);

jest.runAllTimers();

const input = instance.find(
'[data-test-subj="lns-indexPattern-percentile-input"] input[type="number"]'
);
const input = instance
.find('[data-test-subj="lns-indexPattern-percentile-input"]')
.find(EuiRange);

await act(async () => {
input.simulate('change', { target: { value: '27' } });
act(() => {
input.prop('onChange')!(
{ currentTarget: { value: '27' } } as ChangeEvent<HTMLInputElement>,
true
);
});

instance.update();

jest.runAllTimers();

expect(updateLayerSpy).toHaveBeenCalledWith({
...layer,
columns: {
Expand All @@ -314,7 +321,7 @@ describe('percentile', () => {
});
});

it('should not update on invalid input, but show invalid value locally', async () => {
it('should not update on invalid input, but show invalid value locally', () => {
const updateLayerSpy = jest.fn();
const instance = mount(
<InlineOptions
Expand All @@ -326,20 +333,19 @@ describe('percentile', () => {
/>
);

jest.runAllTimers();

const input = instance.find(
'[data-test-subj="lns-indexPattern-percentile-input"] input[type="number"]'
);
const input = instance
.find('[data-test-subj="lns-indexPattern-percentile-input"]')
.find(EuiRange);

await act(async () => {
input.simulate('change', { target: { value: '12.12' } });
act(() => {
input.prop('onChange')!(
{ currentTarget: { value: '12.12' } } as ChangeEvent<HTMLInputElement>,
true
);
});

instance.update();

jest.runAllTimers();

expect(updateLayerSpy).not.toHaveBeenCalled();

expect(
Expand All @@ -351,7 +357,7 @@ describe('percentile', () => {
expect(
instance
.find('[data-test-subj="lns-indexPattern-percentile-input"]')
.find(EuiFieldNumber)
.find(EuiRange)
.prop('value')
).toEqual('12.12');
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
* 2.0.
*/

import { EuiFieldNumber, EuiFormRow } from '@elastic/eui';
import React, { useCallback, useState } from 'react';
import { EuiFormRow, EuiRange, EuiRangeProps } from '@elastic/eui';
import React, { useCallback } from 'react';
import { i18n } from '@kbn/i18n';
import { AggFunctionsMapping } from 'src/plugins/data/public';
import { buildExpressionFunction } from '../../../../../../../src/plugins/expressions/public';
Expand All @@ -21,7 +21,7 @@ import {
} from './helpers';
import { FieldBasedIndexPatternColumn } from './column_types';
import { adjustTimeScaleLabelSuffix } from '../time_scale_utils';
import { useDebounceWithOptions } from '../../../shared_components';
import { useDebouncedValue } from '../../../shared_components';

export interface PercentileIndexPatternColumn extends FieldBasedIndexPatternColumn {
operationType: 'percentile';
Expand Down Expand Up @@ -150,16 +150,14 @@ export const percentileOperation: OperationDefinition<
columnId,
indexPattern,
}) {
const [inputValue, setInputValue] = useState(String(currentColumn.params.percentile));

const inputValueAsNumber = Number(inputValue);
// an input is value if it's not an empty string, parses to a valid number, is between 0 and 100 (exclusive)
// and is an integer
const inputValueIsValid = isValidNumber(inputValue, true, 99, 1);

useDebounceWithOptions(
() => {
if (!inputValueIsValid) return;
const onChange = useCallback(
(value) => {
if (
!isValidNumber(value, true, 99, 1) ||
Number(value) === currentColumn.params.percentile
) {
return;
}
updateLayer({
...layer,
columns: {
Expand All @@ -171,33 +169,39 @@ export const percentileOperation: OperationDefinition<
: ofName(
indexPattern.getFieldByName(currentColumn.sourceField)?.displayName ||
currentColumn.sourceField,
inputValueAsNumber,
Number(value),
currentColumn.timeShift
),
params: {
...currentColumn.params,
percentile: inputValueAsNumber,
percentile: Number(value),
},
} as PercentileIndexPatternColumn,
},
});
},
{ skipFirstRender: true },
256,
[inputValue]
[updateLayer, layer, columnId, currentColumn, indexPattern]
);
const { inputValue, handleInputChange: handleInputChangeWithoutValidation } = useDebouncedValue<
string | undefined
>({
onChange,
value: String(currentColumn.params.percentile),
});
const inputValueIsValid = isValidNumber(inputValue, true, 99, 1);

const handleInputChange: EuiRangeProps['onChange'] = useCallback(
(e) => handleInputChangeWithoutValidation(String(e.currentTarget.value)),
[handleInputChangeWithoutValidation]
);

const handleInputChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
const val = String(e.target.value);
setInputValue(val);
}, []);
return (
<EuiFormRow
label={i18n.translate('xpack.lens.indexPattern.percentile.percentileValue', {
defaultMessage: 'Percentile',
})}
data-test-subj="lns-indexPattern-percentile-form"
display="columnCompressed"
display="rowCompressed"
fullWidth
isInvalid={!inputValueIsValid}
error={
Expand All @@ -207,14 +211,18 @@ export const percentileOperation: OperationDefinition<
})
}
>
<EuiFieldNumber
<EuiRange
data-test-subj="lns-indexPattern-percentile-input"
compressed
value={inputValue}
value={inputValue ?? ''}
min={1}
max={99}
step={1}
onChange={handleInputChange}
showInput
aria-label={i18n.translate('xpack.lens.indexPattern.percentile.percentileValue', {
defaultMessage: 'Percentile',
})}
/>
</EuiFormRow>
);
Expand Down
Loading

0 comments on commit 7176dd5

Please sign in to comment.