From 12f4eea96cb62a6611bbd3beff0d69cd4e3cb815 Mon Sep 17 00:00:00 2001 From: Marco Liberati Date: Tue, 6 Oct 2020 12:38:53 +0200 Subject: [PATCH] [7.x] [Lens] Fix open custom ranges saved issue (#78915) (#79319) Co-authored-by: Elastic Machine Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../definitions/ranges/advanced_editor.tsx | 4 +- .../definitions/ranges/ranges.test.tsx | 42 ++++++++++++++++++- .../operations/definitions/ranges/ranges.tsx | 19 ++++++--- 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.tsx index a6756df403ba7..16b861ae034fa 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/advanced_editor.tsx @@ -132,11 +132,11 @@ export const RangePopover = ({ { const newRange = { ...tempRange, - to: target.value !== '' ? Number(target.value) : -Infinity, + to: target.value !== '' ? Number(target.value) : Infinity, }; setTempRange(newRange); saveRangeAndReset(newRange); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx index 2409406afcdbc..fb6cf6df8573f 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.test.tsx @@ -485,7 +485,7 @@ describe('ranges', () => { /> ); - // This series of act clojures are made to make it work properly the update flush + // This series of act closures are made to make it work properly the update flush act(() => { instance.find(RangePopover).find(EuiLink).prop('onClick')!({} as ReactMouseEvent); }); @@ -550,6 +550,46 @@ describe('ranges', () => { expect(instance.find(RangePopover)).toHaveLength(1); }); }); + + it('should handle correctly open ranges when saved', () => { + const setStateSpy = jest.fn(); + + // Add an extra open range: + (state.layers.first.columns.col1 as RangeIndexPatternColumn).params.ranges.push({ + from: null, + to: null, + label: '', + }); + + const instance = mount( + + ); + + act(() => { + instance.find(RangePopover).last().find(EuiLink).prop('onClick')!({} as ReactMouseEvent); + }); + + act(() => { + // need another wrapping for this in order to work + instance.update(); + + // Check UI values for open ranges + expect( + instance.find(RangePopover).last().find(EuiFieldNumber).first().prop('value') + ).toBe(''); + + expect(instance.find(RangePopover).last().find(EuiFieldNumber).last().prop('value')).toBe( + '' + ); + }); + }); }); }); }); diff --git a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx index a59780ef59939..a8304456262eb 100644 --- a/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx +++ b/x-pack/plugins/lens/public/indexpattern_datasource/operations/definitions/ranges/ranges.tsx @@ -16,7 +16,13 @@ import { updateColumnParam, changeColumn } from '../../../state_helpers'; import { MODES, AUTO_BARS, DEFAULT_INTERVAL, MIN_HISTOGRAM_BARS, SLICES } from './constants'; type RangeType = Omit; -export type RangeTypeLens = RangeType & { label: string }; +// Try to cover all possible serialized states for ranges +export type RangeTypeLens = (RangeType | { from: Range['from'] | null; to: Range['to'] | null }) & { + label: string; +}; + +// This is a subset of RangeTypeLens which has both from and to defined +type FullRangeTypeLens = Extract>; export type MODES_TYPES = typeof MODES[keyof typeof MODES]; @@ -35,10 +41,13 @@ export type UpdateParamsFnType = ( value: RangeColumnParams[K] ) => void; -export const isValidNumber = (value: number | '') => - value !== '' && !isNaN(value) && isFinite(value); -export const isRangeWithin = (range: RangeTypeLens): boolean => range.from <= range.to; -const isFullRange = ({ from, to }: RangeType) => isValidNumber(from) && isValidNumber(to); +// on initialization values can be null (from the Infinity serialization), so handle it correctly +// or they will be casted to 0 by the editor ( see #78867 ) +export const isValidNumber = (value: number | '' | null): value is number => + value != null && value !== '' && !isNaN(value) && isFinite(value); +export const isRangeWithin = (range: RangeType): boolean => range.from <= range.to; +const isFullRange = (range: RangeTypeLens): range is FullRangeTypeLens => + isValidNumber(range.from) && isValidNumber(range.to); export const isValidRange = (range: RangeTypeLens): boolean => { if (isFullRange(range)) { return isRangeWithin(range);