Skip to content

Commit

Permalink
Dynamic actions to xpack (#62647)
Browse files Browse the repository at this point in the history
* feat: ๐ŸŽธ set up sample action factory provider

* feat: ๐ŸŽธ create dashboard_enhanced plugin

* feat: ๐ŸŽธ add EnhancedEmbeddable interface

* refactor: ๐Ÿ’ก move DynamicActionManager to x-pack

* feat: ๐ŸŽธ connect dynamic action manager to embeddable life-cycle

* test: ๐Ÿ’ fix Jest tests after refactor

* fix: ๐Ÿ› fix type error

Co-authored-by: Elastic Machine <[email protected]>
  • Loading branch information
streamich and elasticmachine authored Apr 9, 2020
1 parent c2ea2e3 commit 57ddccf
Show file tree
Hide file tree
Showing 34 changed files with 524 additions and 315 deletions.
9 changes: 5 additions & 4 deletions src/plugins/embeddable/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,23 +23,24 @@ import { PluginInitializerContext } from 'src/core/public';
import { EmbeddablePublicPlugin } from './plugin';

export {
Adapters,
ACTION_ADD_PANEL,
AddPanelAction,
ACTION_APPLY_FILTER,
ACTION_EDIT_PANEL,
Adapters,
AddPanelAction,
Container,
ContainerInput,
ContainerOutput,
CONTEXT_MENU_TRIGGER,
contextMenuTrigger,
ACTION_EDIT_PANEL,
defaultEmbeddableFactoryProvider,
EditPanelAction,
Embeddable,
EmbeddableChildPanel,
EmbeddableChildPanelProps,
EmbeddableContext,
EmbeddableFactoryDefinition,
EmbeddableFactory,
EmbeddableFactoryDefinition,
EmbeddableFactoryNotFoundError,
EmbeddableFactoryRenderer,
EmbeddableInput,
Expand Down
51 changes: 1 addition & 50 deletions src/plugins/embeddable/public/lib/embeddables/embeddable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,7 @@ import { Adapters, ViewMode } from '../types';
import { IContainer } from '../containers';
import { EmbeddableInput, EmbeddableOutput, IEmbeddable } from './i_embeddable';
import { TriggerContextMapping } from '../ui_actions';
import { EmbeddableActionStorage } from './embeddable_action_storage';
import {
UiActionsDynamicActionManager,
UiActionsStart,
} from '../../../../../plugins/ui_actions/public';
import { EmbeddableContext } from '../triggers';
import { UiActionsStart } from '../../../../../plugins/ui_actions/public';

function getPanelTitle(input: EmbeddableInput, output: EmbeddableOutput) {
return input.hidePanelTitles ? '' : input.title === undefined ? output.defaultTitle : input.title;
Expand Down Expand Up @@ -60,28 +55,9 @@ export abstract class Embeddable<
// to update input when the parent changes.
private parentSubscription?: Rx.Subscription;

private storageSubscription?: Rx.Subscription;

// TODO: Rename to destroyed.
private destoyed: boolean = false;

private storage = new EmbeddableActionStorage((this as unknown) as Embeddable);

private cachedDynamicActions?: UiActionsDynamicActionManager;
public get dynamicActions(): UiActionsDynamicActionManager | undefined {
if (!this.params.uiActions) return undefined;
if (!this.cachedDynamicActions) {
this.cachedDynamicActions = new UiActionsDynamicActionManager({
isCompatible: async (context: unknown) =>
(context as EmbeddableContext).embeddable.runtimeId === this.runtimeId,
storage: this.storage,
uiActions: this.params.uiActions,
});
}

return this.cachedDynamicActions;
}

constructor(
input: TEmbeddableInput,
output: TEmbeddableOutput,
Expand Down Expand Up @@ -111,18 +87,6 @@ export abstract class Embeddable<
this.onResetInput(newInput);
});
}

if (this.dynamicActions) {
this.dynamicActions.start().catch(error => {
/* eslint-disable */
console.log('Failed to start embeddable dynamic actions', this);
console.error(error);
/* eslint-enable */
});
this.storageSubscription = this.input$.subscribe(() => {
this.storage.reload$.next();
});
}
}

