mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-01-25 02:08:11 +00:00
feat(ui): integrate threat map with regions API endpoint (#9324)
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
This commit is contained in:
@@ -4,32 +4,12 @@ import { useRouter } from "next/navigation";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Rectangle, ResponsiveContainer, Sankey, Tooltip } from "recharts";
|
||||
|
||||
import {
|
||||
AWSProviderBadge,
|
||||
AzureProviderBadge,
|
||||
GCPProviderBadge,
|
||||
GitHubProviderBadge,
|
||||
IacProviderBadge,
|
||||
KS8ProviderBadge,
|
||||
M365ProviderBadge,
|
||||
OracleCloudProviderBadge,
|
||||
} from "@/components/icons/providers-badge";
|
||||
import { IconSvgProps } from "@/types";
|
||||
import { PROVIDER_ICONS } from "@/components/icons/providers-badge";
|
||||
import { initializeChartColors } from "@/lib/charts/colors";
|
||||
import { SEVERITY_FILTER_MAP } from "@/types/severities";
|
||||
|
||||
import { ChartTooltip } from "./shared/chart-tooltip";
|
||||
|
||||
// Map node names to their corresponding provider icon components
|
||||
const PROVIDER_ICONS: Record<string, React.FC<IconSvgProps>> = {
|
||||
AWS: AWSProviderBadge,
|
||||
Azure: AzureProviderBadge,
|
||||
"Google Cloud": GCPProviderBadge,
|
||||
Kubernetes: KS8ProviderBadge,
|
||||
"Microsoft 365": M365ProviderBadge,
|
||||
GitHub: GitHubProviderBadge,
|
||||
"Infrastructure as Code": IacProviderBadge,
|
||||
"Oracle Cloud Infrastructure": OracleCloudProviderBadge,
|
||||
};
|
||||
|
||||
interface SankeyNode {
|
||||
name: string;
|
||||
newFindings?: number;
|
||||
@@ -74,77 +54,6 @@ interface NodeTooltipState {
|
||||
const TOOLTIP_OFFSET_PX = 10;
|
||||
const MIN_LINK_WIDTH = 4;
|
||||
|
||||
// Map severity node names to their filter values for the findings page
|
||||
const SEVERITY_FILTER_MAP: Record<string, string> = {
|
||||
Critical: "critical",
|
||||
High: "high",
|
||||
Medium: "medium",
|
||||
Low: "low",
|
||||
Informational: "informational",
|
||||
};
|
||||
|
||||
// Map color names to CSS variable names defined in globals.css
|
||||
const COLOR_MAP: Record<string, string> = {
|
||||
// Status colors
|
||||
Success: "--color-bg-pass",
|
||||
Pass: "--color-bg-pass",
|
||||
Fail: "--color-bg-fail",
|
||||
// Provider colors
|
||||
AWS: "--color-bg-data-aws",
|
||||
Azure: "--color-bg-data-azure",
|
||||
"Google Cloud": "--color-bg-data-gcp",
|
||||
Kubernetes: "--color-bg-data-kubernetes",
|
||||
"Microsoft 365": "--color-bg-data-m365",
|
||||
GitHub: "--color-bg-data-github",
|
||||
"Infrastructure as Code": "--color-bg-data-muted",
|
||||
"Oracle Cloud Infrastructure": "--color-bg-data-muted",
|
||||
// Severity colors
|
||||
Critical: "--color-bg-data-critical",
|
||||
High: "--color-bg-data-high",
|
||||
Medium: "--color-bg-data-medium",
|
||||
Low: "--color-bg-data-low",
|
||||
Info: "--color-bg-data-info",
|
||||
Informational: "--color-bg-data-info",
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute color value from CSS variable name at runtime.
|
||||
* SVG fill attributes cannot directly resolve CSS variables,
|
||||
* so we extract computed values from globals.css CSS variables.
|
||||
* Falls back to black (#000000) if variable not found or access fails.
|
||||
*
|
||||
* @param colorName - Key in COLOR_MAP (e.g., "AWS", "Fail")
|
||||
* @returns Computed CSS variable value or fallback color
|
||||
*/
|
||||
const getColorVariable = (colorName: string): string => {
|
||||
const varName = COLOR_MAP[colorName];
|
||||
if (!varName) return "#000000";
|
||||
|
||||
try {
|
||||
if (typeof document === "undefined") {
|
||||
// SSR context - return fallback
|
||||
return "#000000";
|
||||
}
|
||||
return (
|
||||
getComputedStyle(document.documentElement)
|
||||
.getPropertyValue(varName)
|
||||
.trim() || "#000000"
|
||||
);
|
||||
} catch (error: unknown) {
|
||||
// CSS variables not loaded or access failed - return fallback
|
||||
return "#000000";
|
||||
}
|
||||
};
|
||||
|
||||
// Initialize all color variables from CSS
|
||||
const initializeColors = (): Record<string, string> => {
|
||||
const colors: Record<string, string> = {};
|
||||
for (const [colorName] of Object.entries(COLOR_MAP)) {
|
||||
colors[colorName] = getColorVariable(colorName);
|
||||
}
|
||||
return colors;
|
||||
};
|
||||
|
||||
interface TooltipPayload {
|
||||
payload: {
|
||||
source?: { name: string };
|
||||
@@ -476,7 +385,7 @@ export function SankeyChart({ data, height = 400 }: SankeyChartProps) {
|
||||
|
||||
// Initialize colors from CSS variables on mount
|
||||
useEffect(() => {
|
||||
setColors(initializeColors());
|
||||
setColors(initializeChartColors());
|
||||
}, []);
|
||||
|
||||
const handleLinkHover = (
|
||||
|
||||
@@ -512,23 +512,20 @@ export function ThreatMap({
|
||||
position={tooltipPosition}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className="mt-3 flex items-center gap-2"
|
||||
role="status"
|
||||
aria-label={`${filteredLocations.length} threat locations on map`}
|
||||
>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="h-3 w-3 rounded-full"
|
||||
style={{ backgroundColor: "var(--bg-data-critical)" }}
|
||||
/>
|
||||
<span
|
||||
className="text-sm"
|
||||
style={{ color: "var(--text-neutral-tertiary)" }}
|
||||
className="border-border-neutral-primary bg-bg-neutral-secondary absolute bottom-4 left-4 flex items-center gap-2 rounded-full border px-3 py-1.5"
|
||||
role="status"
|
||||
aria-label={`${filteredLocations.length} threat locations on map`}
|
||||
>
|
||||
{filteredLocations.length} Locations
|
||||
</span>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="h-3 w-3 rounded"
|
||||
style={{ backgroundColor: "var(--bg-data-critical)" }}
|
||||
/>
|
||||
<span className="text-text-neutral-primary text-sm font-medium">
|
||||
{filteredLocations.length} Locations
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
@@ -542,9 +539,13 @@ export function ThreatMap({
|
||||
<div className="flex w-full flex-col">
|
||||
<div className="mb-4">
|
||||
<div
|
||||
className="mb-1 flex items-center gap-2"
|
||||
className="mb-1 flex items-center"
|
||||
aria-label={`Selected location: ${selectedLocation.name}`}
|
||||
>
|
||||
<MapPin
|
||||
size={21}
|
||||
style={{ color: "var(--color-text-text-error)" }}
|
||||
/>
|
||||
<div
|
||||
aria-hidden="true"
|
||||
className="bg-pass-primary h-2 w-2 rounded-full"
|
||||
|
||||
@@ -1,8 +1,33 @@
|
||||
export * from "./aws-provider-badge";
|
||||
export * from "./azure-provider-badge";
|
||||
export * from "./gcp-provider-badge";
|
||||
export * from "./github-provider-badge";
|
||||
export * from "./iac-provider-badge";
|
||||
export * from "./ks8-provider-badge";
|
||||
export * from "./m365-provider-badge";
|
||||
export * from "./oraclecloud-provider-badge";
|
||||
import { IconSvgProps } from "@/types";
|
||||
|
||||
import { AWSProviderBadge } from "./aws-provider-badge";
|
||||
import { AzureProviderBadge } from "./azure-provider-badge";
|
||||
import { GCPProviderBadge } from "./gcp-provider-badge";
|
||||
import { GitHubProviderBadge } from "./github-provider-badge";
|
||||
import { IacProviderBadge } from "./iac-provider-badge";
|
||||
import { KS8ProviderBadge } from "./ks8-provider-badge";
|
||||
import { M365ProviderBadge } from "./m365-provider-badge";
|
||||
import { OracleCloudProviderBadge } from "./oraclecloud-provider-badge";
|
||||
|
||||
export {
|
||||
AWSProviderBadge,
|
||||
AzureProviderBadge,
|
||||
GCPProviderBadge,
|
||||
GitHubProviderBadge,
|
||||
IacProviderBadge,
|
||||
KS8ProviderBadge,
|
||||
M365ProviderBadge,
|
||||
OracleCloudProviderBadge,
|
||||
};
|
||||
|
||||
// Map provider display names to their icon components
|
||||
export const PROVIDER_ICONS: Record<string, React.FC<IconSvgProps>> = {
|
||||
AWS: AWSProviderBadge,
|
||||
Azure: AzureProviderBadge,
|
||||
"Google Cloud": GCPProviderBadge,
|
||||
Kubernetes: KS8ProviderBadge,
|
||||
"Microsoft 365": M365ProviderBadge,
|
||||
GitHub: GitHubProviderBadge,
|
||||
"Infrastructure as Code": IacProviderBadge,
|
||||
"Oracle Cloud Infrastructure": OracleCloudProviderBadge,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user