[Discover] Validate timerange before submitting query to ES (#69363)
This commit is contained in:
parent
be3886b77f
commit
c4b2e6f111
|
@ -64,6 +64,7 @@ const {
|
||||||
} = getServices();
|
} = getServices();
|
||||||
|
|
||||||
import { getRootBreadcrumbs, getSavedSearchBreadcrumbs } from '../helpers/breadcrumbs';
|
import { getRootBreadcrumbs, getSavedSearchBreadcrumbs } from '../helpers/breadcrumbs';
|
||||||
|
import { validateTimeRange } from '../helpers/validate_time_range';
|
||||||
import {
|
import {
|
||||||
esFilters,
|
esFilters,
|
||||||
indexPatterns as indexPatternsUtils,
|
indexPatterns as indexPatternsUtils,
|
||||||
|
@ -784,6 +785,10 @@ function discoverController(
|
||||||
if (!init.complete) return;
|
if (!init.complete) return;
|
||||||
$scope.fetchCounter++;
|
$scope.fetchCounter++;
|
||||||
$scope.fetchError = undefined;
|
$scope.fetchError = undefined;
|
||||||
|
if (!validateTimeRange(timefilter.getTime(), toastNotifications)) {
|
||||||
|
$scope.resultState = 'none';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Abort any in-progress requests before fetching again
|
// Abort any in-progress requests before fetching again
|
||||||
if (abortController) abortController.abort();
|
if (abortController) abortController.abort();
|
||||||
|
@ -916,14 +921,18 @@ function discoverController(
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.updateTime = function () {
|
$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 = {
|
$scope.timeRange = {
|
||||||
from: dateMath.parse(timefilter.getTime().from),
|
from: dateMath.parse(from),
|
||||||
to: dateMath.parse(timefilter.getTime().to, { roundUp: true }),
|
to: dateMath.parse(to, { roundUp: true }),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.toMoment = function (datetime) {
|
$scope.toMoment = function (datetime) {
|
||||||
|
if (!datetime) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
return moment(datetime).format(config.get('dateFormat'));
|
return moment(datetime).format(config.get('dateFormat'));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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')",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -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;
|
||||||
|
}
|
|
@ -257,5 +257,16 @@ export default function ({ getService, getPageObjects }) {
|
||||||
expect(refreshedTimeString).not.to.be(initialTimeString);
|
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');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -399,7 +399,7 @@ export function CommonPageProvider({ getService, getPageObjects }: FtrProviderCo
|
||||||
const toast = await find.byCssSelector('.euiToast', 2 * defaultFindTimeout);
|
const toast = await find.byCssSelector('.euiToast', 2 * defaultFindTimeout);
|
||||||
await toast.moveMouseTo();
|
await toast.moveMouseTo();
|
||||||
const title = await (await find.byCssSelector('.euiToastHeader__title')).getVisibleText();
|
const title = await (await find.byCssSelector('.euiToastHeader__title')).getVisibleText();
|
||||||
log.debug(`Toast title: ${title}`);
|
|
||||||
await find.clickByCssSelector('.euiToast__closeButton');
|
await find.clickByCssSelector('.euiToast__closeButton');
|
||||||
return title;
|
return title;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue