"use client"; import { zodResolver } from "@hookform/resolvers/zod"; import { InfoIcon } from "lucide-react"; import { useRouter } from "next/navigation"; import { Controller, DefaultValues, useForm, UseFormReturn, useWatch, } from "react-hook-form"; import { Checkbox } from "@/components/shadcn/checkbox/checkbox"; import { Form, FormButtons, FormControl, FormField, FormItem, FormLabel, FormMessage, } from "@/components/shadcn/form"; import { Input } from "@/components/shadcn/input/input"; import { EnhancedMultiSelect } from "@/components/shadcn/select/enhanced-multi-select"; import { Separator } from "@/components/shadcn/separator/separator"; import { Tooltip, TooltipContent, TooltipTrigger, } from "@/components/shadcn/tooltip"; import { useFormServerErrors } from "@/hooks/use-form-server-errors"; import { useManageProvidersUnlimitedVisibility } from "@/hooks/use-manage-providers-unlimited-visibility"; import { getUnlimitedVisibilityField, getVisiblePermissionFormFields, } from "@/lib/role-permissions"; import { isCloud } from "@/lib/shared/env"; import { roleFormSchema, RoleFormValues } from "@/types"; import { UnlimitedVisibilityField } from "./unlimited-visibility-section"; export interface RoleGroupOption { id: string; name: string; } export interface RoleFormSubmitContext { form: UseFormReturn; handleServerResponse: (data: unknown) => boolean; } interface RoleFormProps { groups: RoleGroupOption[]; defaultValues: DefaultValues; submitText: string; onSubmit: ( values: RoleFormValues, ctx: RoleFormSubmitContext, ) => void | Promise; onCancel?: () => void; } export const RoleForm = ({ groups, defaultValues, submitText, onSubmit, onCancel, }: RoleFormProps) => { const router = useRouter(); const form = useForm({ resolver: zodResolver(roleFormSchema), defaultValues, }); const isCloudEnvironment = isCloud(); const visiblePermissionFormFields = getVisiblePermissionFormFields(isCloudEnvironment); const showUnlimitedVisibilityField = !!getUnlimitedVisibilityField(); const { setPermissionValue, setUnlimitedVisibility } = useManageProvidersUnlimitedVisibility(form); const { handleServerResponse } = useFormServerErrors(form, { "/data/attributes/name": "name", }); // useWatch instead of form.watch: React Compiler can keep memoized JSX stale // when getter reads happen during render. const formValues = useWatch({ control: form.control }); const unlimitedVisibility = !!formValues.unlimited_visibility; const isLoading = form.formState.isSubmitting; const onSelectAllChange = (checked: boolean) => { visiblePermissionFormFields.forEach(({ field }) => { setPermissionValue(field, checked); }); }; const handleCancel = onCancel ?? (() => router.push("/roles")); return (
onSubmit(values, { form, handleServerResponse }), )} className="flex flex-col gap-6" > ( Role Name * )} />
Admin Permissions {/* Select All Checkbox */}
Boolean(formValues[perm.field as keyof RoleFormValues]), )} onCheckedChange={(checked) => onSelectAllChange(Boolean(checked))} />
{/* Permissions Grid */}
{visiblePermissionFormFields.map( ({ field, label, description }) => (
setPermissionValue(field, Boolean(checked)) } />
{description}
), )}
Visibility {showUnlimitedVisibilityField && ( )} {!unlimitedVisibility && ( <>

Select the groups this role will have access to. If no groups are selected and unlimited visibility is not enabled, the role will not have access to any accounts.

(
({ label: group.name, value: group.id, }))} onValueChange={field.onChange} defaultValue={field.value || []} placeholder="Select groups" searchable={true} hideSelectAll={true} emptyIndicator="No results found" resetOnDefaultValueChange={true} />
)} /> {form.formState.errors.groups && (

{form.formState.errors.groups.message}

)} )}
); };