"use client"; import { zodResolver } from "@hookform/resolvers/zod"; import { Icon } from "@iconify/react"; import { Loader2 } from "lucide-react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; import { deleteCredentials } from "@/actions/providers"; import { CheckIcon, ConnectionPending } from "@/components/icons"; import { Button } from "@/components/shadcn"; import { Form } from "@/components/shadcn/form"; import { testProviderConnection, type TestConnectionResult, } from "@/lib/provider-helpers"; import { ProviderType, testConnectionFormSchema } from "@/types"; import { CONNECTION_CHECK_STATUS } from "@/types/providers"; import { ProviderConnectionInfo } from "./provider-connection-info"; type FormValues = z.input; export interface TestConnectionProviderData { data: { id: string; type: string; attributes: { uid: string; connection: { connected: boolean | null; last_checked_at: string | null; }; provider: ProviderType; alias: string; scanner_args: Record; }; relationships: { secret: { data: { type: string; id: string; } | null; }; }; }; } interface TestConnectionFormProps { searchParams: { type: string; id: string; updated: string }; providerData: TestConnectionProviderData; onSuccess?: () => void; onResetCredentials?: () => void; formId?: string; hideActions?: boolean; onLoadingChange?: (isLoading: boolean) => void; } export const TestConnectionForm = ({ searchParams, providerData, onSuccess, onResetCredentials: onResetCredentialsCallback, formId, hideActions = false, onLoadingChange, }: TestConnectionFormProps) => { const router = useRouter(); const providerId = searchParams.id; const [apiErrorMessage, setApiErrorMessage] = useState(null); const [connectionStatus, setConnectionStatus] = useState(null); const [isResettingCredentials, setIsResettingCredentials] = useState(false); const formSchema = testConnectionFormSchema; const form = useForm({ resolver: zodResolver(formSchema), defaultValues: { providerId, }, }); const isLoading = form.formState.isSubmitting; const isUpdated = searchParams?.updated === "true"; useEffect(() => { onLoadingChange?.(isLoading || isResettingCredentials); }, [isLoading, isResettingCredentials, onLoadingChange]); const onSubmitClient = async (values: FormValues) => { setApiErrorMessage(null); const result = await testProviderConnection(values.providerId); if (result.error === "Not found.") { setApiErrorMessage(result.error); return; } setConnectionStatus(result); if (result.status === CONNECTION_CHECK_STATUS.SUCCESS) { if (onSuccess) { onSuccess(); return; } return router.push("/providers"); } }; const handleResetCredentials = async () => { setIsResettingCredentials(true); // Check if provider the provider has no credentials const providerSecretId = providerData?.data?.relationships?.secret?.data?.id; const hasNoCredentials = !providerSecretId; if (hasNoCredentials) { if (onResetCredentialsCallback) { onResetCredentialsCallback(); } else { router.push("/providers"); } setIsResettingCredentials(false); return; } // If provider has credentials, delete them first try { await deleteCredentials(providerSecretId); if (onResetCredentialsCallback) { onResetCredentialsCallback(); } else { router.push("/providers"); } } catch (error) { console.error("Failed to delete credentials:", error); } finally { setIsResettingCredentials(false); } }; return (
Check connection

{!isUpdated ? "After a successful connection, continue to the launch step to configure and start your scan." : "A successful connection will redirect you to the providers page."}

{apiErrorMessage && (

{apiErrorMessage}

)} {connectionStatus?.status === CONNECTION_CHECK_STATUS.FAILED && ( <>

{connectionStatus.error || "Unknown error"}

It seems there was an issue with your credentials. Please review your credentials and try again.

)} {connectionStatus?.status === CONNECTION_CHECK_STATUS.PENDING && (
{/* Static, not spinning: nothing is polling any more once the wait is exhausted, so an animated spinner would misrepresent this as still in progress. */}

{connectionStatus.error || "The connection test is still running. Refresh in a moment to see the result."}

)} {isUpdated && !connectionStatus?.error && (

Check the new credentials and test the connection.

)} {!hideActions && (
{apiErrorMessage ? ( ) : connectionStatus?.status === CONNECTION_CHECK_STATUS.FAILED ? ( ) : ( )}
)} ); };