import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; import { Cog } from "lucide-react"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; enum BuildType { dockerfile = "dockerfile", heroku_buildpacks = "heroku_buildpacks", paketo_buildpacks = "paketo_buildpacks", nixpacks = "nixpacks", static = "static", } const mySchema = z.discriminatedUnion("buildType", [ z.object({ buildType: z.literal("dockerfile"), dockerfile: z .string({ required_error: "Dockerfile path is required", invalid_type_error: "Dockerfile path is required", }) .min(1, "Dockerfile required"), dockerContextPath: z.string().nullable().default(""), dockerBuildStage: z.string().nullable().default(""), }), z.object({ buildType: z.literal("heroku_buildpacks"), herokuVersion: z.string().nullable().default(""), }), z.object({ buildType: z.literal("paketo_buildpacks"), }), z.object({ buildType: z.literal("nixpacks"), publishDirectory: z.string().optional(), }), z.object({ buildType: z.literal("static"), }), ]); type AddTemplate = z.infer; interface Props { applicationId: string; } export const ShowBuildChooseForm = ({ applicationId }: Props) => { const { mutateAsync, isLoading } = api.application.saveBuildType.useMutation(); const { data, refetch } = api.application.one.useQuery( { applicationId, }, { enabled: !!applicationId, }, ); const form = useForm({ defaultValues: { buildType: BuildType.nixpacks, }, resolver: zodResolver(mySchema), }); const buildType = form.watch("buildType"); useEffect(() => { if (data) { if (data.buildType === "dockerfile") { form.reset({ buildType: data.buildType, ...(data.buildType && { dockerfile: data.dockerfile || "", dockerContextPath: data.dockerContextPath || "", dockerBuildStage: data.dockerBuildStage || "", }), }); } else if (data.buildType === "heroku_buildpacks") { form.reset({ buildType: data.buildType, ...(data.buildType && { herokuVersion: data.herokuVersion || "", }), }); } else { form.reset({ buildType: data.buildType, publishDirectory: data.publishDirectory || undefined, }); } } }, [form.formState.isSubmitSuccessful, form.reset, data, form]); const onSubmit = async (data: AddTemplate) => { await mutateAsync({ applicationId, buildType: data.buildType, publishDirectory: data.buildType === "nixpacks" ? data.publishDirectory : null, dockerfile: data.buildType === "dockerfile" ? data.dockerfile : null, dockerContextPath: data.buildType === "dockerfile" ? data.dockerContextPath : null, dockerBuildStage: data.buildType === "dockerfile" ? data.dockerBuildStage : null, herokuVersion: data.buildType === "heroku_buildpacks" ? data.herokuVersion : null, }) .then(async () => { toast.success("Build type saved"); await refetch(); }) .catch(() => { toast.error("Error saving the build type"); }); }; return (
Build Type

Select the way of building your code

{ return ( Build Type Dockerfile Nixpacks Heroku Buildpacks Paketo Buildpacks Static ); }} /> {buildType === "heroku_buildpacks" && ( { return ( Heroku Version (Optional) ); }} /> )} {buildType === "dockerfile" && ( <> { return ( Docker File ); }} /> { return ( Docker Context Path ); }} /> { return (
Docker Build Stage Allows you to target a specific stage in a Multi-stage Dockerfile. If empty, Docker defaults to build the last defined stage.
); }} /> )} {buildType === "nixpacks" && ( { return (
Publish Directory Allows you to serve a single directory via NGINX after the build phase. Useful if the final build assets should be served as a static site.
); }} /> )}
); };