mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
## Summary * Added ISO Handler called normalizeTimeRange * Added unit tests * Implemented and tested with Machine Learning Jobs to ensure it works as expected * Moved around Omit Utility to the common area * https://xkcd.com/1179/ ### Checklist Use ~~strikethroughs~~ to remove checklist items you don't feel are applicable to this PR. ~~- [ ] This was checked for cross-browser compatibility, [including a check against IE11](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility)~~ ~~- [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/master/packages/kbn-i18n/README.md)~~ ~~- [ ] [Documentation](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#writing-documentation) was added for features that require explanation or tutorials~~ - [x] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios ~~- [ ] This was checked for [keyboard-only and screenreader accessibility](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Cross_browser_testing/Accessibility#Accessibility_testing_checklist)~~ ### For maintainers ~~- [ ] This was checked for breaking API changes and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process)~~ ~~- [ ] This includes a feature addition or change that requires a release note and was [labeled appropriately](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#release-notes-process)~~
This commit is contained in:
parent
cf0b1200ab
commit
1b10a02cf9
10 changed files with 426 additions and 73 deletions
|
@ -7,3 +7,5 @@
|
|||
export type Pick3<T, K1 extends keyof T, K2 extends keyof T[K1], K3 extends keyof T[K1][K2]> = {
|
||||
[P1 in K1]: { [P2 in K2]: { [P3 in K3]: ((T[K1])[K2])[P3] } }
|
||||
};
|
||||
|
||||
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||
|
|
|
@ -9,6 +9,7 @@ import * as React from 'react';
|
|||
import { pure } from 'recompose';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { Omit } from '../../../common/utility_types';
|
||||
import { DragEffects, DraggableWrapper } from '../drag_and_drop/draggable_wrapper';
|
||||
import { escapeDataProviderId } from '../drag_and_drop/helpers';
|
||||
import { getEmptyStringTag } from '../empty_value';
|
||||
|
@ -120,8 +121,6 @@ const Badge = styled(EuiBadge)`
|
|||
vertical-align: top;
|
||||
`;
|
||||
|
||||
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
||||
|
||||
export type BadgeDraggableType = Omit<DefaultDraggableType, 'id'> & {
|
||||
contextId: string;
|
||||
eventId: string;
|
||||
|
|
|
@ -12,7 +12,7 @@ import * as React from 'react';
|
|||
import { AppTestingFrameworkAdapter } from '../../lib/adapters/framework/testing_framework_adapter';
|
||||
import { mockFrameworks, TestProviders } from '../../mock';
|
||||
|
||||
import { PreferenceFormattedDate, FormattedDate, getMaybeDate } from '.';
|
||||
import { PreferenceFormattedDate, FormattedDate } from '.';
|
||||
import { getEmptyValue } from '../empty_value';
|
||||
import { KibanaConfigContext } from '../../lib/adapters/framework/kibana_framework_adapter';
|
||||
|
||||
|
@ -155,56 +155,4 @@ describe('formatted_date', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getMaybeDate', () => {
|
||||
test('returns empty string as invalid date', () => {
|
||||
expect(getMaybeDate('').isValid()).toBe(false);
|
||||
});
|
||||
|
||||
test('returns string with empty spaces as invalid date', () => {
|
||||
expect(getMaybeDate(' ').isValid()).toBe(false);
|
||||
});
|
||||
|
||||
test('returns string date time as valid date', () => {
|
||||
expect(getMaybeDate('2019-05-28T23:05:28.405Z').isValid()).toBe(true);
|
||||
});
|
||||
|
||||
test('returns string date time as the date we expect', () => {
|
||||
expect(getMaybeDate('2019-05-28T23:05:28.405Z').toISOString()).toBe(
|
||||
'2019-05-28T23:05:28.405Z'
|
||||
);
|
||||
});
|
||||
|
||||
test('returns plain string number as epoch as valid date', () => {
|
||||
expect(getMaybeDate('1559084770612').isValid()).toBe(true);
|
||||
});
|
||||
|
||||
test('returns plain string number as the date we expect', () => {
|
||||
expect(
|
||||
getMaybeDate('1559084770612')
|
||||
.toDate()
|
||||
.toISOString()
|
||||
).toBe('2019-05-28T23:06:10.612Z');
|
||||
});
|
||||
|
||||
test('returns plain number as epoch as valid date', () => {
|
||||
expect(getMaybeDate(1559084770612).isValid()).toBe(true);
|
||||
});
|
||||
|
||||
test('returns plain number as epoch as the date we expect', () => {
|
||||
expect(
|
||||
getMaybeDate(1559084770612)
|
||||
.toDate()
|
||||
.toISOString()
|
||||
).toBe('2019-05-28T23:06:10.612Z');
|
||||
});
|
||||
|
||||
test('returns a short date time string as an epoch (sadly) so this is ambiguous', () => {
|
||||
expect(
|
||||
getMaybeDate('20190101')
|
||||
.toDate()
|
||||
.toISOString()
|
||||
).toBe('1970-01-01T05:36:30.101Z');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -9,13 +9,13 @@ import * as React from 'react';
|
|||
import { useContext } from 'react';
|
||||
import { pure } from 'recompose';
|
||||
|
||||
import { isString } from 'lodash/fp';
|
||||
import {
|
||||
AppKibanaFrameworkAdapter,
|
||||
KibanaConfigContext,
|
||||
} from '../../lib/adapters/framework/kibana_framework_adapter';
|
||||
import { getOrEmptyTagFromValue } from '../empty_value';
|
||||
import { LocalizedDateTooltip } from '../localized_date_tooltip';
|
||||
import { getMaybeDate } from './maybe_date';
|
||||
|
||||
export const PreferenceFormattedDate = pure<{ value: Date }>(({ value }) => {
|
||||
const config: Partial<AppKibanaFrameworkAdapter> = useContext(KibanaConfigContext);
|
||||
|
@ -30,19 +30,6 @@ export const PreferenceFormattedDate = pure<{ value: Date }>(({ value }) => {
|
|||
);
|
||||
});
|
||||
|
||||
export const getMaybeDate = (value: string | number): moment.Moment => {
|
||||
if (isString(value) && value.trim() !== '') {
|
||||
const maybeDate = moment(new Date(value));
|
||||
if (maybeDate.isValid() || isNaN(+value)) {
|
||||
return maybeDate;
|
||||
} else {
|
||||
return moment(new Date(+value));
|
||||
}
|
||||
} else {
|
||||
return moment(new Date(value));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Renders the specified date value in a format determined by the user's preferences,
|
||||
* with a tooltip that renders:
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { getMaybeDate } from './maybe_date';
|
||||
|
||||
describe('#getMaybeDate', () => {
|
||||
test('returns empty string as invalid date', () => {
|
||||
expect(getMaybeDate('').isValid()).toBe(false);
|
||||
});
|
||||
|
||||
test('returns string with empty spaces as invalid date', () => {
|
||||
expect(getMaybeDate(' ').isValid()).toBe(false);
|
||||
});
|
||||
|
||||
test('returns string date time as valid date', () => {
|
||||
expect(getMaybeDate('2019-05-28T23:05:28.405Z').isValid()).toBe(true);
|
||||
});
|
||||
|
||||
test('returns string date time as the date we expect', () => {
|
||||
expect(getMaybeDate('2019-05-28T23:05:28.405Z').toISOString()).toBe('2019-05-28T23:05:28.405Z');
|
||||
});
|
||||
|
||||
test('returns plain string number as epoch as valid date', () => {
|
||||
expect(getMaybeDate('1559084770612').isValid()).toBe(true);
|
||||
});
|
||||
|
||||
test('returns plain string number as the date we expect', () => {
|
||||
expect(
|
||||
getMaybeDate('1559084770612')
|
||||
.toDate()
|
||||
.toISOString()
|
||||
).toBe('2019-05-28T23:06:10.612Z');
|
||||
});
|
||||
|
||||
test('returns plain number as epoch as valid date', () => {
|
||||
expect(getMaybeDate(1559084770612).isValid()).toBe(true);
|
||||
});
|
||||
|
||||
test('returns plain number as epoch as the date we expect', () => {
|
||||
expect(
|
||||
getMaybeDate(1559084770612)
|
||||
.toDate()
|
||||
.toISOString()
|
||||
).toBe('2019-05-28T23:06:10.612Z');
|
||||
});
|
||||
|
||||
test('returns a short date time string as an epoch (sadly) so this is ambiguous', () => {
|
||||
expect(
|
||||
getMaybeDate('20190101')
|
||||
.toDate()
|
||||
.toISOString()
|
||||
).toBe('1970-01-01T05:36:30.101Z');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { isString } from 'lodash/fp';
|
||||
import moment from 'moment';
|
||||
|
||||
export const getMaybeDate = (value: string | number): moment.Moment => {
|
||||
if (isString(value) && value.trim() !== '') {
|
||||
const maybeDate = moment(new Date(value));
|
||||
if (maybeDate.isValid() || isNaN(+value)) {
|
||||
return maybeDate;
|
||||
} else {
|
||||
return moment(new Date(+value));
|
||||
}
|
||||
} else {
|
||||
return moment(new Date(value));
|
||||
}
|
||||
};
|
|
@ -48,6 +48,7 @@ import {
|
|||
} from './types';
|
||||
import { CONSTANTS } from './constants';
|
||||
import { InputsModelId, TimeRangeKinds } from '../../store/inputs/constants';
|
||||
import { normalizeTimeRange } from './normalize_time_range';
|
||||
|
||||
export class UrlStateContainerLifecycle extends React.Component<UrlStateContainerPropTypes> {
|
||||
public render() {
|
||||
|
@ -123,14 +124,18 @@ export class UrlStateContainerLifecycle extends React.Component<UrlStateContaine
|
|||
this.props.toggleTimelineLinkTo({ linkToId: 'global' });
|
||||
}
|
||||
if (globalType === 'absolute') {
|
||||
const absoluteRange: AbsoluteTimeRange = get('global.timerange', timerangeStateData);
|
||||
const absoluteRange = normalizeTimeRange<AbsoluteTimeRange>(
|
||||
get('global.timerange', timerangeStateData)
|
||||
);
|
||||
this.props.setAbsoluteTimerange({
|
||||
...absoluteRange,
|
||||
id: globalId,
|
||||
});
|
||||
}
|
||||
if (globalType === 'relative') {
|
||||
const relativeRange: RelativeTimeRange = get('global.timerange', timerangeStateData);
|
||||
const relativeRange = normalizeTimeRange<RelativeTimeRange>(
|
||||
get('global.timerange', timerangeStateData)
|
||||
);
|
||||
this.props.setRelativeTimerange({
|
||||
...relativeRange,
|
||||
id: globalId,
|
||||
|
@ -145,14 +150,18 @@ export class UrlStateContainerLifecycle extends React.Component<UrlStateContaine
|
|||
this.props.toggleTimelineLinkTo({ linkToId: 'timeline' });
|
||||
}
|
||||
if (timelineType === 'absolute') {
|
||||
const absoluteRange: AbsoluteTimeRange = get('timeline.timerange', timerangeStateData);
|
||||
const absoluteRange = normalizeTimeRange<AbsoluteTimeRange>(
|
||||
get('timeline.timerange', timerangeStateData)
|
||||
);
|
||||
this.props.setAbsoluteTimerange({
|
||||
...absoluteRange,
|
||||
id: timelineId,
|
||||
});
|
||||
}
|
||||
if (timelineType === 'relative') {
|
||||
const relativeRange: RelativeTimeRange = get('timeline.timerange', timerangeStateData);
|
||||
const relativeRange = normalizeTimeRange<RelativeTimeRange>(
|
||||
get('timeline.timerange', timerangeStateData)
|
||||
);
|
||||
this.props.setRelativeTimerange({
|
||||
...relativeRange,
|
||||
id: timelineId,
|
||||
|
|
|
@ -0,0 +1,296 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { normalizeTimeRange } from './normalize_time_range';
|
||||
import {
|
||||
URLTimeRange,
|
||||
AbsoluteTimeRange,
|
||||
isAbsoluteTimeRange,
|
||||
RelativeTimeRange,
|
||||
isRelativeTimeRange,
|
||||
} from '../../store/inputs/model';
|
||||
|
||||
describe('#normalizeTimeRange', () => {
|
||||
test('Absolute time range returns empty strings as 0', () => {
|
||||
const dateTimeRange: URLTimeRange = {
|
||||
kind: 'absolute',
|
||||
fromStr: undefined,
|
||||
toStr: undefined,
|
||||
from: '',
|
||||
to: '',
|
||||
};
|
||||
if (isAbsoluteTimeRange(dateTimeRange)) {
|
||||
const expected: AbsoluteTimeRange = {
|
||||
kind: 'absolute',
|
||||
from: 0,
|
||||
to: 0,
|
||||
fromStr: undefined,
|
||||
toStr: undefined,
|
||||
};
|
||||
expect(normalizeTimeRange<AbsoluteTimeRange>(dateTimeRange)).toEqual(expected);
|
||||
} else {
|
||||
throw new Error('Was expecting date time range to be a AbsoluteTimeRange');
|
||||
}
|
||||
});
|
||||
|
||||
test('Absolute time range returns string with empty spaces as 0', () => {
|
||||
const dateTimeRange: URLTimeRange = {
|
||||
kind: 'absolute',
|
||||
fromStr: undefined,
|
||||
toStr: undefined,
|
||||
from: ' ',
|
||||
to: ' ',
|
||||
};
|
||||
if (isAbsoluteTimeRange(dateTimeRange)) {
|
||||
const expected: AbsoluteTimeRange = {
|
||||
kind: 'absolute',
|
||||
from: 0,
|
||||
to: 0,
|
||||
fromStr: undefined,
|
||||
toStr: undefined,
|
||||
};
|
||||
expect(normalizeTimeRange<AbsoluteTimeRange>(dateTimeRange)).toEqual(expected);
|
||||
} else {
|
||||
throw new Error('Was expecting date time range to be a AbsoluteTimeRange');
|
||||
}
|
||||
});
|
||||
|
||||
test('Absolute time range returns string date time as valid date with from and to as ISO strings', () => {
|
||||
const to = new Date('2019-04-28T23:05:28.405Z');
|
||||
const from = new Date('2019-05-28T23:05:28.405Z');
|
||||
const dateTimeRange: URLTimeRange = {
|
||||
kind: 'absolute',
|
||||
fromStr: undefined,
|
||||
toStr: undefined,
|
||||
from: from.toISOString(),
|
||||
to: to.toISOString(),
|
||||
};
|
||||
if (isAbsoluteTimeRange(dateTimeRange)) {
|
||||
const expected: AbsoluteTimeRange = {
|
||||
kind: 'absolute',
|
||||
from: from.valueOf(),
|
||||
to: to.valueOf(),
|
||||
fromStr: undefined,
|
||||
toStr: undefined,
|
||||
};
|
||||
expect(normalizeTimeRange<AbsoluteTimeRange>(dateTimeRange)).toEqual(expected);
|
||||
} else {
|
||||
throw new Error('Was expecting date time range to be a AbsoluteTimeRange');
|
||||
}
|
||||
});
|
||||
|
||||
test('Absolute time range returns number as valid date with from and to as Epoch', () => {
|
||||
const to = new Date('2019-04-28T23:05:28.405Z');
|
||||
const from = new Date('2019-05-28T23:05:28.405Z');
|
||||
const dateTimeRange: URLTimeRange = {
|
||||
kind: 'absolute',
|
||||
fromStr: undefined,
|
||||
toStr: undefined,
|
||||
from: from.valueOf(),
|
||||
to: to.valueOf(),
|
||||
};
|
||||
if (isAbsoluteTimeRange(dateTimeRange)) {
|
||||
const expected: AbsoluteTimeRange = {
|
||||
kind: 'absolute',
|
||||
from: from.valueOf(),
|
||||
to: to.valueOf(),
|
||||
fromStr: undefined,
|
||||
toStr: undefined,
|
||||
};
|
||||
expect(normalizeTimeRange<AbsoluteTimeRange>(dateTimeRange)).toEqual(expected);
|
||||
} else {
|
||||
throw new Error('Was expecting date time range to be a AbsoluteTimeRange');
|
||||
}
|
||||
});
|
||||
|
||||
test('Absolute time range returns number as valid date with from and to as Epoch when the Epoch is a string', () => {
|
||||
const to = new Date('2019-04-28T23:05:28.405Z');
|
||||
const from = new Date('2019-05-28T23:05:28.405Z');
|
||||
const dateTimeRange: URLTimeRange = {
|
||||
kind: 'absolute',
|
||||
fromStr: undefined,
|
||||
toStr: undefined,
|
||||
from: `${from.valueOf()}`,
|
||||
to: `${to.valueOf()}`,
|
||||
};
|
||||
if (isAbsoluteTimeRange(dateTimeRange)) {
|
||||
const expected: AbsoluteTimeRange = {
|
||||
kind: 'absolute',
|
||||
from: from.valueOf(),
|
||||
to: to.valueOf(),
|
||||
fromStr: undefined,
|
||||
toStr: undefined,
|
||||
};
|
||||
expect(normalizeTimeRange<AbsoluteTimeRange>(dateTimeRange)).toEqual(expected);
|
||||
} else {
|
||||
throw new Error('Was expecting date time range to be a AbsoluteTimeRange');
|
||||
}
|
||||
});
|
||||
|
||||
test('Absolute time range returns NaN with from and to when garbage is sent in', () => {
|
||||
const to = 'garbage';
|
||||
const from = 'garbage';
|
||||
const dateTimeRange: URLTimeRange = {
|
||||
kind: 'absolute',
|
||||
fromStr: undefined,
|
||||
toStr: undefined,
|
||||
from,
|
||||
to,
|
||||
};
|
||||
if (isAbsoluteTimeRange(dateTimeRange)) {
|
||||
const expected: AbsoluteTimeRange = {
|
||||
kind: 'absolute',
|
||||
from: NaN,
|
||||
to: NaN,
|
||||
fromStr: undefined,
|
||||
toStr: undefined,
|
||||
};
|
||||
expect(normalizeTimeRange<AbsoluteTimeRange>(dateTimeRange)).toEqual(expected);
|
||||
} else {
|
||||
throw new Error('Was expecting date time range to be a AbsoluteTimeRange');
|
||||
}
|
||||
});
|
||||
|
||||
test('Relative time range returns empty strings as 0', () => {
|
||||
const dateTimeRange: URLTimeRange = {
|
||||
kind: 'relative',
|
||||
fromStr: '',
|
||||
toStr: '',
|
||||
from: '',
|
||||
to: '',
|
||||
};
|
||||
if (isRelativeTimeRange(dateTimeRange)) {
|
||||
const expected: RelativeTimeRange = {
|
||||
kind: 'relative',
|
||||
from: 0,
|
||||
to: 0,
|
||||
fromStr: '',
|
||||
toStr: '',
|
||||
};
|
||||
expect(normalizeTimeRange<RelativeTimeRange>(dateTimeRange)).toEqual(expected);
|
||||
} else {
|
||||
throw new Error('Was expecting date time range to be a RelativeTimeRange');
|
||||
}
|
||||
});
|
||||
|
||||
test('Relative time range returns string with empty spaces as 0', () => {
|
||||
const dateTimeRange: URLTimeRange = {
|
||||
kind: 'relative',
|
||||
fromStr: '',
|
||||
toStr: '',
|
||||
from: ' ',
|
||||
to: ' ',
|
||||
};
|
||||
if (isRelativeTimeRange(dateTimeRange)) {
|
||||
const expected: RelativeTimeRange = {
|
||||
kind: 'relative',
|
||||
from: 0,
|
||||
to: 0,
|
||||
fromStr: '',
|
||||
toStr: '',
|
||||
};
|
||||
expect(normalizeTimeRange<RelativeTimeRange>(dateTimeRange)).toEqual(expected);
|
||||
} else {
|
||||
throw new Error('Was expecting date time range to be a RelativeTimeRange');
|
||||
}
|
||||
});
|
||||
|
||||
test('Relative time range returns string date time as valid date with from and to as ISO strings', () => {
|
||||
const to = new Date('2019-04-28T23:05:28.405Z');
|
||||
const from = new Date('2019-05-28T23:05:28.405Z');
|
||||
const dateTimeRange: URLTimeRange = {
|
||||
kind: 'relative',
|
||||
fromStr: '',
|
||||
toStr: '',
|
||||
from: from.toISOString(),
|
||||
to: to.toISOString(),
|
||||
};
|
||||
if (isRelativeTimeRange(dateTimeRange)) {
|
||||
const expected: RelativeTimeRange = {
|
||||
kind: 'relative',
|
||||
from: from.valueOf(),
|
||||
to: to.valueOf(),
|
||||
fromStr: '',
|
||||
toStr: '',
|
||||
};
|
||||
expect(normalizeTimeRange<RelativeTimeRange>(dateTimeRange)).toEqual(expected);
|
||||
} else {
|
||||
throw new Error('Was expecting date time range to be a RelativeTimeRange');
|
||||
}
|
||||
});
|
||||
|
||||
test('Relative time range returns number as valid date with from and to as Epoch', () => {
|
||||
const to = new Date('2019-04-28T23:05:28.405Z');
|
||||
const from = new Date('2019-05-28T23:05:28.405Z');
|
||||
const dateTimeRange: URLTimeRange = {
|
||||
kind: 'relative',
|
||||
fromStr: '',
|
||||
toStr: '',
|
||||
from: from.valueOf(),
|
||||
to: to.valueOf(),
|
||||
};
|
||||
if (isRelativeTimeRange(dateTimeRange)) {
|
||||
const expected: RelativeTimeRange = {
|
||||
kind: 'relative',
|
||||
from: from.valueOf(),
|
||||
to: to.valueOf(),
|
||||
fromStr: '',
|
||||
toStr: '',
|
||||
};
|
||||
expect(normalizeTimeRange<RelativeTimeRange>(dateTimeRange)).toEqual(expected);
|
||||
} else {
|
||||
throw new Error('Was expecting date time range to be a RelativeTimeRange');
|
||||
}
|
||||
});
|
||||
|
||||
test('Relative time range returns number as valid date with from and to as Epoch when the Epoch is a string', () => {
|
||||
const to = new Date('2019-04-28T23:05:28.405Z');
|
||||
const from = new Date('2019-05-28T23:05:28.405Z');
|
||||
const dateTimeRange: URLTimeRange = {
|
||||
kind: 'relative',
|
||||
fromStr: '',
|
||||
toStr: '',
|
||||
from: `${from.valueOf()}`,
|
||||
to: `${to.valueOf()}`,
|
||||
};
|
||||
if (isRelativeTimeRange(dateTimeRange)) {
|
||||
const expected: RelativeTimeRange = {
|
||||
kind: 'relative',
|
||||
from: from.valueOf(),
|
||||
to: to.valueOf(),
|
||||
fromStr: '',
|
||||
toStr: '',
|
||||
};
|
||||
expect(normalizeTimeRange<RelativeTimeRange>(dateTimeRange)).toEqual(expected);
|
||||
} else {
|
||||
throw new Error('Was expecting date time range to be a RelativeTimeRange');
|
||||
}
|
||||
});
|
||||
|
||||
test('Relative time range returns NaN with from and to when garbage is sent in', () => {
|
||||
const to = 'garbage';
|
||||
const from = 'garbage';
|
||||
const dateTimeRange: URLTimeRange = {
|
||||
kind: 'relative',
|
||||
fromStr: '',
|
||||
toStr: '',
|
||||
from,
|
||||
to,
|
||||
};
|
||||
if (isRelativeTimeRange(dateTimeRange)) {
|
||||
const expected: RelativeTimeRange = {
|
||||
kind: 'relative',
|
||||
from: NaN,
|
||||
to: NaN,
|
||||
fromStr: '',
|
||||
toStr: '',
|
||||
};
|
||||
expect(normalizeTimeRange<RelativeTimeRange>(dateTimeRange)).toEqual(expected);
|
||||
} else {
|
||||
throw new Error('Was expecting date time range to be a RelativeTimeRange');
|
||||
}
|
||||
});
|
||||
});
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { URLTimeRange } from '../../store/inputs/model';
|
||||
import { getMaybeDate } from '../formatted_date/maybe_date';
|
||||
|
||||
export const normalizeTimeRange = <T extends URLTimeRange>(dateRange: T): T => {
|
||||
const maybeTo = getMaybeDate(dateRange.to);
|
||||
const maybeFrom = getMaybeDate(dateRange.from);
|
||||
const to: number = maybeTo.isValid() ? maybeTo.valueOf() : Number(dateRange.to);
|
||||
const from: number = maybeFrom.isValid() ? maybeFrom.valueOf() : Number(dateRange.from);
|
||||
return {
|
||||
...dateRange,
|
||||
to,
|
||||
from,
|
||||
};
|
||||
};
|
|
@ -4,6 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { Omit } from '../../../common/utility_types';
|
||||
import { InputsModelId } from './constants';
|
||||
import { CONSTANTS } from '../../components/url_state/constants';
|
||||
|
||||
|
@ -23,8 +24,21 @@ export interface RelativeTimeRange {
|
|||
to: number;
|
||||
}
|
||||
|
||||
export const isRelativeTimeRange = (
|
||||
timeRange: RelativeTimeRange | AbsoluteTimeRange | URLTimeRange
|
||||
): timeRange is RelativeTimeRange => timeRange.kind === 'relative';
|
||||
|
||||
export const isAbsoluteTimeRange = (
|
||||
timeRange: RelativeTimeRange | AbsoluteTimeRange | URLTimeRange
|
||||
): timeRange is AbsoluteTimeRange => timeRange.kind === 'absolute';
|
||||
|
||||
export type TimeRange = AbsoluteTimeRange | RelativeTimeRange;
|
||||
|
||||
export type URLTimeRange = Omit<TimeRange, 'from' | 'to'> & {
|
||||
from: string | TimeRange['from'];
|
||||
to: string | TimeRange['to'];
|
||||
};
|
||||
|
||||
export interface Policy {
|
||||
kind: 'manual' | 'interval';
|
||||
duration: number; // in ms
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue