[TSVB] Timeseries Drop last bucket set default to false (#97257)
* [TSVB] Timeseries Drop last bucket should default to false * Rename isLastBucketDropped prop and move series domain calculation to a separate file * Fix failing tests because of wrong default value * update drop_last_bucket.js * Refactor drop_last_bucket and some functional tests * Change infra metrics test values because of last bucket value changed * Refactor series_domain_calculation and related code * Update series_domain_calculations.test * Update series_domain_calculations.test * Fix tooltip showing wrong time * Refactor index Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Alexey Antonov <alexwizp@gmail.com>
This commit is contained in:
parent
e297fec23e
commit
6b6ad111c0
|
@ -113,7 +113,7 @@ export const IndexPattern = ({
|
|||
const defaults = {
|
||||
[indexPatternName]: '',
|
||||
[intervalName]: AUTO_INTERVAL,
|
||||
[dropBucketName]: 1,
|
||||
[dropBucketName]: 0,
|
||||
[maxBarsName]: config.get(UI_SETTINGS.HISTOGRAM_BAR_TARGET),
|
||||
[TIME_RANGE_MODE_KEY]: timeRangeOptions[0].value,
|
||||
};
|
||||
|
|
|
@ -406,6 +406,7 @@ export class TimeseriesPanelConfig extends Component<
|
|||
<EuiTab
|
||||
isSelected={selectedTab === PANEL_CONFIG_TABS.DATA}
|
||||
onClick={() => this.switchTab(PANEL_CONFIG_TABS.DATA)}
|
||||
data-test-subj="timeSeriesEditorDataBtn"
|
||||
>
|
||||
<FormattedMessage
|
||||
id="visTypeTimeseries.timeseries.dataTab.dataButtonLabel"
|
||||
|
|
|
@ -17,7 +17,6 @@ import { createTickFormatter } from '../../lib/tick_formatter';
|
|||
import { TimeSeries } from '../../../visualizations/views/timeseries';
|
||||
import { MarkdownSimple } from '../../../../../../../plugins/kibana_react/public';
|
||||
import { replaceVars } from '../../lib/replace_vars';
|
||||
import { getAxisLabelString } from '../../lib/get_axis_label_string';
|
||||
import { getInterval } from '../../lib/get_interval';
|
||||
import { createIntervalBasedFormatter } from '../../lib/create_interval_based_formatter';
|
||||
import { STACKED_OPTIONS } from '../../../visualizations/constants';
|
||||
|
@ -235,11 +234,15 @@ class TimeseriesVisualization extends Component {
|
|||
legend={Boolean(model.show_legend)}
|
||||
legendPosition={model.legend_position}
|
||||
tooltipMode={model.tooltip_mode}
|
||||
xAxisLabel={getAxisLabelString(interval)}
|
||||
xAxisFormatter={this.xAxisFormatter(interval)}
|
||||
annotations={this.prepareAnnotations()}
|
||||
syncColors={syncColors}
|
||||
palettesService={palettesService}
|
||||
interval={interval}
|
||||
isLastBucketDropped={Boolean(
|
||||
model.drop_last_bucket ||
|
||||
model.series.some((series) => series.series_drop_last_bucket)
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -32,6 +32,9 @@ import { getStackAccessors } from './utils/stack_format';
|
|||
import { getBaseTheme, getChartClasses } from './utils/theme';
|
||||
import { emptyLabel } from '../../../../../common/empty_label';
|
||||
import { getSplitByTermsColor } from '../../../lib/get_split_by_terms_color';
|
||||
import { renderEndzoneTooltip } from '../../../../../../charts/public';
|
||||
import { getAxisLabelString } from '../../../components/lib/get_axis_label_string';
|
||||
import { calculateDomainForSeries } from './utils/series_domain_calculation';
|
||||
|
||||
const generateAnnotationData = (values, formatter) =>
|
||||
values.map(({ key, docs }) => ({
|
||||
|
@ -54,7 +57,6 @@ export const TimeSeries = ({
|
|||
legend,
|
||||
legendPosition,
|
||||
tooltipMode,
|
||||
xAxisLabel,
|
||||
series,
|
||||
yAxis,
|
||||
onBrush,
|
||||
|
@ -62,6 +64,8 @@ export const TimeSeries = ({
|
|||
annotations,
|
||||
syncColors,
|
||||
palettesService,
|
||||
interval,
|
||||
isLastBucketDropped,
|
||||
}) => {
|
||||
const chartRef = useRef();
|
||||
// const [palettesRegistry, setPalettesRegistry] = useState(null);
|
||||
|
@ -80,7 +84,17 @@ export const TimeSeries = ({
|
|||
};
|
||||
}, []);
|
||||
|
||||
const tooltipFormatter = decorateFormatter(xAxisFormatter);
|
||||
let tooltipFormatter = decorateFormatter(xAxisFormatter);
|
||||
if (!isLastBucketDropped) {
|
||||
const domainBounds = calculateDomainForSeries(series);
|
||||
tooltipFormatter = renderEndzoneTooltip(
|
||||
interval,
|
||||
domainBounds?.domainStart,
|
||||
domainBounds?.domainEnd,
|
||||
xAxisFormatter
|
||||
);
|
||||
}
|
||||
|
||||
const uiSettings = getUISettings();
|
||||
const timeZone = getTimezone(uiSettings);
|
||||
const hasBarChart = series.some(({ bars }) => bars?.show);
|
||||
|
@ -281,7 +295,7 @@ export const TimeSeries = ({
|
|||
<Axis
|
||||
id="bottom"
|
||||
position={Position.Bottom}
|
||||
title={xAxisLabel}
|
||||
title={getAxisLabelString(interval)}
|
||||
tickFormat={xAxisFormatter}
|
||||
gridLine={{
|
||||
...GRID_LINE_CONFIG,
|
||||
|
@ -303,10 +317,11 @@ TimeSeries.propTypes = {
|
|||
showGrid: PropTypes.bool,
|
||||
legend: PropTypes.bool,
|
||||
legendPosition: PropTypes.string,
|
||||
xAxisLabel: PropTypes.string,
|
||||
series: PropTypes.array,
|
||||
yAxis: PropTypes.array,
|
||||
onBrush: PropTypes.func,
|
||||
xAxisFormatter: PropTypes.func,
|
||||
annotations: PropTypes.array,
|
||||
interval: PropTypes.number,
|
||||
isLastBucketDropped: PropTypes.bool,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { PanelData } from '../../../../../../common/types';
|
||||
|
||||
export const calculateDomainForSeries = (series: PanelData[]) => {
|
||||
const seriesData = series[0]?.data || [];
|
||||
|
||||
return seriesData?.length
|
||||
? {
|
||||
domainStart: seriesData[0][0],
|
||||
domainEnd: seriesData[Math.max(seriesData.length - 1, 0)][0],
|
||||
}
|
||||
: undefined;
|
||||
};
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { calculateDomainForSeries } from './series_domain_calculation';
|
||||
import { PanelData } from 'src/plugins/vis_type_timeseries/common/types';
|
||||
|
||||
describe('calculateDomainForSeries', () => {
|
||||
it('should return 0 for domainStart and 3 for domainEnd', () => {
|
||||
const series = [
|
||||
{
|
||||
data: [
|
||||
[0, 0],
|
||||
[1, 1],
|
||||
[2, 2],
|
||||
[3, 3],
|
||||
],
|
||||
},
|
||||
] as PanelData[];
|
||||
const domainBounds = calculateDomainForSeries(series);
|
||||
|
||||
expect(domainBounds?.domainStart).toBe(0);
|
||||
expect(domainBounds?.domainEnd).toBe(3);
|
||||
});
|
||||
|
||||
it('should return undefined when series is empty', () => {
|
||||
const domainBounds = calculateDomainForSeries([]);
|
||||
|
||||
expect(domainBounds).toBeUndefined();
|
||||
});
|
||||
});
|
|
@ -62,6 +62,7 @@ export const metricsVisDefinition = {
|
|||
show_legend: 1,
|
||||
show_grid: 1,
|
||||
tooltip_mode: 'show_all',
|
||||
drop_last_bucket: 0,
|
||||
},
|
||||
},
|
||||
editorConfig: {
|
||||
|
|
|
@ -14,8 +14,9 @@ export function dropLastBucket(resp, panel, series) {
|
|||
const shouldDropLastBucket = isLastValueTimerangeMode(panel, series);
|
||||
|
||||
if (shouldDropLastBucket) {
|
||||
const seriesDropLastBucket = get(series, 'override_drop_last_bucket', 1);
|
||||
const dropLastBucket = get(panel, 'drop_last_bucket', seriesDropLastBucket);
|
||||
const dropLastBucket = series.override_index_pattern
|
||||
? get(series, 'series_drop_last_bucket', 0)
|
||||
: get(panel, 'drop_last_bucket', 0);
|
||||
|
||||
if (dropLastBucket) {
|
||||
results.forEach((item) => {
|
||||
|
|
|
@ -45,6 +45,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await PageObjects.visualBuilder.checkMetricTabIsPresent();
|
||||
await PageObjects.visualBuilder.clickPanelOptions('metric');
|
||||
await PageObjects.visualBuilder.setMetricsDataTimerangeMode('Last value');
|
||||
await PageObjects.visualBuilder.setDropLastBucket(true);
|
||||
await PageObjects.visualBuilder.clickDataTab('metric');
|
||||
});
|
||||
|
||||
|
@ -106,6 +107,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await PageObjects.visualBuilder.checkTopNTabIsPresent();
|
||||
await PageObjects.visualBuilder.clickPanelOptions('topN');
|
||||
await PageObjects.visualBuilder.setMetricsDataTimerangeMode('Last value');
|
||||
await PageObjects.visualBuilder.setDropLastBucket(true);
|
||||
await PageObjects.visualBuilder.clickDataTab('topN');
|
||||
});
|
||||
|
||||
|
@ -129,6 +131,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
await PageObjects.visualBuilder.checkMetricTabIsPresent();
|
||||
await PageObjects.visualBuilder.clickPanelOptions('metric');
|
||||
await PageObjects.visualBuilder.setMetricsDataTimerangeMode('Last value');
|
||||
await PageObjects.visualBuilder.setDropLastBucket(true);
|
||||
await PageObjects.visualBuilder.clickDataTab('metric');
|
||||
await PageObjects.timePicker.setAbsoluteRange(
|
||||
'Sep 22, 2019 @ 00:00:00.000',
|
||||
|
@ -215,6 +218,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
|
|||
const finalLegendItems = ['jpg: 106', 'css: 22', 'png: 14', 'gif: 8', 'php: 6'];
|
||||
|
||||
log.debug('Group metrics by terms: extension.raw');
|
||||
await PageObjects.visualBuilder.clickPanelOptions('timeSeries');
|
||||
await PageObjects.visualBuilder.setDropLastBucket(true);
|
||||
await PageObjects.visualBuilder.clickDataTab('timeSeries');
|
||||
await PageObjects.visualBuilder.setMetricsGroupByTerms('extension.raw');
|
||||
await PageObjects.visChart.waitForVisualizationRenderingStabilized();
|
||||
const legendItems1 = await PageObjects.visualBuilder.getLegendItemsContent();
|
||||
|
|
|
@ -39,6 +39,7 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
);
|
||||
await visualBuilder.markdownSwitchSubTab('options');
|
||||
await visualBuilder.setMetricsDataTimerangeMode('Last value');
|
||||
await visualBuilder.setDropLastBucket(true);
|
||||
await visualBuilder.markdownSwitchSubTab('markdown');
|
||||
});
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ export default function ({ getPageObjects }: FtrProviderContext) {
|
|||
await visualBuilder.checkTableTabIsPresent();
|
||||
await visualBuilder.clickPanelOptions('table');
|
||||
await visualBuilder.setMetricsDataTimerangeMode('Last value');
|
||||
await visualBuilder.setDropLastBucket(true);
|
||||
await visualBuilder.clickDataTab('table');
|
||||
await visualBuilder.selectGroupByField('machine.os.raw');
|
||||
await visualBuilder.setColumnLabelValue('OS');
|
||||
|
|
|
@ -26,6 +26,9 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) {
|
|||
describe('Time Series', () => {
|
||||
beforeEach(async () => {
|
||||
await visualBuilder.resetPage();
|
||||
await visualBuilder.clickPanelOptions('timeSeries');
|
||||
await visualBuilder.setDropLastBucket(true);
|
||||
await visualBuilder.clickDataTab('timeSeries');
|
||||
});
|
||||
|
||||
it('should render all necessary components', async () => {
|
||||
|
|
|
@ -69,8 +69,8 @@ export default function ({ getService }: FtrProviderContext) {
|
|||
expect(series).to.have.property('id', 'user');
|
||||
expect(series).to.have.property('data');
|
||||
const datapoint = last(series.data) as any;
|
||||
expect(datapoint).to.have.property('timestamp', 1547571720000);
|
||||
expect(datapoint).to.have.property('value', 0.0018333333333333333);
|
||||
expect(datapoint).to.have.property('timestamp', 1547571780000);
|
||||
expect(datapoint).to.have.property('value', 0.0015);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue