Finding detail card

Finding detail card
This commit is contained in:
Pedro De Castro
2024-11-08 12:50:24 +01:00
committed by GitHub
5 changed files with 93 additions and 162 deletions
@@ -142,10 +142,10 @@ export const ColumnFindings: ColumnDef<FindingProps>[] = [
return (
<TriggerSheet
triggerComponent={<PlusIcon />}
title="Scan Details"
description="View the scan details"
title="Finding Details"
description="View the finding details"
>
<DataTableRowDetails entityId={row.original.id} />
<DataTableRowDetails finding={getFindingsData(row)} />
</TriggerSheet>
);
},
@@ -2,36 +2,10 @@
import { useEffect, useState } from "react";
import { getScan } from "@/actions/scans";
import { ScanDetail, SkeletonTableScans } from "@/components/scans/table";
import { ScanProps } from "@/types";
import { FindingDetail } from "@/components/findings/table";
import { FindingProps } from "@/types";
export const DataTableRowDetails = ({ entityId }: { entityId: string }) => {
const [scanDetails, setScanDetails] = useState<ScanProps | null>(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const fetchScanDetails = async () => {
try {
const result = await getScan(entityId);
setScanDetails(result?.data);
} catch (error) {
console.error("Error fetching scan details:", error);
} finally {
setIsLoading(false);
}
};
fetchScanDetails();
}, [entityId]);
if (isLoading) {
return <SkeletonTableScans />;
}
if (!scanDetails) {
return <div>No scan details available</div>;
}
return <ScanDetail scanDetails={scanDetails} />;
export const DataTableRowDetails = ({ finding }: { finding: FindingProps }) => {
console.log(finding);
return <FindingDetail findingDetails={finding} />;
};
+83 -128
View File
@@ -4,139 +4,94 @@ import { Card, CardBody, CardHeader, Divider } from "@nextui-org/react";
import { DateWithTime, SnippetId } from "@/components/ui/entities";
import { StatusBadge } from "@/components/ui/table/status-badge";
import { ScanProps } from "@/types";
import { FindingProps } from "@/types";
import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell} from "@nextui-org/react";
export const FindingDetail = ({ findingDetails }: { findingDetails: ScanProps }) => {
const scanOnDemand = findingDetails.attributes;
export const FindingDetail = ({ findingDetails }: { findingDetails: FindingProps }) => {
const finding = findingDetails;
console.log(finding)
return (
<div className="space-y-4">
<div className="flex items-center justify-between">
<div className="flex flex-col items-baseline md:flex-row md:gap-x-4">
<h2 className="text-lg font-black uppercase">Scan Details - </h2>
<p>{scanOnDemand.name}</p>
</div>
<StatusBadge size="lg" status={scanOnDemand.state} />
</div>
<Divider />
<div className="relative z-0 flex w-full flex-col justify-between gap-4 overflow-auto rounded-large bg-content1 p-4 shadow-small">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<div className="space-y-4">
<DetailItem
label="ID"
value={<SnippetId label="Type" entityId={findingDetails.id} />}
/>
<DetailItem label="Trigger" value={scanOnDemand.trigger} />
<DetailItem
label="Resource Count"
value={scanOnDemand.unique_resource_count.toString()}
/>
<DetailItem label="Progress" value={`${scanOnDemand.progress}%`} />
<DetailItem
label="Duration"
value={`${scanOnDemand.duration} seconds`}
/>
</div>
<div className="space-y-4">
<DateItem
label="Started At"
value={
scanOnDemand.started_at ? (
<DateWithTime dateTime={scanOnDemand.started_at.toString()} />
) : (
"Not Started"
)
}
/>
<DateItem
label="Completed At"
value={
scanOnDemand.completed_at ? (
<DateWithTime
dateTime={scanOnDemand.completed_at.toString()}
/>
) : (
"Not Started"
)
}
/>
<DateItem
label="Scheduled At"
value={
scanOnDemand.scheduled_at ? (
<DateWithTime
dateTime={scanOnDemand.scheduled_at.toString()}
/>
) : (
"Not Scheduled"
)
}
/>
<DetailItem
label="Provider ID"
value={
<SnippetId
label="Provider ID"
entityId={findingDetails.relationships.provider.data.id}
/>
}
/>
<DetailItem
label="Task ID"
value={
<SnippetId
label="Task ID"
entityId={findingDetails.relationships.task.data.id}
/>
}
/>
</div>
</div>
</div>
<Card className="relative w-full border-small border-default-100 p-3 shadow-lg">
<CardHeader className="py-2">
<h2 className="text-2xl font-bold">Scan Arguments</h2>
</CardHeader>
<Divider />
<CardBody className="p-4">
<DetailItem
label="Checks"
value={
(scanOnDemand.scanner_args as any)?.checks_to_execute?.join(
", ",
) || "N/A"
}
/>
</CardBody>
</Card>
<Table aria-label="Example static collection table">
<TableHeader>
<TableColumn>Name </TableColumn>
<TableColumn>Value</TableColumn>
</TableHeader>
<TableBody>
<TableRow key="1">
<TableCell>Resource ID</TableCell>
<TableCell>{finding.relationships.resource.id}</TableCell>
</TableRow>
<TableRow key="2">
<TableCell>Resource ARN</TableCell>
<TableCell>{finding.relationships.resource.attributes.uid}</TableCell>
</TableRow>
<TableRow key="3">
<TableCell>Check ID</TableCell>
<TableCell>{finding.attributes.check_id}</TableCell>
</TableRow>
<TableRow key="4">
<TableCell>Types</TableCell>
<TableCell>{finding.attributes.check_metadata.checktype}</TableCell>
</TableRow>
<TableRow key="5">
<TableCell>Scan time</TableCell>
<TableCell>{finding.attributes.inserted_at}</TableCell>
</TableRow>
<TableRow key="6">
<TableCell>Prowler Finding ID</TableCell>
<TableCell>{finding.relationships.resource.attributes.uid}</TableCell>
</TableRow>
<TableRow key="7">
<TableCell>Severity</TableCell>
<TableCell>{finding.id}</TableCell>
</TableRow>
<TableRow key="8">
<TableCell>Status</TableCell>
<TableCell>{finding.attributes.status}</TableCell>
</TableRow>
<TableRow key="9">
<TableCell>Region</TableCell>
<TableCell>{finding.relationships.resource.attributes.region}</TableCell>
</TableRow>
<TableRow key="10">
<TableCell>Service</TableCell>
<TableCell>{finding.relationships.resource.attributes.service}</TableCell>
</TableRow>
<TableRow key="11">
<TableCell>Account</TableCell>
<TableCell>{finding.relationships.provider.attributes.uid}</TableCell>
</TableRow>
<TableRow key="12">
<TableCell>Details</TableCell>
<TableCell>{finding.attributes.status_extended}</TableCell>
</TableRow>
<TableRow key="13">
<TableCell>Risk</TableCell>
<TableCell>{finding.attributes.check_metadata.risk}</TableCell>
</TableRow>
<TableRow key="14">
<TableCell>Recommendation</TableCell>
<TableCell>{finding.attributes.check_metadata.remediation.recommendation.text}</TableCell>
</TableRow>
<TableRow key="15">
<TableCell>CLI</TableCell>
<TableCell>{finding.attributes.check_metadata.remediation.code.cli}</TableCell>
</TableRow>
<TableRow key="16">
<TableCell>Other</TableCell>
<TableCell>{finding.attributes.check_metadata.remediation.code.other}</TableCell>
</TableRow>
<TableRow key="17">
<TableCell>Terraform</TableCell>
<TableCell>{finding.attributes.check_metadata.remediation.code.terraform}</TableCell>
</TableRow>
</TableBody>
</Table>
</div>
</div>
);
};
const DateItem = ({
label,
value,
}: {
label: string;
value: React.ReactNode;
}) => (
<div className="flex items-center justify-between">
<span className="font-semibold text-default-500">{label}:</span>
<span className="text-default-700">{value}</span>
</div>
);
const DetailItem = ({
label,
value,
}: {
label: string;
value: React.ReactNode;
}) => (
<div className="flex items-center justify-between">
<span className="font-semibold text-default-500">{label}:</span>
<span className="text-default-700">{value}</span>
</div>
);
+1
View File
@@ -2,3 +2,4 @@ export * from "./column-findings";
export * from "./data-table-row-actions";
export * from "./data-table-row-details";
export * from "./skeleton-table-findings";
export * from "./finding-detail";
+1
View File
@@ -247,6 +247,7 @@ export interface FindingProps {
type: "Resource";
id: string;
}[];
id: string;
attributes: {
uid: string;
name: string;