From 56d8defebeb5df4fcf452f699fdb11a53d6dea44 Mon Sep 17 00:00:00 2001 From: Jason Parks Date: Wed, 19 Mar 2025 16:48:51 -0600 Subject: [PATCH] Added watchlist paths for Gitea and some minor typescript fixes. --- .../general/generic/save-gitea-provider.tsx | 97 +- .../dashboard/compose/general/actions.tsx | 2 +- .../generic/save-gitea-provider-compose.tsx | 893 +++++++++--------- .../compose/general/generic/show.tsx | 96 +- .../settings/cluster/nodes/add-node.tsx | 2 +- .../settings/git/gitea/add-gitea-provider.tsx | 12 +- .../web-server/manage-traefik-ports.tsx | 12 +- .../dokploy/server/api/routers/application.ts | 1 + apps/dokploy/server/api/routers/gitea.ts | 382 ++++---- packages/server/src/db/schema/application.ts | 1 + packages/server/src/services/gitea.ts | 6 +- 11 files changed, 814 insertions(+), 690 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/general/generic/save-gitea-provider.tsx b/apps/dokploy/components/dashboard/application/general/generic/save-gitea-provider.tsx index 2351c8fb..60565824 100644 --- a/apps/dokploy/components/dashboard/application/general/generic/save-gitea-provider.tsx +++ b/apps/dokploy/components/dashboard/application/general/generic/save-gitea-provider.tsx @@ -29,16 +29,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"; -// Define types for repository and branch objects interface GiteaRepository { name: string; url: string; @@ -63,6 +69,7 @@ const GiteaProviderSchema = z.object({ owner: z.string().min(1, "Owner is required"), giteaPathNamespace: z.string().min(1), id: z.number().nullable(), + watchPaths: z.array(z.string()).default([]), }) .required(), branch: z.string().min(1, "Branch is required"), @@ -90,6 +97,7 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => { repo: "", giteaPathNamespace: "", id: null, + watchPaths: [], }, giteaId: "", branch: "", @@ -138,6 +146,7 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => { owner: data.giteaOwner || "", giteaPathNamespace: data.giteaPathNamespace || "", id: data.giteaProjectId, + watchPaths: data.watchPaths || [], }, buildPath: data.giteaBuildPath || "/", giteaId: data.giteaId || "", @@ -155,6 +164,7 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => { applicationId, giteaProjectId: data.repository.id, giteaPathNamespace: data.repository.giteaPathNamespace, + watchPaths: data.repository.watchPaths, }) .then(async () => { toast.success("Service Provider Saved"); @@ -188,6 +198,7 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => { repo: "", id: null, giteaPathNamespace: "", + watchPaths: [], }); form.setValue("branch", ""); }} @@ -274,6 +285,7 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => { repo: repo.name, id: repo.id, giteaPathNamespace: repo.name, + watchPaths: [], }); form.setValue("branch", ""); }} @@ -399,6 +411,85 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => { )} /> + ( + +
+ Watch Paths + + + + + + +

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

