From d6a4a50efa0b9351a4bfbc29164cde3cbda3b28d Mon Sep 17 00:00:00 2001 From: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 22 Jun 2021 10:16:44 -0400 Subject: [PATCH] added ability to filter in global search by "type:package" (#102754) (#102898) Co-authored-by: Jean-Louis Leysens --- .../fleet/public/search_provider.test.ts | 100 ++++++++++++++++++ .../plugins/fleet/public/search_provider.ts | 69 ++++++++---- 2 files changed, 146 insertions(+), 23 deletions(-) diff --git a/x-pack/plugins/fleet/public/search_provider.test.ts b/x-pack/plugins/fleet/public/search_provider.test.ts index fa2e8508c938ef..c42ac2e5a15512 100644 --- a/x-pack/plugins/fleet/public/search_provider.test.ts +++ b/x-pack/plugins/fleet/public/search_provider.test.ts @@ -185,5 +185,105 @@ describe('Package search provider', () => { expect(sendGetPackages).toHaveBeenCalledTimes(1); }); + + describe('tags', () => { + test('without packages tag, without search term', () => { + getTestScheduler().run(({ hot, expectObservable }) => { + mockSendGetPackages.mockReturnValue( + hot('--(a|)', { a: { data: { response: testResponse } } }) + ); + setupMock.getStartServices.mockReturnValue( + hot('--(a|)', { a: [coreMock.createStart()] }) as any + ); + const packageSearchProvider = createPackageSearchProvider(setupMock); + expectObservable( + packageSearchProvider.find( + { types: ['test'] }, + { aborted$: NEVER, maxResults: 100, preference: '' } + ) + ).toBe('(a|)', { + a: [], + }); + }); + + expect(sendGetPackages).toHaveBeenCalledTimes(0); + }); + + test('with packages tag, with no search term', () => { + getTestScheduler().run(({ hot, expectObservable }) => { + mockSendGetPackages.mockReturnValue( + hot('--(a|)', { a: { data: { response: testResponse } } }) + ); + setupMock.getStartServices.mockReturnValue( + hot('--(a|)', { a: [coreMock.createStart()] }) as any + ); + const packageSearchProvider = createPackageSearchProvider(setupMock); + expectObservable( + packageSearchProvider.find( + { types: ['package'] }, + { aborted$: NEVER, maxResults: 100, preference: '' } + ) + ).toBe('--(a|)', { + a: [ + { + id: 'test-test', + score: 80, + title: 'test', + type: 'package', + url: { + path: 'undefined#/detail/test-test/overview', + prependBasePath: false, + }, + }, + { + id: 'test1-test1', + score: 80, + title: 'test1', + type: 'package', + url: { + path: 'undefined#/detail/test1-test1/overview', + prependBasePath: false, + }, + }, + ], + }); + }); + + expect(sendGetPackages).toHaveBeenCalledTimes(1); + }); + + test('with packages tag, with search term', () => { + getTestScheduler().run(({ hot, expectObservable }) => { + mockSendGetPackages.mockReturnValue( + hot('--(a|)', { a: { data: { response: testResponse } } }) + ); + setupMock.getStartServices.mockReturnValue( + hot('--(a|)', { a: [coreMock.createStart()] }) as any + ); + const packageSearchProvider = createPackageSearchProvider(setupMock); + expectObservable( + packageSearchProvider.find( + { term: 'test1', types: ['package'] }, + { aborted$: NEVER, maxResults: 100, preference: '' } + ) + ).toBe('--(a|)', { + a: [ + { + id: 'test1-test1', + score: 80, + title: 'test1', + type: 'package', + url: { + path: 'undefined#/detail/test1-test1/overview', + prependBasePath: false, + }, + }, + ], + }); + }); + + expect(sendGetPackages).toHaveBeenCalledTimes(1); + }); + }); }); }); diff --git a/x-pack/plugins/fleet/public/search_provider.ts b/x-pack/plugins/fleet/public/search_provider.ts index cd4ec1c29b4579..56e08ecad29fb2 100644 --- a/x-pack/plugins/fleet/public/search_provider.ts +++ b/x-pack/plugins/fleet/public/search_provider.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import type { CoreSetup, CoreStart } from 'src/core/public'; +import type { CoreSetup, CoreStart, ApplicationStart } from 'src/core/public'; import type { Observable } from 'rxjs'; import { from, of, combineLatest } from 'rxjs'; @@ -34,6 +34,26 @@ const createPackages$ = () => shareReplay(1) ); +const toSearchResult = ( + pkg: GetPackagesResponse['response'][number], + application: ApplicationStart +) => { + const pkgkey = `${pkg.name}-${pkg.version}`; + return { + id: pkgkey, + type: packageType, + title: pkg.title, + score: 80, + url: { + // TODO: See https://github.com/elastic/kibana/issues/96134 for details about why we use '#' here. Below should be updated + // as part of migrating to non-hash based router. + // prettier-ignore + path: `${application.getUrlForApp(INTEGRATIONS_PLUGIN_ID)}#${pagePathGetters.integration_details_overview({ pkgkey })[1]}`, + prependBasePath: false, + }, + }; +}; + export const createPackageSearchProvider = (core: CoreSetup): GlobalSearchResultProvider => { const coreStart$ = from(core.getStartServices()).pipe( map(([coreStart]) => coreStart), @@ -52,12 +72,23 @@ export const createPackageSearchProvider = (core: CoreSetup): GlobalSearchResult return { id: 'packages', getSearchableTypes: () => [packageType], - find: ({ term }, { maxResults, aborted$ }) => { - if (!term) { + find: ({ term, types }, { maxResults, aborted$ }) => { + if (types?.includes(packageType) === false) { return of([]); } - term = term.toLowerCase(); + const hasTypes = Boolean(types); + const typesIncludePackage = hasTypes && types!.includes(packageType); + const noSearchTerm = !term; + const includeAllPackages = typesIncludePackage && noSearchTerm; + + if (!includeAllPackages && noSearchTerm) { + return of([]); + } + + if (term) { + term = term.toLowerCase(); + } const toSearchResults = ( coreStart: CoreStart, @@ -65,25 +96,17 @@ export const createPackageSearchProvider = (core: CoreSetup): GlobalSearchResult ): GlobalSearchProviderResult[] => { const packages = packagesResponse.slice(0, maxResults); - return packages.flatMap((pkg) => { - if (!term || !pkg.title.toLowerCase().includes(term)) { - return []; - } - const pkgkey = `${pkg.name}-${pkg.version}`; - return { - id: pkgkey, - type: packageType, - title: pkg.title, - score: 80, - url: { - // TODO: See https://github.com/elastic/kibana/issues/96134 for details about why we use '#' here. Below should be updated - // as part of migrating to non-hash based router. - // prettier-ignore - path: `${coreStart.application.getUrlForApp(INTEGRATIONS_PLUGIN_ID)}#${pagePathGetters.integration_details_overview({ pkgkey })[1]}`, - prependBasePath: false, - }, - }; - }); + return packages.flatMap( + includeAllPackages + ? (pkg) => toSearchResult(pkg, coreStart.application) + : (pkg) => { + if (!term || !pkg.title.toLowerCase().includes(term)) { + return []; + } + + return toSearchResult(pkg, coreStart.application); + } + ); }; return combineLatest([coreStart$, getPackages$()]).pipe(