Force entity references to be full in the owner picker.

Signed-off-by: Aramis Sennyey <sennyeya@amazon.com>
This commit is contained in:
Aramis Sennyey
2023-03-28 16:35:55 -04:00
committed by Fredrik Adelöw
parent b39b897a7b
commit 0b42e304f8
4 changed files with 88 additions and 16 deletions
@@ -198,7 +198,7 @@ describe('<EntityOwnerPicker/>', () => {
);
expect(updateFilters).toHaveBeenLastCalledWith({
owners: new EntityOwnerFilter(['another-owner']),
owners: new EntityOwnerFilter(['group:default/another-owner']),
});
});
@@ -224,7 +224,7 @@ describe('<EntityOwnerPicker/>', () => {
fireEvent.click(screen.getByTestId('owner-picker-expand'));
fireEvent.click(screen.getByText('some-owner'));
expect(updateFilters).toHaveBeenLastCalledWith({
owners: new EntityOwnerFilter(['some-owner']),
owners: new EntityOwnerFilter(['group:default/some-owner']),
});
});
@@ -245,9 +245,10 @@ describe('<EntityOwnerPicker/>', () => {
</ApiProvider>,
);
expect(updateFilters).toHaveBeenLastCalledWith({
owners: new EntityOwnerFilter(['some-owner']),
owners: new EntityOwnerFilter(['group:default/some-owner']),
});
fireEvent.click(screen.getByTestId('owner-picker-expand'));
expect(screen.getByLabelText('some-owner')).toBeChecked();
fireEvent.click(screen.getByLabelText('some-owner'));
@@ -272,7 +273,7 @@ describe('<EntityOwnerPicker/>', () => {
</ApiProvider>,
);
expect(updateFilters).toHaveBeenLastCalledWith({
owners: new EntityOwnerFilter(['team-a']),
owners: new EntityOwnerFilter(['group:default/team-a']),
});
rendered.rerender(
<ApiProvider apis={mockApis}>
@@ -288,7 +289,7 @@ describe('<EntityOwnerPicker/>', () => {
</ApiProvider>,
);
expect(updateFilters).toHaveBeenLastCalledWith({
owners: new EntityOwnerFilter(['team-b']),
owners: new EntityOwnerFilter(['group:default/team-b']),
});
});
it('removes owners from filters if there are none available', async () => {
@@ -107,14 +107,13 @@ export const EntityOwnerPicker = () => {
if (entity) {
return {
label: humanizeEntity(entity, { defaultKind: 'Group' }),
entityRef: humanizeEntityRef(entity, { defaultKind: 'Group' }),
entityRef: stringifyEntityRef(entity),
};
}
return {
label: humanizeEntityRef(
parseEntityRef(ownerEntityRefs[index], { defaultKind: 'Group' }),
{ defaultKind: 'group' },
),
label: humanizeEntityRef(parseEntityRef(ownerEntityRefs[index]), {
defaultKind: 'group',
}),
entityRef: ownerEntityRefs[index],
};
});
@@ -143,7 +142,8 @@ export const EntityOwnerPicker = () => {
// external updates to the page location.
useEffect(() => {
if (queryParamOwners.length) {
setSelectedOwners(queryParamOwners);
const filter = new EntityOwnerFilter(queryParamOwners);
setSelectedOwners(filter.values);
}
}, [queryParamOwners]);
+49 -1
View File
@@ -15,11 +15,12 @@
*/
import { AlphaEntity } from '@backstage/catalog-model/alpha';
import { Entity } from '@backstage/catalog-model';
import { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model';
import { TemplateEntityV1beta3 } from '@backstage/plugin-scaffolder-common';
import {
EntityErrorFilter,
EntityOrphanFilter,
EntityOwnerFilter,
EntityTextFilter,
} from './filters';
@@ -143,3 +144,50 @@ describe('EntityErrorFilter', () => {
expect(filter.filterEntity(entities[1])).toBeFalsy();
});
});
describe('EntityOwnerFilter', () => {
it('should handle humanizedEntityRefs', () => {
const filter = new EntityOwnerFilter(['my-user']);
expect(
filter.filterEntity({
relations: [
{
type: RELATION_OWNED_BY,
targetRef: 'group:default/my-user',
},
],
} as Entity),
).toBeTruthy();
expect(filter.values).toStrictEqual(['group:default/my-user']);
});
it('should also handle full entityRefs', () => {
const filter = new EntityOwnerFilter(['group:default/my-user']);
expect(
filter.filterEntity({
relations: [
{
type: RELATION_OWNED_BY,
targetRef: 'group:default/my-user',
},
],
} as Entity),
).toBeTruthy();
expect(filter.values).toStrictEqual(['group:default/my-user']);
});
it('should also gracefully reject non-entity refs', () => {
const filter = new EntityOwnerFilter(['group:default/my-user', '']);
expect(
filter.filterEntity({
relations: [
{
type: RELATION_OWNED_BY,
targetRef: 'group:default/my-user',
},
],
} as Entity),
).toBeTruthy();
expect(filter.values).toStrictEqual(['group:default/my-user']);
});
});
+27 -4
View File
@@ -14,9 +14,13 @@
* limitations under the License.
*/
import { Entity, RELATION_OWNED_BY } from '@backstage/catalog-model';
import {
Entity,
parseEntityRef,
RELATION_OWNED_BY,
stringifyEntityRef,
} from '@backstage/catalog-model';
import { AlphaEntity } from '@backstage/catalog-model/alpha';
import { humanizeEntityRef } from './components/EntityRefLink';
import { EntityFilter, UserListFilterKind } from './types';
import { getEntityRelations } from './utils';
@@ -113,18 +117,37 @@ export class EntityTextFilter implements EntityFilter {
/**
* Filter matching entities that are owned by group.
* @public
*
* CAUTION: This class may contain both full and partial entity refs.
*/
export class EntityOwnerFilter implements EntityFilter {
constructor(readonly values: string[]) {}
readonly values: string[];
constructor(values: string[]) {
this.values = values.reduce((fullRefs, ref) => {
// Attempt to remove bad entity references here.
try {
fullRefs.push(
stringifyEntityRef(parseEntityRef(ref, { defaultKind: 'Group' })),
);
return fullRefs;
} catch (err) {
return fullRefs;
}
}, [] as string[]);
}
filterEntity(entity: Entity): boolean {
return this.values.some(v =>
getEntityRelations(entity, RELATION_OWNED_BY).some(
o => humanizeEntityRef(o, { defaultKind: 'group' }) === v,
o => stringifyEntityRef(o) === v,
),
);
}
/**
* Get the URL query parameter value. May be a mix of full and humanized entity refs.
* @returns list of entity refs.
*/
toQueryValue(): string[] {
return this.values;
}