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] Context menu trigger for URL Drilldown (#81158) #82119

Merged
merged 1 commit into from
Oct 30, 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [kibana-plugin-plugins-embeddable-public](./kibana-plugin-plugins-embeddable-public.md) &gt; [isContextMenuTriggerContext](./kibana-plugin-plugins-embeddable-public.iscontextmenutriggercontext.md)

## isContextMenuTriggerContext variable

<b>Signature:</b>

```typescript
isContextMenuTriggerContext: (context: unknown) => context is EmbeddableContext
```
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
| [contextMenuTrigger](./kibana-plugin-plugins-embeddable-public.contextmenutrigger.md) | |
| [defaultEmbeddableFactoryProvider](./kibana-plugin-plugins-embeddable-public.defaultembeddablefactoryprovider.md) | |
| [EmbeddableRenderer](./kibana-plugin-plugins-embeddable-public.embeddablerenderer.md) | Helper react component to render an embeddable Can be used if you have an embeddable object or an embeddable factory Supports updating input by passing <code>input</code> prop |
| [isContextMenuTriggerContext](./kibana-plugin-plugins-embeddable-public.iscontextmenutriggercontext.md) | |
| [isRangeSelectTriggerContext](./kibana-plugin-plugins-embeddable-public.israngeselecttriggercontext.md) | |
| [isValueClickTriggerContext](./kibana-plugin-plugins-embeddable-public.isvalueclicktriggercontext.md) | |
| [PANEL\_BADGE\_TRIGGER](./kibana-plugin-plugins-embeddable-public.panel_badge_trigger.md) | |
Expand Down
1 change: 1 addition & 0 deletions src/plugins/embeddable/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export {
isSavedObjectEmbeddableInput,
isRangeSelectTriggerContext,
isValueClickTriggerContext,
isContextMenuTriggerContext,
EmbeddableStateTransfer,
EmbeddableEditorState,
EmbeddablePackageState,
Expand Down
47 changes: 33 additions & 14 deletions src/plugins/embeddable/public/lib/triggers/triggers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* under the License.
*/

import { i18n } from '@kbn/i18n';
import { Datatable } from '../../../../expressions';
import { Trigger } from '../../../../ui_actions/public';
import { IEmbeddable } from '..';
Expand Down Expand Up @@ -53,31 +54,49 @@ export type ChartActionContext<T extends IEmbeddable = IEmbeddable> =
| ValueClickContext<T>
| RangeSelectContext<T>;

export const isValueClickTriggerContext = (
context: ChartActionContext
): context is ValueClickContext => context.data && 'data' in context.data;

export const isRangeSelectTriggerContext = (
context: ChartActionContext
): context is RangeSelectContext => context.data && 'range' in context.data;

export const CONTEXT_MENU_TRIGGER = 'CONTEXT_MENU_TRIGGER';
export const contextMenuTrigger: Trigger<'CONTEXT_MENU_TRIGGER'> = {
id: CONTEXT_MENU_TRIGGER,
title: 'Context menu',
description: 'Triggered on top-right corner context-menu select.',
title: i18n.translate('embeddableApi.contextMenuTrigger.title', {
defaultMessage: 'Context menu',
}),
description: i18n.translate('embeddableApi.contextMenuTrigger.description', {
defaultMessage: 'A panel top-right corner context menu click.',
}),
};

export const PANEL_BADGE_TRIGGER = 'PANEL_BADGE_TRIGGER';
export const panelBadgeTrigger: Trigger<'PANEL_BADGE_TRIGGER'> = {
id: PANEL_BADGE_TRIGGER,
title: 'Panel badges',
description: 'Actions appear in title bar when an embeddable loads in a panel.',
title: i18n.translate('embeddableApi.panelBadgeTrigger.title', {
defaultMessage: 'Panel badges',
}),
description: i18n.translate('embeddableApi.panelBadgeTrigger.description', {
defaultMessage: 'Actions appear in title bar when an embeddable loads in a panel.',
}),
};

export const PANEL_NOTIFICATION_TRIGGER = 'PANEL_NOTIFICATION_TRIGGER';
export const panelNotificationTrigger: Trigger<'PANEL_NOTIFICATION_TRIGGER'> = {
id: PANEL_NOTIFICATION_TRIGGER,
title: 'Panel notifications',
description: 'Actions appear in top-right corner of a panel.',
title: i18n.translate('embeddableApi.panelNotificationTrigger.title', {
defaultMessage: 'Panel notifications',
}),
description: i18n.translate('embeddableApi.panelNotificationTrigger.description', {
defaultMessage: 'Actions appear in top-right corner of a panel.',
}),
};

export const isValueClickTriggerContext = (
context: ChartActionContext
): context is ValueClickContext => context.data && 'data' in context.data;

export const isRangeSelectTriggerContext = (
context: ChartActionContext
): context is RangeSelectContext => context.data && 'range' in context.data;

export const isContextMenuTriggerContext = (context: unknown): context is EmbeddableContext =>
!!context &&
typeof context === 'object' &&
!!(context as EmbeddableContext).embeddable &&
typeof (context as EmbeddableContext).embeddable === 'object';
7 changes: 6 additions & 1 deletion src/plugins/embeddable/public/public.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,11 @@ export interface IEmbeddable<I extends EmbeddableInput = EmbeddableInput, O exte
updateInput(changes: Partial<I>): void;
}

// Warning: (ae-missing-release-tag) "isContextMenuTriggerContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
export const isContextMenuTriggerContext: (context: unknown) => context is EmbeddableContext;

// Warning: (ae-missing-release-tag) "isErrorEmbeddable" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
Expand Down Expand Up @@ -884,7 +889,7 @@ export const withEmbeddableSubscription: <I extends EmbeddableInput, O extends E
// src/plugins/embeddable/common/types.ts:59:3 - (ae-forgotten-export) The symbol "TimeRange" needs to be exported by the entry point index.d.ts
// src/plugins/embeddable/common/types.ts:64:3 - (ae-forgotten-export) The symbol "Query" needs to be exported by the entry point index.d.ts
// src/plugins/embeddable/common/types.ts:69:3 - (ae-forgotten-export) The symbol "Filter" needs to be exported by the entry point index.d.ts
// src/plugins/embeddable/public/lib/triggers/triggers.ts:45:5 - (ae-forgotten-export) The symbol "Datatable" needs to be exported by the entry point index.d.ts
// src/plugins/embeddable/public/lib/triggers/triggers.ts:46:5 - (ae-forgotten-export) The symbol "Datatable" needs to be exported by the entry point index.d.ts

// (No @packageDocumentation comment for this package)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ import {
} from '../../../../../../../src/plugins/ui_actions/public';

