diff --git a/apps/webservice/src/app/[workspaceSlug]/_components/variable-set-drawer/OverviewContent.tsx b/apps/webservice/src/app/[workspaceSlug]/_components/variable-set-drawer/OverviewContent.tsx new file mode 100644 index 000000000..bc6394847 --- /dev/null +++ b/apps/webservice/src/app/[workspaceSlug]/_components/variable-set-drawer/OverviewContent.tsx @@ -0,0 +1,314 @@ +import type * as SCHEMA from "@ctrlplane/db/schema"; +import type React from "react"; +import { useRouter } from "next/navigation"; +import { IconX } from "@tabler/icons-react"; +import { z } from "zod"; + +import { cn } from "@ctrlplane/ui"; +import { Badge } from "@ctrlplane/ui/badge"; +import { Button } from "@ctrlplane/ui/button"; +import { + Command, + CommandInput, + CommandItem, + CommandList, +} from "@ctrlplane/ui/command"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@ctrlplane/ui/dropdown-menu"; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, + useFieldArray, + useForm, +} from "@ctrlplane/ui/form"; +import { Input } from "@ctrlplane/ui/input"; +import { Label } from "@ctrlplane/ui/label"; +import { Popover, PopoverContent, PopoverTrigger } from "@ctrlplane/ui/popover"; +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@ctrlplane/ui/select"; +import { Textarea } from "@ctrlplane/ui/textarea"; + +import { api } from "~/trpc/react"; + +const schema = z.object({ + name: z.string().min(1).max(255), + description: z.string().optional(), + environmentIds: z.array(z.object({ id: z.string().uuid() })), + values: z.array( + z.object({ + key: z.string().refine((data) => data.length > 2, { + message: "Key must be at least 3 characters", + }), + value: z.union([z.string(), z.number(), z.boolean()]).refine((data) => { + if (typeof data === "string") return data.length > 0; + return true; + }), + }), + ), +}); + +export const OverviewContent: React.FC<{ + variableSet: SCHEMA.VariableSet & { + values: SCHEMA.VariableSetValue[]; + assignments: (SCHEMA.VariableSetAssignment & { + environment: SCHEMA.Environment; + })[]; + }; + environments: SCHEMA.Environment[]; +}> = ({ variableSet, environments }) => { + const update = api.variableSet.update.useMutation(); + + const description = variableSet.description ?? undefined; + const environmentIds = variableSet.assignments.map((assignment) => ({ + id: assignment.environmentId, + })); + const form = useForm({ + schema, + defaultValues: { ...variableSet, description, environmentIds }, + }); + + const { fields, append, remove } = useFieldArray({ + name: "values", + control: form.control, + }); + + const { + fields: envs, + append: appendEnv, + remove: removeEnv, + } = useFieldArray({ + name: "environmentIds", + control: form.control, + }); + + const router = useRouter(); + const utils = api.useUtils(); + + const onSubmit = form.handleSubmit((data) => { + const environmentIds = data.environmentIds.map((env) => env.id); + update + .mutateAsync({ data: { ...data, environmentIds }, id: variableSet.id }) + .then(() => form.reset(data)) + .then(() => utils.variableSet.byId.invalidate(variableSet.id)) + .then(() => router.refresh()); + }); + + const selectedEnvsIds = form.watch("environmentIds").map((env) => env.id); + const newEnvironments = environments.filter( + (env) => !selectedEnvsIds.includes(env.id), + ); + + return ( +
+ + ( + + Name + + + + + + )} + /> + + ( + + Description + +