From 04318ce90cdd493da08c5f2cf3f289ba4549bfe4 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 2 Jul 2020 16:05:44 +0200 Subject: [PATCH 1/9] auto actions and nested triggers --- .../public/actions/actions.tsx | 16 +-- .../ui_actions_explorer/public/plugin.tsx | 8 +- .../public/actions/apply_filter_action.ts | 2 + .../emit_apply_filter_trigger_action.ts | 74 +++++++++++ src/plugins/data/public/actions/index.ts | 15 ++- .../public/actions/select_range_action.ts | 77 ----------- .../data/public/actions/value_click_action.ts | 115 ----------------- src/plugins/data/public/index.ts | 6 + src/plugins/data/public/plugin.ts | 45 +++---- .../public/lib/panel/embeddable_panel.tsx | 3 +- .../ui_actions/public/actions/action.ts | 12 ++ .../public/actions/action_internal.ts | 5 + .../build_eui_context_menu_panels.tsx | 20 ++- .../service/ui_actions_execution_service.ts | 121 ++++++++++++++++++ .../public/service/ui_actions_service.ts | 2 + .../tests/execute_trigger_actions.test.ts | 15 ++- .../public/triggers/trigger_internal.ts | 39 ++---- src/plugins/ui_actions/public/types.ts | 10 +- 18 files changed, 299 insertions(+), 286 deletions(-) create mode 100644 src/plugins/data/public/actions/emit_apply_filter_trigger_action.ts delete mode 100644 src/plugins/data/public/actions/select_range_action.ts delete mode 100644 src/plugins/data/public/actions/value_click_action.ts create mode 100644 src/plugins/ui_actions/public/service/ui_actions_execution_service.ts diff --git a/examples/ui_actions_explorer/public/actions/actions.tsx b/examples/ui_actions_explorer/public/actions/actions.tsx index 4ef8d5bf4d9c6..6d83362e998bc 100644 --- a/examples/ui_actions_explorer/public/actions/actions.tsx +++ b/examples/ui_actions_explorer/public/actions/actions.tsx @@ -31,7 +31,7 @@ export const ACTION_VIEW_IN_MAPS = 'ACTION_VIEW_IN_MAPS'; export const ACTION_TRAVEL_GUIDE = 'ACTION_TRAVEL_GUIDE'; export const ACTION_CALL_PHONE_NUMBER = 'ACTION_CALL_PHONE_NUMBER'; export const ACTION_EDIT_USER = 'ACTION_EDIT_USER'; -export const ACTION_PHONE_USER = 'ACTION_PHONE_USER'; +export const ACTION_TRIGGER_PHONE_USER = 'ACTION_TRIGGER_PHONE_USER'; export const ACTION_SHOWCASE_PLUGGABILITY = 'ACTION_SHOWCASE_PLUGGABILITY'; export const showcasePluggability = createAction({ @@ -120,19 +120,13 @@ export interface UserContext { update: (user: User) => void; } -export const createPhoneUserAction = (getUiActionsApi: () => Promise) => - createAction({ - type: ACTION_PHONE_USER, +export const createTriggerPhoneTriggerAction = (getUiActionsApi: () => Promise) => + createAction({ + type: ACTION_TRIGGER_PHONE_USER, getDisplayName: () => 'Call phone number', + shouldAutoExecute: async () => true, isCompatible: async ({ user }) => user.phone !== undefined, execute: async ({ user }) => { - // One option - execute the more specific action directly. - // makePhoneCallAction.execute({ phone: user.phone }); - - // Another option - emit the trigger and automatically get *all* the actions attached - // to the phone number trigger. - // TODO: we need to figure out the best way to handle these nested actions however, since - // we don't want multiple context menu's to pop up. if (user.phone !== undefined) { (await getUiActionsApi()).executeTriggerActions(PHONE_TRIGGER, { phone: user.phone }); } diff --git a/examples/ui_actions_explorer/public/plugin.tsx b/examples/ui_actions_explorer/public/plugin.tsx index 670138b43b9c4..b28e5e7a9f692 100644 --- a/examples/ui_actions_explorer/public/plugin.tsx +++ b/examples/ui_actions_explorer/public/plugin.tsx @@ -23,7 +23,6 @@ import { PHONE_TRIGGER, USER_TRIGGER, COUNTRY_TRIGGER, - createPhoneUserAction, lookUpWeatherAction, viewInMapsAction, createEditUserAction, @@ -37,7 +36,8 @@ import { ACTION_CALL_PHONE_NUMBER, ACTION_TRAVEL_GUIDE, ACTION_VIEW_IN_MAPS, - ACTION_PHONE_USER, + ACTION_TRIGGER_PHONE_USER, + createTriggerPhoneTriggerAction, } from './actions/actions'; import { DeveloperExamplesSetup } from '../../developer_examples/public'; import image from './ui_actions.png'; @@ -64,7 +64,7 @@ declare module '../../../src/plugins/ui_actions/public' { [ACTION_CALL_PHONE_NUMBER]: PhoneContext; [ACTION_TRAVEL_GUIDE]: CountryContext; [ACTION_VIEW_IN_MAPS]: CountryContext; - [ACTION_PHONE_USER]: UserContext; + [ACTION_TRIGGER_PHONE_USER]: UserContext; } } @@ -84,7 +84,7 @@ export class UiActionsExplorerPlugin implements Plugin (await startServices)[1].uiActions) + createTriggerPhoneTriggerAction(async () => (await startServices)[1].uiActions) ); deps.uiActions.addTriggerAction( USER_TRIGGER, diff --git a/src/plugins/data/public/actions/apply_filter_action.ts b/src/plugins/data/public/actions/apply_filter_action.ts index 7e8ed5ec8fb22..a2621e6ce8802 100644 --- a/src/plugins/data/public/actions/apply_filter_action.ts +++ b/src/plugins/data/public/actions/apply_filter_action.ts @@ -22,6 +22,7 @@ import { toMountPoint } from '../../../kibana_react/public'; import { ActionByType, createAction, IncompatibleActionError } from '../../../ui_actions/public'; import { getOverlays, getIndexPatterns } from '../services'; import { applyFiltersPopover } from '../ui/apply_filters'; +import type { IEmbeddable } from '../../../embeddable/public'; import { Filter, FilterManager, TimefilterContract, esFilters } from '..'; export const ACTION_GLOBAL_APPLY_FILTER = 'ACTION_GLOBAL_APPLY_FILTER'; @@ -29,6 +30,7 @@ export const ACTION_GLOBAL_APPLY_FILTER = 'ACTION_GLOBAL_APPLY_FILTER'; export interface ApplyGlobalFilterActionContext { filters: Filter[]; timeFieldName?: string; + embeddable?: IEmbeddable; } async function isCompatible(context: ApplyGlobalFilterActionContext) { diff --git a/src/plugins/data/public/actions/emit_apply_filter_trigger_action.ts b/src/plugins/data/public/actions/emit_apply_filter_trigger_action.ts new file mode 100644 index 0000000000000..8f4cba25be2a6 --- /dev/null +++ b/src/plugins/data/public/actions/emit_apply_filter_trigger_action.ts @@ -0,0 +1,74 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + ActionByType, + APPLY_FILTER_TRIGGER, + createAction, + UiActionsStart, +} from '../../../../plugins/ui_actions/public'; +import { createFiltersFromRangeSelectAction } from './filters/create_filters_from_range_select'; +// TODO: remove this import in next iteration, this helper functions should go to data plugin probably? +import type { RangeSelectContext, ValueClickContext } from '../../../embeddable/public'; +import { Filter } from '../../common/es_query/filters'; +import { createFiltersFromValueClickAction } from './filters/create_filters_from_value_click'; +import { ChartActionContext } from '../../../embeddable/public'; + +export const ACTION_EMIT_APPLY_FILTER_TRIGGER = 'ACTION_EMIT_APPLY_FILTER_TRIGGER'; + +export type EmitApplyFilterTriggerActionContext = RangeSelectContext | ValueClickContext; + +export const isValueClickTriggerContext = ( + context: ChartActionContext +): context is ValueClickContext => context.data && 'data' in context.data; + +export const isRangeSelectTriggerContext = ( + context: ChartActionContext +): context is RangeSelectContext => context.data && 'range' in context.data; + +export function createEmitApplyFilterTriggerAction( + getStartServices: () => { uiActions: UiActionsStart } +): ActionByType { + return createAction({ + type: ACTION_EMIT_APPLY_FILTER_TRIGGER, + id: ACTION_EMIT_APPLY_FILTER_TRIGGER, + shouldAutoExecute: async () => true, + execute: async (context: EmitApplyFilterTriggerActionContext) => { + try { + let filters: Filter[] = []; + if (isValueClickTriggerContext(context)) + filters = await createFiltersFromValueClickAction(context.data); + if (isRangeSelectTriggerContext(context)) + filters = await createFiltersFromRangeSelectAction(context.data); + if (filters.length > 0) { + await getStartServices().uiActions.getTrigger(APPLY_FILTER_TRIGGER).exec({ + filters, + embeddable: context.embeddable, + timeFieldName: context.data.timeFieldName, + }); + } + } catch (e) { + // eslint-disable-next-line no-console + console.warn( + `Error [ACTION_EMIT_APPLY_FILTER_TRIGGER]: can\'t extract filters from action context` + ); + } + }, + }); +} diff --git a/src/plugins/data/public/actions/index.ts b/src/plugins/data/public/actions/index.ts index ef9014aafe82d..bd8cfc8664c8b 100644 --- a/src/plugins/data/public/actions/index.ts +++ b/src/plugins/data/public/actions/index.ts @@ -17,8 +17,17 @@ * under the License. */ -export { ACTION_GLOBAL_APPLY_FILTER, createFilterAction } from './apply_filter_action'; +export { + ACTION_GLOBAL_APPLY_FILTER, + createFilterAction, + ApplyGlobalFilterActionContext, +} from './apply_filter_action'; 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'; +export { + EmitApplyFilterTriggerActionContext, + ACTION_EMIT_APPLY_FILTER_TRIGGER, + createEmitApplyFilterTriggerAction, + isValueClickTriggerContext, + isRangeSelectTriggerContext, +} from './emit_apply_filter_trigger_action'; diff --git a/src/plugins/data/public/actions/select_range_action.ts b/src/plugins/data/public/actions/select_range_action.ts deleted file mode 100644 index 49766143b5588..0000000000000 --- a/src/plugins/data/public/actions/select_range_action.ts +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { - createAction, - IncompatibleActionError, - ActionByType, -} from '../../../../plugins/ui_actions/public'; -import { createFiltersFromRangeSelectAction } from './filters/create_filters_from_range_select'; -import { RangeSelectContext } from '../../../embeddable/public'; -import { FilterManager, TimefilterContract, esFilters } from '..'; - -export const ACTION_SELECT_RANGE = 'ACTION_SELECT_RANGE'; - -export type SelectRangeActionContext = RangeSelectContext; - -async function isCompatible(context: SelectRangeActionContext) { - try { - return Boolean(await createFiltersFromRangeSelectAction(context.data)); - } catch { - return false; - } -} - -export function selectRangeAction( - filterManager: FilterManager, - timeFilter: TimefilterContract -): ActionByType { - return createAction({ - type: ACTION_SELECT_RANGE, - id: ACTION_SELECT_RANGE, - getIconType: () => 'filter', - getDisplayName: () => { - return i18n.translate('data.filter.applyFilterActionTitle', { - defaultMessage: 'Apply filter to current view', - }); - }, - isCompatible, - execute: async ({ data }: SelectRangeActionContext) => { - if (!(await isCompatible({ data }))) { - throw new IncompatibleActionError(); - } - - const selectedFilters = await createFiltersFromRangeSelectAction(data); - - if (data.timeFieldName) { - const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter( - data.timeFieldName, - selectedFilters - ); - filterManager.addFilters(restOfFilters); - if (timeRangeFilter) { - esFilters.changeTimeFilter(timeFilter, timeRangeFilter); - } - } else { - filterManager.addFilters(selectedFilters); - } - }, - }); -} diff --git a/src/plugins/data/public/actions/value_click_action.ts b/src/plugins/data/public/actions/value_click_action.ts deleted file mode 100644 index dd74a7ee507f3..0000000000000 --- a/src/plugins/data/public/actions/value_click_action.ts +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; -import { toMountPoint } from '../../../../plugins/kibana_react/public'; -import { - ActionByType, - createAction, - IncompatibleActionError, -} from '../../../../plugins/ui_actions/public'; -import { getOverlays, getIndexPatterns } from '../services'; -import { applyFiltersPopover } from '../ui/apply_filters'; -import { createFiltersFromValueClickAction } from './filters/create_filters_from_value_click'; -import { ValueClickContext } from '../../../embeddable/public'; -import { Filter, FilterManager, TimefilterContract, esFilters } from '..'; - -export const ACTION_VALUE_CLICK = 'ACTION_VALUE_CLICK'; - -export type ValueClickActionContext = ValueClickContext; - -async function isCompatible(context: ValueClickActionContext) { - try { - const filters: Filter[] = await createFiltersFromValueClickAction(context.data); - return filters.length > 0; - } catch { - return false; - } -} - -export function valueClickAction( - filterManager: FilterManager, - timeFilter: TimefilterContract -): ActionByType { - return createAction({ - type: ACTION_VALUE_CLICK, - id: ACTION_VALUE_CLICK, - getIconType: () => 'filter', - getDisplayName: () => { - return i18n.translate('data.filter.applyFilterActionTitle', { - defaultMessage: 'Apply filter to current view', - }); - }, - isCompatible, - execute: async ({ data }: ValueClickActionContext) => { - if (!(await isCompatible({ data }))) { - throw new IncompatibleActionError(); - } - - const filters: Filter[] = await createFiltersFromValueClickAction(data); - - let selectedFilters = filters; - - if (filters.length > 1) { - const indexPatterns = await Promise.all( - filters.map((filter) => { - return getIndexPatterns().get(filter.meta.index!); - }) - ); - - const filterSelectionPromise: Promise = new Promise((resolve) => { - const overlay = getOverlays().openModal( - toMountPoint( - applyFiltersPopover( - filters, - indexPatterns, - () => { - overlay.close(); - resolve([]); - }, - (filterSelection: Filter[]) => { - overlay.close(); - resolve(filterSelection); - } - ) - ), - { - 'data-test-subj': 'selectFilterOverlay', - } - ); - }); - - selectedFilters = await filterSelectionPromise; - } - - if (data.timeFieldName) { - const { timeRangeFilter, restOfFilters } = esFilters.extractTimeFilter( - data.timeFieldName, - selectedFilters - ); - filterManager.addFilters(restOfFilters); - if (timeRangeFilter) { - esFilters.changeTimeFilter(timeFilter, timeRangeFilter); - } - } else { - filterManager.addFilters(selectedFilters); - } - }, - }); -} diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 89b0d7e0303b9..e163a3b5c4809 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -442,6 +442,12 @@ export { export { isTimeRange, isQuery, isFilter, isFilters } from '../common'; +export { + ApplyGlobalFilterActionContext, + isRangeSelectTriggerContext, + isValueClickTriggerContext, +} from './actions'; + export * from '../common/field_mapping'; /* diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index ec71794fde87d..af12a462d2757 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -69,30 +69,30 @@ import { createFilterAction, createFiltersFromValueClickAction, createFiltersFromRangeSelectAction, + ApplyGlobalFilterActionContext, + ACTION_EMIT_APPLY_FILTER_TRIGGER, + EmitApplyFilterTriggerActionContext, + createEmitApplyFilterTriggerAction, } from './actions'; -import { ApplyGlobalFilterActionContext } from './actions/apply_filter_action'; -import { - selectRangeAction, - SelectRangeActionContext, - ACTION_SELECT_RANGE, -} from './actions/select_range_action'; -import { - valueClickAction, - ACTION_VALUE_CLICK, - ValueClickActionContext, -} from './actions/value_click_action'; + import { SavedObjectsClientPublicToCommon } from './index_patterns'; import { indexPatternLoad } from './index_patterns/expressions/load_index_pattern'; declare module '../../ui_actions/public' { export interface ActionContextMapping { [ACTION_GLOBAL_APPLY_FILTER]: ApplyGlobalFilterActionContext; - [ACTION_SELECT_RANGE]: SelectRangeActionContext; - [ACTION_VALUE_CLICK]: ValueClickActionContext; + [ACTION_EMIT_APPLY_FILTER_TRIGGER]: EmitApplyFilterTriggerActionContext; } } -export class DataPublicPlugin implements Plugin { +export class DataPublicPlugin + implements + Plugin< + DataPublicPluginSetup, + DataPublicPluginStart, + DataSetupDependencies, + DataStartDependencies + > { private readonly autocomplete: AutocompleteService; private readonly searchService: SearchService; private readonly fieldFormatsService: FieldFormatsService; @@ -110,13 +110,13 @@ export class DataPublicPlugin implements Plugin, { expressions, uiActions }: DataSetupDependencies ): DataPublicPluginSetup { const startServices = createStartServicesGetter(core.getStartServices); const getInternalStartServices = (): InternalStartServices => { - const { core: coreStart, self }: any = startServices(); + const { core: coreStart, self } = startServices(); return { fieldFormats: self.fieldFormats, notifications: coreStart.notifications, @@ -138,15 +138,12 @@ export class DataPublicPlugin implements Plugin ({ + uiActions: startServices().plugins.uiActions, + })); - uiActions.addTriggerAction( - VALUE_CLICK_TRIGGER, - valueClickAction(queryService.filterManager, queryService.timefilter.timefilter) - ); + uiActions.addTriggerAction(SELECT_RANGE_TRIGGER, emitApplyFilterTriggerAction); + uiActions.addTriggerAction(VALUE_CLICK_TRIGGER, emitApplyFilterTriggerAction); return { autocomplete: this.autocomplete.setup(core), diff --git a/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx b/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx index 8cf2e015f88cf..cb02ffc470e95 100644 --- a/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx +++ b/src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx @@ -311,8 +311,7 @@ export class EmbeddablePanel extends React.Component { const sortedActions = [...regularActions, ...extraActions].sort(sortByOrderField); return await buildContextMenuForActions({ - actions: sortedActions, - actionContext: { embeddable: this.props.embeddable }, + actions: sortedActions.map((action) => [action, { embeddable: this.props.embeddable }]), closeMenu: this.closeMyContextMenuPanel, }); }; diff --git a/src/plugins/ui_actions/public/actions/action.ts b/src/plugins/ui_actions/public/actions/action.ts index f5dbbc9f923ac..8fd8e77e24a28 100644 --- a/src/plugins/ui_actions/public/actions/action.ts +++ b/src/plugins/ui_actions/public/actions/action.ts @@ -68,6 +68,12 @@ export interface Action * Executes the action. */ execute(context: Context): Promise; + + /** + * Determines if action should be executed automatically, + * without first showing up in context menu. + */ + shouldAutoExecute?(context: Context): Promise; } /** @@ -89,6 +95,12 @@ export interface ActionDefinition * Executes the action. */ execute(context: Context): Promise; + + /** + * Determines if action should be executed automatically, + * without first showing up in context menu + */ + shouldAutoExecute?(context: Context): Promise; } export type ActionContext = A extends ActionDefinition ? Context : never; diff --git a/src/plugins/ui_actions/public/actions/action_internal.ts b/src/plugins/ui_actions/public/actions/action_internal.ts index 10eb760b13089..a22b3fa5b0367 100644 --- a/src/plugins/ui_actions/public/actions/action_internal.ts +++ b/src/plugins/ui_actions/public/actions/action_internal.ts @@ -65,4 +65,9 @@ export class ActionInternal if (!this.definition.getHref) return undefined; return await this.definition.getHref(context); } + + public async shouldAutoExecute(context: Context): Promise { + if (!this.definition.shouldAutoExecute) return false; + return this.definition.shouldAutoExecute(context); + } } diff --git a/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx b/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx index 74e9ef96b575b..207722b4ac286 100644 --- a/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx +++ b/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx @@ -23,28 +23,28 @@ import _ from 'lodash'; import { i18n } from '@kbn/i18n'; import { uiToReactComponent } from '../../../kibana_react/public'; import { Action } from '../actions'; +import { BaseContext } from '../types'; export const defaultTitle = i18n.translate('uiActions.actionPanel.title', { defaultMessage: 'Options', }); +type ActionWithContext = [Action, Context]; + /** * Transforms an array of Actions to the shape EuiContextMenuPanel expects. */ -export async function buildContextMenuForActions({ +export async function buildContextMenuForActions({ actions, - actionContext, title = defaultTitle, closeMenu, }: { - actions: Array>; - actionContext: Context; + actions: ActionWithContext[]; title?: string; closeMenu: () => void; }): Promise { - const menuItems = await buildEuiContextMenuPanelItems({ + const menuItems = await buildEuiContextMenuPanelItems({ actions, - actionContext, closeMenu, }); @@ -58,17 +58,15 @@ export async function buildContextMenuForActions({ /** * Transform an array of Actions into the shape needed to build an EUIContextMenu */ -async function buildEuiContextMenuPanelItems({ +async function buildEuiContextMenuPanelItems({ actions, - actionContext, closeMenu, }: { - actions: Array>; - actionContext: Context; + actions: ActionWithContext[]; closeMenu: () => void; }) { const items: EuiContextMenuPanelItemDescriptor[] = new Array(actions.length); - const promises = actions.map(async (action, index) => { + const promises = actions.map(async ([action, actionContext], index) => { const isCompatible = await action.isCompatible(actionContext); if (!isCompatible) { return; diff --git a/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts b/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts new file mode 100644 index 0000000000000..2d1b7942f9722 --- /dev/null +++ b/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts @@ -0,0 +1,121 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { uniq } from 'lodash'; +import { Action } from '../actions'; +import { BaseContext } from '../types'; +import { defer as createDefer, Defer } from '../../../kibana_utils/public'; +import { buildContextMenuForActions, openContextMenu } from '../context_menu'; +import { Trigger } from '../triggers'; + +interface ExecuteActionTask { + action: Action; + context: BaseContext; + trigger: Trigger; + defer: Defer; +} + +export class UiActionsExecutionService { + private readonly batchingQueue: ExecuteActionTask[] = []; + private readonly pendingTasks = new Set(); + + constructor() {} + + async execute({ + action, + context, + trigger, + }: { + action: Action; + context: BaseContext; + trigger: Trigger; + }): Promise { + const shouldBatch = !(await action.shouldAutoExecute?.(context)) ?? false; + const task: ExecuteActionTask = { + action, + context, + trigger, + defer: createDefer(), + }; + + if (shouldBatch) { + this.batchingQueue.push(task); + } else { + this.pendingTasks.add(task); + try { + await action.execute(context); + this.pendingTasks.delete(task); + } catch (e) { + this.pendingTasks.delete(task); + throw new Error(e); + } + } + + this.scheduleFlush(); + + return task.defer.promise; + } + + private scheduleFlush() { + /** + * Have to delay at least until next macro task + * Otherwise chain: + * Trigger -> await action.execute() -> trigger -> action + * isn't batched + * + * This basically needed to support a chain of scheduled micro tasks (async/awaits) within uiActions code + */ + setTimeout(() => { + if (this.pendingTasks.size === 0) { + const tasks = uniq(this.batchingQueue, (t) => t.action.id); + if (tasks.length === 1) { + this.executeSingleTask(tasks[0]); + } + if (tasks.length > 1) { + this.executeMultipleActions(tasks); + } + + this.batchingQueue.splice(0, this.batchingQueue.length); + } + }, 0); + } + + private async executeSingleTask({ context, action, defer }: ExecuteActionTask) { + try { + await action.execute(context); + defer.resolve(); + } catch (e) { + defer.reject(e); + } + } + + private async executeMultipleActions(tasks: ExecuteActionTask[]) { + const panel = await buildContextMenuForActions({ + actions: tasks.map(({ action, context }) => [action, context]), + title: tasks[0].trigger.title, // title of context menu is title of trigger which originated the chain + closeMenu: () => { + tasks.forEach((t) => t.defer.resolve()); + session.close(); + }, + }); + const session = openContextMenu([panel], { + 'data-test-subj': 'multipleActionsContextMenu', + }); + } +} diff --git a/src/plugins/ui_actions/public/service/ui_actions_service.ts b/src/plugins/ui_actions/public/service/ui_actions_service.ts index 11f5769a94648..08efffbb6b5a8 100644 --- a/src/plugins/ui_actions/public/service/ui_actions_service.ts +++ b/src/plugins/ui_actions/public/service/ui_actions_service.ts @@ -28,6 +28,7 @@ import { ActionInternal, Action, ActionDefinition, ActionContext } from '../acti import { Trigger, TriggerContext } from '../triggers/trigger'; import { TriggerInternal } from '../triggers/trigger_internal'; import { TriggerContract } from '../triggers/trigger_contract'; +import { UiActionsExecutionService } from './ui_actions_execution_service'; export interface UiActionsServiceParams { readonly triggers?: TriggerRegistry; @@ -40,6 +41,7 @@ export interface UiActionsServiceParams { } export class UiActionsService { + public readonly executionService = new UiActionsExecutionService(); protected readonly triggers: TriggerRegistry; protected readonly actions: ActionRegistry; protected readonly triggerToActions: TriggerToActionsRegistry; diff --git a/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts b/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts index 983c6796eeb09..b9570d3e76f29 100644 --- a/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts +++ b/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts @@ -22,6 +22,7 @@ import { openContextMenu } from '../context_menu'; import { uiActionsPluginMock } from '../mocks'; import { Trigger } from '../triggers'; import { TriggerId, ActionType } from '../types'; +import { wait } from '@testing-library/dom'; jest.mock('../context_menu'); @@ -57,6 +58,7 @@ const reset = () => { executeFn.mockReset(); openContextMenuSpy.mockReset(); + jest.useFakeTimers(); }; beforeEach(reset); @@ -75,6 +77,8 @@ test('executes a single action mapped to a trigger', async () => { const start = doStart(); await start.executeTriggerActions('MY-TRIGGER' as TriggerId, context); + jest.runAllTimers(); + expect(executeFn).toBeCalledTimes(1); expect(executeFn).toBeCalledWith(context); }); @@ -117,6 +121,8 @@ test('does not execute an incompatible action', async () => { }; await start.executeTriggerActions('MY-TRIGGER' as TriggerId, context); + jest.runAllTimers(); + expect(executeFn).toBeCalledTimes(1); }); @@ -139,8 +145,12 @@ test('shows a context menu when more than one action is mapped to a trigger', as const context = {}; await start.executeTriggerActions('MY-TRIGGER' as TriggerId, context); - expect(executeFn).toBeCalledTimes(0); - expect(openContextMenu).toHaveBeenCalledTimes(1); + jest.runAllTimers(); + + await wait(() => { + expect(executeFn).toBeCalledTimes(0); + expect(openContextMenu).toHaveBeenCalledTimes(1); + }); }); test('passes whole action context to isCompatible()', async () => { @@ -161,4 +171,5 @@ test('passes whole action context to isCompatible()', async () => { const context = { foo: 'bar' }; await start.executeTriggerActions('MY-TRIGGER' as TriggerId, context); + jest.runAllTimers(); }); diff --git a/src/plugins/ui_actions/public/triggers/trigger_internal.ts b/src/plugins/ui_actions/public/triggers/trigger_internal.ts index e499c404ae745..c91468d31add5 100644 --- a/src/plugins/ui_actions/public/triggers/trigger_internal.ts +++ b/src/plugins/ui_actions/public/triggers/trigger_internal.ts @@ -20,8 +20,6 @@ import { Trigger } from './trigger'; import { TriggerContract } from './trigger_contract'; import { UiActionsService } from '../service'; -import { Action } from '../actions'; -import { buildContextMenuForActions, openContextMenu } from '../context_menu'; import { TriggerId, TriggerContextMapping } from '../types'; /** @@ -43,33 +41,14 @@ export class TriggerInternal { ); } - if (actions.length === 1) { - await this.executeSingleAction(actions[0], context); - return; - } - - await this.executeMultipleActions(actions, context); - } - - private async executeSingleAction( - action: Action, - context: TriggerContextMapping[T] - ) { - await action.execute(context); - } - - private async executeMultipleActions( - actions: Array>, - context: TriggerContextMapping[T] - ) { - const panel = await buildContextMenuForActions({ - actions, - actionContext: context, - title: this.trigger.title, - closeMenu: () => session.close(), - }); - const session = openContextMenu([panel], { - 'data-test-subj': 'multipleActionsContextMenu', - }); + await Promise.all([ + actions.map((action) => + this.service.executionService.execute({ + action, + context, + trigger: this.trigger, + }) + ), + ]); } } diff --git a/src/plugins/ui_actions/public/types.ts b/src/plugins/ui_actions/public/types.ts index 9fcd8a32881df..5631441cf9a1b 100644 --- a/src/plugins/ui_actions/public/types.ts +++ b/src/plugins/ui_actions/public/types.ts @@ -19,10 +19,9 @@ import { ActionInternal } from './actions/action_internal'; import { TriggerInternal } from './triggers/trigger_internal'; -import { Filter } from '../../data/public'; import { SELECT_RANGE_TRIGGER, VALUE_CLICK_TRIGGER, APPLY_FILTER_TRIGGER } from './triggers'; -import { IEmbeddable } from '../../embeddable/public'; -import { RangeSelectContext, ValueClickContext } from '../../embeddable/public'; +import type { RangeSelectContext, ValueClickContext } from '../../embeddable/public'; +import type { ApplyGlobalFilterActionContext } from '../../data/public'; export type TriggerRegistry = Map>; export type ActionRegistry = Map; @@ -39,10 +38,7 @@ export interface TriggerContextMapping { [DEFAULT_TRIGGER]: TriggerContext; [SELECT_RANGE_TRIGGER]: RangeSelectContext; [VALUE_CLICK_TRIGGER]: ValueClickContext; - [APPLY_FILTER_TRIGGER]: { - embeddable: IEmbeddable; - filters: Filter[]; - }; + [APPLY_FILTER_TRIGGER]: ApplyGlobalFilterActionContext; } const DEFAULT_ACTION = ''; From e784e0da8688b6431e1339c8bcedd464ebbf0c5c Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 2 Jul 2020 16:53:42 +0200 Subject: [PATCH 2/9] add test --- .../emit_apply_filter_trigger_action.ts | 10 +++--- .../create_filters_from_range_select.ts | 2 +- .../create_filters_from_value_click.ts | 2 +- .../tests/execute_trigger_actions.test.ts | 31 ++++++++++++++++++- 4 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/plugins/data/public/actions/emit_apply_filter_trigger_action.ts b/src/plugins/data/public/actions/emit_apply_filter_trigger_action.ts index 8f4cba25be2a6..ff9c02d23abe4 100644 --- a/src/plugins/data/public/actions/emit_apply_filter_trigger_action.ts +++ b/src/plugins/data/public/actions/emit_apply_filter_trigger_action.ts @@ -24,11 +24,13 @@ import { UiActionsStart, } from '../../../../plugins/ui_actions/public'; import { createFiltersFromRangeSelectAction } from './filters/create_filters_from_range_select'; -// TODO: remove this import in next iteration, this helper functions should go to data plugin probably? -import type { RangeSelectContext, ValueClickContext } from '../../../embeddable/public'; -import { Filter } from '../../common/es_query/filters'; import { createFiltersFromValueClickAction } from './filters/create_filters_from_value_click'; -import { ChartActionContext } from '../../../embeddable/public'; +import type { Filter } from '../../common/es_query/filters'; +import type { + ChartActionContext, + RangeSelectContext, + ValueClickContext, +} from '../../../embeddable/public'; export const ACTION_EMIT_APPLY_FILTER_TRIGGER = 'ACTION_EMIT_APPLY_FILTER_TRIGGER'; diff --git a/src/plugins/data/public/actions/filters/create_filters_from_range_select.ts b/src/plugins/data/public/actions/filters/create_filters_from_range_select.ts index a0eb49d773f3d..d9aa1b8ec8048 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_range_select.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_range_select.ts @@ -22,7 +22,7 @@ import moment from 'moment'; import { esFilters, IFieldType, RangeFilterParams } from '../../../public'; import { getIndexPatterns } from '../../../public/services'; import { deserializeAggConfig } from '../../search/expressions/utils'; -import { RangeSelectContext } from '../../../../embeddable/public'; +import type { RangeSelectContext } from '../../../../embeddable/public'; export async function createFiltersFromRangeSelectAction(event: RangeSelectContext['data']) { const column: Record = event.table.columns[event.column]; diff --git a/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts b/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts index 1974b9f776748..9429df91f693c 100644 --- a/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts +++ b/src/plugins/data/public/actions/filters/create_filters_from_value_click.ts @@ -21,7 +21,7 @@ import { KibanaDatatable } from '../../../../../plugins/expressions/public'; import { deserializeAggConfig } from '../../search/expressions'; import { esFilters, Filter } from '../../../public'; import { getIndexPatterns } from '../../../public/services'; -import { ValueClickContext } from '../../../../embeddable/public'; +import type { ValueClickContext } from '../../../../embeddable/public'; /** * For terms aggregations on `__other__` buckets, this assembles a list of applicable filter diff --git a/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts b/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts index b9570d3e76f29..9af46f25b4fec 100644 --- a/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts +++ b/src/plugins/ui_actions/public/tests/execute_trigger_actions.test.ts @@ -37,13 +37,15 @@ const TEST_ACTION_TYPE = 'TEST_ACTION_TYPE' as ActionType; function createTestAction( type: string, - checkCompatibility: (context: C) => boolean + checkCompatibility: (context: C) => boolean, + autoExecutable = false ): Action { return createAction({ type: type as ActionType, id: type, isCompatible: (context: C) => Promise.resolve(checkCompatibility(context)), execute: (context) => executeFn(context), + shouldAutoExecute: () => Promise.resolve(autoExecutable), }); } @@ -173,3 +175,30 @@ test('passes whole action context to isCompatible()', async () => { await start.executeTriggerActions('MY-TRIGGER' as TriggerId, context); jest.runAllTimers(); }); + +test("doesn't show a context menu for auto executable actions", async () => { + const { setup, doStart } = uiActions; + const trigger: Trigger = { + id: 'MY-TRIGGER' as TriggerId, + title: 'My trigger', + }; + const action1 = createTestAction('test1', () => true, true); + const action2 = createTestAction('test2', () => true, false); + + setup.registerTrigger(trigger); + setup.addTriggerAction(trigger.id, action1); + setup.addTriggerAction(trigger.id, action2); + + expect(openContextMenu).toHaveBeenCalledTimes(0); + + const start = doStart(); + const context = {}; + await start.executeTriggerActions('MY-TRIGGER' as TriggerId, context); + + jest.runAllTimers(); + + await wait(() => { + expect(executeFn).toBeCalledTimes(2); + expect(openContextMenu).toHaveBeenCalledTimes(0); + }); +}); From b9e990fe968980e8d1c709c5a78fac2d83b927c2 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Thu, 2 Jul 2020 18:04:13 +0200 Subject: [PATCH 3/9] docs, remove redundant public api --- ...plyglobalfilteractioncontext.embeddable.md | 11 +++++++++ ....applyglobalfilteractioncontext.filters.md | 11 +++++++++ ...a-public.applyglobalfilteractioncontext.md | 22 +++++++++++++++++ ...globalfilteractioncontext.timefieldname.md | 11 +++++++++ .../kibana-plugin-plugins-data-public.md | 1 + ...plugin-plugins-data-public.plugin.setup.md | 4 ++-- .../public/actions/apply_filter_action.ts | 4 ++++ src/plugins/data/public/index.ts | 6 +---- src/plugins/data/public/public.api.md | 24 ++++++++++++++----- 9 files changed, 81 insertions(+), 13 deletions(-) create mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.embeddable.md create mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.filters.md create mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md create mode 100644 docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.timefieldname.md diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.embeddable.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.embeddable.md new file mode 100644 index 0000000000000..027ae4209b77f --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.embeddable.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [ApplyGlobalFilterActionContext](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md) > [embeddable](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.embeddable.md) + +## ApplyGlobalFilterActionContext.embeddable property + +Signature: + +```typescript +embeddable?: IEmbeddable; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.filters.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.filters.md new file mode 100644 index 0000000000000..6d1d20580fb19 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.filters.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [ApplyGlobalFilterActionContext](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md) > [filters](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.filters.md) + +## ApplyGlobalFilterActionContext.filters property + +Signature: + +```typescript +filters: Filter[]; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md new file mode 100644 index 0000000000000..3f78aa80f7e26 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md @@ -0,0 +1,22 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [ApplyGlobalFilterActionContext](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md) + +## ApplyGlobalFilterActionContext interface + +Action context for + +Signature: + +```typescript +export interface ApplyGlobalFilterActionContext +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [embeddable](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.embeddable.md) | IEmbeddable | | +| [filters](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.filters.md) | Filter[] | | +| [timeFieldName](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.timefieldname.md) | string | | + diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.timefieldname.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.timefieldname.md new file mode 100644 index 0000000000000..a5cf58018ec65 --- /dev/null +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.timefieldname.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-public](./kibana-plugin-plugins-data-public.md) > [ApplyGlobalFilterActionContext](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md) > [timeFieldName](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.timefieldname.md) + +## ApplyGlobalFilterActionContext.timeFieldName property + +Signature: + +```typescript +timeFieldName?: string; +``` diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md index feeb686a1f5ed..bfda722fadda8 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md @@ -49,6 +49,7 @@ | Interface | Description | | --- | --- | | [AggParamOption](./kibana-plugin-plugins-data-public.aggparamoption.md) | | +| [ApplyGlobalFilterActionContext](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md) | Action context for | | [DataPublicPluginSetup](./kibana-plugin-plugins-data-public.datapublicpluginsetup.md) | | | [DataPublicPluginStart](./kibana-plugin-plugins-data-public.datapublicpluginstart.md) | | | [EsQueryConfig](./kibana-plugin-plugins-data-public.esqueryconfig.md) | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md index 51bc46bbdccc8..19cec37915144 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md @@ -7,14 +7,14 @@ Signature: ```typescript -setup(core: CoreSetup, { expressions, uiActions }: DataSetupDependencies): DataPublicPluginSetup; +setup(core: CoreSetup, { expressions, uiActions }: DataSetupDependencies): DataPublicPluginSetup; ``` ## Parameters | Parameter | Type | Description | | --- | --- | --- | -| core | CoreSetup | | +| core | CoreSetup<DataStartDependencies, DataPublicPluginStart> | | | { expressions, uiActions } | DataSetupDependencies | | Returns: diff --git a/src/plugins/data/public/actions/apply_filter_action.ts b/src/plugins/data/public/actions/apply_filter_action.ts index a2621e6ce8802..74b5df4a18461 100644 --- a/src/plugins/data/public/actions/apply_filter_action.ts +++ b/src/plugins/data/public/actions/apply_filter_action.ts @@ -27,6 +27,10 @@ import { Filter, FilterManager, TimefilterContract, esFilters } from '..'; export const ACTION_GLOBAL_APPLY_FILTER = 'ACTION_GLOBAL_APPLY_FILTER'; +/** + * Action context for {@link ACTION_GLOBAL_APPLY_FILTER} + * @public + */ export interface ApplyGlobalFilterActionContext { filters: Filter[]; timeFieldName?: string; diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index e163a3b5c4809..2395d18306248 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -442,11 +442,7 @@ export { export { isTimeRange, isQuery, isFilter, isFilters } from '../common'; -export { - ApplyGlobalFilterActionContext, - isRangeSelectTriggerContext, - isValueClickTriggerContext, -} from './actions'; +export { ApplyGlobalFilterActionContext } from './actions'; export * from '../common/field_mapping'; diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index f19611bc1d526..39b740b17ea4a 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -244,6 +244,20 @@ export class AggParamType extends Ba makeAgg: (agg: TAggConfig, state?: AggConfigSerialized) => TAggConfig; } +// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "ACTION_GLOBAL_APPLY_FILTER" +// +// @public +export interface ApplyGlobalFilterActionContext { + // Warning: (ae-forgotten-export) The symbol "IEmbeddable" needs to be exported by the entry point index.d.ts + // + // (undocumented) + embeddable?: IEmbeddable; + // (undocumented) + filters: Filter[]; + // (undocumented) + timeFieldName?: string; +} + // Warning: (ae-forgotten-export) The symbol "DateFormat" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "baseFormattersPublic" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -1484,18 +1498,16 @@ export type PhrasesFilter = Filter & { meta: PhrasesFilterMeta; }; +// Warning: (ae-forgotten-export) The symbol "DataSetupDependencies" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "DataStartDependencies" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "DataPublicPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export class Plugin implements Plugin_2 { +export class Plugin implements Plugin_2 { // Warning: (ae-forgotten-export) The symbol "ConfigSchema" needs to be exported by the entry point index.d.ts constructor(initializerContext: PluginInitializerContext_2); - // Warning: (ae-forgotten-export) The symbol "DataSetupDependencies" needs to be exported by the entry point index.d.ts - // // (undocumented) - setup(core: CoreSetup, { expressions, uiActions }: DataSetupDependencies): DataPublicPluginSetup; - // Warning: (ae-forgotten-export) The symbol "DataStartDependencies" needs to be exported by the entry point index.d.ts - // + setup(core: CoreSetup, { expressions, uiActions }: DataSetupDependencies): DataPublicPluginSetup; // (undocumented) start(core: CoreStart_2, { uiActions }: DataStartDependencies): DataPublicPluginStart; // (undocumented) From 81b1fd3b23b521f5b8dbf6e5a7ffbcc6280d59fe Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Fri, 3 Jul 2020 15:47:38 +0200 Subject: [PATCH 4/9] fix lodash usage --- .../ui_actions/public/service/ui_actions_execution_service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts b/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts index 2d1b7942f9722..cc9ceefca098f 100644 --- a/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts +++ b/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts @@ -17,7 +17,7 @@ * under the License. */ -import { uniq } from 'lodash'; +import { uniqBy } from 'lodash'; import { Action } from '../actions'; import { BaseContext } from '../types'; import { defer as createDefer, Defer } from '../../../kibana_utils/public'; @@ -83,7 +83,7 @@ export class UiActionsExecutionService { */ setTimeout(() => { if (this.pendingTasks.size === 0) { - const tasks = uniq(this.batchingQueue, (t) => t.action.id); + const tasks = uniqBy(this.batchingQueue, (t) => t.action.id); if (tasks.length === 1) { this.executeSingleTask(tasks[0]); } From fb279db3c3af73dfd9b5339f7b176ab19147214c Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Mon, 13 Jul 2020 12:58:29 +0200 Subject: [PATCH 5/9] review --- .../public/actions/apply_filter_action.ts | 7 ++- src/plugins/data/public/actions/index.ts | 9 +-- .../public/actions/select_range_action.ts | 56 +++++++++++++++++++ ...rigger_action.ts => value_click_action.ts} | 38 ++++--------- src/plugins/data/public/plugin.ts | 29 +++++++--- src/plugins/ui_actions/kibana.json | 1 + .../ui_actions/public/actions/action.ts | 4 +- .../service/ui_actions_execution_service.ts | 3 +- 8 files changed, 98 insertions(+), 49 deletions(-) create mode 100644 src/plugins/data/public/actions/select_range_action.ts rename src/plugins/data/public/actions/{emit_apply_filter_trigger_action.ts => value_click_action.ts} (56%) diff --git a/src/plugins/data/public/actions/apply_filter_action.ts b/src/plugins/data/public/actions/apply_filter_action.ts index 74b5df4a18461..95646de8dc584 100644 --- a/src/plugins/data/public/actions/apply_filter_action.ts +++ b/src/plugins/data/public/actions/apply_filter_action.ts @@ -26,9 +26,10 @@ import type { IEmbeddable } from '../../../embeddable/public'; import { Filter, FilterManager, TimefilterContract, esFilters } from '..'; export const ACTION_GLOBAL_APPLY_FILTER = 'ACTION_GLOBAL_APPLY_FILTER'; +type ActionGlobalApplyFilterFilterType = typeof ACTION_GLOBAL_APPLY_FILTER; /** - * Action context for {@link ACTION_GLOBAL_APPLY_FILTER} + * Action context for {@link ActionGlobalApplyFilterFilterType} * @public */ export interface ApplyGlobalFilterActionContext { @@ -44,8 +45,8 @@ async function isCompatible(context: ApplyGlobalFilterActionContext) { export function createFilterAction( filterManager: FilterManager, timeFilter: TimefilterContract -): ActionByType { - return createAction({ +): ActionByType { + return createAction({ type: ACTION_GLOBAL_APPLY_FILTER, id: ACTION_GLOBAL_APPLY_FILTER, getIconType: () => 'filter', diff --git a/src/plugins/data/public/actions/index.ts b/src/plugins/data/public/actions/index.ts index bd8cfc8664c8b..692996cf6fd19 100644 --- a/src/plugins/data/public/actions/index.ts +++ b/src/plugins/data/public/actions/index.ts @@ -24,10 +24,5 @@ export { } from './apply_filter_action'; export { createFiltersFromValueClickAction } from './filters/create_filters_from_value_click'; export { createFiltersFromRangeSelectAction } from './filters/create_filters_from_range_select'; -export { - EmitApplyFilterTriggerActionContext, - ACTION_EMIT_APPLY_FILTER_TRIGGER, - createEmitApplyFilterTriggerAction, - isValueClickTriggerContext, - isRangeSelectTriggerContext, -} from './emit_apply_filter_trigger_action'; +export * from './select_range_action'; +export * from './value_click_action'; diff --git a/src/plugins/data/public/actions/select_range_action.ts b/src/plugins/data/public/actions/select_range_action.ts new file mode 100644 index 0000000000000..1781da980dc30 --- /dev/null +++ b/src/plugins/data/public/actions/select_range_action.ts @@ -0,0 +1,56 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { + ActionByType, + APPLY_FILTER_TRIGGER, + createAction, + UiActionsStart, +} from '../../../../plugins/ui_actions/public'; +import { createFiltersFromRangeSelectAction } from './filters/create_filters_from_range_select'; +import type { RangeSelectContext } from '../../../embeddable/public'; + +export type SelectRangeActionContext = RangeSelectContext; + +export const ACTION_SELECT_RANGE = 'ACTION_SELECT_RANGE'; + +export function createSelectRangeAction( + getStartServices: () => { uiActions: UiActionsStart } +): ActionByType { + return createAction({ + type: ACTION_SELECT_RANGE, + id: ACTION_SELECT_RANGE, + shouldAutoExecute: async () => true, + execute: async (context: SelectRangeActionContext) => { + try { + const filters = await createFiltersFromRangeSelectAction(context.data); + if (filters.length > 0) { + await getStartServices().uiActions.getTrigger(APPLY_FILTER_TRIGGER).exec({ + filters, + embeddable: context.embeddable, + timeFieldName: context.data.timeFieldName, + }); + } + } catch (e) { + // eslint-disable-next-line no-console + console.warn(`Error [ACTION_SELECT_RANGE]: can\'t extract filters from action context`); + } + }, + }); +} diff --git a/src/plugins/data/public/actions/emit_apply_filter_trigger_action.ts b/src/plugins/data/public/actions/value_click_action.ts similarity index 56% rename from src/plugins/data/public/actions/emit_apply_filter_trigger_action.ts rename to src/plugins/data/public/actions/value_click_action.ts index ff9c02d23abe4..81e62380eacfb 100644 --- a/src/plugins/data/public/actions/emit_apply_filter_trigger_action.ts +++ b/src/plugins/data/public/actions/value_click_action.ts @@ -23,41 +23,23 @@ import { createAction, UiActionsStart, } from '../../../../plugins/ui_actions/public'; -import { createFiltersFromRangeSelectAction } from './filters/create_filters_from_range_select'; import { createFiltersFromValueClickAction } from './filters/create_filters_from_value_click'; import type { Filter } from '../../common/es_query/filters'; -import type { - ChartActionContext, - RangeSelectContext, - ValueClickContext, -} from '../../../embeddable/public'; +import type { ValueClickContext } from '../../../embeddable/public'; -export const ACTION_EMIT_APPLY_FILTER_TRIGGER = 'ACTION_EMIT_APPLY_FILTER_TRIGGER'; +export type ValueClickActionContext = ValueClickContext; +export const ACTION_VALUE_CLICK = 'ACTION_VALUE_CLICK'; -export type EmitApplyFilterTriggerActionContext = RangeSelectContext | ValueClickContext; - -export const isValueClickTriggerContext = ( - context: ChartActionContext -): context is ValueClickContext => context.data && 'data' in context.data; - -export const isRangeSelectTriggerContext = ( - context: ChartActionContext -): context is RangeSelectContext => context.data && 'range' in context.data; - -export function createEmitApplyFilterTriggerAction( +export function createValueClickAction( getStartServices: () => { uiActions: UiActionsStart } -): ActionByType { - return createAction({ - type: ACTION_EMIT_APPLY_FILTER_TRIGGER, - id: ACTION_EMIT_APPLY_FILTER_TRIGGER, +): ActionByType { + return createAction({ + type: ACTION_VALUE_CLICK, + id: ACTION_VALUE_CLICK, shouldAutoExecute: async () => true, - execute: async (context: EmitApplyFilterTriggerActionContext) => { + execute: async (context: ValueClickActionContext) => { try { - let filters: Filter[] = []; - if (isValueClickTriggerContext(context)) - filters = await createFiltersFromValueClickAction(context.data); - if (isRangeSelectTriggerContext(context)) - filters = await createFiltersFromRangeSelectAction(context.data); + const filters: Filter[] = await createFiltersFromValueClickAction(context.data); if (filters.length > 0) { await getStartServices().uiActions.getTrigger(APPLY_FILTER_TRIGGER).exec({ filters, diff --git a/src/plugins/data/public/plugin.ts b/src/plugins/data/public/plugin.ts index 62f40fb11bf46..923e615475761 100644 --- a/src/plugins/data/public/plugin.ts +++ b/src/plugins/data/public/plugin.ts @@ -70,9 +70,12 @@ import { createFiltersFromValueClickAction, createFiltersFromRangeSelectAction, ApplyGlobalFilterActionContext, - ACTION_EMIT_APPLY_FILTER_TRIGGER, - EmitApplyFilterTriggerActionContext, - createEmitApplyFilterTriggerAction, + ACTION_SELECT_RANGE, + ACTION_VALUE_CLICK, + SelectRangeActionContext, + ValueClickActionContext, + createValueClickAction, + createSelectRangeAction, } from './actions'; import { SavedObjectsClientPublicToCommon } from './index_patterns'; @@ -81,7 +84,8 @@ import { indexPatternLoad } from './index_patterns/expressions/load_index_patter declare module '../../ui_actions/public' { export interface ActionContextMapping { [ACTION_GLOBAL_APPLY_FILTER]: ApplyGlobalFilterActionContext; - [ACTION_EMIT_APPLY_FILTER_TRIGGER]: EmitApplyFilterTriggerActionContext; + [ACTION_SELECT_RANGE]: SelectRangeActionContext; + [ACTION_VALUE_CLICK]: ValueClickActionContext; } } @@ -138,12 +142,19 @@ export class DataPublicPlugin createFilterAction(queryService.filterManager, queryService.timefilter.timefilter) ); - const emitApplyFilterTriggerAction = createEmitApplyFilterTriggerAction(() => ({ - uiActions: startServices().plugins.uiActions, - })); + uiActions.addTriggerAction( + SELECT_RANGE_TRIGGER, + createSelectRangeAction(() => ({ + uiActions: startServices().plugins.uiActions, + })) + ); - uiActions.addTriggerAction(SELECT_RANGE_TRIGGER, emitApplyFilterTriggerAction); - uiActions.addTriggerAction(VALUE_CLICK_TRIGGER, emitApplyFilterTriggerAction); + uiActions.addTriggerAction( + VALUE_CLICK_TRIGGER, + createValueClickAction(() => ({ + uiActions: startServices().plugins.uiActions, + })) + ); return { autocomplete: this.autocomplete.setup(core), diff --git a/src/plugins/ui_actions/kibana.json b/src/plugins/ui_actions/kibana.json index 7b24b3cc5c48b..337c5ddf0fd5c 100644 --- a/src/plugins/ui_actions/kibana.json +++ b/src/plugins/ui_actions/kibana.json @@ -7,6 +7,7 @@ "public/tests/test_samples" ], "requiredBundles": [ + "kibanaUtils", "kibanaReact" ] } diff --git a/src/plugins/ui_actions/public/actions/action.ts b/src/plugins/ui_actions/public/actions/action.ts index 8fd8e77e24a28..bc5f36acb8f0c 100644 --- a/src/plugins/ui_actions/public/actions/action.ts +++ b/src/plugins/ui_actions/public/actions/action.ts @@ -72,6 +72,7 @@ export interface Action /** * Determines if action should be executed automatically, * without first showing up in context menu. + * false by default. */ shouldAutoExecute?(context: Context): Promise; } @@ -98,7 +99,8 @@ export interface ActionDefinition /** * Determines if action should be executed automatically, - * without first showing up in context menu + * without first showing up in context menu. + * false by default. */ shouldAutoExecute?(context: Context): Promise; } diff --git a/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts b/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts index cc9ceefca098f..b6b895ed2c5f6 100644 --- a/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts +++ b/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts @@ -42,7 +42,7 @@ export class UiActionsExecutionService { context, trigger, }: { - action: Action; + action: Action; context: BaseContext; trigger: Trigger; }): Promise { @@ -106,6 +106,7 @@ export class UiActionsExecutionService { } private async executeMultipleActions(tasks: ExecuteActionTask[]) { + debugger; const panel = await buildContextMenuForActions({ actions: tasks.map(({ action, context }) => [action, context]), title: tasks[0].trigger.title, // title of context menu is title of trigger which originated the chain From bb7a96b88fd7f855c5d769465b617a8de03b047e Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Mon, 13 Jul 2020 12:58:45 +0200 Subject: [PATCH 6/9] fix lint --- .../ui_actions/public/service/ui_actions_execution_service.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts b/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts index b6b895ed2c5f6..7393989672e9d 100644 --- a/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts +++ b/src/plugins/ui_actions/public/service/ui_actions_execution_service.ts @@ -106,7 +106,6 @@ export class UiActionsExecutionService { } private async executeMultipleActions(tasks: ExecuteActionTask[]) { - debugger; const panel = await buildContextMenuForActions({ actions: tasks.map(({ action, context }) => [action, context]), title: tasks[0].trigger.title, // title of context menu is title of trigger which originated the chain From 46efa57e50a4e48a854ea0141fa94ba5ea15406f Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Mon, 13 Jul 2020 13:51:52 +0200 Subject: [PATCH 7/9] fix docs --- src/plugins/data/public/public.api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index e7d38846095e3..9d07a3304b5a7 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -246,7 +246,7 @@ export class AggParamType extends Ba makeAgg: (agg: TAggConfig, state?: AggConfigSerialized) => TAggConfig; } -// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "ACTION_GLOBAL_APPLY_FILTER" +// Warning: (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "ActionGlobalApplyFilterFilterType" // // @public export interface ApplyGlobalFilterActionContext { From 2ee8e54a7810e6bbde78fbbbdfbeffad10daa469 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Wed, 15 Jul 2020 09:08:48 +0200 Subject: [PATCH 8/9] any -> BaseContext --- .../public/context_menu/build_eui_context_menu_panels.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx b/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx index 207722b4ac286..7b87a5992a7f5 100644 --- a/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx +++ b/src/plugins/ui_actions/public/context_menu/build_eui_context_menu_panels.tsx @@ -29,7 +29,7 @@ export const defaultTitle = i18n.translate('uiActions.actionPanel.title', { defaultMessage: 'Options', }); -type ActionWithContext = [Action, Context]; +type ActionWithContext = [Action, Context]; /** * Transforms an array of Actions to the shape EuiContextMenuPanel expects. From c3f632d4bcc0968e19148e30477ddf74da205481 Mon Sep 17 00:00:00 2001 From: Anton Dosov Date: Wed, 15 Jul 2020 14:08:38 +0200 Subject: [PATCH 9/9] fix docs --- ...a-public.applyglobalfilteractioncontext.md | 2 -- .../kibana-plugin-plugins-data-public.md | 2 +- ...plugin-plugins-data-public.plugin.setup.md | 4 ++-- .../public/actions/apply_filter_action.ts | 9 ++----- src/plugins/data/public/public.api.md | 24 ++++++++++++++----- 5 files changed, 23 insertions(+), 18 deletions(-) diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md index 3f78aa80f7e26..62817cd0a1e33 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md @@ -4,8 +4,6 @@ ## ApplyGlobalFilterActionContext interface -Action context for - Signature: ```typescript diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md index 4fffff63d698a..db41936f35cca 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.md @@ -48,7 +48,7 @@ | Interface | Description | | --- | --- | | [AggParamOption](./kibana-plugin-plugins-data-public.aggparamoption.md) | | -| [ApplyGlobalFilterActionContext](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md) | Action context for | +| [ApplyGlobalFilterActionContext](./kibana-plugin-plugins-data-public.applyglobalfilteractioncontext.md) | | | [DataPublicPluginSetup](./kibana-plugin-plugins-data-public.datapublicpluginsetup.md) | | | [DataPublicPluginStart](./kibana-plugin-plugins-data-public.datapublicpluginstart.md) | | | [EsQueryConfig](./kibana-plugin-plugins-data-public.esqueryconfig.md) | | diff --git a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md index 7bae595e75ad0..a0c9b38792825 100644 --- a/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md +++ b/docs/development/plugins/data/public/kibana-plugin-plugins-data-public.plugin.setup.md @@ -7,14 +7,14 @@ Signature: ```typescript -setup(core: CoreSetup, { expressions, uiActions, usageCollection }: DataSetupDependencies): DataPublicPluginSetup; +setup(core: CoreSetup, { expressions, uiActions, usageCollection }: DataSetupDependencies): DataPublicPluginSetup; ``` ## Parameters | Parameter | Type | Description | | --- | --- | --- | -| core | CoreSetup | | +| core | CoreSetup<DataStartDependencies, DataPublicPluginStart> | | | { expressions, uiActions, usageCollection } | DataSetupDependencies | | Returns: diff --git a/src/plugins/data/public/actions/apply_filter_action.ts b/src/plugins/data/public/actions/apply_filter_action.ts index 95646de8dc584..a2621e6ce8802 100644 --- a/src/plugins/data/public/actions/apply_filter_action.ts +++ b/src/plugins/data/public/actions/apply_filter_action.ts @@ -26,12 +26,7 @@ import type { IEmbeddable } from '../../../embeddable/public'; import { Filter, FilterManager, TimefilterContract, esFilters } from '..'; export const ACTION_GLOBAL_APPLY_FILTER = 'ACTION_GLOBAL_APPLY_FILTER'; -type ActionGlobalApplyFilterFilterType = typeof ACTION_GLOBAL_APPLY_FILTER; -/** - * Action context for {@link ActionGlobalApplyFilterFilterType} - * @public - */ export interface ApplyGlobalFilterActionContext { filters: Filter[]; timeFieldName?: string; @@ -45,8 +40,8 @@ async function isCompatible(context: ApplyGlobalFilterActionContext) { export function createFilterAction( filterManager: FilterManager, timeFilter: TimefilterContract -): ActionByType { - return createAction({ +): ActionByType { + return createAction({ type: ACTION_GLOBAL_APPLY_FILTER, id: ACTION_GLOBAL_APPLY_FILTER, getIconType: () => 'filter', diff --git a/src/plugins/data/public/public.api.md b/src/plugins/data/public/public.api.md index f8b8cb43b2297..38e0416233e25 100644 --- a/src/plugins/data/public/public.api.md +++ b/src/plugins/data/public/public.api.md @@ -250,6 +250,20 @@ export class AggParamType extends Ba makeAgg: (agg: TAggConfig, state?: AggConfigSerialized) => TAggConfig; } +// Warning: (ae-missing-release-tag) "ApplyGlobalFilterActionContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface ApplyGlobalFilterActionContext { + // Warning: (ae-forgotten-export) The symbol "IEmbeddable" needs to be exported by the entry point index.d.ts + // + // (undocumented) + embeddable?: IEmbeddable; + // (undocumented) + filters: Filter[]; + // (undocumented) + timeFieldName?: string; +} + // Warning: (ae-forgotten-export) The symbol "DateNanosFormat" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "DateFormat" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "baseFormattersPublic" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -1443,18 +1457,16 @@ export type PhrasesFilter = Filter & { meta: PhrasesFilterMeta; }; +// Warning: (ae-forgotten-export) The symbol "DataSetupDependencies" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "DataStartDependencies" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "DataPublicPlugin" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export class Plugin implements Plugin_2 { +export class Plugin implements Plugin_2 { // Warning: (ae-forgotten-export) The symbol "ConfigSchema" needs to be exported by the entry point index.d.ts constructor(initializerContext: PluginInitializerContext_2); - // Warning: (ae-forgotten-export) The symbol "DataSetupDependencies" needs to be exported by the entry point index.d.ts - // // (undocumented) - setup(core: CoreSetup, { expressions, uiActions, usageCollection }: DataSetupDependencies): DataPublicPluginSetup; - // Warning: (ae-forgotten-export) The symbol "DataStartDependencies" needs to be exported by the entry point index.d.ts - // + setup(core: CoreSetup, { expressions, uiActions, usageCollection }: DataSetupDependencies): DataPublicPluginSetup; // (undocumented) start(core: CoreStart_2, { uiActions }: DataStartDependencies): DataPublicPluginStart; // (undocumented)