+
+
+
+
+
+ {field.value && field.value.map((path: string, index: number) => ( + + {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 = ""; + } + } + }} + /> + + +
+ +
+ )} + />
); -}; +}; \ No newline at end of file diff --git a/apps/dokploy/components/dashboard/compose/general/actions.tsx b/apps/dokploy/components/dashboard/compose/general/actions.tsx index aacf458f..0a4433e7 100644 --- a/apps/dokploy/components/dashboard/compose/general/actions.tsx +++ b/apps/dokploy/components/dashboard/compose/general/actions.tsx @@ -8,11 +8,11 @@ import { TooltipTrigger, } from "@/components/ui/tooltip"; import { api } from "@/utils/api"; +import * as TooltipPrimitive from "@radix-ui/react-tooltip"; import { Ban, CheckCircle2, RefreshCcw, Rocket, Terminal } from "lucide-react"; import { useRouter } from "next/router"; import { toast } from "sonner"; import { DockerTerminalModal } from "../../settings/web-server/docker-terminal-modal"; -import * as TooltipPrimitive from "@radix-ui/react-tooltip"; interface Props { composeId: string; diff --git a/apps/dokploy/components/dashboard/compose/general/generic/save-gitea-provider-compose.tsx b/apps/dokploy/components/dashboard/compose/general/generic/save-gitea-provider-compose.tsx index 95ff9784..5059672e 100644 --- a/apps/dokploy/components/dashboard/compose/general/generic/save-gitea-provider-compose.tsx +++ b/apps/dokploy/components/dashboard/compose/general/generic/save-gitea-provider-compose.tsx @@ -3,39 +3,39 @@ import { AlertBlock } from "@/components/shared/alert-block"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { - Command, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, } from "@/components/ui/command"; import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, } from "@/components/ui/form"; import { Input } from "@/components/ui/input"; import { - Popover, - PopoverContent, - PopoverTrigger, + Popover, + PopoverContent, + PopoverTrigger, } from "@/components/ui/popover"; import { ScrollArea } from "@/components/ui/scroll-area"; import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, } from "@/components/ui/select"; import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, } from "@/components/ui/tooltip"; import { cn } from "@/lib/utils"; import { api } from "@/utils/api"; @@ -48,439 +48,466 @@ import { toast } from "sonner"; import { z } from "zod"; interface Repository { - name: string; - url: string; - id: number; - owner: { - username: string; - }; + name: string; + url: string; + id: number; + owner: { + username: string; + }; } interface Branch { - name: string; + name: string; } interface GiteaProviderType { - giteaId: string; - gitProvider: { - name: string; - gitProviderId: string; - providerType: "github" | "gitlab" | "bitbucket" | "gitea"; - createdAt: string; - organizationId: string; - }; - name: string; + giteaId: string; + gitProvider: { + name: string; + gitProviderId: string; + providerType: "github" | "gitlab" | "bitbucket" | "gitea"; + createdAt: string; + organizationId: string; + }; + name: string; } const GiteaProviderSchema = z.object({ - composePath: z.string().min(1), - repository: z - .object({ - repo: z.string().min(1, "Repo is required"), - owner: z.string().min(1, "Owner is required"), - id: z.number().nullable(), - giteaPathNamespace: z.string().min(1), - }) - .required(), - branch: z.string().min(1, "Branch is required"), - giteaId: z.string().min(1, "Gitea Provider is required"), - watchPaths: z.array(z.string()).optional(), + composePath: z.string().min(1), + repository: z + .object({ + repo: z.string().min(1, "Repo is required"), + owner: z.string().min(1, "Owner is required"), + id: z.number().nullable(), + giteaPathNamespace: z.string().min(1), + }) + .required(), + branch: z.string().min(1, "Branch is required"), + giteaId: z.string().min(1, "Gitea Provider is required"), + watchPaths: z.array(z.string()).optional(), }); type GiteaProvider = z.infer; interface Props { - composeId: string; + composeId: string; } export const SaveGiteaProviderCompose = ({ composeId }: Props) => { - const { data: giteaProviders } = api.gitea.giteaProviders.useQuery(); - const { data, refetch } = api.compose.one.useQuery({ composeId }); + const { data: giteaProviders } = api.gitea.giteaProviders.useQuery(); + const { data, refetch } = api.compose.one.useQuery({ composeId }); - const { mutateAsync, isLoading: isSavingGiteaProvider } = api.compose.update.useMutation(); + const { mutateAsync, isLoading: isSavingGiteaProvider } = + api.compose.update.useMutation(); - const form = useForm({ - defaultValues: { - composePath: "./docker-compose.yml", - repository: { - owner: "", - repo: "", - giteaPathNamespace: "", - id: null, - }, - giteaId: "", - branch: "", - watchPaths: [], - }, - resolver: zodResolver(GiteaProviderSchema), - }); + const form = useForm({ + defaultValues: { + composePath: "./docker-compose.yml", + repository: { + owner: "", + repo: "", + giteaPathNamespace: "", + id: null, + }, + giteaId: "", + branch: "", + watchPaths: [], + }, + resolver: zodResolver(GiteaProviderSchema), + }); - const repository = form.watch("repository"); - const giteaId = form.watch("giteaId"); + const repository = form.watch("repository"); + const giteaId = form.watch("giteaId"); - const { data: repositories, isLoading: isLoadingRepositories, error } = api.gitea.getGiteaRepositories.useQuery( - { - giteaId, - }, - { - enabled: !!giteaId, - } - ); + const { + data: repositories, + isLoading: isLoadingRepositories, + error, + } = api.gitea.getGiteaRepositories.useQuery( + { + giteaId, + }, + { + enabled: !!giteaId, + }, + ); - const { data: branches, fetchStatus, status } = api.gitea.getGiteaBranches.useQuery( - { - owner: repository?.owner, - repositoryName: repository?.repo, - id: repository?.id || 0, - giteaId: giteaId, - }, - { - enabled: !!repository?.owner && !!repository?.repo && !!giteaId, - } - ); + const { + data: branches, + fetchStatus, + status, + } = api.gitea.getGiteaBranches.useQuery( + { + owner: repository?.owner, + repositoryName: repository?.repo, + id: repository?.id || 0, + giteaId: giteaId, + }, + { + enabled: !!repository?.owner && !!repository?.repo && !!giteaId, + }, + ); - useEffect(() => { - if (data) { - form.reset({ - branch: data.giteaBranch || "", - repository: { - repo: data.giteaRepository || "", - owner: data.giteaOwner || "", - id: null, - giteaPathNamespace: "", - }, - composePath: data.composePath, - giteaId: data.giteaId || "", - watchPaths: data.watchPaths || [], - }); - } - }, [form.reset, data, form]); + useEffect(() => { + if (data) { + form.reset({ + branch: data.giteaBranch || "", + repository: { + repo: data.giteaRepository || "", + owner: data.giteaOwner || "", + id: null, + giteaPathNamespace: "", + }, + composePath: data.composePath, + giteaId: data.giteaId || "", + watchPaths: data.watchPaths || [], + }); + } + }, [data, form]); - const onSubmit = async (data: GiteaProvider) => { - await mutateAsync({ - giteaBranch: data.branch, - giteaRepository: data.repository.repo, - giteaOwner: data.repository.owner, - composePath: data.composePath, - giteaId: data.giteaId, - composeId, - sourceType: "gitea", - composeStatus: "idle", - watchPaths: data.watchPaths, - } as any) - .then(async () => { - toast.success("Service Provided Saved"); - await refetch(); - }) - .catch(() => { - toast.error("Error saving the Gitea provider"); - }); - }; + const onSubmit = async (data: GiteaProvider) => { + await mutateAsync({ + giteaBranch: data.branch, + giteaRepository: data.repository.repo, + giteaOwner: data.repository.owner, + composePath: data.composePath, + giteaId: data.giteaId, + composeId, + sourceType: "gitea", + composeStatus: "idle", + watchPaths: data.watchPaths, + } as any) + .then(async () => { + toast.success("Service Provided Saved"); + await refetch(); + }) + .catch(() => { + toast.error("Error saving the Gitea provider"); + }); + }; - return ( -
-
- - {error && {error?.message}} -
- ( - - Gitea Account - - - - )} - /> - ( - -
- Repository - {field.value.owner && field.value.repo && ( - - - View Repository - - )} -
- - - - - - - - - - {isLoadingRepositories && ( - Loading Repositories.... - )} - No repositories found. - - - {repositories?.map((repo: Repository) => { - return ( - { - form.setValue("repository", { - owner: repo.owner.username as string, - repo: repo.name, - id: repo.id, - giteaPathNamespace: repo.url, - }); - form.setValue("branch", ""); - }} - > - - {repo.name} - - {repo.owner.username} - - - - - ); - })} - - - - - - {form.formState.errors.repository && ( -

- Repository is required -

- )} -
- )} - /> - ( - - Branch - - - - - - - - - - No branches found. - - - {branches?.map((branch: Branch) => ( - form.setValue("branch", branch.name)} - > - - {branch.name} - - - - ))} - - - - - - {form.formState.errors.branch && ( -

- Branch is required -

- )} -
- )} - /> - ( - - Compose Path - - - - - - )} - /> - ( - -
- 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 = ""; - } - } - }} - /> - -
-
- -
- )} - /> -
- -
- -
- ); -}; \ No newline at end of file +
+ ( + + Gitea Account + + + + )} + /> + + ( + +
+ Repository + {field.value.owner && field.value.repo && ( + + + View Repository + + )} +
+ + + + + + + + + + {isLoadingRepositories && ( + + Loading Repositories.... + + )} + No repositories found. + + + {repositories?.map((repo) => ( + { + form.setValue("repository", { + owner: repo.owner.username, + repo: repo.name, + id: repo.id, + giteaPathNamespace: repo.url, + }); + form.setValue("branch", ""); + }} + > + + {repo.name} + + {repo.owner.username} + + + + + ))} + + + + + + {form.formState.errors.repository && ( +

+ Repository is required +

+ )} +
+ )} + /> + + ( + + Branch + + + + + + + + + + No branches found. + + + {branches?.map((branch) => ( + + form.setValue("branch", branch.name) + } + > + + {branch.name} + + + + ))} + + + + + + {form.formState.errors.branch && ( +

+ Branch is required +

+ )} +
+ )} + /> + + ( + + Compose Path + + + + + + )} + /> + + ( + +
+ 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/show.tsx b/apps/dokploy/components/dashboard/compose/general/generic/show.tsx index 38ca5fbe..340037ad 100644 --- a/apps/dokploy/components/dashboard/compose/general/generic/show.tsx +++ b/apps/dokploy/components/dashboard/compose/general/generic/show.tsx @@ -1,26 +1,25 @@ import { BitbucketIcon, - GitIcon, + GiteaIcon, GithubIcon, GitlabIcon, - GiteaIcon, + GitIcon, } from "@/components/icons/data-tools-icons"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { api } from "@/utils/api"; import { CodeIcon, GitBranch } from "lucide-react"; import Link from "next/link"; -import { useState } from "react"; +import { useState, useEffect } from "react"; import { ComposeFileEditor } from "../compose-file-editor"; import { ShowConvertedCompose } from "../show-converted-compose"; import { SaveBitbucketProviderCompose } from "./save-bitbucket-provider-compose"; import { SaveGitProviderCompose } from "./save-git-provider-compose"; +import { SaveGiteaProviderCompose } from "./save-gitea-provider-compose"; import { SaveGithubProviderCompose } from "./save-github-provider-compose"; import { SaveGitlabProviderCompose } from "./save-gitlab-provider-compose"; -import { SaveGiteaProviderCompose } from "./save-gitea-provider-compose"; - - type TabState = "github" | "git" | "raw" | "gitlab" | "bitbucket" | "gitea"; + type TabState = "github" | "git" | "raw" | "gitlab" | "bitbucket" | "gitea"; // Adding gitea to the TabState interface Props { composeId: string; } @@ -29,11 +28,40 @@ import { SaveGiteaProviderCompose } from "./save-gitea-provider-compose"; const { data: githubProviders } = api.github.githubProviders.useQuery(); const { data: gitlabProviders } = api.gitlab.gitlabProviders.useQuery(); const { data: bitbucketProviders } = api.bitbucket.bitbucketProviders.useQuery(); - const { data: giteaProviders } = api.gitea.giteaProviders.useQuery(); + const { data: giteaProviders } = api.gitea.giteaProviders.useQuery(); // Fetching Gitea providers const { data: compose } = api.compose.one.useQuery({ composeId }); const [tab, setSab] = useState(compose?.sourceType || "github"); + // Ensure we fall back to empty arrays if the data is undefined + const safeGithubProviders = githubProviders || []; + const safeGitlabProviders = gitlabProviders || []; + const safeBitbucketProviders = bitbucketProviders || []; + const safeGiteaProviders = giteaProviders || []; + + const renderProviderContent = (providers: any[], providerType: string, ProviderComponent: React.ComponentType) => { + if (providers.length > 0) { + return ; + } else { + return ( +
+ {providerType === "github" && } + {providerType === "gitlab" && } + {providerType === "bitbucket" && } + {providerType === "gitea" && } + + To deploy using {providerType.charAt(0).toUpperCase() + providerType.slice(1)}, you need to configure your account first. + Please, go to{" "} + + Settings + {" "} + to do so. + +
+ ); + } + }; + return ( @@ -82,11 +110,10 @@ import { SaveGiteaProviderCompose } from "./save-gitea-provider-compose"; Bitbucket - {/* Add Gitea Icon */} - Gitea + Gitea + - {githubProviders && githubProviders?.length > 0 ? ( - - ) : ( -
- - - To deploy using GitHub, you need to configure your account first. Please, go to{" "} - - Settings - {" "} - to do so. - -
- )} + {renderProviderContent(safeGithubProviders, "github", SaveGithubProviderCompose)}
- {/* Added Gitea tab */} - {giteaProviders && giteaProviders?.length > 0 ? ( - - ) : ( -
- - - To deploy using Gitea, you need to configure your account first. Please, go to{" "} - - Settings - {" "} - to do so. - -
- )} + + {renderProviderContent(safeGiteaProviders, "gitea", SaveGiteaProviderCompose)} + + + {renderProviderContent(safeGitlabProviders, "gitlab", SaveGitlabProviderCompose)} + + + {renderProviderContent(safeBitbucketProviders, "bitbucket", SaveBitbucketProviderCompose)} + + + + + + + - {/* Other tabs remain unchanged */}
); - }; \ No newline at end of file + }; \ No newline at end of file diff --git a/apps/dokploy/components/dashboard/settings/cluster/nodes/add-node.tsx b/apps/dokploy/components/dashboard/settings/cluster/nodes/add-node.tsx index 966055b4..63fb17dd 100644 --- a/apps/dokploy/components/dashboard/settings/cluster/nodes/add-node.tsx +++ b/apps/dokploy/components/dashboard/settings/cluster/nodes/add-node.tsx @@ -1,3 +1,4 @@ +import { AlertBlock } from "@/components/shared/alert-block"; import { Button } from "@/components/ui/button"; import { Dialog, @@ -12,7 +13,6 @@ import { ExternalLink, PlusIcon } from "lucide-react"; import Link from "next/link"; import { AddManager } from "./manager/add-manager"; import { AddWorker } from "./workers/add-worker"; -import { AlertBlock } from "@/components/shared/alert-block"; interface Props { serverId?: string; diff --git a/apps/dokploy/components/dashboard/settings/git/gitea/add-gitea-provider.tsx b/apps/dokploy/components/dashboard/settings/git/gitea/add-gitea-provider.tsx index 459afb7d..407486c0 100644 --- a/apps/dokploy/components/dashboard/settings/git/gitea/add-gitea-provider.tsx +++ b/apps/dokploy/components/dashboard/settings/git/gitea/add-gitea-provider.tsx @@ -45,7 +45,7 @@ const Schema = z.object({ redirectUri: z.string().min(1, { message: "Redirect URI is required", }), - organizationName: z.string().optional(), // Added organizationName to the schema + organizationName: z.string().optional(), }); type Schema = z.infer; @@ -54,8 +54,8 @@ export const AddGiteaProvider = () => { const utils = api.useUtils(); const [isOpen, setIsOpen] = useState(false); const url = useUrl(); - const { mutateAsync, error, isError } = api.gitea.create.useMutation(); // Updated API call for Gitea - const webhookUrl = `${url}/api/providers/gitea/callback`; // Updated webhook URL for Gitea + const { mutateAsync, error, isError } = api.gitea.create.useMutation(); + const webhookUrl = `${url}/api/providers/gitea/callback`; const form = useForm({ defaultValues: { @@ -86,7 +86,7 @@ export const AddGiteaProvider = () => { clientSecret: data.clientSecret || "", name: data.name || "", redirectUri: data.redirectUri || "", - giteaUrl: data.giteaUrl || "https://gitea.com", // Use Gitea URL + giteaUrl: data.giteaUrl || "https://gitea.com", }) .then(async () => { await utils.gitProvider.getAll.invalidate(); @@ -177,7 +177,7 @@ export const AddGiteaProvider = () => { ( Gitea URL @@ -240,7 +240,7 @@ export const AddGiteaProvider = () => { /> diff --git a/apps/dokploy/components/dashboard/settings/web-server/manage-traefik-ports.tsx b/apps/dokploy/components/dashboard/settings/web-server/manage-traefik-ports.tsx index d20b7c91..dd9839e3 100644 --- a/apps/dokploy/components/dashboard/settings/web-server/manage-traefik-ports.tsx +++ b/apps/dokploy/components/dashboard/settings/web-server/manage-traefik-ports.tsx @@ -161,7 +161,11 @@ export const ManageTraefikPorts = ({ children, serverId }: Props) => { {...field} onChange={(e) => { const value = e.target.value; - field.onChange(value === "" ? undefined : Number(value)); + field.onChange( + value === "" + ? undefined + : Number(value), + ); }} value={field.value || ""} className="w-full dark:bg-black" @@ -189,7 +193,11 @@ export const ManageTraefikPorts = ({ children, serverId }: Props) => { {...field} onChange={(e) => { const value = e.target.value; - field.onChange(value === "" ? undefined : Number(value)); + field.onChange( + value === "" + ? undefined + : Number(value), + ); }} value={field.value || ""} className="w-full dark:bg-black" diff --git a/apps/dokploy/server/api/routers/application.ts b/apps/dokploy/server/api/routers/application.ts index a0b1a964..fcf19806 100644 --- a/apps/dokploy/server/api/routers/application.ts +++ b/apps/dokploy/server/api/routers/application.ts @@ -424,6 +424,7 @@ export const applicationRouter = createTRPCRouter({ giteaId: input.giteaId, giteaProjectId: input.giteaProjectId, giteaPathNamespace: input.giteaPathNamespace, + watchPaths: input.watchPaths, }); return true; diff --git a/apps/dokploy/server/api/routers/gitea.ts b/apps/dokploy/server/api/routers/gitea.ts index 89d21a77..dc194de8 100644 --- a/apps/dokploy/server/api/routers/gitea.ts +++ b/apps/dokploy/server/api/routers/gitea.ts @@ -21,220 +21,202 @@ import { import { TRPCError } from "@trpc/server"; -// Gitea Router export const giteaRouter = createTRPCRouter({ // Create a new Gitea provider create: protectedProcedure - .input(apiCreateGitea) - .mutation(async ({ input, ctx }) => { - try { - return await createGitea(input, ctx.session.activeOrganizationId); - } catch (error) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Error creating this Gitea provider", - cause: error, - }); - } - }), - + .input(apiCreateGitea) + .mutation(async ({ input, ctx }: { input: typeof apiCreateGitea._input; ctx: any }) => { + try { + return await createGitea(input, ctx.session.activeOrganizationId); + } catch (error) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Error creating this Gitea provider", + cause: error, + }); + } + }), + // Fetch a specific Gitea provider by ID one: protectedProcedure - .input(apiFindOneGitea) - .query(async ({ input, ctx }) => { - const giteaProvider = await findGiteaById(input.giteaId); - if ( - giteaProvider.gitProvider.organizationId !== - ctx.session.activeOrganizationId - ) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not allowed to access this Gitea provider", - }); - } - return giteaProvider; - }), - + .input(apiFindOneGitea) + .query(async ({ input, ctx }: { input: typeof apiFindOneGitea._input; ctx: any }) => { + const giteaProvider = await findGiteaById(input.giteaId); + if ( + giteaProvider.gitProvider.organizationId !== ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not allowed to access this Gitea provider", + }); + } + return giteaProvider; + }), + // Fetch all Gitea providers for the active organization - giteaProviders: protectedProcedure.query(async ({ ctx }) => { - let result = await db.query.gitea.findMany({ - with: { - gitProvider: true, + giteaProviders: protectedProcedure.query(async ({ ctx }: { ctx: any }) => { + let result = await db.query.gitea.findMany({ + with: { + gitProvider: true, + }, + }); + + // Filter by organization ID + result = result.filter( + (provider) => + provider.gitProvider.organizationId === ctx.session.activeOrganizationId, + ); + + // Filter providers that meet the requirements + const filtered = result + .filter((provider) => haveGiteaRequirements(provider)) + .map((provider) => { + return { + giteaId: provider.giteaId, + gitProvider: { + ...provider.gitProvider, }, + }; }); - - // Filter by organization ID - result = result.filter( - (provider) => - provider.gitProvider.organizationId === - ctx.session.activeOrganizationId, - ); - - // Filter providers that meet the requirements - const filtered = result - .filter((provider) => haveGiteaRequirements(provider)) - .map((provider) => { - return { - giteaId: provider.giteaId, - gitProvider: { - ...provider.gitProvider, - }, - }; - }); - - return filtered; + + return filtered; }), - + // Fetch repositories from Gitea provider getGiteaRepositories: protectedProcedure - .input(apiFindOneGitea) - .query(async ({ input, ctx }) => { - const { giteaId } = input; - - if (!giteaId) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: "Gitea provider ID is required.", - }); - } - - const giteaProvider = await findGiteaById(giteaId); - if ( - giteaProvider.gitProvider.organizationId !== - ctx.session.activeOrganizationId - ) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not allowed to access this Gitea provider", - }); - } - - try { - // Call the service layer function to get repositories - console.log("Calling getGiteaRepositories with giteaId:", giteaId); - return await getGiteaRepositories(giteaId); - } catch (error) { - console.error("Error fetching Gitea repositories:", error); - throw new TRPCError({ - code: "BAD_REQUEST", - message: error instanceof Error ? error.message : String(error), - }); - } - }), - + .input(apiFindOneGitea) + .query(async ({ input, ctx }: { input: typeof apiFindOneGitea._input; ctx: any }) => { + const { giteaId } = input; + + if (!giteaId) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Gitea provider ID is required.", + }); + } + + const giteaProvider = await findGiteaById(giteaId); + if ( + giteaProvider.gitProvider.organizationId !== ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not allowed to access this Gitea provider", + }); + } + + try { + return await getGiteaRepositories(giteaId); + } catch (error) { + console.error("Error fetching Gitea repositories:", error); + throw new TRPCError({ + code: "BAD_REQUEST", + message: error instanceof Error ? error.message : String(error), + }); + } + }), + // Fetch branches of a specific Gitea repository getGiteaBranches: protectedProcedure - .input(apiFindGiteaBranches) - .query(async ({ input, ctx }) => { - const { giteaId, owner, repositoryName } = input; - - if (!giteaId || !owner || !repositoryName) { - throw new TRPCError({ - code: "BAD_REQUEST", - message: - "Gitea provider ID, owner, and repository name are required.", - }); - } - - const giteaProvider = await findGiteaById(giteaId); - if ( - giteaProvider.gitProvider.organizationId !== - ctx.session.activeOrganizationId - ) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not allowed to access this Gitea provider", - }); - } - - try { - // Call the service layer function with the required parameters - console.log("Calling getGiteaBranches with:", { - giteaId, - owner, - repo: repositoryName, - }); - - return await getGiteaBranches({ - giteaId, - owner, - repo: repositoryName, - id: 0, // Provide a default value for the optional id - }); - } catch (error) { - console.error("Error fetching Gitea branches:", error); - throw new TRPCError({ - code: "BAD_REQUEST", - message: error instanceof Error ? error.message : String(error), - }); - } - }), - + .input(apiFindGiteaBranches) + .query(async ({ input, ctx }: { input: typeof apiFindGiteaBranches._input; ctx: any }) => { + const { giteaId, owner, repositoryName } = input; + + if (!giteaId || !owner || !repositoryName) { + throw new TRPCError({ + code: "BAD_REQUEST", + message: "Gitea provider ID, owner, and repository name are required.", + }); + } + + const giteaProvider = await findGiteaById(giteaId); + if ( + giteaProvider.gitProvider.organizationId !== ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not allowed to access this Gitea provider", + }); + } + + try { + return await getGiteaBranches({ + giteaId, + owner, + repo: repositoryName, + id: 0, // Provide a default value for the optional id + }); + } catch (error) { + console.error("Error fetching Gitea branches:", error); + throw new TRPCError({ + code: "BAD_REQUEST", + message: error instanceof Error ? error.message : String(error), + }); + } + }), + // Test connection to Gitea provider testConnection: protectedProcedure - .input(apiGiteaTestConnection) - .mutation(async ({ input, ctx }) => { - // Ensure giteaId is always a non-empty string - const giteaId = input.giteaId ?? ""; - - try { - const giteaProvider = await findGiteaById(giteaId); - if ( - giteaProvider.gitProvider.organizationId !== - ctx.session.activeOrganizationId - ) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not allowed to access this Gitea provider", - }); - } - - const result = await testGiteaConnection({ - giteaId, - }); - - return `Found ${result} repositories`; - } catch (error) { - console.error("Gitea connection test error:", error); - throw new TRPCError({ - code: "BAD_REQUEST", - message: error instanceof Error ? error.message : String(error), - }); - } - }), - + .input(apiGiteaTestConnection) + .mutation(async ({ input, ctx }: { input: typeof apiGiteaTestConnection._input; ctx: any }) => { + const giteaId = input.giteaId ?? ""; + + try { + const giteaProvider = await findGiteaById(giteaId); + if ( + giteaProvider.gitProvider.organizationId !== ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not allowed to access this Gitea provider", + }); + } + + const result = await testGiteaConnection({ + giteaId, + }); + + return `Found ${result} repositories`; + } catch (error) { + console.error("Gitea connection test error:", error); + throw new TRPCError({ + code: "BAD_REQUEST", + message: error instanceof Error ? error.message : String(error), + }); + } + }), + // Update an existing Gitea provider update: protectedProcedure - .input(apiUpdateGitea) - .mutation(async ({ input, ctx }) => { - const giteaProvider = await findGiteaById(input.giteaId); - if ( - giteaProvider.gitProvider.organizationId !== - ctx.session.activeOrganizationId - ) { - throw new TRPCError({ - code: "UNAUTHORIZED", - message: "You are not allowed to access this Gitea provider", - }); - } - - console.log("Updating Gitea provider:", input); - - if (input.name) { - await updateGitProvider(input.gitProviderId, { - name: input.name, - organizationId: ctx.session.activeOrganizationId, - }); - - await updateGitea(input.giteaId, { - ...input, - }); - } else { - await updateGitea(input.giteaId, { - ...input, - }); - } - - return { success: true }; - }), -}); + .input(apiUpdateGitea) + .mutation(async ({ input, ctx }: { input: typeof apiUpdateGitea._input; ctx: any }) => { + const giteaProvider = await findGiteaById(input.giteaId); + if ( + giteaProvider.gitProvider.organizationId !== ctx.session.activeOrganizationId + ) { + throw new TRPCError({ + code: "UNAUTHORIZED", + message: "You are not allowed to access this Gitea provider", + }); + } + + console.log("Updating Gitea provider:", input); + + if (input.name) { + await updateGitProvider(input.gitProviderId, { + name: input.name, + organizationId: ctx.session.activeOrganizationId, + }); + + await updateGitea(input.giteaId, { + ...input, + }); + } else { + await updateGitea(input.giteaId, { + ...input, + }); + } + + return { success: true }; + }), + }); \ No newline at end of file diff --git a/packages/server/src/db/schema/application.ts b/packages/server/src/db/schema/application.ts index b5ca987e..aed811e0 100644 --- a/packages/server/src/db/schema/application.ts +++ b/packages/server/src/db/schema/application.ts @@ -511,6 +511,7 @@ export const apiSaveGiteaProvider = createSchema giteaId: true, giteaProjectId: true, giteaPathNamespace: true, + watchPaths: true, }) .required(); diff --git a/packages/server/src/services/gitea.ts b/packages/server/src/services/gitea.ts index fecd8134..c5e0139a 100644 --- a/packages/server/src/services/gitea.ts +++ b/packages/server/src/services/gitea.ts @@ -23,7 +23,7 @@ export const createGitea = async ( name: input.name, }) .returning() - .then((response: typeof gitProvider.$inferSelect[]) => response[0]); + .then((response: (typeof gitProvider.$inferSelect)[]) => response[0]); if (!newGitProvider) { throw new TRPCError({ @@ -39,7 +39,7 @@ export const createGitea = async ( gitProviderId: newGitProvider?.gitProviderId, }) .returning() - .then((response: typeof gitea.$inferSelect[]) => response[0]); + .then((response: (typeof gitea.$inferSelect)[]) => response[0]); }); }; @@ -96,4 +96,4 @@ export const updateGitea = async (giteaId: string, input: Partial) => { console.error("Error updating Gitea provider:", error); throw error; } -}; \ No newline at end of file +};