mirror of
https://github.com/prowler-cloud/prowler.git
synced 2025-12-19 05:17:47 +00:00
fix(ui): improve overview charts UX and consistency (#9484)
This commit is contained in:
@@ -267,6 +267,10 @@ export function RiskPlotClient({ data }: RiskPlotClientProps) {
|
||||
<h3 className="text-text-neutral-primary text-lg font-semibold">
|
||||
Risk Plot
|
||||
</h3>
|
||||
<p className="text-text-neutral-tertiary mt-1 text-xs">
|
||||
Threat Score is severity-weighted, not quantity-based. Higher
|
||||
severity findings have greater impact on the score.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="relative min-h-[400px] w-full flex-1">
|
||||
@@ -298,9 +302,9 @@ export function RiskPlotClient({ data }: RiskPlotClientProps) {
|
||||
<YAxis
|
||||
type="number"
|
||||
dataKey="y"
|
||||
name="Failed Findings"
|
||||
name="Fail Findings"
|
||||
label={{
|
||||
value: "Failed Findings",
|
||||
value: "Fail Findings",
|
||||
angle: -90,
|
||||
position: "left",
|
||||
offset: 10,
|
||||
@@ -338,7 +342,7 @@ export function RiskPlotClient({ data }: RiskPlotClientProps) {
|
||||
{/* Interactive Legend - below chart */}
|
||||
<div className="mt-4 flex flex-col items-start gap-2">
|
||||
<p className="text-text-neutral-tertiary pl-2 text-xs">
|
||||
Click to filter by provider.
|
||||
Click to filter by provider
|
||||
</p>
|
||||
<ChartLegend
|
||||
items={providers.map((p) => ({
|
||||
@@ -363,7 +367,7 @@ export function RiskPlotClient({ data }: RiskPlotClientProps) {
|
||||
{selectedPoint.name}
|
||||
</h4>
|
||||
<p className="text-text-neutral-tertiary text-xs">
|
||||
Threat Score: {selectedPoint.x}% | Failed Findings:{" "}
|
||||
Threat Score: {selectedPoint.x}% | Fail Findings:{" "}
|
||||
{selectedPoint.y}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,6 @@ import { getSeverityTrendsByTimeRange } from "@/actions/overview/severity-trends
|
||||
import { LineChart } from "@/components/graphs/line-chart";
|
||||
import { LineConfig, LineDataPoint } from "@/components/graphs/types";
|
||||
import {
|
||||
MUTED_COLOR,
|
||||
SEVERITY_LEVELS,
|
||||
SEVERITY_LINE_CONFIGS,
|
||||
SeverityLevel,
|
||||
@@ -40,6 +39,9 @@ export const FindingSeverityOverTime = ({
|
||||
const params = new URLSearchParams();
|
||||
params.set("filter[inserted_at]", point.date);
|
||||
|
||||
// Always filter by FAIL status since this chart shows failed findings
|
||||
params.set("filter[status__in]", "FAIL");
|
||||
|
||||
// Add scan_ids filter
|
||||
if (
|
||||
point.scan_ids &&
|
||||
@@ -97,15 +99,6 @@ export const FindingSeverityOverTime = ({
|
||||
// Build line configurations from shared severity configs
|
||||
const lines: LineConfig[] = [...SEVERITY_LINE_CONFIGS];
|
||||
|
||||
// Only add muted line if data contains it
|
||||
if (data.some((item) => item.muted !== undefined)) {
|
||||
lines.push({
|
||||
dataKey: "muted",
|
||||
color: MUTED_COLOR,
|
||||
label: "Muted",
|
||||
});
|
||||
}
|
||||
|
||||
// Calculate x-axis interval based on data length to show all labels without overlap
|
||||
const getXAxisInterval = (): number => {
|
||||
const dataLength = data.length;
|
||||
|
||||
@@ -68,10 +68,31 @@ const CustomLineTooltip = ({
|
||||
const typedPayload = payload as unknown as TooltipPayloadItem[];
|
||||
|
||||
// Filter payload if a line is selected or hovered
|
||||
const displayPayload = filterLine
|
||||
const filteredPayload = filterLine
|
||||
? typedPayload.filter((item) => item.dataKey === filterLine)
|
||||
: typedPayload;
|
||||
|
||||
// Sort by severity order: critical, high, medium, low, informational
|
||||
const severityOrder = [
|
||||
"critical",
|
||||
"high",
|
||||
"medium",
|
||||
"low",
|
||||
"informational",
|
||||
] as const;
|
||||
const displayPayload = [...filteredPayload].sort((a, b) => {
|
||||
const aIndex = severityOrder.indexOf(
|
||||
a.dataKey as (typeof severityOrder)[number],
|
||||
);
|
||||
const bIndex = severityOrder.indexOf(
|
||||
b.dataKey as (typeof severityOrder)[number],
|
||||
);
|
||||
// Items not in severityOrder go to the end
|
||||
if (aIndex === -1) return 1;
|
||||
if (bIndex === -1) return -1;
|
||||
return aIndex - bIndex;
|
||||
});
|
||||
|
||||
if (displayPayload.length === 0) {
|
||||
return null;
|
||||
}
|
||||
@@ -96,12 +117,17 @@ const CustomLineTooltip = ({
|
||||
|
||||
return (
|
||||
<div key={item.dataKey} className="space-y-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="h-2 w-2 rounded-full"
|
||||
style={{ backgroundColor: item.stroke }}
|
||||
/>
|
||||
<span className="text-text-neutral-primary text-sm">
|
||||
<div className="flex items-center justify-between gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className="h-2 w-2 rounded-full"
|
||||
style={{ backgroundColor: item.stroke }}
|
||||
/>
|
||||
<span className="text-text-neutral-secondary text-sm">
|
||||
{item.name}
|
||||
</span>
|
||||
</div>
|
||||
<span className="text-text-neutral-primary text-sm font-medium">
|
||||
{item.value}
|
||||
</span>
|
||||
</div>
|
||||
@@ -260,7 +286,7 @@ export function LineChart({
|
||||
|
||||
<div className="mt-4 flex flex-col items-start gap-2">
|
||||
<p className="text-text-neutral-tertiary pl-2 text-xs">
|
||||
Click to filter by severity.
|
||||
Click to filter by severity
|
||||
</p>
|
||||
<ChartLegend
|
||||
items={legendItems}
|
||||
|
||||
Reference in New Issue
Block a user