import { arktypeResolver } from "@hookform/resolvers/arktype"; import { volumeConfigSchema } from "@ironmount/schemas"; import { useMutation } from "@tanstack/react-query"; import { type } from "arktype"; import { CheckCircle, Loader2, XCircle } from "lucide-react"; import { useState } from "react"; import { useForm } from "react-hook-form"; import { testConnectionMutation } from "~/api-client/@tanstack/react-query.gen"; import { slugify } from "~/lib/utils"; import { Button } from "./ui/button"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "./ui/form"; import { Input } from "./ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select"; export const formSchema = type({ name: "2<=string<=32", }).and(volumeConfigSchema); type FormValues = typeof formSchema.inferIn; type Props = { onSubmit: (values: FormValues) => void; mode?: "create" | "update"; initialValues?: Partial; formId?: string; }; export const CreateVolumeForm = ({ onSubmit, mode = "create", initialValues, formId }: Props) => { const form = useForm({ resolver: arktypeResolver(formSchema), defaultValues: initialValues, }); const { watch, getValues } = form; const watchedBackend = watch("backend"); const [testStatus, setTestStatus] = useState<"idle" | "loading" | "success" | "error">("idle"); const [testMessage, setTestMessage] = useState(""); const testBackendConnection = useMutation({ ...testConnectionMutation(), onMutate: () => { setTestMessage(""); setTestStatus("loading"); }, onError: () => { setTestStatus("error"); setTestMessage("Failed to test connection. Please try again."); }, onSuccess: (data) => { if (data?.success) { setTestStatus("success"); setTestMessage(data.message); } else { setTestStatus("error"); setTestMessage(data?.message || "Connection test failed"); } }, }); const handleTestConnection = async () => { const formValues = getValues(); if (formValues.backend === "nfs" || formValues.backend === "smb" || formValues.backend === "webdav") { testBackendConnection.mutate({ body: { config: formValues }, }); } }; return (
( Name field.onChange(slugify(e.target.value))} max={32} min={1} disabled={mode === "update"} className={mode === "update" ? "bg-gray-50" : ""} /> Unique identifier for the volume. )} /> ( Backend Choose the storage backend for this volume. )} /> {watchedBackend === "nfs" && ( <> ( Server NFS server IP address or hostname. )} /> ( Export Path Path to the NFS export on the server. )} /> ( Port field.onChange(parseInt(e.target.value, 10) || undefined)} /> NFS server port (default: 2049). )} /> ( Version NFS protocol version to use. )} /> )} {watchedBackend === "webdav" && ( <> ( Server WebDAV server hostname or IP address. )} /> ( Path Path to the WebDAV directory on the server. )} /> ( Username (Optional) Username for WebDAV authentication (optional). )} /> ( Password (Optional) Password for WebDAV authentication (optional). )} /> ( Port field.onChange(parseInt(e.target.value, 10) || undefined)} /> WebDAV server port (default: 80 for HTTP, 443 for HTTPS). )} /> ( Use SSL/HTTPS
field.onChange(e.target.checked)} className="rounded border-gray-300" /> Enable HTTPS for secure connections
Use HTTPS instead of HTTP for secure connections.
)} /> )} {watchedBackend === "smb" && ( <> ( Server SMB server IP address or hostname. )} /> ( Share SMB share name on the server. )} /> ( Username Username for SMB authentication. )} /> ( Password Password for SMB authentication. )} /> ( SMB Version SMB protocol version to use (default: 3.0). )} /> ( Domain (Optional) Domain or workgroup for authentication (optional). )} /> ( Port field.onChange(parseInt(e.target.value, 10) || undefined)} /> SMB server port (default: 445). )} /> )} {watchedBackend === "smb" && (
{testMessage && (
{testMessage}
)}
)} {watchedBackend === "nfs" && (
{testMessage && (
{testMessage}
)}
)} {watchedBackend === "webdav" && (
{testMessage && (
{testMessage}
)}
)} ); };