Improved empty state for nav search (#79123)

* Improved empty state for nav search

* Updates tests to include required props

* Update empty state text
This commit is contained in:
Ryan Keairns 2020-10-02 08:39:37 -05:00 committed by GitHub
parent 0628cfecf4
commit a7d9e2f481
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 72 additions and 22 deletions

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 102 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 102 KiB

View file

@ -8,6 +8,7 @@ import React from 'react';
import { wait } from '@testing-library/react';
import { of } from 'rxjs';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { httpServiceMock, uiSettingsServiceMock } from '../../../../../src/core/public/mocks';
import {
GlobalSearchBatchedResults,
GlobalSearchPluginStart,
@ -47,6 +48,10 @@ const getSearchProps: any = (component: any) => component.find('EuiFieldSearch')
describe('SearchBar', () => {
let searchService: GlobalSearchPluginStart;
let findSpy: jest.SpyInstance;
const http = httpServiceMock.createSetupContract({ basePath: '/test' });
const basePathUrl = http.basePath.prepend('/plugins/globalSearchBar/assets/');
const uiSettings = uiSettingsServiceMock.createStartContract();
const darkMode = uiSettings.get('theme:darkMode');
beforeEach(() => {
searchService = globalSearchPluginMock.createStartContract();
@ -66,7 +71,12 @@ describe('SearchBar', () => {
.mockReturnValueOnce(of(createBatch('Discover', { id: 'My Dashboard', type: 'test' })));
const component = mountWithIntl(
<SearchBar globalSearch={searchService.find} navigateToUrl={navigate} />
<SearchBar
globalSearch={searchService.find}
navigateToUrl={navigate}
basePathUrl={basePathUrl}
darkMode={darkMode}
/>
);
expect(findSpy).toHaveBeenCalledTimes(0);
@ -85,7 +95,14 @@ describe('SearchBar', () => {
});
it('supports keyboard shortcuts', () => {
mountWithIntl(<SearchBar globalSearch={searchService.find} navigateToUrl={jest.fn()} />);
mountWithIntl(
<SearchBar
globalSearch={searchService.find}
navigateToUrl={jest.fn()}
basePathUrl={basePathUrl}
darkMode={darkMode}
/>
);
const searchEvent = new KeyboardEvent('keydown', {
key: '/',

View file

@ -12,6 +12,7 @@ import {
EuiSelectableTemplateSitewideOption,
EuiText,
EuiIcon,
EuiImage,
EuiHeaderSectionItemButton,
EuiSelectableMessage,
} from '@elastic/eui';
@ -27,6 +28,8 @@ import { GlobalSearchPluginStart, GlobalSearchResult } from '../../../global_sea
interface Props {
globalSearch: GlobalSearchPluginStart['find'];
navigateToUrl: ApplicationStart['navigateToUrl'];
basePathUrl: string;
darkMode: boolean;
}
const clearField = (field: HTMLInputElement) => {
@ -42,7 +45,7 @@ const clearField = (field: HTMLInputElement) => {
const cleanMeta = (str: string) => (str.charAt(0).toUpperCase() + str.slice(1)).replace(/-/g, ' ');
const blurEvent = new FocusEvent('blur');
export function SearchBar({ globalSearch, navigateToUrl }: Props) {
export function SearchBar({ globalSearch, navigateToUrl, basePathUrl, darkMode }: Props) {
const isMounted = useMountedState();
const [searchValue, setSearchValue] = useState<string>('');
const [searchRef, setSearchRef] = useState<HTMLInputElement | null>(null);
@ -134,6 +137,34 @@ export function SearchBar({ globalSearch, navigateToUrl }: Props) {
}
};
const emptyMessage = (
<EuiSelectableMessage style={{ minHeight: 300 }}>
<EuiImage
alt={i18n.translate('xpack.globalSearchBar.searchBar.noResultsImageAlt', {
defaultMessage: 'Illustration of black hole',
})}
size="fullWidth"
url={`${basePathUrl}illustration_product_no_search_results_${
darkMode ? 'dark' : 'light'
}.svg`}
/>
<EuiText size="m">
<p>
<FormattedMessage
id="xpack.globalSearchBar.searchBar.noResultsHeading"
defaultMessage="No results found"
/>
</p>
</EuiText>
<p>
<FormattedMessage
id="xpack.globalSearchBar.searchBar.noResults"
defaultMessage="Try searching for applications, dashboards, visualizations, and more."
/>
</p>
</EuiSelectableMessage>
);
useEvent('keydown', onKeyDown);
return (
@ -164,22 +195,8 @@ export function SearchBar({ globalSearch, navigateToUrl }: Props) {
popoverProps={{
repositionOnScroll: true,
}}
emptyMessage={
<EuiSelectableMessage style={{ minHeight: 300 }}>
<p>
<FormattedMessage
id="xpack.globalSearchBar.searchBar.noResultsHeading"
defaultMessage="No results found"
/>
</p>
<p>
<FormattedMessage
id="xpack.globalSearchBar.searchBar.noResults"
defaultMessage="Try searching for applications and saved objects by name."
/>
</p>
</EuiSelectableMessage>
}
emptyMessage={emptyMessage}
noMatchesMessage={emptyMessage}
popoverFooter={
<EuiText color="subdued" size="xs">
<EuiFlexGroup

View file

@ -24,7 +24,14 @@ export class GlobalSearchBarPlugin implements Plugin<{}, {}> {
public start(core: CoreStart, { globalSearch }: GlobalSearchBarPluginStartDeps) {
core.chrome.navControls.registerCenter({
order: 1000,
mount: (target) => this.mount(target, globalSearch, core.application.navigateToUrl),
mount: (target) =>
this.mount(
target,
globalSearch,
core.application.navigateToUrl,
core.http.basePath.prepend('/plugins/globalSearchBar/assets/'),
core.uiSettings.get('theme:darkMode')
),
});
return {};
}
@ -32,11 +39,18 @@ export class GlobalSearchBarPlugin implements Plugin<{}, {}> {
private mount(
targetDomElement: HTMLElement,
globalSearch: GlobalSearchPluginStart,
navigateToUrl: ApplicationStart['navigateToUrl']
navigateToUrl: ApplicationStart['navigateToUrl'],
basePathUrl: string,
darkMode: boolean
) {
ReactDOM.render(
<I18nProvider>
<SearchBar globalSearch={globalSearch.find} navigateToUrl={navigateToUrl} />
<SearchBar
globalSearch={globalSearch.find}
navigateToUrl={navigateToUrl}
basePathUrl={basePathUrl}
darkMode={darkMode}
/>
</I18nProvider>,
targetDomElement
);