public getIsContainer(): this is IContainer {
Expand Down Expand Up @@ -202,19 +166,6 @@ export abstract class Embeddable<
public destroy(): void {
this.destoyed = true;

if (this.dynamicActions) {
this.dynamicActions.stop().catch(error => {
/* eslint-disable */
console.log('Failed to stop embeddable dynamic actions', this);
console.error(error);
/* eslint-enable */
});
}

if (this.storageSubscription) {
this.storageSubscription.unsubscribe();
}

this.input$.complete();
this.output$.complete();

Expand Down
5 changes: 2 additions & 3 deletions src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
*/

import { Observable } from 'rxjs';
import { UiActionsDynamicActionManager } from '../../../../../plugins/ui_actions/public';
import { Adapters } from '../types';
import { IContainer } from '../containers/i_container';
import { ViewMode } from '../types';
Expand Down Expand Up @@ -92,9 +91,9 @@ export interface IEmbeddable<
readonly runtimeId?: number;

/**
* Default implementation of dynamic action API for embeddables.
* Extra abilities added to Embeddable by `*_enhanced` plugins.
*/
dynamicActions?: UiActionsDynamicActionManager;
enhancements?: object;

/**
* A functional representation of the isContainer variable, but helpful for typescript to
Expand Down
12 changes: 7 additions & 5 deletions src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -203,13 +203,15 @@ export class EmbeddablePanel extends React.Component<Props, State> {
this.props.embeddable.render(this.embeddableRoot.current);
}

const dynamicActions = this.props.embeddable.dynamicActions;
const dynamicActions = (this.props.embeddable.enhancements as any)?.dynamicActions;
if (dynamicActions) {
this.setState({ eventCount: dynamicActions.state.get().events.length });
this.eventCountSubscription = dynamicActions.state.state$.subscribe(({ events }) => {
if (!this.mounted) return;
this.setState({ eventCount: events.length });
});
this.eventCountSubscription = dynamicActions.state.state$.subscribe(
({ events }: { events: unknown[] }) => {
if (!this.mounted) return;
this.setState({ eventCount: events.length });
}
);
}
}

Expand Down
2 changes: 0 additions & 2 deletions src/plugins/ui_actions/public/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,4 @@ export * from './action_factory_definition';
export * from './action_factory';
export * from './create_action';
export * from './incompatible_action_error';
export * from './dynamic_action_storage';
export * from './dynamic_action_manager';
export * from './types';
6 changes: 6 additions & 0 deletions src/plugins/ui_actions/public/actions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,9 @@ export interface SerializedAction<Config> {
readonly name: string;
readonly config: Config;
}

export interface SerializedEvent {
eventId: string;
triggers: string[];
action: SerializedAction<unknown>;
}
6 changes: 1 addition & 5 deletions src/plugins/ui_actions/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,7 @@ export {
ActionDefinition as UiActionsActionDefinition,
ActionFactoryDefinition as UiActionsActionFactoryDefinition,
ActionInternal as UiActionsActionInternal,
ActionStorage as UiActionsActionStorage,
AbstractActionStorage as UiActionsAbstractActionStorage,
createAction,
DynamicActionManager,
DynamicActionManagerState,
IncompatibleActionError,
SerializedAction as UiActionsSerializedAction,
SerializedEvent as UiActionsSerializedEvent,
Expand All @@ -57,4 +53,4 @@ export {
applyFilterTrigger,
} from './triggers';
export { TriggerContextMapping, TriggerId, ActionContextMapping, ActionType } from './types';
export { ActionByType, DynamicActionManager as UiActionsDynamicActionManager } from './actions';
export { ActionByType } from './actions';
Original file line number Diff line number Diff line change
@@ -1,29 +1,18 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { DynamicActionManager } from './dynamic_action_manager';
import { ActionStorage, MemoryActionStorage, SerializedEvent } from './dynamic_action_storage';
import { UiActionsService } from '../service';
import { ActionFactoryDefinition } from './action_factory_definition';
import { ActionRegistry } from '../types';
import { SerializedAction } from './types';
import { of } from '../../../kibana_utils';
import {
UiActionsService,
UiActionsActionFactoryDefinition as ActionFactoryDefinition,
UiActionsSerializedAction as SerializedAction,
UiActionsActionInternal as ActionInternal,
} from '../../../../../src/plugins/ui_actions/public';
import { of } from '../../../../../src/plugins/kibana_utils';

const actionFactoryDefinition1: ActionFactoryDefinition = {
id: 'ACTION_FACTORY_1',
Expand Down Expand Up @@ -82,7 +71,7 @@ const event3: SerializedEvent = {
const setup = (events: readonly SerializedEvent[] = []) => {
const isCompatible = async () => true;
const storage: ActionStorage = new MemoryActionStorage(events);
const actions: ActionRegistry = new Map();
const actions = new Map<string, ActionInternal>();
const uiActions = new UiActionsService({
actions,
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,20 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { v4 as uuidv4 } from 'uuid';
import { Subscription } from 'rxjs';
import { ActionStorage, SerializedEvent } from './dynamic_action_storage';
import { UiActionsService } from '../service';
import { SerializedAction } from './types';
import { TriggerContextMapping } from '../types';
import { ActionDefinition } from './action';
import {
UiActionsService,
UiActionsSerializedAction as SerializedAction,
TriggerContextMapping,
UiActionsActionDefinition as ActionDefinition,
} from '../../../../../src/plugins/ui_actions/public';
import { defaultState, transitions, selectors, State } from './dynamic_action_manager_state';
import { StateContainer, createStateContainer } from '../../../kibana_utils';
import { StateContainer, createStateContainer } from '../../../../../src/plugins/kibana_utils';

const compareEvents = (
a: ReadonlyArray<{ eventId: string }>,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,7 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { SerializedEvent } from './dynamic_action_storage';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,13 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

/* eslint-disable max-classes-per-file */

import { Observable, Subject } from 'rxjs';
import { SerializedAction } from './types';
import { UiActionsSerializedAction as SerializedAction } from '../../../../../src/plugins/ui_actions/public';

/**
* Serialized representation of event-action pair, used to persist in storage.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export * from './dynamic_action_storage';
export * from './dynamic_action_manager_state';
export * from './dynamic_action_manager';
8 changes: 8 additions & 0 deletions x-pack/plugins/advanced_ui_actions/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,11 @@ export {
Configurable as AdvancedUiActionsConfigurable,
CollectConfigProps as AdvancedUiActionsCollectConfigProps,
} from './util';

export {
AbstractActionStorage as UiActionsEnhancedAbstractActionStorage,
DynamicActionManager as UiActionsEnhancedDynamicActionManager,
DynamicActionManagerParams as UiActionsEnhancedDynamicActionManagerParams,
DynamicActionManagerState as UiActionsEnhancedDynamicActionManagerState,
MemoryActionStorage as UiActionsEnhancedMemoryActionStorage,
} from './dynamic_actions';
9 changes: 6 additions & 3 deletions x-pack/plugins/dashboard_enhanced/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@

import { CoreStart, CoreSetup, Plugin, PluginInitializerContext } from 'src/core/public';
import { UiActionsSetup, UiActionsStart } from '../../../../src/plugins/ui_actions/public';
import { EmbeddableSetup, EmbeddableStart } from '../../../../src/plugins/embeddable/public';
import { DashboardDrilldownsService } from './services';
import { DrilldownsSetup, DrilldownsStart } from '../../drilldowns/public';

export interface SetupDependencies {
uiActions: UiActionsSetup;
drilldowns: DrilldownsSetup;
embeddable: EmbeddableSetup;
uiActions: UiActionsSetup;
}

export interface StartDependencies {
uiActions: UiActionsStart;
drilldowns: DrilldownsStart;
embeddable: EmbeddableStart;
uiActions: UiActionsStart;
}

// eslint-disable-next-line
Expand All @@ -36,7 +39,7 @@ export class DashboardEnhancedPlugin

public setup(core: CoreSetup<StartDependencies>, plugins: SetupDependencies): SetupContract {
this.drilldowns.bootstrap(core, plugins, {
enableDrilldowns: this.config.drilldowns.enabled,
enableDrilldowns: true,
});

return {};
Expand Down
Loading

0 comments on commit 57ddccf

Please sign in to comment.