fix(ui): minor bugs (#8898)

This commit is contained in:
Alejandro Bailo
2025-10-10 14:56:34 +02:00
committed by GitHub
parent 8794515318
commit fba2854f65
6 changed files with 63 additions and 50 deletions

View File

@@ -31,15 +31,11 @@ All notable changes to the **Prowler UI** are documented in this file.
- SAML configuration errors are now properly caught and displayed [(#8880)](https://github.com/prowler-cloud/prowler/pull/8880)
- ThreatScore for each pillar in Prowler ThreatScore specific view [(#8582)](https://github.com/prowler-cloud/prowler/pull/8582)
- Remove maxTokens model param for GPT-5 models [(#8843)](https://github.com/prowler-cloud/prowler/pull/8843)
- MITRE ATTACK compliance view now shows all requirements in charts [(#8886)](https://github.com/prowler-cloud/prowler/pull/8886)
---
## [1.12.4] (Prowler v5.12.4)
### 🐞 Fixed
- Remove maxTokens model param for GPT-5 models [(#8843)](https://github.com/prowler-cloud/prowler/pull/8843)
## [1.12.3] (Prowler v5.12.3)
### 🐞 Fixed

View File

@@ -1,6 +1,7 @@
import { Spacer } from "@heroui/spacer";
import { Suspense } from "react";
import { getRoles } from "@/actions/roles/roles";
import { getUsers } from "@/actions/users/users";
import { FilterControls } from "@/components/filters";
import { filterUsers } from "@/components/filters/data-filters";
@@ -52,6 +53,7 @@ const SSRDataTable = async ({
const query = (filters["filter[search]"] as string) || "";
const usersData = await getUsers({ query, page, sort, filters, pageSize });
const rolesData = await getRoles({});
// Create a dictionary for roles by user ID
const roleDict = (usersData?.included || []).reduce(
@@ -67,7 +69,7 @@ const SSRDataTable = async ({
// Generate the array of roles with all the roles available
const roles = Array.from(
new Map(
(usersData?.included || []).map((role: Role) => [
(rolesData?.data || []).map((role: Role) => [
role.id,
{ id: role.id, name: role.attributes?.name || "Unnamed Role" },
]),

View File

@@ -17,7 +17,7 @@ interface CISDetailsProps {
export const CISCustomDetails = ({ requirement }: CISDetailsProps) => {
const processReferences = (
references: string | number | string[] | object[] | undefined,
references: string | number | boolean | string[] | object[] | undefined,
): string[] => {
if (typeof references !== "string") return [];

View File

@@ -119,7 +119,12 @@ export const EditForm = ({
</div>
<div className="text-small flex items-center text-gray-600">
<ShieldIcon className="mr-2 h-4 w-4" />
<span className="text-gray-500">Role:</span>
<span className="text-gray-500">
Role:
<span className="ml-2 font-semibold text-gray-900">
{currentRole ? currentRole : "No role"}
</span>
</span>
<span className="ml-2 font-semibold text-gray-900">
{currentRole}
</span>

View File

@@ -25,16 +25,15 @@ export const mapComplianceData = (
): Framework[] => {
const attributes = attributesData?.data || [];
const requirementsMap = createRequirementsMap(requirementsData);
const frameworks: Framework[] = [];
// Process attributes and merge with requirements data
// Process ALL attributes to ensure consistent counters for charts
for (const attributeItem of attributes) {
const id = attributeItem.id;
const metadataArray = attributeItem.attributes?.attributes
?.metadata as unknown as MITREAttributesMetadata[];
if (!metadataArray || metadataArray.length === 0) continue;
// Get corresponding requirement data
const requirementData = requirementsMap.get(id);
if (!requirementData) continue;
@@ -56,6 +55,7 @@ export const mapComplianceData = (
const framework = findOrCreateFramework(frameworks, frameworkName);
// Create requirement directly (flat structure - no categories)
// Include ALL requirements, even those without metadata (for accurate chart counts)
const finalStatus: RequirementStatus = status as RequirementStatus;
const requirement: Requirement = {
name: requirementName,
@@ -72,20 +72,23 @@ export const mapComplianceData = (
subtechniques: subtechniques,
platforms: platforms,
technique_url: techniqueUrl,
cloud_services: metadataArray.map((m) => {
// Dynamically find the service field (AWSService, GCPService, AzureService, etc.)
const serviceKey = Object.keys(m).find((key) =>
key.toLowerCase().includes("service"),
);
const serviceName = serviceKey ? m[serviceKey] : "Unknown Service";
// Mark items without metadata so accordion can filter them out
hasMetadata: !!(metadataArray && metadataArray.length > 0),
cloud_services:
metadataArray?.map((m) => {
// Dynamically find the service field (AWSService, GCPService, AzureService, etc.)
const serviceKey = Object.keys(m).find((key) =>
key.toLowerCase().includes("service"),
);
const serviceName = serviceKey ? m[serviceKey] : "Unknown Service";
return {
service: serviceName,
category: m.Category,
value: m.Value,
comment: m.Comment,
};
}),
return {
service: serviceName,
category: m.Category,
value: m.Value,
comment: m.Comment,
};
}) || [],
};
// Add requirement directly to framework (store in a special property)
@@ -106,31 +109,38 @@ export const toAccordionItems = (
return data.flatMap((framework) => {
const requirements = (framework as any).requirements || [];
return requirements.map((requirement: Requirement, i: number) => {
const itemKey = `${framework.name}-req-${i}`;
// Filter out requirements without metadata (can't be displayed in accordion)
const displayableRequirements = requirements.filter(
(requirement: Requirement) => requirement.hasMetadata !== false,
);
return {
key: itemKey,
title: (
<ComplianceAccordionRequirementTitle
type=""
name={requirement.name}
status={requirement.status as FindingStatus}
/>
),
content: (
<ClientAccordionContent
requirement={requirement}
scanId={scanId || ""}
framework={framework.name}
disableFindings={
requirement.check_ids.length === 0 && requirement.manual === 0
}
/>
),
items: [],
};
});
return displayableRequirements.map(
(requirement: Requirement, i: number) => {
const itemKey = `${framework.name}-req-${i}`;
return {
key: itemKey,
title: (
<ComplianceAccordionRequirementTitle
type=""
name={requirement.name}
status={requirement.status as FindingStatus}
/>
),
content: (
<ClientAccordionContent
requirement={requirement}
scanId={scanId || ""}
framework={framework.name}
disableFindings={
requirement.check_ids.length === 0 && requirement.manual === 0
}
/>
),
items: [],
};
},
);
});
};

View File

@@ -27,7 +27,7 @@ export interface Requirement {
check_ids: string[];
// This is to allow any key to be added to the requirement object
// because each compliance has different keys
[key: string]: string | string[] | number | object[] | undefined;
[key: string]: string | string[] | number | boolean | object[] | undefined;
}
export interface Control {