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
This commit is contained in:
Vadim Dalecky 2020-05-08 10:05:27 +02:00 committed by GitHub
parent e35a74375a
commit 86bafec3a4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 99 additions and 10 deletions

View file

@ -62,16 +62,34 @@ function renderNotifications(
notifications: Array<Action<EmbeddableContext>>,
embeddable: IEmbeddable
) {
return notifications.map(notification => (
<EuiNotificationBadge
data-test-subj={`embeddablePanelNotification-${notification.id}`}
key={notification.id}
style={{ marginTop: '4px', marginRight: '4px' }}
onClick={() => notification.execute({ embeddable })}
>
{notification.getDisplayName({ embeddable })}
</EuiNotificationBadge>
));
return notifications.map(notification => {
const context = { embeddable };
let badge = (
<EuiNotificationBadge
data-test-subj={`embeddablePanelNotification-${notification.id}`}
key={notification.id}
style={{ marginTop: '4px', marginRight: '4px' }}
onClick={() => notification.execute(context)}
>
{notification.getDisplayName(context)}
</EuiNotificationBadge>
);
if (notification.getDisplayNameTooltip) {
const tooltip = notification.getDisplayNameTooltip(context);
if (tooltip) {
badge = (
<EuiToolTip position="top" delay="regular" content={tooltip}>
{badge}
</EuiToolTip>
);
}
}
return badge;
});
}
function renderTooltip(description: string) {

View file

@ -48,6 +48,11 @@ export class ActionInternal<A extends ActionDefinition = ActionDefinition>
return this.definition.getDisplayName(context);
}
public getDisplayNameTooltip(context: Context<A>): string {
if (!this.definition.getDisplayNameTooltip) return '';
return this.definition.getDisplayNameTooltip(context);
}
public async isCompatible(context: Context<A>): Promise<boolean> {
if (!this.definition.isCompatible) return true;
return await this.definition.isCompatible(context);

View file

@ -50,6 +50,12 @@ export interface Presentable<Context extends object = object> {
*/
getDisplayName(context: Context): string;
/**
* Returns tooltip text which should be displayed when user hovers this object.
* Should return empty string if tooltip should not be displayed.
*/
getDisplayNameTooltip(context: Context): string;
/**
* This method should return a link if this item can be clicked on. The link
* is used to navigate user if user middle-clicks it or Ctrl + clicks or

View file

@ -14,6 +14,7 @@
"xpack.dashboardMode": "legacy/plugins/dashboard_mode",
"xpack.data": "plugins/data_enhanced",
"xpack.drilldowns": "plugins/drilldowns",
"xpack.embeddableEnhanced": "plugins/embeddable_enhanced",
"xpack.endpoint": "plugins/endpoint",
"xpack.features": "plugins/features",
"xpack.fileUpload": "plugins/file_upload",

View file

@ -42,6 +42,10 @@ export class ActionFactory<
return this.def.getDisplayName(context);
}
public getDisplayNameTooltip(context: FactoryContext): string {
return '';
}
public async isCompatible(context: FactoryContext): Promise<boolean> {
if (!this.def.isCompatible) return true;
return await this.def.isCompatible(context);

View file

@ -47,6 +47,40 @@ describe('PanelNotificationsAction', () => {
});
});
describe('getDisplayNameTooltip', () => {
test('returns empty string if embeddable has no event', async () => {
const context = createContext();
const action = new PanelNotificationsAction();
const name = await action.getDisplayNameTooltip(context);
expect(name).toBe('');
});
test('returns "1 drilldown" if embeddable has one event', async () => {
const context = createContext([{}]);
const action = new PanelNotificationsAction();
const name = await action.getDisplayNameTooltip(context);
expect(name).toBe('Panel has 1 drilldown');
});
test('returns "2 drilldowns" if embeddable has two events', async () => {
const context = createContext([{}, {}]);
const action = new PanelNotificationsAction();
const name = await action.getDisplayNameTooltip(context);
expect(name).toBe('Panel has 2 drilldowns');
});
test('returns "3 drilldowns" if embeddable has three events', async () => {
const context = createContext([{}, {}, {}]);
const action = new PanelNotificationsAction();
const name = await action.getDisplayNameTooltip(context);
expect(name).toBe('Panel has 3 drilldowns');
});
});
describe('isCompatible', () => {
test('returns false if not in "edit" mode', async () => {
const context = createContext([{}]);

View file

@ -4,10 +4,26 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { i18n } from '@kbn/i18n';
import { UiActionsActionDefinition as ActionDefinition } from '../../../../../src/plugins/ui_actions/public';
import { ViewMode } from '../../../../../src/plugins/embeddable/public';
import { EnhancedEmbeddableContext, EnhancedEmbeddable } from '../types';
export const txtOneDrilldown = i18n.translate(
'xpack.embeddableEnhanced.actions.panelNotifications.oneDrilldown',
{
defaultMessage: 'Panel has 1 drilldown',
}
);
export const txtManyDrilldowns = (count: number) =>
i18n.translate('xpack.embeddableEnhanced.actions.panelNotifications.manyDrilldowns', {
defaultMessage: 'Panel has {count} drilldowns',
values: {
count: String(count),
},
});
export const ACTION_PANEL_NOTIFICATIONS = 'ACTION_PANEL_NOTIFICATIONS';
/**
@ -25,6 +41,11 @@ export class PanelNotificationsAction implements ActionDefinition<EnhancedEmbedd
return String(this.getEventCount(embeddable));
};
public readonly getDisplayNameTooltip = ({ embeddable }: EnhancedEmbeddableContext) => {
const count = this.getEventCount(embeddable);
return !count ? '' : count === 1 ? txtOneDrilldown : txtManyDrilldowns(count);
};
public readonly isCompatible = async ({ embeddable }: EnhancedEmbeddableContext) => {
if (embeddable.getInput().viewMode !== ViewMode.EDIT) return false;
return this.getEventCount(embeddable) > 0;