Skip to content

Commit

Permalink
[Dashboard Navigation] Add Links telemetry (elastic#171877)
Browse files Browse the repository at this point in the history
Closes elastic#164305

## Summary

This PR adds two `uiCounters` to keep track of when something is clicked
in the new Links panel:

1. `dashboardLink:click` - counts when a dashboard link is clicked
2. `externalLink:click` - counts when an external link is clicked

These counters can be tracked via the `kibana-ui-counters` data view on
the telemetry clusters, like so:

![Screenshot 2023-11-23 at 1 37
26 PM](https://github.com/elastic/kibana/assets/8698078/fe719121-73e3-4b53-8440-5a725a1a7c98)

Note that this **only** applies if the `onClick` method is called; if
the user, for example, right clicks on the link and selects "Open in new
tab" instead, this "click" will not be tracked. To my knowledge, there
is no way to track these types of clicks.

### For maintainers

- [ ] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)

---------

Co-authored-by: kibanamachine <[email protected]>
  • Loading branch information
Heenawter and kibanamachine authored Nov 27, 2023
1 parent 618cc48 commit 31a8b7b
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 21 deletions.
2 changes: 1 addition & 1 deletion src/plugins/links/kibana.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"uiActionsEnhanced",
"visualizations"
],
"optionalPlugins": ["triggersActionsUi"],
"optionalPlugins": ["triggersActionsUi", "usageCollection"],
"requiredBundles": ["savedObjects"]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import useAsync from 'react-use/lib/useAsync';
import useObservable from 'react-use/lib/useObservable';

