fix(ui): Improved the findings page scan Id filter

This commit is contained in:
sumit_chaturvedi
2025-05-23 13:17:26 +05:30
parent 36aaec8a55
commit ff995e7750
7 changed files with 101 additions and 36 deletions
+2
View File
@@ -16,6 +16,7 @@ export const getScans = async ({
sort = "",
filters = {},
pageSize = 10,
include = "",
}) => {
const headers = await getAuthHeaders({ contentType: false });
@@ -27,6 +28,7 @@ export const getScans = async ({
if (pageSize) url.searchParams.append("page[size]", pageSize.toString());
if (query) url.searchParams.append("filter[search]", query);
if (sort) url.searchParams.append("sort", sort);
if (include) url.searchParams.append("include", include);
// Handle multiple filters
Object.entries(filters).forEach(([key, value]) => {
+53 -12
View File
@@ -23,8 +23,13 @@ import {
extractSortAndKey,
hasDateOrScanFilter,
} from "@/lib";
import { ProviderAccountProps, ProviderProps } from "@/types";
import { FindingProps, ScanProps, SearchParamsProps } from "@/types/components";
import { ProviderProps } from "@/types";
import {
FindingProps,
IncludeProps,
ScanProps,
SearchParamsProps,
} from "@/types/components";
export default async function Findings({
searchParams,
@@ -44,7 +49,9 @@ export default async function Findings({
filters,
}),
getProviders({ pageSize: 50 }),
getScans({}),
getScans({
include: "provider",
}),
]);
// Extract unique regions and services from the new endpoint
@@ -62,20 +69,21 @@ export default async function Findings({
),
);
const providerDetails: Array<{ [uid: string]: ProviderAccountProps }> =
providerUIDs.map((uid) => {
const provider = providersData.data.find(
(p: { attributes: { uid: string } }) => p.attributes?.uid === uid,
);
const providerDetails = providerUIDs.map((uid) => {
const provider = providersData.data.find(
(p: { attributes: { uid: string } }) => p.attributes?.uid === uid,
);
return {
[uid]: {
return {
[uid]: {
providerInfo: {
provider: provider?.attributes?.provider || "",
uid: uid,
alias: provider?.attributes?.alias ?? null,
},
};
});
},
};
});
// Extract scan UUIDs with "completed" state and more than one resource
const completedScans = scansData?.data
@@ -87,11 +95,43 @@ export default async function Findings({
.map((scan: ScanProps) => ({
id: scan.id,
name: scan.attributes.name,
providerId: scan.relationships.provider.data.id,
completed_at: scan.attributes.completed_at,
}));
const completedScanIds =
completedScans?.map((scan: ScanProps) => scan.id) || [];
const providerDetailsAssociatedWithScans = completedScans?.map(
(scan: {
id: string;
name: string;
providerId: string;
completed_at: string;
}) => {
const providerId = scan.providerId;
const providerDetails = scansData.included.find(
(provider: IncludeProps) =>
provider.type === "providers" && provider.id === providerId,
);
return {
[scan.id]: {
providerInfo: {
provider: providerDetails?.attributes?.provider,
alias: providerDetails?.attributes?.alias,
uid: providerDetails?.attributes?.uid,
},
attributes: {
name: scan.name,
completed_at: scan.completed_at,
},
},
};
},
);
return (
<ContentLayout title="Findings" icon="carbon:data-view-alt">
<FilterControls search date />
@@ -124,6 +164,7 @@ export default async function Findings({
key: "scan__in",
labelCheckboxGroup: "Scan ID",
values: completedScanIds,
valueLabelMapping: providerDetailsAssociatedWithScans,
},
]}
defaultOpen={true}
@@ -10,7 +10,7 @@ interface ComplianceScanInfoProps {
alias?: string;
uid?: string;
};
attributes: {
attributes?: {
name?: string;
completed_at: string;
};
@@ -28,13 +28,17 @@ export const ComplianceScanInfo: React.FC<ComplianceScanInfoProps> = ({
entityId={scan.providerInfo.uid}
hideCopyButton
/>
<Divider orientation="vertical" className="mx-2 h-6" />
<div className="flex flex-col items-start">
<p className="text-xs text-default-500">
{scan.attributes.name || "- -"}
</p>
<DateWithTime inline dateTime={scan.attributes.completed_at} />
</div>
{scan.attributes && (
<>
<Divider orientation="vertical" className="mx-2 h-6" />
<div className="flex flex-col items-start">
<p className="text-xs text-default-500">
{scan.attributes.name || "- -"}
</p>
<DateWithTime inline dateTime={scan.attributes.completed_at} />
</div>
</>
)}
</div>
);
};
@@ -14,12 +14,11 @@ import { XCircle } from "lucide-react";
import { useSearchParams } from "next/navigation";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { ComplianceScanInfo } from "@/components/compliance";
import { PlusCircleIcon } from "@/components/icons";
import { useUrlFilters } from "@/hooks/use-url-filters";
import { CustomDropdownFilterProps } from "@/types";
import { EntityInfoShort } from "../entities";
const filterSelectedClass =
"inline-flex items-center border py-1 text-xs transition-colors border-transparent bg-default-500 text-secondary-foreground hover:bg-default-500/80 rounded-md px-2 font-normal";
@@ -169,7 +168,7 @@ export const CustomDropdownFilter: React.FC<CustomDropdownFilterProps> = ({
)}
</Button>
</PopoverTrigger>
<PopoverContent className="w-80 dark:bg-prowler-blue-800">
<PopoverContent className="min-w-[20rem] dark:bg-prowler-blue-800">
<div className="flex w-full flex-col gap-6 p-2">
<CheckboxGroup
color="default"
@@ -192,14 +191,14 @@ export const CustomDropdownFilter: React.FC<CustomDropdownFilterProps> = ({
<Divider orientation="horizontal" className="mt-2" />
<ScrollShadow
hideScrollBar
className="flex max-h-96 max-w-56 flex-col gap-y-2 py-2"
className="flex max-h-96 max-w-full flex-col gap-y-2 py-2"
>
{memoizedFilterValues.map((value) => {
// Find the corresponding entity from valueLabelMapping
const matchingEntry = filter.valueLabelMapping?.find(
(entry) => entry[value],
);
const entity = matchingEntry?.[value];
const scanData = matchingEntry?.[value];
return (
<Checkbox
@@ -210,13 +209,8 @@ export const CustomDropdownFilter: React.FC<CustomDropdownFilterProps> = ({
key={value}
value={value}
>
{entity ? (
<EntityInfoShort
cloudProvider={entity.provider}
entityAlias={entity.alias}
entityId={entity.uid}
hideCopyButton
/>
{scanData ? (
<ComplianceScanInfo scan={scanData} />
) : (
value
)}
@@ -20,7 +20,7 @@ export const EntityInfoShort: React.FC<EntityInfoProps> = ({
hideCopyButton = false,
}) => {
return (
<div className="flex w-full items-center justify-between space-x-2">
<div className="flex w-fit items-center justify-between">
<div className="flex items-center gap-x-2">
<div className="flex-shrink-0">{getProviderLogo(cloudProvider)}</div>
<div className="flex flex-col">
+13 -1
View File
@@ -1,7 +1,7 @@
import { LucideIcon } from "lucide-react";
import { SVGProps } from "react";
import { ProviderType } from "./providers";
import { ProviderAccountProps, ProviderType } from "./providers";
export type IconSvgProps = SVGProps<SVGSVGElement> & {
size?: number;
@@ -704,3 +704,15 @@ export interface UserProps {
dateAdded: string;
status: "active" | "inactive";
}
export interface Connection {
connected: string;
last_checked_at: string;
}
export interface IncludeProps {
type: string;
id: string;
attributes: ProviderAccountProps;
connection: Connection;
}
+14 -2
View File
@@ -1,10 +1,22 @@
import { ProviderAccountProps } from "./providers";
import { ProviderType } from "./providers";
export interface FilterOption {
key: string;
labelCheckboxGroup: string;
values: string[];
valueLabelMapping?: Array<{ [uid: string]: ProviderAccountProps }>;
valueLabelMapping?: Array<{
[uid: string]: {
providerInfo: {
provider: ProviderType;
alias?: string;
uid?: string;
};
attributes: {
name?: string;
completed_at: string;
};
};
}>;
}
export interface CustomDropdownFilterProps {