diff --git a/.changeset/happy-cups-tap.md b/.changeset/happy-cups-tap.md index 307b6fb4fc..051f9def1c 100644 --- a/.changeset/happy-cups-tap.md +++ b/.changeset/happy-cups-tap.md @@ -1,5 +1,4 @@ --- -'example-backend': patch '@backstage/plugin-catalog-backend': patch --- diff --git a/plugins/catalog-backend/config.d.ts b/plugins/catalog-backend/config.d.ts index 5a9291541c..7da9cad139 100644 --- a/plugins/catalog-backend/config.d.ts +++ b/plugins/catalog-backend/config.d.ts @@ -179,17 +179,5 @@ export interface Config { }; }; }; - - /** - * Configuration for search collation - */ - search?: { - /** - * Request search to only index these particular kinds. - * - * E.g. ["Component", "API", "Template", "Location"] - */ - allow: Array; - }; }; } diff --git a/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts b/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts index c19d2d21a6..f1b7cfe862 100644 --- a/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts +++ b/plugins/catalog-backend/src/search/DefaultCatalogCollator.test.ts @@ -16,7 +16,10 @@ import { PluginEndpointDiscovery } from '@backstage/backend-common'; import { Entity } from '@backstage/catalog-model'; -import { DefaultCatalogCollator } from './DefaultCatalogCollator'; +import { + DefaultCatalogCollator, + mapFilterToQueryString, +} from './DefaultCatalogCollator'; import { setupServer } from 'msw/node'; import { rest } from 'msw'; import { ConfigReader } from '@backstage/config'; @@ -105,21 +108,35 @@ describe('DefaultCatalogCollator', () => { }); it('allows filtering of the retrieved catalog entities', async () => { - const config = new ConfigReader({ - catalog: { - search: { - allow: ['Foo', 'Bar'], - }, - }, - }); - // Provide an alternate location template. - collator = DefaultCatalogCollator.fromConfig(config, { + collator = DefaultCatalogCollator.fromConfig(new ConfigReader({}), { discovery: mockDiscoveryApi, + filter: { + kind: ['Foo', 'Bar'], + }, }); const documents = await collator.execute(); // The simulated 'Foo,Bar' filter should return in an empty list expect(documents).toHaveLength(0); }); + + it('can map filters to query strings', () => { + expect( + mapFilterToQueryString({ + a: 'Foo', + }), + ).toEqual('?filter=a=Foo'); + expect( + mapFilterToQueryString({ + a: ['Foo', 'Bar'], + }), + ).toEqual('?filter=a=Foo,Bar'); + expect( + mapFilterToQueryString({ + a: ['Foo', 'Bar'], + b: ['Quu', 'Qux'], + }), + ).toEqual('?filter=a=Foo,Bar,b=Quu,Qux'); + }); }); diff --git a/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts b/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts index 4043cf1c1d..b372350a08 100644 --- a/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts +++ b/plugins/catalog-backend/src/search/DefaultCatalogCollator.ts @@ -19,6 +19,7 @@ import { Entity } from '@backstage/catalog-model'; import { IndexableDocument, DocumentCollator } from '@backstage/search-common'; import fetch from 'cross-fetch'; import { Config } from '@backstage/config'; +import { CatalogEntitiesRequest } from '@backstage/catalog-client'; export interface CatalogEntityDocument extends IndexableDocument { componentType: string; @@ -31,36 +32,34 @@ export interface CatalogEntityDocument extends IndexableDocument { export class DefaultCatalogCollator implements DocumentCollator { protected discovery: PluginEndpointDiscovery; protected locationTemplate: string; - protected filterUrl: string; + protected filterUrl?: string; public readonly type: string = 'software-catalog'; static fromConfig( - config: Config, - options: { discovery: PluginEndpointDiscovery }, + _config: Config, + options: { + discovery: PluginEndpointDiscovery; + filter?: CatalogEntitiesRequest['filter']; + }, ) { return new DefaultCatalogCollator({ ...options, - allow: config.getOptionalStringArray('catalog.search.allow'), }); } constructor({ discovery, locationTemplate, - allow, + filter, }: { discovery: PluginEndpointDiscovery; locationTemplate?: string; - allow?: string[]; + filter?: CatalogEntitiesRequest['filter']; }) { this.discovery = discovery; this.locationTemplate = locationTemplate || '/catalog/:namespace/:kind/:name'; - if (allow && allow.length) { - this.filterUrl = `?filter=kind=${allow.join(',')}`; - } else { - this.filterUrl = ''; - } + this.filterUrl = mapFilterToQueryString(filter); } protected applyArgsToFormat( @@ -76,7 +75,7 @@ export class DefaultCatalogCollator implements DocumentCollator { async execute() { const baseUrl = await this.discovery.getBaseUrl('catalog'); - const res = await fetch(`${baseUrl}/entities${this.filterUrl}`); + const res = await fetch(`${baseUrl}/entities${this.filterUrl || ''}`); const entities: Entity[] = await res.json(); return entities.map((entity: Entity): CatalogEntityDocument => { return { @@ -96,3 +95,18 @@ export class DefaultCatalogCollator implements DocumentCollator { }); } } + +export function mapFilterToQueryString( + filter: CatalogEntitiesRequest['filter'], +): string | undefined { + if (!filter) { + return undefined; + } + + const mappedFilters = Object.entries(filter).map(kvp => { + const type = kvp[0]; + const values = [].concat(kvp[1]); + return `${type}=${values.join(',')}`; + }); + return `?filter=${mappedFilters.join(',')}`; +} diff --git a/plugins/catalog-backend/src/search/index.ts b/plugins/catalog-backend/src/search/index.ts index 7e13999864..dfe1cf541e 100644 --- a/plugins/catalog-backend/src/search/index.ts +++ b/plugins/catalog-backend/src/search/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export * from './DefaultCatalogCollator'; +export { DefaultCatalogCollator } from './DefaultCatalogCollator';