Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TSVB] Filter by clicking on the timeseries chart #97426

Merged
merged 20 commits into from
May 12, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export enum METRIC_TYPES {
// We should probably use BUCKET_TYPES from data plugin in future.
export enum BUCKET_TYPES {
TERMS = 'terms',
FILTERS = 'filters',
}

export const EXTENDED_STATS_TYPES = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,18 @@ jest.mock('../../../services', () => {
getDataStart: jest.fn(() => {
return {
indexPatterns: jest.fn(),
query: {
timefilter: {
timefilter: {
getTime: jest.fn(() => {
return {
from: '2021-04-30T16:42:24.502Z',
to: '2021-05-05T14:42:24.502Z',
};
}),
},
},
},
};
}),
};
Expand All @@ -25,9 +37,12 @@ describe('convert series to datatables', () => {

beforeEach(() => {
const fieldMap: Record<string, IndexPatternField> = {
test1: { name: 'test1', spec: { type: 'date' } } as IndexPatternField,
test2: { name: 'test2' } as IndexPatternField,
test3: { name: 'test3', spec: { type: 'boolean' } } as IndexPatternField,
test1: { name: 'test1', spec: { type: 'date', name: 'test1' } } as IndexPatternField,
test2: {
name: 'test2',
spec: { type: 'number', name: 'Average of test2' },
} as IndexPatternField,
test3: { name: 'test3', spec: { type: 'boolean', name: 'test3' } } as IndexPatternField,
};

const getFieldByName = (name: string): IndexPatternField | undefined => fieldMap[name];
Expand All @@ -41,8 +56,8 @@ describe('convert series to datatables', () => {

describe('addMetaColumns()', () => {
test('adds the correct meta to a date column', () => {
const columns = [{ id: 0, name: 'test1', isSplit: false }];
const columnsWithMeta = addMetaToColumns(columns, indexPattern, 'count');
const columns = [{ id: 0, name: 'test1', isMetric: true, type: 'date_histogram' }];
const columnsWithMeta = addMetaToColumns(columns, indexPattern);
expect(columnsWithMeta).toEqual([
{
id: '0',
Expand All @@ -54,6 +69,13 @@ describe('convert series to datatables', () => {
enabled: true,
indexPatternId: 'index1',
type: 'date_histogram',
schema: 'metric',
params: {
timeRange: {
from: '2021-04-30T16:42:24.502Z',
to: '2021-05-05T14:42:24.502Z',
},
},
},
type: 'date',
},
Expand All @@ -63,8 +85,8 @@ describe('convert series to datatables', () => {
});

test('adds the correct meta to a non date column', () => {
const columns = [{ id: 1, name: 'Average of test2', isSplit: false }];
const columnsWithMeta = addMetaToColumns(columns, indexPattern, 'avg');
const columns = [{ id: 1, name: 'test2', isMetric: true, type: 'avg' }];
const columnsWithMeta = addMetaToColumns(columns, indexPattern);
expect(columnsWithMeta).toEqual([
{
id: '1',
Expand All @@ -76,17 +98,21 @@ describe('convert series to datatables', () => {
enabled: true,
indexPatternId: 'index1',
type: 'avg',
schema: 'metric',
params: {
field: 'Average of test2',
},
},
type: 'number',
},
name: 'Average of test2',
name: 'test2',
},
]);
});

test('adds the correct meta for a split column', () => {
const columns = [{ id: 2, name: 'test3', isSplit: true }];
const columnsWithMeta = addMetaToColumns(columns, indexPattern, 'avg');
const columns = [{ id: 2, name: 'test3', isMetric: false, type: 'terms' }];
const columnsWithMeta = addMetaToColumns(columns, indexPattern);
expect(columnsWithMeta).toEqual([
{
id: '2',
Expand All @@ -98,6 +124,10 @@ describe('convert series to datatables', () => {
enabled: true,
indexPatternId: 'index1',
type: 'terms',
schema: 'group',
params: {
field: 'test3',
},
},
type: 'boolean',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,51 +6,74 @@
* Side Public License, v 1.
*/
import { IndexPattern } from 'src/plugins/data/public';
import {
Datatable,
DatatableRow,
DatatableColumn,
DatatableColumnType,
} from 'src/plugins/expressions/public';
import { DatatableRow, DatatableColumn, DatatableColumnType } from 'src/plugins/expressions/public';
import { Query } from 'src/plugins/data/common';
import { TimeseriesVisParams } from '../../../types';
import type { PanelData } from '../../../../common/types';
import { BUCKET_TYPES } from '../../../../common/enums';
import { fetchIndexPattern } from '../../../../common/index_patterns_utils';
import { getDataStart } from '../../../services';
import { X_ACCESSOR_INDEX } from '../../visualizations/constants';
import type { TSVBTables } from './types';

interface TSVBTables {
[key: string]: Datatable;
interface FilterParams {
filter?: Query;
label?: string;
field?: string;
}

interface TSVBColumns {
id: number;
name: string;
isSplit: boolean;
isMetric: boolean;
type: string;
params?: FilterParams[];
}

export const addMetaToColumns = (
columns: TSVBColumns[],
indexPattern: IndexPattern,
metricsType: string
indexPattern: IndexPattern
): DatatableColumn[] => {
return columns.map((column) => {
const field = indexPattern.getFieldByName(column.name);
const type = (field?.spec.type as DatatableColumnType) || 'number';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure whether it matters, but this isn't correct for filters - it will assume type as number because there is no field in this case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@flash1293 this is now the case on viz, here is the example of the meta on a filters column (taken by xy axis)
image

type === number

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, guess we should fix this on esaggs side as well. Anyway, for consistency reasons it makes sense to keep it for now 👍


let params: unknown = {
field: field?.spec.name,
};
if (column.type === BUCKET_TYPES.FILTERS && column.params) {
const filters = column.params.map((col) => ({
input: col.filter,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think if you add label: col.label in here, it will pick it up as custom label for the filter pill (this is what happens for Lens/Visualize as well)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are absolutely right
image

Fixed eb75702

label: col.label,
}));
params = {
filters,
};
} else if (column.type === 'date_histogram') {
const { query } = getDataStart();
const timeRange = query.timefilter.timefilter.getTime();
params = {
timeRange,
};
}

const cleanedColumn = {
id: column.id.toString(),
name: column.name,
meta: {
type,
field: column.name,
field: field?.spec.name,
index: indexPattern.title,
source: 'esaggs',
sourceParams: {
enabled: true,
indexPatternId: indexPattern?.id,
type: type === 'date' ? 'date_histogram' : column.isSplit ? 'terms' : metricsType,
type: column.type,
schema: column.isMetric ? 'metric' : 'group',
params,
},
},
};
} as DatatableColumn;
return cleanedColumn;
});
};
Expand All @@ -73,30 +96,58 @@ export const convertSeriesToDataTable = async (
usedIndexPattern = indexPattern;
}
}
const isGroupedByTerms = layer.split_mode === 'terms';
const isGroupedByTerms = layer.split_mode === BUCKET_TYPES.TERMS;
const isGroupedByFilters = layer.split_mode === BUCKET_TYPES.FILTERS;
const seriesPerLayer = series.filter((s) => s.seriesId === layer.id);
let id = X_ACCESSOR_INDEX;

const columns: TSVBColumns[] = [
{ id, name: usedIndexPattern.timeFieldName || '', isSplit: false },
{
id,
name: usedIndexPattern.timeFieldName || '',
isMetric: false,
type: 'date_histogram',
},
];

if (seriesPerLayer.length) {
id++;
columns.push({ id, name: seriesPerLayer[0].splitByLabel, isSplit: false });
// Adds an extra column, if the layer is split by terms aggregation
const metrics = layer.metrics;
columns.push({
id,
name: metrics[metrics.length - 1].field || seriesPerLayer[0].splitByLabel,
isMetric: true,
type: metrics[metrics.length - 1].type,
});

// Adds an extra column, if the layer is split by terms or filters aggregation
if (isGroupedByTerms) {
id++;
columns.push({ id, name: layer.terms_field || '', isSplit: true });
columns.push({
id,
name: layer.terms_field || '',
isMetric: false,
type: BUCKET_TYPES.TERMS,
});
} else if (isGroupedByFilters) {
id++;
columns.push({
id,
name: BUCKET_TYPES.FILTERS,
isMetric: false,
params: layer?.split_filters as FilterParams[],
type: BUCKET_TYPES.FILTERS,
});
}
}
const columnsWithMeta = addMetaToColumns(columns, usedIndexPattern, layer.metrics[0].type);

const columnsWithMeta = addMetaToColumns(columns, usedIndexPattern);
const filtersColumn = columns.find((col) => col.type === BUCKET_TYPES.FILTERS);
let rows: DatatableRow[] = [];
for (let j = 0; j < seriesPerLayer.length; j++) {
const data = seriesPerLayer[j].data.map((rowData) => {
const row: DatatableRow = [rowData[0], rowData[1]];
// If the layer is split by terms aggregation, the data array should also contain the split value.
if (isGroupedByTerms) {
if (isGroupedByTerms || filtersColumn) {
row.push(seriesPerLayer[j].label);
}
return row;
Expand Down
Loading