feat: upgrade to React 19, Next.js 15, React Compiler, HeroUI and Tailwind 4 (#8748)

Co-authored-by: Alan Buscaglia <alanbuscaglia@MacBook-Pro.local>
Co-authored-by: alejandrobailo <alejandrobailo94@gmail.com>
Co-authored-by: César Arroba <cesar@prowler.com>
Co-authored-by: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com>
This commit is contained in:
Alan Buscaglia
2025-09-30 09:59:51 +02:00
committed by GitHub
co-authored by Alan Buscaglia alejandrobailo César Arroba Alejandro Bailo
parent 2a4b62527a
commit 4d5676f00e
261 changed files with 6339 additions and 6126 deletions
+17 -16
View File
@@ -69,7 +69,7 @@ export interface ComplianceMapper {
getDetailsComponent: (requirement: Requirement) => React.ReactNode;
}
const defaultMapper: ComplianceMapper = {
const getDefaultMapper = (): ComplianceMapper => ({
mapComplianceData: mapGenericComplianceData,
toAccordionItems: toGenericAccordionItems,
getTopFailedSections,
@@ -77,22 +77,9 @@ const defaultMapper: ComplianceMapper = {
calculateCategoryHeatmapData(data),
getDetailsComponent: (requirement: Requirement) =>
React.createElement(GenericCustomDetails, { requirement }),
};
});
/**
* Get the appropriate compliance mapper based on the framework name
* @param framework - The framework name (e.g., "ENS", "ISO27001", "CIS")
* @returns ComplianceMapper object with specific functions for the framework
*/
export const getComplianceMapper = (framework?: string): ComplianceMapper => {
if (!framework) {
return defaultMapper;
}
return complianceMappers[framework] || defaultMapper;
};
export const complianceMappers: Record<string, ComplianceMapper> = {
const getComplianceMappers = (): Record<string, ComplianceMapper> => ({
ENS: {
mapComplianceData: mapENSComplianceData,
toAccordionItems: toENSAccordionItems,
@@ -164,4 +151,18 @@ export const complianceMappers: Record<string, ComplianceMapper> = {
getDetailsComponent: (requirement: Requirement) =>
React.createElement(ThreatCustomDetails, { requirement }),
},
});
/**
* Get the appropriate compliance mapper based on the framework name
* @param framework - The framework name (e.g., "ENS", "ISO27001", "CIS")
* @returns ComplianceMapper object with specific functions for the framework
*/
export const getComplianceMapper = (framework?: string): ComplianceMapper => {
if (!framework) {
return getDefaultMapper();
}
const complianceMappers = getComplianceMappers();
return complianceMappers[framework] || getDefaultMapper();
};
-84
View File
@@ -1,5 +1,3 @@
import { revalidatePath } from "next/cache";
import { getComplianceCsv, getExportsZip } from "@/actions/scans";
import { getTask } from "@/actions/task";
import { auth } from "@/auth.config";
@@ -340,85 +338,3 @@ export const permissionFormFields: PermissionInfo[] = [
description: "Provides access to billing settings and invoices",
},
];
// Helper function to handle API responses consistently
export const handleApiResponse = async (
response: Response,
pathToRevalidate?: string,
parse = true,
) => {
if (!response.ok) {
// Read error body safely; prefer JSON, fallback to plain text
const rawErrorText = await response.text().catch(() => "");
let errorData: any = null;
try {
errorData = rawErrorText ? JSON.parse(rawErrorText) : null;
} catch {
errorData = null;
}
const errorsArray = Array.isArray(errorData?.errors)
? (errorData.errors as any[])
: undefined;
const errorDetail =
errorsArray?.[0]?.detail ||
errorData?.error ||
errorData?.message ||
(rawErrorText && rawErrorText.trim()) ||
response.statusText ||
"Oops! Something went wrong.";
//5XX errors
if (response.status >= 500) {
throw new Error(
errorDetail ||
`Server error (${response.status}): The server encountered an error. Please try again later.`,
);
}
return errorsArray
? { error: errorDetail, errors: errorsArray, status: response.status }
: ({ error: errorDetail, status: response.status } as any);
}
// Handle empty or no-content responses gracefully (e.g., 204, empty body)
if (response.status === 204) {
if (pathToRevalidate && pathToRevalidate !== "") {
revalidatePath(pathToRevalidate);
}
return { success: true, status: response.status } as any;
}
// Read raw text to determine if there's a body to parse
const rawText = await response.text();
const hasBody = rawText && rawText.trim().length > 0;
if (!hasBody) {
if (pathToRevalidate && pathToRevalidate !== "") {
revalidatePath(pathToRevalidate);
}
return { success: true, status: response.status } as any;
}
let data: any;
try {
data = JSON.parse(rawText);
} catch (e) {
// If body isn't valid JSON, return as text payload
data = { data: rawText };
}
if (pathToRevalidate && pathToRevalidate !== "") {
revalidatePath(pathToRevalidate);
}
return parse ? parseStringify(data) : data;
};
// Helper function to handle API errors consistently
export const handleApiError = (error: unknown): { error: string } => {
console.error(error);
return {
error: getErrorMessage(error),
};
};
+3 -3
View File
@@ -35,7 +35,7 @@ export const convertVercelMessageToLangChainMessage = (
export const convertLangChainMessageToVercelMessage = (
message: BaseMessage,
) => {
switch (message.getType()) {
switch (message._getType()) {
case "human":
return { content: message.content, role: "user" };
case "ai":
@@ -45,7 +45,7 @@ export const convertLangChainMessageToVercelMessage = (
tool_calls: (message as AIMessage).tool_calls,
};
default:
return { content: message.content, role: message.getType() };
return { content: message.content, role: message._getType() };
}
};
@@ -60,7 +60,7 @@ export const getModelParams = (config: any): ModelParams => {
if (modelId.startsWith("gpt-5")) {
params.temperature = undefined;
params.reasoningEffort = "minimal";
params.reasoningEffort = "minimal" as const;
}
return params;
-2
View File
@@ -1,5 +1,3 @@
"use client";
import {
Bookmark,
CloudCog,
+85
View File
@@ -0,0 +1,85 @@
import { revalidatePath } from "next/cache";
import { getErrorMessage, parseStringify } from "./helper";
// Helper function to handle API responses consistently
export const handleApiResponse = async (
response: Response,
pathToRevalidate?: string,
parse = true,
) => {
if (!response.ok) {
// Read error body safely; prefer JSON, fallback to plain text
const rawErrorText = await response.text().catch(() => "");
let errorData: any = null;
try {
errorData = rawErrorText ? JSON.parse(rawErrorText) : null;
} catch {
errorData = null;
}
const errorsArray = Array.isArray(errorData?.errors)
? (errorData.errors as any[])
: undefined;
const errorDetail =
errorsArray?.[0]?.detail ||
errorData?.error ||
errorData?.message ||
(rawErrorText && rawErrorText.trim()) ||
response.statusText ||
"Oops! Something went wrong.";
//5XX errors
if (response.status >= 500) {
throw new Error(
errorDetail ||
`Server error (${response.status}): The server encountered an error. Please try again later.`,
);
}
return errorsArray
? { error: errorDetail, errors: errorsArray, status: response.status }
: ({ error: errorDetail, status: response.status } as any);
}
// Handle empty or no-content responses gracefully (e.g., 204, empty body)
if (response.status === 204) {
if (pathToRevalidate && pathToRevalidate !== "") {
revalidatePath(pathToRevalidate);
}
return { success: true, status: response.status } as any;
}
// Read raw text to determine if there's a body to parse
const rawText = await response.text();
const hasBody = rawText && rawText.trim().length > 0;
if (!hasBody) {
if (pathToRevalidate && pathToRevalidate !== "") {
revalidatePath(pathToRevalidate);
}
return { success: true, status: response.status } as any;
}
let data: any;
try {
data = JSON.parse(rawText);
} catch (e) {
// If body isn't valid JSON, return as text payload
data = { data: rawText };
}
if (pathToRevalidate && pathToRevalidate !== "") {
revalidatePath(pathToRevalidate);
}
return parse ? parseStringify(data) : data;
};
// Helper function to handle API errors consistently
export const handleApiError = (error: unknown): { error: string } => {
console.error(error);
return {
error: getErrorMessage(error),
};
};