diff --git a/src/core_plugins/metrics/common/interval_regexp.js b/src/core_plugins/metrics/common/interval_regexp.js new file mode 100644 index 0000000000000..011c173b63b46 --- /dev/null +++ b/src/core_plugins/metrics/common/interval_regexp.js @@ -0,0 +1,4 @@ +import dateMath from '@elastic/datemath'; +export const GTE_INTERVAL_RE = new RegExp(`^>=([\\d\\.]*\\s*(${dateMath.units.join('|')}))$`); +export const INTERVAL_STRING_RE = new RegExp('^([0-9\\.]*)\\s*(' + dateMath.units.join('|') + ')$'); + diff --git a/src/core_plugins/metrics/public/components/index_pattern.js b/src/core_plugins/metrics/public/components/index_pattern.js index 5625de853e367..f036ce440b485 100644 --- a/src/core_plugins/metrics/public/components/index_pattern.js +++ b/src/core_plugins/metrics/public/components/index_pattern.js @@ -51,7 +51,7 @@ export const IndexPattern = props => { /> { const panel = vis.params; if (panel && panel.id) { diff --git a/src/core_plugins/metrics/public/lib/validate_interval.js b/src/core_plugins/metrics/public/lib/validate_interval.js index ea397b9f14eed..6a342a8bace19 100644 --- a/src/core_plugins/metrics/public/lib/validate_interval.js +++ b/src/core_plugins/metrics/public/lib/validate_interval.js @@ -1,16 +1,19 @@ import { parseInterval } from 'ui/utils/parse_interval'; +import { GTE_INTERVAL_RE } from '../../common/interval_regexp'; export function validateInterval(timefilter, panel, maxBuckets) { const { interval } = panel; const { min, max } = timefilter.getBounds(); // No need to check auto it will return around 100 + if (!interval) return; if (interval === 'auto') return; + const greaterThanMatch = interval.match(GTE_INTERVAL_RE); + if (greaterThanMatch) return; const duration = parseInterval(interval); - if (!duration) { - throw new Error(`Invalid interval: ${interval} is not a valid interval`); - } - const span = max.valueOf() - min.valueOf(); - const buckets = Math.floor(span / duration.asMilliseconds()); - if (buckets > maxBuckets) { - throw new Error(`Max buckets exceeded: ${buckets} is greater than ${maxBuckets}, try a larger time interval in the panel options.`); + if (duration) { + const span = max.valueOf() - min.valueOf(); + const buckets = Math.floor(span / duration.asMilliseconds()); + if (buckets > maxBuckets) { + throw new Error(`Max buckets exceeded: ${buckets} is greater than ${maxBuckets}, try a larger time interval in the panel options.`); + } } } diff --git a/src/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/get_bucket_size.js b/src/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/get_bucket_size.js index c22c744b1b213..60de2065bff7d 100644 --- a/src/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/get_bucket_size.js +++ b/src/core_plugins/metrics/server/lib/vis_data/__tests__/helpers/get_bucket_size.js @@ -35,4 +35,16 @@ describe('getBucketSize', () => { expect(result).to.have.property('intervalString', '1d'); }); + it('returns overriden buckets (>=2d)', () => { + const result = getBucketSize(req, '>=2d'); + expect(result).to.have.property('bucketSize', 86400 * 2); + expect(result).to.have.property('intervalString', '2d'); + }); + + it('returns overriden buckets (>=10s)', () => { + const result = getBucketSize(req, '>=10s'); + expect(result).to.have.property('bucketSize', 30); + expect(result).to.have.property('intervalString', '30s'); + }); + }); diff --git a/src/core_plugins/metrics/server/lib/vis_data/helpers/get_bucket_size.js b/src/core_plugins/metrics/server/lib/vis_data/helpers/get_bucket_size.js index d5d19f6a10278..dea0cd44aaacd 100644 --- a/src/core_plugins/metrics/server/lib/vis_data/helpers/get_bucket_size.js +++ b/src/core_plugins/metrics/server/lib/vis_data/helpers/get_bucket_size.js @@ -1,6 +1,10 @@ import calculateAuto from './calculate_auto'; import moment from 'moment'; import unitToSeconds from './unit_to_seconds'; +import { + INTERVAL_STRING_RE, + GTE_INTERVAL_RE +} from '../../../../common/interval_regexp'; export default (req, interval) => { const from = moment.utc(req.payload.timerange.min); const to = moment.utc(req.payload.timerange.max); @@ -9,7 +13,19 @@ export default (req, interval) => { if (bucketSize < 1) bucketSize = 1; // don't go too small let intervalString = `${bucketSize}s`; - const matches = interval && interval.match(/^([\d]+)([shmdwMy]|ms)$/); + const gteAutoMatch = interval && interval.match(GTE_INTERVAL_RE); + if (gteAutoMatch) { + const intervalStringMatch = gteAutoMatch[1].match(INTERVAL_STRING_RE); + const gteBucketSize = Number(intervalStringMatch[1]) * unitToSeconds(intervalStringMatch[2]); + if (gteBucketSize >= bucketSize) { + return { + bucketSize: gteBucketSize, + intervalString: gteAutoMatch[1] + }; + } + } + + const matches = interval && interval.match(INTERVAL_STRING_RE); if (matches) { bucketSize = Number(matches[1]) * unitToSeconds(matches[2]); intervalString = interval;