diff --git a/apps/dokploy/components/dashboard/application/general/generic/save-bitbucket-provider.tsx b/apps/dokploy/components/dashboard/application/general/generic/save-bitbucket-provider.tsx index 9af040b79..35aba58aa 100644 --- a/apps/dokploy/components/dashboard/application/general/generic/save-bitbucket-provider.tsx +++ b/apps/dokploy/components/dashboard/application/general/generic/save-bitbucket-provider.tsx @@ -29,14 +29,21 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; import { cn } from "@/lib/utils"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import { CheckIcon, ChevronsUpDown } from "lucide-react"; +import { CheckIcon, ChevronsUpDown, X } from "lucide-react"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; +import { Badge } from "@/components/ui/badge"; const BitbucketProviderSchema = z.object({ buildPath: z.string().min(1, "Path is required").default("/"), @@ -48,6 +55,7 @@ const BitbucketProviderSchema = z.object({ .required(), branch: z.string().min(1, "Branch is required"), bitbucketId: z.string().min(1, "Bitbucket Provider is required"), + watchPaths: z.array(z.string()).optional(), }); type BitbucketProvider = z.infer; @@ -73,6 +81,7 @@ export const SaveBitbucketProvider = ({ applicationId }: Props) => { }, bitbucketId: "", branch: "", + watchPaths: [], }, resolver: zodResolver(BitbucketProviderSchema), }); @@ -118,6 +127,7 @@ export const SaveBitbucketProvider = ({ applicationId }: Props) => { }, buildPath: data.bitbucketBuildPath || "/", bitbucketId: data.bitbucketId || "", + watchPaths: data.watchPaths || [], }); } }, [form.reset, data, form]); @@ -130,6 +140,7 @@ export const SaveBitbucketProvider = ({ applicationId }: Props) => { bitbucketBuildPath: data.buildPath, bitbucketId: data.bitbucketId, applicationId, + watchPaths: data.watchPaths || [], }) .then(async () => { toast.success("Service Provided Saved"); @@ -363,6 +374,84 @@ export const SaveBitbucketProvider = ({ applicationId }: Props) => { )} /> + ( + +
+ Watch Paths + + + +
+ ? +
+
+ +

+ Add paths to watch for changes. When files in these + paths change, a new deployment will be triggered. +

+
+
+
+
+
+ {field.value?.map((path, index) => ( + + {path} + { + const newPaths = [...(field.value || [])]; + newPaths.splice(index, 1); + form.setValue("watchPaths", newPaths); + }} + /> + + ))} +
+ +
+ { + if (e.key === "Enter") { + e.preventDefault(); + const input = e.currentTarget; + const value = input.value.trim(); + if (value) { + const newPaths = [...(field.value || []), value]; + form.setValue("watchPaths", newPaths); + input.value = ""; + } + } + }} + /> + +
+
+ +
+ )} + />
)}
- ( - - Branch - - - - - - )} - /> +
+ ( + + Branch + + + + + + )} + /> +
+ { )} /> + ( + +
+ Watch Paths + + + +
+ ? +
+
+ +

+ Add paths to watch for changes. When files in these + paths change, a new deployment will be triggered. This + will work only when manual webhook is setup. +

+
+
+
+
+
+ {field.value?.map((path, index) => ( + + {path} + { + const newPaths = [...(field.value || [])]; + newPaths.splice(index, 1); + form.setValue("watchPaths", newPaths); + }} + /> + + ))} +
+ +
+ { + if (e.key === "Enter") { + e.preventDefault(); + const input = e.currentTarget; + const value = input.value.trim(); + if (value) { + const newPaths = [...(field.value || []), value]; + form.setValue("watchPaths", newPaths); + input.value = ""; + } + } + }} + /> + +
+
+ +
+ )} + />
diff --git a/apps/dokploy/components/dashboard/application/general/generic/save-github-provider.tsx b/apps/dokploy/components/dashboard/application/general/generic/save-github-provider.tsx index adb445752..d8b6922ed 100644 --- a/apps/dokploy/components/dashboard/application/general/generic/save-github-provider.tsx +++ b/apps/dokploy/components/dashboard/application/general/generic/save-github-provider.tsx @@ -28,14 +28,22 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { Badge } from "@/components/ui/badge"; import { cn } from "@/lib/utils"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import { CheckIcon, ChevronsUpDown } from "lucide-react"; +import { CheckIcon, ChevronsUpDown, HelpCircle, Plus, X } from "lucide-react"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; +import Link from "next/link"; const GithubProviderSchema = z.object({ buildPath: z.string().min(1, "Path is required").default("/"), @@ -47,6 +55,7 @@ const GithubProviderSchema = z.object({ .required(), branch: z.string().min(1, "Branch is required"), githubId: z.string().min(1, "Github Provider is required"), + watchPaths: z.array(z.string()).optional(), }); type GithubProvider = z.infer; @@ -113,6 +122,7 @@ export const SaveGithubProvider = ({ applicationId }: Props) => { }, buildPath: data.buildPath || "/", githubId: data.githubId || "", + watchPaths: data.watchPaths || [], }); } }, [form.reset, data, form]); @@ -125,6 +135,7 @@ export const SaveGithubProvider = ({ applicationId }: Props) => { owner: data.repository.owner, buildPath: data.buildPath, githubId: data.githubId, + watchPaths: data.watchPaths || [], }) .then(async () => { toast.success("Service Provided Saved"); @@ -350,7 +361,85 @@ export const SaveGithubProvider = ({ applicationId }: Props) => { - + + + )} + /> + ( + +
+ Watch Paths + + + + + + +

+ Add paths to watch for changes. When files in these + paths change, a new deployment will be triggered. +

+
+
+
+
+
+ {field.value?.map((path, index) => ( + + {path} + { + const newPaths = [...(field.value || [])]; + newPaths.splice(index, 1); + field.onChange(newPaths); + }} + /> + + ))} +
+
+ + { + if (e.key === "Enter") { + e.preventDefault(); + const input = e.currentTarget; + const path = input.value.trim(); + if (path) { + field.onChange([...(field.value || []), path]); + input.value = ""; + } + } + }} + /> + + +
)} @@ -365,6 +454,16 @@ export const SaveGithubProvider = ({ applicationId }: Props) => { Save
+ {/* create github link */} +
+ + Repository + +
diff --git a/apps/dokploy/components/dashboard/application/general/generic/save-gitlab-provider.tsx b/apps/dokploy/components/dashboard/application/general/generic/save-gitlab-provider.tsx index 298a91142..2073f1a6d 100644 --- a/apps/dokploy/components/dashboard/application/general/generic/save-gitlab-provider.tsx +++ b/apps/dokploy/components/dashboard/application/general/generic/save-gitlab-provider.tsx @@ -29,10 +29,17 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { Badge } from "@/components/ui/badge"; import { cn } from "@/lib/utils"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import { CheckIcon, ChevronsUpDown } from "lucide-react"; +import { CheckIcon, ChevronsUpDown, HelpCircle, Plus, X } from "lucide-react"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; @@ -50,6 +57,7 @@ const GitlabProviderSchema = z.object({ .required(), branch: z.string().min(1, "Branch is required"), gitlabId: z.string().min(1, "Gitlab Provider is required"), + watchPaths: z.array(z.string()).optional(), }); type GitlabProvider = z.infer; @@ -124,6 +132,7 @@ export const SaveGitlabProvider = ({ applicationId }: Props) => { }, buildPath: data.gitlabBuildPath || "/", gitlabId: data.gitlabId || "", + watchPaths: data.watchPaths || [], }); } }, [form.reset, data, form]); @@ -138,6 +147,7 @@ export const SaveGitlabProvider = ({ applicationId }: Props) => { applicationId, gitlabProjectId: data.repository.id, gitlabPathNamespace: data.repository.gitlabPathNamespace, + watchPaths: data.watchPaths || [], }) .then(async () => { toast.success("Service Provided Saved"); @@ -375,7 +385,85 @@ export const SaveGitlabProvider = ({ applicationId }: Props) => { - + + + )} + /> + ( + +
+ Watch Paths + + + + + + +

+ Add paths to watch for changes. When files in these + paths change, a new deployment will be triggered. +

+
+
+
+
+
+ {field.value?.map((path, index) => ( + + {path} + { + const newPaths = [...(field.value || [])]; + newPaths.splice(index, 1); + field.onChange(newPaths); + }} + /> + + ))} +
+
+ + { + if (e.key === "Enter") { + e.preventDefault(); + const input = e.currentTarget; + const path = input.value.trim(); + if (path) { + field.onChange([...(field.value || []), path]); + input.value = ""; + } + } + }} + /> + + +
)} diff --git a/apps/dokploy/components/dashboard/compose/general/generic/save-bitbucket-provider-compose.tsx b/apps/dokploy/components/dashboard/compose/general/generic/save-bitbucket-provider-compose.tsx index 875841338..079eeb1b9 100644 --- a/apps/dokploy/components/dashboard/compose/general/generic/save-bitbucket-provider-compose.tsx +++ b/apps/dokploy/components/dashboard/compose/general/generic/save-bitbucket-provider-compose.tsx @@ -29,14 +29,21 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; import { cn } from "@/lib/utils"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import { CheckIcon, ChevronsUpDown } from "lucide-react"; +import { CheckIcon, ChevronsUpDown, X } from "lucide-react"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; import { z } from "zod"; +import { Badge } from "@/components/ui/badge"; const BitbucketProviderSchema = z.object({ composePath: z.string().min(1), @@ -48,6 +55,7 @@ const BitbucketProviderSchema = z.object({ .required(), branch: z.string().min(1, "Branch is required"), bitbucketId: z.string().min(1, "Bitbucket Provider is required"), + watchPaths: z.array(z.string()).optional(), }); type BitbucketProvider = z.infer; @@ -73,6 +81,7 @@ export const SaveBitbucketProviderCompose = ({ composeId }: Props) => { }, bitbucketId: "", branch: "", + watchPaths: [], }, resolver: zodResolver(BitbucketProviderSchema), }); @@ -118,6 +127,7 @@ export const SaveBitbucketProviderCompose = ({ composeId }: Props) => { }, composePath: data.composePath, bitbucketId: data.bitbucketId || "", + watchPaths: data.watchPaths || [], }); } }, [form.reset, data, form]); @@ -132,6 +142,7 @@ export const SaveBitbucketProviderCompose = ({ composeId }: Props) => { composeId, sourceType: "bitbucket", composeStatus: "idle", + watchPaths: data.watchPaths, }) .then(async () => { toast.success("Service Provided Saved"); @@ -365,6 +376,84 @@ export const SaveBitbucketProviderCompose = ({ composeId }: Props) => { )} /> + ( + +
+ Watch Paths + + + +
+ ? +
+
+ +

+ Add paths to watch for changes. When files in these + paths change, a new deployment will be triggered. +

+
+
+
+
+
+ {field.value?.map((path, index) => ( + + {path} + { + const newPaths = [...(field.value || [])]; + newPaths.splice(index, 1); + form.setValue("watchPaths", newPaths); + }} + /> + + ))} +
+ +
+ { + if (e.key === "Enter") { + e.preventDefault(); + const input = e.currentTarget; + const value = input.value.trim(); + if (value) { + const newPaths = [...(field.value || []), value]; + form.setValue("watchPaths", newPaths); + input.value = ""; + } + } + }} + /> + +
+
+ +
+ )} + />
+
+ + + + )} + />
diff --git a/apps/dokploy/components/dashboard/compose/general/generic/save-github-provider-compose.tsx b/apps/dokploy/components/dashboard/compose/general/generic/save-github-provider-compose.tsx index 7787cb3ce..6328386ad 100644 --- a/apps/dokploy/components/dashboard/compose/general/generic/save-github-provider-compose.tsx +++ b/apps/dokploy/components/dashboard/compose/general/generic/save-github-provider-compose.tsx @@ -1,3 +1,4 @@ +import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { Command, @@ -28,10 +29,16 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; import { cn } from "@/lib/utils"; import { api } from "@/utils/api"; import { zodResolver } from "@hookform/resolvers/zod"; -import { CheckIcon, ChevronsUpDown } from "lucide-react"; +import { CheckIcon, ChevronsUpDown, X } from "lucide-react"; import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; @@ -47,6 +54,7 @@ const GithubProviderSchema = z.object({ .required(), branch: z.string().min(1, "Branch is required"), githubId: z.string().min(1, "Github Provider is required"), + watchPaths: z.array(z.string()).optional(), }); type GithubProvider = z.infer; @@ -71,6 +79,7 @@ export const SaveGithubProviderCompose = ({ composeId }: Props) => { }, githubId: "", branch: "", + watchPaths: [], }, resolver: zodResolver(GithubProviderSchema), }); @@ -113,6 +122,7 @@ export const SaveGithubProviderCompose = ({ composeId }: Props) => { }, composePath: data.composePath, githubId: data.githubId || "", + watchPaths: data.watchPaths || [], }); } }, [form.reset, data, form]); @@ -127,6 +137,7 @@ export const SaveGithubProviderCompose = ({ composeId }: Props) => { githubId: data.githubId, sourceType: "github", composeStatus: "idle", + watchPaths: data.watchPaths, }) .then(async () => { toast.success("Service Provided Saved"); @@ -183,7 +194,6 @@ export const SaveGithubProviderCompose = ({ composeId }: Props) => { )} /> - { )} /> + ( + +
+ Watch Paths + + + +
+ ? +
+
+ +

+ Add paths to watch for changes. When files in these + paths change, a new deployment will be triggered. +

+
+
+
+
+
+ {field.value?.map((path, index) => ( + + {path} + { + const newPaths = [...(field.value || [])]; + newPaths.splice(index, 1); + form.setValue("watchPaths", newPaths); + }} + /> + + ))} +
+ +
+ { + if (e.key === "Enter") { + e.preventDefault(); + const input = e.currentTarget; + const value = input.value.trim(); + if (value) { + const newPaths = [...(field.value || []), value]; + form.setValue("watchPaths", newPaths); + input.value = ""; + } + } + }} + /> + +
+
+ +
+ )} + />
+
+ + + + )} + />