fix(ui): fetch all providers in scan page dropdown (#9781)

Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Hugo Pereira Brito
2026-01-26 15:14:22 +01:00
committed by GitHub
co-authored by alejandrobailo Claude Opus 4.5
parent 5784592437
commit d386730770
3 changed files with 93 additions and 4 deletions
+8
View File
@@ -2,6 +2,14 @@
All notable changes to the **Prowler UI** are documented in this file.
## [1.17.1] (Prowler v5.17.1)
### 🐞 Fixed
- Launch Scan page now displays all providers without pagination limit [(#9700)](https://github.com/prowler-cloud/prowler/pull/9700)
---
## [1.17.0] (Prowler v5.17.0)
### 🚀 Added
+83
View File
@@ -48,6 +48,89 @@ export const getProviders = async ({
}
};
/**
* Fetches all providers by iterating through all pages.
* This is useful when you need the complete list of providers without pagination limits,
* such as for dropdown menus or selection lists.
*/
export const getAllProviders = async ({
query = "",
sort = "",
filters = {},
}: {
query?: string;
sort?: string;
filters?: Record<string, unknown>;
} = {}): Promise<ProvidersApiResponse | undefined> => {
const headers = await getAuthHeaders({ contentType: false });
const pageSize = 100; // Use larger page size to minimize API calls
const maxPages = 50; // Safety limit: 50 pages × 100 = 5000 providers max
let currentPage = 1;
const allProviders: ProvidersApiResponse["data"] = [];
let lastResponse: ProvidersApiResponse | undefined;
let hasMorePages = true;
try {
while (hasMorePages && currentPage <= maxPages) {
const url = new URL(`${apiBaseUrl}/providers?include=provider_groups`);
url.searchParams.append("page[number]", currentPage.toString());
url.searchParams.append("page[size]", pageSize.toString());
if (query) url.searchParams.append("filter[search]", query);
if (sort) url.searchParams.append("sort", sort);
Object.entries(filters).forEach(([key, value]) => {
if (key !== "filter[search]") {
url.searchParams.append(key, String(value));
}
});
const response = await fetch(url.toString(), { headers });
const data = (await handleApiResponse(response)) as
| ProvidersApiResponse
| undefined;
if (!data?.data || data.data.length === 0) {
hasMorePages = false;
continue;
}
allProviders.push(...data.data);
lastResponse = data;
// Check if we've fetched all pages
const totalPages = data.meta?.pagination?.pages || 1;
if (currentPage >= totalPages) {
hasMorePages = false;
} else {
currentPage++;
}
}
// Return combined response with all providers
if (lastResponse) {
return {
...lastResponse,
data: allProviders,
meta: {
...lastResponse.meta,
pagination: {
...lastResponse.meta?.pagination,
page: 1,
pages: 1,
count: allProviders.length,
},
},
};
}
return undefined;
} catch (error) {
console.error("Error fetching all providers:", error);
return undefined;
}
};
export const getProvider = async (formData: FormData) => {
const headers = await getAuthHeaders({ contentType: false });
const providerId = formData.get("id");
+2 -4
View File
@@ -1,6 +1,6 @@
import { Suspense } from "react";
import { getProviders } from "@/actions/providers";
import { getAllProviders } from "@/actions/providers";
import { getScans, getScansByState } from "@/actions/scans";
import { auth } from "@/auth.config";
import { MutedFindingsConfigButton } from "@/components/providers";
@@ -32,9 +32,7 @@ export default async function Scans({
const filteredParams = { ...resolvedSearchParams };
delete filteredParams.scanId;
const providersData = await getProviders({
pageSize: 50,
});
const providersData = await getAllProviders();
const providerInfo =
providersData?.data