chore: render an message if there is no data for compliances

This commit is contained in:
Pablo Lara
2024-11-18 07:45:19 +01:00
parent e92bbffc53
commit eb40369c30
6 changed files with 120 additions and 29 deletions
+34
View File
@@ -0,0 +1,34 @@
"use server";
import { revalidatePath } from "next/cache";
import { auth } from "@/auth.config";
import { parseStringify } from "@/lib";
export const getCompliancesOverview = async ({
scanId,
}: {
scanId: string;
}) => {
const session = await auth();
const keyServer = process.env.API_BASE_URL;
const url = new URL(
`${keyServer}/compliance-overviews?filter[scan_id]=${scanId}`,
);
try {
const compliances = await fetch(url.toString(), {
headers: {
Accept: "application/vnd.api+json",
Authorization: `Bearer ${session?.accessToken}`,
},
});
const data = await compliances.json();
const parsedData = parseStringify(data);
revalidatePath("/compliance");
return parsedData;
} catch (error) {
// eslint-disable-next-line no-console
console.error("Error fetching providers:", error);
return undefined;
}
};
+1
View File
@@ -0,0 +1 @@
export * from "./compliances";
+1
View File
@@ -0,0 +1 @@
export * from "./invitation";
+2
View File
@@ -42,6 +42,7 @@ export const getInvitations = async ({
revalidatePath("/invitations");
return parsedData;
} catch (error) {
// eslint-disable-next-line no-console
console.error("Error fetching invitations:", error);
return undefined;
}
@@ -117,6 +118,7 @@ export const updateInvite = async (formData: FormData) => {
revalidatePath("/invitations");
return parseStringify(data);
} catch (error) {
// eslint-disable-next-line no-console
console.error("Error updating invitation:", error);
return {
error: getErrorMessage(error),
+35 -29
View File
@@ -1,15 +1,14 @@
import { Spacer } from "@nextui-org/react";
import { redirect } from "next/navigation";
import { Suspense } from "react";
import { getCompliance } from "@/actions/compliance";
import { getCompliancesOverview } from "@/actions/compliances";
import {
ComplianceCard,
ComplianceSkeletonGrid,
} from "@/components/compliance";
import { FilterControls } from "@/components/filters";
import { Header } from "@/components/ui";
import { SearchParamsProps } from "@/types";
import { ComplianceOverviewData, SearchParamsProps } from "@/types";
export default async function Compliance({
searchParams,
@@ -23,41 +22,48 @@ export default async function Compliance({
<Header title="Compliance" icon="fluent-mdl2:compliance-audit" />
<Spacer y={4} />
<FilterControls mutedFindings={false} />
<Spacer y={4} />
<Spacer y={8} />
<Suspense key={searchParamsKey} fallback={<ComplianceSkeletonGrid />}>
<SSRComplianceGrid searchParams={searchParams} />
<SSRComplianceGrid />
</Suspense>
</>
);
}
const SSRComplianceGrid = async ({
searchParams,
}: {
searchParams: SearchParamsProps;
}) => {
const page = parseInt(searchParams.page?.toString() || "1", 10);
const compliancesData = await getCompliance({ page });
const [compliances] = await Promise.all([compliancesData]);
const SSRComplianceGrid = async () => {
// const scanId = "01929f57-c0ee-7553-be0b-cbde006fb6f7";
const scanId = "0193358c-bd7f-7eec-b13a-2d4a648b8df";
const compliancesData = await getCompliancesOverview({ scanId });
console.log(compliancesData, "compliancesData");
if (compliances?.errors) redirect("/compliance");
if (compliancesData?.errors?.length > 0) {
return (
<div className="flex h-full items-center justify-center">
<div className="text-default-500">There is no compliance data.</div>
</div>
);
}
return (
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-3 3xl:grid-cols-4">
{compliances.compliance?.data.map((compliance: any) => (
<ComplianceCard
key={compliance.id}
title={compliance.attributes.title}
passingRequirements={compliance.attributes.passingRequirements}
totalRequirements={compliance.attributes.totalRequirements}
prevPassingRequirements={
compliance.lastScan.attributes.passingRequirements
}
prevTotalRequirements={
compliance.lastScan.attributes.totalRequirements
}
/>
))}
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-3">
{compliancesData?.data?.map((compliance: ComplianceOverviewData) => {
const { attributes } = compliance;
const {
framework,
requirements_status: { passed, total },
} = attributes;
return (
<ComplianceCard
key={compliance.id}
title={framework}
passingRequirements={passed}
totalRequirements={total}
prevPassingRequirements={passed}
prevTotalRequirements={total}
/>
);
})}
</div>
);
};
+47
View File
@@ -100,6 +100,53 @@ export interface ApiError {
};
code: string;
}
export interface CompliancesOverview {
links: {
first: string;
last: string;
next: string | null;
prev: string | null;
};
data: ComplianceOverviewData[];
meta: {
pagination: {
page: number;
pages: number;
count: number;
};
version: string;
};
}
export interface ComplianceOverviewData {
type: "compliance-overviews";
id: string;
attributes: {
inserted_at: string;
compliance_id: string;
framework: string;
version: string;
requirements_status: {
passed: number;
failed: number;
manual: number;
total: number;
};
region: string;
provider_type: string;
};
relationships: {
scan: {
data: {
type: "scans";
id: string;
};
};
};
links: {
self: string;
};
}
export interface InvitationProps {
type: "invitations";