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

Disabled actions #51975

Merged
merged 5 commits into from
Dec 4, 2019
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
5 changes: 5 additions & 0 deletions src/plugins/embeddable/public/lib/embeddables/i_embeddable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ export interface EmbeddableInput {
id: string;
lastReloadRequestTime?: number;
hidePanelTitles?: boolean;

/**
* List of action IDs that this embeddable should not render.
*/
disabledActions?: string[];
streamich marked this conversation as resolved.
Show resolved Hide resolved
}

export interface EmbeddableOutput {
Expand Down
102 changes: 101 additions & 1 deletion src/plugins/embeddable/public/lib/panel/embeddable_panel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { nextTick } from 'test_utils/enzyme_helpers';
import { findTestSubject } from '@elastic/eui/lib/test';
import { I18nProvider } from '@kbn/i18n/react';
import { CONTEXT_MENU_TRIGGER } from '../triggers';
import { IAction, ITrigger } from 'src/plugins/ui_actions/public';
import { IAction, ITrigger, IUiActionsApi } from 'src/plugins/ui_actions/public';
import { Trigger, GetEmbeddableFactory, ViewMode } from '../types';
import { EmbeddableFactory, isErrorEmbeddable } from '../embeddables';
import { EmbeddablePanel } from './embeddable_panel';
Expand All @@ -42,6 +42,7 @@ import {
} from '../test_samples/embeddables/contact_card/contact_card_embeddable';
// eslint-disable-next-line
import { inspectorPluginMock } from 'src/plugins/inspector/public/mocks';
import { EuiBadge } from '@elastic/eui';

const actionRegistry = new Map<string, IAction>();
const triggerRegistry = new Map<string, ITrigger>();
Expand Down Expand Up @@ -174,6 +175,105 @@ test('HelloWorldContainer in view mode hides edit mode actions', async () => {
expect(findTestSubject(component, `embeddablePanelAction-${editModeAction.id}`).length).toBe(0);
});

const renderInEditModeAndOpenContextMenu = async (
embeddableInputs: any,
getActions: IUiActionsApi['getTriggerCompatibleActions'] = () => Promise.resolve([])
) => {
const inspector = inspectorPluginMock.createStartContract();

const container = new HelloWorldContainer({ id: '123', panels: {}, viewMode: ViewMode.VIEW }, {
getEmbeddableFactory,
} as any);

const embeddable = await container.addNewEmbeddable<
ContactCardEmbeddableInput,
ContactCardEmbeddableOutput,
ContactCardEmbeddable
>(CONTACT_CARD_EMBEDDABLE, embeddableInputs);

const component = mount(
<I18nProvider>
<EmbeddablePanel
embeddable={embeddable}
getActions={getActions}
getAllEmbeddableFactories={(() => []) as any}
getEmbeddableFactory={(() => undefined) as any}
notifications={{} as any}
overlays={{} as any}
inspector={inspector}
SavedObjectFinder={() => null}
/>
</I18nProvider>
);

findTestSubject(component, 'embeddablePanelToggleMenuIcon').simulate('click');
await nextTick();
component.update();

return { component };
};

test('HelloWorldContainer in edit mode hides disabledActions', async () => {
const action = {
id: 'FOO',
type: 'FOO',
getIconType: () => undefined,
getDisplayName: () => 'foo',
isCompatible: async () => true,
execute: async () => {},
};
const getActions = () => Promise.resolve([action]);

const { component: component1 } = await renderInEditModeAndOpenContextMenu(
{
firstName: 'Bob',
},
getActions
);
const { component: component2 } = await renderInEditModeAndOpenContextMenu(
{
firstName: 'Bob',
disabledActions: ['FOO'],
},
getActions
);

const fooContextMenuActionItem1 = findTestSubject(component1, 'embeddablePanelAction-FOO');
const fooContextMenuActionItem2 = findTestSubject(component2, 'embeddablePanelAction-FOO');

expect(fooContextMenuActionItem1.length).toBe(1);
expect(fooContextMenuActionItem2.length).toBe(0);
});

test('HelloWorldContainer hides disabled badges', async () => {
const action = {
id: 'BAR',
type: 'BAR',
getIconType: () => undefined,
getDisplayName: () => 'bar',
isCompatible: async () => true,
execute: async () => {},
};
const getActions = () => Promise.resolve([action]);

const { component: component1 } = await renderInEditModeAndOpenContextMenu(
{
firstName: 'Bob',
},
getActions
);
const { component: component2 } = await renderInEditModeAndOpenContextMenu(
{
firstName: 'Bob',
disabledActions: ['BAR'],
},
getActions
);

expect(component1.find(EuiBadge).length).toBe(1);
expect(component2.find(EuiBadge).length).toBe(0);
});

test('HelloWorldContainer in edit mode shows edit mode actions', async () => {
const inspector = inspectorPluginMock.createStartContract();

Expand Down
21 changes: 15 additions & 6 deletions src/plugins/embeddable/public/lib/panel/embeddable_panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,19 @@ export class EmbeddablePanel extends React.Component<Props, State> {
}

private async refreshBadges() {
const badges = await this.props.getActions(PANEL_BADGE_TRIGGER, {
let badges: IAction[] = await this.props.getActions(PANEL_BADGE_TRIGGER, {
embeddable: this.props.embeddable,
});
if (!this.mounted) return;

if (this.mounted) {
this.setState({
badges,
});
const { disabledActions } = this.props.embeddable.getInput();
if (disabledActions) {
badges = badges.filter(badge => disabledActions.indexOf(badge.id) === -1);
}

this.setState({
badges,
});
}

public UNSAFE_componentWillMount() {
Expand Down Expand Up @@ -200,10 +204,15 @@ export class EmbeddablePanel extends React.Component<Props, State> {
};

private getActionContextMenuPanel = async () => {
const actions = await this.props.getActions(CONTEXT_MENU_TRIGGER, {
let actions = await this.props.getActions(CONTEXT_MENU_TRIGGER, {
embeddable: this.props.embeddable,
});

const { disabledActions } = this.props.embeddable.getInput();
if (disabledActions) {
streamich marked this conversation as resolved.
Show resolved Hide resolved
actions = actions.filter(action => disabledActions.indexOf(action.id) === -1);
streamich marked this conversation as resolved.
Show resolved Hide resolved
}

const createGetUserData = (overlays: OverlayStart) =>
async function getUserData(context: { embeddable: IEmbeddable }) {
return new Promise<{ title: string | undefined }>(resolve => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { Loader } from '../loader';
import { useStateToaster } from '../toasters';
import { Embeddable } from './embeddable';
import { EmbeddableHeader } from './embeddable_header';
import { createEmbeddable, displayErrorToast, setupEmbeddablesAPI } from './embedded_map_helpers';
import { createEmbeddable, displayErrorToast } from './embedded_map_helpers';
import { IndexPatternsMissingPrompt } from './index_patterns_missing_prompt';
import { MapToolTip } from './map_tool_tip/map_tool_tip';
import * as i18n from './translations';
Expand Down Expand Up @@ -104,17 +104,6 @@ export const EmbeddedMapComponent = ({
const plugins = useKibanaPlugins();
const core = useKibanaCore();

// Setup embeddables API (i.e. detach extra actions) useEffect
useEffect(() => {
try {
setupEmbeddablesAPI(plugins);
} catch (e) {
displayErrorToast(i18n.ERROR_CONFIGURING_EMBEDDABLES_API, e.message, dispatchToaster);
setIsLoading(false);
setIsError(true);
}
}, []);

// Initial Load useEffect
useEffect(() => {
let isSubscribed = true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { createEmbeddable, displayErrorToast, setupEmbeddablesAPI } from './embedded_map_helpers';
import { createEmbeddable, displayErrorToast } from './embedded_map_helpers';
import { createUiNewPlatformMock } from 'ui/new_platform/__mocks__/helpers';
import { createPortalNode } from 'react-reverse-portal';
import { PluginsStart } from 'ui/new_platform/new_platform';

jest.mock('ui/new_platform');
jest.mock('../../lib/settings/use_kibana_ui_setting');
Expand Down Expand Up @@ -45,13 +44,6 @@ describe('embedded_map_helpers', () => {
});
});

describe('setupEmbeddablesAPI', () => {
test('detaches extra UI actions', () => {
setupEmbeddablesAPI((npStart.plugins as unknown) as PluginsStart);
expect(npStart.plugins.uiActions.detachAction).toHaveBeenCalledTimes(2);
});
});

describe('createEmbeddable', () => {
test('attaches refresh action', async () => {
const setQueryMock = jest.fn();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,8 @@
import uuid from 'uuid';
import React from 'react';
import { OutPortal, PortalNode } from 'react-reverse-portal';
import { PluginsStart } from 'ui/new_platform/new_platform';

import { ActionToaster, AppToast } from '../toasters';
import {
CONTEXT_MENU_TRIGGER,
PANEL_BADGE_TRIGGER,
ViewMode,
} from '../../../../../../../src/legacy/core_plugins/embeddable_api/public/np_ready/public';
import { ViewMode } from '../../../../../../../src/legacy/core_plugins/embeddable_api/public/np_ready/public';
import {
IndexPatternMapping,
MapEmbeddable,
Expand Down Expand Up @@ -53,23 +47,6 @@ export const displayErrorToast = (
});
};

/**
* Temporary Embeddables API configuration override until ability to edit actions is addressed:
* https://github.com/elastic/kibana/issues/43643
*
* @param plugins new platform plugins
*
* @throws Error if trigger/action doesn't exist
*/
export const setupEmbeddablesAPI = (plugins: PluginsStart) => {
try {
plugins.uiActions.detachAction(CONTEXT_MENU_TRIGGER, 'CUSTOM_TIME_RANGE');
plugins.uiActions.detachAction(PANEL_BADGE_TRIGGER, 'CUSTOM_TIME_RANGE_BADGE');
} catch (e) {
throw e;
}
};

/**
* Creates MapEmbeddable with provided initial configuration
*
Expand Down Expand Up @@ -115,6 +92,7 @@ export const createEmbeddable = async (
openTOCDetails: [],
hideFilterActions: false,
mapCenter: { lon: -1.05469, lat: 15.96133, zoom: 1 },
disabledActions: ['CUSTOM_TIME_RANGE', 'CUSTOM_TIME_RANGE_BADGE'],
};

const renderTooltipContent = ({
Expand Down