refactor action filter creation utils (#62969)
This commit is contained in:
parent
2f794e6c42
commit
222fdc5029
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
actions: {
|
actions: {
|
||||||
createFiltersFromEvent: typeof createFiltersFromEvent;
|
createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction;
|
||||||
|
createFiltersFromRangeSelectAction: typeof createFiltersFromRangeSelectAction;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
|
@ -14,7 +14,7 @@ export interface DataPublicPluginStart
|
||||||
|
|
||||||
| Property | Type | Description |
|
| Property | Type | Description |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| [actions](./kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md) | <code>{</code><br/><code> createFiltersFromEvent: typeof createFiltersFromEvent;</code><br/><code> }</code> | |
|
| [actions](./kibana-plugin-plugins-data-public.datapublicpluginstart.actions.md) | <code>{</code><br/><code> createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction;</code><br/><code> createFiltersFromRangeSelectAction: typeof createFiltersFromRangeSelectAction;</code><br/><code> }</code> | |
|
||||||
| [autocomplete](./kibana-plugin-plugins-data-public.datapublicpluginstart.autocomplete.md) | <code>AutocompleteStart</code> | |
|
| [autocomplete](./kibana-plugin-plugins-data-public.datapublicpluginstart.autocomplete.md) | <code>AutocompleteStart</code> | |
|
||||||
| [fieldFormats](./kibana-plugin-plugins-data-public.datapublicpluginstart.fieldformats.md) | <code>FieldFormatsStart</code> | |
|
| [fieldFormats](./kibana-plugin-plugins-data-public.datapublicpluginstart.fieldformats.md) | <code>FieldFormatsStart</code> | |
|
||||||
| [indexPatterns](./kibana-plugin-plugins-data-public.datapublicpluginstart.indexpatterns.md) | <code>IndexPatternsContract</code> | |
|
| [indexPatterns](./kibana-plugin-plugins-data-public.datapublicpluginstart.indexpatterns.md) | <code>IndexPatternsContract</code> | |
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
fieldFormats: {
|
fieldFormats: {
|
||||||
FieldFormat: typeof FieldFormat;
|
FieldFormat: typeof FieldFormat;
|
||||||
FieldFormatsRegistry: typeof FieldFormatsRegistry;
|
FieldFormatsRegistry: typeof FieldFormatsRegistry;
|
||||||
serialize: (agg: import("./search").AggConfig) => import("../../expressions/common").SerializedFieldFormat<object>;
|
serialize: (agg: import("./search").AggConfig) => import("../../expressions").SerializedFieldFormat<object>;
|
||||||
DEFAULT_CONVERTER_COLOR: {
|
DEFAULT_CONVERTER_COLOR: {
|
||||||
range: string;
|
range: string;
|
||||||
regex: string;
|
regex: string;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
fieldFormats: {
|
fieldFormats: {
|
||||||
FieldFormatsRegistry: typeof FieldFormatsRegistry;
|
FieldFormatsRegistry: typeof FieldFormatsRegistry;
|
||||||
FieldFormat: typeof FieldFormat;
|
FieldFormat: typeof FieldFormat;
|
||||||
serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions/common").SerializedFieldFormat<object>;
|
serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions").SerializedFieldFormat<object>;
|
||||||
BoolFormat: typeof BoolFormat;
|
BoolFormat: typeof BoolFormat;
|
||||||
BytesFormat: typeof BytesFormat;
|
BytesFormat: typeof BytesFormat;
|
||||||
ColorFormat: typeof ColorFormat;
|
ColorFormat: typeof ColorFormat;
|
||||||
|
|
|
@ -108,6 +108,6 @@ export class VisTypeVislibPlugin implements Plugin<void, void> {
|
||||||
|
|
||||||
public start(core: CoreStart, { data }: VisTypeVislibPluginStartDependencies) {
|
public start(core: CoreStart, { data }: VisTypeVislibPluginStartDependencies) {
|
||||||
setFormatService(data.fieldFormats);
|
setFormatService(data.fieldFormats);
|
||||||
setDataActions({ createFiltersFromEvent: data.actions.createFiltersFromEvent });
|
setDataActions(data.actions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,9 @@ jest.mock('../../../legacy_imports', () => ({
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock('../../../services', () => ({
|
jest.mock('../../../services', () => ({
|
||||||
getDataActions: () => ({ createFiltersFromEvent: jest.fn().mockResolvedValue(['yes']) }),
|
getDataActions: () => ({
|
||||||
|
createFiltersFromValueClickAction: jest.fn().mockResolvedValue(['yes']),
|
||||||
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const vis = {
|
const vis = {
|
||||||
|
|
|
@ -101,7 +101,7 @@ export class VisLegend extends PureComponent<VisLegendProps, VisLegendState> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const filters = await getDataActions().createFiltersFromEvent(item.values);
|
const filters = await getDataActions().createFiltersFromValueClickAction({ data: item.values });
|
||||||
return Boolean(filters.length);
|
return Boolean(filters.length);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -83,10 +83,21 @@ export class Handler {
|
||||||
|
|
||||||
// memoize so that the same function is returned every time,
|
// memoize so that the same function is returned every time,
|
||||||
// allowing us to remove/re-add the same function
|
// allowing us to remove/re-add the same function
|
||||||
this.getProxyHandler = _.memoize(function(event) {
|
this.getProxyHandler = _.memoize(function(eventType) {
|
||||||
const self = this;
|
const self = this;
|
||||||
return function(e) {
|
return function(eventPayload) {
|
||||||
self.vis.emit(event, e);
|
switch (eventType) {
|
||||||
|
case 'brush':
|
||||||
|
const xRaw = _.get(eventPayload.data, 'series[0].values[0].xRaw');
|
||||||
|
if (!xRaw) return; // not sure if this is possible?
|
||||||
|
return self.vis.emit(eventType, {
|
||||||
|
table: xRaw.table,
|
||||||
|
range: eventPayload.range,
|
||||||
|
column: xRaw.column,
|
||||||
|
});
|
||||||
|
case 'click':
|
||||||
|
return self.vis.emit(eventType, eventPayload);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -377,7 +377,8 @@ export const npStart = {
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
actions: {
|
actions: {
|
||||||
createFiltersFromEvent: Promise.resolve(['yes']),
|
createFiltersFromValueClickAction: Promise.resolve(['yes']),
|
||||||
|
createFiltersFromRangeSelectAction: sinon.fake(),
|
||||||
},
|
},
|
||||||
autocomplete: {
|
autocomplete: {
|
||||||
getProvider: sinon.fake(),
|
getProvider: sinon.fake(),
|
||||||
|
|
|
@ -19,30 +19,34 @@
|
||||||
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import { onBrushEvent, BrushEvent } from './brush_event';
|
import { createFiltersFromRangeSelectAction } from './create_filters_from_range_select';
|
||||||
|
|
||||||
import { IndexPatternsContract } from '../../../public';
|
import { IndexPatternsContract, RangeFilter } from '../../../public';
|
||||||
import { dataPluginMock } from '../../../public/mocks';
|
import { dataPluginMock } from '../../../public/mocks';
|
||||||
import { setIndexPatterns } from '../../../public/services';
|
import { setIndexPatterns } from '../../../public/services';
|
||||||
import { mockDataServices } from '../../../public/search/aggs/test_helpers';
|
import { mockDataServices } from '../../../public/search/aggs/test_helpers';
|
||||||
|
import { TriggerContextMapping } from '../../../../ui_actions/public';
|
||||||
|
|
||||||
describe('brushEvent', () => {
|
describe('brushEvent', () => {
|
||||||
const DAY_IN_MS = 24 * 60 * 60 * 1000;
|
const DAY_IN_MS = 24 * 60 * 60 * 1000;
|
||||||
const JAN_01_2014 = 1388559600000;
|
const JAN_01_2014 = 1388559600000;
|
||||||
let baseEvent: BrushEvent;
|
let baseEvent: TriggerContextMapping['SELECT_RANGE_TRIGGER']['data'];
|
||||||
|
|
||||||
|
const indexPattern = {
|
||||||
|
id: 'indexPatternId',
|
||||||
|
timeFieldName: 'time',
|
||||||
|
fields: {
|
||||||
|
getByName: () => undefined,
|
||||||
|
filter: () => [],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
const aggConfigs = [
|
const aggConfigs = [
|
||||||
{
|
{
|
||||||
params: {
|
params: {
|
||||||
field: {},
|
field: {},
|
||||||
},
|
},
|
||||||
getIndexPattern: () => ({
|
getIndexPattern: () => indexPattern,
|
||||||
timeFieldName: 'time',
|
|
||||||
fields: {
|
|
||||||
getByName: () => undefined,
|
|
||||||
filter: () => [],
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -50,56 +54,37 @@ describe('brushEvent', () => {
|
||||||
mockDataServices();
|
mockDataServices();
|
||||||
setIndexPatterns(({
|
setIndexPatterns(({
|
||||||
...dataPluginMock.createStartContract().indexPatterns,
|
...dataPluginMock.createStartContract().indexPatterns,
|
||||||
get: async () => ({
|
get: async () => indexPattern,
|
||||||
id: 'indexPatternId',
|
|
||||||
timeFieldName: 'time',
|
|
||||||
fields: {
|
|
||||||
getByName: () => undefined,
|
|
||||||
filter: () => [],
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
} as unknown) as IndexPatternsContract);
|
} as unknown) as IndexPatternsContract);
|
||||||
|
|
||||||
baseEvent = {
|
baseEvent = {
|
||||||
data: {
|
column: 0,
|
||||||
ordered: {
|
table: {
|
||||||
date: false,
|
type: 'kibana_datatable',
|
||||||
},
|
columns: [
|
||||||
series: [
|
|
||||||
{
|
{
|
||||||
values: [
|
id: '1',
|
||||||
{
|
name: '1',
|
||||||
xRaw: {
|
meta: {
|
||||||
column: 0,
|
type: 'histogram',
|
||||||
table: {
|
indexPatternId: 'indexPatternId',
|
||||||
columns: [
|
aggConfigParams: aggConfigs[0].params,
|
||||||
{
|
},
|
||||||
id: '1',
|
|
||||||
meta: {
|
|
||||||
type: 'histogram',
|
|
||||||
indexPatternId: 'indexPatternId',
|
|
||||||
aggConfigParams: aggConfigs[0].params,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
rows: [],
|
||||||
},
|
},
|
||||||
range: [],
|
range: [],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should be a function', () => {
|
test('should be a function', () => {
|
||||||
expect(typeof onBrushEvent).toBe('function');
|
expect(typeof createFiltersFromRangeSelectAction).toBe('function');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('ignores event when data.xAxisField not provided', async () => {
|
test('ignores event when data.xAxisField not provided', async () => {
|
||||||
const filter = await onBrushEvent(baseEvent);
|
const filter = await createFiltersFromRangeSelectAction(baseEvent);
|
||||||
expect(filter).toBeUndefined();
|
expect(filter).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('handles an event when the x-axis field is a date field', () => {
|
describe('handles an event when the x-axis field is a date field', () => {
|
||||||
|
@ -109,29 +94,29 @@ describe('brushEvent', () => {
|
||||||
name: 'time',
|
name: 'time',
|
||||||
type: 'date',
|
type: 'date',
|
||||||
};
|
};
|
||||||
baseEvent.data.ordered = { date: true };
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
baseEvent.range = [];
|
baseEvent.range = [];
|
||||||
baseEvent.data.ordered = { date: false };
|
aggConfigs[0].params.field = {};
|
||||||
});
|
});
|
||||||
|
|
||||||
test('by ignoring the event when range spans zero time', async () => {
|
test('by ignoring the event when range spans zero time', async () => {
|
||||||
baseEvent.range = [JAN_01_2014, JAN_01_2014];
|
baseEvent.range = [JAN_01_2014, JAN_01_2014];
|
||||||
const filter = await onBrushEvent(baseEvent);
|
const filter = await createFiltersFromRangeSelectAction(baseEvent);
|
||||||
expect(filter).toBeUndefined();
|
expect(filter).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('by updating the timefilter', async () => {
|
test('by updating the timefilter', async () => {
|
||||||
baseEvent.range = [JAN_01_2014, JAN_01_2014 + DAY_IN_MS];
|
baseEvent.range = [JAN_01_2014, JAN_01_2014 + DAY_IN_MS];
|
||||||
const filter = await onBrushEvent(baseEvent);
|
const filter = await createFiltersFromRangeSelectAction(baseEvent);
|
||||||
expect(filter).toBeDefined();
|
expect(filter).toBeDefined();
|
||||||
|
|
||||||
if (filter) {
|
if (filter.length) {
|
||||||
expect(filter.range.time.gte).toBe(new Date(JAN_01_2014).toISOString());
|
const rangeFilter = filter[0] as RangeFilter;
|
||||||
|
expect(rangeFilter.range.time.gte).toBe(new Date(JAN_01_2014).toISOString());
|
||||||
// Set to a baseline timezone for comparison.
|
// Set to a baseline timezone for comparison.
|
||||||
expect(filter.range.time.lt).toBe(new Date(JAN_01_2014 + DAY_IN_MS).toISOString());
|
expect(rangeFilter.range.time.lt).toBe(new Date(JAN_01_2014 + DAY_IN_MS).toISOString());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -142,26 +127,26 @@ describe('brushEvent', () => {
|
||||||
name: 'anotherTimeField',
|
name: 'anotherTimeField',
|
||||||
type: 'date',
|
type: 'date',
|
||||||
};
|
};
|
||||||
baseEvent.data.ordered = { date: true };
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(() => {
|
afterAll(() => {
|
||||||
baseEvent.range = [];
|
baseEvent.range = [];
|
||||||
baseEvent.data.ordered = { date: false };
|
aggConfigs[0].params.field = {};
|
||||||
});
|
});
|
||||||
|
|
||||||
test('creates a new range filter', async () => {
|
test('creates a new range filter', async () => {
|
||||||
const rangeBegin = JAN_01_2014;
|
const rangeBegin = JAN_01_2014;
|
||||||
const rangeEnd = rangeBegin + DAY_IN_MS;
|
const rangeEnd = rangeBegin + DAY_IN_MS;
|
||||||
baseEvent.range = [rangeBegin, rangeEnd];
|
baseEvent.range = [rangeBegin, rangeEnd];
|
||||||
const filter = await onBrushEvent(baseEvent);
|
const filter = await createFiltersFromRangeSelectAction(baseEvent);
|
||||||
|
|
||||||
expect(filter).toBeDefined();
|
expect(filter).toBeDefined();
|
||||||
|
|
||||||
if (filter) {
|
if (filter.length) {
|
||||||
expect(filter.range.anotherTimeField.gte).toBe(moment(rangeBegin).toISOString());
|
const rangeFilter = filter[0] as RangeFilter;
|
||||||
expect(filter.range.anotherTimeField.lt).toBe(moment(rangeEnd).toISOString());
|
expect(rangeFilter.range.anotherTimeField.gte).toBe(moment(rangeBegin).toISOString());
|
||||||
expect(filter.range.anotherTimeField).toHaveProperty(
|
expect(rangeFilter.range.anotherTimeField.lt).toBe(moment(rangeEnd).toISOString());
|
||||||
|
expect(rangeFilter.range.anotherTimeField).toHaveProperty(
|
||||||
'format',
|
'format',
|
||||||
'strict_date_optional_time'
|
'strict_date_optional_time'
|
||||||
);
|
);
|
||||||
|
@ -184,20 +169,21 @@ describe('brushEvent', () => {
|
||||||
|
|
||||||
test('by ignoring the event when range does not span at least 2 values', async () => {
|
test('by ignoring the event when range does not span at least 2 values', async () => {
|
||||||
baseEvent.range = [1];
|
baseEvent.range = [1];
|
||||||
const filter = await onBrushEvent(baseEvent);
|
const filter = await createFiltersFromRangeSelectAction(baseEvent);
|
||||||
expect(filter).toBeUndefined();
|
expect(filter).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('by creating a new filter', async () => {
|
test('by creating a new filter', async () => {
|
||||||
baseEvent.range = [1, 2, 3, 4];
|
baseEvent.range = [1, 2, 3, 4];
|
||||||
const filter = await onBrushEvent(baseEvent);
|
const filter = await createFiltersFromRangeSelectAction(baseEvent);
|
||||||
|
|
||||||
expect(filter).toBeDefined();
|
expect(filter).toBeDefined();
|
||||||
|
|
||||||
if (filter) {
|
if (filter.length) {
|
||||||
expect(filter.range.numberField.gte).toBe(1);
|
const rangeFilter = filter[0] as RangeFilter;
|
||||||
expect(filter.range.numberField.lt).toBe(4);
|
expect(rangeFilter.range.numberField.gte).toBe(1);
|
||||||
expect(filter.range.numberField).not.toHaveProperty('format');
|
expect(rangeFilter.range.numberField.lt).toBe(4);
|
||||||
|
expect(rangeFilter.range.numberField).not.toHaveProperty('format');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -17,34 +17,18 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { get, last } from 'lodash';
|
import { last } from 'lodash';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { esFilters, IFieldType, RangeFilterParams } from '../../../public';
|
import { esFilters, IFieldType, RangeFilterParams } from '../../../public';
|
||||||
import { getIndexPatterns } from '../../../public/services';
|
import { getIndexPatterns } from '../../../public/services';
|
||||||
import { deserializeAggConfig } from '../../search/expressions/utils';
|
import { deserializeAggConfig } from '../../search/expressions/utils';
|
||||||
|
import { RangeSelectTriggerContext } from '../../../../embeddable/public';
|
||||||
|
|
||||||
export interface BrushEvent {
|
export async function createFiltersFromRangeSelectAction(event: RangeSelectTriggerContext['data']) {
|
||||||
data: {
|
const column: Record<string, any> = event.table.columns[event.column];
|
||||||
ordered: {
|
|
||||||
date: boolean;
|
|
||||||
};
|
|
||||||
series: Array<Record<string, any>>;
|
|
||||||
};
|
|
||||||
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];
|
|
||||||
|
|
||||||
if (!column || !column.meta) {
|
if (!column || !column.meta) {
|
||||||
return;
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const indexPattern = await getIndexPatterns().get(column.meta.indexPatternId);
|
const indexPattern = await getIndexPatterns().get(column.meta.indexPatternId);
|
||||||
|
@ -55,16 +39,18 @@ export async function onBrushEvent(event: BrushEvent) {
|
||||||
const field: IFieldType = aggConfig.params.field;
|
const field: IFieldType = aggConfig.params.field;
|
||||||
|
|
||||||
if (!field || event.range.length <= 1) {
|
if (!field || event.range.length <= 1) {
|
||||||
return;
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const min = event.range[0];
|
const min = event.range[0];
|
||||||
const max = last(event.range);
|
const max = last(event.range);
|
||||||
|
|
||||||
if (min === max) {
|
if (min === max) {
|
||||||
return;
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isDate = field.type === 'date';
|
||||||
|
|
||||||
const range: RangeFilterParams = {
|
const range: RangeFilterParams = {
|
||||||
gte: isDate ? moment(min).toISOString() : min,
|
gte: isDate ? moment(min).toISOString() : min,
|
||||||
lt: isDate ? moment(max).toISOString() : max,
|
lt: isDate ? moment(max).toISOString() : max,
|
||||||
|
@ -74,5 +60,5 @@ export async function onBrushEvent(event: BrushEvent) {
|
||||||
range.format = 'strict_date_optional_time';
|
range.format = 'strict_date_optional_time';
|
||||||
}
|
}
|
||||||
|
|
||||||
return esFilters.buildRangeFilter(field, range, indexPattern);
|
return esFilters.mapAndFlattenFilters([esFilters.buildRangeFilter(field, range, indexPattern)]);
|
||||||
}
|
}
|
|
@ -26,7 +26,8 @@ import {
|
||||||
import { dataPluginMock } from '../../../public/mocks';
|
import { dataPluginMock } from '../../../public/mocks';
|
||||||
import { setIndexPatterns } from '../../../public/services';
|
import { setIndexPatterns } from '../../../public/services';
|
||||||
import { mockDataServices } from '../../../public/search/aggs/test_helpers';
|
import { mockDataServices } from '../../../public/search/aggs/test_helpers';
|
||||||
import { createFiltersFromEvent, EventData } from './create_filters_from_event';
|
import { createFiltersFromValueClickAction } from './create_filters_from_value_click';
|
||||||
|
import { ValueClickTriggerContext } from '../../../../embeddable/public';
|
||||||
|
|
||||||
const mockField = {
|
const mockField = {
|
||||||
name: 'bytes',
|
name: 'bytes',
|
||||||
|
@ -37,8 +38,8 @@ const mockField = {
|
||||||
format: new fieldFormats.BytesFormat({}, (() => {}) as FieldFormatsGetConfigFn),
|
format: new fieldFormats.BytesFormat({}, (() => {}) as FieldFormatsGetConfigFn),
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('createFiltersFromEvent', () => {
|
describe('createFiltersFromValueClick', () => {
|
||||||
let dataPoints: EventData[];
|
let dataPoints: ValueClickTriggerContext['data']['data'];
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
dataPoints = [
|
dataPoints = [
|
||||||
|
@ -86,7 +87,7 @@ describe('createFiltersFromEvent', () => {
|
||||||
|
|
||||||
test('ignores event when value for rows is not provided', async () => {
|
test('ignores event when value for rows is not provided', async () => {
|
||||||
dataPoints[0].table.rows[0]['1-1'] = null;
|
dataPoints[0].table.rows[0]['1-1'] = null;
|
||||||
const filters = await createFiltersFromEvent(dataPoints);
|
const filters = await createFiltersFromValueClickAction({ data: dataPoints });
|
||||||
|
|
||||||
expect(filters.length).toEqual(0);
|
expect(filters.length).toEqual(0);
|
||||||
});
|
});
|
||||||
|
@ -95,14 +96,14 @@ describe('createFiltersFromEvent', () => {
|
||||||
if (dataPoints[0].table.columns[0].meta) {
|
if (dataPoints[0].table.columns[0].meta) {
|
||||||
dataPoints[0].table.columns[0].meta.type = 'terms';
|
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.length).toEqual(1);
|
||||||
expect(filters[0].query.match_phrase.bytes).toEqual('2048');
|
expect(filters[0].query.match_phrase.bytes).toEqual('2048');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('handles an event when aggregations type is not terms', async () => {
|
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);
|
expect(filters.length).toEqual(1);
|
||||||
|
|
|
@ -21,13 +21,7 @@ import { KibanaDatatable } from '../../../../../plugins/expressions/public';
|
||||||
import { deserializeAggConfig } from '../../search/expressions';
|
import { deserializeAggConfig } from '../../search/expressions';
|
||||||
import { esFilters, Filter } from '../../../public';
|
import { esFilters, Filter } from '../../../public';
|
||||||
import { getIndexPatterns } from '../../../public/services';
|
import { getIndexPatterns } from '../../../public/services';
|
||||||
|
import { ValueClickTriggerContext } from '../../../../embeddable/public';
|
||||||
export interface EventData {
|
|
||||||
table: Pick<KibanaDatatable, 'rows' | 'columns'>;
|
|
||||||
column: number;
|
|
||||||
row: number;
|
|
||||||
value: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For terms aggregations on `__other__` buckets, this assembles a list of applicable filter
|
* For terms aggregations on `__other__` buckets, this assembles a list of applicable filter
|
||||||
|
@ -39,7 +33,7 @@ export interface EventData {
|
||||||
* @return {array} - array of terms to filter against
|
* @return {array} - array of terms to filter against
|
||||||
*/
|
*/
|
||||||
const getOtherBucketFilterTerms = (
|
const getOtherBucketFilterTerms = (
|
||||||
table: EventData['table'],
|
table: Pick<KibanaDatatable, 'rows' | 'columns'>,
|
||||||
columnIndex: number,
|
columnIndex: number,
|
||||||
rowIndex: number
|
rowIndex: number
|
||||||
) => {
|
) => {
|
||||||
|
@ -76,7 +70,11 @@ const getOtherBucketFilterTerms = (
|
||||||
* @param {string} cellValue - value of the current cell
|
* @param {string} cellValue - value of the current cell
|
||||||
* @return {Filter[]|undefined} - list of filters to provide to queryFilter.addFilters()
|
* @return {Filter[]|undefined} - list of filters to provide to queryFilter.addFilters()
|
||||||
*/
|
*/
|
||||||
const createFilter = async (table: EventData['table'], columnIndex: number, rowIndex: number) => {
|
const createFilter = async (
|
||||||
|
table: Pick<KibanaDatatable, 'rows' | 'columns'>,
|
||||||
|
columnIndex: number,
|
||||||
|
rowIndex: number
|
||||||
|
) => {
|
||||||
if (!table || !table.columns || !table.columns[columnIndex]) {
|
if (!table || !table.columns || !table.columns[columnIndex]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -113,11 +111,14 @@ const createFilter = async (table: EventData['table'], columnIndex: number, rowI
|
||||||
};
|
};
|
||||||
|
|
||||||
/** @public */
|
/** @public */
|
||||||
export const createFiltersFromEvent = async (dataPoints: EventData[], negate?: boolean) => {
|
export const createFiltersFromValueClickAction = async ({
|
||||||
|
data,
|
||||||
|
negate,
|
||||||
|
}: ValueClickTriggerContext['data']) => {
|
||||||
const filters: Filter[] = [];
|
const filters: Filter[] = [];
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
dataPoints
|
data
|
||||||
.filter(point => point)
|
.filter(point => point)
|
||||||
.map(async val => {
|
.map(async val => {
|
||||||
const { table, column, row } = val;
|
const { table, column, row } = val;
|
||||||
|
@ -133,5 +134,5 @@ export const createFiltersFromEvent = async (dataPoints: EventData[], negate?: b
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
return filters;
|
return esFilters.mapAndFlattenFilters(filters);
|
||||||
};
|
};
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export { ACTION_GLOBAL_APPLY_FILTER, createFilterAction } from './apply_filter_action';
|
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 { createFiltersFromRangeSelectAction } from './filters/create_filters_from_range_select';
|
||||||
export { selectRangeAction } from './select_range_action';
|
export { selectRangeAction } from './select_range_action';
|
||||||
export { valueClickAction } from './value_click_action';
|
export { valueClickAction } from './value_click_action';
|
||||||
|
|
|
@ -23,19 +23,17 @@ import {
|
||||||
IncompatibleActionError,
|
IncompatibleActionError,
|
||||||
ActionByType,
|
ActionByType,
|
||||||
} from '../../../../plugins/ui_actions/public';
|
} from '../../../../plugins/ui_actions/public';
|
||||||
import { onBrushEvent } from './filters/brush_event';
|
import { createFiltersFromRangeSelectAction } from './filters/create_filters_from_range_select';
|
||||||
|
import { RangeSelectTriggerContext } from '../../../embeddable/public';
|
||||||
import { FilterManager, TimefilterContract, esFilters } from '..';
|
import { FilterManager, TimefilterContract, esFilters } from '..';
|
||||||
|
|
||||||
export const ACTION_SELECT_RANGE = 'ACTION_SELECT_RANGE';
|
export const ACTION_SELECT_RANGE = 'ACTION_SELECT_RANGE';
|
||||||
|
|
||||||
export interface SelectRangeActionContext {
|
export type SelectRangeActionContext = RangeSelectTriggerContext;
|
||||||
data: any;
|
|
||||||
timeFieldName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function isCompatible(context: SelectRangeActionContext) {
|
async function isCompatible(context: SelectRangeActionContext) {
|
||||||
try {
|
try {
|
||||||
return Boolean(await onBrushEvent(context.data));
|
return Boolean(await createFiltersFromRangeSelectAction(context.data));
|
||||||
} catch {
|
} catch {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -59,13 +57,7 @@ export function selectRangeAction(
|
||||||
throw new IncompatibleActionError();
|
throw new IncompatibleActionError();
|
||||||
}
|
}
|
||||||
|
|
||||||
const filter = await onBrushEvent(data);
|
const selectedFilters = await createFiltersFromRangeSelectAction(data);
|
||||||
|
|
||||||
if (!filter) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedFilters = esFilters.mapAndFlattenFilters([filter]);
|
|
||||||
|
|
||||||
if (timeFieldName) {
|
if (timeFieldName) {
|
||||||
const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter(
|
const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter(
|
||||||
|
|
|
@ -26,21 +26,17 @@ import {
|
||||||
} from '../../../../plugins/ui_actions/public';
|
} from '../../../../plugins/ui_actions/public';
|
||||||
import { getOverlays, getIndexPatterns } from '../services';
|
import { getOverlays, getIndexPatterns } from '../services';
|
||||||
import { applyFiltersPopover } from '../ui/apply_filters';
|
import { applyFiltersPopover } from '../ui/apply_filters';
|
||||||
import { createFiltersFromEvent } from './filters/create_filters_from_event';
|
import { createFiltersFromValueClickAction } from './filters/create_filters_from_value_click';
|
||||||
|
import { ValueClickTriggerContext } from '../../../embeddable/public';
|
||||||
import { Filter, FilterManager, TimefilterContract, esFilters } from '..';
|
import { Filter, FilterManager, TimefilterContract, esFilters } from '..';
|
||||||
|
|
||||||
export const ACTION_VALUE_CLICK = 'ACTION_VALUE_CLICK';
|
export const ACTION_VALUE_CLICK = 'ACTION_VALUE_CLICK';
|
||||||
|
|
||||||
export interface ValueClickActionContext {
|
export type ValueClickActionContext = ValueClickTriggerContext;
|
||||||
data: any;
|
|
||||||
timeFieldName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function isCompatible(context: ValueClickActionContext) {
|
async function isCompatible(context: ValueClickActionContext) {
|
||||||
try {
|
try {
|
||||||
const filters: Filter[] =
|
const filters: Filter[] = await createFiltersFromValueClickAction(context.data);
|
||||||
(await createFiltersFromEvent(context.data.data || [context.data], context.data.negate)) ||
|
|
||||||
[];
|
|
||||||
return filters.length > 0;
|
return filters.length > 0;
|
||||||
} catch {
|
} catch {
|
||||||
return false;
|
return false;
|
||||||
|
@ -60,17 +56,16 @@ export function valueClickAction(
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
isCompatible,
|
isCompatible,
|
||||||
execute: async ({ timeFieldName, data }: ValueClickActionContext) => {
|
execute: async (context: ValueClickActionContext) => {
|
||||||
if (!(await isCompatible({ timeFieldName, data }))) {
|
if (!(await isCompatible(context))) {
|
||||||
throw new IncompatibleActionError();
|
throw new IncompatibleActionError();
|
||||||
}
|
}
|
||||||
|
|
||||||
const filters: Filter[] =
|
const filters: Filter[] = await createFiltersFromValueClickAction(context.data);
|
||||||
(await createFiltersFromEvent(data.data || [data], data.negate)) || [];
|
|
||||||
|
|
||||||
let selectedFilters: Filter[] = esFilters.mapAndFlattenFilters(filters);
|
let selectedFilters = filters;
|
||||||
|
|
||||||
if (selectedFilters.length > 1) {
|
if (filters.length > 1) {
|
||||||
const indexPatterns = await Promise.all(
|
const indexPatterns = await Promise.all(
|
||||||
filters.map(filter => {
|
filters.map(filter => {
|
||||||
return getIndexPatterns().get(filter.meta.index!);
|
return getIndexPatterns().get(filter.meta.index!);
|
||||||
|
@ -102,9 +97,9 @@ export function valueClickAction(
|
||||||
selectedFilters = await filterSelectionPromise;
|
selectedFilters = await filterSelectionPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeFieldName) {
|
if (context.timeFieldName) {
|
||||||
const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter(
|
const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter(
|
||||||
timeFieldName,
|
context.timeFieldName,
|
||||||
selectedFilters
|
selectedFilters
|
||||||
);
|
);
|
||||||
filterManager.addFilters(restOfFilters);
|
filterManager.addFilters(restOfFilters);
|
||||||
|
|
|
@ -45,7 +45,8 @@ const createStartContract = (): Start => {
|
||||||
const queryStartMock = queryServiceMock.createStartContract();
|
const queryStartMock = queryServiceMock.createStartContract();
|
||||||
return {
|
return {
|
||||||
actions: {
|
actions: {
|
||||||
createFiltersFromEvent: jest.fn().mockResolvedValue(['yes']),
|
createFiltersFromValueClickAction: jest.fn().mockResolvedValue(['yes']),
|
||||||
|
createFiltersFromRangeSelectAction: jest.fn(),
|
||||||
},
|
},
|
||||||
autocomplete: autocompleteMock,
|
autocomplete: autocompleteMock,
|
||||||
search: searchStartMock,
|
search: searchStartMock,
|
||||||
|
|
|
@ -58,7 +58,12 @@ import {
|
||||||
VALUE_CLICK_TRIGGER,
|
VALUE_CLICK_TRIGGER,
|
||||||
APPLY_FILTER_TRIGGER,
|
APPLY_FILTER_TRIGGER,
|
||||||
} from '../../ui_actions/public';
|
} from '../../ui_actions/public';
|
||||||
import { ACTION_GLOBAL_APPLY_FILTER, createFilterAction, createFiltersFromEvent } from './actions';
|
import {
|
||||||
|
ACTION_GLOBAL_APPLY_FILTER,
|
||||||
|
createFilterAction,
|
||||||
|
createFiltersFromValueClickAction,
|
||||||
|
createFiltersFromRangeSelectAction,
|
||||||
|
} from './actions';
|
||||||
import { ApplyGlobalFilterActionContext } from './actions/apply_filter_action';
|
import { ApplyGlobalFilterActionContext } from './actions/apply_filter_action';
|
||||||
import {
|
import {
|
||||||
selectRangeAction,
|
selectRangeAction,
|
||||||
|
@ -162,7 +167,8 @@ export class DataPublicPlugin implements Plugin<DataPublicPluginSetup, DataPubli
|
||||||
|
|
||||||
const dataServices = {
|
const dataServices = {
|
||||||
actions: {
|
actions: {
|
||||||
createFiltersFromEvent,
|
createFiltersFromValueClickAction,
|
||||||
|
createFiltersFromRangeSelectAction,
|
||||||
},
|
},
|
||||||
autocomplete: this.autocomplete.start(),
|
autocomplete: this.autocomplete.start(),
|
||||||
fieldFormats,
|
fieldFormats,
|
||||||
|
|
|
@ -248,7 +248,8 @@ export interface DataPublicPluginSetup {
|
||||||
export interface DataPublicPluginStart {
|
export interface DataPublicPluginStart {
|
||||||
// (undocumented)
|
// (undocumented)
|
||||||
actions: {
|
actions: {
|
||||||
createFiltersFromEvent: typeof createFiltersFromEvent;
|
createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction;
|
||||||
|
createFiltersFromRangeSelectAction: typeof createFiltersFromRangeSelectAction;
|
||||||
};
|
};
|
||||||
// Warning: (ae-forgotten-export) The symbol "AutocompleteStart" needs to be exported by the entry point index.d.ts
|
// Warning: (ae-forgotten-export) The symbol "AutocompleteStart" needs to be exported by the entry point index.d.ts
|
||||||
//
|
//
|
||||||
|
@ -484,7 +485,7 @@ export type FieldFormatId = FIELD_FORMAT_IDS | string;
|
||||||
export const fieldFormats: {
|
export const fieldFormats: {
|
||||||
FieldFormat: typeof FieldFormat;
|
FieldFormat: typeof FieldFormat;
|
||||||
FieldFormatsRegistry: typeof FieldFormatsRegistry;
|
FieldFormatsRegistry: typeof FieldFormatsRegistry;
|
||||||
serialize: (agg: import("./search").AggConfig) => import("../../expressions/common").SerializedFieldFormat<object>;
|
serialize: (agg: import("./search").AggConfig) => import("../../expressions").SerializedFieldFormat<object>;
|
||||||
DEFAULT_CONVERTER_COLOR: {
|
DEFAULT_CONVERTER_COLOR: {
|
||||||
range: string;
|
range: string;
|
||||||
regex: string;
|
regex: string;
|
||||||
|
@ -1892,8 +1893,9 @@ export type TSearchStrategyProvider<T extends TStrategyTypes> = (context: ISearc
|
||||||
// src/plugins/data/public/index.ts:414:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/index.ts:414:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/query/state_sync/connect_to_query_state.ts:33:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/query/state_sync/connect_to_query_state.ts:33:33 - (ae-forgotten-export) The symbol "FilterStateStore" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/query/state_sync/connect_to_query_state.ts:37:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/query/state_sync/connect_to_query_state.ts:37:1 - (ae-forgotten-export) The symbol "QueryStateChange" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromEvent" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/types.ts:52:5 - (ae-forgotten-export) The symbol "createFiltersFromValueClickAction" needs to be exported by the entry point index.d.ts
|
||||||
// src/plugins/data/public/types.ts:60:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts
|
// src/plugins/data/public/types.ts:53:5 - (ae-forgotten-export) The symbol "createFiltersFromRangeSelectAction" needs to be exported by the entry point index.d.ts
|
||||||
|
// src/plugins/data/public/types.ts:61:5 - (ae-forgotten-export) The symbol "IndexPatternSelectProps" needs to be exported by the entry point index.d.ts
|
||||||
|
|
||||||
// (No @packageDocumentation comment for this package)
|
// (No @packageDocumentation comment for this package)
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ import { ExpressionsSetup } from 'src/plugins/expressions/public';
|
||||||
import { UiActionsSetup, UiActionsStart } from 'src/plugins/ui_actions/public';
|
import { UiActionsSetup, UiActionsStart } from 'src/plugins/ui_actions/public';
|
||||||
import { AutocompleteSetup, AutocompleteStart } from './autocomplete';
|
import { AutocompleteSetup, AutocompleteStart } from './autocomplete';
|
||||||
import { FieldFormatsSetup, FieldFormatsStart } from './field_formats';
|
import { FieldFormatsSetup, FieldFormatsStart } from './field_formats';
|
||||||
import { createFiltersFromEvent } from './actions';
|
import { createFiltersFromRangeSelectAction, createFiltersFromValueClickAction } from './actions';
|
||||||
import { ISearchSetup, ISearchStart } from './search';
|
import { ISearchSetup, ISearchStart } from './search';
|
||||||
import { QuerySetup, QueryStart } from './query';
|
import { QuerySetup, QueryStart } from './query';
|
||||||
import { IndexPatternSelectProps } from './ui/index_pattern_select';
|
import { IndexPatternSelectProps } from './ui/index_pattern_select';
|
||||||
|
@ -49,7 +49,8 @@ export interface DataPublicPluginSetup {
|
||||||
|
|
||||||
export interface DataPublicPluginStart {
|
export interface DataPublicPluginStart {
|
||||||
actions: {
|
actions: {
|
||||||
createFiltersFromEvent: typeof createFiltersFromEvent;
|
createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction;
|
||||||
|
createFiltersFromRangeSelectAction: typeof createFiltersFromRangeSelectAction;
|
||||||
};
|
};
|
||||||
autocomplete: AutocompleteStart;
|
autocomplete: AutocompleteStart;
|
||||||
indexPatterns: IndexPatternsContract;
|
indexPatterns: IndexPatternsContract;
|
||||||
|
|
|
@ -283,7 +283,7 @@ export interface FieldFormatConfig {
|
||||||
export const fieldFormats: {
|
export const fieldFormats: {
|
||||||
FieldFormatsRegistry: typeof FieldFormatsRegistry;
|
FieldFormatsRegistry: typeof FieldFormatsRegistry;
|
||||||
FieldFormat: typeof FieldFormat;
|
FieldFormat: typeof FieldFormat;
|
||||||
serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions/common").SerializedFieldFormat<object>;
|
serializeFieldFormat: (agg: import("../public/search").AggConfig) => import("../../expressions").SerializedFieldFormat<object>;
|
||||||
BoolFormat: typeof BoolFormat;
|
BoolFormat: typeof BoolFormat;
|
||||||
BytesFormat: typeof BytesFormat;
|
BytesFormat: typeof BytesFormat;
|
||||||
ColorFormat: typeof ColorFormat;
|
ColorFormat: typeof ColorFormat;
|
||||||
|
|
|
@ -47,7 +47,8 @@ export {
|
||||||
EmbeddableOutput,
|
EmbeddableOutput,
|
||||||
EmbeddablePanel,
|
EmbeddablePanel,
|
||||||
EmbeddableRoot,
|
EmbeddableRoot,
|
||||||
EmbeddableVisTriggerContext,
|
ValueClickTriggerContext,
|
||||||
|
RangeSelectTriggerContext,
|
||||||
ErrorEmbeddable,
|
ErrorEmbeddable,
|
||||||
IContainer,
|
IContainer,
|
||||||
IEmbeddable,
|
IEmbeddable,
|
||||||
|
|
|
@ -18,18 +18,34 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Trigger } from '../../../../ui_actions/public';
|
import { Trigger } from '../../../../ui_actions/public';
|
||||||
|
import { KibanaDatatable } from '../../../../expressions';
|
||||||
import { IEmbeddable } from '..';
|
import { IEmbeddable } from '..';
|
||||||
|
|
||||||
export interface EmbeddableContext {
|
export interface EmbeddableContext {
|
||||||
embeddable: IEmbeddable;
|
embeddable: IEmbeddable;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EmbeddableVisTriggerContext {
|
export interface ValueClickTriggerContext {
|
||||||
embeddable?: IEmbeddable;
|
embeddable?: IEmbeddable;
|
||||||
timeFieldName?: string;
|
timeFieldName?: string;
|
||||||
data: {
|
data: {
|
||||||
e?: MouseEvent;
|
data: Array<{
|
||||||
data: unknown;
|
table: Pick<KibanaDatatable, 'rows' | 'columns'>;
|
||||||
|
column: number;
|
||||||
|
row: number;
|
||||||
|
value: any;
|
||||||
|
}>;
|
||||||
|
negate?: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RangeSelectTriggerContext {
|
||||||
|
embeddable?: IEmbeddable;
|
||||||
|
timeFieldName?: string;
|
||||||
|
data: {
|
||||||
|
table: KibanaDatatable;
|
||||||
|
column: number;
|
||||||
|
range: number[];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,9 +19,10 @@
|
||||||
|
|
||||||
import { ActionByType } from './actions/action';
|
import { ActionByType } from './actions/action';
|
||||||
import { TriggerInternal } from './triggers/trigger_internal';
|
import { TriggerInternal } from './triggers/trigger_internal';
|
||||||
import { EmbeddableVisTriggerContext, IEmbeddable } from '../../embeddable/public';
|
|
||||||
import { Filter } from '../../data/public';
|
import { Filter } from '../../data/public';
|
||||||
import { SELECT_RANGE_TRIGGER, VALUE_CLICK_TRIGGER, APPLY_FILTER_TRIGGER } from './triggers';
|
import { SELECT_RANGE_TRIGGER, VALUE_CLICK_TRIGGER, APPLY_FILTER_TRIGGER } from './triggers';
|
||||||
|
import { IEmbeddable } from '../../embeddable/public';
|
||||||
|
import { RangeSelectTriggerContext, ValueClickTriggerContext } from '../../embeddable/public';
|
||||||
|
|
||||||
export type TriggerRegistry = Map<TriggerId, TriggerInternal<any>>;
|
export type TriggerRegistry = Map<TriggerId, TriggerInternal<any>>;
|
||||||
export type ActionRegistry = Map<string, ActionByType<any>>;
|
export type ActionRegistry = Map<string, ActionByType<any>>;
|
||||||
|
@ -36,8 +37,8 @@ export type TriggerContext = BaseContext;
|
||||||
|
|
||||||
export interface TriggerContextMapping {
|
export interface TriggerContextMapping {
|
||||||
[DEFAULT_TRIGGER]: TriggerContext;
|
[DEFAULT_TRIGGER]: TriggerContext;
|
||||||
[SELECT_RANGE_TRIGGER]: EmbeddableVisTriggerContext;
|
[SELECT_RANGE_TRIGGER]: RangeSelectTriggerContext;
|
||||||
[VALUE_CLICK_TRIGGER]: EmbeddableVisTriggerContext;
|
[VALUE_CLICK_TRIGGER]: ValueClickTriggerContext;
|
||||||
[APPLY_FILTER_TRIGGER]: {
|
[APPLY_FILTER_TRIGGER]: {
|
||||||
embeddable: IEmbeddable;
|
embeddable: IEmbeddable;
|
||||||
filters: Filter[];
|
filters: Filter[];
|
||||||
|
|
|
@ -33,7 +33,6 @@ import {
|
||||||
EmbeddableInput,
|
EmbeddableInput,
|
||||||
EmbeddableOutput,
|
EmbeddableOutput,
|
||||||
Embeddable,
|
Embeddable,
|
||||||
EmbeddableVisTriggerContext,
|
|
||||||
IContainer,
|
IContainer,
|
||||||
} from '../../../../plugins/embeddable/public';
|
} from '../../../../plugins/embeddable/public';
|
||||||
import { dispatchRenderComplete } from '../../../../plugins/kibana_utils/public';
|
import { dispatchRenderComplete } from '../../../../plugins/kibana_utils/public';
|
||||||
|
@ -261,7 +260,7 @@ export class VisualizeEmbeddable extends Embeddable<VisualizeInput, VisualizeOut
|
||||||
if (!this.input.disableTriggers) {
|
if (!this.input.disableTriggers) {
|
||||||
const triggerId =
|
const triggerId =
|
||||||
event.name === 'brush' ? VIS_EVENT_TO_TRIGGER.brush : VIS_EVENT_TO_TRIGGER.filter;
|
event.name === 'brush' ? VIS_EVENT_TO_TRIGGER.brush : VIS_EVENT_TO_TRIGGER.filter;
|
||||||
const context: EmbeddableVisTriggerContext = {
|
const context = {
|
||||||
embeddable: this,
|
embeddable: this,
|
||||||
timeFieldName: this.vis.data.indexPattern!.timeFieldName!,
|
timeFieldName: this.vis.data.indexPattern!.timeFieldName!,
|
||||||
data: event.data,
|
data: event.data,
|
||||||
|
|
|
@ -69,7 +69,15 @@ export class ExprVis extends EventEmitter {
|
||||||
events: {
|
events: {
|
||||||
filter: (data: any) => {
|
filter: (data: any) => {
|
||||||
if (!this.eventsSubject) return;
|
if (!this.eventsSubject) return;
|
||||||
this.eventsSubject.next({ name: 'filterBucket', data });
|
this.eventsSubject.next({
|
||||||
|
name: 'filterBucket',
|
||||||
|
data: data.data
|
||||||
|
? {
|
||||||
|
data: data.data,
|
||||||
|
negate: data.negate,
|
||||||
|
}
|
||||||
|
: { data: [data] },
|
||||||
|
});
|
||||||
},
|
},
|
||||||
brush: (data: any) => {
|
brush: (data: any) => {
|
||||||
if (!this.eventsSubject) return;
|
if (!this.eventsSubject) return;
|
||||||
|
|
|
@ -28,7 +28,7 @@ import {
|
||||||
import { EuiIcon, EuiText, IconType, EuiSpacer } from '@elastic/eui';
|
import { EuiIcon, EuiText, IconType, EuiSpacer } from '@elastic/eui';
|
||||||
import { FormattedMessage } from '@kbn/i18n/react';
|
import { FormattedMessage } from '@kbn/i18n/react';
|
||||||
import { i18n } from '@kbn/i18n';
|
import { i18n } from '@kbn/i18n';
|
||||||
import { EmbeddableVisTriggerContext } from '../../../../../src/plugins/embeddable/public';
|
import { ValueClickTriggerContext } from '../../../../../src/plugins/embeddable/public';
|
||||||
import { VIS_EVENT_TO_TRIGGER } from '../../../../../src/plugins/visualizations/public';
|
import { VIS_EVENT_TO_TRIGGER } from '../../../../../src/plugins/visualizations/public';
|
||||||
import { LensMultiTable, FormatFactory } from '../types';
|
import { LensMultiTable, FormatFactory } from '../types';
|
||||||
import { XYArgs, SeriesType, visualizationTypes } from './types';
|
import { XYArgs, SeriesType, visualizationTypes } from './types';
|
||||||
|
@ -277,7 +277,7 @@ export function XYChart({
|
||||||
|
|
||||||
const timeFieldName = xDomain && xAxisFieldName;
|
const timeFieldName = xDomain && xAxisFieldName;
|
||||||
|
|
||||||
const context: EmbeddableVisTriggerContext = {
|
const context: ValueClickTriggerContext = {
|
||||||
data: {
|
data: {
|
||||||
data: points.map(point => ({
|
data: points.map(point => ({
|
||||||
row: point.row,
|
row: point.row,
|
||||||
|
|
Loading…
Reference in a new issue