diff --git a/apps/dokploy/components/dashboard/project/add-application.tsx b/apps/dokploy/components/dashboard/project/add-application.tsx index 3ab9f9ae..1c829895 100644 --- a/apps/dokploy/components/dashboard/project/add-application.tsx +++ b/apps/dokploy/components/dashboard/project/add-application.tsx @@ -73,7 +73,7 @@ export const AddApplication = ({ projectId, projectName }: Props) => { const [visible, setVisible] = useState(false); const slug = slugify(projectName); - const { data: servers } = api.server.all.useQuery(); + const { data: servers } = api.server.withSSHKey.useQuery(); const { mutateAsync, isLoading, error, isError } = api.application.create.useMutation(); diff --git a/apps/dokploy/components/dashboard/project/add-compose.tsx b/apps/dokploy/components/dashboard/project/add-compose.tsx index 89240a04..c0f357cc 100644 --- a/apps/dokploy/components/dashboard/project/add-compose.tsx +++ b/apps/dokploy/components/dashboard/project/add-compose.tsx @@ -72,7 +72,7 @@ interface Props { export const AddCompose = ({ projectId, projectName }: Props) => { const utils = api.useUtils(); const slug = slugify(projectName); - const { data: servers } = api.server.all.useQuery(); + const { data: servers } = api.server.withSSHKey.useQuery(); const { mutateAsync, isLoading, error, isError } = api.compose.create.useMutation(); diff --git a/apps/dokploy/components/dashboard/project/add-database.tsx b/apps/dokploy/components/dashboard/project/add-database.tsx index 32994caa..7db399e9 100644 --- a/apps/dokploy/components/dashboard/project/add-database.tsx +++ b/apps/dokploy/components/dashboard/project/add-database.tsx @@ -157,7 +157,7 @@ export const AddDatabase = ({ projectId, projectName }: Props) => { const utils = api.useUtils(); const [visible, setVisible] = useState(false); const slug = slugify(projectName); - const { data: servers } = api.server.all.useQuery(); + const { data: servers } = api.server.withSSHKey.useQuery(); const postgresMutation = api.postgres.create.useMutation(); const mongoMutation = api.mongo.create.useMutation(); const redisMutation = api.redis.create.useMutation(); diff --git a/apps/dokploy/components/dashboard/project/add-template.tsx b/apps/dokploy/components/dashboard/project/add-template.tsx index 40a1d670..0f84316a 100644 --- a/apps/dokploy/components/dashboard/project/add-template.tsx +++ b/apps/dokploy/components/dashboard/project/add-template.tsx @@ -19,6 +19,21 @@ import { CommandInput, CommandItem, } from "@/components/ui/command"; +import { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectTrigger, + SelectValue, +} from "@/components/ui/select"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; import { Dialog, DialogContent, @@ -43,12 +58,14 @@ import { Code, Github, Globe, + HelpCircle, PuzzleIcon, SearchIcon, } from "lucide-react"; import Link from "next/link"; import { useState } from "react"; import { toast } from "sonner"; +import { Label } from "@/components/ui/label"; interface Props { projectId: string; } @@ -58,9 +75,12 @@ export const AddTemplate = ({ projectId }: Props) => { const [open, setOpen] = useState(false); const { data } = api.compose.templates.useQuery(); const [selectedTags, setSelectedTags] = useState([]); + const { data: servers } = api.server.withSSHKey.useQuery(); const { data: tags, isLoading: isLoadingTags } = api.compose.getTags.useQuery(); const utils = api.useUtils(); + + const [serverId, setServerId] = useState(undefined); const { mutateAsync, isLoading, error, isError } = api.compose.deployTemplate.useMutation(); @@ -109,7 +129,6 @@ export const AddTemplate = ({ projectId }: Props) => { role="combobox" className={cn( "md:max-w-[15rem] w-full justify-between !bg-input", - // !field.value && "text-muted-foreground", )} > {isLoadingTags @@ -267,30 +286,79 @@ export const AddTemplate = ({ projectId }: Props) => { This will deploy {template.name} template to your project. + +
+ + + + + + + + If not server is selected, the + application will be deployed on the + server where the user is logged in. + + + + + + +
Cancel { - await mutateAsync({ + const promise = mutateAsync({ projectId, + serverId: serverId || undefined, id: template.id, - }) - .then(async () => { - toast.success( - `${template.name} template created succesfully`, - ); - + }); + toast.promise(promise, { + loading: "Setting up...", + success: (data) => { utils.project.one.invalidate({ projectId, }); setOpen(false); - }) - .catch(() => { - toast.error( - `Error to delete ${template.name} template`, - ); - }); + return `${template.name} template created succesfully`; + }, + error: (err) => { + return `Ocurred an error deploying ${template.name} template`; + }, + }); }} > Confirm diff --git a/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx b/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx index 147ebfc7..75580773 100644 --- a/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx +++ b/apps/dokploy/components/dashboard/settings/servers/show-servers.tsx @@ -26,7 +26,7 @@ import { TerminalModal } from "../web-server/terminal-modal"; import { AddServer } from "./add-server"; import { SetupServer } from "./setup-server"; export const ShowServers = () => { - const { data, refetch } = api.server.all.useQuery(); + const { data, refetch } = api.server.withSSHKey.useQuery(); const { mutateAsync } = api.server.remove.useMutation(); const { data: sshKeys } = api.sshKey.all.useQuery(); diff --git a/apps/dokploy/server/api/routers/compose.ts b/apps/dokploy/server/api/routers/compose.ts index 5034f220..433b5345 100644 --- a/apps/dokploy/server/api/routers/compose.ts +++ b/apps/dokploy/server/api/routers/compose.ts @@ -37,7 +37,7 @@ import { eq } from "drizzle-orm"; import { dump } from "js-yaml"; import _ from "lodash"; import { nanoid } from "nanoid"; -import { findAdmin } from "../services/admin"; +import { findAdmin, findAdminById } from "../services/admin"; import { createCompose, createComposeByTemplate, @@ -53,6 +53,7 @@ import { createMount } from "../services/mount"; import { findProjectById } from "../services/project"; import { addNewService, checkServiceAccess } from "../services/user"; import { createTRPCRouter, protectedProcedure } from "../trpc"; +import { findServerById } from "../services/server"; export const composeRouter = createTRPCRouter({ create: protectedProcedure @@ -235,7 +236,8 @@ export const composeRouter = createTRPCRouter({ const generate = await loadTemplateModule(input.id as TemplatesKeys); - const admin = await findAdmin(); + const admin = await findAdminById(ctx.user.adminId); + let serverIp = admin.serverIp; if (!admin.serverIp) { throw new TRPCError({ @@ -247,9 +249,14 @@ export const composeRouter = createTRPCRouter({ const project = await findProjectById(input.projectId); + if (input.serverId) { + const server = await findServerById(input.serverId); + serverIp = server.ipAddress; + } + const projectName = slugify(`${project.name} ${input.id}`); const { envs, mounts, domains } = generate({ - serverIp: admin.serverIp, + serverIp: serverIp || "", projectName: projectName, }); @@ -257,6 +264,7 @@ export const composeRouter = createTRPCRouter({ ...input, composeFile: composeFile, env: envs?.join("\n"), + serverId: input.serverId, name: input.id, sourceType: "raw", appName: `${projectName}-${generatePassword(6)}`, diff --git a/apps/dokploy/server/api/routers/server.ts b/apps/dokploy/server/api/routers/server.ts index 1073cda3..cb9f7673 100644 --- a/apps/dokploy/server/api/routers/server.ts +++ b/apps/dokploy/server/api/routers/server.ts @@ -10,7 +10,7 @@ import { } from "@/server/db/schema"; import { setupServer } from "@/server/utils/servers/setup-server"; import { TRPCError } from "@trpc/server"; -import { desc } from "drizzle-orm"; +import { desc, isNotNull } from "drizzle-orm"; import { removeDeploymentsByServerId } from "../services/deployment"; import { createServer, @@ -46,6 +46,12 @@ export const serverRouter = createTRPCRouter({ orderBy: desc(server.createdAt), }); }), + withSSHKey: protectedProcedure.query(async ({ input, ctx }) => { + return await db.query.server.findMany({ + orderBy: desc(server.createdAt), + where: isNotNull(server.sshKeyId), + }); + }), setup: protectedProcedure .input(apiFindOneServer) .mutation(async ({ input, ctx }) => { diff --git a/apps/dokploy/server/api/services/compose.ts b/apps/dokploy/server/api/services/compose.ts index d5f0c0f7..5557c05e 100644 --- a/apps/dokploy/server/api/services/compose.ts +++ b/apps/dokploy/server/api/services/compose.ts @@ -97,7 +97,6 @@ export const createComposeByTemplate = async ( .insert(compose) .values({ ...input, - serverId: "y91z1__c4SJbBe1TwQuaN", }) .returning() .then((value) => value[0]); @@ -304,7 +303,6 @@ export const deployRemoteCompose = async ({ title: titleLog, description: descriptionLog, }); - try { if (compose.serverId) { let command = "set -e;"; @@ -362,6 +360,7 @@ export const deployRemoteCompose = async ({ buildLink, }); } catch (error) { + console.log(error); await updateDeploymentStatus(deployment.deploymentId, "error"); await updateCompose(composeId, { composeStatus: "error", diff --git a/apps/dokploy/server/db/schema/compose.ts b/apps/dokploy/server/db/schema/compose.ts index 662ca4c4..ec376606 100644 --- a/apps/dokploy/server/db/schema/compose.ts +++ b/apps/dokploy/server/db/schema/compose.ts @@ -145,6 +145,7 @@ export const apiCreateComposeByTemplate = createSchema }) .extend({ id: z.string().min(1), + serverId: z.string().optional(), }); export const apiFindCompose = z.object({