Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[7.x] [Drilldowns] misc improvements & fixes (#75276) #75404

Merged
merged 1 commit into from
Aug 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/plugins/kibana_utils/public/ui/configurable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ export interface Configurable<Config extends object = object, Context = object>
/**
* 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -52,10 +53,24 @@ export class DashboardHelloWorldOnlyRangeSelectDrilldown
name: '',
});

public readonly isConfigValid = (config: Config): config is Config => {
public readonly isConfigValid = (
config: Config,
context: BaseActionFactoryContext<typeof SELECT_RANGE_TRIGGER>
): 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<boolean> {
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)}`);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,9 @@ export function Demo({ actionFactories }: { actionFactories: Array<ActionFactory

setState({
currentActionFactory: newActionFactory,
config: newActionFactory.createConfig(),
config: newActionFactory.createConfig({
triggers: state.selectedTriggers ?? [],
}),
});
}

Expand Down Expand Up @@ -255,7 +257,11 @@ export function Demo({ actionFactories }: { actionFactories: Array<ActionFactory
<div>Action Factory Config: {JSON.stringify(state.config)}</div>
<div>
Is config valid:{' '}
{JSON.stringify(state.currentActionFactory?.isConfigValid(state.config!) ?? false)}
{JSON.stringify(
state.currentActionFactory?.isConfigValid(state.config!, {
triggers: state.selectedTriggers ?? [],
}) ?? false
)}
</div>
<div>Picked trigger: {state.selectedTriggers?.[0]}</div>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export interface FlyoutDrilldownWizardProps<
}

function useWizardConfigState(
actionFactoryContext: BaseActionFactoryContext,
initialDrilldownWizardConfig?: DrilldownWizardConfig
): [
DrilldownWizardConfig,
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -147,7 +151,18 @@ export function FlyoutDrilldownWizard<CurrentActionConfig extends object = objec
const [
wizardConfig,
{ setActionFactory, setActionConfig, setName, setSelectedTriggers },
] = useWizardConfigState(initialDrilldownWizardConfig);
] = useWizardConfigState(
{ ...extraActionFactoryContext, triggers: supportedTriggers },
initialDrilldownWizardConfig
);

const actionFactoryContext: BaseActionFactoryContext = useMemo(
() => ({
...extraActionFactoryContext,
triggers: wizardConfig.selectedTriggers ?? [],
}),
[extraActionFactoryContext, wizardConfig.selectedTriggers]
);

const isActionValid = (
config: DrilldownWizardConfig
Expand All @@ -157,17 +172,12 @@ export function FlyoutDrilldownWizard<CurrentActionConfig extends object = objec
if (!wizardConfig.actionConfig) return false;
if (!wizardConfig.selectedTriggers || wizardConfig.selectedTriggers.length === 0) return false;

return wizardConfig.actionFactory.isConfigValid(wizardConfig.actionConfig);
return wizardConfig.actionFactory.isConfigValid(
wizardConfig.actionConfig,
actionFactoryContext
);
};

const actionFactoryContext: BaseActionFactoryContext = useMemo(
() => ({
...extraActionFactoryContext,
triggers: wizardConfig.selectedTriggers ?? [],
}),
[extraActionFactoryContext, wizardConfig.selectedTriggers]
);

const footer = (
<EuiButton
onClick={() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<ExecutionContext>
): Promise<boolean>;

/**
* Implements the "navigation" action of the drilldown. This happens when
* user clicks something in the UI that executes a trigger to which this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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' } })
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export class UiActionsServiceEnhancements {
getHref,
minimalLicense,
supportedTriggers,
isCompatible,
}: DrilldownDefinition<Config, SupportedTriggers, FactoryContext, ExecutionContext>): void => {
const actionFactory: ActionFactoryDefinition<
Config,
Expand All @@ -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<Config, SupportedTriggers, FactoryContext, ExecutionContext>;

Expand Down