diff --git a/ui/actions/scans/scans.ts b/ui/actions/scans/scans.ts index 52da71bb3b..cb4f4b9c0e 100644 --- a/ui/actions/scans/scans.ts +++ b/ui/actions/scans/scans.ts @@ -165,6 +165,72 @@ export const scheduleDaily = async (formData: FormData) => { } }; +export const launchOrganizationScans = async ( + providerIds: string[], + scheduleOption: "daily" | "single", +) => { + const validProviderIds = providerIds.filter(Boolean); + if (validProviderIds.length === 0) { + return { + successCount: 0, + failureCount: 0, + totalCount: 0, + }; + } + + const launchPromises = validProviderIds.map(async (providerId) => { + const formData = new FormData(); + formData.set("providerId", providerId); + + const result = + scheduleOption === "daily" + ? await scheduleDaily(formData) + : await scanOnDemand(formData); + + return { + providerId, + ok: !result?.error, + error: result?.error ? String(result.error) : null, + }; + }); + + const settled = await Promise.allSettled(launchPromises); + const summary = settled.reduce( + (acc, item) => { + if (item.status === "fulfilled") { + if (item.value.ok) { + acc.successCount += 1; + } else { + acc.failureCount += 1; + acc.errors.push({ + providerId: item.value.providerId, + error: item.value.error || "Failed to launch scan.", + }); + } + return acc; + } + + acc.failureCount += 1; + acc.errors.push({ + providerId: "", + error: + item.reason instanceof Error + ? item.reason.message + : String(item.reason), + }); + return acc; + }, + { + successCount: 0, + failureCount: 0, + totalCount: validProviderIds.length, + errors: [] as Array<{ providerId: string; error: string }>, + }, + ); + + return summary; +}; + export const updateScan = async (formData: FormData) => { const headers = await getAuthHeaders({ contentType: true }); diff --git a/ui/components/providers/organizations/org-launch-scan.tsx b/ui/components/providers/organizations/org-launch-scan.tsx index 42528e23a8..b0c81cf325 100644 --- a/ui/components/providers/organizations/org-launch-scan.tsx +++ b/ui/components/providers/organizations/org-launch-scan.tsx @@ -3,7 +3,7 @@ import { useRouter } from "next/navigation"; import { useEffect, useRef, useState } from "react"; -import { scanOnDemand, scheduleDaily } from "@/actions/scans/scans"; +import { launchOrganizationScans } from "@/actions/scans/scans"; import { AWSProviderBadge } from "@/components/icons/providers-badge"; import { WIZARD_FOOTER_ACTION_TYPE, @@ -54,20 +54,11 @@ export function OrgLaunchScan({ const handleLaunchScan = async () => { setIsLaunching(true); - let successCount = 0; - - for (const providerId of createdProviderIds) { - const formData = new FormData(); - formData.set("providerId", providerId); - - const result = - scheduleOption === SCAN_SCHEDULE.DAILY - ? await scheduleDaily(formData) - : await scanOnDemand(formData); - if (!result?.error) { - successCount++; - } - } + const result = await launchOrganizationScans( + createdProviderIds, + scheduleOption, + ); + const successCount = result.successCount; setIsLaunching(false); reset();