diff --git a/src/plugins/kibana_utils/public/ui/configurable.ts b/src/plugins/kibana_utils/public/ui/configurable.ts index a4a9f09c1c0e0..3fa5cdc8b5e47 100644 --- a/src/plugins/kibana_utils/public/ui/configurable.ts +++ b/src/plugins/kibana_utils/public/ui/configurable.ts @@ -26,12 +26,12 @@ export interface Configurable /** * Create default config for this item, used when item is created for the first time. */ - readonly createConfig: () => Config; + readonly createConfig: (context: Context) => Config; /** * Is this config valid. Used to validate user's input before saving. */ - readonly isConfigValid: (config: Config) => boolean; + readonly isConfigValid: (config: Config, context: Context) => boolean; /** * `UiComponent` to be rendered when collecting configuration for this item. diff --git a/x-pack/examples/ui_actions_enhanced_examples/public/dashboard_hello_world_only_range_select_drilldown/index.tsx b/x-pack/examples/ui_actions_enhanced_examples/public/dashboard_hello_world_only_range_select_drilldown/index.tsx index 38e2abc1f89a3..7394690a61eae 100644 --- a/x-pack/examples/ui_actions_enhanced_examples/public/dashboard_hello_world_only_range_select_drilldown/index.tsx +++ b/x-pack/examples/ui_actions_enhanced_examples/public/dashboard_hello_world_only_range_select_drilldown/index.tsx @@ -11,6 +11,7 @@ import { UiActionsEnhancedDrilldownDefinition as Drilldown } from '../../../../p import { RangeSelectContext } from '../../../../../src/plugins/embeddable/public'; import { CollectConfigProps } from '../../../../../src/plugins/kibana_utils/public'; import { SELECT_RANGE_TRIGGER } from '../../../../../src/plugins/ui_actions/public'; +import { BaseActionFactoryContext } from '../../../../plugins/ui_actions_enhanced/public/dynamic_actions'; export interface Config { name: string; @@ -52,10 +53,24 @@ export class DashboardHelloWorldOnlyRangeSelectDrilldown name: '', }); - public readonly isConfigValid = (config: Config): config is Config => { + public readonly isConfigValid = ( + config: Config, + context: BaseActionFactoryContext + ): config is Config => { + // eslint-disable-next-line no-console + console.log('Showcasing, that can access action factory context:', context); + return !!config.name; }; + /** + * Showcase isCompatible. Disabled drilldown action in case if range.length === 0 + */ + isCompatible(config: Config, context: RangeSelectContext): Promise { + if (context.data.range.length === 0) return Promise.resolve(false); + return Promise.resolve(true); + } + public readonly execute = async (config: Config, context: RangeSelectContext) => { alert(`Hello, ${config.name}, your selected range: ${JSON.stringify(context.data.range)}`); }; diff --git a/x-pack/plugins/ui_actions_enhanced/public/components/action_wizard/test_data.tsx b/x-pack/plugins/ui_actions_enhanced/public/components/action_wizard/test_data.tsx index 2ac8dd6392552..d48cb13b1a470 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/components/action_wizard/test_data.tsx +++ b/x-pack/plugins/ui_actions_enhanced/public/components/action_wizard/test_data.tsx @@ -220,7 +220,9 @@ export function Demo({ actionFactories }: { actionFactories: ArrayAction Factory Config: {JSON.stringify(state.config)}
Is config valid:{' '} - {JSON.stringify(state.currentActionFactory?.isConfigValid(state.config!) ?? false)} + {JSON.stringify( + state.currentActionFactory?.isConfigValid(state.config!, { + triggers: state.selectedTriggers ?? [], + }) ?? false + )}
Picked trigger: {state.selectedTriggers?.[0]}
diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/components/flyout_drilldown_wizard/flyout_drilldown_wizard.tsx b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/components/flyout_drilldown_wizard/flyout_drilldown_wizard.tsx index 4b84a177e682c..a908d53bf6ae7 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/components/flyout_drilldown_wizard/flyout_drilldown_wizard.tsx +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/components/flyout_drilldown_wizard/flyout_drilldown_wizard.tsx @@ -57,6 +57,7 @@ export interface FlyoutDrilldownWizardProps< } function useWizardConfigState( + actionFactoryContext: BaseActionFactoryContext, initialDrilldownWizardConfig?: DrilldownWizardConfig ): [ DrilldownWizardConfig, @@ -102,7 +103,10 @@ function useWizardConfigState( setWizardConfig({ ...wizardConfig, actionFactory, - actionConfig: actionConfigCache[actionFactory.id] ?? actionFactory.createConfig(), + actionConfig: + actionConfigCache[actionFactory.id] ?? + actionFactory.createConfig(actionFactoryContext), + selectedTriggers: [], }); } else { if (wizardConfig.actionFactory?.id) { @@ -147,7 +151,18 @@ export function FlyoutDrilldownWizard ({ + ...extraActionFactoryContext, + triggers: wizardConfig.selectedTriggers ?? [], + }), + [extraActionFactoryContext, wizardConfig.selectedTriggers] + ); const isActionValid = ( config: DrilldownWizardConfig @@ -157,17 +172,12 @@ export function FlyoutDrilldownWizard ({ - ...extraActionFactoryContext, - triggers: wizardConfig.selectedTriggers ?? [], - }), - [extraActionFactoryContext, wizardConfig.selectedTriggers] - ); - const footer = ( { diff --git a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_definition.ts b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_definition.ts index 0efde6214ab2b..ff455c6ae45b6 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_definition.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/drilldowns/drilldown_definition.ts @@ -106,6 +106,15 @@ export interface DrilldownDefinition< */ getDisplayName: () => string; + /** + * isCompatible during execution + * Could be used to prevent drilldown from execution + */ + isCompatible?( + config: Config, + context: ExecutionContext | ActionExecutionContext + ): Promise; + /** * Implements the "navigation" action of the drilldown. This happens when * user clicks something in the UI that executes a trigger to which this diff --git a/x-pack/plugins/ui_actions_enhanced/public/dynamic_actions/action_factory.test.ts b/x-pack/plugins/ui_actions_enhanced/public/dynamic_actions/action_factory.test.ts index 159e8be95f272..a07fed8486438 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/dynamic_actions/action_factory.test.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/dynamic_actions/action_factory.test.ts @@ -37,6 +37,14 @@ describe('License & ActionFactory', () => { expect(factory.isCompatibleLicence()).toBe(false); }); + test('licence has expired', async () => { + const factory = new ActionFactory({ ...def, minimalLicense: 'gold' }, () => + licensingMock.createLicense({ license: { type: 'gold', status: 'expired' } }) + ); + expect(await factory.isCompatible({ triggers: [] })).toBe(true); + expect(factory.isCompatibleLicence()).toBe(false); + }); + test('enough license level', async () => { const factory = new ActionFactory({ ...def, minimalLicense: 'gold' }, () => licensingMock.createLicense({ license: { type: 'gold' } }) diff --git a/x-pack/plugins/ui_actions_enhanced/public/dynamic_actions/action_factory.ts b/x-pack/plugins/ui_actions_enhanced/public/dynamic_actions/action_factory.ts index cb764d99b4a03..35e06ab036fc9 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/dynamic_actions/action_factory.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/dynamic_actions/action_factory.ts @@ -70,7 +70,8 @@ export class ActionFactory< */ public isCompatibleLicence() { if (!this.minimalLicense) return true; - return this.getLicence().hasAtLeast(this.minimalLicense); + const licence = this.getLicence(); + return licence.isAvailable && licence.isActive && licence.hasAtLeast(this.minimalLicense); } public create( diff --git a/x-pack/plugins/ui_actions_enhanced/public/services/ui_actions_service_enhancements.test.ts b/x-pack/plugins/ui_actions_enhanced/public/services/ui_actions_service_enhancements.test.ts index ab17c3f549dcd..08823833b9af2 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/services/ui_actions_service_enhancements.test.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/services/ui_actions_service_enhancements.test.ts @@ -75,5 +75,18 @@ describe('UiActionsService', () => { 'Action factory [actionFactoryId = UNKNOWN_ID] does not exist.' ); }); + + test('isCompatible from definition is used on registered factory', async () => { + const service = new UiActionsServiceEnhancements({ getLicenseInfo }); + + service.registerActionFactory({ + ...factoryDefinition1, + isCompatible: () => Promise.resolve(false), + }); + + await expect( + service.getActionFactory(factoryDefinition1.id).isCompatible({ triggers: [] }) + ).resolves.toBe(false); + }); }); }); diff --git a/x-pack/plugins/ui_actions_enhanced/public/services/ui_actions_service_enhancements.ts b/x-pack/plugins/ui_actions_enhanced/public/services/ui_actions_service_enhancements.ts index 10786697243dc..9575329514835 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/services/ui_actions_service_enhancements.ts +++ b/x-pack/plugins/ui_actions_enhanced/public/services/ui_actions_service_enhancements.ts @@ -95,6 +95,7 @@ export class UiActionsServiceEnhancements { getHref, minimalLicense, supportedTriggers, + isCompatible, }: DrilldownDefinition): void => { const actionFactory: ActionFactoryDefinition< Config, @@ -119,6 +120,9 @@ export class UiActionsServiceEnhancements { getDisplayName: () => serializedAction.name, execute: async (context) => await execute(serializedAction.config, context), getHref: getHref ? async (context) => getHref(serializedAction.config, context) : undefined, + isCompatible: isCompatible + ? async (context) => isCompatible(serializedAction.config, context) + : undefined, }), } as ActionFactoryDefinition;