+
+ {value.map((tag, index) => (
+
+ {tag}
+
+
+ ))}
+
+
+
+ );
+ },
+);
+
+TagsInput.displayName = "TagsInput";
+
+export { TagsInput };
diff --git a/ui-v2/src/components/variables/add-variable-dialog.tsx b/ui-v2/src/components/variables/add-variable-dialog.tsx
new file mode 100644
index 000000000000..b7a9bd04e4ac
--- /dev/null
+++ b/ui-v2/src/components/variables/add-variable-dialog.tsx
@@ -0,0 +1,188 @@
+import { Button } from "@/components/ui/button";
+import {
+ Dialog,
+ DialogContent,
+ DialogFooter,
+ DialogHeader,
+ DialogTitle,
+ DialogDescription,
+ DialogTrigger,
+} from "@/components/ui/dialog";
+import { zodResolver } from "@hookform/resolvers/zod";
+import CodeMirror, { EditorView } from "@uiw/react-codemirror";
+import { json } from "@codemirror/lang-json";
+import { useMutation } from "@tanstack/react-query";
+import { useForm } from "react-hook-form";
+import { z } from "zod";
+import {
+ Form,
+ FormControl,
+ FormField,
+ FormItem,
+ FormLabel,
+ FormMessage,
+} from "../ui/form";
+import { Input } from "../ui/input";
+import { createQueryService } from "@/api/service";
+import type { components } from "@/api/prefect";
+import type { JSONValue } from "@/lib/types";
+import { Loader2 } from "lucide-react";
+import { TagsInput } from "../ui/tags-input";
+import { useToast } from "@/hooks/use-toast";
+
+const formSchema = z.object({
+ name: z.string().min(2, { message: "Name must be at least 2 characters" }),
+ value: z.string(),
+ tags: z
+ .string()
+ .min(2, { message: "Tags must be at least 2 characters" })
+ .array()
+ .optional(),
+});
+
+type AddVariableDialogProps = {
+ onOpenChange: (open: boolean) => void;
+ open: boolean;
+};
+
+export const AddVariableDialog = ({
+ onOpenChange,
+ open,
+}: AddVariableDialogProps) => {
+ const defaultValues = {
+ name: "",
+ value: "",
+ tags: [],
+ };
+ const form = useForm