diff --git a/src/legacy/core_plugins/dashboard_embeddable_container/public/np_ready/public/lib/actions/expand_panel_action.tsx b/src/legacy/core_plugins/dashboard_embeddable_container/public/np_ready/public/lib/actions/expand_panel_action.tsx index 273234cf8d8d..494110750fcf 100644 --- a/src/legacy/core_plugins/dashboard_embeddable_container/public/np_ready/public/lib/actions/expand_panel_action.tsx +++ b/src/legacy/core_plugins/dashboard_embeddable_container/public/np_ready/public/lib/actions/expand_panel_action.tsx @@ -21,7 +21,6 @@ import { i18n } from '@kbn/i18n'; import { Action, IEmbeddable, - ActionContext, IncompatibleActionError, } from '../../../../../../embeddable_api/public/np_ready/public'; import { DASHBOARD_CONTAINER_TYPE, DashboardContainer } from '../embeddable'; @@ -40,7 +39,11 @@ function isExpanded(embeddable: IEmbeddable) { return embeddable.id === embeddable.parent.getInput().expandedPanelId; } -export class ExpandPanelAction extends Action { +interface ActionContext { + embeddable: IEmbeddable; +} + +export class ExpandPanelAction extends Action { public readonly type = EXPAND_PANEL_ACTION; constructor() { @@ -80,7 +83,7 @@ export class ExpandPanelAction extends Action { return Boolean(embeddable.parent && isDashboard(embeddable.parent)); } - public execute({ embeddable }: ActionContext) { + public async execute({ embeddable }: ActionContext) { if (!embeddable.parent || !isDashboard(embeddable.parent)) { throw new IncompatibleActionError(); } diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/api/execute_trigger_actions.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/api/execute_trigger_actions.ts index 5c6216fb629a..b7bf7e33e7c9 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/api/execute_trigger_actions.ts +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/api/execute_trigger_actions.ts @@ -18,9 +18,9 @@ */ import { EmbeddableApiPure } from './types'; -import { Action, ActionContext, buildContextMenuForActions, openContextMenu } from '../lib'; +import { Action, buildContextMenuForActions, openContextMenu } from '../lib'; -const executeSingleAction = async (action: Action, actionContext: ActionContext) => { +const executeSingleAction = async (action: Action, actionContext: A) => { const href = action.getHref(actionContext); // TODO: Do we need a `getHref()` special case? diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/api/types.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/api/types.ts index e68b3b89f5eb..18073d2b9008 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/api/types.ts +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/api/types.ts @@ -24,7 +24,6 @@ import { EmbeddableFactory, ExecuteTriggerActions, GetEmbeddableFactories, - TriggerContext, } from '../lib'; export interface EmbeddableApi { @@ -35,7 +34,7 @@ export interface EmbeddableApi { getEmbeddableFactories: GetEmbeddableFactories; getTrigger: (id: string) => Trigger; getTriggerActions: (id: string) => Action[]; - getTriggerCompatibleActions: (triggerId: string, context: TriggerContext) => Promise; + getTriggerCompatibleActions: (triggerId: string, context: C) => Promise>>; registerAction: (action: Action) => void; // TODO: Make `registerEmbeddableFactory` receive only `factory` argument. registerEmbeddableFactory: (id: string, factory: EmbeddableFactory) => void; diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/index.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/index.ts index 4cceceb57824..79bdd65f9cfc 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/index.ts +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/index.ts @@ -26,7 +26,6 @@ export { APPLY_FILTER_TRIGGER, PANEL_BADGE_TRIGGER, Action, - ActionContext, Adapters, AddPanelAction, ApplyFilterAction, @@ -59,7 +58,6 @@ export { PropertySpec, SavedObjectMetaData, Trigger, - TriggerContext, ViewMode, isErrorEmbeddable, openAddPanelFlyout, diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/action.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/action.ts index 1002915de1d9..5569a3938bc7 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/action.ts +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/action.ts @@ -17,20 +17,7 @@ * under the License. */ -import { IEmbeddable } from '../embeddables'; - -export interface ActionContext< - TEmbeddable extends IEmbeddable = IEmbeddable, - TTriggerContext extends {} = {} -> { - embeddable: TEmbeddable; - triggerContext?: TTriggerContext; -} - -export abstract class Action< - TEmbeddable extends IEmbeddable = IEmbeddable, - TTriggerContext extends {} = {} -> { +export abstract class Action { /** * Determined the order when there is more than one action matched to a trigger. * Higher numbers are displayed first. @@ -43,7 +30,7 @@ export abstract class Action< /** * Optional EUI icon type that can be displayed along with the title. */ - public getIconType(context: ActionContext): string | undefined { + public getIconType(context: ActionContext): string | undefined { return undefined; } @@ -51,27 +38,25 @@ export abstract class Action< * Returns a title to be displayed to the user. * @param context */ - public abstract getDisplayName(context: ActionContext): string; + public abstract getDisplayName(context: ActionContext): string; /** * Returns a promise that resolves to true if this action is compatible given the context, * otherwise resolves to false. */ - public async isCompatible( - context: ActionContext - ): Promise { + public async isCompatible(context: ActionContext): Promise { return true; } /** * If this returns something truthy, this is used in addition to the `execute` method when clicked. */ - public getHref(context: ActionContext): string | undefined { + public getHref(context: ActionContext): string | undefined { return undefined; } /** * Executes the action. */ - public abstract execute(context: ActionContext): void; + public abstract async execute(context: ActionContext): Promise; } diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/apply_filter_action.test.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/apply_filter_action.test.ts index e32500af1d7f..c14f258b5641 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/apply_filter_action.test.ts +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/apply_filter_action.test.ts @@ -48,9 +48,7 @@ describe('isCompatible()', () => { }), }), } as any, - triggerContext: { - filters: [], - }, + filters: [], }); expect(result).toBe(true); }); @@ -65,9 +63,7 @@ describe('isCompatible()', () => { }), }), } as any, - triggerContext: { - filters: [], - }, + filters: [], }); expect(result).toBe(false); }); @@ -83,25 +79,8 @@ describe('isCompatible()', () => { }), }), } as any, - triggerContext: { - // filters: [], - } as any, - }); + } as any); expect(result1).toBe(false); - - const result2 = await action.isCompatible({ - embeddable: { - getRoot: () => ({ - getInput: () => ({ - filters: [], - }), - }), - } as any, - // triggerContext: { - // filters: [], - // } as any - }); - expect(result2).toBe(false); }); }); @@ -125,42 +104,41 @@ describe('execute()', () => { const error = expectError(() => action.execute({ embeddable: getEmbeddable(), - triggerContext: {}, } as any) ); expect(error).toBeInstanceOf(Error); }); - test('updates filter input on success', () => { + test('updates filter input on success', async done => { const action = new ApplyFilterAction(); const [embeddable, root] = getEmbeddable(); - action.execute({ + await action.execute({ embeddable, - triggerContext: { - filters: ['FILTER' as any], - }, + filters: ['FILTER' as any], }); expect(root.updateInput).toHaveBeenCalledTimes(1); expect(root.updateInput.mock.calls[0][0]).toMatchObject({ filters: ['FILTER'], }); + + done(); }); - test('checks if action isCompatible', () => { + test('checks if action isCompatible', async done => { const action = new ApplyFilterAction(); const spy = jest.spyOn(action, 'isCompatible'); const [embeddable] = getEmbeddable(); - action.execute({ + await action.execute({ embeddable, - triggerContext: { - filters: ['FILTER' as any], - }, + filters: ['FILTER' as any], }); expect(spy).toHaveBeenCalledTimes(1); + + done(); }); }); }); diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/apply_filter_action.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/apply_filter_action.ts index c7b12629eeab..24549a64bfc2 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/apply_filter_action.ts +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/apply_filter_action.ts @@ -20,14 +20,18 @@ import { i18n } from '@kbn/i18n'; import { Filter } from '@kbn/es-query'; import { IEmbeddable, EmbeddableInput } from '../embeddables'; -import { Action, ActionContext } from './action'; +import { Action } from './action'; import { IncompatibleActionError } from '../errors'; export const APPLY_FILTER_ACTION = 'APPLY_FILTER_ACTION'; type RootEmbeddable = IEmbeddable; +interface ActionContext { + embeddable: IEmbeddable; + filters: Filter[]; +} -export class ApplyFilterAction extends Action { +export class ApplyFilterAction extends Action { public readonly type = APPLY_FILTER_ACTION; constructor() { @@ -40,30 +44,27 @@ export class ApplyFilterAction extends Action) { + public async isCompatible(context: ActionContext) { + if (context.embeddable === undefined) { + return false; + } const root = context.embeddable.getRoot() as RootEmbeddable; - return Boolean( - root.getInput().filters !== undefined && - context.triggerContext && - context.triggerContext.filters !== undefined - ); + return Boolean(root.getInput().filters !== undefined && context.filters !== undefined); } - public execute({ - embeddable, - triggerContext, - }: ActionContext) { - if (!triggerContext) { - throw new Error('Applying a filter requires a filter as context'); + public async execute({ embeddable, filters }: ActionContext) { + if (!filters || !embeddable) { + throw new Error('Applying a filter requires a filter and embeddable as context'); } - const root = embeddable.getRoot() as RootEmbeddable; - if (!this.isCompatible({ triggerContext, embeddable })) { + if (!(await this.isCompatible({ embeddable, filters }))) { throw new IncompatibleActionError(); } + const root = embeddable.getRoot() as RootEmbeddable; + root.updateInput({ - filters: triggerContext.filters, + filters, }); } } diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/edit_panel_action.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/edit_panel_action.ts index 5edd82bd14a3..0b3749121281 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/edit_panel_action.ts +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/edit_panel_action.ts @@ -18,13 +18,18 @@ */ import { i18n } from '@kbn/i18n'; -import { Action, ActionContext } from './action'; +import { Action } from './action'; import { GetEmbeddableFactory, ViewMode } from '../types'; import { EmbeddableFactoryNotFoundError } from '../errors'; +import { IEmbeddable } from '../embeddables'; export const EDIT_PANEL_ACTION_ID = 'editPanel'; -export class EditPanelAction extends Action { +interface ActionContext { + embeddable: IEmbeddable; +} + +export class EditPanelAction extends Action { public readonly type = EDIT_PANEL_ACTION_ID; constructor(private readonly getEmbeddableFactory: GetEmbeddableFactory) { super(EDIT_PANEL_ACTION_ID); @@ -56,8 +61,8 @@ export class EditPanelAction extends Action { return Boolean(canEditEmbeddable && inDashboardEditMode); } - public execute() { - return undefined; + public async execute() { + return; } public getHref({ embeddable }: ActionContext): string { diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/index.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/index.ts index ae0df0a2122c..7deace8345af 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/index.ts +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions/index.ts @@ -17,6 +17,6 @@ * under the License. */ -export { Action, ActionContext } from './action'; +export { Action } from './action'; export * from './apply_filter_action'; export * from './edit_panel_action'; diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/context_menu_actions/build_eui_context_menu_panels.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/context_menu_actions/build_eui_context_menu_panels.ts index b51a40a3ef2d..5b1998834a2e 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/context_menu_actions/build_eui_context_menu_panels.ts +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/context_menu_actions/build_eui_context_menu_panels.ts @@ -20,21 +20,21 @@ import { EuiContextMenuPanelDescriptor, EuiContextMenuPanelItemDescriptor } from '@elastic/eui'; import _ from 'lodash'; import { i18n } from '@kbn/i18n'; -import { Action, ActionContext } from '../actions'; +import { Action } from '../actions'; /** * Transforms an array of Actions to the shape EuiContextMenuPanel expects. */ -export async function buildContextMenuForActions({ +export async function buildContextMenuForActions({ actions, actionContext, closeMenu, }: { - actions: Action[]; - actionContext: ActionContext; + actions: Array>; + actionContext: A; closeMenu: () => void; }): Promise { - const menuItems = await buildEuiContextMenuPanelItems({ + const menuItems = await buildEuiContextMenuPanelItems({ actions, actionContext, closeMenu, @@ -52,13 +52,13 @@ 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: Action[]; - actionContext: ActionContext; + actions: Array>; + actionContext: A; closeMenu: () => void; }) { const items: EuiContextMenuPanelItemDescriptor[] = []; @@ -88,13 +88,13 @@ async function buildEuiContextMenuPanelItems({ * @param {Embeddable} embeddable * @return {EuiContextMenuPanelItemDescriptor} */ -function convertPanelActionToContextMenuItem({ +function convertPanelActionToContextMenuItem({ action, actionContext, closeMenu, }: { - action: Action; - actionContext: ActionContext; + action: Action; + actionContext: A; closeMenu: () => void; }): EuiContextMenuPanelItemDescriptor { const menuPanelItem: EuiContextMenuPanelItemDescriptor = { diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/embeddable_panel.tsx b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/embeddable_panel.tsx index c06f4ed99e8f..172a5a76c4b2 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/embeddable_panel.tsx +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/embeddable_panel.tsx @@ -37,7 +37,7 @@ import { AddPanelAction } from './panel_header/panel_actions/add_panel/add_panel import { CustomizePanelTitleAction } from './panel_header/panel_actions/customize_title/customize_panel_action'; import { PanelHeader } from './panel_header/panel_header'; import { InspectPanelAction } from './panel_header/panel_actions/inspect_panel_action'; -import { EditPanelAction, Action, ActionContext } from '../actions'; +import { EditPanelAction, Action } from '../actions'; import { CustomizePanelModal } from './panel_header/panel_actions/customize_title/customize_panel_modal'; import { Start as InspectorStartContract } from '../../../../../../../../plugins/inspector/public'; @@ -192,7 +192,7 @@ export class EmbeddablePanel extends React.Component { }); const createGetUserData = (overlays: CoreStart['overlays']) => - async function getUserData(context: ActionContext) { + async function getUserData(context: { embeddable: IEmbeddable }) { return new Promise<{ title: string | undefined }>(resolve => { const session = overlays.openModal( { test('Is not compatible when embeddable is not a container', async () => { expect( - await action.isCompatible({ - embeddable, - }) + // @ts-ignore + await action.isCompatible({ embeddable }) ).toBe(false); }); diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.ts index 5c660f392d42..7a49927e4725 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.ts +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/add_panel/add_panel_action.ts @@ -18,14 +18,19 @@ */ import { i18n } from '@kbn/i18n'; import { ViewMode, GetEmbeddableFactory, GetEmbeddableFactories } from '../../../../types'; -import { Action, ActionContext } from '../../../../actions'; +import { Action } from '../../../../actions'; import { openAddPanelFlyout } from './open_add_panel_flyout'; import { NotificationsStart } from '../../../../../../../../../../../core/public'; import { KibanaReactOverlays } from '../../../../../../../../../../../plugins/kibana_react/public'; +import { IContainer } from '../../../../containers'; export const ADD_PANEL_ACTION_ID = 'ADD_PANEL_ACTION_ID'; -export class AddPanelAction extends Action { +interface ActionContext { + embeddable: IContainer; +} + +export class AddPanelAction extends Action { public readonly type = ADD_PANEL_ACTION_ID; constructor( diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/customize_title/customize_panel_action.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/customize_title/customize_panel_action.ts index 51001de0fefb..d91cee3048c1 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/customize_title/customize_panel_action.ts +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/customize_title/customize_panel_action.ts @@ -18,14 +18,19 @@ */ import { i18n } from '@kbn/i18n'; -import { Action, ActionContext } from '../../../../actions'; +import { Action } from '../../../../actions'; import { ViewMode } from '../../../../types'; +import { IEmbeddable } from '../../../../embeddables'; const CUSTOMIZE_PANEL_ACTION_ID = 'CUSTOMIZE_PANEL_ACTION_ID'; type GetUserData = (context: ActionContext) => Promise<{ title: string | undefined }>; -export class CustomizePanelTitleAction extends Action { +interface ActionContext { + embeddable: IEmbeddable; +} + +export class CustomizePanelTitleAction extends Action { public readonly type = CUSTOMIZE_PANEL_ACTION_ID; constructor(private readonly getDataFromUser: GetUserData) { diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/inspect_panel_action.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/inspect_panel_action.ts index 06ba48a5e23b..3e4e2a36d46b 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/inspect_panel_action.ts +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/inspect_panel_action.ts @@ -18,12 +18,17 @@ */ import { i18n } from '@kbn/i18n'; -import { Action, ActionContext } from '../../../actions'; +import { Action } from '../../../actions'; import { Start as InspectorStartContract } from '../../../../../../../../../../plugins/inspector/public'; +import { IEmbeddable } from '../../../embeddables'; export const INSPECT_PANEL_ACTION_ID = 'openInspector'; -export class InspectPanelAction extends Action { +interface ActionContext { + embeddable: IEmbeddable; +} + +export class InspectPanelAction extends Action { public readonly type = INSPECT_PANEL_ACTION_ID; constructor(private readonly inspector: InspectorStartContract) { diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/remove_panel_action.test.tsx b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/remove_panel_action.test.tsx index 6421f4e85730..22e3be89f1ae 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/remove_panel_action.test.tsx +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/remove_panel_action.test.tsx @@ -28,7 +28,7 @@ import { } from '../../../test_samples/embeddables/filterable_embeddable'; import { FilterableEmbeddableFactory } from '../../../test_samples/embeddables/filterable_embeddable_factory'; import { FilterableContainer } from '../../../test_samples/embeddables/filterable_container'; -import { GetEmbeddableFactory } from '../../../types'; +import { GetEmbeddableFactory, ViewMode } from '../../../types'; import { ContactCardEmbeddable } from '../../../test_samples/embeddables/contact_card/contact_card_embeddable'; const embeddableFactories = new Map(); @@ -45,7 +45,7 @@ beforeEach(async () => { query: { match: {} }, }; container = new FilterableContainer( - { id: 'hello', panels: {}, filters: [derivedFilter] }, + { id: 'hello', panels: {}, filters: [derivedFilter], viewMode: ViewMode.EDIT }, getFactory ); @@ -55,6 +55,7 @@ beforeEach(async () => { FilterableEmbeddable >(FILTERABLE_EMBEDDABLE, { id: '123', + viewMode: ViewMode.EDIT, }); if (isErrorEmbeddable(filterableEmbeddable)) { @@ -68,7 +69,7 @@ test('Removes the embeddable', async () => { const removePanelAction = new RemovePanelAction(); expect(container.getChild(embeddable.id)).toBeDefined(); - removePanelAction.execute({ embeddable }); + await removePanelAction.execute({ embeddable }); expect(container.getChild(embeddable.id)).toBeUndefined(); }); diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/remove_panel_action.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/remove_panel_action.ts index f8fc9d02992d..2a61857d17f7 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/remove_panel_action.ts +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/panel/panel_header/panel_actions/remove_panel_action.ts @@ -19,8 +19,9 @@ import { i18n } from '@kbn/i18n'; import { ContainerInput, IContainer } from '../../../containers'; import { ViewMode } from '../../../types'; -import { Action, ActionContext } from '../../../actions'; +import { Action } from '../../../actions'; import { IncompatibleActionError } from '../../../errors'; +import { IEmbeddable } from '../../../embeddables'; export const REMOVE_PANEL_ACTION = 'deletePanel'; @@ -28,13 +29,17 @@ interface ExpandedPanelInput extends ContainerInput { expandedPanelId: string; } +interface ActionContext { + embeddable: IEmbeddable; +} + function hasExpandedPanelInput( container: IContainer ): container is IContainer<{}, ExpandedPanelInput> { return (container as IContainer<{}, ExpandedPanelInput>).getInput().expandedPanelId !== undefined; } -export class RemovePanelAction extends Action { +export class RemovePanelAction extends Action { public readonly type = REMOVE_PANEL_ACTION; constructor() { super(REMOVE_PANEL_ACTION); @@ -63,8 +68,8 @@ export class RemovePanelAction extends Action { ); } - public execute({ embeddable }: ActionContext) { - if (!embeddable.parent || !this.isCompatible({ embeddable })) { + public async execute({ embeddable }: ActionContext) { + if (!embeddable.parent || !(await this.isCompatible({ embeddable }))) { throw new IncompatibleActionError(); } embeddable.parent.removeEmbeddable(embeddable.id); diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/edit_mode_action.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/edit_mode_action.ts index d2e893887808..f87ff835f59c 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/edit_mode_action.ts +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/edit_mode_action.ts @@ -18,11 +18,15 @@ */ import { ViewMode } from '../../types'; -import { Action, ActionContext } from '../../actions'; +import { Action } from '../../actions'; +import { IEmbeddable } from '../../embeddables'; export const EDIT_MODE_ACTION = 'EDIT_MODE_ACTION'; -export class EditModeAction extends Action { +interface ActionContext { + embeddable: IEmbeddable; +} +export class EditModeAction extends Action { public readonly type = EDIT_MODE_ACTION; constructor() { @@ -37,7 +41,7 @@ export class EditModeAction extends Action { return context.embeddable.getInput().viewMode === ViewMode.EDIT; } - execute() { + async execute() { return; } } diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/hello_world_action.tsx b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/hello_world_action.tsx index bfd7ac6541f0..356679b5e450 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/hello_world_action.tsx +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/hello_world_action.tsx @@ -35,7 +35,7 @@ export class HelloWorldAction extends Action { return 'Hello World Action!'; } - public execute() { + public async execute() { const flyoutSession = this.overlays.openFlyout( flyoutSession && flyoutSession.close()}> Hello World, I am a hello world action! diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/restricted_action.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/restricted_action.ts index 950b843816c7..16aede6da18d 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/restricted_action.ts +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/restricted_action.ts @@ -17,15 +17,15 @@ * under the License. */ -import { Action, ActionContext } from '../../actions'; +import { Action } from '../../actions'; export const RESTRICTED_ACTION = 'RESTRICTED_ACTION'; -export class RestrictedAction extends Action { +export class RestrictedAction extends Action { public readonly type = RESTRICTED_ACTION; - private isCompatibleFn: (context: ActionContext) => boolean; - constructor(isCompatible: (context: ActionContext) => boolean) { + private isCompatibleFn: (context: A) => boolean; + constructor(isCompatible: (context: A) => boolean) { super(RESTRICTED_ACTION); this.isCompatibleFn = isCompatible; } @@ -34,9 +34,9 @@ export class RestrictedAction extends Action { return `I am only sometimes compatible`; } - async isCompatible(context: ActionContext) { + async isCompatible(context: A) { return this.isCompatibleFn(context); } - execute() {} + async execute() {} } diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/say_hello_action.tsx b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/say_hello_action.tsx index e64d0e8cec58..1a884148498a 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/say_hello_action.tsx +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/say_hello_action.tsx @@ -17,7 +17,7 @@ * under the License. */ -import { Action, ActionContext } from '../../actions'; +import { Action } from '../../actions'; import { EmbeddableInput, Embeddable, EmbeddableOutput, IEmbeddable } from '../../embeddables'; import { IncompatibleActionError } from '../../errors'; @@ -36,7 +36,12 @@ export function hasFullNameOutput( ); } -export class SayHelloAction extends Action { +interface ActionContext { + embeddable: Embeddable; + message?: string; +} + +export class SayHelloAction extends Action { public readonly type = SAY_HELLO_ACTION; private sayHello: (name: string) => void; @@ -53,9 +58,7 @@ export class SayHelloAction extends Action { // Can use typescript generics to get compiler time warnings for immediate feedback if // the context is not compatible. - async isCompatible( - context: ActionContext> - ) { + async isCompatible(context: ActionContext) { // Option 1: only compatible with Greeting Embeddables. // return context.embeddable.type === CONTACT_CARD_EMBEDDABLE; @@ -63,20 +66,15 @@ export class SayHelloAction extends Action { return hasFullNameOutput(context.embeddable); } - async execute( - context: ActionContext< - Embeddable, - { message?: string } - > - ) { + async execute(context: ActionContext) { if (!(await this.isCompatible(context))) { throw new IncompatibleActionError(); } const greeting = `Hello, ${context.embeddable.getOutput().fullName}`; - if (context.triggerContext && context.triggerContext.message) { - this.sayHello(`${greeting}. ${context.triggerContext.message}`); + if (context.message) { + this.sayHello(`${greeting}. ${context.message}`); } else { this.sayHello(greeting); } diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/send_message_action.tsx b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/send_message_action.tsx index 9ac823272529..0f54f80398f2 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/send_message_action.tsx +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/test_samples/actions/send_message_action.tsx @@ -18,7 +18,7 @@ */ import React from 'react'; import { EuiFlyoutBody } from '@elastic/eui'; -import { Action, ActionContext, IncompatibleActionError } from '../..'; +import { Action, IncompatibleActionError } from '../..'; import { Embeddable, EmbeddableInput } from '../../embeddables'; import { GetMessageModal } from './get_message_modal'; import { FullNameEmbeddableOutput, hasFullNameOutput } from './say_hello_action'; @@ -26,6 +26,10 @@ import { CoreStart } from '../../../../../../../../../core/public'; export const SEND_MESSAGE_ACTION = 'SEND_MESSAGE_ACTION'; +interface ActionContext { + embeddable: Embeddable; + message: string; +} export class SendMessageAction extends Action { public readonly type = SEND_MESSAGE_ACTION; @@ -37,28 +41,18 @@ export class SendMessageAction extends Action { return 'Send message'; } - async isCompatible( - context: ActionContext> - ) { + async isCompatible(context: ActionContext) { return hasFullNameOutput(context.embeddable); } - async sendMessage( - context: ActionContext>, - message: string - ) { + async sendMessage(context: ActionContext, message: string) { const greeting = `Hello, ${context.embeddable.getOutput().fullName}`; const content = message ? `${greeting}. ${message}` : greeting; this.overlays.openFlyout({content}); } - async execute( - context: ActionContext< - Embeddable, - { message?: string } - > - ) { + async execute(context: ActionContext) { if (!(await this.isCompatible(context))) { throw new IncompatibleActionError(); } diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/types.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/types.ts index 9d10a0f059f3..925afe07ff53 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/types.ts +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/types.ts @@ -17,9 +17,7 @@ * under the License. */ -import { Action, ActionContext } from './actions'; -import { IEmbeddable } from './embeddables'; -import { IContainer } from './containers'; +import { Action } from './actions'; import { EmbeddableFactory } from './embeddables/embeddable_factory'; import { Adapters } from '../../../../../../../plugins/inspector/public'; @@ -55,18 +53,10 @@ export interface SavedObjectMetaData { showSavedObject?(savedObject: any): any; } -export interface TriggerContext { - embeddable: IEmbeddable; - container?: IContainer; -} - -export type ExecuteTriggerActions = ( +export type ExecuteTriggerActions = (triggerId: string, actionContext: A) => Promise; +export type GetActionsCompatibleWithTrigger = ( triggerId: string, - actionContext: ActionContext -) => Promise; -export type GetActionsCompatibleWithTrigger = ( - triggerId: string, - context: TriggerContext + context: C ) => Promise; export type GetEmbeddableFactory = (id: string) => EmbeddableFactory | undefined; export type GetEmbeddableFactories = () => IterableIterator; diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/tests/apply_filter_action.test.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/tests/apply_filter_action.test.ts index 7cd56290bf78..6e5d2182b706 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/tests/apply_filter_action.test.ts +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/tests/apply_filter_action.test.ts @@ -85,7 +85,7 @@ test('ApplyFilterAction applies the filter to the root of the container tree', a query: { match: { extension: { query: 'foo' } } }, }; - applyFilterAction.execute({ embeddable, triggerContext: { filters: [filter] } }); + await applyFilterAction.execute({ embeddable, filters: [filter] }); expect(root.getInput().filters.length).toBe(1); expect(node1.getInput().filters.length).toBe(1); expect(embeddable.getInput().filters.length).toBe(1); @@ -124,6 +124,7 @@ test('ApplyFilterAction is incompatible if the root container does not accept a throw new Error(); } + // @ts-ignore expect(await applyFilterAction.isCompatible({ embeddable })).toBe(false); }); @@ -160,6 +161,7 @@ test('trying to execute on incompatible context throws an error ', async () => { } async function check() { + // @ts-ignore await applyFilterAction.execute({ embeddable }); } await expect(check()).rejects.toThrow(Error); diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/tests/execute_trigger_actions.test.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/tests/execute_trigger_actions.test.ts index a2406a548b0c..1b5a80af5298 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/tests/execute_trigger_actions.test.ts +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/tests/execute_trigger_actions.test.ts @@ -19,7 +19,7 @@ import { testPlugin, TestPluginReturn } from './test_plugin'; import { of } from './helpers'; -import { ActionContext, Action, openContextMenu } from '../lib'; +import { Action, openContextMenu, IEmbeddable } from '../lib'; import { ContactCardEmbeddable, CONTACT_USER_TRIGGER, @@ -31,11 +31,11 @@ jest.mock('../lib/context_menu_actions'); const executeFn = jest.fn(); const openContextMenuSpy = (openContextMenu as any) as jest.SpyInstance; -class TestAction extends Action { +class TestAction extends Action { public readonly type = 'testAction'; - public checkCompatibility: (context: ActionContext) => boolean; + public checkCompatibility: (context: A) => boolean; - constructor(id: string, checkCompatibility: (context: ActionContext) => boolean) { + constructor(id: string, checkCompatibility: (context: A) => boolean) { super(id); this.checkCompatibility = checkCompatibility; } @@ -44,11 +44,11 @@ class TestAction extends Action { return 'test'; } - async isCompatible(context: ActionContext) { + async isCompatible(context: A) { return this.checkCompatibility(context); } - execute(context: ActionContext) { + async execute(context: unknown) { executeFn(context); } } @@ -124,7 +124,10 @@ test('does not execute an incompatible action', async () => { title: 'My trigger', actionIds: ['test1'], }; - const action = new TestAction('test1', ({ embeddable }) => embeddable.id === 'executeme'); + const action = new TestAction<{ embeddable: IEmbeddable }>( + 'test1', + ({ embeddable }) => embeddable.id === 'executeme' + ); const embeddable = new ContactCardEmbeddable( { id: 'executeme', @@ -187,7 +190,7 @@ test('passes whole action context to isCompatible()', async () => { title: 'My trigger', actionIds: ['test'], }; - const action = new TestAction('test', ({ triggerContext }) => { + const action = new TestAction<{ triggerContext: any }>('test', ({ triggerContext }) => { expect(triggerContext).toEqual({ foo: 'bar', }); diff --git a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/tests/get_trigger_compatible_actions.test.ts b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/tests/get_trigger_compatible_actions.test.ts index ba926458cce1..f70bfcb080ae 100644 --- a/src/legacy/core_plugins/embeddable_api/public/np_ready/public/tests/get_trigger_compatible_actions.test.ts +++ b/src/legacy/core_plugins/embeddable_api/public/np_ready/public/tests/get_trigger_compatible_actions.test.ts @@ -22,7 +22,7 @@ import { HelloWorldAction } from '../lib/test_samples/actions/hello_world_action import { SayHelloAction } from '../lib/test_samples/actions/say_hello_action'; import { RestrictedAction } from '../lib/test_samples/actions/restricted_action'; import { EmptyEmbeddable } from '../lib/test_samples/embeddables/empty_embeddable'; -import { ActionContext, CONTEXT_MENU_TRIGGER } from '../lib'; +import { CONTEXT_MENU_TRIGGER, IEmbeddable } from '../lib'; import { of } from './helpers'; let action: SayHelloAction; @@ -73,7 +73,7 @@ test('getTriggerCompatibleActions returns attached actions', async () => { test('filters out actions not applicable based on the context', async () => { const { setup, doStart } = embeddables; - const restrictedAction = new RestrictedAction((context: ActionContext) => { + const restrictedAction = new RestrictedAction<{ embeddable: IEmbeddable }>(context => { return context.embeddable.id === 'accept'; }); diff --git a/src/legacy/core_plugins/kibana/public/discover/doc_table/components/table_row/cell.html b/src/legacy/core_plugins/kibana/public/discover/doc_table/components/table_row/cell.html index cea571221965..77702ed60647 100644 --- a/src/legacy/core_plugins/kibana/public/discover/doc_table/components/table_row/cell.html +++ b/src/legacy/core_plugins/kibana/public/discover/doc_table/components/table_row/cell.html @@ -17,6 +17,7 @@ if (timefield) { class="fa fa-search-plus kbnDocTableRowFilterButton" data-column="<%- column %>" tooltip-append-to-body="1" + data-test-subj="docTableCellFilter" tooltip="{{ ::'kbn.docTable.tableRow.filterForValueButtonTooltip' | i18n: {defaultMessage: 'Filter for value'} }}" aria-label="{{ ::'kbn.docTable.tableRow.filterForValueButtonAriaLabel' | i18n: {defaultMessage: 'Filter for value'} }}" > @@ -25,6 +26,7 @@ if (timefield) { ng-click="inlineFilter($event, '-')" class="fa fa-search-minus kbnDocTableRowFilterButton" data-column="<%- column %>" + data-test-subj="docTableCellFilterNegate" tooltip="{{ ::'kbn.docTable.tableRow.filterOutValueButtonTooltip' | i18n: {defaultMessage: 'Filter out value'} }}" aria-label="{{ ::'kbn.docTable.tableRow.filterOutValueButtonAriaLabel' | i18n: {defaultMessage: 'Filter out value'} }}" tooltip-append-to-body="1" diff --git a/src/legacy/core_plugins/kibana/public/discover/embeddable/search_embeddable.ts b/src/legacy/core_plugins/kibana/public/discover/embeddable/search_embeddable.ts index c7a17146e6d1..e307d5da7ebe 100644 --- a/src/legacy/core_plugins/kibana/public/discover/embeddable/search_embeddable.ts +++ b/src/legacy/core_plugins/kibana/public/discover/embeddable/search_embeddable.ts @@ -257,9 +257,7 @@ export class SearchEmbeddable extends Embeddable await this.executeTriggerActions(APPLY_FILTER_TRIGGER, { embeddable: this, - triggerContext: { - filters, - }, + filters, }); }; } diff --git a/test/functional/apps/dashboard/dashboard_filter_bar.js b/test/functional/apps/dashboard/dashboard_filter_bar.js index 312066000c63..a48393e11b19 100644 --- a/test/functional/apps/dashboard/dashboard_filter_bar.js +++ b/test/functional/apps/dashboard/dashboard_filter_bar.js @@ -133,10 +133,10 @@ export default function ({ getService, getPageObjects }) { await PageObjects.dashboard.setTimepickerInDataRange(); }); - it('are added when pie chart legend item is clicked', async function () { - await dashboardAddPanel.addVisualization('Rendering Test: pie'); + it('are added when a cell magnifying glass is clicked', async function () { + await dashboardAddPanel.addSavedSearch('Rendering-Test:-saved-search'); await PageObjects.dashboard.waitForRenderComplete(); - await pieChart.filterByLegendItem('4,886'); + await testSubjects.click('docTableCellFilter'); const filterCount = await filterBar.getFilterCount(); expect(filterCount).to.equal(1); diff --git a/test/plugin_functional/plugins/kbn_tp_sample_panel_action/public/sample_panel_action.tsx b/test/plugin_functional/plugins/kbn_tp_sample_panel_action/public/sample_panel_action.tsx index e5872a95e0f6..79d17f43a4ff 100644 --- a/test/plugin_functional/plugins/kbn_tp_sample_panel_action/public/sample_panel_action.tsx +++ b/test/plugin_functional/plugins/kbn_tp_sample_panel_action/public/sample_panel_action.tsx @@ -22,12 +22,16 @@ import { npStart } from 'ui/new_platform'; import { Action, - ActionContext, CONTEXT_MENU_TRIGGER, + IEmbeddable, } from '../../../../../src/legacy/core_plugins/embeddable_api/public/np_ready/public'; import { setup } from '../../../../../src/legacy/core_plugins/embeddable_api/public/np_ready/public/legacy'; -class SamplePanelAction extends Action { +interface ActionContext { + embeddable: IEmbeddable; +} + +class SamplePanelAction extends Action { public readonly type = 'samplePanelAction'; constructor() { @@ -38,7 +42,7 @@ class SamplePanelAction extends Action { return 'Sample Panel Action'; } - public execute = ({ embeddable }: ActionContext) => { + public execute = async ({ embeddable }: ActionContext) => { if (!embeddable) { return; } diff --git a/test/plugin_functional/plugins/kbn_tp_sample_panel_action/public/sample_panel_link.ts b/test/plugin_functional/plugins/kbn_tp_sample_panel_action/public/sample_panel_link.ts index faac3c60b96c..75897d1b794b 100644 --- a/test/plugin_functional/plugins/kbn_tp_sample_panel_action/public/sample_panel_link.ts +++ b/test/plugin_functional/plugins/kbn_tp_sample_panel_action/public/sample_panel_link.ts @@ -33,7 +33,7 @@ class SamplePanelLink extends Action { return 'Sample panel Link'; } - public execute() { + public async execute() { return; } diff --git a/x-pack/legacy/plugins/advanced_ui_actions/public/np_ready/public/custom_time_range_action.test.ts b/x-pack/legacy/plugins/advanced_ui_actions/public/np_ready/public/custom_time_range_action.test.ts index f553ac1c0b2d..a2d20399ec6c 100644 --- a/x-pack/legacy/plugins/advanced_ui_actions/public/np_ready/public/custom_time_range_action.test.ts +++ b/x-pack/legacy/plugins/advanced_ui_actions/public/np_ready/public/custom_time_range_action.test.ts @@ -339,6 +339,7 @@ test('Attempting to execute on incompatible embeddable throws an error', async ( }); async function check() { + // @ts-ignore await action.execute({ embeddable: child }); } await expect(check()).rejects.toThrow(Error); diff --git a/x-pack/legacy/plugins/advanced_ui_actions/public/np_ready/public/custom_time_range_action.tsx b/x-pack/legacy/plugins/advanced_ui_actions/public/np_ready/public/custom_time_range_action.tsx index ae3cbbc05911..83675af94a5a 100644 --- a/x-pack/legacy/plugins/advanced_ui_actions/public/np_ready/public/custom_time_range_action.tsx +++ b/x-pack/legacy/plugins/advanced_ui_actions/public/np_ready/public/custom_time_range_action.tsx @@ -14,7 +14,6 @@ import { VISUALIZE_EMBEDDABLE_TYPE } from '../../../../../../../src/legacy/core_ import { Action, IEmbeddable, - ActionContext, IncompatibleActionError, Embeddable, EmbeddableInput, @@ -41,7 +40,11 @@ function isVisualizeEmbeddable( return embeddable.type === VISUALIZE_EMBEDDABLE_TYPE; } -export class CustomTimeRangeAction extends Action { +interface ActionContext { + embeddable: Embeddable; +} + +export class CustomTimeRangeAction extends Action { public readonly type = CUSTOM_TIME_RANGE; private openModal: OpenModal; private dateFormat?: string; @@ -76,10 +79,11 @@ export class CustomTimeRangeAction extends Action { public async isCompatible({ embeddable }: ActionContext) { const isInputControl = isVisualizeEmbeddable(embeddable) && - embeddable.getOutput().visTypeName === 'input_control_vis'; + (embeddable as VisualizeEmbeddable).getOutput().visTypeName === 'input_control_vis'; const isMarkdown = - isVisualizeEmbeddable(embeddable) && embeddable.getOutput().visTypeName === 'markdown'; + isVisualizeEmbeddable(embeddable) && + (embeddable as VisualizeEmbeddable).getOutput().visTypeName === 'markdown'; return Boolean( embeddable && hasTimeRange(embeddable) && diff --git a/x-pack/legacy/plugins/advanced_ui_actions/public/np_ready/public/custom_time_range_badge.tsx b/x-pack/legacy/plugins/advanced_ui_actions/public/np_ready/public/custom_time_range_badge.tsx index 537ac498a7da..70cd74eb79d0 100644 --- a/x-pack/legacy/plugins/advanced_ui_actions/public/np_ready/public/custom_time_range_badge.tsx +++ b/x-pack/legacy/plugins/advanced_ui_actions/public/np_ready/public/custom_time_range_badge.tsx @@ -11,7 +11,6 @@ import { TimeRange } from '../../../../../../../src/plugins/data/public'; import { Action, IEmbeddable, - ActionContext, IncompatibleActionError, Embeddable, EmbeddableInput, @@ -33,7 +32,11 @@ function hasTimeRange( return (embeddable as Embeddable).getInput().timeRange !== undefined; } -export class CustomTimeRangeBadge extends Action { +interface ActionContext { + embeddable: Embeddable; +} + +export class CustomTimeRangeBadge extends Action { public readonly type = CUSTOM_TIME_RANGE_BADGE; private openModal: OpenModal; private dateFormat: string; @@ -55,7 +58,7 @@ export class CustomTimeRangeBadge extends Action { this.commonlyUsedRanges = commonlyUsedRanges; } - public getDisplayName({ embeddable }: ActionContext>) { + public getDisplayName({ embeddable }: ActionContext) { return prettyDuration( embeddable.getInput().timeRange.from, embeddable.getInput().timeRange.to, diff --git a/x-pack/legacy/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx b/x-pack/legacy/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx index cc182b817339..c1812cb40cf2 100644 --- a/x-pack/legacy/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx +++ b/x-pack/legacy/plugins/reporting/public/panel_actions/get_csv_panel_action.tsx @@ -15,7 +15,6 @@ import { EuiIcon } from '@elastic/eui'; import { Action, - ActionContext, ViewMode, IncompatibleActionError, IEmbeddable, @@ -37,7 +36,12 @@ function isSavedSearchEmbeddable( ): embeddable is ISearchEmbeddable { return embeddable.type === SEARCH_EMBEDDABLE_TYPE; } -class GetCsvReportPanelAction extends Action { + +interface ActionContext { + embeddable: ISearchEmbeddable; +} + +class GetCsvReportPanelAction extends Action { private isDownloading: boolean; public readonly type = CSV_REPORTING_ACTION; @@ -82,7 +86,7 @@ class GetCsvReportPanelAction extends Action { return embeddable.getInput().viewMode !== ViewMode.EDIT && embeddable.type === 'search'; }; - public execute = async (context: ActionContext) => { + public execute = async (context: ActionContext) => { const { embeddable } = context; if (!isSavedSearchEmbeddable(embeddable)) { diff --git a/x-pack/legacy/plugins/siem/public/components/embeddables/actions/apply_siem_filter_action.test.tsx b/x-pack/legacy/plugins/siem/public/components/embeddables/actions/apply_siem_filter_action.test.tsx index 41ed7c9359ca..731cc034f977 100644 --- a/x-pack/legacy/plugins/siem/public/components/embeddables/actions/apply_siem_filter_action.test.tsx +++ b/x-pack/legacy/plugins/siem/public/components/embeddables/actions/apply_siem_filter_action.test.tsx @@ -29,10 +29,6 @@ const isEmbeddable = ( return get('type', embeddable) != null; }; -const isTriggerContext = (triggerContext: unknown): triggerContext is { filters: Filter[] } => { - return typeof triggerContext === 'object'; -}; - describe('ApplySiemFilterAction', () => { let applyFilterQueryFromKueryExpression: (expression: string) => void; @@ -57,7 +53,7 @@ describe('ApplySiemFilterAction', () => { }); describe('#isCompatible', () => { - test('when embeddable type is MAP_SAVED_OBJECT_TYPE and triggerContext filters exist, returns true', async () => { + test('when embeddable type is MAP_SAVED_OBJECT_TYPE and filters exist, returns true', async () => { const action = new ApplySiemFilterAction({ applyFilterQueryFromKueryExpression }); const embeddable = { type: MAP_SAVED_OBJECT_TYPE, @@ -65,9 +61,7 @@ describe('ApplySiemFilterAction', () => { if (isEmbeddable(embeddable)) { const result = await action.isCompatible({ embeddable, - triggerContext: { - filters: [], - }, + filters: [], }); expect(result).toBe(true); } else { @@ -75,7 +69,7 @@ describe('ApplySiemFilterAction', () => { } }); - test('when embeddable type is MAP_SAVED_OBJECT_TYPE and triggerContext does not exist, returns false', async () => { + test('when embeddable type is MAP_SAVED_OBJECT_TYPE and filters do not exist, returns false', async () => { const action = new ApplySiemFilterAction({ applyFilterQueryFromKueryExpression }); const embeddable = { type: MAP_SAVED_OBJECT_TYPE, @@ -83,30 +77,14 @@ describe('ApplySiemFilterAction', () => { if (isEmbeddable(embeddable)) { const result = await action.isCompatible({ embeddable, - }); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any); expect(result).toBe(false); } else { throw new Error('Invalid embeddable in unit test'); } }); - test('when embeddable type is MAP_SAVED_OBJECT_TYPE and triggerContext filters do not exist, returns false', async () => { - const action = new ApplySiemFilterAction({ applyFilterQueryFromKueryExpression }); - const embeddable = { - type: MAP_SAVED_OBJECT_TYPE, - }; - const triggerContext = {}; - if (isEmbeddable(embeddable) && isTriggerContext(triggerContext)) { - const result = await action.isCompatible({ - embeddable, - triggerContext, - }); - expect(result).toBe(false); - } else { - throw new Error('Invalid embeddable/triggerContext in unit test'); - } - }); - test('when embeddable type is not MAP_SAVED_OBJECT_TYPE, returns false', async () => { const action = new ApplySiemFilterAction({ applyFilterQueryFromKueryExpression }); const embeddable = { @@ -115,9 +93,7 @@ describe('ApplySiemFilterAction', () => { if (isEmbeddable(embeddable)) { const result = await action.isCompatible({ embeddable, - triggerContext: { - filters: [], - }, + filters: [], }); expect(result).toBe(false); } else { @@ -136,7 +112,8 @@ describe('ApplySiemFilterAction', () => { const error = expectError(() => action.execute({ embeddable, - }) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any) ); expect(error).toBeInstanceOf(Error); } else { @@ -152,24 +129,27 @@ describe('ApplySiemFilterAction', () => { query: { query: '' }, }), }; - const triggerContext = { - filters: [ - { - query: { - match: { - 'host.name': { - query: 'zeek-newyork-sha-aa8df15', - type: 'phrase', - }, + const filters: Filter[] = [ + { + query: { + match: { + 'host.name': { + query: 'zeek-newyork-sha-aa8df15', + type: 'phrase', }, }, }, - ], - }; - if (isEmbeddable(embeddable) && isTriggerContext(triggerContext)) { + meta: { + disabled: false, + negate: false, + alias: '', + }, + }, + ]; + if (isEmbeddable(embeddable)) { await action.execute({ embeddable, - triggerContext, + filters, }); expect( @@ -177,7 +157,7 @@ describe('ApplySiemFilterAction', () => { .calls[0][0] ).toBe('host.name: "zeek-newyork-sha-aa8df15"'); } else { - throw new Error('Invalid embeddable/triggerContext in unit test'); + throw new Error('Invalid embeddable in unit test'); } }); }); diff --git a/x-pack/legacy/plugins/siem/public/components/embeddables/actions/apply_siem_filter_action.tsx b/x-pack/legacy/plugins/siem/public/components/embeddables/actions/apply_siem_filter_action.tsx index 875b8a4fe172..961ae1207df2 100644 --- a/x-pack/legacy/plugins/siem/public/components/embeddables/actions/apply_siem_filter_action.tsx +++ b/x-pack/legacy/plugins/siem/public/components/embeddables/actions/apply_siem_filter_action.tsx @@ -9,15 +9,17 @@ import { getOr } from 'lodash/fp'; import { i18n } from '@kbn/i18n'; // @ts-ignore Missing type defs as maps moves to Typescript import { MAP_SAVED_OBJECT_TYPE } from '../../../../../maps/common/constants'; -import { - Action, - ActionContext, -} from '../../../../../../../../src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions'; +import { Action } from '../../../../../../../../src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/actions'; import { IEmbeddable } from '../../../../../../../../src/legacy/core_plugins/embeddable_api/public/np_ready/public/lib/embeddables'; export const APPLY_SIEM_FILTER_ACTION_ID = 'APPLY_SIEM_FILTER_ACTION_ID'; -export class ApplySiemFilterAction extends Action { +interface ActionContext { + embeddable: IEmbeddable; + filters: Filter[]; +} + +export class ApplySiemFilterAction extends Action { public readonly type = APPLY_SIEM_FILTER_ACTION_ID; private readonly applyFilterQueryFromKueryExpression: (expression: string) => void; @@ -36,26 +38,17 @@ export class ApplySiemFilterAction extends Action { }); } - public async isCompatible( - context: ActionContext - ): Promise { - return ( - context.embeddable.type === MAP_SAVED_OBJECT_TYPE && - context.triggerContext != null && - context.triggerContext.filters !== undefined - ); + public async isCompatible(context: ActionContext): Promise { + return context.embeddable.type === MAP_SAVED_OBJECT_TYPE && context.filters !== undefined; } - public execute({ - embeddable, - triggerContext, - }: ActionContext) { - if (!triggerContext) { + public async execute({ embeddable, filters }: ActionContext) { + if (!filters) { throw new Error('Applying a filter requires a filter as context'); } // Parse queryExpression from queryDSL and apply to SIEM global KQL Bar via redux - const filterObject = getOr(null, 'filters[0].query.match', triggerContext); + const filterObject = getOr(null, '[0].query.match', filters); if (filterObject != null) { const filterQuery = getOr('', 'query.query', embeddable.getInput());