[Search][Homepage] Add Telemetry support (#188364)

## Summary

Adds support for telemetry tracking to Search Homepage for both ES3 &
Stack.

Additionally fixed a small markup bug with the page header.
This commit is contained in:
Rodney Norris 2024-07-16 08:14:28 -05:00 committed by GitHub
parent 5756b299a3
commit ef2d7b29ba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 141 additions and 33 deletions

View file

@ -12,22 +12,25 @@ import { KibanaRenderContextProvider } from '@kbn/react-kibana-context-render';
import { KibanaContextProvider } from '@kbn/kibana-react-plugin/public';
import { I18nProvider } from '@kbn/i18n-react';
import { Router } from '@kbn/shared-ux-router';
import { SearchHomepageAppPluginStartDependencies } from './types';
import { SearchHomepageServicesContext } from './types';
import { HomepageRouter } from './router';
import { UsageTrackerContextProvider } from './contexts/usage_tracker_context';
export const renderApp = async (
core: CoreStart,
services: SearchHomepageAppPluginStartDependencies,
services: SearchHomepageServicesContext,
element: HTMLElement
) => {
ReactDOM.render(
<KibanaRenderContextProvider {...core}>
<KibanaContextProvider services={{ ...core, ...services }}>
<I18nProvider>
<Router history={services.history}>
<HomepageRouter />
</Router>
</I18nProvider>
<UsageTrackerContextProvider usageCollection={services.usageCollection}>
<I18nProvider>
<Router history={services.history}>
<HomepageRouter />
</Router>
</I18nProvider>
</UsageTrackerContextProvider>
</KibanaContextProvider>
</KibanaRenderContextProvider>,
element

View file

@ -10,6 +10,7 @@ import { FormattedMessage } from '@kbn/i18n-react';
import type { ConsolePluginStart } from '@kbn/console-plugin/public';
import { useKibana } from '../hooks/use_kibana';
import { useUsageTracker } from '../hooks/use_usage_tracker';
const canOpenConsole = (plugin?: ConsolePluginStart): boolean => {
if (!plugin) return false;
@ -21,11 +22,13 @@ export const ConsoleLinkButton = () => {
const {
services: { console: consolePlugin },
} = useKibana();
const usageTracker = useUsageTracker();
const openConsole = useCallback(() => {
usageTracker.click('get_started_in_console');
if (!canOpenConsole(consolePlugin)) return;
consolePlugin!.openEmbeddedConsole!();
}, [consolePlugin]);
}, [consolePlugin, usageTracker]);
if (consolePlugin === undefined || consolePlugin.openEmbeddedConsole === undefined) return null;
return (

View file

@ -4,7 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React from 'react';
import React, { useState, useCallback } from 'react';
import { EuiButtonEmpty, EuiFlexGroup, EuiFlyout, EuiHeaderLinks } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import {
@ -12,8 +12,15 @@ import {
ConnectionDetailsFlyoutContent,
} from '@kbn/cloud/connection_details';
import { useUsageTracker } from '../hooks/use_usage_tracker';
export const EndpointsHeaderAction = () => {
const [open, setOpen] = React.useState(false);
const usageTracker = useUsageTracker();
const [open, setOpen] = useState<boolean>(false);
const onClickEndpointsButton = useCallback(() => {
usageTracker.click('endpoints_and_api_keys');
setOpen(true);
}, [usageTracker]);
return (
<>
@ -22,7 +29,7 @@ export const EndpointsHeaderAction = () => {
<EuiButtonEmpty
iconType="endpoint"
size="s"
onClick={() => setOpen(true)}
onClick={onClickEndpointsButton}
data-test-subj="searchHomepageEndpointsHeaderActionEndpointsApiKeysButton"
data-telemetry-id="searchHomepageEndpointsHeaderActionEndpointsApiKeysButton"
>

View file

@ -17,13 +17,8 @@ export interface SearchHomepageHeaderProps {
export const SearchHomepageHeader = ({ showEndpointsAPIKeys }: SearchHomepageHeaderProps) => (
<EuiPageTemplate.Header
pageTitle={
<EuiTitle data-test-subj="search-homepage-header-title">
<h2>
<FormattedMessage
id="xpack.searchHomepage.pageTitle"
defaultMessage="Welcome to Search"
/>
</h2>
<EuiTitle data-test-subj="search-homepage-header-title" size="l">
<FormattedMessage id="xpack.searchHomepage.pageTitle" defaultMessage="Welcome to Search" />
</EuiTitle>
}
data-test-subj="search-homepage-header"

View file

@ -6,14 +6,20 @@
*/
import React from 'react';
import { UsageTrackerContextProvider } from '../contexts/usage_tracker_context';
import { useKibana } from '../hooks/use_kibana';
import { SearchHomepageBody } from './search_homepage_body';
import { SearchHomepageHeader } from './search_homepage_header';
export const App: React.FC = () => {
const {
services: { usageCollection },
} = useKibana();
return (
<>
<UsageTrackerContextProvider usageCollection={usageCollection}>
<SearchHomepageHeader showEndpointsAPIKeys={false} />
<SearchHomepageBody />
</>
</UsageTrackerContextProvider>
);
};

View file

@ -0,0 +1,43 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import React, { createContext, useContext, useMemo } from 'react';
import type {
UsageCollectionSetup,
UsageCollectionStart,
} from '@kbn/usage-collection-plugin/public';
import { createUsageTracker, createEmptyUsageTracker } from '../usage_tracker';
import { AppUsageTracker } from '../types';
const UsageTrackerContext = createContext<AppUsageTracker>(createEmptyUsageTracker());
export interface UsageTrackerContextProviderProps {
children: React.ReactNode | React.ReactNode[];
usageCollection?: UsageCollectionSetup | UsageCollectionStart;
}
export function UsageTrackerContextProvider({
children,
usageCollection,
}: UsageTrackerContextProviderProps) {
const usageTracker = useMemo(() => {
const homePageUsageTracker = createUsageTracker(usageCollection);
homePageUsageTracker.load('opened_app');
return homePageUsageTracker;
}, [usageCollection]);
return (
<UsageTrackerContext.Provider value={usageTracker}>{children}</UsageTrackerContext.Provider>
);
}
export const useUsageTracker = () => {
const ctx = useContext(UsageTrackerContext);
if (!ctx) {
throw new Error('UsageTrackerContext should be used inside of the UsageTrackerContextProvider');
}
return ctx;
};

View file

@ -0,0 +1,8 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export { useUsageTracker } from '../contexts/usage_tracker_context';

View file

@ -23,6 +23,7 @@ import {
SearchHomepagePluginStart,
SearchHomepageAppPluginStartDependencies,
SearchHomepageAppInfo,
SearchHomepageServicesContext,
} from './types';
const appInfo: SearchHomepageAppInfo = {
@ -56,7 +57,7 @@ export class SearchHomepagePlugin
async mount({ element, history }: AppMountParameters) {
const { renderApp } = await import('./application');
const [coreStart, depsStart] = await core.getStartServices();
const startDeps: SearchHomepageAppPluginStartDependencies = {
const startDeps: SearchHomepageServicesContext = {
...depsStart,
history,
};

View file

@ -6,9 +6,8 @@
*/
import type { ComponentProps, FC } from 'react';
import type { CloudSetup } from '@kbn/cloud-plugin/public';
import type { ConsolePluginStart } from '@kbn/console-plugin/public';
import type { AppMountParameters, HttpStart } from '@kbn/core/public';
import type { AppMountParameters } from '@kbn/core/public';
import type { SharePluginStart } from '@kbn/share-plugin/public';
import type { UsageCollectionStart } from '@kbn/usage-collection-plugin/public';
import type { App } from './components/stack_app';
@ -59,16 +58,17 @@ export interface SearchHomepagePluginStart {
}
export interface SearchHomepageAppPluginStartDependencies {
history: AppMountParameters['history'];
usageCollection?: UsageCollectionStart;
share: SharePluginStart;
console?: ConsolePluginStart;
share: SharePluginStart;
usageCollection?: UsageCollectionStart;
}
export interface SearchHomepageServicesContext {
http: HttpStart;
share: SharePluginStart;
cloud?: CloudSetup;
usageCollection?: UsageCollectionStart;
console?: ConsolePluginStart;
export interface SearchHomepageServicesContext extends SearchHomepageAppPluginStartDependencies {
history: AppMountParameters['history'];
}
export interface AppUsageTracker {
click: (eventName: string | string[]) => void;
count: (eventName: string | string[]) => void;
load: (eventName: string | string[]) => void;
}

View file

@ -0,0 +1,42 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
import { METRIC_TYPE, UiCounterMetricType } from '@kbn/analytics';
import type {
UsageCollectionSetup,
UsageCollectionStart,
} from '@kbn/usage-collection-plugin/public';
import { AppUsageTracker } from './types';
const APP_TRACKER_NAME = 'searchHomepage';
export function createUsageTracker(
usageCollection?: UsageCollectionSetup | UsageCollectionStart
): AppUsageTracker {
const track = (type: UiCounterMetricType, name: string | string[]) =>
usageCollection?.reportUiCounter(APP_TRACKER_NAME, type, name);
return {
click: (eventName: string | string[]) => {
track(METRIC_TYPE.CLICK, eventName);
},
count: (eventName: string | string[]) => {
track(METRIC_TYPE.COUNT, eventName);
},
load: (eventName: string | string[]) => {
track(METRIC_TYPE.LOADED, eventName);
},
};
}
export function createEmptyUsageTracker(): AppUsageTracker {
return {
click: (_eventName: string | string[]) => {},
count: (_eventName: string | string[]) => {},
load: (_eventName: string | string[]) => {},
};
}

View file

@ -18,12 +18,12 @@
"@kbn/shared-ux-page-kibana-template",
"@kbn/shared-ux-utility",
"@kbn/i18n",
"@kbn/cloud-plugin",
"@kbn/console-plugin",
"@kbn/share-plugin",
"@kbn/usage-collection-plugin",
"@kbn/config-schema",
"@kbn/cloud",
"@kbn/analytics",
],
"exclude": [
"target/**/*",