mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 12:31:54 +00:00
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:
@@ -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 || []} />
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -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";
|
||||
Reference in New Issue
Block a user