Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,6 @@ import moment from 'moment-timezone';
import * as helpers from './helpers';

describe('url_params_context helpers', () => {
describe('getParsedDate', () => {
describe('given undefined', () => {
it('returns undefined', () => {
expect(helpers.getParsedDate(undefined)).toBeUndefined();
});
});

describe('given a parsable date', () => {
it('returns the parsed date', () => {
expect(helpers.getParsedDate('1970-01-01T00:00:00.000Z')).toEqual(
'1970-01-01T00:00:00.000Z'
);
});
});

describe('given a non-parsable date', () => {
it('returns null', () => {
expect(helpers.getParsedDate('nope')).toEqual(null);
});
});
});

describe('getDateRange', () => {
describe('when rangeFrom and rangeTo are not changed', () => {
it('returns the previous state', () => {
Expand All @@ -52,6 +30,43 @@ describe('url_params_context helpers', () => {
});
});

describe('when rangeFrom or rangeTo are falsy', () => {
it('returns the previous state', () => {
jest.spyOn(console, 'warn').mockImplementationOnce(() => {});
expect(
helpers.getDateRange({
state: {
start: '1972-01-01T00:00:00.000Z',
end: '1973-01-01T00:00:00.000Z',
},
rangeFrom: '',
rangeTo: 'now',
})
).toEqual({
start: '1972-01-01T00:00:00.000Z',
end: '1973-01-01T00:00:00.000Z',
});
});
});

describe('when the start or end are invalid', () => {
it('returns the previous state', () => {
expect(
helpers.getDateRange({
state: {
start: '1972-01-01T00:00:00.000Z',
end: '1973-01-01T00:00:00.000Z',
},
rangeFrom: 'nope',
rangeTo: 'now',
})
).toEqual({
start: '1972-01-01T00:00:00.000Z',
end: '1973-01-01T00:00:00.000Z',
});
});
});

describe('when rangeFrom or rangeTo have changed', () => {
it('returns new state', () => {
jest.spyOn(datemath, 'parse').mockReturnValue(moment(0).utc());
Expand Down
29 changes: 22 additions & 7 deletions x-pack/plugins/apm/public/context/url_params_context/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { compact, pickBy } from 'lodash';
import datemath from '@elastic/datemath';
import { scaleTime } from 'd3-scale';
import { compact, pickBy } from 'lodash';
import { IUrlParams } from './types';

export function getParsedDate(rawDate?: string, opts = {}) {
function getParsedDate(rawDate?: string, options = {}) {
if (rawDate) {
const parsed = datemath.parse(rawDate, opts);
if (parsed) {
return parsed.toISOString();
const parsed = datemath.parse(rawDate, options);
if (parsed && parsed.isValid()) {
return parsed.toDate();
}
}
}
Expand All @@ -26,13 +27,27 @@ export function getDateRange({
rangeFrom?: string;
rangeTo?: string;
}) {
// If the previous state had the same range, just return that instead of calculating a new range.
if (state.rangeFrom === rangeFrom && state.rangeTo === rangeTo) {
return { start: state.start, end: state.end };
}

const start = getParsedDate(rangeFrom);
const end = getParsedDate(rangeTo, { roundUp: true });

// `getParsedDate` will return undefined for invalid or empty dates. We return
// the previous state if either date is undefined.
if (!start || !end) {
return { start: state.start, end: state.end };
}

// Calculate ticks for the time ranges to produce nicely rounded values
const ticks = scaleTime().domain([start, end]).ticks();

// Return the first and last tick values.
return {
start: getParsedDate(rangeFrom),
end: getParsedDate(rangeTo, { roundUp: true }),
start: ticks[0].toISOString(),
end: ticks[ticks.length - 1].toISOString(),
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@
* you may not use this file except in compliance with the Elastic License.
*/

import * as React from 'react';
import { UrlParamsContext, UrlParamsProvider } from './url_params_context';
import { waitFor } from '@testing-library/react';
import { mount } from 'enzyme';
import { Location, History } from 'history';
import { MemoryRouter, Router } from 'react-router-dom';
import { History, Location } from 'history';
import moment from 'moment-timezone';
import * as React from 'react';
import { MemoryRouter, Router } from 'react-router-dom';
import { IUrlParams } from './types';
import { getParsedDate } from './helpers';
import { waitFor } from '@testing-library/react';
import { UrlParamsContext, UrlParamsProvider } from './url_params_context';

function mountParams(location: Location) {
return mount(
Expand Down Expand Up @@ -50,8 +49,8 @@ describe('UrlParamsContext', () => {

const wrapper = mountParams(location);
const params = getDataFromOutput(wrapper);
expect(params.start).toEqual('2010-03-15T12:00:00.000Z');
expect(params.end).toEqual('2010-04-10T12:00:00.000Z');
expect(params.start).toEqual('2010-03-17T05:00:00.000Z');
expect(params.end).toEqual('2010-04-09T05:00:00.000Z');
});

it('should update param values if location has changed', () => {
Expand All @@ -66,8 +65,8 @@ describe('UrlParamsContext', () => {
// force an update
wrapper.setProps({ abc: 123 });
const params = getDataFromOutput(wrapper);
expect(params.start).toEqual('2009-03-15T12:00:00.000Z');
expect(params.end).toEqual('2009-04-10T12:00:00.000Z');
expect(params.start).toEqual('2009-03-17T05:00:00.000Z');
expect(params.end).toEqual('2009-04-09T05:00:00.000Z');
});

it('should parse relative time ranges on mount', () => {
Expand All @@ -81,8 +80,8 @@ describe('UrlParamsContext', () => {
// force an update
wrapper.setProps({ abc: 123 });
const params = getDataFromOutput(wrapper);
expect(params.start).toEqual(getParsedDate('now-1d/d'));
expect(params.end).toEqual(getParsedDate('now-1d/d', { roundUp: true }));
expect(new Date(params.start).getTime()).not.toBeNaN();
expect(new Date(params.end).getTime()).not.toBeNaN();
});

it('should refresh the time range with new values', async () => {
Expand Down Expand Up @@ -130,8 +129,8 @@ describe('UrlParamsContext', () => {
expect(calls.length).toBe(2);

const params = getDataFromOutput(wrapper);
expect(params.start).toEqual('2005-09-20T12:00:00.000Z');
expect(params.end).toEqual('2005-10-21T12:00:00.000Z');
expect(params.start).toEqual('2005-09-21T05:00:00.000Z');
expect(params.end).toEqual('2005-10-21T05:00:00.000Z');
});

it('should refresh the time range with new values if time range is relative', async () => {
Expand Down Expand Up @@ -177,7 +176,7 @@ describe('UrlParamsContext', () => {
await waitFor(() => {});

const params = getDataFromOutput(wrapper);
expect(params.start).toEqual('2000-06-14T00:00:00.000Z');
expect(params.end).toEqual('2000-06-14T23:59:59.999Z');
expect(params.start).toEqual('2000-06-14T02:00:00.000Z');
expect(params.end).toEqual('2000-06-14T23:00:00.000Z');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@ import React, {
import { withRouter } from 'react-router-dom';
import { uniqueId, mapValues } from 'lodash';
import { IUrlParams } from './types';
import { getParsedDate } from './helpers';
import { getDateRange } from './helpers';
import { resolveUrlParams } from './resolve_url_params';
import { UIFilters } from '../../../typings/ui_filters';
import {
localUIFilterNames,

// eslint-disable-next-line @kbn/eslint/no-restricted-paths
} from '../../../server/lib/ui_filters/local_ui_filters/config';
import { pickKeys } from '../../../common/utils/pick_keys';
Expand Down Expand Up @@ -79,8 +78,7 @@ const UrlParamsProvider: React.ComponentClass<{}> = withRouter(
(timeRange: TimeRange) => {
refUrlParams.current = {
...refUrlParams.current,
start: getParsedDate(timeRange.rangeFrom),
end: getParsedDate(timeRange.rangeTo, { roundUp: true }),
...getDateRange({ state: {}, ...timeRange }),
};

forceUpdate(uniqueId());
Expand Down