mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-11-02 01:15:31 +00:00
feat: filters relationships in findings and scans page (#8046)
Co-authored-by: Pablo Lara <larabjj@gmail.com>
This commit is contained in:
1 parent
b3f2a1c532
commit
6b7b700a98
22 files changed
+576
-265
No files matched your search
@@ -9,14 +9,13 @@ import {
|
||||
} from "@/actions/findings";
|
||||
import { getProviders } from "@/actions/providers";
|
||||
import { getScans } from "@/actions/scans";
|
||||
import { filterFindings } from "@/components/filters/data-filters";
|
||||
import { FilterControls } from "@/components/filters/filter-controls";
|
||||
import { FindingsFilters } from "@/components/findings/findings-filters";
|
||||
import {
|
||||
ColumnFindings,
|
||||
SkeletonTableFindings,
|
||||
} from "@/components/findings/table";
|
||||
import { ContentLayout } from "@/components/ui";
|
||||
import { DataTable, DataTableFilterCustom } from "@/components/ui/table";
|
||||
import { DataTable } from "@/components/ui/table";
|
||||
import {
|
||||
createDict,
|
||||
createScanDetailsMapping,
|
||||
@@ -28,7 +27,7 @@ import {
|
||||
createProviderDetailsMapping,
|
||||
extractProviderUIDs,
|
||||
} from "@/lib/provider-helpers";
|
||||
import { ScanProps } from "@/types";
|
||||
import { FilterEntity, ScanEntity, ScanProps } from "@/types";
|
||||
import { FindingProps, SearchParamsProps } from "@/types/components";
|
||||
|
||||
export default async function Findings({
|
||||
@@ -61,21 +60,11 @@ export default async function Findings({
|
||||
// Extract provider UIDs and details using helper functions
|
||||
const providerUIDs = providersData ? extractProviderUIDs(providersData) : [];
|
||||
const providerDetails = providersData
|
||||
? createProviderDetailsMapping(providerUIDs, providersData)
|
||||
? (createProviderDetailsMapping(providerUIDs, providersData) as {
|
||||
[uid: string]: FilterEntity;
|
||||
}[])
|
||||
: [];
|
||||
|
||||
// Update the Provider UID filter
|
||||
const updatedFilters = filterFindings.map((filter) => {
|
||||
if (filter.key === "provider_uid__in") {
|
||||
return {
|
||||
...filter,
|
||||
values: providerUIDs,
|
||||
valueLabelMapping: providerDetails,
|
||||
};
|
||||
}
|
||||
return filter;
|
||||
});
|
||||
|
||||
// Extract scan UUIDs with "completed" state and more than one resource
|
||||
const completedScans = scansData?.data?.filter(
|
||||
(scan: ScanProps) =>
|
||||
@@ -86,45 +75,24 @@ export default async function Findings({
|
||||
const completedScanIds =
|
||||
completedScans?.map((scan: ScanProps) => scan.id) || [];
|
||||
|
||||
const scanDetails = createScanDetailsMapping(completedScans, providersData);
|
||||
const scanDetails = createScanDetailsMapping(
|
||||
completedScans,
|
||||
providersData,
|
||||
) as { [uid: string]: ScanEntity }[];
|
||||
|
||||
return (
|
||||
<ContentLayout title="Findings" icon="carbon:data-view-alt">
|
||||
<FilterControls search date />
|
||||
<Spacer y={8} />
|
||||
<DataTableFilterCustom
|
||||
filters={[
|
||||
...updatedFilters,
|
||||
{
|
||||
key: "region__in",
|
||||
labelCheckboxGroup: "Regions",
|
||||
values: uniqueRegions,
|
||||
index: 5,
|
||||
},
|
||||
{
|
||||
key: "service__in",
|
||||
labelCheckboxGroup: "Services",
|
||||
values: uniqueServices,
|
||||
index: 6,
|
||||
},
|
||||
{
|
||||
key: "resource_type__in",
|
||||
labelCheckboxGroup: "Resource Type",
|
||||
values: uniqueResourceTypes,
|
||||
index: 7,
|
||||
},
|
||||
{
|
||||
key: "scan__in",
|
||||
labelCheckboxGroup: "Scan ID",
|
||||
values: completedScanIds,
|
||||
valueLabelMapping: scanDetails,
|
||||
index: 9,
|
||||
},
|
||||
]}
|
||||
defaultOpen={true}
|
||||
<FindingsFilters
|
||||
providerUIDs={providerUIDs}
|
||||
providerDetails={providerDetails}
|
||||
completedScans={completedScans || []}
|
||||
completedScanIds={completedScanIds}
|
||||
scanDetails={scanDetails}
|
||||
uniqueRegions={uniqueRegions}
|
||||
uniqueServices={uniqueServices}
|
||||
uniqueResourceTypes={uniqueResourceTypes}
|
||||
/>
|
||||
<Spacer y={8} />
|
||||
|
||||
<Suspense key={searchParamsKey} fallback={<SkeletonTableFindings />}>
|
||||
<SSRDataTable searchParams={searchParams} />
|
||||
</Suspense>
|
||||
|
||||
+25
-27
@@ -33,37 +33,35 @@ export default function Home({
|
||||
const searchParamsKey = JSON.stringify(searchParams || {});
|
||||
return (
|
||||
<ContentLayout title="Overview" icon="solar:pie-chart-2-outline">
|
||||
<Spacer y={4} />
|
||||
<FilterControls providers />
|
||||
<div className="mx-auto space-y-8 px-0 py-6">
|
||||
<div className="grid grid-cols-12 gap-6">
|
||||
<div className="col-span-12 lg:col-span-4">
|
||||
<Suspense fallback={<SkeletonProvidersOverview />}>
|
||||
<SSRProvidersOverview />
|
||||
</Suspense>
|
||||
</div>
|
||||
|
||||
<div className="col-span-12 lg:col-span-4">
|
||||
<Suspense fallback={<SkeletonFindingsBySeverityChart />}>
|
||||
<SSRFindingsBySeverity searchParams={searchParams} />
|
||||
</Suspense>
|
||||
</div>
|
||||
<div className="grid grid-cols-12 gap-12 lg:gap-6">
|
||||
<div className="col-span-12 lg:col-span-4">
|
||||
<Suspense fallback={<SkeletonProvidersOverview />}>
|
||||
<SSRProvidersOverview />
|
||||
</Suspense>
|
||||
</div>
|
||||
|
||||
<div className="col-span-12 lg:col-span-4">
|
||||
<Suspense fallback={<SkeletonFindingsByStatusChart />}>
|
||||
<SSRFindingsByStatus searchParams={searchParams} />
|
||||
</Suspense>
|
||||
</div>
|
||||
<div className="col-span-12 lg:col-span-4">
|
||||
<Suspense fallback={<SkeletonFindingsBySeverityChart />}>
|
||||
<SSRFindingsBySeverity searchParams={searchParams} />
|
||||
</Suspense>
|
||||
</div>
|
||||
|
||||
<div className="col-span-12">
|
||||
<Spacer y={16} />
|
||||
<Suspense
|
||||
key={searchParamsKey}
|
||||
fallback={<SkeletonTableNewFindings />}
|
||||
>
|
||||
<SSRDataNewFindingsTable />
|
||||
</Suspense>
|
||||
</div>
|
||||
<div className="col-span-12 lg:col-span-4">
|
||||
<Suspense fallback={<SkeletonFindingsByStatusChart />}>
|
||||
<SSRFindingsByStatus searchParams={searchParams} />
|
||||
</Suspense>
|
||||
</div>
|
||||
|
||||
<div className="col-span-12">
|
||||
<Spacer y={16} />
|
||||
<Suspense
|
||||
key={searchParamsKey}
|
||||
fallback={<SkeletonTableNewFindings />}
|
||||
>
|
||||
<SSRDataNewFindingsTable />
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
</ContentLayout>
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
SkeletonTableProviders,
|
||||
} from "@/components/providers/table";
|
||||
import { ContentLayout } from "@/components/ui";
|
||||
import { DataTable, DataTableFilterCustom } from "@/components/ui/table";
|
||||
import { DataTable } from "@/components/ui/table";
|
||||
import { ProviderProps, SearchParamsProps } from "@/types";
|
||||
|
||||
export default async function Providers({
|
||||
@@ -22,14 +22,12 @@ export default async function Providers({
|
||||
|
||||
return (
|
||||
<ContentLayout title="Cloud Providers" icon="fluent:cloud-sync-24-regular">
|
||||
<FilterControls search />
|
||||
<FilterControls search customFilters={filterProviders || []} />
|
||||
<Spacer y={8} />
|
||||
<div className="flex items-center gap-4 md:justify-end">
|
||||
<ManageGroupsButton />
|
||||
<AddProviderButton />
|
||||
</div>
|
||||
<Spacer y={4} />
|
||||
<DataTableFilterCustom filters={filterProviders || []} />
|
||||
<Spacer y={8} />
|
||||
|
||||
<div className="grid grid-cols-12 gap-4">
|
||||
|
||||
@@ -3,17 +3,17 @@ import { Suspense } from "react";
|
||||
|
||||
import { getProvider, getProviders } from "@/actions/providers";
|
||||
import { getScans, getScansByState } from "@/actions/scans";
|
||||
import { FilterControls, filterScans } from "@/components/filters";
|
||||
import {
|
||||
AutoRefresh,
|
||||
NoProvidersAdded,
|
||||
NoProvidersConnected,
|
||||
ScansFilters,
|
||||
} from "@/components/scans";
|
||||
import { LaunchScanWorkflow } from "@/components/scans/launch-workflow";
|
||||
import { SkeletonTableScans } from "@/components/scans/table";
|
||||
import { ColumnGetScans } from "@/components/scans/table/scans";
|
||||
import { ContentLayout } from "@/components/ui";
|
||||
import { DataTable, DataTableFilterCustom } from "@/components/ui/table";
|
||||
import { DataTable } from "@/components/ui/table";
|
||||
import {
|
||||
createProviderDetailsMapping,
|
||||
extractProviderUIDs,
|
||||
@@ -49,8 +49,7 @@ export default async function Scans({
|
||||
filters: { "filter[connected]": true },
|
||||
pageSize: 50,
|
||||
});
|
||||
const thereIsNoProviders =
|
||||
!providersCountConnected?.data || providersCountConnected.data.length === 0;
|
||||
const thereIsNoProviders = !providersCountConnected?.data;
|
||||
|
||||
const thereIsNoProvidersConnected = providersCountConnected?.data?.every(
|
||||
(provider: ProviderProps) => !provider.attributes.connection.connected,
|
||||
@@ -71,59 +70,37 @@ export default async function Scans({
|
||||
? createProviderDetailsMapping(providerUIDs, providersData)
|
||||
: [];
|
||||
|
||||
// Update the Provider UID filter
|
||||
const updatedFilters = filterScans.map((filter) => {
|
||||
if (filter.key === "provider_uid__in") {
|
||||
return {
|
||||
...filter,
|
||||
values: providerUIDs,
|
||||
valueLabelMapping: providerDetails,
|
||||
};
|
||||
}
|
||||
return filter;
|
||||
});
|
||||
if (thereIsNoProviders) {
|
||||
return (
|
||||
<ContentLayout title="Scans" icon="lucide:scan-search">
|
||||
<NoProvidersAdded />
|
||||
</ContentLayout>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{thereIsNoProviders && (
|
||||
<>
|
||||
<Spacer y={4} />
|
||||
<NoProvidersAdded />
|
||||
</>
|
||||
)}
|
||||
|
||||
{!thereIsNoProviders && (
|
||||
<>
|
||||
{thereIsNoProvidersConnected ? (
|
||||
<ContentLayout title="Scans" icon="lucide:scan-search">
|
||||
<Spacer y={8} />
|
||||
<NoProvidersConnected />
|
||||
<Spacer y={8} />
|
||||
</ContentLayout>
|
||||
) : (
|
||||
<ContentLayout title="Scans" icon="lucide:scan-search">
|
||||
<AutoRefresh hasExecutingScan={hasExecutingScan} />
|
||||
<LaunchScanWorkflow providers={providerInfo} />
|
||||
<Spacer y={8} />
|
||||
</ContentLayout>
|
||||
)}
|
||||
|
||||
<div className="grid grid-cols-12 items-start gap-4 px-6 py-4 sm:px-8 xl:px-10">
|
||||
<div className="col-span-12">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<DataTableFilterCustom filters={updatedFilters || []} />
|
||||
<Spacer x={4} />
|
||||
<FilterControls />
|
||||
</div>
|
||||
<Spacer y={8} />
|
||||
<Suspense key={searchParamsKey} fallback={<SkeletonTableScans />}>
|
||||
<SSRDataTableScans searchParams={searchParams} />
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
<ContentLayout title="Scans" icon="lucide:scan-search">
|
||||
<AutoRefresh hasExecutingScan={hasExecutingScan} />
|
||||
<>
|
||||
{thereIsNoProvidersConnected ? (
|
||||
<>
|
||||
<Spacer y={8} />
|
||||
<NoProvidersConnected />
|
||||
<Spacer y={8} />
|
||||
</>
|
||||
) : (
|
||||
<LaunchScanWorkflow providers={providerInfo} />
|
||||
)}
|
||||
<ScansFilters
|
||||
providerUIDs={providerUIDs}
|
||||
providerDetails={providerDetails}
|
||||
/>
|
||||
<Spacer y={8} />
|
||||
<Suspense key={searchParamsKey} fallback={<SkeletonTableScans />}>
|
||||
<SSRDataTableScans searchParams={searchParams} />
|
||||
</Suspense>
|
||||
</>
|
||||
</ContentLayout>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user