refactor action filter creation utils (#62969)

This commit is contained in:
Peter Pisljar 2020-04-22 10:41:58 +02:00 committed by GitHub
parent 2f794e6c42
commit 222fdc5029
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 184 additions and 172 deletions

View file

@ -8,6 +8,7 @@
```typescript
actions: {
createFiltersFromEvent: typeof createFiltersFromEvent;
createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction;
createFiltersFromRangeSelectAction: typeof createFiltersFromRangeSelectAction;
};
```

View file

@ -14,7 +14,7 @@ export interface DataPublicPluginStart
| 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> | |
| [fieldFormats](./kibana-plugin-plugins-data-public.datapublicpluginstart.fieldformats.md) | <code>FieldFormatsStart</code> | |
| [indexPatterns](./kibana-plugin-plugins-data-public.datapublicpluginstart.indexpatterns.md) | <code>IndexPatternsContract</code> | |

View file

@ -10,7 +10,7 @@
fieldFormats: {
FieldFormat: typeof FieldFormat;
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: {
range: string;
regex: string;

View file

@ -10,7 +10,7 @@
fieldFormats: {
FieldFormatsRegistry: typeof FieldFormatsRegistry;
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;
BytesFormat: typeof BytesFormat;
ColorFormat: typeof ColorFormat;

View file

@ -108,6 +108,6 @@ export class VisTypeVislibPlugin implements Plugin<void, void> {
public start(core: CoreStart, { data }: VisTypeVislibPluginStartDependencies) {
setFormatService(data.fieldFormats);
setDataActions({ createFiltersFromEvent: data.actions.createFiltersFromEvent });
setDataActions(data.actions);
}
}

View file

@ -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 = {

View file

@ -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);
};

View file

@ -83,10 +83,21 @@ export class Handler {
// memoize so that the same function is returned every time,
// allowing us to remove/re-add the same function
this.getProxyHandler = _.memoize(function(event) {
this.getProxyHandler = _.memoize(function(eventType) {
const self = this;
return function(e) {
self.vis.emit(event, e);
return function(eventPayload) {
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);
}
};
});

View file

@ -377,7 +377,8 @@ export const npStart = {
},
data: {
actions: {
createFiltersFromEvent: Promise.resolve(['yes']),
createFiltersFromValueClickAction: Promise.resolve(['yes']),
createFiltersFromRangeSelectAction: sinon.fake(),
},
autocomplete: {
getProvider: sinon.fake(),

View file

@ -19,30 +19,34 @@
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 { setIndexPatterns } from '../../../public/services';
import { mockDataServices } from '../../../public/search/aggs/test_helpers';
import { TriggerContextMapping } from '../../../../ui_actions/public';
describe('brushEvent', () => {
const DAY_IN_MS = 24 * 60 * 60 * 1000;
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 = [
{
params: {
field: {},
},
getIndexPattern: () => ({
timeFieldName: 'time',
fields: {
getByName: () => undefined,
filter: () => [],
},
}),
getIndexPattern: () => indexPattern,
},
];
@ -50,56 +54,37 @@ describe('brushEvent', () => {
mockDataServices();
setIndexPatterns(({
...dataPluginMock.createStartContract().indexPatterns,
get: async () => ({
id: 'indexPatternId',
timeFieldName: 'time',
fields: {
getByName: () => undefined,
filter: () => [],
},
}),
get: async () => indexPattern,
} 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);
expect(filter).toBeUndefined();
const filter = await createFiltersFromRangeSelectAction(baseEvent);
expect(filter).toEqual([]);
});
describe('handles an event when the x-axis field is a date field', () => {
@ -109,29 +94,29 @@ describe('brushEvent', () => {
name: 'time',
type: 'date',
};
baseEvent.data.ordered = { date: true };
});
afterAll(() => {
baseEvent.range = [];
baseEvent.data.ordered = { date: false };
aggConfigs[0].params.field = {};
});
test('by ignoring the event when range spans zero time', async () => {
baseEvent.range = [JAN_01_2014, JAN_01_2014];
const filter = await onBrushEvent(baseEvent);
expect(filter).toBeUndefined();
const filter = await createFiltersFromRangeSelectAction(baseEvent);
expect(filter).toEqual([]);
});
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) {
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.
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',
type: 'date',
};
baseEvent.data.ordered = { date: true };
});
afterAll(() => {
baseEvent.range = [];
baseEvent.data.ordered = { date: false };
aggConfigs[0].params.field = {};
});
test('creates a new range filter', async () => {
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) {
const rangeFilter = filter[0] as RangeFilter;
expect(rangeFilter.range.anotherTimeField.gte).toBe(moment(rangeBegin).toISOString());
expect(rangeFilter.range.anotherTimeField.lt).toBe(moment(rangeEnd).toISOString());
expect(rangeFilter.range.anotherTimeField).toHaveProperty(
'format',
'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 () => {
baseEvent.range = [1];
const filter = await onBrushEvent(baseEvent);
expect(filter).toBeUndefined();
const filter = await createFiltersFromRangeSelectAction(baseEvent);
expect(filter).toEqual([]);
});
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) {
const rangeFilter = filter[0] as RangeFilter;
expect(rangeFilter.range.numberField.gte).toBe(1);
expect(rangeFilter.range.numberField.lt).toBe(4);
expect(rangeFilter.range.numberField).not.toHaveProperty('format');
}
});
});

View file

@ -17,34 +17,18 @@
* 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 { RangeSelectTriggerContext } from '../../../../embeddable/public';
export interface BrushEvent {
data: {
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];
export async function createFiltersFromRangeSelectAction(event: RangeSelectTriggerContext['data']) {
const column: Record<string, any> = event.table.columns[event.column];
if (!column || !column.meta) {
return;
return [];
}
const indexPattern = await getIndexPatterns().get(column.meta.indexPatternId);
@ -55,16 +39,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,
@ -74,5 +60,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)]);
}

View file

@ -26,7 +26,8 @@ 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 } from './create_filters_from_value_click';
import { ValueClickTriggerContext } from '../../../../embeddable/public';
const mockField = {
name: 'bytes',
@ -37,8 +38,8 @@ const mockField = {
format: new fieldFormats.BytesFormat({}, (() => {}) as FieldFormatsGetConfigFn),
};
describe('createFiltersFromEvent', () => {
let dataPoints: EventData[];
describe('createFiltersFromValueClick', () => {
let dataPoints: ValueClickTriggerContext['data']['data'];
beforeEach(() => {
dataPoints = [
@ -86,7 +87,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);
});
@ -95,14 +96,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);

View file

@ -21,13 +21,7 @@ import { KibanaDatatable } from '../../../../../plugins/expressions/public';
import { deserializeAggConfig } from '../../search/expressions';
import { esFilters, Filter } from '../../../public';
import { getIndexPatterns } from '../../../public/services';
export interface EventData {
table: Pick<KibanaDatatable, 'rows' | 'columns'>;
column: number;
row: number;
value: any;
}
import { ValueClickTriggerContext } from '../../../../embeddable/public';
/**
* 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
*/
const getOtherBucketFilterTerms = (
table: EventData['table'],
table: Pick<KibanaDatatable, 'rows' | 'columns'>,
columnIndex: number,
rowIndex: number
) => {
@ -76,7 +70,11 @@ const getOtherBucketFilterTerms = (
* @param {string} cellValue - value of the current cell
* @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]) {
return;
}
@ -113,11 +111,14 @@ const createFilter = async (table: EventData['table'], columnIndex: number, rowI
};
/** @public */
export const createFiltersFromEvent = async (dataPoints: EventData[], negate?: boolean) => {
export const createFiltersFromValueClickAction = async ({
data,
negate,
}: ValueClickTriggerContext['data']) => {
const filters: Filter[] = [];
await Promise.all(
dataPoints
data
.filter(point => point)
.map(async val => {
const { table, column, row } = val;
@ -133,5 +134,5 @@ export const createFiltersFromEvent = async (dataPoints: EventData[], negate?: b
})
);
return filters;
return esFilters.mapAndFlattenFilters(filters);
};

View file

@ -18,6 +18,7 @@
*/
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 { valueClickAction } from './value_click_action';

View file

@ -23,19 +23,17 @@ import {
IncompatibleActionError,
ActionByType,
} 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 '..';
export const ACTION_SELECT_RANGE = 'ACTION_SELECT_RANGE';
export interface SelectRangeActionContext {
data: any;
timeFieldName: string;
}
export type SelectRangeActionContext = RangeSelectTriggerContext;
async function isCompatible(context: SelectRangeActionContext) {
try {
return Boolean(await onBrushEvent(context.data));
return Boolean(await createFiltersFromRangeSelectAction(context.data));
} catch {
return false;
}
@ -59,13 +57,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(

View file

@ -26,21 +26,17 @@ import {
} from '../../../../plugins/ui_actions/public';
import { getOverlays, getIndexPatterns } from '../services';
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 '..';
export const ACTION_VALUE_CLICK = 'ACTION_VALUE_CLICK';
export interface ValueClickActionContext {
data: any;
timeFieldName: string;
}
export type ValueClickActionContext = ValueClickTriggerContext;
async function isCompatible(context: ValueClickActionContext) {
try {
const filters: Filter[] =
(await createFiltersFromEvent(context.data.data || [context.data], context.data.negate)) ||
[];
const filters: Filter[] = await createFiltersFromValueClickAction(context.data);
return filters.length > 0;
} catch {
return false;
@ -60,17 +56,16 @@ export function valueClickAction(
});
},
isCompatible,
execute: async ({ timeFieldName, data }: ValueClickActionContext) => {
if (!(await isCompatible({ timeFieldName, data }))) {
execute: async (context: ValueClickActionContext) => {
if (!(await isCompatible(context))) {
throw new IncompatibleActionError();
}
const filters: Filter[] =
(await createFiltersFromEvent(data.data || [data], data.negate)) || [];
const filters: Filter[] = await createFiltersFromValueClickAction(context.data);
let selectedFilters: Filter[] = esFilters.mapAndFlattenFilters(filters);
let selectedFilters = filters;
if (selectedFilters.length > 1) {
if (filters.length > 1) {
const indexPatterns = await Promise.all(
filters.map(filter => {
return getIndexPatterns().get(filter.meta.index!);
@ -102,9 +97,9 @@ export function valueClickAction(
selectedFilters = await filterSelectionPromise;
}
if (timeFieldName) {
if (context.timeFieldName) {
const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter(
timeFieldName,
context.timeFieldName,
selectedFilters
);
filterManager.addFilters(restOfFilters);

View file

@ -45,7 +45,8 @@ const createStartContract = (): Start => {
const queryStartMock = queryServiceMock.createStartContract();
return {
actions: {
createFiltersFromEvent: jest.fn().mockResolvedValue(['yes']),
createFiltersFromValueClickAction: jest.fn().mockResolvedValue(['yes']),
createFiltersFromRangeSelectAction: jest.fn(),
},
autocomplete: autocompleteMock,
search: searchStartMock,

View file

@ -58,7 +58,12 @@ import {
VALUE_CLICK_TRIGGER,
APPLY_FILTER_TRIGGER,
} 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 {
selectRangeAction,
@ -162,7 +167,8 @@ export class DataPublicPlugin implements Plugin<DataPublicPluginSetup, DataPubli
const dataServices = {
actions: {
createFiltersFromEvent,
createFiltersFromValueClickAction,
createFiltersFromRangeSelectAction,
},
autocomplete: this.autocomplete.start(),
fieldFormats,

View file

@ -248,7 +248,8 @@ export interface DataPublicPluginSetup {
export interface DataPublicPluginStart {
// (undocumented)
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
//
@ -484,7 +485,7 @@ export type FieldFormatId = FIELD_FORMAT_IDS | string;
export const fieldFormats: {
FieldFormat: typeof FieldFormat;
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: {
range: 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/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/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: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: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: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)

View file

@ -24,7 +24,7 @@ import { ExpressionsSetup } from 'src/plugins/expressions/public';
import { UiActionsSetup, UiActionsStart } from 'src/plugins/ui_actions/public';
import { AutocompleteSetup, AutocompleteStart } from './autocomplete';
import { FieldFormatsSetup, FieldFormatsStart } from './field_formats';
import { createFiltersFromEvent } from './actions';
import { createFiltersFromRangeSelectAction, createFiltersFromValueClickAction } from './actions';
import { ISearchSetup, ISearchStart } from './search';
import { QuerySetup, QueryStart } from './query';
import { IndexPatternSelectProps } from './ui/index_pattern_select';
@ -49,7 +49,8 @@ export interface DataPublicPluginSetup {
export interface DataPublicPluginStart {
actions: {
createFiltersFromEvent: typeof createFiltersFromEvent;
createFiltersFromValueClickAction: typeof createFiltersFromValueClickAction;
createFiltersFromRangeSelectAction: typeof createFiltersFromRangeSelectAction;
};
autocomplete: AutocompleteStart;
indexPatterns: IndexPatternsContract;

View file

@ -283,7 +283,7 @@ export interface FieldFormatConfig {
export const fieldFormats: {
FieldFormatsRegistry: typeof FieldFormatsRegistry;
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;
BytesFormat: typeof BytesFormat;
ColorFormat: typeof ColorFormat;

View file

@ -47,7 +47,8 @@ export {
EmbeddableOutput,
EmbeddablePanel,
EmbeddableRoot,
EmbeddableVisTriggerContext,
ValueClickTriggerContext,
RangeSelectTriggerContext,
ErrorEmbeddable,
IContainer,
IEmbeddable,

View file

@ -18,18 +18,34 @@
*/
import { Trigger } from '../../../../ui_actions/public';
import { KibanaDatatable } from '../../../../expressions';
import { IEmbeddable } from '..';
export interface EmbeddableContext {
embeddable: IEmbeddable;
}
export interface EmbeddableVisTriggerContext {
export interface ValueClickTriggerContext {
embeddable?: IEmbeddable;
timeFieldName?: string;
data: {
e?: MouseEvent;
data: unknown;
data: Array<{
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[];
};
}

View file

@ -19,9 +19,10 @@
import { ActionByType } from './actions/action';
import { TriggerInternal } from './triggers/trigger_internal';
import { EmbeddableVisTriggerContext, IEmbeddable } from '../../embeddable/public';
import { Filter } from '../../data/public';
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 ActionRegistry = Map<string, ActionByType<any>>;
@ -36,8 +37,8 @@ export type TriggerContext = BaseContext;
export interface TriggerContextMapping {
[DEFAULT_TRIGGER]: TriggerContext;
[SELECT_RANGE_TRIGGER]: EmbeddableVisTriggerContext;
[VALUE_CLICK_TRIGGER]: EmbeddableVisTriggerContext;
[SELECT_RANGE_TRIGGER]: RangeSelectTriggerContext;
[VALUE_CLICK_TRIGGER]: ValueClickTriggerContext;
[APPLY_FILTER_TRIGGER]: {
embeddable: IEmbeddable;
filters: Filter[];

View file

@ -33,7 +33,6 @@ import {
EmbeddableInput,
EmbeddableOutput,
Embeddable,
EmbeddableVisTriggerContext,
IContainer,
} from '../../../../plugins/embeddable/public';
import { dispatchRenderComplete } from '../../../../plugins/kibana_utils/public';
@ -261,7 +260,7 @@ export class VisualizeEmbeddable extends Embeddable<VisualizeInput, VisualizeOut
if (!this.input.disableTriggers) {
const triggerId =
event.name === 'brush' ? VIS_EVENT_TO_TRIGGER.brush : VIS_EVENT_TO_TRIGGER.filter;
const context: EmbeddableVisTriggerContext = {
const context = {
embeddable: this,
timeFieldName: this.vis.data.indexPattern!.timeFieldName!,
data: event.data,

View file

@ -69,7 +69,15 @@ export class ExprVis extends EventEmitter {
events: {
filter: (data: any) => {
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) => {
if (!this.eventsSubject) return;

View file

@ -28,7 +28,7 @@ import {
import { EuiIcon, EuiText, IconType, EuiSpacer } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
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 { LensMultiTable, FormatFactory } from '../types';
import { XYArgs, SeriesType, visualizationTypes } from './types';
@ -277,7 +277,7 @@ export function XYChart({
const timeFieldName = xDomain && xAxisFieldName;
const context: EmbeddableVisTriggerContext = {
const context: ValueClickTriggerContext = {
data: {
data: points.map(point => ({
row: point.row,