import { EuiButtonEmpty, EuiListGroupItem } from '@elastic/eui';
import { METRIC_TYPE } from '@kbn/analytics';
import {
DashboardLocatorParams,
getDashboardLocatorParamsFromEmbeddable,
Expand All @@ -22,7 +23,13 @@ import {
DEFAULT_DASHBOARD_DRILLDOWN_OPTIONS,
} from '@kbn/presentation-util-plugin/public';

import { Link, LinksLayoutType, LINKS_VERTICAL_LAYOUT } from '../../../common/content_management';
import {
DASHBOARD_LINK_TYPE,
Link,
LinksLayoutType,
LINKS_VERTICAL_LAYOUT,
} from '../../../common/content_management';
import { trackUiMetric } from '../../services/kibana_services';
import { useLinks } from '../links_hooks';
import { DashboardLinkStrings } from './dashboard_link_strings';
import { fetchDashboard } from './dashboard_link_tools';
Expand Down Expand Up @@ -97,9 +104,9 @@ export const DashboardLinkComponent = ({
/**
* Dashboard-to-dashboard navigation
*/
const { loading: loadingOnClickProps, value: onClickProps } = useAsync(async () => {
const onClickProps = useMemo(() => {
/** If the link points to the current dashboard, then there should be no `onClick` or `href` prop */
if (link.destination === parentDashboardId) return;
if (!link.destination || link.destination === parentDashboardId) return;

const linkOptions = {
...DEFAULT_DASHBOARD_DRILLDOWN_OPTIONS,
Expand All @@ -118,6 +125,8 @@ export const DashboardLinkComponent = ({
return {
href,
onClick: async (event: React.MouseEvent) => {
trackUiMetric?.(METRIC_TYPE.CLICK, `${DASHBOARD_LINK_TYPE}:click`);

/**
* If the link is being opened via a modified click, then we should use the default `href` navigation behaviour
* by passing all the dashboard state via the URL - this will keep behaviour consistent across all browsers.
Expand All @@ -132,26 +141,19 @@ export const DashboardLinkComponent = ({
if (linkOptions.openInNewTab) {
window.open(href, '_blank');
} else {
locator.navigate(params);
await locator.navigate(params);
}
},
};
}, [link]);
}, [link, dashboardContainer.locator, linksEmbeddable, parentDashboardId]);

useEffect(() => {
if (loadingDestinationDashboard || loadingOnClickProps) {
if (loadingDestinationDashboard) {
onLoading();
} else {
onRender();
}
}, [
link,
linksEmbeddable,
loadingDestinationDashboard,
loadingOnClickProps,
onLoading,
onRender,
]);
}, [link, linksEmbeddable, loadingDestinationDashboard, onLoading, onRender]);

const id = `dashboardLink--${link.id}`;

Expand All @@ -178,7 +180,7 @@ export const DashboardLinkComponent = ({
}}
iconType={error ? 'warning' : undefined}
iconProps={{ className: 'dashboardLinkIcon' }}
isDisabled={Boolean(error) || loadingOnClickProps}
isDisabled={Boolean(error)}
className={classNames('linksPanelLink', {
linkCurrent: link.destination === parentDashboardId,
dashboardLinkError: Boolean(error),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,21 @@
import React, { useMemo, useState } from 'react';
import useMount from 'react-use/lib/useMount';

import { EuiListGroupItem } from '@elastic/eui';
import { METRIC_TYPE } from '@kbn/analytics';
import {
UrlDrilldownOptions,
DEFAULT_URL_DRILLDOWN_OPTIONS,
UrlDrilldownOptions,
} from '@kbn/ui-actions-enhanced-plugin/public';
import { EuiListGroupItem } from '@elastic/eui';

import {
EXTERNAL_LINK_TYPE,
Link,
LinksLayoutType,
LINKS_VERTICAL_LAYOUT,
} from '../../../common/content_management';
import { coreServices, trackUiMetric } from '../../services/kibana_services';
import { validateUrl } from './external_link_tools';
import { coreServices } from '../../services/kibana_services';
import { Link, LinksLayoutType, LINKS_VERTICAL_LAYOUT } from '../../../common/content_management';

export const ExternalLinkComponent = ({
link,
Expand Down Expand Up @@ -78,6 +84,8 @@ export const ExternalLinkComponent = ({
onClick={async (event) => {
if (!destination) return;

trackUiMetric?.(METRIC_TYPE.CLICK, `${EXTERNAL_LINK_TYPE}:click`);

/** Only use `navigateToUrl` if we **aren't** opening in a new window/tab; otherwise, just use default href handling */
const modifiedClick = event.ctrlKey || event.metaKey || event.shiftKey;
if (!modifiedClick) {
Expand Down
2 changes: 2 additions & 0 deletions src/plugins/links/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { DashboardStart } from '@kbn/dashboard-plugin/public';
import { DashboardContainer } from '@kbn/dashboard-plugin/public/dashboard_container';
import { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public';
import { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public';
import { UsageCollectionStart } from '@kbn/usage-collection-plugin/public';
import { VisualizationsSetup } from '@kbn/visualizations-plugin/public';

import { APP_ICON, APP_NAME, CONTENT_ID, LATEST_VERSION } from '../common';
Expand All @@ -36,6 +37,7 @@ export interface LinksStartDependencies {
dashboard: DashboardStart;
presentationUtil: PresentationUtilPluginStart;
contentManagement: ContentManagementPublicStart;
usageCollection?: UsageCollectionStart;
}

export class LinksPlugin
Expand Down
10 changes: 9 additions & 1 deletion src/plugins/links/public/services/kibana_services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,25 @@

import { BehaviorSubject } from 'rxjs';

import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public';
import { CoreStart } from '@kbn/core/public';
import { DashboardStart } from '@kbn/dashboard-plugin/public';
import { EmbeddableStart } from '@kbn/embeddable-plugin/public';
import { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public';
import { ContentManagementPublicStart } from '@kbn/content-management-plugin/public';

import { CONTENT_ID } from '../../common';
import { LinksStartDependencies } from '../plugin';

export let coreServices: CoreStart;
export let dashboardServices: DashboardStart;
export let embeddableService: EmbeddableStart;
export let presentationUtil: PresentationUtilPluginStart;
export let contentManagement: ContentManagementPublicStart;
export let trackUiMetric: (
type: string,
eventNames: string | string[],
count?: number
) => void | undefined;

const servicesReady$ = new BehaviorSubject(false);

Expand All @@ -42,6 +48,8 @@ export const setKibanaServices = (kibanaCore: CoreStart, deps: LinksStartDepende
embeddableService = deps.embeddable;
presentationUtil = deps.presentationUtil;
contentManagement = deps.contentManagement;
if (deps.usageCollection)
trackUiMetric = deps.usageCollection.reportUiCounter.bind(deps.usageCollection, CONTENT_ID);

servicesReady$.next(true);
};
2 changes: 2 additions & 0 deletions src/plugins/links/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
"@kbn/core-plugins-server",
"@kbn/react-kibana-mount",
"@kbn/react-kibana-context-theme",
"@kbn/analytics",
"@kbn/usage-collection-plugin",
"@kbn/visualizations-plugin",
"@kbn/core-mount-utils-browser"
],
Expand Down

0 comments on commit 31a8b7b

Please sign in to comment.