diff --git a/src/plugins/links/kibana.jsonc b/src/plugins/links/kibana.jsonc index a1e59cff9dc3..a058db8a03ce 100644 --- a/src/plugins/links/kibana.jsonc +++ b/src/plugins/links/kibana.jsonc @@ -17,7 +17,7 @@ "uiActionsEnhanced", "visualizations" ], - "optionalPlugins": ["triggersActionsUi"], + "optionalPlugins": ["triggersActionsUi", "usageCollection"], "requiredBundles": ["savedObjects"] } } diff --git a/src/plugins/links/public/components/dashboard_link/dashboard_link_component.tsx b/src/plugins/links/public/components/dashboard_link/dashboard_link_component.tsx index 4ad4608080b5..30977b593238 100644 --- a/src/plugins/links/public/components/dashboard_link/dashboard_link_component.tsx +++ b/src/plugins/links/public/components/dashboard_link/dashboard_link_component.tsx @@ -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, @@ -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'; @@ -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, @@ -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. @@ -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}`; @@ -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), diff --git a/src/plugins/links/public/components/external_link/external_link_component.tsx b/src/plugins/links/public/components/external_link/external_link_component.tsx index ac409cfbac4c..4af95c83cc32 100644 --- a/src/plugins/links/public/components/external_link/external_link_component.tsx +++ b/src/plugins/links/public/components/external_link/external_link_component.tsx @@ -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, @@ -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) { diff --git a/src/plugins/links/public/plugin.ts b/src/plugins/links/public/plugin.ts index 6569f6d76780..f72f45d4c6a2 100644 --- a/src/plugins/links/public/plugin.ts +++ b/src/plugins/links/public/plugin.ts @@ -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'; @@ -36,6 +37,7 @@ export interface LinksStartDependencies { dashboard: DashboardStart; presentationUtil: PresentationUtilPluginStart; contentManagement: ContentManagementPublicStart; + usageCollection?: UsageCollectionStart; } export class LinksPlugin diff --git a/src/plugins/links/public/services/kibana_services.ts b/src/plugins/links/public/services/kibana_services.ts index 76acd242f757..7536c1226279 100644 --- a/src/plugins/links/public/services/kibana_services.ts +++ b/src/plugins/links/public/services/kibana_services.ts @@ -8,12 +8,13 @@ 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; @@ -21,6 +22,11 @@ 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); @@ -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); }; diff --git a/src/plugins/links/tsconfig.json b/src/plugins/links/tsconfig.json index be7692c7fa43..f839243325d0 100644 --- a/src/plugins/links/tsconfig.json +++ b/src/plugins/links/tsconfig.json @@ -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" ],