mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 17:59:23 -04:00
[Global search] fix navigating app name (#159072)
## Summary Telemetry data for global search showed that all applications navigated to via global search were identified as `undefined`. ## Other changes This PR does some light refactoring in `x-pack/plugins/global_search_bar/public/components` in preparation for further work in https://github.com/elastic/kibana/issues/158874 and https://github.com/elastic/kibana/issues/158879 ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
This commit is contained in:
parent
031c237439
commit
6383f45ed0
7 changed files with 236 additions and 114 deletions
55
x-pack/plugins/global_search_bar/public/components/index.ts
Normal file
55
x-pack/plugins/global_search_bar/public/components/index.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* 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 { GlobalSearchResult } from '@kbn/global-search-plugin/public';
|
||||
|
||||
/* @internal */
|
||||
export enum COUNT_METRIC {
|
||||
UNHANDLED_ERROR = 'unhandled_error',
|
||||
SEARCH_REQUEST = 'search_request',
|
||||
SHORTCUT_USED = 'shortcut_used',
|
||||
SEARCH_FOCUS = 'search_focus',
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export enum CLICK_METRIC {
|
||||
USER_NAVIGATED_TO_APPLICATION = 'user_navigated_to_application',
|
||||
USER_NAVIGATED_TO_SAVED_OBJECT = 'user_navigated_to_saved_object',
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export const getClickMetric = (metric: CLICK_METRIC, context: string) => {
|
||||
return [metric, `${metric}_${context}`];
|
||||
};
|
||||
|
||||
/* @internal */
|
||||
export const isMac = navigator.platform.toLowerCase().indexOf('mac') >= 0;
|
||||
|
||||
/* @internal */
|
||||
export const blurEvent = new FocusEvent('focusout', {
|
||||
bubbles: true,
|
||||
});
|
||||
|
||||
const sortByScore = (a: GlobalSearchResult, b: GlobalSearchResult): number => {
|
||||
if (a.score < b.score) return 1;
|
||||
if (a.score > b.score) return -1;
|
||||
return 0;
|
||||
};
|
||||
|
||||
const sortByTitle = (a: GlobalSearchResult, b: GlobalSearchResult): number => {
|
||||
const titleA = a.title.toUpperCase(); // ignore upper and lowercase
|
||||
const titleB = b.title.toUpperCase(); // ignore upper and lowercase
|
||||
if (titleA < titleB) return -1;
|
||||
if (titleA > titleB) return 1;
|
||||
return 0;
|
||||
};
|
||||
|
||||
/* @internal */
|
||||
export const sort = {
|
||||
byScore: sortByScore,
|
||||
byTitle: sortByTitle,
|
||||
};
|
|
@ -14,6 +14,7 @@ import { globalSearchPluginMock } from '@kbn/global-search-plugin/public/mocks';
|
|||
import { GlobalSearchBatchedResults, GlobalSearchResult } from '@kbn/global-search-plugin/public';
|
||||
import { SearchBar } from './search_bar';
|
||||
import { __IntlProvider as IntlProvider } from '@kbn/i18n-react';
|
||||
import { TrackUiMetricFn } from '../types';
|
||||
|
||||
jest.mock(
|
||||
'react-virtualized-auto-sizer',
|
||||
|
@ -47,12 +48,15 @@ jest.useFakeTimers({ legacyFakeTimers: true });
|
|||
describe('SearchBar', () => {
|
||||
let searchService: ReturnType<typeof globalSearchPluginMock.createStartContract>;
|
||||
let applications: ReturnType<typeof applicationServiceMock.createStartContract>;
|
||||
let trackUiMetric: TrackUiMetricFn;
|
||||
|
||||
const basePathUrl = '/plugins/globalSearchBar/assets/';
|
||||
const darkMode = false;
|
||||
|
||||
beforeEach(() => {
|
||||
applications = applicationServiceMock.createStartContract();
|
||||
searchService = globalSearchPluginMock.createStartContract();
|
||||
trackUiMetric = jest.fn();
|
||||
});
|
||||
|
||||
const update = () => {
|
||||
|
@ -100,7 +104,7 @@ describe('SearchBar', () => {
|
|||
navigateToUrl={applications.navigateToUrl}
|
||||
basePathUrl={basePathUrl}
|
||||
darkMode={darkMode}
|
||||
trackUiMetric={jest.fn()}
|
||||
trackUiMetric={trackUiMetric}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
@ -118,6 +122,10 @@ describe('SearchBar', () => {
|
|||
await assertSearchResults(['Discover • Kibana', 'My Dashboard • Test']);
|
||||
expect(searchService.find).toHaveBeenCalledTimes(2);
|
||||
expect(searchService.find).toHaveBeenLastCalledWith({ term: 'd' }, {});
|
||||
|
||||
expect(trackUiMetric).nthCalledWith(1, 'count', 'search_focus');
|
||||
expect(trackUiMetric).nthCalledWith(2, 'count', 'search_request');
|
||||
expect(trackUiMetric).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('supports keyboard shortcuts', async () => {
|
||||
|
@ -128,7 +136,7 @@ describe('SearchBar', () => {
|
|||
navigateToUrl={applications.navigateToUrl}
|
||||
basePathUrl={basePathUrl}
|
||||
darkMode={darkMode}
|
||||
trackUiMetric={jest.fn()}
|
||||
trackUiMetric={trackUiMetric}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
@ -139,6 +147,10 @@ describe('SearchBar', () => {
|
|||
const inputElement = await screen.findByTestId('nav-search-input');
|
||||
|
||||
expect(document.activeElement).toEqual(inputElement);
|
||||
|
||||
expect(trackUiMetric).nthCalledWith(1, 'count', 'shortcut_used');
|
||||
expect(trackUiMetric).nthCalledWith(2, 'count', 'search_focus');
|
||||
expect(trackUiMetric).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('only display results from the last search', async () => {
|
||||
|
@ -160,7 +172,7 @@ describe('SearchBar', () => {
|
|||
navigateToUrl={applications.navigateToUrl}
|
||||
basePathUrl={basePathUrl}
|
||||
darkMode={darkMode}
|
||||
trackUiMetric={jest.fn()}
|
||||
trackUiMetric={trackUiMetric}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
@ -178,4 +190,42 @@ describe('SearchBar', () => {
|
|||
|
||||
await assertSearchResults(['Visualize • Kibana', 'Map • Kibana']);
|
||||
});
|
||||
|
||||
it('tracks the application navigated to', async () => {
|
||||
searchService.find.mockReturnValueOnce(
|
||||
of(createBatch('Discover', { id: 'My Dashboard', type: 'test' }))
|
||||
);
|
||||
|
||||
render(
|
||||
<IntlProvider locale="en">
|
||||
<SearchBar
|
||||
globalSearch={searchService}
|
||||
navigateToUrl={applications.navigateToUrl}
|
||||
basePathUrl={basePathUrl}
|
||||
darkMode={darkMode}
|
||||
trackUiMetric={trackUiMetric}
|
||||
/>
|
||||
</IntlProvider>
|
||||
);
|
||||
|
||||
expect(searchService.find).toHaveBeenCalledTimes(0);
|
||||
|
||||
await focusAndUpdate();
|
||||
|
||||
expect(searchService.find).toHaveBeenCalledTimes(1);
|
||||
expect(searchService.find).toHaveBeenCalledWith({}, {});
|
||||
await assertSearchResults(['Discover • Kibana']);
|
||||
|
||||
const navSearchOptionToClick = await screen.findByTestId('nav-search-option');
|
||||
act(() => {
|
||||
fireEvent.click(navSearchOptionToClick);
|
||||
});
|
||||
|
||||
expect(trackUiMetric).nthCalledWith(1, 'count', 'search_focus');
|
||||
expect(trackUiMetric).nthCalledWith(2, 'click', [
|
||||
'user_navigated_to_application',
|
||||
'user_navigated_to_application_discover',
|
||||
]);
|
||||
expect(trackUiMetric).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,75 +5,53 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import React, { FC, useCallback, useRef, useState, useEffect } from 'react';
|
||||
import {
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiFormLabel,
|
||||
EuiHeaderSectionItemButton,
|
||||
EuiIcon,
|
||||
EuiLoadingSpinner,
|
||||
EuiSelectableTemplateSitewide,
|
||||
EuiSelectableTemplateSitewideOption,
|
||||
euiSelectableTemplateSitewideRenderOptions,
|
||||
useEuiTheme,
|
||||
} from '@elastic/eui';
|
||||
import { METRIC_TYPE } from '@kbn/analytics';
|
||||
import type { GlobalSearchFindParams, GlobalSearchResult } from '@kbn/global-search-plugin/public';
|
||||
import React, { FC, useCallback, useEffect, useRef, useState } from 'react';
|
||||
import useDebounce from 'react-use/lib/useDebounce';
|
||||
import useEvent from 'react-use/lib/useEvent';
|
||||
import useMountedState from 'react-use/lib/useMountedState';
|
||||
import { Subscription } from 'rxjs';
|
||||
import {
|
||||
useEuiTheme,
|
||||
EuiFormLabel,
|
||||
EuiHeaderSectionItemButton,
|
||||
EuiIcon,
|
||||
EuiSelectableTemplateSitewide,
|
||||
EuiSelectableTemplateSitewideOption,
|
||||
euiSelectableTemplateSitewideRenderOptions,
|
||||
EuiLoadingSpinner,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
} from '@elastic/eui';
|
||||
import { METRIC_TYPE, UiCounterMetricType } from '@kbn/analytics';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import type { ApplicationStart } from '@kbn/core/public';
|
||||
import type {
|
||||
GlobalSearchPluginStart,
|
||||
GlobalSearchResult,
|
||||
GlobalSearchFindParams,
|
||||
} from '@kbn/global-search-plugin/public';
|
||||
import type { SavedObjectTaggingPluginStart } from '@kbn/saved-objects-tagging-plugin/public';
|
||||
import { parseSearchParams } from '../search_syntax';
|
||||
import { getSuggestions, SearchSuggestion } from '../suggestions';
|
||||
import { blurEvent, CLICK_METRIC, COUNT_METRIC, getClickMetric, isMac, sort } from '.';
|
||||
import { resultToOption, suggestionToOption } from '../lib';
|
||||
import { parseSearchParams } from '../search_syntax';
|
||||
import { i18nStrings } from '../strings';
|
||||
import { getSuggestions, SearchSuggestion } from '../suggestions';
|
||||
import { PopoverFooter } from './popover_footer';
|
||||
import { PopoverPlaceholder } from './popover_placeholder';
|
||||
import './search_bar.scss';
|
||||
import { SearchBarProps } from './types';
|
||||
|
||||
const isMac = navigator.platform.toLowerCase().indexOf('mac') >= 0;
|
||||
const NoMatchesMessage = (props: { basePathUrl: string; darkMode: boolean }) => (
|
||||
<PopoverPlaceholder darkMode={props.darkMode} basePath={props.basePathUrl} />
|
||||
);
|
||||
|
||||
const blurEvent = new FocusEvent('focusout', {
|
||||
bubbles: true,
|
||||
});
|
||||
|
||||
const sortByScore = (a: GlobalSearchResult, b: GlobalSearchResult): number => {
|
||||
if (a.score < b.score) return 1;
|
||||
if (a.score > b.score) return -1;
|
||||
return 0;
|
||||
};
|
||||
|
||||
const sortByTitle = (a: GlobalSearchResult, b: GlobalSearchResult): number => {
|
||||
const titleA = a.title.toUpperCase(); // ignore upper and lowercase
|
||||
const titleB = b.title.toUpperCase(); // ignore upper and lowercase
|
||||
if (titleA < titleB) return -1;
|
||||
if (titleA > titleB) return 1;
|
||||
return 0;
|
||||
};
|
||||
|
||||
interface SearchBarProps {
|
||||
globalSearch: GlobalSearchPluginStart;
|
||||
navigateToUrl: ApplicationStart['navigateToUrl'];
|
||||
trackUiMetric: (metricType: UiCounterMetricType, eventName: string | string[]) => void;
|
||||
taggingApi?: SavedObjectTaggingPluginStart;
|
||||
basePathUrl: string;
|
||||
darkMode: boolean;
|
||||
}
|
||||
const EmptyMessage = () => (
|
||||
<EuiFlexGroup direction="column" justifyContent="center" style={{ minHeight: '300px' }}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiLoadingSpinner size="xl" />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
|
||||
export const SearchBar: FC<SearchBarProps> = ({
|
||||
globalSearch,
|
||||
taggingApi,
|
||||
navigateToUrl,
|
||||
trackUiMetric,
|
||||
basePathUrl,
|
||||
darkMode,
|
||||
...props
|
||||
}) => {
|
||||
const isMounted = useMountedState();
|
||||
const { euiTheme } = useEuiTheme();
|
||||
|
@ -146,7 +124,7 @@ export const SearchBar: FC<SearchBarProps> = ({
|
|||
|
||||
let aggregatedResults: GlobalSearchResult[] = [];
|
||||
if (searchValue.length !== 0) {
|
||||
trackUiMetric(METRIC_TYPE.COUNT, 'search_request');
|
||||
trackUiMetric(METRIC_TYPE.COUNT, COUNT_METRIC.SEARCH_REQUEST);
|
||||
}
|
||||
|
||||
const rawParams = parseSearchParams(searchValue);
|
||||
|
@ -170,7 +148,7 @@ export const SearchBar: FC<SearchBarProps> = ({
|
|||
searchSubscription.current = globalSearch.find(searchParams, {}).subscribe({
|
||||
next: ({ results }) => {
|
||||
if (searchValue.length > 0) {
|
||||
aggregatedResults = [...results, ...aggregatedResults].sort(sortByScore);
|
||||
aggregatedResults = [...results, ...aggregatedResults].sort(sort.byScore);
|
||||
setOptions(aggregatedResults, suggestions, searchParams.tags);
|
||||
return;
|
||||
}
|
||||
|
@ -178,14 +156,14 @@ export const SearchBar: FC<SearchBarProps> = ({
|
|||
// if searchbar is empty, filter to only applications and sort alphabetically
|
||||
results = results.filter(({ type }: GlobalSearchResult) => type === 'application');
|
||||
|
||||
aggregatedResults = [...results, ...aggregatedResults].sort(sortByTitle);
|
||||
aggregatedResults = [...results, ...aggregatedResults].sort(sort.byTitle);
|
||||
|
||||
setOptions(aggregatedResults, suggestions, searchParams.tags);
|
||||
},
|
||||
error: () => {
|
||||
// Not doing anything on error right now because it'll either just show the previous
|
||||
// results or empty results which is basically what we want anyways
|
||||
trackUiMetric(METRIC_TYPE.COUNT, 'unhandled_error');
|
||||
trackUiMetric(METRIC_TYPE.COUNT, COUNT_METRIC.UNHANDLED_ERROR);
|
||||
},
|
||||
complete: () => {},
|
||||
});
|
||||
|
@ -199,7 +177,7 @@ export const SearchBar: FC<SearchBarProps> = ({
|
|||
(event: KeyboardEvent) => {
|
||||
if (event.key === '/' && (isMac ? event.metaKey : event.ctrlKey)) {
|
||||
event.preventDefault();
|
||||
trackUiMetric(METRIC_TYPE.COUNT, 'shortcut_used');
|
||||
trackUiMetric(METRIC_TYPE.COUNT, COUNT_METRIC.SHORTCUT_USED);
|
||||
if (searchRef) {
|
||||
searchRef.focus();
|
||||
} else if (buttonRef) {
|
||||
|
@ -230,16 +208,17 @@ export const SearchBar: FC<SearchBarProps> = ({
|
|||
// errors in tracking should not prevent selection behavior
|
||||
try {
|
||||
if (type === 'application') {
|
||||
const key = selected.keys ?? 'unknown';
|
||||
trackUiMetric(METRIC_TYPE.CLICK, [
|
||||
'user_navigated_to_application',
|
||||
`user_navigated_to_application_${key.toLowerCase().replaceAll(' ', '_')}`, // which application
|
||||
]);
|
||||
const key = selected.key ?? 'unknown';
|
||||
const application = `${key.toLowerCase().replaceAll(' ', '_')}`;
|
||||
trackUiMetric(
|
||||
METRIC_TYPE.CLICK,
|
||||
getClickMetric(CLICK_METRIC.USER_NAVIGATED_TO_APPLICATION, application)
|
||||
);
|
||||
} else {
|
||||
trackUiMetric(METRIC_TYPE.CLICK, [
|
||||
'user_navigated_to_saved_object',
|
||||
`user_navigated_to_saved_object_${type}`, // which type of saved object
|
||||
]);
|
||||
trackUiMetric(
|
||||
METRIC_TYPE.CLICK,
|
||||
getClickMetric(CLICK_METRIC.USER_NAVIGATED_TO_SAVED_OBJECT, type)
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
|
@ -259,34 +238,8 @@ export const SearchBar: FC<SearchBarProps> = ({
|
|||
|
||||
const clearField = () => setSearchValue('');
|
||||
|
||||
const noMatchesMessage = <PopoverPlaceholder darkMode={darkMode} basePath={basePathUrl} />;
|
||||
const emptyMessage = (
|
||||
<EuiFlexGroup direction="column" justifyContent="center" style={{ minHeight: '300px' }}>
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiLoadingSpinner size="xl" />
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
|
||||
const placeholderText = i18n.translate('xpack.globalSearchBar.searchBar.placeholder', {
|
||||
defaultMessage: 'Find apps, content, and more.',
|
||||
});
|
||||
const keyboardShortcutTooltip = `${i18n.translate(
|
||||
'xpack.globalSearchBar.searchBar.shortcutTooltip.description',
|
||||
{
|
||||
defaultMessage: 'Keyboard shortcut',
|
||||
}
|
||||
)}: ${
|
||||
isMac
|
||||
? i18n.translate('xpack.globalSearchBar.searchBar.shortcutTooltip.macCommandDescription', {
|
||||
defaultMessage: 'Command + /',
|
||||
})
|
||||
: i18n.translate(
|
||||
'xpack.globalSearchBar.searchBar.shortcutTooltip.windowsCommandDescription',
|
||||
{
|
||||
defaultMessage: 'Control + /',
|
||||
}
|
||||
)
|
||||
const keyboardShortcutTooltip = `${i18nStrings.keyboardShortcutTooltip.prefix}: ${
|
||||
isMac ? i18nStrings.keyboardShortcutTooltip.onMac : i18nStrings.keyboardShortcutTooltip.onNotMac
|
||||
}`;
|
||||
|
||||
useEvent('keydown', onKeyDown);
|
||||
|
@ -306,10 +259,10 @@ export const SearchBar: FC<SearchBarProps> = ({
|
|||
'data-test-subj': 'nav-search-input',
|
||||
inputRef: setSearchRef,
|
||||
compressed: true,
|
||||
'aria-label': placeholderText,
|
||||
placeholder: placeholderText,
|
||||
'aria-label': i18nStrings.placeholderText,
|
||||
placeholder: i18nStrings.placeholderText,
|
||||
onFocus: () => {
|
||||
trackUiMetric(METRIC_TYPE.COUNT, 'search_focus');
|
||||
trackUiMetric(METRIC_TYPE.COUNT, COUNT_METRIC.SEARCH_FOCUS);
|
||||
setInitialLoad(true);
|
||||
setShowAppend(false);
|
||||
},
|
||||
|
@ -326,8 +279,8 @@ export const SearchBar: FC<SearchBarProps> = ({
|
|||
</EuiFormLabel>
|
||||
) : undefined,
|
||||
}}
|
||||
emptyMessage={emptyMessage}
|
||||
noMatchesMessage={noMatchesMessage}
|
||||
emptyMessage={<EmptyMessage />}
|
||||
noMatchesMessage={<NoMatchesMessage {...props} />}
|
||||
popoverProps={{
|
||||
'data-test-subj': 'nav-search-popover',
|
||||
panelClassName: 'navSearch__panel',
|
||||
|
@ -336,12 +289,7 @@ export const SearchBar: FC<SearchBarProps> = ({
|
|||
panelStyle: { marginTop: '6px' },
|
||||
}}
|
||||
popoverButton={
|
||||
<EuiHeaderSectionItemButton
|
||||
aria-label={i18n.translate(
|
||||
'xpack.globalSearchBar.searchBar.mobileSearchButtonAriaLabel',
|
||||
{ defaultMessage: 'Site-wide search' }
|
||||
)}
|
||||
>
|
||||
<EuiHeaderSectionItemButton aria-label={i18nStrings.popoverButton}>
|
||||
<EuiIcon type="search" size="m" />
|
||||
</EuiHeaderSectionItemButton>
|
||||
}
|
||||
|
|
21
x-pack/plugins/global_search_bar/public/components/types.ts
Normal file
21
x-pack/plugins/global_search_bar/public/components/types.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* 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 type { ApplicationStart } from '@kbn/core/public';
|
||||
import type { GlobalSearchPluginStart } from '@kbn/global-search-plugin/public';
|
||||
import type { SavedObjectTaggingPluginStart } from '@kbn/saved-objects-tagging-plugin/public';
|
||||
import { TrackUiMetricFn } from '../types';
|
||||
|
||||
/* @internal */
|
||||
export interface SearchBarProps {
|
||||
globalSearch: GlobalSearchPluginStart;
|
||||
navigateToUrl: ApplicationStart['navigateToUrl'];
|
||||
trackUiMetric: TrackUiMetricFn;
|
||||
taggingApi?: SavedObjectTaggingPluginStart;
|
||||
basePathUrl: string;
|
||||
darkMode: boolean;
|
||||
}
|
|
@ -8,7 +8,6 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Observable } from 'rxjs';
|
||||
import { UiCounterMetricType } from '@kbn/analytics';
|
||||
import { I18nProvider } from '@kbn/i18n-react';
|
||||
import { ApplicationStart, CoreTheme, CoreStart, Plugin } from '@kbn/core/public';
|
||||
import { KibanaThemeProvider } from '@kbn/kibana-react-plugin/public';
|
||||
|
@ -16,6 +15,7 @@ import { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public';
|
|||
import { GlobalSearchPluginStart } from '@kbn/global-search-plugin/public';
|
||||
import { SavedObjectTaggingPluginStart } from '@kbn/saved-objects-tagging-plugin/public';
|
||||
import { SearchBar } from './components/search_bar';
|
||||
import { TrackUiMetricFn } from './types';
|
||||
|
||||
export interface GlobalSearchBarPluginStartDeps {
|
||||
globalSearch: GlobalSearchPluginStart;
|
||||
|
@ -32,9 +32,12 @@ export class GlobalSearchBarPlugin implements Plugin<{}, {}> {
|
|||
core: CoreStart,
|
||||
{ globalSearch, savedObjectsTagging, usageCollection }: GlobalSearchBarPluginStartDeps
|
||||
) {
|
||||
const trackUiMetric = usageCollection
|
||||
? usageCollection.reportUiCounter.bind(usageCollection, 'global_search_bar')
|
||||
: (metricType: UiCounterMetricType, eventName: string | string[]) => {};
|
||||
let trackUiMetric: TrackUiMetricFn = () => {};
|
||||
if (usageCollection) {
|
||||
trackUiMetric = (...args) => {
|
||||
usageCollection.reportUiCounter('global_search_bar', ...args);
|
||||
};
|
||||
}
|
||||
|
||||
core.chrome.navControls.registerCenter({
|
||||
order: 1000,
|
||||
|
@ -70,7 +73,7 @@ export class GlobalSearchBarPlugin implements Plugin<{}, {}> {
|
|||
basePathUrl: string;
|
||||
darkMode: boolean;
|
||||
theme$: Observable<CoreTheme>;
|
||||
trackUiMetric: (metricType: UiCounterMetricType, eventName: string | string[]) => void;
|
||||
trackUiMetric: TrackUiMetricFn;
|
||||
}) {
|
||||
ReactDOM.render(
|
||||
<KibanaThemeProvider theme$={theme$}>
|
||||
|
|
32
x-pack/plugins/global_search_bar/public/strings.ts
Normal file
32
x-pack/plugins/global_search_bar/public/strings.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
|
||||
export const i18nStrings = {
|
||||
placeholderText: i18n.translate('xpack.globalSearchBar.searchBar.placeholder', {
|
||||
defaultMessage: 'Find apps, content, and more.',
|
||||
}),
|
||||
popoverButton: i18n.translate('xpack.globalSearchBar.searchBar.mobileSearchButtonAriaLabel', {
|
||||
defaultMessage: 'Site-wide search',
|
||||
}),
|
||||
keyboardShortcutTooltip: {
|
||||
prefix: i18n.translate('xpack.globalSearchBar.searchBar.shortcutTooltip.description', {
|
||||
defaultMessage: 'Keyboard shortcut',
|
||||
}),
|
||||
onMac: i18n.translate('xpack.globalSearchBar.searchBar.shortcutTooltip.macCommandDescription', {
|
||||
defaultMessage: 'Command + /',
|
||||
}),
|
||||
|
||||
onNotMac: i18n.translate(
|
||||
'xpack.globalSearchBar.searchBar.shortcutTooltip.windowsCommandDescription',
|
||||
{
|
||||
defaultMessage: 'Control + /',
|
||||
}
|
||||
),
|
||||
},
|
||||
};
|
13
x-pack/plugins/global_search_bar/public/types.ts
Normal file
13
x-pack/plugins/global_search_bar/public/types.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* 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 { UiCounterMetricType } from '@kbn/analytics';
|
||||
|
||||
export type TrackUiMetricFn = (
|
||||
metricType: UiCounterMetricType,
|
||||
eventName: string | string[]
|
||||
) => void;
|
Loading…
Add table
Add a link
Reference in a new issue