Merge pull request #8220 from djamaile/master
feat: hide owned selector picker if user doesn't own an entity
This commit is contained in:
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user