From 8ade18a82dcaa91057112c25bcd45bcfe26ac790 Mon Sep 17 00:00:00 2001 From: streamich Date: Mon, 16 Mar 2020 10:47:50 +0100 Subject: [PATCH 1/5] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20hide=20"Create=20dri?= =?UTF-8?q?lldown"=20from=20context=20menu=20when=20needed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../actions/flyout_create_drilldown/index.tsx | 21 ++++++++++++------- .../dashboard_drilldowns_services.ts | 3 +-- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/index.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/index.tsx index a6be110c44a02..9ef9800ab90e6 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/index.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/actions/flyout_create_drilldown/index.tsx @@ -9,15 +9,11 @@ import { i18n } from '@kbn/i18n'; import { CoreStart } from 'src/core/public'; import { ActionByType } from '../../../../../../../../src/plugins/ui_actions/public'; import { toMountPoint } from '../../../../../../../../src/plugins/kibana_react/public'; -import { IEmbeddable } from '../../../../../../../../src/plugins/embeddable/public'; import { DrilldownsStartContract } from '../../../../../../drilldowns/public'; +import { EmbeddableContext } from '../../../../../../../../src/plugins/embeddable/public'; export const OPEN_FLYOUT_ADD_DRILLDOWN = 'OPEN_FLYOUT_ADD_DRILLDOWN'; -export interface FlyoutCreateDrilldownActionContext { - embeddable: IEmbeddable; -} - export interface OpenFlyoutAddDrilldownParams { overlays: () => Promise; drilldowns: () => Promise; @@ -40,14 +36,23 @@ export class FlyoutCreateDrilldownAction implements ActionByType -1; } - public async execute(context: FlyoutCreateDrilldownActionContext) { + public async isCompatible(context: EmbeddableContext) { + const isEditMode = context.embeddable.getInput().viewMode === 'edit'; + return isEditMode && this.isEmbeddableCompatible(context); + } + + public async execute(context: EmbeddableContext) { const overlays = await this.params.overlays(); const drilldowns = await this.params.drilldowns(); const dynamicActionManager = context.embeddable.dynamicActions; + if (!dynamicActionManager) { throw new Error(`Can't execute FlyoutCreateDrilldownAction without dynamicActionsManager`); } diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts index ed0cb425ee106..6695811500e73 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_drilldowns_services.ts @@ -12,7 +12,6 @@ import { } from '../../../../../../src/plugins/embeddable/public'; import { FlyoutCreateDrilldownAction, - FlyoutCreateDrilldownActionContext, FlyoutEditDrilldownAction, OPEN_FLYOUT_ADD_DRILLDOWN, OPEN_FLYOUT_EDIT_DRILLDOWN, @@ -22,7 +21,7 @@ import { DashboardToDashboardDrilldown } from './dashboard_to_dashboard_drilldow declare module '../../../../../../src/plugins/ui_actions/public' { export interface ActionContextMapping { - [OPEN_FLYOUT_ADD_DRILLDOWN]: FlyoutCreateDrilldownActionContext; + [OPEN_FLYOUT_ADD_DRILLDOWN]: EmbeddableContext; [OPEN_FLYOUT_EDIT_DRILLDOWN]: EmbeddableContext; } } From 77cc530b74f1a5ec32a6884ae4d48432f86c93db Mon Sep 17 00:00:00 2001 From: streamich Date: Mon, 16 Mar 2020 11:05:28 +0100 Subject: [PATCH 2/5] =?UTF-8?q?style:=20=F0=9F=92=84=20remove=20AnyDrilldo?= =?UTF-8?q?wn=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../drilldown.tsx | 5 ----- .../public/services/drilldown_service.ts | 4 ++-- x-pack/plugins/drilldowns/public/types.ts | 20 +++++++++++++++---- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx index 211a16451b30c..e80f4a24a56de 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/drilldown.tsx @@ -13,11 +13,6 @@ import { DASHBOARD_TO_DASHBOARD_DRILLDOWN } from './constants'; import { DrilldownsDrilldown as Drilldown } from '../../../../../drilldowns/public'; import { txtGoToDashboard } from './i18n'; -export const dashboards = [ - { id: 'dashboard1', title: 'Dashboard 1' }, - { id: 'dashboard2', title: 'Dashboard 2' }, -]; - export interface Params { savedObjects: () => Promise; } diff --git a/x-pack/plugins/drilldowns/public/services/drilldown_service.ts b/x-pack/plugins/drilldowns/public/services/drilldown_service.ts index e258319a16b70..6c628abe59755 100644 --- a/x-pack/plugins/drilldowns/public/services/drilldown_service.ts +++ b/x-pack/plugins/drilldowns/public/services/drilldown_service.ts @@ -6,7 +6,7 @@ import { CoreSetup } from 'src/core/public'; import { AdvancedUiActionsSetup } from '../../../advanced_ui_actions/public'; -import { AnyDrilldown } from '../types'; +import { Drilldown } from '../types'; // TODO: MOCK DATA import { @@ -23,7 +23,7 @@ export interface DrilldownServiceSetupContract { /** * Convenience method to register a drilldown. */ - registerDrilldown: (drilldown: AnyDrilldown) => void; + registerDrilldown: (drilldown: Drilldown) => void; } export class DrilldownService { diff --git a/x-pack/plugins/drilldowns/public/types.ts b/x-pack/plugins/drilldowns/public/types.ts index 4c5cfa2e596aa..b61696720ec54 100644 --- a/x-pack/plugins/drilldowns/public/types.ts +++ b/x-pack/plugins/drilldowns/public/types.ts @@ -8,11 +8,11 @@ import { AdvancedUiActionsActionFactoryDefinition as ActionFactoryDefinition } f export interface Drilldown< Config extends object = object, - FactoryContext extends object = object, + CreationContext extends object = object, ExecutionContext extends object = object > extends Pick< - ActionFactoryDefinition, + ActionFactoryDefinition, 'id' | 'createConfig' | 'CollectConfig' | 'isConfigValid' | 'getDisplayName' > { /** @@ -26,6 +26,20 @@ export interface Drilldown< */ euiIcon?: string; + /** + * Whether this drilldown should be considered for execution given `config` + * and `context`. When multiple drilldowns are attached to the same trigger + * user is presented with a context menu to pick on drilldown to execute. If + * this method returns `true` this trigger will appear in the context menu + * list, if `false`, it will not be presented to the user. If `doExecute` is + * not implemented, this drilldown will always be show to the user. + * + * @param config Config object that user configured this drilldown with. + * @param context Object that represents context in which the underlying + * `UIAction` of this drilldown is being executed in. + */ + doExecute?(config: Config, context: ExecutionContext): Promise; + /** * Implements the "navigation" action when user clicks something in the UI and * instance of this drilldown is triggered. @@ -36,5 +50,3 @@ export interface Drilldown< */ execute(config: Config, context: ExecutionContext): void; } - -export type AnyDrilldown = Drilldown; From e23f6a813290990f5d81769d8fb8a55256f1c89f Mon Sep 17 00:00:00 2001 From: streamich Date: Mon, 16 Mar 2020 13:31:55 +0100 Subject: [PATCH 3/5] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20add=20drilldown=20fa?= =?UTF-8?q?ctory=20context?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/ui_actions/public/index.ts | 9 +- .../public/service/ui_actions_service.ts | 12 ++- .../dashboard_to_dashboard_drilldown/types.ts | 7 +- .../public/services/drilldown_service.ts | 50 ++++++---- x-pack/plugins/drilldowns/public/types.ts | 95 +++++++++++++++++-- 5 files changed, 137 insertions(+), 36 deletions(-) diff --git a/src/plugins/ui_actions/public/index.ts b/src/plugins/ui_actions/public/index.ts index e0ac61a55081b..f674179a217aa 100644 --- a/src/plugins/ui_actions/public/index.ts +++ b/src/plugins/ui_actions/public/index.ts @@ -28,14 +28,15 @@ export { UiActionsSetup, UiActionsStart } from './plugin'; export { UiActionsServiceParams, UiActionsService } from './service'; export { Action, - createAction, - IncompatibleActionError, ActionDefinition as UiActionsActionDefinition, + ActionFactoryDefinition as UiActionsActionFactoryDefinition, ActionInternal as UiActionsActionInternal, ActionStorage as UiActionsActionStorage, - SerializedEvent as UiActionsSerializedEvent, - SerializedAction as UiActionsSerializedAction, + createAction, DynamicActionManager, + IncompatibleActionError, + SerializedAction as UiActionsSerializedAction, + SerializedEvent as UiActionsSerializedEvent, } from './actions'; export { buildContextMenuForActions, contextMenuSeparatorAction } from './context_menu'; export { 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 824be69a991a8..deacf61af41a8 100644 --- a/src/plugins/ui_actions/public/service/ui_actions_service.ts +++ b/src/plugins/ui_actions/public/service/ui_actions_service.ts @@ -273,14 +273,20 @@ export class UiActionsService { * Register an action factory. Action factories are used to configure and * serialize/deserialize dynamic actions. */ - public readonly registerActionFactory = (definition: ActionFactoryDefinition) => { + public readonly registerActionFactory = < + Config extends object = object, + FactoryContext extends object = object, + ActionContext extends object = object + >( + definition: ActionFactoryDefinition + ) => { if (this.actionFactories.has(definition.id)) { throw new Error(`ActionFactory [actionFactory.id = ${definition.id}] already registered.`); } - const actionFactory = new ActionFactory(definition); + const actionFactory = new ActionFactory(definition); - this.actionFactories.set(actionFactory.id, actionFactory); + this.actionFactories.set(actionFactory.id, actionFactory as ActionFactory); }; public readonly getActionFactory = (actionFactoryId: string): ActionFactory => { diff --git a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts index 92f5a9be648bc..74be9c328f7f2 100644 --- a/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts +++ b/x-pack/plugins/dashboard_enhanced/public/services/drilldowns/dashboard_to_dashboard_drilldown/types.ts @@ -4,10 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EmbeddableVisTriggerContext } from '../../../../../../../src/plugins/embeddable/public'; +import { + EmbeddableVisTriggerContext, + EmbeddableContext, +} from '../../../../../../../src/plugins/embeddable/public'; import { UiActionsCollectConfigProps } from '../../../../../../../src/plugins/ui_actions/public'; -export type FactoryContext = any; +export type FactoryContext = EmbeddableContext; export type ActionContext = EmbeddableVisTriggerContext; export interface Config { diff --git a/x-pack/plugins/drilldowns/public/services/drilldown_service.ts b/x-pack/plugins/drilldowns/public/services/drilldown_service.ts index 6c628abe59755..d4fc7aa4c7df1 100644 --- a/x-pack/plugins/drilldowns/public/services/drilldown_service.ts +++ b/x-pack/plugins/drilldowns/public/services/drilldown_service.ts @@ -6,7 +6,8 @@ import { CoreSetup } from 'src/core/public'; import { AdvancedUiActionsSetup } from '../../../advanced_ui_actions/public'; -import { Drilldown } from '../types'; +import { Drilldown, DrilldownFactoryContext } from '../types'; +import { UiActionsActionFactoryDefinition as ActionFactoryDefinition } from '../../../../../src/plugins/ui_actions/public'; // TODO: MOCK DATA import { @@ -23,7 +24,13 @@ export interface DrilldownServiceSetupContract { /** * Convenience method to register a drilldown. */ - registerDrilldown: (drilldown: Drilldown) => void; + registerDrilldown: < + Config extends object = object, + CreationContext extends object = object, + ExecutionContext extends object = object + >( + drilldown: Drilldown + ) => void; } export class DrilldownService { @@ -31,8 +38,12 @@ export class DrilldownService { core: CoreSetup, { advancedUiActions }: DrilldownServiceSetupDeps ): DrilldownServiceSetupContract { - const registerDrilldown: DrilldownServiceSetupContract['registerDrilldown'] = ({ - id, + const registerDrilldown = < + Config extends object = object, + CreationContext extends object = object, + ExecutionContext extends object = object + >({ + id: factoryId, places, CollectConfig, createConfig, @@ -40,30 +51,35 @@ export class DrilldownService { getDisplayName, euiIcon, execute, - }) => { - advancedUiActions.registerActionFactory({ - id, + }: Drilldown) => { + const actionFactory: ActionFactoryDefinition< + Config, + DrilldownFactoryContext, + ExecutionContext + > = { + id: factoryId, CollectConfig, createConfig, isConfigValid, getDisplayName, getIconType: () => euiIcon, isCompatible: async ({ place }: any) => (!places ? true : places.indexOf(place) > -1), - create: config => ({ + create: serializedAction => ({ id: '', - type: id as any, + type: factoryId, getIconType: () => euiIcon, - execute: async context => await execute(config, context), + execute: async context => await execute(serializedAction.config, context), }), - }); + } as ActionFactoryDefinition< + Config, + DrilldownFactoryContext, + ExecutionContext + >; + + advancedUiActions.registerActionFactory(actionFactory); }; - /* - registerDrilldown({ - ...dashboardDrilldownActionFactory, - execute: () => alert('Dashboard drilldown!'), - } as any); - */ + // TODO: disable this registerDrilldown({ ...urlDrilldownActionFactory, euiIcon: 'link', diff --git a/x-pack/plugins/drilldowns/public/types.ts b/x-pack/plugins/drilldowns/public/types.ts index b61696720ec54..21e28d8a1e64f 100644 --- a/x-pack/plugins/drilldowns/public/types.ts +++ b/x-pack/plugins/drilldowns/public/types.ts @@ -10,26 +10,77 @@ export interface Drilldown< Config extends object = object, CreationContext extends object = object, ExecutionContext extends object = object -> - extends Pick< - ActionFactoryDefinition, - 'id' | 'createConfig' | 'CollectConfig' | 'isConfigValid' | 'getDisplayName' - > { +> { /** - * List of places where this drilldown should be available, e.g "dashboard". + * Globally unique identifier for this drilldown. + */ + id: string; + + /** + * List of places where this drilldown should be available, e.g "dashboard", "graph". * If omitted, the drilldown will be shown in all places. */ places?: string[]; /** - * Name of EUI icon to display next to this drilldown. + * Function that returns default config for this drilldown. + */ + createConfig: ActionFactoryDefinition< + Config, + DrilldownFactoryContext, + ExecutionContext + >['createConfig']; + + /** + * `UiComponent` that collections config for this drilldown. You can create + * a React component and transform it `UiComponent` using `uiToReactComponent` + * helper from `kibana_utils` plugin. + * + * ```tsx + * import React from 'react'; + * import { uiToReactComponent } from 'src/plugins/kibana_utils'; + * import { UiActionsCollectConfigProps as CollectConfigProps } from 'src/plugins/ui_actions/public'; + * + * type Props = CollectConfigProps; + * + * const ReactCollectConfig: React.FC = () => { + * return
Collecting config...'
; + * }; + * + * export const CollectConfig = uiToReactComponent(ReactCollectConfig); + * ``` + */ + CollectConfig: ActionFactoryDefinition< + Config, + DrilldownFactoryContext, + ExecutionContext + >['CollectConfig']; + + /** + * A validator function for the config object. Should always return a boolean + * given any input. + */ + isConfigValid: ActionFactoryDefinition< + Config, + DrilldownFactoryContext, + ExecutionContext + >['isConfigValid']; + + /** + * Name of EUI icon to display when showing this drilldown to user. */ euiIcon?: string; + /** + * Should return an internationalized name of the drilldown, which will be + * displayed to the user. + */ + getDisplayName: () => string; + /** * Whether this drilldown should be considered for execution given `config` * and `context`. When multiple drilldowns are attached to the same trigger - * user is presented with a context menu to pick on drilldown to execute. If + * user is presented with a context menu to pick one drilldown for execute. If * this method returns `true` this trigger will appear in the context menu * list, if `false`, it will not be presented to the user. If `doExecute` is * not implemented, this drilldown will always be show to the user. @@ -41,8 +92,9 @@ export interface Drilldown< doExecute?(config: Config, context: ExecutionContext): Promise; /** - * Implements the "navigation" action when user clicks something in the UI and - * instance of this drilldown is triggered. + * Implements the "navigation" action of the drilldown. This happens when + * user clicks something in the UI that executes a trigger to which this + * drilldown was attached. * * @param config Config object that user configured this drilldown with. * @param context Object that represents context in which the underlying @@ -50,3 +102,26 @@ export interface Drilldown< */ execute(config: Config, context: ExecutionContext): void; } + +/** + * Context object used when creating a drilldown. + */ +export interface DrilldownFactoryContext { + /** + * List of places as configured in @type {Drilldown} interface. + */ + places?: string[]; + + /** + * Context provided to the drilldown factory by the place where the UI is + * rendered. For example, for the "dashboard" place, this context contains + * the ID of the current dashboard, which could be used for filtering it out + * of the list. + */ + placeContext: T; + + /** + * List of triggers that user selected in the UI. + */ + triggers: string[]; +} From 64abc99c55c2b9e6c77d14d8eb0c973fc0bdc8df Mon Sep 17 00:00:00 2001 From: streamich Date: Mon, 16 Mar 2020 13:37:14 +0100 Subject: [PATCH 4/5] =?UTF-8?q?chore:=20=F0=9F=A4=96=20remove=20sample=20d?= =?UTF-8?q?rilldown?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../public/services/drilldown_service.ts | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/x-pack/plugins/drilldowns/public/services/drilldown_service.ts b/x-pack/plugins/drilldowns/public/services/drilldown_service.ts index d4fc7aa4c7df1..3f89a9f5d6441 100644 --- a/x-pack/plugins/drilldowns/public/services/drilldown_service.ts +++ b/x-pack/plugins/drilldowns/public/services/drilldown_service.ts @@ -9,13 +9,6 @@ import { AdvancedUiActionsSetup } from '../../../advanced_ui_actions/public'; import { Drilldown, DrilldownFactoryContext } from '../types'; import { UiActionsActionFactoryDefinition as ActionFactoryDefinition } from '../../../../../src/plugins/ui_actions/public'; -// TODO: MOCK DATA -import { - // dashboardDrilldownActionFactory, - urlDrilldownActionFactory, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../advanced_ui_actions/public/components/action_wizard/test_data'; - export interface DrilldownServiceSetupDeps { advancedUiActions: AdvancedUiActionsSetup; } @@ -79,13 +72,6 @@ export class DrilldownService { advancedUiActions.registerActionFactory(actionFactory); }; - // TODO: disable this - registerDrilldown({ - ...urlDrilldownActionFactory, - euiIcon: 'link', - execute: () => alert('URL drilldown!'), - } as any); - return { registerDrilldown, }; From 2a612f9f9f0b1cce7bbb3c421daf624398da70fe Mon Sep 17 00:00:00 2001 From: streamich Date: Mon, 16 Mar 2020 14:12:15 +0100 Subject: [PATCH 5/5] =?UTF-8?q?fix:=20=F0=9F=90=9B=20increase=20spacing=20?= =?UTF-8?q?between=20action=20factory=20picker?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../action_wizard/action_wizard.tsx | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx index f6fcbba7f4a9a..783b0e1d4aff7 100644 --- a/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx +++ b/x-pack/plugins/advanced_ui_actions/public/components/action_wizard/action_wizard.tsx @@ -172,21 +172,23 @@ const ActionFactorySelector: React.FC = ({ } return ( - + {[...actionFactories] .sort((f1, f2) => f1.order - f2.order) .map(actionFactory => ( - onActionFactorySelected(actionFactory)} - > - {actionFactory.getIconType(context) && ( - - )} - + + onActionFactorySelected(actionFactory)} + > + {actionFactory.getIconType(context) && ( + + )} + + ))} );