[Discover] Validate timerange before submitting query to ES (#69363)

This commit is contained in:
Matthias Wilhelm 2020-06-26 06:51:13 +02:00 committed by GitHub
parent be3886b77f
commit c4b2e6f111
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 120 additions and 4 deletions

View file

@ -64,6 +64,7 @@ const {
} = getServices();
import { getRootBreadcrumbs, getSavedSearchBreadcrumbs } from '../helpers/breadcrumbs';
import { validateTimeRange } from '../helpers/validate_time_range';
import {
esFilters,
indexPatterns as indexPatternsUtils,
@ -784,6 +785,10 @@ function discoverController(
if (!init.complete) return;
$scope.fetchCounter++;
$scope.fetchError = undefined;
if (!validateTimeRange(timefilter.getTime(), toastNotifications)) {
$scope.resultState = 'none';
return;
}
// Abort any in-progress requests before fetching again
if (abortController) abortController.abort();
@ -916,14 +921,18 @@ function discoverController(
}
$scope.updateTime = function () {
//this is the timerange for the histogram, should be refactored
const { from, to } = timefilter.getTime();
// this is the timerange for the histogram, should be refactored
$scope.timeRange = {
from: dateMath.parse(timefilter.getTime().from),
to: dateMath.parse(timefilter.getTime().to, { roundUp: true }),
from: dateMath.parse(from),
to: dateMath.parse(to, { roundUp: true }),
};
};
$scope.toMoment = function (datetime) {
if (!datetime) {
return;
}
return moment(datetime).format(config.get('dateFormat'));
};

View file

@ -0,0 +1,47 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { validateTimeRange } from './validate_time_range';
import { notificationServiceMock } from '../../../../../core/public/mocks';
describe('Discover validateTimeRange', () => {
test('validates given time ranges correctly', async () => {
const { toasts } = notificationServiceMock.createStartContract();
[
{ from: '', to: '', result: false },
{ from: 'now', to: 'now+1h', result: true },
{ from: 'now', to: 'lala+1h', result: false },
{ from: '', to: 'now', result: false },
{ from: 'now', to: '', result: false },
{ from: ' 2020-06-02T13:36:13.689Z', to: 'now', result: true },
{ from: ' 2020-06-02T13:36:13.689Z', to: '2020-06-02T13:36:13.690Z', result: true },
].map((test) => {
expect(validateTimeRange({ from: test.from, to: test.to }, toasts)).toEqual(test.result);
});
});
test('displays a toast when invalid data is entered', async () => {
const { toasts } = notificationServiceMock.createStartContract();
expect(validateTimeRange({ from: 'now', to: 'null' }, toasts)).toEqual(false);
expect(toasts.addDanger).toHaveBeenCalledWith({
title: 'Invalid time range',
text: "The provided time range is invalid. (from: 'now', to: 'null')",
});
});
});

View file

@ -0,0 +1,49 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import dateMath from '@elastic/datemath';
import { i18n } from '@kbn/i18n';
import { ToastsStart } from 'kibana/public';
/**
* Validates a given time filter range, provided by URL or UI
* Unless valid, it returns false and displays a notification
*/
export function validateTimeRange(
{ from, to }: { from: string; to: string },
toastNotifications: ToastsStart
): boolean {
const fromMoment = dateMath.parse(from);
const toMoment = dateMath.parse(to);
if (!fromMoment || !toMoment || !fromMoment.isValid() || !toMoment.isValid()) {
toastNotifications.addDanger({
title: i18n.translate('discover.notifications.invalidTimeRangeTitle', {
defaultMessage: `Invalid time range`,
}),
text: i18n.translate('discover.notifications.invalidTimeRangeText', {
defaultMessage: `The provided time range is invalid. (from: '{from}', to: '{to}')`,
values: {
from,
to,
},
}),
});
return false;
}
return true;
}

View file

@ -257,5 +257,16 @@ export default function ({ getService, getPageObjects }) {
expect(refreshedTimeString).not.to.be(initialTimeString);
});
});
describe('invalid time range in URL', function () {
it('should display a "Invalid time range toast"', async function () {
await PageObjects.common.navigateToUrl('discover', '#/?_g=(time:(from:now-15m,to:null))', {
useActualUrl: true,
});
await PageObjects.header.awaitKibanaChrome();
const toastMessage = await PageObjects.common.closeToast();
expect(toastMessage).to.be('Invalid time range');
});
});
});
}

View file

@ -399,7 +399,7 @@ export function CommonPageProvider({ getService, getPageObjects }: FtrProviderCo
const toast = await find.byCssSelector('.euiToast', 2 * defaultFindTimeout);
await toast.moveMouseTo();
const title = await (await find.byCssSelector('.euiToastHeader__title')).getVisibleText();
log.debug(`Toast title: ${title}`);
await find.clickByCssSelector('.euiToast__closeButton');
return title;
}