feat(UI): Add Provider detail component in Findings, Scan details (#7968)

Co-authored-by: Pablo Lara <larabjj@gmail.com>
This commit is contained in:
sumit-tft
2025-06-13 15:47:18 +05:30
committed by GitHub
parent e26b2e6527
commit 4a2a3921da
4 changed files with 43 additions and 80 deletions
+1
View File
@@ -26,6 +26,7 @@ All notable changes to the **Prowler UI** are documented in this file.
- `Provider UID` filter to scans page [(#7820)](https://github.com/prowler-cloud/prowler/pull/7820)
- Aligned Next.js version to `v14.2.29` across Prowler and Cloud environments for consistency and improved maintainability [(#7962)](https://github.com/prowler-cloud/prowler/pull/7962)
- Refactor credentials forms with reusable components and error handling [(#7988)](https://github.com/prowler-cloud/prowler/pull/7988)
- Updated the provider details section in Scan and Findings detail pages [(#7968)](https://github.com/prowler-cloud/prowler/pull/7968)
### 🐞 Fixed
@@ -4,9 +4,8 @@ import { Snippet } from "@nextui-org/react";
import Link from "next/link";
import { CodeSnippet } from "@/components/ui/code-snippet/code-snippet";
import { InfoField } from "@/components/ui/entities";
import { EntityInfoShort, InfoField } from "@/components/ui/entities";
import { DateWithTime } from "@/components/ui/entities/date-with-time";
import { getProviderLogo } from "@/components/ui/entities/get-provider-logo";
import { SeverityBadge } from "@/components/ui/table/severity-badge";
import { FindingProps, ProviderType } from "@/types";
@@ -56,7 +55,7 @@ export const FindingDetail = ({
const attributes = finding.attributes;
const resource = finding.relationships.resource.attributes;
const scan = finding.relationships.scan.attributes;
const provider = finding.relationships.provider.attributes;
const providerDetails = finding.relationships.provider.attributes;
return (
<div className="flex flex-col gap-6 rounded-lg">
@@ -87,11 +86,12 @@ export const FindingDetail = ({
{/* Check Metadata */}
<Section title="Finding Details">
<div className="flex flex-wrap gap-4">
<InfoField label="Provider" variant="simple">
{getProviderLogo(
attributes.check_metadata.provider as ProviderType,
)}
</InfoField>
<EntityInfoShort
cloudProvider={providerDetails.provider as ProviderType}
entityAlias={providerDetails.alias}
entityId={providerDetails.uid}
showConnectionStatus={providerDetails.connection.connected}
/>
<InfoField label="Service">
{attributes.check_metadata.servicename}
</InfoField>
@@ -259,7 +259,7 @@ export const FindingDetail = ({
{/* Add new Scan Details section */}
<Section title="Scan Details">
<div className="grid grid-cols-1 gap-4 md:grid-cols-3">
<InfoField label="Scan Name">{scan.name}</InfoField>
<InfoField label="Scan Name">{scan.name || "N/A"}</InfoField>
<InfoField label="Resources Scanned">
{scan.unique_resource_count}
</InfoField>
@@ -294,31 +294,6 @@ export const FindingDetail = ({
)}
</div>
</Section>
{/* Provider Details section */}
<Section title="Provider Details">
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
<InfoField label="Provider" variant="simple">
{getProviderLogo(
attributes.check_metadata.provider as ProviderType,
)}
</InfoField>
<InfoField label="Account ID">{provider.uid}</InfoField>
</div>
<div className="grid grid-cols-1 gap-4 md:grid-cols-2">
{provider.alias && (
<InfoField label="Alias">{provider.alias}</InfoField>
)}
<InfoField label="Connection Status">
<span
className={`${provider.connection.connected ? "text-green-500" : "text-red-500"}`}
>
{provider.connection.connected ? "Connected" : "Disconnected"}
</span>
</InfoField>
</div>
</Section>
</div>
);
};
+16 -45
View File
@@ -2,15 +2,13 @@
import { Snippet } from "@nextui-org/react";
import { ConnectionTrue } from "@/components/icons";
import { ConnectionFalse } from "@/components/icons/Icons";
import {
DateWithTime,
EntityInfoShort,
InfoField,
} from "@/components/ui/entities";
import { StatusBadge } from "@/components/ui/table/status-badge";
import { ProviderProps, ScanProps, TaskDetails } from "@/types";
import { ProviderProps, ProviderType, ScanProps, TaskDetails } from "@/types";
const renderValue = (value: string | null | undefined) => {
return value && value.trim() !== "" ? value : "-";
@@ -50,6 +48,7 @@ export const ScanDetail = ({
}: {
scanDetails: ScanProps & {
taskDetails?: TaskDetails;
// TODO: Remove the "?" once we have a proper provider details type
providerDetails?: ProviderProps;
};
}) => {
@@ -60,12 +59,20 @@ export const ScanDetail = ({
return (
<div className="flex flex-col gap-6 rounded-lg">
{/* Header */}
<div className="flex items-center justify-between">
<StatusBadge
size="md"
className="w-fit"
status={scan.state}
loadingProgress={scan.progress}
<div className="flex items-center gap-4">
<div className="flex items-center">
<StatusBadge
size="md"
className="w-fit"
status={scan.state}
loadingProgress={scan.progress}
/>
</div>
<EntityInfoShort
cloudProvider={providerDetails?.provider as ProviderType}
entityAlias={providerDetails?.alias}
entityId={providerDetails?.uid}
showConnectionStatus={providerDetails?.connection.connected}
/>
</div>
@@ -127,42 +134,6 @@ export const ScanDetail = ({
</InfoField>
</div>
</Section>
{/* Provider Details */}
<Section title="Provider Details">
{providerDetails ? (
<div className="grid grid-cols-1 gap-4 md:grid-cols-3">
<EntityInfoShort
cloudProvider={
providerDetails.provider as
| "aws"
| "azure"
| "gcp"
| "kubernetes"
}
entityAlias={providerDetails.alias}
entityId={providerDetails.uid}
/>
<InfoField label="Connection Status" variant="simple">
{providerDetails.connection.connected ? (
<ConnectionTrue className="text-system-success" size={24} />
) : (
<ConnectionFalse className="text-danger" size={24} />
)}
</InfoField>
<InfoField label="Last Checked">
<DateWithTime
inline
dateTime={providerDetails.connection.last_checked_at}
/>
</InfoField>
</div>
) : (
<span className="text-sm text-gray-500">
No provider details available
</span>
)}
</Section>
</div>
);
};
@@ -13,6 +13,7 @@ interface EntityInfoProps {
entityId?: string;
hideCopyButton?: boolean;
snippetWidth?: string;
showConnectionStatus?: boolean;
}
export const EntityInfoShort: React.FC<EntityInfoProps> = ({
@@ -20,11 +21,26 @@ export const EntityInfoShort: React.FC<EntityInfoProps> = ({
entityAlias,
entityId,
hideCopyButton = false,
showConnectionStatus = false,
}) => {
return (
<div className="flex items-center justify-start">
<div className="flex items-center justify-between gap-x-2">
<div className="flex-shrink-0">{getProviderLogo(cloudProvider)}</div>
<div className="relative flex-shrink-0">
{getProviderLogo(cloudProvider)}
{showConnectionStatus && (
<Tooltip
size="sm"
content={showConnectionStatus ? "Connected" : "Not Connected"}
>
<span
className={`absolute right-[-0.2rem] top-[-0.1rem] h-2 w-2 cursor-pointer rounded-full ${
showConnectionStatus ? "bg-green-500" : "bg-red-500"
}`}
/>
</Tooltip>
)}
</div>
<div className="flex max-w-[120px] flex-col">
{entityAlias && (
<Tooltip content={entityAlias} placement="top" size="sm">