feat: add EntityFilterQuery to EntityPicker to allow filtering entities

Signed-off-by: Enrico Alvarenga <enrico.alvarenga@segment.com>
This commit is contained in:
Enrico Alvarenga
2022-12-06 12:18:25 -08:00
parent 325ebb0b34
commit b97b844835
3 changed files with 121 additions and 3 deletions
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import { EntityFilterQuery } from '@backstage/catalog-client';
import { Entity } from '@backstage/catalog-model';
import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react';
import { renderInTestApp, TestApiProvider } from '@backstage/test-utils';
@@ -34,7 +35,13 @@ describe('<EntityPicker />', () => {
const schema = {};
const required = false;
let uiSchema: {
'ui:options': { allowedKinds?: string[]; defaultKind?: string };
'ui:options': {
allowedKinds?: string[];
defaultKind?: string;
allowArbitraryValues?: boolean;
defaultNamespace?: string | false;
catalogFilter?: EntityFilterQuery;
};
};
const rawErrors: string[] = [];
const formData = undefined;
@@ -66,7 +73,7 @@ describe('<EntityPicker />', () => {
afterEach(() => jest.resetAllMocks());
describe('without allowedKinds', () => {
describe('without allowedKinds and catalogFilter', () => {
beforeEach(() => {
uiSchema = { 'ui:options': {} };
props = {
@@ -136,4 +143,97 @@ describe('<EntityPicker />', () => {
});
});
});
describe('with catalogFilter', () => {
beforeEach(() => {
uiSchema = {
'ui:options': {
catalogFilter: [
{
kind: ['Group'],
'metadata.name': 'test-entity',
},
{
kind: ['User'],
'metadata.name': 'test-entity',
},
],
},
};
props = {
onChange,
schema,
required,
uiSchema,
rawErrors,
formData,
} as unknown as FieldProps<any>;
catalogApi.getEntities.mockResolvedValue({ items: entities });
});
it('searches for a specific group entity', async () => {
await renderInTestApp(
<Wrapper>
<EntityPicker {...props} />
</Wrapper>,
);
expect(catalogApi.getEntities).toHaveBeenCalledWith({
filter: [
{
kind: ['Group'],
'metadata.name': 'test-entity',
},
{
kind: ['User'],
'metadata.name': 'test-entity',
},
],
});
});
});
describe('catalogFilter should take precedence over allowedKinds', () => {
beforeEach(() => {
uiSchema = {
'ui:options': {
catalogFilter: [
{
kind: ['Group'],
'metadata.name': 'test-group',
},
],
allowedKinds: ['User'],
},
};
props = {
onChange,
schema,
required,
uiSchema,
rawErrors,
formData,
} as unknown as FieldProps<any>;
catalogApi.getEntities.mockResolvedValue({ items: entities });
});
it('searches for a Group entity', async () => {
await renderInTestApp(
<Wrapper>
<EntityPicker {...props} />
</Wrapper>,
);
expect(catalogApi.getEntities).toHaveBeenCalledWith({
filter: [
{
kind: ['Group'],
'metadata.name': 'test-group',
},
],
});
});
});
});
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { type EntityFilterQuery } from '@backstage/catalog-client';
import { useApi } from '@backstage/core-plugin-api';
import {
catalogApiRef,
@@ -44,6 +45,11 @@ export const EntityPicker = (props: EntityPickerProps) => {
idSchema,
} = props;
const allowedKinds = uiSchema['ui:options']?.allowedKinds;
const catalogFilter: EntityFilterQuery | undefined =
uiSchema['ui:options']?.catalogFilter ||
(allowedKinds && { kind: allowedKinds });
const defaultKind = uiSchema['ui:options']?.defaultKind;
const defaultNamespace = uiSchema['ui:options']?.defaultNamespace;
@@ -51,7 +57,7 @@ export const EntityPicker = (props: EntityPickerProps) => {
const { value: entities, loading } = useAsync(() =>
catalogApi.getEntities(
allowedKinds ? { filter: { kind: allowedKinds } } : undefined,
catalogFilter ? { filter: catalogFilter } : undefined,
),
);
@@ -16,6 +16,13 @@
import { z } from 'zod';
import { makeFieldSchemaFromZod } from '../utils';
/**
* @public
*/
export const entityQueryFilterExpressionSchema = z.record(
z.string().or(z.array(z.string())),
);
/**
* @public
*/
@@ -42,6 +49,11 @@ export const EntityPickerFieldSchema = makeFieldSchemaFromZod(
.describe(
'The default namespace. Options with this namespace will not be prefixed.',
),
catalogFilter: z
.array(entityQueryFilterExpressionSchema)
.or(entityQueryFilterExpressionSchema)
.optional()
.describe('List of key-value filter expression for entities'),
}),
);