import { useEffect } from "react"; import { Controller, useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import slugify from "@sindresorhus/slugify"; import ms from "ms"; import { z } from "zod"; import { createNotification } from "@app/components/notifications"; import { Button, FormControl, Input, Modal, ModalContent, Select, SelectItem, Switch } from "@app/components/v2"; import { useProject } from "@app/context"; import { useCreateSshCertTemplate, useGetSshCaById, useGetSshCertTemplate, useListWorkspaceSshCas, useUpdateSshCertTemplate } from "@app/hooks/api"; import { UsePopUpState } from "@app/hooks/usePopUp"; const schema = z .object({ sshCaId: z.string(), name: z .string() .trim() .toLowerCase() .min(1) .max(36) .refine((v) => slugify(v) === v, { message: "Invalid name. Name can only contain alphanumeric characters and hyphens." }), ttl: z .string() .trim() .refine( (val) => ms(val) > 0, "TTL must be a valid time string such as 2 days, 1d, 2h 1y, ..." ) .default("1h"), maxTTL: z .string() .trim() .refine( (val) => ms(val) > 0, "Max TTL must be a valid time string such as 2 days, 1d, 2h 1y, ..." ) .default("30d"), allowedUsers: z.string(), allowedHosts: z.string(), allowUserCertificates: z.boolean().optional().default(false), allowHostCertificates: z.boolean().optional().default(false), allowCustomKeyIds: z.boolean().optional().default(false) }) .refine((data) => ms(data.maxTTL) >= ms(data.ttl), { message: "Max TTL must be greater than or equal to TTL", path: ["maxTTL"] }); export type FormData = z.infer; type Props = { sshCaId: string; popUp: UsePopUpState<["sshCertificateTemplate"]>; handlePopUpToggle: ( popUpName: keyof UsePopUpState<["sshCertificateTemplate"]>, state?: boolean ) => void; }; export const SshCertificateTemplateModal = ({ popUp, handlePopUpToggle, sshCaId }: Props) => { const { currentProject } = useProject(); const { data: ca } = useGetSshCaById(sshCaId); const { data: certTemplate } = useGetSshCertTemplate( (popUp?.sshCertificateTemplate?.data as { id: string })?.id || "" ); const { data: cas } = useListWorkspaceSshCas(currentProject?.id || ""); const { mutateAsync: createSshCertTemplate } = useCreateSshCertTemplate(); const { mutateAsync: updateSshCertTemplate } = useUpdateSshCertTemplate(); const { control, handleSubmit, reset, formState: { isSubmitting } } = useForm({ resolver: zodResolver(schema), defaultValues: {} }); useEffect(() => { if (certTemplate) { reset({ sshCaId: certTemplate.sshCaId, name: certTemplate.name, ttl: certTemplate.ttl, maxTTL: certTemplate.maxTTL, allowedUsers: certTemplate.allowedUsers.join(", "), allowedHosts: certTemplate.allowedHosts.join(", "), allowUserCertificates: certTemplate.allowUserCertificates, allowHostCertificates: certTemplate.allowHostCertificates, allowCustomKeyIds: certTemplate.allowCustomKeyIds }); } else { reset({ sshCaId, name: "", ttl: "1h", maxTTL: "30d", allowedUsers: "", allowedHosts: "", allowUserCertificates: false, allowHostCertificates: false, allowCustomKeyIds: false }); } }, [certTemplate, ca]); const onFormSubmit = async ({ name, ttl, maxTTL, allowUserCertificates, allowHostCertificates, allowedUsers, allowedHosts, allowCustomKeyIds }: FormData) => { try { if (certTemplate) { await updateSshCertTemplate({ id: certTemplate.id, name, ttl, maxTTL, allowedUsers: allowedUsers ? allowedUsers.split(",").map((user) => user.trim()) : [], allowedHosts: allowedHosts ? allowedHosts.split(",").map((host) => host.trim()) : [], allowUserCertificates, allowHostCertificates, allowCustomKeyIds }); createNotification({ text: "Successfully updated SSH certificate template", type: "success" }); } else { await createSshCertTemplate({ sshCaId, name, ttl, maxTTL, allowedUsers: allowedUsers ? allowedUsers.split(",").map((user) => user.trim()) : [], allowedHosts: allowedHosts ? allowedHosts.split(",").map((host) => host.trim()) : [], allowUserCertificates, allowHostCertificates, allowCustomKeyIds }); createNotification({ text: "Successfully created SSH certificate template", type: "success" }); } reset(); handlePopUpToggle("sshCertificateTemplate", false); } catch (err) { console.error(err); createNotification({ text: "Failed to save changes", type: "error" }); } }; return ( { handlePopUpToggle("sshCertificateTemplate", isOpen); reset(); }} >
{certTemplate && ( )} ( )} /> ( )} /> ( )} /> ( )} /> ( )} /> ( )} /> { return ( field.onChange(value)} isChecked={field.value} >

Allow User Certificates

); }} /> { return ( field.onChange(value)} isChecked={field.value} >

Allow Host Certificates

); }} /> { return ( field.onChange(value)} isChecked={field.value} >

Allow Custom Key IDs

); }} />
); };