diff --git a/README.md b/README.md index 33891a3c..28b1f226 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ Dokploy include multiples features to make your life easier. - **Docker Management**: Easily deploy and manage Docker containers. - **CLI/API**: Manage your applications and databases using the command line or trought the API. - **Notifications**: Get notified when your deployments are successful or failed (Slack, Discord, Telegram, Email, etc.) +- **Multi Server**: Deploy and manager your applications remotely to external servers. - **Self-Hosted**: Self-host Dokploy on your VPS. ## 🚀 Getting Started diff --git a/apps/dokploy/components/dashboard/projects/show.tsx b/apps/dokploy/components/dashboard/projects/show.tsx index a6bdc5b9..6c3ff8cd 100644 --- a/apps/dokploy/components/dashboard/projects/show.tsx +++ b/apps/dokploy/components/dashboard/projects/show.tsx @@ -15,20 +15,25 @@ import { Card, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; import { DropdownMenu, DropdownMenuContent, + DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, + DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { api } from "@/utils/api"; import { AlertTriangle, BookIcon, + CircuitBoard, + ExternalLink, ExternalLinkIcon, FolderInput, MoreHorizontalIcon, TrashIcon, } from "lucide-react"; import Link from "next/link"; +import { Fragment } from "react"; import { toast } from "sonner"; import { UpdateProject } from "./update"; @@ -45,6 +50,7 @@ export const ShowProjects = () => { }, ); const { mutateAsync } = api.project.remove.useMutation(); + return ( <> {data?.length === 0 && ( @@ -74,17 +80,87 @@ export const ShowProjects = () => { project?.redis.length + project?.applications.length + project?.compose.length; + + const flattedDomains = [ + ...project.applications.flatMap((a) => a.domains), + ...project.compose.flatMap((a) => a.domains), + ]; + + const renderDomainsDropdown = ( + item: typeof project.compose | typeof project.applications, + ) => + item[0] ? ( + + + {"applicationId" in item[0] ? "Applications" : "Compose"} + + {item.map((a) => ( + + + + + {a.name} + + + {a.domains.map((domain) => ( + + + {domain.host} + + + + ))} + + + ))} + + ) : null; + return (
- + {flattedDomains.length > 1 ? ( + + + + + e.stopPropagation()} + > + {renderDomainsDropdown(project.applications)} + {renderDomainsDropdown(project.compose)} + + + ) : flattedDomains[0] ? ( + + ) : null} + diff --git a/apps/dokploy/server/api/routers/application.ts b/apps/dokploy/server/api/routers/application.ts index 85ceb1e3..270f6ca7 100644 --- a/apps/dokploy/server/api/routers/application.ts +++ b/apps/dokploy/server/api/routers/application.ts @@ -86,6 +86,7 @@ export const applicationRouter = createTRPCRouter({ if (ctx.user.rol === "user") { await addNewService(ctx.user.authId, newApplication.applicationId); } + return newApplication; } catch (error: unknown) { if (error instanceof TRPCError) { throw error; diff --git a/apps/dokploy/server/api/routers/project.ts b/apps/dokploy/server/api/routers/project.ts index acc58d12..c3fe8605 100644 --- a/apps/dokploy/server/api/routers/project.ts +++ b/apps/dokploy/server/api/routers/project.ts @@ -132,6 +132,7 @@ export const projectRouter = createTRPCRouter({ applications.applicationId, accesedServices, ), + with: { domains: true }, }, mariadb: { where: buildServiceFilter(mariadb.mariadbId, accesedServices), @@ -150,6 +151,7 @@ export const projectRouter = createTRPCRouter({ }, compose: { where: buildServiceFilter(compose.composeId, accesedServices), + with: { domains: true }, }, }, orderBy: desc(projects.createdAt), @@ -160,13 +162,21 @@ export const projectRouter = createTRPCRouter({ return await db.query.projects.findMany({ with: { - applications: true, + applications: { + with: { + domains: true, + }, + }, mariadb: true, mongo: true, mysql: true, postgres: true, redis: true, - compose: true, + compose: { + with: { + domains: true, + }, + }, }, where: eq(projects.adminId, ctx.user.adminId), orderBy: desc(projects.createdAt),