diff --git a/workspaces/marketplace/.changeset/quiet-kiwis-admire.md b/workspaces/marketplace/.changeset/quiet-kiwis-admire.md new file mode 100644 index 000000000..b504c0f4d --- /dev/null +++ b/workspaces/marketplace/.changeset/quiet-kiwis-admire.md @@ -0,0 +1,7 @@ +--- +'@red-hat-developer-hub/backstage-plugin-marketplace-backend': patch +'@red-hat-developer-hub/backstage-plugin-marketplace-common': patch +'@red-hat-developer-hub/backstage-plugin-marketplace': patch +--- + +add optional sorting, filtering, pagination to marketplace api diff --git a/workspaces/marketplace/plugins/marketplace-backend/src/router.test.ts b/workspaces/marketplace/plugins/marketplace-backend/src/router.test.ts index 73cf551a0..a05e9eb57 100644 --- a/workspaces/marketplace/plugins/marketplace-backend/src/router.test.ts +++ b/workspaces/marketplace/plugins/marketplace-backend/src/router.test.ts @@ -140,7 +140,7 @@ describe('createRouter', () => { '/api/marketplace/plugins', ); expect(response.status).toEqual(200); - expect(response.body).toHaveLength(2); + expect(response.body.items).toHaveLength(2); }); it('should get the plugin by name', async () => { diff --git a/workspaces/marketplace/plugins/marketplace-backend/src/router.ts b/workspaces/marketplace/plugins/marketplace-backend/src/router.ts index 81af2714e..5f085cfa4 100644 --- a/workspaces/marketplace/plugins/marketplace-backend/src/router.ts +++ b/workspaces/marketplace/plugins/marketplace-backend/src/router.ts @@ -20,9 +20,11 @@ import Router from 'express-promise-router'; import { HttpAuthService } from '@backstage/backend-plugin-api'; import { InputError, NotFoundError } from '@backstage/errors'; import { + decodeGetPluginsRequest, decodeQueryParams, EntityFacetSchema, GetEntityFacetsRequest, + GetPluginsRequest, MarketplaceApi, MarketplaceKinds, } from '@red-hat-developer-hub/backstage-plugin-marketplace-common'; @@ -36,8 +38,10 @@ export async function createRouter({ const router = Router(); router.use(express.json()); - router.get('/plugins', async (_req, res) => { - const plugins = await marketplaceApi.getPlugins(); + router.get('/plugins', async (req, res) => { + const query = req.url.split('?')[1] || ''; + const request: GetPluginsRequest = decodeGetPluginsRequest(query); + const plugins = await marketplaceApi.getPlugins(request); res.json(plugins); }); diff --git a/workspaces/marketplace/plugins/marketplace-common/report.api.md b/workspaces/marketplace/plugins/marketplace-common/report.api.md index 5e8a894a1..cb9d85f8b 100644 --- a/workspaces/marketplace/plugins/marketplace-common/report.api.md +++ b/workspaces/marketplace/plugins/marketplace-common/report.api.md @@ -9,9 +9,13 @@ import { CatalogApi } from '@backstage/catalog-client'; import { Entity } from '@backstage/catalog-model'; import { EntityFilterQuery } from '@backstage/catalog-client'; import { EntityFilterQuery as EntityFilterQuery_2 } from '@red-hat-developer-hub/backstage-plugin-marketplace-common'; +import { EntityOrderQuery } from '@backstage/catalog-client'; +import { EntityOrderQuery as EntityOrderQuery_2 } from '@backstage/catalog-client/index'; import { GetEntityFacetsRequest } from '@backstage/catalog-client'; import { GetEntityFacetsResponse } from '@backstage/catalog-client'; +import { GetPluginsRequest as GetPluginsRequest_2 } from '@red-hat-developer-hub/backstage-plugin-marketplace-common'; import { JsonObject } from '@backstage/types'; +import { QueryEntitiesRequest } from '@backstage/catalog-client/index'; import { z } from 'zod'; // @public (undocumented) @@ -22,12 +26,24 @@ export interface AppConfigExample extends JsonObject { title: string; } +// @public (undocumented) +export const convertGetPluginsRequestToQueryEntitiesRequest: (query?: GetPluginsRequest) => QueryEntitiesRequest; + // @public (undocumented) export const decodeFacetParams: (searchParams: URLSearchParams) => string[]; // @public (undocumented) export const decodeFilterParams: (searchParams: URLSearchParams) => Record; +// @public (undocumented) +export const decodeGetPluginsRequest: (queryString: string) => GetPluginsRequest; + +// @public (undocumented) +export const decodeOrderFields: (searchParams: URLSearchParams) => { + field: string; + order: "desc" | "asc"; +}[]; + // @public (undocumented) export const decodeQueryParams: (queryString: string) => { facets?: string[] | undefined; @@ -40,6 +56,12 @@ export const encodeFacetParams: (facets: string[]) => URLSearchParams; // @public (undocumented) export const encodeFilterParams: (filter: EntityFilterQuery_2) => URLSearchParams; +// @public (undocumented) +export const encodeGetPluginsQueryParams: (options?: GetPluginsRequest_2) => URLSearchParams; + +// @public (undocumented) +export const encodeOrderFieldsParams: (orderFields: EntityOrderQuery_2) => URLSearchParams; + // @public (undocumented) export const encodeQueryParams: (options?: { filter?: EntityFilterQuery_2; @@ -63,10 +85,25 @@ export { EntityFilterQuery } // @public (undocumented) export const EntityFilterQuerySchema: z.ZodRecord]>>; +// @public (undocumented) +export type FullTextFilter = { + term: string; + fields?: string[]; +}; + export { GetEntityFacetsRequest } export { GetEntityFacetsResponse } +// @public (undocumented) +export type GetPluginsRequest = { + limit?: number; + offset?: number; + filter?: EntityFilterQuery; + orderFields?: EntityOrderQuery; + searchTerm?: string; +}; + // @public (undocumented) export enum InstallStatus { // (undocumented) @@ -89,7 +126,7 @@ export interface MarketplaceApi { // (undocumented) getPluginLists(): Promise; // (undocumented) - getPlugins(): Promise; + getPlugins(request?: GetPluginsRequest): Promise; // (undocumented) getPluginsByPluginListName(name: string): Promise; } @@ -106,7 +143,7 @@ export class MarketplaceCatalogClient implements MarketplaceApi { // (undocumented) getPluginLists(): Promise; // (undocumented) - getPlugins(): Promise; + getPlugins(request?: GetPluginsRequest): Promise; // (undocumented) getPluginsByPluginListName(name: string): Promise; } @@ -207,4 +244,25 @@ export interface MarketplacePluginSpec extends JsonObject { packages?: (string | MarketplacePluginPackage)[]; } +// @public (undocumented) +export interface MarketplacePluginWithPageInfo { + // (undocumented) + items: MarketplacePlugin[]; + // (undocumented) + pageInfo?: { + nextCursor?: string; + prevCursor?: string; + }; + // (undocumented) + totalItems?: number; +} + +// @public (undocumented) +export enum SortOrder { + // (undocumented) + asc = "asc", + // (undocumented) + desc = "desc" +} + ``` diff --git a/workspaces/marketplace/plugins/marketplace-common/src/api/MarketplaceCatalogClient.test.ts b/workspaces/marketplace/plugins/marketplace-common/src/api/MarketplaceCatalogClient.test.ts index 9695a9420..b2de6790d 100644 --- a/workspaces/marketplace/plugins/marketplace-common/src/api/MarketplaceCatalogClient.test.ts +++ b/workspaces/marketplace/plugins/marketplace-common/src/api/MarketplaceCatalogClient.test.ts @@ -94,13 +94,13 @@ describe('MarketplaceCatalogClient', () => { it('should return the plugins', async () => { const api = new MarketplaceCatalogClient(options); const plugins = await api.getPlugins(); - expect(plugins).toHaveLength(2); + expect(plugins?.items).toHaveLength(2); }); it('should return the plugins when the auth options is not passed', async () => { const api = new MarketplaceCatalogClient({ ...options, auth: undefined }); const plugins = await api.getPlugins(); - expect(plugins).toHaveLength(2); + expect(plugins?.items).toHaveLength(2); }); }); diff --git a/workspaces/marketplace/plugins/marketplace-common/src/api/MarketplaceCatalogClient.ts b/workspaces/marketplace/plugins/marketplace-common/src/api/MarketplaceCatalogClient.ts index 112c8ddea..7ac6e65e7 100644 --- a/workspaces/marketplace/plugins/marketplace-common/src/api/MarketplaceCatalogClient.ts +++ b/workspaces/marketplace/plugins/marketplace-common/src/api/MarketplaceCatalogClient.ts @@ -23,11 +23,14 @@ import { } from '@backstage/catalog-client'; import { NotFoundError } from '@backstage/errors'; import { + GetPluginsRequest, MarketplaceApi, MarketplaceKinds, MarketplacePlugin, MarketplacePluginList, + MarketplacePluginWithPageInfo, } from '../types'; +import { convertGetPluginsRequestToQueryEntitiesRequest } from '../utils'; /** * @public @@ -59,18 +62,22 @@ export class MarketplaceCatalogClient implements MarketplaceApi { }); } - async getPlugins(): Promise { + async getPlugins( + request?: GetPluginsRequest, + ): Promise { const token = await this.getServiceToken(); + const queryEntitiesRequest = + convertGetPluginsRequestToQueryEntitiesRequest(request); const result = await this.catalog.queryEntities( - { - filter: { - kind: 'plugin', - }, - }, + queryEntitiesRequest, token, ); - return result.items as MarketplacePlugin[]; + return { + items: result.items as MarketplacePlugin[], + totalItems: result.totalItems, + pageInfo: result.pageInfo, + }; } async getPluginLists(): Promise { diff --git a/workspaces/marketplace/plugins/marketplace-common/src/types.ts b/workspaces/marketplace/plugins/marketplace-common/src/types.ts index a32d5d8a8..fdeda2438 100644 --- a/workspaces/marketplace/plugins/marketplace-common/src/types.ts +++ b/workspaces/marketplace/plugins/marketplace-common/src/types.ts @@ -15,6 +15,8 @@ */ import { + EntityFilterQuery, + EntityOrderQuery, GetEntityFacetsRequest, GetEntityFacetsResponse, } from '@backstage/catalog-client'; @@ -28,6 +30,18 @@ export interface MarketplacePlugin extends Entity { spec?: MarketplacePluginSpec; } +/** + * @public + */ +export interface MarketplacePluginWithPageInfo { + items: MarketplacePlugin[]; + totalItems?: number; + pageInfo?: { + nextCursor?: string; + prevCursor?: string; + }; +} + /** * @public */ @@ -58,6 +72,14 @@ export enum MarketplaceKinds { package = 'Package', } +/** + * @public + */ +export enum SortOrder { + asc = 'asc', + desc = 'desc', +} + /** * @public */ @@ -96,6 +118,25 @@ export interface MarketplacePluginSpec extends JsonObject { }; } +/** + * @public + */ +export type FullTextFilter = { + term: string; + fields?: string[]; +}; + +/** + * @public + */ +export type GetPluginsRequest = { + limit?: number; + offset?: number; + filter?: EntityFilterQuery; + orderFields?: EntityOrderQuery; + searchTerm?: string; +}; + /** * @public */ @@ -135,7 +176,9 @@ export type { * @public */ export interface MarketplaceApi { - getPlugins(): Promise; + getPlugins( + request?: GetPluginsRequest, + ): Promise; getPluginByName(name: string): Promise; getPluginLists(): Promise; getPluginListByName(name: string): Promise; diff --git a/workspaces/marketplace/plugins/marketplace-common/src/utils/decodeQueryParams.test.ts b/workspaces/marketplace/plugins/marketplace-common/src/utils/decodeQueryParams.test.ts index e22f5e3cb..125140512 100644 --- a/workspaces/marketplace/plugins/marketplace-common/src/utils/decodeQueryParams.test.ts +++ b/workspaces/marketplace/plugins/marketplace-common/src/utils/decodeQueryParams.test.ts @@ -13,13 +13,54 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import { GetPluginsRequest } from '../types'; import { decodeFacetParams, decodeFilterParams, decodeQueryParams, + decodeGetPluginsRequest, + decodeOrderFields, } from './decodeQueryParams'; describe('decodeFilterParams', () => { + it('should decode single orderFields', () => { + const searchParams = new URLSearchParams( + 'orderFields=metadata.title%2Casc', + ); + expect(decodeOrderFields(searchParams)).toEqual([ + { field: 'metadata.title', order: 'asc' }, + ]); + }); + + it('should decode multiple orderFields', () => { + const searchParams = new URLSearchParams( + 'orderFields=metadata.title%2Cdesc&orderFields=metadata.name%2Casc', + ); + expect(decodeOrderFields(searchParams)).toEqual([ + { field: 'metadata.title', order: 'desc' }, + { field: 'metadata.name', order: 'asc' }, + ]); + }); + + it('should decode GetPlugins Request', () => { + const encodedString = + 'filter=metadata.name%3Dsearch&filter=spec.type%3Dbackend-plugin&orderFields=metadata.title%2Cdesc&orderFields=metadata.name%2Casc&searchTerm=search&limit=2&offset=1'; + const params: GetPluginsRequest = { + filter: { + 'metadata.name': ['search'], + 'spec.type': ['backend-plugin'], + }, + orderFields: [ + { field: 'metadata.title', order: 'desc' }, + { field: 'metadata.name', order: 'asc' }, + ], + searchTerm: 'search', + limit: 2, + offset: 1, + }; + expect(decodeGetPluginsRequest(encodedString)).toEqual(params); + }); + it('should decode single filter', () => { const searchParams = new URLSearchParams('filter=kind%3Dplugin'); expect(decodeFilterParams(searchParams)).toEqual({ kind: ['plugin'] }); diff --git a/workspaces/marketplace/plugins/marketplace-common/src/utils/decodeQueryParams.ts b/workspaces/marketplace/plugins/marketplace-common/src/utils/decodeQueryParams.ts index 971d812e4..e24efccd7 100644 --- a/workspaces/marketplace/plugins/marketplace-common/src/utils/decodeQueryParams.ts +++ b/workspaces/marketplace/plugins/marketplace-common/src/utils/decodeQueryParams.ts @@ -14,6 +14,14 @@ * limitations under the License. */ +import { + EntityOrderQuery, + QueryEntitiesRequest, +} from '@backstage/catalog-client/index'; +import { GetPluginsRequest, SortOrder } from '../types'; + +const requiredFilter = { kind: 'plugin' }; + /** * * @public @@ -32,6 +40,73 @@ export const decodeFilterParams = (searchParams: URLSearchParams) => { return filter; }; +/** + * + * @public + */ +export const decodeOrderFields = (searchParams: URLSearchParams) => { + const orderFields = searchParams.getAll('orderFields'); + const decodedOrderFields: EntityOrderQuery = orderFields.map(field => { + const [key, order] = field.split(','); + return { field: key, order: order as SortOrder }; + }); + return decodedOrderFields; +}; + +/** + * + * @public + */ +export const decodeGetPluginsRequest = ( + queryString: string, +): GetPluginsRequest => { + const searchParams = new URLSearchParams(queryString); + return { + orderFields: + searchParams.getAll('orderFields').length > 0 + ? decodeOrderFields(searchParams) + : undefined, + searchTerm: searchParams.get('searchTerm') || undefined, + limit: searchParams.get('limit') + ? Number(searchParams.get('limit')) + : undefined, + offset: searchParams.get('offset') + ? Number(searchParams.get('offset')) + : undefined, + filter: + searchParams.getAll('filter').length > 0 + ? decodeFilterParams(searchParams) + : undefined, + }; +}; + +/** + * @public + */ +export const convertGetPluginsRequestToQueryEntitiesRequest = ( + query?: GetPluginsRequest, +): QueryEntitiesRequest => { + const entitiesRequest: QueryEntitiesRequest = {}; + + entitiesRequest.filter = { ...query?.filter, ...requiredFilter }; + + if (query?.orderFields) { + entitiesRequest.orderFields = query.orderFields; + } + if (query?.limit) { + entitiesRequest.limit = query.limit; + } + if (query?.offset) { + entitiesRequest.offset = query.offset; + } + if (query?.searchTerm) { + entitiesRequest.fullTextFilter = { + term: query.searchTerm, + }; + } + return entitiesRequest; +}; + /** * @public */ diff --git a/workspaces/marketplace/plugins/marketplace-common/src/utils/encodeQueryParams.test.ts b/workspaces/marketplace/plugins/marketplace-common/src/utils/encodeQueryParams.test.ts index f1dce0a3e..63a14c46b 100644 --- a/workspaces/marketplace/plugins/marketplace-common/src/utils/encodeQueryParams.test.ts +++ b/workspaces/marketplace/plugins/marketplace-common/src/utils/encodeQueryParams.test.ts @@ -13,14 +13,62 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { EntityFilterQuery } from '@red-hat-developer-hub/backstage-plugin-marketplace-common'; +import { + EntityFilterQuery, + GetPluginsRequest, + SortOrder, +} from '@red-hat-developer-hub/backstage-plugin-marketplace-common'; import { encodeFilterParams, encodeFacetParams, encodeQueryParams, + encodeGetPluginsQueryParams, + encodeOrderFieldsParams, } from './encodeQueryParams'; +import { EntityOrderQuery } from '@backstage/catalog-client/index'; describe('encodeFilterParams', () => { + it('should encode single orderFields correctly', () => { + const orderFields: EntityOrderQuery = { + field: 'metadata.title', + order: 'asc' as SortOrder, + }; + const params = encodeOrderFieldsParams(orderFields).toString(); + expect(params).toBe('orderFields=metadata.title%2Casc'); + }); + + it('should encode multiple orderFields correctly', () => { + const orderFields: EntityOrderQuery = [ + { field: 'metadata.title', order: 'desc' }, + { field: 'metadata.name', order: 'asc' }, + ]; + const params = encodeOrderFieldsParams(orderFields).toString(); + expect(params).toBe( + 'orderFields=metadata.title%2Cdesc&orderFields=metadata.name%2Casc', + ); + }); + + it('should encode GetPluginsRequest correctly', () => { + const params: GetPluginsRequest = { + filter: { + 'metadata.name': 'search', + 'spec.type': 'backend-plugin', + }, + orderFields: [ + { field: 'metadata.title', order: 'desc' }, + { field: 'metadata.name', order: 'asc' }, + ], + searchTerm: 'search', + limit: 2, + offset: 1, + }; + + const encodedParams = encodeGetPluginsQueryParams(params).toString(); + expect(encodedParams).toBe( + 'limit=2&offset=1&searchTerm=search&orderFields=metadata.title%2Cdesc&orderFields=metadata.name%2Casc&filter=metadata.name%3Dsearch&filter=spec.type%3Dbackend-plugin', + ); + }); + it('should encode single filter correctly', () => { const filter: EntityFilterQuery = { kind: 'component' }; const params = encodeFilterParams(filter).toString(); diff --git a/workspaces/marketplace/plugins/marketplace-common/src/utils/encodeQueryParams.ts b/workspaces/marketplace/plugins/marketplace-common/src/utils/encodeQueryParams.ts index 4a360597a..cd6a867d1 100644 --- a/workspaces/marketplace/plugins/marketplace-common/src/utils/encodeQueryParams.ts +++ b/workspaces/marketplace/plugins/marketplace-common/src/utils/encodeQueryParams.ts @@ -13,7 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { EntityFilterQuery } from '@red-hat-developer-hub/backstage-plugin-marketplace-common'; +import { EntityOrderQuery } from '@backstage/catalog-client/index'; +import { + EntityFilterQuery, + GetPluginsRequest, +} from '@red-hat-developer-hub/backstage-plugin-marketplace-common'; /** * @public @@ -35,6 +39,55 @@ export const encodeFilterParams = (filter: EntityFilterQuery) => { return params; }; +/** + * @public + */ +export const encodeOrderFieldsParams = (orderFields: EntityOrderQuery) => { + const params = new URLSearchParams(); + if (Array.isArray(orderFields)) { + orderFields.forEach(({ field, order }) => { + params.append( + 'orderFields', + `${encodeURIComponent(field)},${encodeURIComponent(order)}`, + ); + }); + } else { + const { field, order } = orderFields; + params.append('orderFields', `${field},${order}`); + } + return params; +}; + +/** + * @public + */ +export const encodeGetPluginsQueryParams = ( + options?: GetPluginsRequest, +): URLSearchParams => { + const params = new URLSearchParams(); + const { searchTerm, limit, offset, orderFields, filter } = options || {}; + if (limit) { + params.append('limit', String(limit)); + } + if (offset) { + params.append('offset', String(offset)); + } + if (searchTerm) { + params.append('searchTerm', encodeURIComponent(searchTerm)); + } + if (orderFields) { + encodeOrderFieldsParams(orderFields).forEach((value, key) => { + params.append(key, value); + }); + } + if (filter) { + encodeFilterParams(filter).forEach((value, key) => + params.append(key, value), + ); + } + return params; +}; + /** * @public */ diff --git a/workspaces/marketplace/plugins/marketplace/src/api/MarketplaceBackendClient.tsx b/workspaces/marketplace/plugins/marketplace/src/api/MarketplaceBackendClient.tsx index aa6f1ce51..db40a3088 100644 --- a/workspaces/marketplace/plugins/marketplace/src/api/MarketplaceBackendClient.tsx +++ b/workspaces/marketplace/plugins/marketplace/src/api/MarketplaceBackendClient.tsx @@ -17,12 +17,15 @@ import { DiscoveryApi, FetchApi } from '@backstage/core-plugin-api'; import { + GetPluginsRequest, encodeQueryParams, GetEntityFacetsRequest, GetEntityFacetsResponse, MarketplaceApi, MarketplacePlugin, MarketplacePluginList, + MarketplacePluginWithPageInfo, + encodeGetPluginsQueryParams, } from '@red-hat-developer-hub/backstage-plugin-marketplace-common'; export type MarketplaceBackendClientOptions = { @@ -39,9 +42,13 @@ export class MarketplaceBackendClient implements MarketplaceApi { this.fetchApi = options.fetchApi; } - async getPlugins(): Promise { + async getPlugins( + request?: GetPluginsRequest, + ): Promise { const baseUrl = await this.discoveryApi.getBaseUrl('marketplace'); - const url = `${baseUrl}/plugins`; + const params = encodeGetPluginsQueryParams(request); + const query = params.toString(); + const url = `${baseUrl}/plugins${query ? '?' : ''}${query}`; const response = await this.fetchApi.fetch(url); if (!response.ok) { diff --git a/workspaces/marketplace/plugins/marketplace/src/components/MarketplaceCatalogContent.tsx b/workspaces/marketplace/plugins/marketplace/src/components/MarketplaceCatalogContent.tsx index 79b5d9516..c51c1ebbc 100644 --- a/workspaces/marketplace/plugins/marketplace/src/components/MarketplaceCatalogContent.tsx +++ b/workspaces/marketplace/plugins/marketplace/src/components/MarketplaceCatalogContent.tsx @@ -37,7 +37,7 @@ export const MarketplaceCatalogContent = () => { > All plugins - {plugins.data ? ` (${plugins.data?.length})` : null} + {plugins.data ? ` (${plugins.data?.items?.length})` : null} diff --git a/workspaces/marketplace/plugins/marketplace/src/components/MarketplaceCatalogGrid.tsx b/workspaces/marketplace/plugins/marketplace/src/components/MarketplaceCatalogGrid.tsx index 407a68ad1..5a2b955cf 100644 --- a/workspaces/marketplace/plugins/marketplace/src/components/MarketplaceCatalogGrid.tsx +++ b/workspaces/marketplace/plugins/marketplace/src/components/MarketplaceCatalogGrid.tsx @@ -171,10 +171,10 @@ export const MarketplaceCatalogGrid = () => { const filteredEntries = React.useMemo(() => { if (!search || !plugins.data) { - return plugins.data; + return plugins.data?.items; } const lowerCaseSearch = search.toLocaleLowerCase('en-US'); - return plugins.data.filter(entry => { + return plugins.data.items.filter(entry => { const lowerCaseValue = entry.metadata?.title?.toLocaleLowerCase('en-US'); return lowerCaseValue?.includes(lowerCaseSearch); }); diff --git a/workspaces/marketplace/plugins/marketplace/src/components/MarketplaceEntryAboutDrawer.tsx b/workspaces/marketplace/plugins/marketplace/src/components/MarketplaceEntryAboutDrawer.tsx index 068aa3a8f..28fec9a46 100644 --- a/workspaces/marketplace/plugins/marketplace/src/components/MarketplaceEntryAboutDrawer.tsx +++ b/workspaces/marketplace/plugins/marketplace/src/components/MarketplaceEntryAboutDrawer.tsx @@ -183,7 +183,7 @@ const EntryContent = ({ entry }: { entry: MarketplacePlugin }) => { const Entry = ({ entryName }: { entryName: string }) => { const plugins = usePlugins(); - const entry = plugins.data?.find(e => e.metadata.name === entryName); + const entry = plugins.data?.items?.find(e => e.metadata.name === entryName); if (plugins.isLoading) { return ; diff --git a/workspaces/marketplace/plugins/marketplace/src/components/MarketplaceEntryInstallDrawer.tsx b/workspaces/marketplace/plugins/marketplace/src/components/MarketplaceEntryInstallDrawer.tsx index 514b342d9..4bdffec6f 100644 --- a/workspaces/marketplace/plugins/marketplace/src/components/MarketplaceEntryInstallDrawer.tsx +++ b/workspaces/marketplace/plugins/marketplace/src/components/MarketplaceEntryInstallDrawer.tsx @@ -104,7 +104,7 @@ const EntryContent = ({ entry }: { entry: MarketplacePlugin }) => { const Entry = ({ entryName }: { entryName: string }) => { const plugins = usePlugins(); - const entry = plugins.data?.find(e => e.metadata.name === entryName); + const entry = plugins.data?.items?.find(e => e.metadata.name === entryName); if (plugins.isLoading) { return ; diff --git a/workspaces/marketplace/plugins/marketplace/src/hooks/usePlugins.ts b/workspaces/marketplace/plugins/marketplace/src/hooks/usePlugins.ts index 347f2ff43..0c897176c 100644 --- a/workspaces/marketplace/plugins/marketplace/src/hooks/usePlugins.ts +++ b/workspaces/marketplace/plugins/marketplace/src/hooks/usePlugins.ts @@ -18,11 +18,12 @@ import { useApi } from '@backstage/core-plugin-api'; import { useQuery } from '@tanstack/react-query'; import { marketplaceApiRef } from '../api'; +import { GetPluginsRequest } from '@red-hat-developer-hub/backstage-plugin-marketplace-common'; -export const usePlugins = () => { +export const usePlugins = (request?: GetPluginsRequest) => { const marketplaceApi = useApi(marketplaceApiRef); return useQuery({ - queryKey: ['plugins'], - queryFn: () => marketplaceApi.getPlugins(), + queryKey: ['plugins', request], + queryFn: () => marketplaceApi.getPlugins(request), }); };