Configure DefaultCatalogCollator programmatically
Signed-off-by: Roy Jacobs <roy.jacobs@gmail.com>
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
---
|
||||
'example-backend': patch
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
|
||||
Vendored
-12
@@ -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<string>;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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(',')}`;
|
||||
}
|
||||
|
||||
@@ -14,4 +14,4 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export * from './DefaultCatalogCollator';
|
||||
export { DefaultCatalogCollator } from './DefaultCatalogCollator';
|
||||
|
||||
Reference in New Issue
Block a user