feat: allow passing optional filter to getEntityByRefs
this closes #22839 Signed-off-by: Heikki Hellgren <heikki.hellgren@op.fi>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'@backstage/catalog-client': patch
|
||||
'@backstage/plugin-catalog-backend': patch
|
||||
---
|
||||
|
||||
Allow passing optional filter to `getEntitiesByRefs`
|
||||
@@ -192,6 +192,7 @@ export type EntityOrderQuery =
|
||||
export interface GetEntitiesByRefsRequest {
|
||||
entityRefs: string[];
|
||||
fields?: EntityFieldsQuery | undefined;
|
||||
filter?: EntityFilterQuery;
|
||||
}
|
||||
|
||||
// @public
|
||||
|
||||
@@ -275,6 +275,7 @@ describe('CatalogClient', () => {
|
||||
};
|
||||
server.use(
|
||||
rest.post(`${mockBaseUrl}/entities/by-refs`, async (req, res, ctx) => {
|
||||
expect(req.url.search).toBe('?filter=kind%3DAPI%2Ckind%3DComponent');
|
||||
await expect(req.json()).resolves.toEqual({
|
||||
entityRefs: ['k:n/a', 'k:n/b'],
|
||||
fields: ['a', 'b'],
|
||||
@@ -284,7 +285,13 @@ describe('CatalogClient', () => {
|
||||
);
|
||||
|
||||
const response = await client.getEntitiesByRefs(
|
||||
{ entityRefs: ['k:n/a', 'k:n/b'], fields: ['a', 'b'] },
|
||||
{
|
||||
entityRefs: ['k:n/a', 'k:n/b'],
|
||||
fields: ['a', 'b'],
|
||||
filter: {
|
||||
kind: ['API', 'Component'],
|
||||
},
|
||||
},
|
||||
{ token },
|
||||
);
|
||||
|
||||
|
||||
@@ -15,32 +15,32 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
Entity,
|
||||
CompoundEntityRef,
|
||||
Entity,
|
||||
parseEntityRef,
|
||||
stringifyEntityRef,
|
||||
stringifyLocationRef,
|
||||
} from '@backstage/catalog-model';
|
||||
import { ResponseError } from '@backstage/errors';
|
||||
import {
|
||||
CATALOG_FILTER_EXISTS,
|
||||
AddLocationRequest,
|
||||
AddLocationResponse,
|
||||
CATALOG_FILTER_EXISTS,
|
||||
CatalogApi,
|
||||
GetEntitiesRequest,
|
||||
GetEntitiesResponse,
|
||||
CatalogRequestOptions,
|
||||
GetEntityAncestorsRequest,
|
||||
GetEntityAncestorsResponse,
|
||||
Location,
|
||||
GetEntityFacetsRequest,
|
||||
GetEntityFacetsResponse,
|
||||
ValidateEntityResponse,
|
||||
EntityFilterQuery,
|
||||
GetEntitiesByRefsRequest,
|
||||
GetEntitiesByRefsResponse,
|
||||
GetEntitiesRequest,
|
||||
GetEntitiesResponse,
|
||||
GetEntityAncestorsRequest,
|
||||
GetEntityAncestorsResponse,
|
||||
GetEntityFacetsRequest,
|
||||
GetEntityFacetsResponse,
|
||||
Location,
|
||||
QueryEntitiesRequest,
|
||||
EntityFilterQuery,
|
||||
QueryEntitiesResponse,
|
||||
ValidateEntityResponse,
|
||||
} from './types/api';
|
||||
import { isQueryEntitiesInitialRequest } from './utils';
|
||||
import { DefaultApiClient, TypedResponse } from './generated';
|
||||
@@ -177,7 +177,13 @@ export class CatalogClient implements CatalogApi {
|
||||
): Promise<GetEntitiesByRefsResponse> {
|
||||
const response = await this.apiClient.getEntitiesByRefs(
|
||||
{
|
||||
body: request,
|
||||
body: {
|
||||
entityRefs: request.entityRefs,
|
||||
fields: request.fields,
|
||||
},
|
||||
query: {
|
||||
filter: this.getFilterValue(request.filter),
|
||||
},
|
||||
},
|
||||
options,
|
||||
);
|
||||
|
||||
@@ -281,14 +281,17 @@ export class DefaultApiClient {
|
||||
// @ts-ignore
|
||||
request: {
|
||||
body: GetEntitiesByRefsRequest;
|
||||
query?: {
|
||||
filter?: Array<string>;
|
||||
};
|
||||
},
|
||||
options?: RequestOptions,
|
||||
): Promise<TypedResponse<EntitiesBatchResponse>> {
|
||||
const baseUrl = await this.discoveryApi.getBaseUrl(pluginId);
|
||||
|
||||
const uriTemplate = `/entities/by-refs`;
|
||||
const uriTemplate = `/entities/by-refs/{?filter*}`;
|
||||
|
||||
const uri = parser.parse(uriTemplate).expand({});
|
||||
const uri = parser.parse(uriTemplate).expand({ ...request.query });
|
||||
|
||||
return await this.fetchApi.fetch(`${baseUrl}${uri}`, {
|
||||
headers: {
|
||||
|
||||
@@ -203,6 +203,10 @@ export interface GetEntitiesByRefsRequest {
|
||||
* declarations.
|
||||
*/
|
||||
fields?: EntityFieldsQuery | undefined;
|
||||
/**
|
||||
* If given, return only entities that match the given filter.
|
||||
*/
|
||||
filter?: EntityFilterQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1107,6 +1107,11 @@ export const spec = {
|
||||
},
|
||||
},
|
||||
},
|
||||
parameters: [
|
||||
{
|
||||
$ref: '#/components/parameters/filter',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
'/entities/by-query': {
|
||||
|
||||
@@ -862,6 +862,8 @@ paths:
|
||||
- component:default/backstage
|
||||
fields:
|
||||
- metadata.annotations
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/filter'
|
||||
/entities/by-query:
|
||||
get:
|
||||
operationId: GetEntitiesByQuery
|
||||
|
||||
@@ -527,7 +527,7 @@ describe('createRouter readonly disabled', () => {
|
||||
const entityRef = stringifyEntityRef(entity);
|
||||
entitiesCatalog.entitiesBatch.mockResolvedValue({ items: [entity] });
|
||||
const response = await request(app)
|
||||
.post('/entities/by-refs')
|
||||
.post('/entities/by-refs?filter=kind=Component')
|
||||
.set('Content-Type', 'application/json')
|
||||
.send(
|
||||
JSON.stringify({
|
||||
@@ -540,6 +540,13 @@ describe('createRouter readonly disabled', () => {
|
||||
entityRefs: [entityRef],
|
||||
fields: expect.any(Function),
|
||||
credentials: mockCredentials.user(),
|
||||
filter: {
|
||||
anyOf: [
|
||||
{
|
||||
allOf: [{ key: 'kind', values: ['Component'] }],
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
expect(response.status).toEqual(200);
|
||||
expect(response.body).toEqual({ items: [entity] });
|
||||
|
||||
@@ -219,6 +219,7 @@ export async function createRouter(
|
||||
const request = entitiesBatchRequest(req);
|
||||
const response = await entitiesCatalog.entitiesBatch({
|
||||
entityRefs: request.entityRefs,
|
||||
filter: parseEntityFilterParams(req.query),
|
||||
fields: parseEntityTransformParams(req.query, request.fields),
|
||||
credentials: await httpAuth.credentials(req),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user