Skip to content

Commit

Permalink
[TSVB] fix No longer possible to define intervals like >=1m or >=12h (e…
Browse files Browse the repository at this point in the history
…lastic#105954) (elastic#106245)

* [TSVB] fix No longer possible to define intervals like >=1m or >=12h

Closes: elastic#105854

* add tests, remove extra logic

* add functional test, update help text

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>

Co-authored-by: Alexey Antonov <alexwizp@gmail.com>
  • Loading branch information
kibanamachine and alexwizp authored Jul 20, 2021
1 parent f9d5209 commit 6b9d1dc
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ export const IndexPattern = ({
content={
<FormattedMessage
id="visTypeTimeseries.indexPattern.detailLevelHelpText"
defaultMessage="Controls the auto interval based on the time range. The default interval is affected by the advanced settings {histogramTargetBars} and {histogramMaxBars}."
defaultMessage="Controls the auto and gte intervals based on the time range. The default interval is affected by the advanced settings {histogramTargetBars} and {histogramMaxBars}."
values={{
histogramTargetBars: UI_SETTINGS.HISTOGRAM_MAX_BARS,
histogramMaxBars: UI_SETTINGS.HISTOGRAM_BAR_TARGET,
Expand Down Expand Up @@ -352,7 +352,7 @@ export const IndexPattern = ({
disabled={
disabled ||
isEntireTimeRangeActive(model, isTimeSeries) ||
!(model[intervalName] === AUTO_INTERVAL || !model[intervalName])
!(isAutoInterval(model[intervalName]) || isGteInterval(model[intervalName]))
}
min={0}
max={maxBarsUiSettings}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('getBucketSize', () => {
body: {
timerange: {
min: '2017-01-01T00:00:00.000Z',
max: '2017-01-01T01:00:00.000Z',
max: '2017-07-01T01:00:00.000Z',
},
},
} as VisTypeTimeseriesVisDataRequest;
Expand All @@ -29,9 +29,10 @@ describe('getBucketSize', () => {

test('returns auto calculated buckets', () => {
const result = getBucketSize(req, 'auto', capabilities, 100);
const expectedValue = 86400; // 24h

expect(result).toHaveProperty('bucketSize', 30);
expect(result).toHaveProperty('intervalString', '30s');
expect(result).toHaveProperty('bucketSize', expectedValue);
expect(result).toHaveProperty('intervalString', `${expectedValue}s`);
});

test('returns overridden buckets (1s)', () => {
Expand All @@ -56,16 +57,23 @@ describe('getBucketSize', () => {
});

test('returns overridden buckets (>=2d)', () => {
const result = getBucketSize(req, '>=2d', capabilities, 100);
const result = getBucketSize(req, '>=2d', capabilities, 1000);

expect(result).toHaveProperty('bucketSize', 86400 * 2);
expect(result).toHaveProperty('intervalString', '2d');
});

test('returns overridden buckets (>=10s)', () => {
const result = getBucketSize(req, '>=10s', capabilities, 100);
test('returns overridden buckets (>=5d)', () => {
const result = getBucketSize(req, '>=5d', capabilities, 100);

expect(result).toHaveProperty('bucketSize', 30);
expect(result).toHaveProperty('intervalString', '30s');
expect(result).toHaveProperty('bucketSize', 432000);
expect(result).toHaveProperty('intervalString', '5d');
});

test('returns overridden buckets for 1 bar and >=1d interval', () => {
const result = getBucketSize(req, '>=1d', capabilities, 1);

expect(result).toHaveProperty('bucketSize', 2592000);
expect(result).toHaveProperty('intervalString', '2592000s');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ import type { SearchCapabilities } from '../../search_strategies';
import type { VisTypeTimeseriesVisDataRequest } from '../../../types';

const calculateBucketData = (timeInterval: string, capabilities: SearchCapabilities) => {
let intervalString = capabilities
? capabilities.getValidTimeInterval(timeInterval)
: timeInterval;
let intervalString = capabilities?.getValidTimeInterval(timeInterval) ?? timeInterval;

const intervalStringMatch = intervalString.match(INTERVAL_STRING_RE);
const parsedInterval = parseInterval(intervalString);

Expand All @@ -34,10 +33,6 @@ const calculateBucketData = (timeInterval: string, capabilities: SearchCapabilit
bucketSize = 1;
}

if (bucketSize > capabilities.maxBucketsLimit) {
bucketSize = capabilities.maxBucketsLimit;
}

// Check decimal
if (parsedInterval && parsedInterval.value % 1 !== 0) {
if (parsedInterval.unit !== 'ms') {
Expand All @@ -60,10 +55,7 @@ const calculateBucketData = (timeInterval: string, capabilities: SearchCapabilit
};
};

const calculateBucketSizeForAutoInterval = (
req: VisTypeTimeseriesVisDataRequest,
maxBars: number
) => {
const calcAutoInterval = (req: VisTypeTimeseriesVisDataRequest, maxBars: number) => {
const { from, to } = getTimerange(req);
const timerange = to.valueOf() - from.valueOf();

Expand All @@ -76,24 +68,24 @@ export const getBucketSize = (
capabilities: SearchCapabilities,
bars: number
) => {
const defaultBucketSize = calculateBucketSizeForAutoInterval(req, bars);
let intervalString = `${defaultBucketSize}s`;
const userIntervalMatches = Boolean(interval) && interval.match(INTERVAL_STRING_RE);

if (userIntervalMatches) {
return calculateBucketData(interval, capabilities);
}

const gteAutoMatch = Boolean(interval) && interval.match(GTE_INTERVAL_RE);
const autoInterval = calcAutoInterval(req, bars);
const autoBucketData = calculateBucketData(`${autoInterval}s`, capabilities);

if (gteAutoMatch) {
const bucketData = calculateBucketData(gteAutoMatch[1], capabilities);
const gteBucketData = calculateBucketData(gteAutoMatch[1], capabilities);
const gteInSecondInterval = convertIntervalToUnit(gteBucketData.intervalString, 's');

if (bucketData.bucketSize >= defaultBucketSize) {
return bucketData;
if (gteInSecondInterval && gteInSecondInterval?.value > autoInterval) {
return gteBucketData;
}
}

const matches = interval && interval.match(INTERVAL_STRING_RE);

if (matches) {
intervalString = interval;
}

return calculateBucketData(intervalString, capabilities);
return autoBucketData;
};
33 changes: 33 additions & 0 deletions test/functional/apps/visualize/_tsvb_chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,39 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
});
});

describe('switch panel interval test', () => {
beforeEach(async () => {
await PageObjects.visualBuilder.resetPage();
await PageObjects.visualBuilder.clickMetric();
await PageObjects.visualBuilder.checkMetricTabIsPresent();
await PageObjects.visualBuilder.clickPanelOptions('metric');
await PageObjects.visualBuilder.setMetricsDataTimerangeMode('Last value');
await PageObjects.visualBuilder.setDropLastBucket(true);
await PageObjects.timePicker.setAbsoluteRange(
'Sep 19, 2015 @ 06:31:44.000',
'Sep 22, 2015 @ 18:31:44.000'
);
});

it('should be able to switch to gte interval (>=2d)', async () => {
await PageObjects.visualBuilder.setIntervalValue('>=2d');
const newValue = await PageObjects.visualBuilder.getMetricValue();
expect(newValue).to.eql('9,371');
});

it('should be able to switch to fixed interval (1d)', async () => {
await PageObjects.visualBuilder.setIntervalValue('1d');
const newValue = await PageObjects.visualBuilder.getMetricValue();
expect(newValue).to.eql('4,614');
});

it('should be able to switch to auto interval', async () => {
await PageObjects.visualBuilder.setIntervalValue('auto');
const newValue = await PageObjects.visualBuilder.getMetricValue();
expect(newValue).to.eql('156');
});
});

describe('browser history changes', () => {
it('should activate previous/next chart tab and panel config', async () => {
await PageObjects.visualBuilder.resetPage();
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -4427,7 +4427,6 @@
"visTypeTimeseries.iconSelect.tagLabel": "タグ",
"visTypeTimeseries.indexPattern.detailLevel": "詳細レベル",
"visTypeTimeseries.indexPattern.detailLevelAriaLabel": "詳細レベル",
"visTypeTimeseries.indexPattern.detailLevelHelpText": "時間範囲に基づき自動間隔を制御します。デフォルトの間隔は詳細設定の{histogramTargetBars}と{histogramMaxBars}の影響を受けます。",
"visTypeTimeseries.indexPattern.dropLastBucketLabel": "最後のバケットをドロップしますか?",
"visTypeTimeseries.indexPattern.finest": "最も細かい",
"visTypeTimeseries.indexPattern.intervalHelpText": "例:auto、1m、1d、7d、1y、>=1m",
Expand Down
1 change: 0 additions & 1 deletion x-pack/plugins/translations/translations/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -4453,7 +4453,6 @@
"visTypeTimeseries.iconSelect.tagLabel": "标签",
"visTypeTimeseries.indexPattern.detailLevel": "详细程度",
"visTypeTimeseries.indexPattern.detailLevelAriaLabel": "详细程度",
"visTypeTimeseries.indexPattern.detailLevelHelpText": "根据时间范围控制自动时间间隔。默认时间间隔受高级设置 {histogramTargetBars} 和 {histogramMaxBars} 影响。",
"visTypeTimeseries.indexPattern.dropLastBucketLabel": "丢弃上一存储桶?",
"visTypeTimeseries.indexPattern.finest": "最精细",
"visTypeTimeseries.indexPattern.intervalHelpText": "示例:auto、1m、1d、7d、1y、>=1m",
Expand Down

0 comments on commit 6b9d1dc

Please sign in to comment.