/**
* We know that VALUE_CLICK_TRIGGER and SELECT_RANGE_TRIGGER are also triggering APPLY_FILTER_TRIGGER
* This function appends APPLY_FILTER_TRIGGER to list of triggers if VALUE_CLICK_TRIGGER or SELECT_RANGE_TRIGGER
* We know that VALUE_CLICK_TRIGGER and SELECT_RANGE_TRIGGER are also triggering APPLY_FILTER_TRIGGER.
* This function appends APPLY_FILTER_TRIGGER to the list of triggers if either VALUE_CLICK_TRIGGER
* or SELECT_RANGE_TRIGGER was executed.
*
* TODO: this probably should be part of uiActions infrastructure,
* but dynamic implementation of nested trigger doesn't allow to statically express such relations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ describe('isCompatible', () => {
});
});

test('not compatible if no triggers intersection', async () => {
test('not compatible if no triggers intersect', async () => {
await assertNonCompatibility({
actionFactoriesTriggers: [],
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,12 @@ import { ActionByType } from '../../../../../../../../src/plugins/ui_actions/pub
import { toMountPoint } from '../../../../../../../../src/plugins/kibana_react/public';
import {
isEnhancedEmbeddable,
embeddableEnhancedContextMenuDrilldownGrouping,
embeddableEnhancedDrilldownGrouping,
} from '../../../../../../embeddable_enhanced/public';
import { EmbeddableContext } from '../../../../../../../../src/plugins/embeddable/public';
import {
CONTEXT_MENU_TRIGGER,
EmbeddableContext,
} from '../../../../../../../../src/plugins/embeddable/public';
import { StartDependencies } from '../../../../plugin';
import { StartServicesGetter } from '../../../../../../../../src/plugins/kibana_utils/public';
import { ensureNestedTriggers } from '../drilldown_shared';
Expand All @@ -27,7 +30,7 @@ export class FlyoutCreateDrilldownAction implements ActionByType<typeof OPEN_FLY
public readonly type = OPEN_FLYOUT_ADD_DRILLDOWN;
public readonly id = OPEN_FLYOUT_ADD_DRILLDOWN;
public order = 12;
public grouping = embeddableEnhancedContextMenuDrilldownGrouping;
public grouping = embeddableEnhancedDrilldownGrouping;

constructor(protected readonly params: OpenFlyoutAddDrilldownParams) {}

Expand Down Expand Up @@ -83,7 +86,7 @@ export class FlyoutCreateDrilldownAction implements ActionByType<typeof OPEN_FLY
onClose={() => handle.close()}
viewMode={'create'}
dynamicActionManager={embeddable.enhancements.dynamicActions}
triggers={ensureNestedTriggers(embeddable.supportedTriggers())}
triggers={[...ensureNestedTriggers(embeddable.supportedTriggers()), CONTEXT_MENU_TRIGGER]}
placeContext={{ embeddable }}
/>
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@ import {
reactToUiComponent,
toMountPoint,
} from '../../../../../../../../src/plugins/kibana_react/public';
import { EmbeddableContext, ViewMode } from '../../../../../../../../src/plugins/embeddable/public';
import {
EmbeddableContext,
ViewMode,
CONTEXT_MENU_TRIGGER,
} from '../../../../../../../../src/plugins/embeddable/public';
import { txtDisplayName } from './i18n';
import { MenuItem } from './menu_item';
import {
isEnhancedEmbeddable,
embeddableEnhancedContextMenuDrilldownGrouping,
embeddableEnhancedDrilldownGrouping,
} from '../../../../../../embeddable_enhanced/public';
import { StartDependencies } from '../../../../plugin';
import { StartServicesGetter } from '../../../../../../../../src/plugins/kibana_utils/public';
Expand All @@ -31,7 +35,7 @@ export class FlyoutEditDrilldownAction implements ActionByType<typeof OPEN_FLYOU
public readonly type = OPEN_FLYOUT_EDIT_DRILLDOWN;
public readonly id = OPEN_FLYOUT_EDIT_DRILLDOWN;
public order = 10;
public grouping = embeddableEnhancedContextMenuDrilldownGrouping;
public grouping = embeddableEnhancedDrilldownGrouping;

constructor(protected readonly params: FlyoutEditDrilldownParams) {}

Expand Down Expand Up @@ -67,7 +71,7 @@ export class FlyoutEditDrilldownAction implements ActionByType<typeof OPEN_FLYOU
onClose={() => handle.close()}
viewMode={'manage'}
dynamicActionManager={embeddable.enhancements.dynamicActions}
triggers={ensureNestedTriggers(embeddable.supportedTriggers())}
triggers={[...ensureNestedTriggers(embeddable.supportedTriggers()), CONTEXT_MENU_TRIGGER]}
placeContext={{ embeddable }}
/>
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@

import React from 'react';
import { reactToUiComponent } from '../../../../../../src/plugins/kibana_react/public';
import { ChartActionContext, IEmbeddable } from '../../../../../../src/plugins/embeddable/public';
import {
ChartActionContext,
CONTEXT_MENU_TRIGGER,
IEmbeddable,
} from '../../../../../../src/plugins/embeddable/public';
import { CollectConfigProps as CollectConfigPropsBase } from '../../../../../../src/plugins/kibana_utils/public';
import {
SELECT_RANGE_TRIGGER,
Expand Down Expand Up @@ -34,7 +38,10 @@ interface UrlDrilldownDeps {

export type ActionContext = ChartActionContext;
export type Config = UrlDrilldownConfig;
export type UrlTrigger = typeof VALUE_CLICK_TRIGGER | typeof SELECT_RANGE_TRIGGER;
export type UrlTrigger =
| typeof CONTEXT_MENU_TRIGGER
| typeof VALUE_CLICK_TRIGGER
| typeof SELECT_RANGE_TRIGGER;
export interface ActionFactoryContext extends BaseActionFactoryContext<UrlTrigger> {
embeddable?: IEmbeddable;
}
Expand All @@ -58,7 +65,7 @@ export class UrlDrilldown implements Drilldown<Config, UrlTrigger, ActionFactory
public readonly euiIcon = 'link';

supportedTriggers(): UrlTrigger[] {
return [VALUE_CLICK_TRIGGER, SELECT_RANGE_TRIGGER];
return [VALUE_CLICK_TRIGGER, SELECT_RANGE_TRIGGER, CONTEXT_MENU_TRIGGER];
}

private readonly ReactCollectConfig: React.FC<CollectConfigProps> = ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,25 +87,25 @@ describe('VALUE_CLICK_TRIGGER', () => {
]) as ValueClickTriggerEventScope;
expect(mockEventScope.points.length).toBeGreaterThan(3);
expect(mockEventScope.points).toMatchInlineSnapshot(`
Array [
Object {
"key": "event.points.0.key",
"value": "event.points.0.value",
},
Object {
"key": "event.points.1.key",
"value": "event.points.1.value",
},
Object {
"key": "event.points.2.key",
"value": "event.points.2.value",
},
Object {
"key": "event.points.3.key",
"value": "event.points.3.value",
},
]
`);
Array [
Object {
"key": "event.points.0.key",
"value": "event.points.0.value",
},
Object {
"key": "event.points.1.key",
"value": "event.points.1.value",
},
Object {
"key": "event.points.2.key",
"value": "event.points.2.value",
},
Object {
"key": "event.points.3.key",
"value": "event.points.3.value",
},
]
`);
});
});

Expand All @@ -130,3 +130,12 @@ describe('VALUE_CLICK_TRIGGER', () => {
});
});
});

describe('CONTEXT_MENU_TRIGGER', () => {
test('getMockEventScope() results in empty scope', () => {
const mockEventScope = getMockEventScope([
'CONTEXT_MENU_TRIGGER',
]) as ValueClickTriggerEventScope;
expect(mockEventScope).toEqual({});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@ import {
IEmbeddable,
isRangeSelectTriggerContext,
isValueClickTriggerContext,
isContextMenuTriggerContext,
RangeSelectContext,
ValueClickContext,
} from '../../../../../../src/plugins/embeddable/public';
import type { ActionContext, ActionFactoryContext, UrlTrigger } from './url_drilldown';
import { SELECT_RANGE_TRIGGER } from '../../../../../../src/plugins/ui_actions/public';
import {
SELECT_RANGE_TRIGGER,
VALUE_CLICK_TRIGGER,
} from '../../../../../../src/plugins/ui_actions/public';

type ContextScopeInput = ActionContext | ActionFactoryContext;

Expand Down Expand Up @@ -101,7 +105,10 @@ export function getContextScope(contextScopeInput: ContextScopeInput): UrlDrilld
* URL drilldown event scope,
* available as {{event.$}}
*/
export type UrlDrilldownEventScope = ValueClickTriggerEventScope | RangeSelectTriggerEventScope;
export type UrlDrilldownEventScope =
| ValueClickTriggerEventScope
| RangeSelectTriggerEventScope
| ContextMenuTriggerEventScope;
export type EventScopeInput = ActionContext;
export interface ValueClickTriggerEventScope {
key?: string;
Expand All @@ -115,11 +122,15 @@ export interface RangeSelectTriggerEventScope {
to?: string | number;
}

export type ContextMenuTriggerEventScope = object;

export function getEventScope(eventScopeInput: EventScopeInput): UrlDrilldownEventScope {
if (isRangeSelectTriggerContext(eventScopeInput)) {
return getEventScopeFromRangeSelectTriggerContext(eventScopeInput);
} else if (isValueClickTriggerContext(eventScopeInput)) {
return getEventScopeFromValueClickTriggerContext(eventScopeInput);
} else if (isContextMenuTriggerContext(eventScopeInput)) {
return {};
} else {
throw new Error("UrlDrilldown [getEventScope] can't build scope from not supported trigger");
}
Expand Down Expand Up @@ -169,7 +180,9 @@ export function getMockEventScope([trigger]: UrlTrigger[]): UrlDrilldownEventSco
from: new Date(Date.now() - 15 * 60 * 1000).toISOString(), // 15 minutes ago
to: new Date().toISOString(),
};
} else {
}

