Skip to content

Commit 76e39f6

Browse files
feat(extensions): ux improvements on the catalog page (#1260)
Co-authored-by: Mitesh Kumar <itsmiteshkumar98@gmail.com>
1 parent 192c262 commit 76e39f6

4 files changed

Lines changed: 63 additions & 12 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@red-hat-developer-hub/backstage-plugin-marketplace': patch
3+
---
4+
5+
display a message when search returns no results

workspaces/marketplace/plugins/marketplace/src/components/MarketplaceCatalogContent.test.tsx

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616
import { renderInTestApp } from '@backstage/test-utils';
1717
import { MarketplaceCatalogContent } from './MarketplaceCatalogContent';
1818
import { useFilteredPlugins } from '../hooks/useFilteredPlugins';
19+
import { useCollections } from '../hooks/useCollections';
1920
import { useExtensionsConfiguration } from '../hooks/useExtensionsConfiguration';
21+
import { mockPlugins } from '../__fixtures__/mockPlugins';
2022

2123
const useFilteredPluginsMock = useFilteredPlugins as jest.Mock;
24+
const useCollectionsMock = useCollections as jest.Mock;
2225
const useExtensionsConfigurationMock = useExtensionsConfiguration as jest.Mock;
2326

2427
jest.mock('../hooks/useCollections', () => ({
@@ -37,6 +40,18 @@ jest.mock('../hooks/useFilteredPlugins', () => ({
3740
useFilteredPlugins: jest.fn(),
3841
}));
3942

43+
jest.mock('../hooks/usePluginFacet', () => ({
44+
usePluginFacet: jest.fn().mockReturnValue({
45+
data: [],
46+
}),
47+
}));
48+
49+
jest.mock('../hooks/usePluginFacets', () => ({
50+
usePluginFacets: jest.fn().mockReturnValue({
51+
data: [],
52+
}),
53+
}));
54+
4055
afterAll(() => {
4156
jest.clearAllMocks();
4257
});
@@ -58,6 +73,31 @@ describe('MarketplaceCatalogContent', () => {
5873
expect(getByText('No plugins found')).toBeInTheDocument();
5974
});
6075

76+
it('should show empty state when filters return no results', async () => {
77+
useExtensionsConfigurationMock.mockReturnValue({
78+
data: {
79+
enabled: false,
80+
},
81+
});
82+
useCollectionsMock.mockReturnValue({
83+
data: {
84+
featuredCollections: [],
85+
},
86+
});
87+
useFilteredPluginsMock.mockReturnValue({
88+
data: {
89+
totalItems: 10,
90+
items: mockPlugins,
91+
filteredItems: 0,
92+
},
93+
});
94+
95+
const { getByText } = await renderInTestApp(<MarketplaceCatalogContent />);
96+
expect(
97+
getByText('No results found. Adjust your filters and try again.'),
98+
).toBeInTheDocument();
99+
});
100+
61101
it('should show empty state with no extensions backend found', async () => {
62102
useFilteredPluginsMock.mockReturnValue({
63103
error: {

workspaces/marketplace/plugins/marketplace/src/components/MarketplaceCatalogGrid.tsx

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,29 @@
1414
* limitations under the License.
1515
*/
1616

17+
import Typography from '@mui/material/Typography';
1718
import { useFilteredPlugins } from '../hooks/useFilteredPlugins';
1819

1920
import { PluginCard, PluginCardGrid, PluginCardSkeleton } from './PluginCard';
2021

2122
export const MarketplaceCatalogGrid = () => {
2223
const filteredPlugins = useFilteredPlugins();
24+
const skeletonComponents = Array(4).fill(<PluginCardSkeleton />);
25+
26+
if (filteredPlugins.isLoading) {
27+
return <PluginCardGrid>{skeletonComponents}</PluginCardGrid>;
28+
}
29+
30+
if (filteredPlugins.data?.filteredItems === 0) {
31+
return (
32+
<Typography sx={{ textAlign: 'center', pb: '16px' }} component="span">
33+
No results found. Adjust your filters and try again.
34+
</Typography>
35+
);
36+
}
2337

2438
return (
2539
<PluginCardGrid>
26-
{filteredPlugins.isLoading ? (
27-
<>
28-
<PluginCardSkeleton />
29-
<PluginCardSkeleton />
30-
<PluginCardSkeleton />
31-
<PluginCardSkeleton />
32-
</>
33-
) : null}
3440
{filteredPlugins.data?.items.map(plugin => (
3541
<PluginCard
3642
key={`${plugin.metadata.namespace}/${plugin.metadata.name}`}

workspaces/marketplace/plugins/marketplace/src/components/MarketplacePluginFilter.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,23 +118,23 @@ const SupportTypeFilter = () => {
118118
const allSupportTypeItems: SelectItem[] = [];
119119

120120
const certified = facets[facetsKeys[0]];
121-
certified.forEach(certifiedBy => {
121+
certified?.forEach(certifiedBy => {
122122
allSupportTypeItems.push({
123123
label: `Certified by ${certifiedBy.value} (${certifiedBy.count})`,
124124
value: `${facetsKeys[0]}=${certifiedBy.value}`,
125125
});
126126
});
127127

128128
const verified = facets[facetsKeys[1]];
129-
verified.forEach(verifiedBy => {
129+
verified?.forEach(verifiedBy => {
130130
allSupportTypeItems.push({
131131
label: `Verified by ${verifiedBy.value} (${verifiedBy.count})`,
132132
value: `${facetsKeys[1]}=${verifiedBy.value}`,
133133
});
134134
});
135135

136136
const preInstalled = facets[facetsKeys[2]];
137-
preInstalled.forEach(preInstall => {
137+
preInstalled?.forEach(preInstall => {
138138
if (preInstall.value === 'false') {
139139
allSupportTypeItems.push({
140140
label: `Custom plugins (${preInstall.count})`,
@@ -144,7 +144,7 @@ const SupportTypeFilter = () => {
144144
});
145145

146146
const supportTypes = facets[facetsKeys[3]];
147-
supportTypes.forEach(supportType => {
147+
supportTypes?.forEach(supportType => {
148148
allSupportTypeItems.push({
149149
label: `${supportType.value} (${supportType.count})`,
150150
value: `${facetsKeys[3]}=${supportType.value}`,

0 commit comments

Comments
 (0)