Skip to content

Commit 90701e7

Browse files
committed
Drilldown count tooltip (#65105)
* feat: 🎸 add tooltip ability to ui_actions * feat: 🎸 add tooltip support to drilldown count notification * test: πŸ’ add drilldown tooltip text tests * fix: πŸ› improve tooltip texts * fix: πŸ› put tooltip on top * fix: πŸ› add missing method to ActionFactory * fix: πŸ› improve handling of optional method
1 parent 7fc70b5 commit 90701e7

7 files changed

Lines changed: 99 additions & 10 deletions

File tree

β€Žsrc/plugins/embeddable/public/lib/panel/panel_header/panel_header.tsxβ€Ž

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,34 @@ function renderNotifications(
6262
notifications: Array<Action<EmbeddableContext>>,
6363
embeddable: IEmbeddable
6464
) {
65-
return notifications.map(notification => (
66-
<EuiNotificationBadge
67-
data-test-subj={`embeddablePanelNotification-${notification.id}`}
68-
key={notification.id}
69-
style={{ marginTop: '4px', marginRight: '4px' }}
70-
onClick={() => notification.execute({ embeddable })}
71-
>
72-
{notification.getDisplayName({ embeddable })}
73-
</EuiNotificationBadge>
74-
));
65+
return notifications.map(notification => {
66+
const context = { embeddable };
67+
68+
let badge = (
69+
<EuiNotificationBadge
70+
data-test-subj={`embeddablePanelNotification-${notification.id}`}
71+
key={notification.id}
72+
style={{ marginTop: '4px', marginRight: '4px' }}
73+
onClick={() => notification.execute(context)}
74+
>
75+
{notification.getDisplayName(context)}
76+
</EuiNotificationBadge>
77+
);
78+
79+
if (notification.getDisplayNameTooltip) {
80+
const tooltip = notification.getDisplayNameTooltip(context);
81+
82+
if (tooltip) {
83+
badge = (
84+
<EuiToolTip position="top" delay="regular" content={tooltip}>
85+
{badge}
86+
</EuiToolTip>
87+
);
88+
}
89+
}
90+
91+
return badge;
92+
});
7593
}
7694

7795
function renderTooltip(description: string) {

β€Žsrc/plugins/ui_actions/public/actions/action_internal.tsβ€Ž

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ export class ActionInternal<A extends ActionDefinition = ActionDefinition>
4848
return this.definition.getDisplayName(context);
4949
}
5050

51+
public getDisplayNameTooltip(context: Context<A>): string {
52+
if (!this.definition.getDisplayNameTooltip) return '';
53+
return this.definition.getDisplayNameTooltip(context);
54+
}
55+
5156
public async isCompatible(context: Context<A>): Promise<boolean> {
5257
if (!this.definition.isCompatible) return true;
5358
return await this.definition.isCompatible(context);

β€Žsrc/plugins/ui_actions/public/util/presentable.tsβ€Ž

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@ export interface Presentable<Context extends object = object> {
5050
*/
5151
getDisplayName(context: Context): string;
5252

53+
/**
54+
* Returns tooltip text which should be displayed when user hovers this object.
55+
* Should return empty string if tooltip should not be displayed.
56+
*/
57+
getDisplayNameTooltip(context: Context): string;
58+
5359
/**
5460
* This method should return a link if this item can be clicked on. The link
5561
* is used to navigate user if user middle-clicks it or Ctrl + clicks or

β€Žx-pack/.i18nrc.jsonβ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"xpack.dashboardMode": "legacy/plugins/dashboard_mode",
1515
"xpack.data": "plugins/data_enhanced",
1616
"xpack.drilldowns": "plugins/drilldowns",
17+
"xpack.embeddableEnhanced": "plugins/embeddable_enhanced",
1718
"xpack.endpoint": "plugins/endpoint",
1819
"xpack.features": "plugins/features",
1920
"xpack.fileUpload": "plugins/file_upload",

β€Žx-pack/plugins/advanced_ui_actions/public/dynamic_actions/action_factory.tsβ€Ž

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ export class ActionFactory<
4242
return this.def.getDisplayName(context);
4343
}
4444

45+
public getDisplayNameTooltip(context: FactoryContext): string {
46+
return '';
47+
}
48+
4549
public async isCompatible(context: FactoryContext): Promise<boolean> {
4650
if (!this.def.isCompatible) return true;
4751
return await this.def.isCompatible(context);

β€Žx-pack/plugins/embeddable_enhanced/public/actions/panel_notifications_action.test.tsβ€Ž

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,40 @@ describe('PanelNotificationsAction', () => {
4747
});
4848
});
4949

50+
describe('getDisplayNameTooltip', () => {
51+
test('returns empty string if embeddable has no event', async () => {
52+
const context = createContext();
53+
const action = new PanelNotificationsAction();
54+
55+
const name = await action.getDisplayNameTooltip(context);
56+
expect(name).toBe('');
57+
});
58+
59+
test('returns "1 drilldown" if embeddable has one event', async () => {
60+
const context = createContext([{}]);
61+
const action = new PanelNotificationsAction();
62+
63+
const name = await action.getDisplayNameTooltip(context);
64+
expect(name).toBe('Panel has 1 drilldown');
65+
});
66+
67+
test('returns "2 drilldowns" if embeddable has two events', async () => {
68+
const context = createContext([{}, {}]);
69+
const action = new PanelNotificationsAction();
70+
71+
const name = await action.getDisplayNameTooltip(context);
72+
expect(name).toBe('Panel has 2 drilldowns');
73+
});
74+
75+
test('returns "3 drilldowns" if embeddable has three events', async () => {
76+
const context = createContext([{}, {}, {}]);
77+
const action = new PanelNotificationsAction();
78+
79+
const name = await action.getDisplayNameTooltip(context);
80+
expect(name).toBe('Panel has 3 drilldowns');
81+
});
82+
});
83+
5084
describe('isCompatible', () => {
5185
test('returns false if not in "edit" mode', async () => {
5286
const context = createContext([{}]);

β€Žx-pack/plugins/embeddable_enhanced/public/actions/panel_notifications_action.tsβ€Ž

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,26 @@
44
* you may not use this file except in compliance with the Elastic License.
55
*/
66

7+
import { i18n } from '@kbn/i18n';
78
import { UiActionsActionDefinition as ActionDefinition } from '../../../../../src/plugins/ui_actions/public';
89
import { ViewMode } from '../../../../../src/plugins/embeddable/public';
910
import { EnhancedEmbeddableContext, EnhancedEmbeddable } from '../types';
1011

12+
export const txtOneDrilldown = i18n.translate(
13+
'xpack.embeddableEnhanced.actions.panelNotifications.oneDrilldown',
14+
{
15+
defaultMessage: 'Panel has 1 drilldown',
16+
}
17+
);
18+
19+
export const txtManyDrilldowns = (count: number) =>
20+
i18n.translate('xpack.embeddableEnhanced.actions.panelNotifications.manyDrilldowns', {
21+
defaultMessage: 'Panel has {count} drilldowns',
22+
values: {
23+
count: String(count),
24+
},
25+
});
26+
1127
export const ACTION_PANEL_NOTIFICATIONS = 'ACTION_PANEL_NOTIFICATIONS';
1228

1329
/**
@@ -25,6 +41,11 @@ export class PanelNotificationsAction implements ActionDefinition<EnhancedEmbedd
2541
return String(this.getEventCount(embeddable));
2642
};
2743

44+
public readonly getDisplayNameTooltip = ({ embeddable }: EnhancedEmbeddableContext) => {
45+
const count = this.getEventCount(embeddable);
46+
return !count ? '' : count === 1 ? txtOneDrilldown : txtManyDrilldowns(count);
47+
};
48+
2849
public readonly isCompatible = async ({ embeddable }: EnhancedEmbeddableContext) => {
2950
if (embeddable.getInput().viewMode !== ViewMode.EDIT) return false;
3051
return this.getEventCount(embeddable) > 0;

0 commit comments

Comments
Β (0)