From 5f8062d37fa0071eee1e30883f0dc0032a404b66 Mon Sep 17 00:00:00 2001 From: Marco Liberati Date: Tue, 14 Dec 2021 10:41:31 +0100 Subject: [PATCH] [Lens] Revisit flyout fields style from column to row compressed (#120103) * :lipstick: Revisit form style + spacers * :white_check_mark: Fix tests * :sparkles: Replace percentile input with range * :lipstick: Fix mobile layout * :lipstick: Make searchbar go below flyout * :fire: 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 --- .../config_panel/dimension_container.scss | 12 ++-- .../editor_frame/config_panel/layer_panel.tsx | 7 +-- .../dimension_panel/advanced_options.tsx | 16 ++--- .../dimension_panel/dimension_editor.tsx | 4 +- .../dimension_panel/filtering.tsx | 2 +- .../dimension_panel/time_scaling.tsx | 2 +- .../dimension_panel/time_shift.tsx | 2 +- .../calculations/moving_average.tsx | 2 +- .../operations/definitions/last_value.tsx | 2 +- .../definitions/percentile.test.tsx | 54 +++++++++-------- .../operations/definitions/percentile.tsx | 58 +++++++++++-------- .../operations/definitions/terms/index.tsx | 56 ++++++++++++++++-- .../definitions/terms/terms.test.tsx | 29 +++++----- .../definitions/terms/values_input.tsx | 2 +- .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - 16 files changed, 149 insertions(+), 103 deletions(-) diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/dimension_container.scss b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/dimension_container.scss index 692db8171d1248..48bb8bc1d70d57 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/dimension_container.scss +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/dimension_container.scss @@ -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 & { diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx index 13f9df17390055..50a867790635f8 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/config_panel/layer_panel.tsx @@ -317,12 +317,7 @@ export function LayerPanel( return ( <> -
+
diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/advanced_options.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/advanced_options.tsx index 252772903809f5..ffd75163e7871f 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/advanced_options.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/advanced_options.tsx @@ -26,7 +26,6 @@ export function AdvancedOptions(props: { <> {popoverOptions.length > 0 && ( - )} - {inlineOptions.length > 0 && ( - <> + {inlineOptions.map((option) => ( + - {inlineOptions.map((option, index) => ( - - {option.inlineElement} - {index !== inlineOptions.length - 1 && } - - ))} - - )} + {option.inlineElement} + + ))} ); } diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx index 1003845a520dec..6a06130d1cced2 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/dimension_editor.tsx @@ -414,7 +414,7 @@ export function DimensionEditor(props: DimensionEditorProps) {
{i18n.translate('xpack.lens.indexPattern.functionsLabel', { - defaultMessage: 'Select a function', + defaultMessage: 'Functions', })} @@ -474,7 +474,7 @@ export function DimensionEditor(props: DimensionEditorProps) { /> ); })} - + {selectedOperationDefinition.selectionStyle !== 'field' ? : null} ) : null} diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/filtering.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/filtering.tsx index d88edff3f0cc39..b8440feae1a490 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/filtering.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/dimension_panel/filtering.tsx @@ -94,7 +94,7 @@ export function Filtering({ return ( diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.tsx index ec949f9f9bc947..46e1b368fc9134 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/last_value.tsx @@ -223,7 +223,7 @@ export const lastValueOperation: OperationDefinition { + const original = jest.requireActual('lodash'); + + return { + ...original, + debounce: (fn: unknown) => fn, + }; +}); + const uiSettingsMock = {} as IUiSettingsClient; const defaultProps = { @@ -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( { /> ); - 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, + true + ); }); instance.update(); - jest.runAllTimers(); - expect(updateLayerSpy).toHaveBeenCalledWith({ ...layer, columns: { @@ -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( { /> ); - 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, + true + ); }); instance.update(); - jest.runAllTimers(); - expect(updateLayerSpy).not.toHaveBeenCalled(); expect( @@ -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'); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.tsx index 3aaeb9d9447288..d1ce42696ea680 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/percentile.tsx @@ -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'; @@ -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'; @@ -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: { @@ -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) => { - const val = String(e.target.value); - setInputValue(val); - }, []); return ( - ); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx index f84664ccc32d83..f58893e6988fce 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/index.tsx @@ -15,6 +15,8 @@ import { EuiSpacer, EuiAccordion, EuiIconTip, + htmlIdGenerator, + EuiButtonGroup, } from '@elastic/eui'; import { AggFunctionsMapping } from '../../../../../../../../src/plugins/data/public'; import { buildExpressionFunction } from '../../../../../../../../src/plugins/expressions/public'; @@ -60,6 +62,7 @@ function ofName(name?: string, count: number = 0) { }); } +const idPrefix = htmlIdGenerator()(); const DEFAULT_SIZE = 3; const supportedTypes = new Set(['string', 'boolean', 'number', 'ip']); @@ -383,7 +386,7 @@ export const termsOperation: OperationDefinition } - display="columnCompressed" + display="rowCompressed" fullWidth > - { + const value = id.replace( + idPrefix, + '' + ) as TermsIndexPatternColumn['params']['orderDirection']; + updateLayer( + updateColumnParam({ + layer, + columnId, + paramName: 'orderDirection', + value, + }) + ); + }} + /> + {/* + /> */} {!hasRestrictions && ( <> diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx index a9c1836aa5b222..d8d20f93900e47 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/terms.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; import { shallow, mount } from 'enzyme'; -import { EuiFieldNumber, EuiSelect, EuiSwitch } from '@elastic/eui'; +import { EuiButtonGroup, EuiFieldNumber, EuiSelect, EuiSwitch } from '@elastic/eui'; import type { IUiSettingsClient, SavedObjectsClientContract, @@ -39,6 +39,16 @@ jest.mock('@elastic/eui', () => { }; }); +// mocking random id generator function +jest.mock('@elastic/eui', () => { + const original = jest.requireActual('@elastic/eui'); + + return { + ...original, + htmlIdGenerator: () => () => '', + }; +}); + const uiSettingsMock = {} as IUiSettingsClient; const defaultProps = { @@ -1517,12 +1527,10 @@ describe('terms', () => { /> ); - const select = instance - .find('[data-test-subj="indexPattern-terms-orderDirection"]') - .find(EuiSelect); + const selection = instance.find(EuiButtonGroup); - expect(select.prop('value')).toEqual('asc'); - expect(select.prop('options')!.map(({ value }) => value)).toEqual(['asc', 'desc']); + expect(selection.prop('idSelected')).toEqual('asc'); + expect(selection.prop('options').map(({ value }) => value)).toEqual(['asc', 'desc']); }); it('should update state with the order direction value', () => { @@ -1537,14 +1545,7 @@ describe('terms', () => { /> ); - instance - .find('[data-test-subj="indexPattern-terms-orderDirection"]') - .find(EuiSelect) - .simulate('change', { - target: { - value: 'desc', - }, - }); + instance.find(EuiButtonGroup).simulate('change', 'desc'); expect(updateLayerSpy).toHaveBeenCalledWith({ ...layer, diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/values_input.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/values_input.tsx index 96b92686f76221..a107893517ea3c 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/values_input.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/terms/values_input.tsx @@ -44,7 +44,7 @@ export const ValuesInput = ({ label={i18n.translate('xpack.lens.indexPattern.terms.size', { defaultMessage: 'Number of values', })} - display="columnCompressed" + display="rowCompressed" fullWidth isInvalid={isHigherThanMax || isLowerThanMin} error={ diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index b821888f0e3978..b4db03951b02e2 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -14148,7 +14148,6 @@ "xpack.lens.indexPattern.cardinality": "ユニークカウント", "xpack.lens.indexPattern.cardinality.signature": "フィールド:文字列", "xpack.lens.indexPattern.cardinalityOf": "{name} のユニークカウント", - "xpack.lens.indexPattern.chooseField": "フィールドを選択", "xpack.lens.indexPattern.chooseFieldLabel": "この関数を使用するには、フィールドを選択してください。", "xpack.lens.indexPattern.chooseSubFunction": "サブ関数を選択", "xpack.lens.indexPattern.columnFormatLabel": "値の形式", @@ -14247,7 +14246,6 @@ "xpack.lens.indexPattern.formulaWarningStaticValueText": "式を上書きするには、入力フィールドの値を変更します", "xpack.lens.indexPattern.formulaWarningText": "式を上書きするには、クイック関数を選択します", "xpack.lens.indexPattern.formulaWithTooManyArguments": "演算{operation}の引数が多すぎます", - "xpack.lens.indexPattern.functionsLabel": "関数を選択", "xpack.lens.indexPattern.groupByDropdown": "グループ分けの条件", "xpack.lens.indexPattern.incompleteOperation": "(未完了)", "xpack.lens.indexPattern.intervals": "間隔", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index d3b1cc495da474..0c5c5ff26cd73d 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -14337,7 +14337,6 @@ "xpack.lens.indexPattern.cardinality": "唯一计数", "xpack.lens.indexPattern.cardinality.signature": "field: string", "xpack.lens.indexPattern.cardinalityOf": "{name} 的唯一计数", - "xpack.lens.indexPattern.chooseField": "选择字段", "xpack.lens.indexPattern.chooseFieldLabel": "要使用此函数,请选择字段。", "xpack.lens.indexPattern.chooseSubFunction": "选择子函数", "xpack.lens.indexPattern.columnFormatLabel": "值格式", @@ -14437,7 +14436,6 @@ "xpack.lens.indexPattern.formulaWarningStaticValueText": "要覆盖公式,请更改输入字段中的值", "xpack.lens.indexPattern.formulaWarningText": "要覆盖公式,请选择快速函数", "xpack.lens.indexPattern.formulaWithTooManyArguments": "运算 {operation} 的参数过多", - "xpack.lens.indexPattern.functionsLabel": "选择函数", "xpack.lens.indexPattern.groupByDropdown": "分组依据", "xpack.lens.indexPattern.incompleteOperation": "(不完整)", "xpack.lens.indexPattern.intervals": "时间间隔",