if (trigger === VALUE_CLICK_TRIGGER) {
// number of mock points to generate
// should be larger or equal of any possible data points length emitted by VALUE_CLICK_TRIGGER
const nPoints = 4;
Expand All @@ -184,6 +197,8 @@ export function getMockEventScope([trigger]: UrlTrigger[]): UrlDrilldownEventSco
points,
};
}

return {};
}

type Primitive = string | number | boolean | null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,19 @@
* you may not use this file except in compliance with the Elastic License.
*/

import { i18n } from '@kbn/i18n';
import { IEmbeddable } from '../../../../../src/plugins/embeddable/public';
import { UiActionsPresentableGrouping as PresentableGrouping } from '../../../../../src/plugins/ui_actions/public';

export const contextMenuDrilldownGrouping: PresentableGrouping<{
export const drilldownGrouping: PresentableGrouping<{
embeddable?: IEmbeddable;
}> = [
{
id: 'drilldowns',
getDisplayName: () => 'Drilldowns',
getDisplayName: () =>
i18n.translate('xpack.embeddableEnhanced.Drilldowns', {
defaultMessage: 'Drilldowns',
}),
getIconType: () => 'symlink',
order: 25,
},
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugins/embeddable_enhanced/public/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ export function plugin(context: PluginInitializerContext) {

export { EnhancedEmbeddable, EnhancedEmbeddableContext } from './types';
export { isEnhancedEmbeddable } from './embeddables';
export { contextMenuDrilldownGrouping as embeddableEnhancedContextMenuDrilldownGrouping } from './actions';
export { drilldownGrouping as embeddableEnhancedDrilldownGrouping } from './actions';
Loading