diff --git a/ui/app/(prowler)/providers/(set-up-provider)/add-credentials/page.tsx b/ui/app/(prowler)/providers/(set-up-provider)/add-credentials/page.tsx index 6a525990fa..fce06d1a88 100644 --- a/ui/app/(prowler)/providers/(set-up-provider)/add-credentials/page.tsx +++ b/ui/app/(prowler)/providers/(set-up-provider)/add-credentials/page.tsx @@ -1,35 +1,30 @@ -import { redirect } from "next/navigation"; import React from "react"; import { ViaCredentialsForm, ViaRoleForm, } from "@/components/providers/workflow/forms"; +import { SelectViaAWS } from "@/components/providers/workflow/forms/select-via-aws/select-via-aws"; interface Props { searchParams: { type: string; id: string; via?: string }; } export default function AddCredentialsPage({ searchParams }: Props) { - if ( - !searchParams.type || - !searchParams.id || - (searchParams.type === "aws" && !searchParams.via) - ) { - redirect("/providers/connect-account"); - } - - const useCredentialsForm = - (searchParams.type === "aws" && searchParams.via === "credentials") || - (searchParams.type !== "aws" && !searchParams.via); - - const useRoleForm = - searchParams.type === "aws" && searchParams.via === "role"; - return ( <> - {useCredentialsForm && } - {useRoleForm && } + {searchParams.type === "aws" && !searchParams.via && ( + + )} + + {((searchParams.type === "aws" && searchParams.via === "credentials") || + searchParams.type !== "aws") && ( + + )} + + {searchParams.type === "aws" && searchParams.via === "role" && ( + + )} ); } diff --git a/ui/components/providers/workflow/forms/connect-account-form.tsx b/ui/components/providers/workflow/forms/connect-account-form.tsx index 800bfd5210..5c0fbf71ac 100644 --- a/ui/components/providers/workflow/forms/connect-account-form.tsx +++ b/ui/components/providers/workflow/forms/connect-account-form.tsx @@ -19,7 +19,6 @@ import { Form } from "@/components/ui/form"; import { addProvider } from "../../../../actions/providers/providers"; import { addProviderFormSchema, ApiError } from "../../../../types"; import { RadioGroupProvider } from "../../radio-group-provider"; -import { RadioGroupAWSViaCredentialsForm } from "./radio-group-aws-via-credentials-form"; export type FormValues = z.infer; @@ -36,7 +35,6 @@ export const ConnectAccountForm = () => { providerType: undefined, providerUid: "", providerAlias: "", - awsCredentialsType: "", }, }); @@ -51,55 +49,60 @@ export const ConnectAccountForm = () => { ([key, value]) => value !== undefined && formData.append(key, value), ); - const data = await addProvider(formData); - - if (data?.errors && data.errors.length > 0) { - // Handle server-side validation errors - data.errors.forEach((error: ApiError) => { - const errorMessage = error.detail; - const pointer = error.source?.pointer; - - switch (pointer) { - case "/data/attributes/provider": - form.setError("providerType", { - type: "server", - message: errorMessage, - }); - break; - case "/data/attributes/uid": - case "/data/attributes/__all__": - form.setError("providerUid", { - type: "server", - message: errorMessage, - }); - break; - case "/data/attributes/alias": - form.setError("providerAlias", { - type: "server", - message: errorMessage, - }); - break; - default: - toast({ - variant: "destructive", - title: "Oops! Something went wrong", - description: errorMessage, - }); - } + try { + const data = await addProvider(formData); + + if (data?.errors && data.errors.length > 0) { + // Handle server-side validation errors + data.errors.forEach((error: ApiError) => { + const errorMessage = error.detail; + const pointer = error.source?.pointer; + + switch (pointer) { + case "/data/attributes/provider": + form.setError("providerType", { + type: "server", + message: errorMessage, + }); + break; + case "/data/attributes/uid": + case "/data/attributes/__all__": + form.setError("providerUid", { + type: "server", + message: errorMessage, + }); + break; + case "/data/attributes/alias": + form.setError("providerAlias", { + type: "server", + message: errorMessage, + }); + break; + default: + toast({ + variant: "destructive", + title: "Oops! Something went wrong", + description: errorMessage, + }); + } + }); + return; + } else { + // Go to the next step after successful submission + const { + id, + attributes: { provider: providerType }, + } = data.data; + + router.push(`/providers/add-credentials?type=${providerType}&id=${id}`); + } + } catch (error: any) { + console.error("Error during submission:", error); + toast({ + variant: "destructive", + title: "Submission Error", + description: error.message || "Something went wrong. Please try again.", }); - return; - } else { - // Navigate to the next step after successful submission - const { - id, - attributes: { provider: providerType }, - } = data.data; - const credentialsParam = values.awsCredentialsType - ? `&via=${values.awsCredentialsType}` - : ""; - router.push( - `/providers/add-credentials?type=${providerType}&id=${id}${credentialsParam}`, - ); } }; @@ -158,13 +161,6 @@ export const ConnectAccountForm = () => { isRequired={false} isInvalid={!!form.formState.errors.providerAlias} /> - {providerType === "aws" && ( - - )} )} {/* Navigation buttons */} diff --git a/ui/components/providers/workflow/forms/radio-group-aws-via-credentials-form.tsx b/ui/components/providers/workflow/forms/radio-group-aws-via-credentials-form.tsx index 7a870c79ff..bb53c5a5b9 100644 --- a/ui/components/providers/workflow/forms/radio-group-aws-via-credentials-form.tsx +++ b/ui/components/providers/workflow/forms/radio-group-aws-via-credentials-form.tsx @@ -7,18 +7,18 @@ import { Control, Controller } from "react-hook-form"; import { CustomRadio } from "@/components/ui/custom"; import { FormMessage } from "@/components/ui/form"; -import { FormValues } from "./connect-account-form"; - type RadioGroupAWSViaCredentialsFormProps = { - control: Control; + control: Control; isInvalid: boolean; errorMessage?: string; + onChange?: (value: string) => void; }; export const RadioGroupAWSViaCredentialsForm = ({ control, isInvalid, errorMessage, + onChange, }: RadioGroupAWSViaCredentialsFormProps) => { return ( { + field.onChange(value); + if (onChange) { + onChange(value); + } + }} >
Using IAM Role diff --git a/ui/components/providers/workflow/forms/select-via-aws/index.ts b/ui/components/providers/workflow/forms/select-via-aws/index.ts new file mode 100644 index 0000000000..8dd9822258 --- /dev/null +++ b/ui/components/providers/workflow/forms/select-via-aws/index.ts @@ -0,0 +1 @@ +export * from "./select-via-aws"; diff --git a/ui/components/providers/workflow/forms/select-via-aws/select-via-aws.tsx b/ui/components/providers/workflow/forms/select-via-aws/select-via-aws.tsx new file mode 100644 index 0000000000..59197bb40e --- /dev/null +++ b/ui/components/providers/workflow/forms/select-via-aws/select-via-aws.tsx @@ -0,0 +1,38 @@ +"use client"; + +import { useRouter } from "next/navigation"; +import { useForm } from "react-hook-form"; + +import { Form } from "@/components/ui/form"; + +import { RadioGroupAWSViaCredentialsForm } from "../radio-group-aws-via-credentials-form"; + +interface SelectViaAWSProps { + initialVia?: string; +} + +export const SelectViaAWS = ({ initialVia }: SelectViaAWSProps) => { + const router = useRouter(); + const form = useForm({ + defaultValues: { + awsCredentialsType: initialVia || "", + }, + }); + + const handleSelectionChange = (value: string) => { + const url = new URL(window.location.href); + url.searchParams.set("via", value); + router.push(url.toString()); + }; + + return ( +
+ + + ); +}; diff --git a/ui/components/providers/workflow/forms/via-credentials-form.tsx b/ui/components/providers/workflow/forms/via-credentials-form.tsx index 3ecb11da41..6c0bd0fe37 100644 --- a/ui/components/providers/workflow/forms/via-credentials-form.tsx +++ b/ui/components/providers/workflow/forms/via-credentials-form.tsx @@ -1,8 +1,8 @@ "use client"; import { zodResolver } from "@hookform/resolvers/zod"; -import { ChevronRightIcon } from "lucide-react"; -import { useRouter } from "next/navigation"; +import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react"; +import { useRouter, useSearchParams } from "next/navigation"; import { Control, useForm } from "react-hook-form"; import * as z from "zod"; @@ -46,6 +46,15 @@ export const ViaCredentialsForm = ({ const router = useRouter(); const { toast } = useToast(); + const searchParamsObj = useSearchParams(); + + // Handler for back button + const handleBackStep = () => { + const currentParams = new URLSearchParams(window.location.search); + currentParams.delete("via"); + router.push(`?${currentParams.toString()}`); + }; + const providerType = searchParams.type; const providerId = searchParams.id; const formSchema = addCredentialsFormSchema(providerType); @@ -199,6 +208,21 @@ export const ViaCredentialsForm = ({ )}
+ {searchParamsObj.get("via") === "credentials" && ( + } + isDisabled={isLoading} + > + Back + + )} { + const currentParams = new URLSearchParams(window.location.search); + currentParams.delete("via"); + router.push(`?${currentParams.toString()}`); + }; + const providerType = searchParams.type; const providerId = searchParams.id; @@ -54,7 +63,6 @@ export const ViaRoleForm = ({ const isLoading = form.formState.isSubmitting; const onSubmitClient = async (values: FormSchemaType) => { - console.log("via ROLE form", values); const formData = new FormData(); Object.entries(values).forEach( @@ -106,6 +114,21 @@ export const ViaRoleForm = ({ )}
+ {searchParamsObj.get("via") === "role" && ( + } + isDisabled={isLoading} + > + Back + + )} } + endContent={!isLoading && } > - {isLoading ? <>Loading : Save} + {isLoading ? <>Loading : Next}
diff --git a/ui/types/formSchemas.ts b/ui/types/formSchemas.ts index 4238df3ef2..cc0221add7 100644 --- a/ui/types/formSchemas.ts +++ b/ui/types/formSchemas.ts @@ -31,6 +31,12 @@ export const scheduleScanFormSchema = () => scheduleDate: z.string(), }); +export const awsCredentialsTypeSchema = z.object({ + awsCredentialsType: z.string().min(1, { + message: "Please select the type of credentials you want to use", + }), +}); + export const addProviderFormSchema = z .object({ providerType: z.enum(["aws", "azure", "gcp", "kubernetes"], { @@ -43,9 +49,6 @@ export const addProviderFormSchema = z providerType: z.literal("aws"), providerAlias: z.string(), providerUid: z.string(), - awsCredentialsType: z.string().min(1, { - message: "Please select the type of credentials you want to use", - }), }), z.object({ providerType: z.literal("azure"),