Skip to content

Commit

Permalink
Context menu trigger for URL Drilldown (#81158)
Browse files Browse the repository at this point in the history
* feat: 🎸 add context menu trigger to URL drilldown

* fix: πŸ› translate "Drilldowns" grouping title

* feat: 🎸 add dynamic action grouping to dynamic actions

* fix: πŸ› add translations to trigger texts

* feat: 🎸 enambe ctx menu trigger in both flyouts, move to end

* fix: πŸ› show context menu event scope variable sfor ctx menu

* test: πŸ’ add tests

* fix: πŸ› use correct namespace for translation keys

* docs: ✏️ update autogenerated docs

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
streamich and kibanamachine authored Oct 30, 2020
1 parent 21615c1 commit aaadbe8
Show file tree
Hide file tree
Showing 17 changed files with 181 additions and 54 deletions.
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

0 comments on commit aaadbe8

Please sign in to comment.