Merge pull request #77 from prowler-cloud/PRWLR-5141-Prowler-V-release-final-touches-for-Launch-Scan-page

Prwlr 5141 prowler v release final touches for launch scan page
This commit is contained in:
Pablo Lara
2024-11-06 15:57:02 +01:00
committed by GitHub
5 changed files with 34 additions and 216 deletions
+9 -63
View File
@@ -3,15 +3,10 @@ import { Suspense } from "react";
import { getProviders } from "@/actions/providers";
import { getScans } from "@/actions/scans";
import {
FilterControls,
filterProviders,
filterScans,
} from "@/components/filters";
import { FilterControls, filterScans } from "@/components/filters";
import { SkeletonTableScans } from "@/components/scans/table";
import { ColumnProviderScans } from "@/components/scans/table/provider-scans";
import { ColumnGetScans } from "@/components/scans/table/scans";
import { ColumnGetScansSchedule } from "@/components/scans/table/schedule-scans";
import { Header } from "@/components/ui";
import { DataTable } from "@/components/ui/table";
import { SearchParamsProps } from "@/types";
@@ -32,75 +27,26 @@ export default async function Scans({
<Spacer y={8} />
<div className="grid grid-cols-12 items-start gap-4">
<div className="col-span-12 lg:col-span-4">
<Suspense key={searchParamsKey} fallback={<SkeletonTableScans />}>
<SSRDataTableProviders />
</Suspense>
</div>
<div className="col-span-12 lg:col-span-6">
<Suspense key={searchParamsKey} fallback={<SkeletonTableScans />}>
<SSRDataTableScansSchedule searchParams={searchParams} />
</Suspense>
</div>
<div className="col-span-12">
<Suspense key={searchParamsKey} fallback={<SkeletonTableScans />}>
<SSRDataTableScans searchParams={searchParams} />
</Suspense>
</div>
<div className="col-span-12 lg:col-span-4">
<Suspense key={searchParamsKey} fallback={<SkeletonTableScans />}>
<SSRDataTableProviders />
</Suspense>
</div>
</div>
</>
);
}
const SSRDataTableProviders = async () => {
// const page = parseInt(searchParams.page?.toString() || "1", 10);
// const sort = searchParams.sort?.toString();
// Extract all filter parameters
// const filters = Object.fromEntries(
// Object.entries(searchParams).filter(([key]) => key.startsWith("filter[")),
// );
// Extract query from filters
// const query = (filters["filter[search]"] as string) || "";
const providersData = await getProviders({ page: 1 });
const filters = { "filter[connected]": "true" };
const providersData = await getProviders({ page: 1, filters });
return (
<DataTable
columns={ColumnProviderScans}
data={providersData?.data || []}
metadata={providersData?.meta}
customFilters={filterProviders}
/>
);
};
const SSRDataTableScansSchedule = async ({
searchParams,
}: {
searchParams: SearchParamsProps;
}) => {
const page = parseInt(searchParams.page?.toString() || "1", 10);
const sort = searchParams.sort?.toString();
// Extract all filter parameters
const filters = Object.fromEntries(
Object.entries(searchParams).filter(([key]) => key.startsWith("filter[")),
);
// Extract query from filters
const query = (filters["filter[search]"] as string) || "";
const scansData = await getScans({ query, page, sort, filters });
return (
<DataTable
columns={ColumnGetScansSchedule}
data={scansData?.data || []}
metadata={scansData?.meta}
customFilters={filterScans}
/>
<DataTable columns={ColumnProviderScans} data={providersData?.data || []} />
);
};
+25 -31
View File
@@ -4,8 +4,6 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { Icon } from "@iconify/react";
import { Button, Checkbox, Divider, Link } from "@nextui-org/react";
import { useRouter } from "next/navigation";
import { useEffect, useState } from "react";
import { useFormState } from "react-dom";
import { useForm } from "react-hook-form";
import { z } from "zod";
@@ -40,35 +38,43 @@ export const AuthForm = ({ type }: { type: string }) => {
},
});
const [state, dispatch] = useFormState(authenticate, undefined);
const [isLoading, setIsLoading] = useState(false);
const isLoading = form.formState.isSubmitting;
const { toast } = useToast();
useEffect(() => {
if (state?.message === "Success") {
router.push("/");
}
}, [state]);
const onSubmit = async (data: z.infer<typeof formSchema>) => {
if (type === "sign-in") {
setIsLoading(true);
dispatch({
const result = await authenticate(null, {
email: data.email.toLowerCase(),
password: data.password,
});
setIsLoading(false);
if (result?.message === "Success") {
router.push("/");
} else if (result?.errors && "credentials" in result.errors) {
form.setError("email", {
type: "server",
message: result.errors.credentials ?? "Incorrect email or password",
});
} else {
toast({
variant: "destructive",
title: "Oops! Something went wrong",
description: "An unexpected error occurred. Please try again.",
});
}
}
if (type === "sign-up") {
setIsLoading(true);
const newUser = await createNewUser(data);
setIsLoading(false);
if (!newUser.errors) {
toast({
title: "Success!",
description: "The user was registered successfully.",
});
form.reset();
router.push("/sign-in");
}
if (newUser?.errors && newUser.errors.length > 0) {
} else {
newUser.errors.forEach((error: ApiError) => {
const errorMessage = error.detail;
switch (error.source.pointer) {
@@ -98,18 +104,6 @@ export const AuthForm = ({ type }: { type: string }) => {
});
}
});
} else {
toast({
title: "Success!",
description: "The user was registered successfully.",
});
form.reset({
name: "",
company: "",
email: "",
password: "",
termsAndConditions: false,
});
}
}
};
@@ -222,7 +216,7 @@ export const AuthForm = ({ type }: { type: string }) => {
</>
)}
{state?.message === "Credentials error" && (
{form.formState.errors?.email && (
<div className="flex flex-row items-center gap-2 text-system-error">
<NotificationIcon size={16} />
<p className="text-s">No user found</p>
@@ -1,83 +0,0 @@
"use client";
import { ColumnDef } from "@tanstack/react-table";
import { PlusIcon } from "@/components/icons";
import { DateWithTime, EntityInfoShort } from "@/components/ui/entities";
import { TriggerSheet } from "@/components/ui/sheet";
import { DataTableColumnHeader, StatusBadge } from "@/components/ui/table";
import { ScanProps } from "@/types";
import { DataTableRowActions } from "../scans/data-table-row-actions";
import { DataTableRowDetails } from ".";
const getScanData = (row: { original: ScanProps }) => {
return row.original;
};
export const ColumnGetScansSchedule: ColumnDef<ScanProps>[] = [
{
accessorKey: "name",
header: ({ column }) => (
<DataTableColumnHeader column={column} title={"Name"} param="name" />
),
cell: ({ row }) => {
const {
attributes: { name },
} = getScanData(row);
return <EntityInfoShort entityAlias={name} entityId={row.original.id} />;
},
},
{
accessorKey: "status",
header: ({ column }) => (
<DataTableColumnHeader column={column} title={"Status"} param="state" />
),
cell: ({ row }) => {
const {
attributes: { state },
} = getScanData(row);
return <StatusBadge status={state} />;
},
},
{
accessorKey: "scheduled_at",
header: ({ column }) => (
<DataTableColumnHeader
column={column}
title={"Scheduled at"}
param="scheduled_at"
/>
),
cell: ({ row }) => {
const {
attributes: { scheduled_at },
} = getScanData(row);
return <DateWithTime dateTime={scheduled_at} />;
},
},
{
id: "moreInfo",
header: "Details",
cell: ({ row }) => {
return (
<TriggerSheet
triggerComponent={<PlusIcon />}
title="Scan Details"
description="View the scan details"
>
<DataTableRowDetails entityId={row.original.id} />
</TriggerSheet>
);
},
},
{
id: "actions",
cell: ({ row }) => {
return <DataTableRowActions row={row} />;
},
},
];
@@ -1,37 +0,0 @@
"use client";
import { useEffect, useState } from "react";
import { getScan } from "@/actions/scans";
import { ScanDetail, SkeletonTableScans } from "@/components/scans/table";
import { ScanProps } from "@/types";
export const DataTableRowDetails = ({ entityId }: { entityId: string }) => {
const [scanDetails, setScanDetails] = useState<ScanProps | null>(null);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const fetchScanDetails = async () => {
try {
const result = await getScan(entityId);
setScanDetails(result?.data);
} catch (error) {
console.error("Error fetching scan details:", error);
} finally {
setIsLoading(false);
}
};
fetchScanDetails();
}, [entityId]);
if (isLoading) {
return <SkeletonTableScans />;
}
if (!scanDetails) {
return <div>No scan details available</div>;
}
return <ScanDetail scanDetails={scanDetails} />;
};
@@ -1,2 +0,0 @@
export * from "./column-get-scans-schedule";
export * from "./data-table-row-details";