Merge pull request #8220 from djamaile/master

feat: hide owned selector picker if user doesn't own an entity
This commit is contained in:
Patrik Oldsberg
2021-12-27 18:37:11 +01:00
committed by GitHub
4 changed files with 55 additions and 21 deletions
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/plugin-catalog-react': patch
---
When a user has zero owned entities when viewing an entity kind in the catalog
page, it will be automatically redirected to see all the entities. Furthermore,
for the kind User and Group there are no longer the owned selector.
@@ -122,26 +122,26 @@ export const UserListPicker = ({
const classes = useStyles();
const configApi = useApi(configApiRef);
const orgName = configApi.getOptionalString('organization.name') ?? 'Company';
const { filters, updateFilters, backendEntities, queryParameters } =
useEntityListProvider();
// Remove group items that aren't in availableFilters and exclude
// any now-empty groups.
const userAndGroupFilterIds = ['starred', 'all'];
const filterGroups = getFilterGroups(orgName)
.map(filterGroup => ({
...filterGroup,
items: filterGroup.items.filter(
({ id }) => !availableFilters || availableFilters.includes(id),
items: filterGroup.items.filter(({ id }) =>
// TODO: avoid hardcoding kinds here
['group', 'user'].some(kind => kind === queryParameters.kind)
? userAndGroupFilterIds.includes(id)
: !availableFilters || availableFilters.includes(id),
),
}))
.filter(({ items }) => !!items.length);
const { filters, updateFilters, backendEntities, queryParameters } =
useEntityListProvider();
const { isStarredEntity } = useStarredEntities();
const { isOwnedEntity } = useEntityOwnership();
const [selectedUserFilter, setSelectedUserFilter] = useState(
[queryParameters.user].flat()[0] ?? initialFilter,
);
// Static filters; used for generating counts of potentially unselected kinds
const ownedFilter = useMemo(
@@ -153,6 +153,19 @@ export const UserListPicker = ({
[isOwnedEntity, isStarredEntity],
);
// To show proper counts for each section, apply all other frontend filters _except_ the user
// filter that's controlled by this picker.
const [entitiesWithoutUserFilter, setEntitiesWithoutUserFilter] =
useState(backendEntities);
const totalOwnedUserEntities = entitiesWithoutUserFilter.filter(entity =>
ownedFilter.filterEntity(entity),
).length;
const [selectedUserFilter, setSelectedUserFilter] = useState(
totalOwnedUserEntities > 0
? [queryParameters.user].flat()[0] ?? initialFilter
: 'all',
);
useEffect(() => {
updateFilters({
user: selectedUserFilter
@@ -165,10 +178,6 @@ export const UserListPicker = ({
});
}, [selectedUserFilter, isOwnedEntity, isStarredEntity, updateFilters]);
// To show proper counts for each section, apply all other frontend filters _except_ the user
// filter that's controlled by this picker.
const [entitiesWithoutUserFilter, setEntitiesWithoutUserFilter] =
useState(backendEntities);
useEffect(() => {
const filterFn = reduceEntityFilters(
compact(Object.values({ ...filters, user: undefined })),
@@ -179,9 +188,7 @@ export const UserListPicker = ({
function getFilterCount(id: UserListFilterKind) {
switch (id) {
case 'owned':
return entitiesWithoutUserFilter.filter(entity =>
ownedFilter.filterEntity(entity),
).length;
return totalOwnedUserEntities;
case 'starred':
return entitiesWithoutUserFilter.filter(entity =>
starredFilter.filterEntity(entity),
@@ -137,12 +137,27 @@ describe('<EntityListProvider />', () => {
const { result, waitFor } = renderHook(() => useEntityListProvider(), {
wrapper,
initialProps: {
userFilter: 'owned',
userFilter: 'all',
},
});
await waitFor(() => !!result.current.entities.length);
expect(result.current.backendEntities.length).toBe(2);
expect(result.current.entities.length).toBe(1);
act(() =>
result.current.updateFilters({
user: new UserListFilter(
'owned',
entity => entity.metadata.name === 'component-1',
() => true,
),
}),
);
await waitFor(() => {
expect(result.current.backendEntities.length).toBe(2);
expect(result.current.entities.length).toBe(1);
expect(mockCatalogApi.getEntities).toHaveBeenCalledTimes(1);
});
});
it('resolves query param filter values', async () => {
@@ -189,12 +189,14 @@ describe('CatalogPage', () => {
c => c.tagName === 'SPAN',
);
const columnHeaderLabels = columnHeader.map(c => c.textContent);
expect(columnHeaderLabels).toEqual(['Foo', 'Bar', 'Baz', 'Actions']);
}, 20_000);
it('should render the default actions of an item in the grid', async () => {
const { findByTitle, findByText } = await renderWrapped(<CatalogPage />);
const { getByTestId, findByTitle, findByText } = await renderWrapped(
<CatalogPage />,
);
fireEvent.click(getByTestId('user-picker-owned'));
expect(await findByText(/Owned \(1\)/)).toBeInTheDocument();
expect(await findByTitle(/View/)).toBeInTheDocument();
expect(await findByTitle(/Edit/)).toBeInTheDocument();
@@ -221,9 +223,10 @@ describe('CatalogPage', () => {
},
];
const { findByTitle, findByText } = await renderWrapped(
const { getByTestId, findByTitle, findByText } = await renderWrapped(
<CatalogPage actions={actions} />,
);
fireEvent.click(getByTestId('user-picker-owned'));
expect(await findByText(/Owned \(1\)/)).toBeInTheDocument();
expect(await findByTitle(/Foo Action/)).toBeInTheDocument();
expect(await findByTitle(/Bar Action/)).toBeInTheDocument();
@@ -235,6 +238,7 @@ describe('CatalogPage', () => {
// https://github.com/mbrn/material-table/issues/1293
it('should render', async () => {
const { findByText, getByTestId } = await renderWrapped(<CatalogPage />);
fireEvent.click(getByTestId('user-picker-owned'));
await expect(findByText(/Owned \(1\)/)).resolves.toBeInTheDocument();
fireEvent.click(getByTestId('user-picker-all'));
await expect(findByText(/All \(2\)/)).resolves.toBeInTheDocument();
@@ -250,7 +254,8 @@ describe('CatalogPage', () => {
// this test is for fixing the bug after favoriting an entity, the matching
// entities defaulting to "owned" filter and not based on the selected filter
it('should render the correct entities filtered on the selected filter', async () => {
await renderWrapped(<CatalogPage />);
const { getByTestId } = await renderWrapped(<CatalogPage />);
fireEvent.click(getByTestId('user-picker-owned'));
await expect(screen.findByText(/Owned \(1\)/)).resolves.toBeInTheDocument();
fireEvent.click(screen.getByTestId('user-picker-starred'));
await expect(