From ca4bd4a619cfb613c19368c85f84a4705de8b067 Mon Sep 17 00:00:00 2001 From: Nicolas Meienberger Date: Wed, 3 Sep 2025 21:16:44 +0200 Subject: [PATCH] feat(client): test mount from form --- .../app/components/create-volume-dialog.tsx | 77 +++++++++++++++++-- apps/client/app/routes/home.tsx | 4 +- apps/server/src/index.ts | 10 +-- .../src/modules/backends/nfs/nfs-backend.ts | 1 + packages/schemas/src/index.ts | 2 +- 5 files changed, 78 insertions(+), 16 deletions(-) diff --git a/apps/client/app/components/create-volume-dialog.tsx b/apps/client/app/components/create-volume-dialog.tsx index 1b53ace..5220011 100644 --- a/apps/client/app/components/create-volume-dialog.tsx +++ b/apps/client/app/components/create-volume-dialog.tsx @@ -1,8 +1,10 @@ import { arktypeResolver } from "@hookform/resolvers/arktype"; import { volumeConfigSchema } from "@ironmount/schemas"; import { type } from "arktype"; -import { Plus } from "lucide-react"; +import { CheckCircle, Loader2, Plus, XCircle } from "lucide-react"; +import { useState } from "react"; import { useForm } from "react-hook-form"; +import { testConnection } from "~/api-client"; import { slugify } from "~/lib/utils"; import { Button } from "./ui/button"; import { @@ -17,6 +19,9 @@ import { 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"; +import { useMutation } from "@tanstack/react-query"; +import { testConnectionMutation } from "~/api-client/@tanstack/react-query.gen"; +import { toast } from "sonner"; export const formSchema = type({ name: "2<=string<=32", @@ -30,6 +35,9 @@ type Props = { }; export const CreateVolumeDialog = ({ open, setOpen, onSubmit }: Props) => { + const [testStatus, setTestStatus] = useState<"idle" | "loading" | "success" | "error">("idle"); + const [testMessage, setTestMessage] = useState(""); + const form = useForm({ resolver: arktypeResolver(formSchema), defaultValues: { @@ -38,8 +46,36 @@ export const CreateVolumeDialog = ({ open, setOpen, onSubmit }: Props) => { }, }); + const testBackendConnection = useMutation({ + ...testConnectionMutation(), + onMutate: () => { + 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 watchedBackend = form.watch("backend"); + const handleTestConnection = async () => { + const formValues = form.getValues(); + + testBackendConnection.mutate({ + body: { config: formValues }, + }); + }; + return ( @@ -165,11 +201,40 @@ export const CreateVolumeDialog = ({ open, setOpen, onSubmit }: Props) => { /> )} - {/* {createVolume.error && ( */} - {/*
*/} - {/* {createVolume.error.message} */} - {/*
*/} - {/* )} */} + {watchedBackend === "nfs" && ( +
+
+ +
+ {testMessage && ( +
+ {testMessage} +
+ )} +
+ )}