Skip to content

Commit

Permalink
refactor action filter creation utils
Browse files Browse the repository at this point in the history
  • Loading branch information
ppisljar committed Apr 8, 2020
1 parent 3d6fd68 commit 6e77cfb
Show file tree
Hide file tree
Showing 15 changed files with 96 additions and 106 deletions.
4 changes: 3 additions & 1 deletion src/legacy/core_plugins/vis_type_vislib/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ export class VisTypeVislibPlugin implements Plugin<void, void> {

public start(core: CoreStart, { data }: VisTypeVislibPluginStartDependencies) {
setFormatService(data.fieldFormats);
setDataActions({ createFiltersFromEvent: data.actions.createFiltersFromEvent });
setDataActions({
createFiltersFromValueClickAction: data.actions.createFiltersFromValueClickAction,
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ jest.mock('../../../legacy_imports', () => ({
}));

jest.mock('../../../services', () => ({
getDataActions: () => ({ createFiltersFromEvent: jest.fn().mockResolvedValue(['yes']) }),
getDataActions: () => ({
createFiltersFromValueClickAction: jest.fn().mockResolvedValue(['yes']),
}),
}));

const vis = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export class VisLegend extends PureComponent<VisLegendProps, VisLegendState> {
return false;
}

const filters = await getDataActions().createFiltersFromEvent(item.values);
const filters = await getDataActions().createFiltersFromValueClickAction({ data: item.values });
return Boolean(filters.length);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ export const npStart = {
},
data: {
actions: {
createFiltersFromEvent: Promise.resolve(['yes']),
createFiltersFromValueClickAction: Promise.resolve(['yes']),
},
autocomplete: {
getProvider: sinon.fake(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@

import moment from 'moment';

import { onBrushEvent, BrushEvent } from './brush_event';
import {
createFiltersFromRangeSelectAction,
RangeSelectEvent,
} from './create_filters_from_range_select';

import { IndexPatternsContract } from '../../../public';
import { dataPluginMock } from '../../../public/mocks';
Expand All @@ -29,7 +32,7 @@ import { mockDataServices } from '../../../public/search/aggs/test_helpers';
describe('brushEvent', () => {
const DAY_IN_MS = 24 * 60 * 60 * 1000;
const JAN_01_2014 = 1388559600000;
let baseEvent: BrushEvent;
let baseEvent: RangeSelectEvent;

const aggConfigs = [
{
Expand Down Expand Up @@ -61,44 +64,32 @@ describe('brushEvent', () => {
} as unknown) as IndexPatternsContract);

baseEvent = {
data: {
ordered: {
date: false,
},
series: [
column: 0,
table: {
type: 'kibana_datatable',
columns: [
{
values: [
{
xRaw: {
column: 0,
table: {
columns: [
{
id: '1',
meta: {
type: 'histogram',
indexPatternId: 'indexPatternId',
aggConfigParams: aggConfigs[0].params,
},
},
],
},
},
},
],
id: '1',
name: '1',
meta: {
type: 'histogram',
indexPatternId: 'indexPatternId',
aggConfigParams: aggConfigs[0].params,
},
},
],
rows: [],
},
range: [],
};
});

test('should be a function', () => {
expect(typeof onBrushEvent).toBe('function');
expect(typeof createFiltersFromRangeSelectAction).toBe('function');
});

test('ignores event when data.xAxisField not provided', async () => {
const filter = await onBrushEvent(baseEvent);
const filter = await createFiltersFromRangeSelectAction(baseEvent);
expect(filter).toBeUndefined();
});

Expand All @@ -119,19 +110,19 @@ describe('brushEvent', () => {

test('by ignoring the event when range spans zero time', async () => {
baseEvent.range = [JAN_01_2014, JAN_01_2014];
const filter = await onBrushEvent(baseEvent);
const filter = await createFiltersFromRangeSelectAction(baseEvent);
expect(filter).toBeUndefined();
});

test('by updating the timefilter', async () => {
baseEvent.range = [JAN_01_2014, JAN_01_2014 + DAY_IN_MS];
const filter = await onBrushEvent(baseEvent);
const filter = await createFiltersFromRangeSelectAction(baseEvent);
expect(filter).toBeDefined();

if (filter) {
expect(filter.range.time.gte).toBe(new Date(JAN_01_2014).toISOString());
if (filter.length) {
expect(filter[0].range.time.gte).toBe(new Date(JAN_01_2014).toISOString());
// Set to a baseline timezone for comparison.
expect(filter.range.time.lt).toBe(new Date(JAN_01_2014 + DAY_IN_MS).toISOString());
expect(filter[0].range.time.lt).toBe(new Date(JAN_01_2014 + DAY_IN_MS).toISOString());
}
});
});
Expand All @@ -154,14 +145,14 @@ describe('brushEvent', () => {
const rangeBegin = JAN_01_2014;
const rangeEnd = rangeBegin + DAY_IN_MS;
baseEvent.range = [rangeBegin, rangeEnd];
const filter = await onBrushEvent(baseEvent);
const filter = await createFiltersFromRangeSelectAction(baseEvent);

expect(filter).toBeDefined();

if (filter) {
expect(filter.range.anotherTimeField.gte).toBe(moment(rangeBegin).toISOString());
expect(filter.range.anotherTimeField.lt).toBe(moment(rangeEnd).toISOString());
expect(filter.range.anotherTimeField).toHaveProperty(
if (filter.length) {
expect(filter[0].range.anotherTimeField.gte).toBe(moment(rangeBegin).toISOString());
expect(filter[0].range.anotherTimeField.lt).toBe(moment(rangeEnd).toISOString());
expect(filter[0].range.anotherTimeField).toHaveProperty(
'format',
'strict_date_optional_time'
);
Expand All @@ -184,20 +175,20 @@ describe('brushEvent', () => {

test('by ignoring the event when range does not span at least 2 values', async () => {
baseEvent.range = [1];
const filter = await onBrushEvent(baseEvent);
const filter = await createFiltersFromRangeSelectAction(baseEvent);
expect(filter).toBeUndefined();
});

test('by creating a new filter', async () => {
baseEvent.range = [1, 2, 3, 4];
const filter = await onBrushEvent(baseEvent);
const filter = await createFiltersFromRangeSelectAction(baseEvent);

expect(filter).toBeDefined();

if (filter) {
expect(filter.range.numberField.gte).toBe(1);
expect(filter.range.numberField.lt).toBe(4);
expect(filter.range.numberField).not.toHaveProperty('format');
if (filter.length) {
expect(filter[0].range.numberField.gte).toBe(1);
expect(filter[0].range.numberField.lt).toBe(4);
expect(filter[0].range.numberField).not.toHaveProperty('format');
}
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,24 @@
* under the License.
*/

import { get, last } from 'lodash';
import { last } from 'lodash';
import moment from 'moment';
import { esFilters, IFieldType, RangeFilterParams } from '../../../public';
import { getIndexPatterns } from '../../../public/services';
import { deserializeAggConfig } from '../../search/expressions/utils';
import { KibanaDatatable } from '../../../../expressions';

export interface BrushEvent {
data: {
ordered: {
date: boolean;
};
series: Array<Record<string, any>>;
};
export interface RangeSelectEvent {
table: KibanaDatatable;
column: number;
range: number[];
}

export async function onBrushEvent(event: BrushEvent) {
const isDate = get(event.data, 'ordered.date');
const xRaw: Record<string, any> = get(event.data, 'series[0].values[0].xRaw');

if (!xRaw) {
return;
}

const column: Record<string, any> = xRaw.table.columns[xRaw.column];
export async function createFiltersFromRangeSelectAction(event: RangeSelectEvent) {
const column: Record<string, any> = event.table.columns[event.column];

if (!column || !column.meta) {
return;
return [];
}

const indexPattern = await getIndexPatterns().get(column.meta.indexPatternId);
Expand All @@ -55,16 +45,18 @@ export async function onBrushEvent(event: BrushEvent) {
const field: IFieldType = aggConfig.params.field;

if (!field || event.range.length <= 1) {
return;
return [];
}

const min = event.range[0];
const max = last(event.range);

if (min === max) {
return;
return [];
}

const isDate = field.type === 'date';

const range: RangeFilterParams = {
gte: isDate ? moment(min).toISOString() : min,
lt: isDate ? moment(max).toISOString() : max,
Expand All @@ -74,5 +66,5 @@ export async function onBrushEvent(event: BrushEvent) {
range.format = 'strict_date_optional_time';
}

return esFilters.buildRangeFilter(field, range, indexPattern);
return esFilters.mapAndFlattenFilters([esFilters.buildRangeFilter(field, range, indexPattern)]);
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
import { dataPluginMock } from '../../../public/mocks';
import { setIndexPatterns } from '../../../public/services';
import { mockDataServices } from '../../../public/search/aggs/test_helpers';
import { createFiltersFromEvent, EventData } from './create_filters_from_event';
import { createFiltersFromValueClickAction, EventData } from './create_filters_from_value_click';

const mockField = {
name: 'bytes',
Expand All @@ -37,7 +37,7 @@ const mockField = {
format: new fieldFormats.BytesFormat({}, (() => {}) as FieldFormatsGetConfigFn),
};

describe('createFiltersFromEvent', () => {
describe('createFiltersFromValueClick', () => {
let dataPoints: EventData[];

beforeEach(() => {
Expand Down Expand Up @@ -86,7 +86,7 @@ describe('createFiltersFromEvent', () => {

test('ignores event when value for rows is not provided', async () => {
dataPoints[0].table.rows[0]['1-1'] = null;
const filters = await createFiltersFromEvent(dataPoints);
const filters = await createFiltersFromValueClickAction({ data: dataPoints });

expect(filters.length).toEqual(0);
});
Expand All @@ -95,14 +95,14 @@ describe('createFiltersFromEvent', () => {
if (dataPoints[0].table.columns[0].meta) {
dataPoints[0].table.columns[0].meta.type = 'terms';
}
const filters = await createFiltersFromEvent(dataPoints);
const filters = await createFiltersFromValueClickAction({ data: dataPoints });

expect(filters.length).toEqual(1);
expect(filters[0].query.match_phrase.bytes).toEqual('2048');
});

test('handles an event when aggregations type is not terms', async () => {
const filters = await createFiltersFromEvent(dataPoints);
const filters = await createFiltersFromValueClickAction({ data: dataPoints });

expect(filters.length).toEqual(1);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ export interface EventData {
value: any;
}

export interface ValueClickEvent {
data: EventData[];
negate?: boolean;
}

/**
* For terms aggregations on `__other__` buckets, this assembles a list of applicable filter
* terms based on a specific cell in the tabified data.
Expand Down Expand Up @@ -113,11 +118,11 @@ const createFilter = async (table: EventData['table'], columnIndex: number, rowI
};

/** @public */
export const createFiltersFromEvent = async (dataPoints: EventData[], negate?: boolean) => {
export const createFiltersFromValueClickAction = async ({ data, negate }: ValueClickEvent) => {
const filters: Filter[] = [];

await Promise.all(
dataPoints
data
.filter(point => point)
.map(async val => {
const { table, column, row } = val;
Expand All @@ -133,5 +138,5 @@ export const createFiltersFromEvent = async (dataPoints: EventData[], negate?: b
})
);

return filters;
return esFilters.mapAndFlattenFilters(filters);
};
2 changes: 1 addition & 1 deletion src/plugins/data/public/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@
*/

export { ACTION_GLOBAL_APPLY_FILTER, createFilterAction } from './apply_filter_action';
export { createFiltersFromEvent } from './filters/create_filters_from_event';
export { createFiltersFromValueClickAction } from './filters/create_filters_from_value_click';
export { selectRangeAction } from './select_range_action';
export { valueClickAction } from './value_click_action';
17 changes: 7 additions & 10 deletions src/plugins/data/public/actions/select_range_action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,22 @@ import {
IncompatibleActionError,
ActionByType,
} from '../../../../plugins/ui_actions/public';
import { onBrushEvent } from './filters/brush_event';
import {
createFiltersFromRangeSelectAction,
RangeSelectEvent,
} from './filters/create_filters_from_range_select';
import { FilterManager, TimefilterContract, esFilters } from '..';

export const ACTION_SELECT_RANGE = 'ACTION_SELECT_RANGE';

export interface SelectRangeActionContext {
data: any;
data: RangeSelectEvent;
timeFieldName: string;
}

async function isCompatible(context: SelectRangeActionContext) {
try {
return Boolean(await onBrushEvent(context.data));
return Boolean(await createFiltersFromRangeSelectAction(context.data));
} catch {
return false;
}
Expand All @@ -59,13 +62,7 @@ export function selectRangeAction(
throw new IncompatibleActionError();
}

const filter = await onBrushEvent(data);

if (!filter) {
return;
}

const selectedFilters = esFilters.mapAndFlattenFilters([filter]);
const selectedFilters = await createFiltersFromRangeSelectAction(data);

if (timeFieldName) {
const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter(
Expand Down
Loading

0 comments on commit 6e77cfb

Please sign in to comment.