[TSVB] Fix series containing colon (#123897)

This commit is contained in:
Joe Reuter 2022-02-03 19:05:19 +01:00 committed by GitHub
parent af9d3a1602
commit 52f0ea20fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 38 additions and 27 deletions

View file

@ -11,6 +11,7 @@ export const UI_SETTINGS = {
ALLOW_STRING_INDICES: 'metrics:allowStringIndices',
ALLOW_CHECKING_FOR_FAILED_SHARDS: 'metrics:allowCheckingForFailedShards',
};
export const SERIES_SEPARATOR = '╰┄►';
export const INDEXES_SEPARATOR = ',';
export const AUTO_INTERVAL = 'auto';
export const ROUTES = {

View file

@ -9,6 +9,7 @@ import { XYChartSeriesIdentifier, GeometryValue } from '@elastic/charts';
import { getClickFilterData } from './get_click_filter_data';
import type { TSVBTables } from './types';
import { TimeseriesVisParams } from '../../../types';
import { SERIES_SEPARATOR } from '../../../../common/constants';
describe('getClickFilterData', () => {
test('gets the correct data for a group by everything timeseries chart', () => {
@ -102,7 +103,7 @@ describe('getClickFilterData', () => {
},
{
key: 'groupId{yaxis_6e0353a0-ad9b-11eb-b112-89cce8e43380_main_group}spec{61ca57f1-469d-11e7-af02-69e470af7417:1}yAccessor{1}splitAccessors{}',
specId: '61ca57f1-469d-11e7-af02-69e470af7417:1',
specId: '61ca57f1-469d-11e7-af02-69e470af7417╰┄►1',
},
],
] as Array<[GeometryValue, XYChartSeriesIdentifier]>;
@ -199,7 +200,7 @@ describe('getClickFilterData', () => {
expect(data[1].column).toEqual(2);
expect(data[1].row).toEqual(10);
// expect(data).toEqual([]);
const splitValue = points[0][1].specId.split(':');
const splitValue = points[0][1].specId.split(SERIES_SEPARATOR);
expect(data[1].value).toEqual(parseInt(splitValue[1], 10));
});
});

View file

@ -11,6 +11,7 @@ import { X_ACCESSOR_INDEX } from '../../visualizations/constants';
import { BUCKET_TYPES } from '../../../../common/enums';
import { TimeseriesVisParams } from '../../../types';
import type { TSVBTables } from './types';
import { SERIES_SEPARATOR } from '../../../../common/constants';
export const getClickFilterData = (
points: Array<[GeometryValue, XYChartSeriesIdentifier]>,
@ -23,7 +24,7 @@ export const getClickFilterData = (
const { specId } = point[1];
// specId for a split series has the format
// 61ca57f1-469d-11e7-af02-69e470af7417:Men's Accessories, <layer_id>:<split_label>
const [layerId, splitLabel] = specId.split(':');
const [layerId, splitLabel] = specId.split(SERIES_SEPARATOR);
const table = tables[layerId];
const layer = model.series.filter(({ id }) => id === layerId);

View file

@ -20,6 +20,7 @@ import { sortBy, first, get } from 'lodash';
import { DATA_FORMATTERS } from '../../../../../common/enums';
import { getOperator, shouldOperate } from '../../../../../common/operators_utils';
import { ExternalUrlErrorModal } from '../../lib/external_url_error_modal';
import { SERIES_SEPARATOR } from '../../../../../common/constants';
function sortByDirection(data, direction, fn) {
if (direction === 'desc') {
@ -32,7 +33,7 @@ function sortSeries(visData, model) {
const series = get(visData, `${model.id}.series`, []);
return model.series.reduce((acc, item) => {
const itemSeries = series.filter((s) => {
const id = first(s.id.split(/:/));
const id = first(s.id.split(SERIES_SEPARATOR));
return id === item.id;
});
const direction = item.terms_direction || 'desc';
@ -47,7 +48,7 @@ function TopNVisualization(props) {
const { backgroundColor, model, visData, fieldFormatMap, getConfig } = props;
const series = sortSeries(visData, model).map((item) => {
const id = first(item.id.split(/:/));
const id = first(item.id.split(SERIES_SEPARATOR));
const seriesConfig = model.series.find((s) => s.id === id);
if (seriesConfig) {
const tickFormatter =

View file

@ -13,6 +13,7 @@ import { labelDateFormatter } from './lib/label_date_formatter';
import { findIndex, first } from 'lodash';
import { getValueOrEmpty } from '../../../common/empty_label';
import { getSplitByTermsColor } from '../lib/get_split_by_terms_color';
import { SERIES_SEPARATOR } from '../../../common/constants';
export function visWithSplits(WrappedComponent) {
function SplitVisComponent(props) {
@ -43,12 +44,12 @@ export function visWithSplits(WrappedComponent) {
);
if (!model || !visData || !visData[model.id]) return <WrappedComponent {...props} />;
if (visData[model.id].series.every((s) => s.id.split(':').length === 1)) {
if (visData[model.id].series.every((s) => s.id.split(SERIES_SEPARATOR).length === 1)) {
return <WrappedComponent {...props} />;
}
const splitsVisData = visData[model.id].series.reduce((acc, series) => {
const [seriesId, splitId] = series.id.split(':');
const [seriesId, splitId] = series.id.split(SERIES_SEPARATOR);
const seriesModel = model.series.find((s) => s.id === seriesId);
if (!seriesModel) return acc;

View file

@ -79,7 +79,7 @@ describe('getSplits(resp, panel, series)', () => {
expect(await getSplits(resp, panel, series, undefined, () => [])).toEqual([
{
id: 'SERIES:example-01',
id: 'SERIES╰┄►example-01',
key: 'example-01',
label: 'example-01',
labelFormatted: '',
@ -90,7 +90,7 @@ describe('getSplits(resp, panel, series)', () => {
SIBAGG: { value: 1 },
},
{
id: 'SERIES:example-02',
id: 'SERIES╰┄►example-02',
key: 'example-02',
label: 'example-02',
labelFormatted: '',
@ -138,7 +138,7 @@ describe('getSplits(resp, panel, series)', () => {
const panel = { type: 'top_n' } as Panel;
expect(await getSplits(resp, panel, series, undefined, () => [])).toEqual([
{
id: 'SERIES:example-01',
id: 'SERIES╰┄►example-01',
key: 'example-01',
label: '--example-01--',
labelFormatted: '',
@ -149,7 +149,7 @@ describe('getSplits(resp, panel, series)', () => {
SIBAGG: { value: 1 },
},
{
id: 'SERIES:example-02',
id: 'SERIES╰┄►example-02',
key: 'example-02',
label: '--example-02--',
labelFormatted: '',
@ -200,7 +200,7 @@ describe('getSplits(resp, panel, series)', () => {
expect(await getSplits(resp, panel, series, undefined, () => [])).toEqual([
{
id: 'SERIES:example-01',
id: 'SERIES╰┄►example-01',
key: 'example-01',
key_as_string: 'false',
label: '--example-01--',
@ -212,7 +212,7 @@ describe('getSplits(resp, panel, series)', () => {
SIBAGG: { value: 1 },
},
{
id: 'SERIES:example-02',
id: 'SERIES╰┄►example-02',
key: 'example-02',
key_as_string: 'true',
label: '--example-02--',
@ -256,7 +256,7 @@ describe('getSplits(resp, panel, series)', () => {
expect(await getSplits(resp, panel, series, undefined, () => [])).toEqual([
{
id: 'SERIES:filter-1',
id: 'SERIES╰┄►filter-1',
key: 'filter-1',
label: '200s',
meta: { bucketSize: 10 },
@ -265,7 +265,7 @@ describe('getSplits(resp, panel, series)', () => {
timeseries: { buckets: [] },
},
{
id: 'SERIES:filter-2',
id: 'SERIES╰┄►filter-2',
key: 'filter-2',
label: '300s',
splitByLabel: 'Count',

View file

@ -11,6 +11,7 @@ import { get, isPlainObject } from 'lodash';
import { overwrite } from '../helpers';
import { calculateLabel } from '../../../../common/calculate_label';
import { SERIES_SEPARATOR } from '../../../../common/constants';
import { getLastMetric } from './get_last_metric';
import { formatKey } from './format_key';
@ -66,7 +67,7 @@ export async function getSplits<TRawResponse = unknown, TMeta extends BaseMeta =
};
}
bucket.id = `${series.id}:${bucket.key}`;
bucket.id = `${series.id}${SERIES_SEPARATOR}${bucket.key}`;
bucket.splitByLabel = splitByLabel;
bucket.label = formatKey(bucket.key, series);
bucket.labelFormatted = bucket.key_as_string ? formatKey(bucket.key_as_string, series) : '';
@ -79,7 +80,7 @@ export async function getSplits<TRawResponse = unknown, TMeta extends BaseMeta =
if (series.split_mode === 'filters' && isPlainObject(buckets)) {
return (series.split_filters || []).map((filter) => {
const bucket = get(resp, `aggregations.${series.id}.buckets.${filter.id}`);
bucket.id = `${series.id}:${filter.id}`;
bucket.id = `${series.id}${SERIES_SEPARATOR}${filter.id}`;
bucket.key = filter.id;
bucket.splitByLabel = splitByLabel;
bucket.color = filter.color;

View file

@ -7,6 +7,7 @@
*/
import { convertIntervalToUnit } from '../../helpers/unit_to_seconds';
import { SERIES_SEPARATOR } from '../../../../../common/constants';
const percentileValueMatch = /\[([0-9\.]+)\]$/;
import { startsWith, flatten, values, first, last } from 'lodash';
@ -20,7 +21,7 @@ export function mathAgg(resp, panel, series, meta, extractFields) {
// Filter the results down to only the ones that match the series.id. Sometimes
// there will be data from other series mixed in.
results = results.filter((s) => {
if (s.id.split(/:/)[0] === series.id) {
if (s.id.split(SERIES_SEPARATOR)[0] === series.id) {
return false;
}
return true;

View file

@ -93,7 +93,7 @@ describe('math(resp, panel, series)', () => {
expect(results).toHaveLength(1);
expect(results[0]).toEqual({
id: 'test:example-01',
id: 'test╰┄►example-01',
label: 'example-01',
color: 'rgb(255, 0, 0)',
stack: false,

View file

@ -11,6 +11,7 @@ import { getDefaultDecoration } from '../../helpers/get_default_decoration';
import { getSplits } from '../../helpers/get_splits';
import { getLastMetric } from '../../helpers/get_last_metric';
import { TSVB_METRIC_TYPES } from '../../../../../common/enums';
import { SERIES_SEPARATOR } from '../../../../../common/constants';
export function percentile(resp, panel, series, meta, extractFields) {
return (next) => async (results) => {
@ -23,7 +24,7 @@ export function percentile(resp, panel, series, meta, extractFields) {
(await getSplits(resp, panel, series, meta, extractFields)).forEach((split) => {
metric.percentiles.forEach((percentile) => {
const percentileValue = percentile.value ? percentile.value : 0;
const id = `${split.id}:${percentile.id}`;
const id = `${split.id}${SERIES_SEPARATOR}${percentile.id}`;
const data = split.timeseries.buckets.map((bucket) => {
const higherMetric = { ...metric, percent: percentileValue };
const serieData = [bucket.key, getAggValue(bucket, higherMetric)];

View file

@ -83,7 +83,7 @@ describe('percentile(resp, panel, series)', () => {
expect(results).toHaveLength(2);
expect(results[0]).toHaveProperty('id', 'test:10-90');
expect(results[0]).toHaveProperty('id', 'test╰┄►10-90');
expect(results[0]).toHaveProperty('color', '#000028');
expect(results[0]).toHaveProperty('label', 'Percentile of cpu');
expect(results[0]).toHaveProperty('lines');
@ -100,7 +100,7 @@ describe('percentile(resp, panel, series)', () => {
[2, 1.2, 5.3],
]);
expect(results[1]).toHaveProperty('id', 'test:50');
expect(results[1]).toHaveProperty('id', 'test╰┄►50');
expect(results[1]).toHaveProperty('color', 'rgb(255, 0, 0)');
expect(results[1]).toHaveProperty('label', '(50) Percentile of cpu');
expect(results[1]).toHaveProperty('stack', false);

View file

@ -12,6 +12,7 @@ import { getSplits } from '../../helpers/get_splits';
import { getLastMetric } from '../../helpers/get_last_metric';
import { toPercentileNumber } from '../../../../../common/to_percentile_number';
import { TSVB_METRIC_TYPES } from '../../../../../common/enums';
import { SERIES_SEPARATOR } from '../../../../../common/constants';
export function percentileRank(resp, panel, series, meta, extractFields) {
return (next) => async (results) => {
@ -33,7 +34,7 @@ export function percentileRank(resp, panel, series, meta, extractFields) {
results.push({
data,
id: `${split.id}:${percentileRank}:${index}`,
id: `${split.id}${SERIES_SEPARATOR}${percentileRank}${SERIES_SEPARATOR}${index}`,
label: `(${percentileRank || 0}) ${split.label}`,
color:
series.split_mode === 'everything' && metric.colors

View file

@ -75,7 +75,7 @@ describe('percentile_rank(resp, panel, series, meta, extractFields)', () => {
expect(results).toHaveLength(2);
expect(results[0]).toHaveProperty('id', 'test:1000:0');
expect(results[0]).toHaveProperty('id', 'test╰┄►1000╰┄►0');
expect(results[0]).toHaveProperty('color', '#000028');
expect(results[0]).toHaveProperty('label', '(1000) Percentile Rank of cpu');
expect(results[0].data).toEqual([
@ -83,7 +83,7 @@ describe('percentile_rank(resp, panel, series, meta, extractFields)', () => {
[2, 1],
]);
expect(results[1]).toHaveProperty('id', 'test:500:1');
expect(results[1]).toHaveProperty('id', 'test╰┄►500╰┄►1');
expect(results[1]).toHaveProperty('color', '#0000FF');
expect(results[1]).toHaveProperty('label', '(500) Percentile Rank of cpu');
expect(results[1].data).toEqual([

View file

@ -9,6 +9,7 @@ import { last, first } from 'lodash';
import { SeriesAgg } from './_series_agg';
import { getDefaultDecoration } from '../../helpers/get_default_decoration';
import { calculateLabel } from '../../../../../common/calculate_label';
import { SERIES_SEPARATOR } from '../../../../../common/constants';
export function seriesAgg(resp, panel, series, meta, extractFields) {
return (next) => async (results) => {
@ -19,7 +20,7 @@ export function seriesAgg(resp, panel, series, meta, extractFields) {
// Filter out the seires with the matching metric and store them
// in targetSeries
results = results.filter((s) => {
if (s.id.split(/:/)[0] === series.id) {
if (s.id.split(SERIES_SEPARATOR)[0] === series.id) {
targetSeries.push(s.data);
return false;
}

View file

@ -9,6 +9,7 @@
import { last } from 'lodash';
import { calculateLabel } from '../../../../../common/calculate_label';
import { SERIES_SEPARATOR } from '../../../../../common/constants';
// @ts-expect-error no typed yet
import { SeriesAgg } from './_series_agg';
@ -26,7 +27,7 @@ export const seriesAgg: TableResponseProcessorsFunction =
// Filter out the seires with the matching metric and store them
// in targetSeries
results = results.filter((s) => {
if (s.id && s.id.split(/:/)[0] === series.id) {
if (s.id && s.id.split(SERIES_SEPARATOR)[0] === series.id) {
targetSeries.push(s.data!);
return false;
}