diff --git a/ui/actions/findings/findings.ts b/ui/actions/findings/findings.ts
index 98aee3456b..3b035f84ab 100644
--- a/ui/actions/findings/findings.ts
+++ b/ui/actions/findings/findings.ts
@@ -45,6 +45,7 @@ export const getFindings = async ({
revalidatePath("/findings");
return parsedData;
} catch (error) {
+ // eslint-disable-next-line no-console
console.error("Error fetching findings:", error);
return undefined;
}
diff --git a/ui/app/(prowler)/findings/page.tsx b/ui/app/(prowler)/findings/page.tsx
index dc1161f531..52801e7259 100644
--- a/ui/app/(prowler)/findings/page.tsx
+++ b/ui/app/(prowler)/findings/page.tsx
@@ -13,7 +13,12 @@ import {
import { Header } from "@/components/ui";
import { DataTable, DataTableFilterCustom } from "@/components/ui/table";
import { createDict } from "@/lib";
-import { FindingProps, SearchParamsProps } from "@/types/components";
+import {
+ FindingProps,
+ ProviderProps,
+ ScanProps,
+ SearchParamsProps,
+} from "@/types/components";
export default async function Findings({
searchParams,
@@ -56,24 +61,28 @@ export default async function Findings({
const scansData = await getScans({});
// Extract provider UIDs
- const providerUIDs = providersData?.data
- ?.map((provider: any) => provider.attributes.uid)
- .filter(Boolean);
+ const providerUIDs = Array.from(
+ new Set(
+ providersData?.data
+ ?.map((provider: ProviderProps) => provider.attributes.uid)
+ .filter(Boolean),
+ ),
+ );
// Extract scan UUIDs with "completed" state and more than one resource
const completedScans = scansData?.data
?.filter(
(scan: any) =>
scan.attributes.state === "completed" &&
- scan.attributes.unique_resource_count > 1 &&
- scan.attributes.name, // Ensure it has a name
+ scan.attributes.unique_resource_count > 1,
)
- .map((scan: any) => ({
+ .map((scan: ScanProps) => ({
id: scan.id,
name: scan.attributes.name,
}));
- const completedScanIds = completedScans?.map((scan: any) => scan.id) || [];
+ const completedScanIds =
+ completedScans?.map((scan: ScanProps) => scan.id) || [];
return (
<>
@@ -97,12 +106,12 @@ export default async function Findings({
},
{
key: "provider_uid__in",
- labelCheckboxGroup: "Account",
+ labelCheckboxGroup: "Provider UID",
values: providerUIDs,
},
{
key: "scan__in",
- labelCheckboxGroup: "Scans",
+ labelCheckboxGroup: "Scan ID",
values: completedScanIds,
},
]}
diff --git a/ui/app/(prowler)/page.tsx b/ui/app/(prowler)/page.tsx
index 730b4e3499..ff2ab3d28c 100644
--- a/ui/app/(prowler)/page.tsx
+++ b/ui/app/(prowler)/page.tsx
@@ -56,6 +56,7 @@ export default function Home({
+
}
diff --git a/ui/app/(prowler)/scans/page.tsx b/ui/app/(prowler)/scans/page.tsx
index f8e7b8e067..8af2caf594 100644
--- a/ui/app/(prowler)/scans/page.tsx
+++ b/ui/app/(prowler)/scans/page.tsx
@@ -1,10 +1,14 @@
import { Spacer } from "@nextui-org/react";
import { Suspense } from "react";
-import { getProviders } from "@/actions/providers";
+import { getProvider, getProviders } from "@/actions/providers";
import { getScans } from "@/actions/scans";
-import { FilterControls, filterScans } from "@/components/filters";
-import { ButtonRefreshData } from "@/components/scans";
+import { filterScans } from "@/components/filters";
+import {
+ ButtonRefreshData,
+ NoProvidersAdded,
+ NoProvidersConnected,
+} from "@/components/scans";
import { LaunchScanWorkflow } from "@/components/scans/launch-workflow";
import { SkeletonTableScans } from "@/components/scans/table";
import { ColumnGetScans } from "@/components/scans/table/scans";
@@ -21,48 +25,72 @@ export default async function Scans({
delete filteredParams.scanId;
const searchParamsKey = JSON.stringify(filteredParams);
- const providersData = await getProviders({});
+ const providersData = await getProviders({
+ filters: {
+ "filter[connected]": true,
+ },
+ });
- const providerInfo = providersData?.data?.length
- ? providersData.data.map((provider: ProviderProps) => ({
- providerId: provider.id,
- alias: provider.attributes.alias,
- providerType: provider.attributes.provider,
- uid: provider.attributes.uid,
- connected: provider.attributes.connection.connected,
- }))
- : [];
+ const providerInfo = providersData.data.map((provider: ProviderProps) => ({
+ providerId: provider.id,
+ alias: provider.attributes.alias,
+ providerType: provider.attributes.provider,
+ uid: provider.attributes.uid,
+ connected: provider.attributes.connection.connected,
+ }));
- // const executingScans = await getExecutingScans();
+ const providersCountConnected = await getProviders({});
+ const thereIsNoProviders =
+ !providersCountConnected?.data || providersCountConnected.data.length === 0;
+
+ const thereIsNoProvidersConnected = providersCountConnected?.data?.every(
+ (provider: ProviderProps) => !provider.attributes.connection.connected,
+ );
return (
<>
-
-
-
-
-
-
-
- {
- "use server";
- await getScans({});
- }}
- />
-
+ {thereIsNoProviders && (
+ <>
+
+
+ >
+ )}
-
-
-
+ {!thereIsNoProviders && (
+ <>
+ {thereIsNoProvidersConnected ? (
+ <>
+
+
+ >
+ ) : (
+ <>
+
+
+ >
+ )}
+
+
+
+
+
+ {
+ "use server";
+ await getScans({});
+ }}
+ />
+
+
+
}>
+
+
+
+
+ >
+ )}
>
);
}
@@ -85,22 +113,40 @@ const SSRDataTableScans = async ({
// Extract query from filters
const query = (filters["filter[search]"] as string) || "";
+ // Fetch scans data
const scansData = await getScans({ query, page, sort, filters });
+ // Handle expanded scans data
+ const expandedScansData = await Promise.all(
+ scansData?.data?.map(async (scan: any) => {
+ const providerId = scan.relationships?.provider?.data?.id;
+
+ if (!providerId) {
+ return { ...scan, providerInfo: null };
+ }
+
+ const formData = new FormData();
+ formData.append("id", providerId);
+
+ const providerData = await getProvider(formData);
+
+ if (providerData?.data) {
+ const { provider, uid, alias } = providerData.data.attributes;
+ return {
+ ...scan,
+ providerInfo: { provider, uid, alias },
+ };
+ }
+
+ return { ...scan, providerInfo: null };
+ }) || [],
+ );
+
return (
);
};
-
-// const getExecutingScans = async () => {
-// const scansData = await getScans({});
-
-// return scansData?.data?.some(
-// (scan: ScanProps) =>
-// scan.attributes.state === "executing" && scan.attributes.progress < 100,
-// );
-// };
diff --git a/ui/components/filters/data-filters.ts b/ui/components/filters/data-filters.ts
index 938972fc38..9400dc427b 100644
--- a/ui/components/filters/data-filters.ts
+++ b/ui/components/filters/data-filters.ts
@@ -8,11 +8,11 @@ export const filterProviders = [
];
export const filterScans = [
- // {
- // key: "provider_type__in",
- // labelCheckboxGroup: "Provider",
- // values: ["aws", "azure", "gcp", "kubernetes"],
- // },
+ {
+ key: "provider_type__in",
+ labelCheckboxGroup: "Cloud Provider",
+ values: ["aws", "azure", "gcp", "kubernetes"],
+ },
{
key: "state",
labelCheckboxGroup: "State",
@@ -51,7 +51,7 @@ export const filterFindings = [
},
{
key: "provider_type__in",
- labelCheckboxGroup: "Provider",
+ labelCheckboxGroup: "Cloud Provider",
values: ["aws", "azure", "gcp", "kubernetes"],
},
// Add more filter categories as needed
diff --git a/ui/components/findings/table/column-findings.tsx b/ui/components/findings/table/column-findings.tsx
index 5ee758027e..e43cb6ae3e 100644
--- a/ui/components/findings/table/column-findings.tsx
+++ b/ui/components/findings/table/column-findings.tsx
@@ -5,7 +5,7 @@ import { useSearchParams } from "next/navigation";
import { DataTableRowDetails } from "@/components/findings/table";
import { InfoIcon } from "@/components/icons";
-import { DateWithTime } from "@/components/ui/entities";
+import { DateWithTime, EntityInfoShort } from "@/components/ui/entities";
import { TriggerSheet } from "@/components/ui/sheet";
import {
DataTableColumnHeader,
@@ -181,16 +181,20 @@ export const ColumnFindings: ColumnDef
[] = [
},
},
{
- accessorKey: "account",
- header: "Account",
+ accessorKey: "cloudProvider",
+ header: "Cloud provider",
cell: ({ row }) => {
- const account = getProviderData(row, "uid");
+ const provider = getProviderData(row, "provider");
+ const alias = getProviderData(row, "alias");
+ const uid = getProviderData(row, "uid");
return (
<>
-
- {typeof account === "string" ? account : "Invalid account"}
-
+
>
);
},
diff --git a/ui/components/overview/findings-by-severity-chart/findings-by-severity-chart.tsx b/ui/components/overview/findings-by-severity-chart/findings-by-severity-chart.tsx
index 7e590fb0d1..66c4b6d081 100644
--- a/ui/components/overview/findings-by-severity-chart/findings-by-severity-chart.tsx
+++ b/ui/components/overview/findings-by-severity-chart/findings-by-severity-chart.tsx
@@ -56,7 +56,7 @@ export const FindingsBySeverityChart = ({
}));
return (
-
+
diff --git a/ui/components/overview/findings-by-status-chart/findings-by-status-chart.tsx b/ui/components/overview/findings-by-status-chart/findings-by-status-chart.tsx
index 3bf7d162c1..571cb37420 100644
--- a/ui/components/overview/findings-by-status-chart/findings-by-status-chart.tsx
+++ b/ui/components/overview/findings-by-status-chart/findings-by-status-chart.tsx
@@ -91,7 +91,7 @@ export const FindingsByStatusChart: React.FC = ({
];
return (
-
+
[] = [
},
},
{
- accessorKey: "account",
- header: "Account",
+ accessorKey: "cloudProvider",
+ header: "Cloud provider",
cell: ({ row }) => {
- const account = getProviderData(row, "uid");
+ const provider = getProviderData(row, "provider");
+ const alias = getProviderData(row, "alias");
+ const uid = getProviderData(row, "uid");
return (
<>
-
- {typeof account === "string" ? account : "Invalid account"}
-
+
>
);
},
diff --git a/ui/components/overview/provider-overview/provider-overview.tsx b/ui/components/overview/provider-overview/provider-overview.tsx
index a64d42c48b..48333c5fbc 100644
--- a/ui/components/overview/provider-overview/provider-overview.tsx
+++ b/ui/components/overview/provider-overview/provider-overview.tsx
@@ -44,9 +44,9 @@ export const ProvidersOverview = ({
if (!providersOverview || !Array.isArray(providersOverview.data)) {
return (
-
+
-
+
Provider
@@ -92,9 +92,9 @@ export const ProvidersOverview = ({
}
return (
-
+
-
+
Provider
@@ -175,7 +175,7 @@ export const ProvidersOverview = ({
({
({
startContent={}
onClick={() => setIsEditOpen(true)}
>
- Edit Provider
+ Edit Provider Alias
diff --git a/ui/components/scans/index.ts b/ui/components/scans/index.ts
index ede26bb35e..aa42edfe3c 100644
--- a/ui/components/scans/index.ts
+++ b/ui/components/scans/index.ts
@@ -1,2 +1,4 @@
export * from "./button-refresh-data";
export * from "./link-to-findings-from-scan";
+export * from "./no-providers-added";
+export * from "./no-providers-connected";
diff --git a/ui/components/scans/launch-workflow/launch-scan-workflow-form.tsx b/ui/components/scans/launch-workflow/launch-scan-workflow-form.tsx
index a19acfea42..20088cad93 100644
--- a/ui/components/scans/launch-workflow/launch-scan-workflow-form.tsx
+++ b/ui/components/scans/launch-workflow/launch-scan-workflow-form.tsx
@@ -5,7 +5,7 @@ import { useForm } from "react-hook-form";
import * as z from "zod";
import { scanOnDemand } from "@/actions/scans";
-import { RocketIcon, ScheduleIcon } from "@/components/icons";
+import { RocketIcon } from "@/components/icons";
import { CustomButton, CustomInput } from "@/components/ui/custom";
import { Form } from "@/components/ui/form";
import { toast } from "@/components/ui/toast";
@@ -79,26 +79,26 @@ export const LaunchScanWorkflow = ({
onSubmit={form.handleSubmit(onSubmitClient)}
className="flex flex-col space-y-4"
>
-
-
-
-
-
- {form.watch("providerId") && (
+
+
+
+ {form.watch("providerId") && (
+ <>
- )}
-
-
-
+
+
+ }
+ >
+ {isLoading ? <>Loading> : Start now}
+
+ form.reset()}
+ className="w-fit border-gray-200 bg-transparent"
+ ariaLabel="Clear form"
+ variant="bordered"
+ size="md"
+ radius="lg"
+ >
+ Cancel
+
+
+
+ >
+ )}
+
+ {/*
{form.watch("providerId") && (
@@ -139,54 +170,7 @@ export const LaunchScanWorkflow = ({
)}
-
-
-
- {form.watch("providerId") && (
-
- form.reset()}
- className="w-fit border-gray-200 bg-transparent"
- ariaLabel="Clear form"
- variant="bordered"
- size="lg"
- radius="lg"
- >
- Cancel
-
- }
- isDisabled={true}
- >
- {isLoading ? <>Loading> : Schedule}
-
-
- }
- >
- {isLoading ? <>Loading> : Start now}
-
-
- )}
-
+
*/}
diff --git a/ui/components/scans/launch-workflow/select-scan-provider.tsx b/ui/components/scans/launch-workflow/select-scan-provider.tsx
index c1805f488b..781656b59b 100644
--- a/ui/components/scans/launch-workflow/select-scan-provider.tsx
+++ b/ui/components/scans/launch-workflow/select-scan-provider.tsx
@@ -55,8 +55,8 @@ export const SelectScanProvider = <
<>