feat: add EntityFilterQuery to OwnerPicker to allow filtering entities

Signed-off-by: Enrico Alvarenga <enrico.alvarenga@segment.com>
This commit is contained in:
Enrico Alvarenga
2022-12-06 12:19:18 -08:00
parent b97b844835
commit 4153796f6e
3 changed files with 113 additions and 7 deletions
@@ -14,6 +14,7 @@
* limitations under the License.
*/
import { type 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';
@@ -32,7 +33,15 @@ describe('<OwnerPicker />', () => {
const onChange = jest.fn();
const schema = {};
const required = false;
let uiSchema: { 'ui:options': { allowedKinds?: string[] } };
let uiSchema: {
'ui:options': {
allowedKinds?: string[];
defaultKind?: string;
allowArbitraryValues?: boolean;
defaultNamespace?: string | false;
catalogFilter?: EntityFilterQuery;
};
};
const rawErrors: string[] = [];
const formData = undefined;
@@ -63,7 +72,7 @@ describe('<OwnerPicker />', () => {
afterEach(() => jest.resetAllMocks());
describe('without allowedKinds', () => {
describe('without catalogFilter and allowedKinds', () => {
beforeEach(() => {
uiSchema = { 'ui:options': {} };
props = {
@@ -108,7 +117,7 @@ describe('<OwnerPicker />', () => {
catalogApi.getEntities.mockResolvedValue({ items: entities });
});
it('searches for users and groups', async () => {
it('searches for users', async () => {
await renderInTestApp(
<Wrapper>
<OwnerPicker {...props} />
@@ -122,4 +131,93 @@ describe('<OwnerPicker />', () => {
});
});
});
describe('with catalogFilter', () => {
beforeEach(() => {
uiSchema = {
'ui:options': {
catalogFilter: [
{
kind: ['Group'],
'spec.type': 'team',
},
],
},
};
props = {
onChange,
schema,
required,
uiSchema,
rawErrors,
formData,
} as unknown as FieldProps<any>;
catalogApi.getEntities.mockResolvedValue({ items: entities });
});
it('searches for group entities of type team', async () => {
await renderInTestApp(
<Wrapper>
<OwnerPicker {...props} />
</Wrapper>,
);
expect(catalogApi.getEntities).toHaveBeenCalledWith({
filter: [
{
kind: ['Group'],
'spec.type': 'team',
},
],
});
});
});
describe('catalogFilter should take precedence over allowedKinds', () => {
beforeEach(() => {
uiSchema = {
'ui:options': {
allowedKinds: ['User'],
catalogFilter: [
{
kind: ['Group', 'User'],
},
{
'spec.type': ['team', 'business-unit'],
},
],
},
};
props = {
onChange,
schema,
required,
uiSchema,
rawErrors,
formData,
} as unknown as FieldProps<any>;
catalogApi.getEntities.mockResolvedValue({ items: entities });
});
it('searches for users and groups or teams and business units', async () => {
await renderInTestApp(
<Wrapper>
<OwnerPicker {...props} />
</Wrapper>,
);
expect(catalogApi.getEntities).toHaveBeenCalledWith({
filter: [
{
kind: ['Group', 'User'],
},
{
'spec.type': ['team', 'business-unit'],
},
],
});
});
});
});
@@ -33,14 +33,16 @@ export const OwnerPicker = (props: OwnerPickerProps) => {
} = props;
const defaultNamespace = uiSchema['ui:options']?.defaultNamespace;
const allowedKinds = uiSchema['ui:options']?.allowedKinds;
const catalogFilter = uiSchema['ui:options']?.catalogFilter || {
kind: allowedKinds || ['Group', 'User'],
};
const ownerUiSchema = {
...uiSchema,
'ui:options': {
allowedKinds: (uiSchema['ui:options']?.allowedKinds || [
'Group',
'User',
]) as string[],
catalogFilter,
defaultKind: 'Group',
allowArbitraryValues:
uiSchema['ui:options']?.allowArbitraryValues ?? true,
@@ -15,6 +15,7 @@
*/
import { z } from 'zod';
import { makeFieldSchemaFromZod } from '../utils';
import { entityQueryFilterExpressionSchema } from '../EntityPicker/schema';
/**
* @public
@@ -39,6 +40,11 @@ export const OwnerPickerFieldSchema = 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'),
}),
);