mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 20:42:02 +00:00
Merge branch 'main' into PRWLR-4375-Services-Page-Card
This commit is contained in:
@@ -49,8 +49,8 @@ const SSRDataTable = async () => {
|
||||
checkId: "cloudformation_stack_outputs_find_secrets",
|
||||
checkLink:
|
||||
"https://app.prowler.pro/app/findings?date=2024-08-05&search=cloudformation_stack_outputs_find_secrets",
|
||||
type: "Not applicable",
|
||||
scanTime: "2024-08-05 @ 14:22:00 UTC",
|
||||
type: ["Not applicable"],
|
||||
scanTime: "2024-07-17T09:55:14.191475Z",
|
||||
findingId: "ba123291-03a5-49a1-b962-6fdb1d2b9c9b",
|
||||
findingLink:
|
||||
"https://app.prowler.pro/app/findings?date=2024-08-05&search=ba123291-03a5-49a1-b962-6fdb1d2b9c9b",
|
||||
@@ -87,8 +87,12 @@ const SSRDataTable = async () => {
|
||||
checkId: "iam_root_mfa_enabled",
|
||||
checkLink:
|
||||
"https://app.prowler.pro/app/findings?search=iam_root_mfa_enabled",
|
||||
type: "Software and Configuration Checks, Industry and Regulatory Standards, CIS AWS Foundations Benchmark",
|
||||
scanTime: "2024-08-05 @ 14:22:00 UTC",
|
||||
type: [
|
||||
"Software and Configuration Checks",
|
||||
"Industry and Regulatory Standards",
|
||||
"CIS AWS Foundations Benchmark",
|
||||
],
|
||||
scanTime: "2024-07-17T09:55:14.191475Z",
|
||||
findingId: "bc3a34e0-16f0-4ea1-ac62-f796c8af3448",
|
||||
findingLink:
|
||||
"https://app.prowler.pro/app/findings?date=2024-08-05&search=bc3a34e0-16f0-4ea1-ac62-f796c8af3448",
|
||||
@@ -123,8 +127,8 @@ const SSRDataTable = async () => {
|
||||
checkId: "s3_bucket_public_access",
|
||||
checkLink:
|
||||
"https://app.prowler.pro/app/findings?date=2024-08-06&search=s3_bucket_public_access",
|
||||
type: "Security",
|
||||
scanTime: "2024-08-06 @ 10:45:00 UTC",
|
||||
type: ["Security"],
|
||||
scanTime: "2024-07-17T09:55:14.191475Z",
|
||||
findingId: "e7b3d6a2-39a1-4f0e-9b78-29f4e6f292d1",
|
||||
findingLink:
|
||||
"https://app.prowler.pro/app/findings?date=2024-08-06&search=e7b3d6a2-39a1-4f0e-9b78-29f4e6f292d1",
|
||||
@@ -162,8 +166,8 @@ const SSRDataTable = async () => {
|
||||
checkId: "iam_password_policy_min_length",
|
||||
checkLink:
|
||||
"https://app.prowler.pro/app/findings?date=2024-08-06&search=iam_password_policy_min_length",
|
||||
type: "Security",
|
||||
scanTime: "2024-08-06 @ 11:10:00 UTC",
|
||||
type: ["Security"],
|
||||
scanTime: "2024-07-17T09:55:14.191475Z",
|
||||
findingId: "c2b3d1a4-7a9f-4d5c-a9ef-765a1d7f421c",
|
||||
findingLink:
|
||||
"https://app.prowler.pro/app/findings?date=2024-08-06&search=c2b3d1a4-7a9f-4d5c-a9ef-765a1d7f421c",
|
||||
@@ -201,8 +205,8 @@ const SSRDataTable = async () => {
|
||||
checkId: "rds_instance_public_access",
|
||||
checkLink:
|
||||
"https://app.prowler.pro/app/findings?date=2024-08-06&search=rds_instance_public_access",
|
||||
type: "Security",
|
||||
scanTime: "2024-08-06 @ 13:15:00 UTC",
|
||||
type: ["Security"],
|
||||
scanTime: "2024-07-17T09:55:14.191475Z",
|
||||
findingId: "f3b4c5d6-19a7-45d8-bc3e-8c5f6a7d8e9b",
|
||||
findingLink:
|
||||
"https://app.prowler.pro/app/findings?date=2024-08-06&search=f3b4c5d6-19a7-45d8-bc3e-8c5f6a7d8e9b",
|
||||
@@ -240,8 +244,8 @@ const SSRDataTable = async () => {
|
||||
checkId: "ebs_volume_encryption",
|
||||
checkLink:
|
||||
"https://app.prowler.pro/app/findings?date=2024-08-07&search=ebs_volume_encryption",
|
||||
type: "Encryption",
|
||||
scanTime: "2024-08-07 @ 09:30:00 UTC",
|
||||
type: ["Encryption"],
|
||||
scanTime: "2024-07-17T09:55:14.191475Z",
|
||||
findingId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
findingLink:
|
||||
"https://app.prowler.pro/app/findings?date=2024-08-07&search=a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
@@ -278,8 +282,8 @@ const SSRDataTable = async () => {
|
||||
checkId: "cloudtrail_all_regions_enabled",
|
||||
checkLink:
|
||||
"https://app.prowler.pro/app/findings?date=2024-08-07&search=cloudtrail_all_regions_enabled",
|
||||
type: "Logging",
|
||||
scanTime: "2024-08-07 @ 11:00:00 UTC",
|
||||
type: ["Logging"],
|
||||
scanTime: "2024-07-17T09:55:14.191475Z",
|
||||
findingId: "b2c3d4e5-f6a7-8901-bcde-f123456789ab",
|
||||
findingLink:
|
||||
"https://app.prowler.pro/app/findings?date=2024-08-07&search=b2c3d4e5-f6a7-8901-bcde-f123456789ab",
|
||||
@@ -317,8 +321,8 @@ const SSRDataTable = async () => {
|
||||
checkId: "ec2_instance_outdated_ami",
|
||||
checkLink:
|
||||
"https://app.prowler.pro/app/findings?date=2024-08-07&search=ec2_instance_outdated_ami",
|
||||
type: "Configuration",
|
||||
scanTime: "2024-08-07 @ 12:45:00 UTC",
|
||||
type: ["Configuration"],
|
||||
scanTime: "2024-07-17T09:55:14.191475Z",
|
||||
findingId: "c3d4e5f6-a789-0123-bcde-f234567890ab",
|
||||
findingLink:
|
||||
"https://app.prowler.pro/app/findings?date=2024-08-07&search=c3d4e5f6-a789-0123-bcde-f234567890ab",
|
||||
@@ -357,8 +361,8 @@ const SSRDataTable = async () => {
|
||||
checkId: "cloudwatch_alarms_for_critical_events",
|
||||
checkLink:
|
||||
"https://app.prowler.pro/app/findings?date=2024-08-08&search=cloudwatch_alarms_for_critical_events",
|
||||
type: "Monitoring",
|
||||
scanTime: "2024-08-08 @ 09:50:00 UTC",
|
||||
type: ["Monitoring"],
|
||||
scanTime: "2024-07-17T09:55:14.191475Z",
|
||||
findingId: "d4e5f6a7-8901-bcde-f345678901ab",
|
||||
findingLink:
|
||||
"https://app.prowler.pro/app/findings?date=2024-08-08&search=d4e5f6a7-8901-bcde-f345678901ab",
|
||||
@@ -396,8 +400,8 @@ const SSRDataTable = async () => {
|
||||
checkId: "iam_user_least_privilege",
|
||||
checkLink:
|
||||
"https://app.prowler.pro/app/findings?date=2024-08-08&search=iam_user_least_privilege",
|
||||
type: "Security",
|
||||
scanTime: "2024-08-08 @ 10:15:00 UTC",
|
||||
type: ["Security"],
|
||||
scanTime: "2024-07-17T09:55:14.191475Z",
|
||||
findingId: "e5f6a7b8-9012-bcde-f456789012ab",
|
||||
findingLink:
|
||||
"https://app.prowler.pro/app/findings?date=2024-08-08&search=e5f6a7b8-9012-bcde-f456789012ab",
|
||||
|
||||
@@ -3,8 +3,7 @@ import "@/styles/globals.css";
|
||||
import { Metadata, Viewport } from "next";
|
||||
import React from "react";
|
||||
|
||||
import { Toaster } from "@/components/ui";
|
||||
import { SidebarWrap } from "@/components/ui/sidebar";
|
||||
import { SidebarWrap, Toaster } from "@/components/ui";
|
||||
import { fontSans } from "@/config/fonts";
|
||||
import { siteConfig } from "@/config/site";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
import { Divider } from "@nextui-org/react";
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
|
||||
import {
|
||||
FindingsCardContent,
|
||||
FindingsCardDetail,
|
||||
FindingsCardScan,
|
||||
FindingsCardType,
|
||||
} from "@/components/findings";
|
||||
import { FindingProps } from "@/types";
|
||||
interface FindingsCardProps {
|
||||
selectedRow: FindingProps;
|
||||
}
|
||||
|
||||
export const FindingsCard: React.FC<FindingsCardProps> = ({ selectedRow }) => {
|
||||
const { attributes, card } = selectedRow || {};
|
||||
const { CheckTitle } = attributes || {};
|
||||
const {
|
||||
resourceLink,
|
||||
resourceId,
|
||||
resourceARN,
|
||||
checkLink,
|
||||
checkId,
|
||||
type,
|
||||
scanTime,
|
||||
findingLink,
|
||||
findingId,
|
||||
details,
|
||||
riskDetails,
|
||||
riskLink,
|
||||
recommendationDetails,
|
||||
recommendationLink,
|
||||
referenceInformation,
|
||||
referenceLink,
|
||||
} = card || {};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={clsx(
|
||||
"max-h-[calc(100vh-146px)] overflow-y-auto rounded-md border bg-background transition-all duration-300",
|
||||
{
|
||||
"w-1/3 translate-x-0 ml-2 p-3 opacity-100": selectedRow,
|
||||
"translate-x-full w-0 opacity-0": !selectedRow,
|
||||
},
|
||||
)}
|
||||
>
|
||||
<p className="font-bold mb-3">{CheckTitle}</p>
|
||||
<Divider />
|
||||
|
||||
<FindingsCardContent
|
||||
title="Resource ID:"
|
||||
url={resourceLink}
|
||||
description={resourceId}
|
||||
/>
|
||||
<FindingsCardContent title="Resource ARN:" description={resourceARN} />
|
||||
<FindingsCardContent
|
||||
title="Check ID:"
|
||||
url={checkLink}
|
||||
description={checkId}
|
||||
/>
|
||||
<FindingsCardType type={type} />
|
||||
<FindingsCardScan title="Scan Time:" dateTime={scanTime} />
|
||||
<FindingsCardContent
|
||||
title="Prowler Finding ID:"
|
||||
url={findingLink}
|
||||
description={findingId}
|
||||
/>
|
||||
|
||||
<FindingsCardDetail title="Details:" description={details} />
|
||||
<FindingsCardDetail
|
||||
title="Risk:"
|
||||
url={riskLink}
|
||||
description={riskDetails}
|
||||
type="risk"
|
||||
/>
|
||||
<FindingsCardDetail
|
||||
title="Recommendation:"
|
||||
url={recommendationLink}
|
||||
description={recommendationDetails}
|
||||
type="recommendation"
|
||||
/>
|
||||
<FindingsCardDetail
|
||||
title="Reference Information:"
|
||||
url={referenceLink}
|
||||
description={referenceInformation}
|
||||
type="reference"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
import { Link } from "@nextui-org/react";
|
||||
import React from "react";
|
||||
|
||||
interface FindingsCardContentProps {
|
||||
title: string;
|
||||
url?: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export const FindingsCardContent: React.FC<FindingsCardContentProps> = ({
|
||||
title,
|
||||
url,
|
||||
description,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<p className="text-sm font-bold mt-3">{title}</p>
|
||||
{url ? (
|
||||
<Link className="text-sm" href={url}>
|
||||
{description}
|
||||
</Link>
|
||||
) : (
|
||||
<p className="text-sm">{description}</p>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
import { Button, Link } from "@nextui-org/react";
|
||||
import React from "react";
|
||||
|
||||
interface FindingsCardDetailProps {
|
||||
title: string;
|
||||
url?: string;
|
||||
description: string;
|
||||
type?: DetailType;
|
||||
}
|
||||
|
||||
type DetailType = "default" | "risk" | "recommendation" | "reference";
|
||||
|
||||
const getDetailColorClass = (type: DetailType): string => {
|
||||
switch (type) {
|
||||
case "risk":
|
||||
return "border-red-200";
|
||||
case "recommendation":
|
||||
return "border-green-200";
|
||||
case "reference":
|
||||
return "border-gray-200";
|
||||
case "default":
|
||||
default:
|
||||
return "border-yellow-200";
|
||||
}
|
||||
};
|
||||
|
||||
export const FindingsCardDetail: React.FC<FindingsCardDetailProps> = ({
|
||||
title,
|
||||
url,
|
||||
description,
|
||||
type = "default",
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
{description && (
|
||||
<div
|
||||
className={`text-sm mt-3 rounded-md border-2 ${getDetailColorClass(type)} p-2`}
|
||||
>
|
||||
<p className="font-bold flex justify-between items-center mb-2">
|
||||
<span>{title}</span>
|
||||
{url && (
|
||||
<Button
|
||||
href={url}
|
||||
as={Link}
|
||||
color="primary"
|
||||
variant="flat"
|
||||
isExternal
|
||||
size="sm"
|
||||
>
|
||||
View Source
|
||||
</Button>
|
||||
)}
|
||||
</p>
|
||||
<p>{description}</p>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
import { format, parseISO } from "date-fns";
|
||||
import React from "react";
|
||||
|
||||
interface FindingsCardScanProps {
|
||||
title: string;
|
||||
dateTime: string;
|
||||
}
|
||||
|
||||
export const FindingsCardScan: React.FC<FindingsCardScanProps> = ({
|
||||
title,
|
||||
dateTime = "",
|
||||
}) => {
|
||||
const date = dateTime && parseISO(dateTime);
|
||||
const formattedDate = date && format(date, "MMM dd, yyyy");
|
||||
const formattedTime = date && format(date, "p 'UTC'");
|
||||
|
||||
return (
|
||||
<>
|
||||
<p className="text-sm font-bold mt-3">{title}</p>
|
||||
<p className="text-sm">
|
||||
{formattedDate} at {formattedTime}
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
import React from "react";
|
||||
|
||||
interface FindingsCardTypeProps {
|
||||
type: string[];
|
||||
}
|
||||
|
||||
export const FindingsCardType: React.FC<FindingsCardTypeProps> = ({
|
||||
type = [],
|
||||
}) => {
|
||||
const typeContent = () => {
|
||||
if (type.length > 0) {
|
||||
return type.join(", ");
|
||||
}
|
||||
return type[0];
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<p className="text-sm font-bold mt-3">
|
||||
{type.length > 1 ? "Types:" : "Type:"}
|
||||
</p>
|
||||
<p className="text-sm">{typeContent()}</p>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -1,4 +1,8 @@
|
||||
export * from "./FindingsCard";
|
||||
export * from "./FindingsCardContent";
|
||||
export * from "./FindingsCardDetail";
|
||||
export * from "./FindingsCardScan";
|
||||
export * from "./FindingsCardType";
|
||||
export * from "./table/ColumnsFindings";
|
||||
export * from "./table/DataTableFindings";
|
||||
export * from "./table/FindingsCard";
|
||||
export * from "./table/SkeletonTableFindings";
|
||||
|
||||
@@ -9,8 +9,9 @@ import {
|
||||
Row,
|
||||
useReactTable,
|
||||
} from "@tanstack/react-table";
|
||||
import clsx from "clsx";
|
||||
|
||||
import { FindingsCard } from "@/components/findings/table/FindingsCard";
|
||||
import { FindingsCard } from "@/components/findings";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
@@ -18,7 +19,7 @@ import {
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table/Table";
|
||||
} from "@/components/ui";
|
||||
import { FindingProps } from "@/types";
|
||||
|
||||
interface DataTableFindingsProps<TData extends FindingProps, TValue> {
|
||||
@@ -48,7 +49,12 @@ export function DataTableFindings<TData extends FindingProps, TValue>({
|
||||
return (
|
||||
<>
|
||||
<div className="flex flex-row w-full">
|
||||
<div className="w-full">
|
||||
<div
|
||||
className={clsx("transition-all duration-300", {
|
||||
"w-2/3": selectedRow,
|
||||
"w-full": !selectedRow,
|
||||
})}
|
||||
>
|
||||
<div className="rounded-md border">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
import { Button, Divider, Link } from "@nextui-org/react";
|
||||
import React from "react";
|
||||
|
||||
import { FindingProps } from "@/types";
|
||||
interface FindingsCardProps {
|
||||
selectedRow: FindingProps;
|
||||
}
|
||||
|
||||
export const FindingsCard: React.FC<FindingsCardProps> = ({ selectedRow }) => {
|
||||
const { attributes, card } = selectedRow || {};
|
||||
const { CheckTitle } = attributes || {};
|
||||
const {
|
||||
resourceLink,
|
||||
resourceId,
|
||||
resourceARN,
|
||||
checkLink,
|
||||
checkId,
|
||||
type,
|
||||
scanTime,
|
||||
findingLink,
|
||||
findingId,
|
||||
details,
|
||||
riskDetails,
|
||||
riskLink,
|
||||
recommendationDetails,
|
||||
recommendationLink,
|
||||
referenceInformation,
|
||||
referenceLink,
|
||||
} = card || {};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={`rounded-md border bg-background transition-transform duration-300 ${selectedRow ? "w-2/5 translate-x-0 ml-2 p-3" : "translate-x-full w-0"}`}
|
||||
>
|
||||
<p className="font-bold mb-3">{CheckTitle}</p>
|
||||
<Divider />
|
||||
<div className="text-sm mt-3">
|
||||
<p className="font-bold">Resource ID:</p>
|
||||
<Link className="text-sm" href={resourceLink}>
|
||||
{resourceId}
|
||||
</Link>
|
||||
<p className="font-bold mt-3">Resource ARN:</p>
|
||||
<p>{resourceARN}</p>
|
||||
<p className="font-bold mt-3">Check ID:</p>
|
||||
<Link className="text-sm" href={checkLink}>
|
||||
{checkId}
|
||||
</Link>
|
||||
<p className="font-bold mt-3">Type:</p>
|
||||
<p>{type}</p>
|
||||
<p className="font-bold mt-3">Scan Time:</p>
|
||||
<p>{scanTime}</p>
|
||||
<p className="font-bold mt-3">Prowler Finding ID:</p>
|
||||
<Link className="text-sm" href={findingLink}>
|
||||
{findingId}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{details && (
|
||||
<div className="text-sm mt-3 rounded-md border-2 border-yellow-500 p-2">
|
||||
<p className="font-bold">Details:</p>
|
||||
<p>{details}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{riskDetails && (
|
||||
<div className="text-sm mt-3 rounded-md border-2 border-red-500 p-2">
|
||||
<p className="font-bold flex justify-between items-center mb-2">
|
||||
<span>Risk:</span>
|
||||
{riskLink && (
|
||||
<Button
|
||||
href={riskLink}
|
||||
as={Link}
|
||||
color="primary"
|
||||
variant="flat"
|
||||
isExternal
|
||||
size="sm"
|
||||
className="h-[28px] p-2"
|
||||
>
|
||||
View Source
|
||||
</Button>
|
||||
)}
|
||||
</p>
|
||||
<p>{riskDetails}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{recommendationDetails && (
|
||||
<div className="text-sm mt-3 rounded-md border-2 border-green-500 p-2">
|
||||
<div className="font-bold flex justify-between items-center mb-2">
|
||||
<span>Recommendation:</span>
|
||||
{recommendationLink && (
|
||||
<Button
|
||||
href={recommendationLink}
|
||||
as={Link}
|
||||
color="primary"
|
||||
variant="flat"
|
||||
isExternal
|
||||
size="sm"
|
||||
className="h-[28px] p-2"
|
||||
>
|
||||
View Source
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<p>{recommendationDetails}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{referenceInformation && (
|
||||
<div className="text-sm mt-3 rounded-md border-2 border-gray-500 p-2">
|
||||
<div className="font-bold flex justify-between items-center mb-2">
|
||||
<span>Reference Information:</span>
|
||||
{referenceLink && (
|
||||
<Button
|
||||
href={referenceLink}
|
||||
as={Link}
|
||||
color="primary"
|
||||
variant="flat"
|
||||
isExternal
|
||||
size="sm"
|
||||
className="h-[28px] p-2"
|
||||
>
|
||||
View Source
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<p>{referenceInformation}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -11,7 +11,7 @@ import { ColumnDef } from "@tanstack/react-table";
|
||||
import { add } from "date-fns";
|
||||
|
||||
import { VerticalDotsIcon } from "@/components/icons";
|
||||
import { StatusBadge } from "@/components/ui/table/StatusBadge";
|
||||
import { StatusBadge } from "@/components/ui";
|
||||
import { ProviderProps } from "@/types";
|
||||
|
||||
import { CheckConnectionProvider } from "../CheckConnectionProvider";
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table/Table";
|
||||
} from "@/components/ui";
|
||||
import { MetaDataProps } from "@/types";
|
||||
|
||||
import { DataTablePagination } from "./DataTablePagination";
|
||||
|
||||
@@ -1,46 +1,47 @@
|
||||
import { Chip } from "@nextui-org/react";
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
|
||||
import { AlertIcon } from "@/components/icons";
|
||||
|
||||
type Severity = "critical" | "high" | "medium" | "low";
|
||||
|
||||
const severityColorMap: Record<
|
||||
Severity,
|
||||
| "text-white bg-red-800"
|
||||
| "text-white bg-red-600"
|
||||
| "text-white bg-orange-500"
|
||||
| "bg-yellow-200"
|
||||
> = {
|
||||
critical: "text-white bg-red-800",
|
||||
high: "text-white bg-red-600",
|
||||
medium: "text-white bg-orange-500",
|
||||
low: "bg-yellow-200",
|
||||
};
|
||||
|
||||
const severityIconMap: Partial<Record<Severity, React.ReactNode>> = {
|
||||
const severityIconMap = {
|
||||
critical: <AlertIcon size={14} className="mr-1" />,
|
||||
} as const;
|
||||
|
||||
const getSeverityColor = (
|
||||
severity: Severity,
|
||||
): "danger" | "warning" | "default" => {
|
||||
switch (severity) {
|
||||
case "critical":
|
||||
return "danger";
|
||||
case "high":
|
||||
return "danger";
|
||||
case "medium":
|
||||
return "warning";
|
||||
case "low":
|
||||
return "default";
|
||||
default:
|
||||
return "default"; // this is a fallback, though unnecessary due to typing
|
||||
}
|
||||
};
|
||||
|
||||
const getSeverityColor: (severity: Severity) => string = (severity) =>
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
severityColorMap[severity];
|
||||
|
||||
const getSeverityIcon: (severity: Severity) => React.ReactNode | null = (
|
||||
severity,
|
||||
) =>
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
severityIconMap[severity] || null;
|
||||
const getSeverityIcon = (severity: Severity): React.ReactNode | null => {
|
||||
return severity === "critical" ? severityIconMap.critical : null;
|
||||
};
|
||||
|
||||
export const SeverityBadge = ({ severity }: { severity: Severity }) => {
|
||||
const color = getSeverityColor(severity);
|
||||
|
||||
return (
|
||||
<Chip
|
||||
classNames={{
|
||||
base: `capitalize border-none gap-1 text-gray-600 ${getSeverityColor(severity)}`,
|
||||
content: "font-semibold",
|
||||
}}
|
||||
className={clsx("capitalize border-none gap-1 text-default-600", {
|
||||
"bg-rose-700/20": severity === "critical",
|
||||
})}
|
||||
size="sm"
|
||||
variant="flat"
|
||||
color={color}
|
||||
endContent={getSeverityIcon(severity)}
|
||||
>
|
||||
{severity}
|
||||
|
||||
@@ -11,32 +11,25 @@ type Status =
|
||||
|
||||
const statusColorMap: Record<
|
||||
Status,
|
||||
| "text-white bg-green-600"
|
||||
| "bg-yellow-200"
|
||||
| "text-white bg-red-600"
|
||||
| "bg-gray-300"
|
||||
"danger" | "warning" | "success" | "default"
|
||||
> = {
|
||||
completed: "text-white bg-green-600",
|
||||
pending: "bg-yellow-200",
|
||||
cancelled: "text-white bg-red-600",
|
||||
fail: "text-white bg-red-600",
|
||||
success: "text-white bg-green-600",
|
||||
muted: "bg-gray-300",
|
||||
completed: "success",
|
||||
pending: "warning",
|
||||
cancelled: "danger",
|
||||
fail: "danger",
|
||||
success: "success",
|
||||
muted: "default",
|
||||
};
|
||||
|
||||
const getStatusColor: (status: Status) => string = (status) =>
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
statusColorMap[status];
|
||||
|
||||
export const StatusBadge = ({ status }: { status: Status }) => {
|
||||
const color = statusColorMap[status as keyof typeof statusColorMap];
|
||||
|
||||
return (
|
||||
<Chip
|
||||
classNames={{
|
||||
base: `capitalize border-none gap-1 text-gray-600 ${getStatusColor(status)}`,
|
||||
content: "font-semibold",
|
||||
}}
|
||||
className="capitalize border-none gap-1 text-default-600"
|
||||
size="sm"
|
||||
variant="solid"
|
||||
variant="flat"
|
||||
color={color}
|
||||
>
|
||||
{status}
|
||||
</Chip>
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ export interface FindingProps {
|
||||
resourceARN: string;
|
||||
checkId: string;
|
||||
checkLink: string;
|
||||
type: string;
|
||||
type: string[];
|
||||
scanTime: string;
|
||||
findingId: string;
|
||||
findingLink: string;
|
||||
|
||||
Reference in New Issue
Block a user