diff --git a/apps/dokploy/components/dashboard/application/deployments/show-deployments-modal.tsx b/apps/dokploy/components/dashboard/application/deployments/show-deployments-modal.tsx new file mode 100644 index 00000000..f9a26c40 --- /dev/null +++ b/apps/dokploy/components/dashboard/application/deployments/show-deployments-modal.tsx @@ -0,0 +1,63 @@ +import { Button } from "@/components/ui/button"; +import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"; + +import type { RouterOutputs } from "@/utils/api"; +import { useState } from "react"; +import { ShowDeployment } from "../deployments/show-deployment"; +import { ShowDeployments } from "./show-deployments"; + +interface Props { + id: string; + type: "application" | "compose" | "schedule" | "server" | "backup"; + serverId?: string; + refreshToken?: string; + children?: React.ReactNode; +} + +export const formatDuration = (seconds: number) => { + if (seconds < 60) return `${seconds}s`; + const minutes = Math.floor(seconds / 60); + const remainingSeconds = seconds % 60; + return `${minutes}m ${remainingSeconds}s`; +}; + +export const ShowDeploymentsModal = ({ + id, + type, + serverId, + refreshToken, + children, +}: Props) => { + const [activeLog, setActiveLog] = useState< + RouterOutputs["deployment"]["all"][number] | null + >(null); + const [isOpen, setIsOpen] = useState(false); + return ( + + + {children ? ( + children + ) : ( + + )} + + + + + setActiveLog(null)} + logPath={activeLog?.logPath || ""} + errorMessage={activeLog?.errorMessage || ""} + /> + + ); +}; diff --git a/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx b/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx index dc8d3065..c2c629dd 100644 --- a/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx +++ b/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx @@ -16,35 +16,34 @@ import { RefreshToken } from "./refresh-token"; import { ShowDeployment } from "./show-deployment"; import { Badge } from "@/components/ui/badge"; import { formatDuration } from "../schedules/show-schedules-logs"; + interface Props { id: string; - type: "application" | "compose"; + type: "application" | "compose" | "schedule" | "server" | "backup"; + refreshToken?: string; + serverId?: string; } -export const ShowDeployments = ({ id, type }: Props) => { +export const ShowDeployments = ({ + id, + type, + refreshToken, + serverId, +}: Props) => { const [activeLog, setActiveLog] = useState< RouterOutputs["deployment"]["all"][number] | null >(null); - const { data } = - type === "application" - ? api.application.one.useQuery({ applicationId: id }) - : api.compose.one.useQuery({ composeId: id }); const { data: deployments, isLoading: isLoadingDeployments } = - type === "application" - ? api.deployment.all.useQuery( - { applicationId: id }, - { - enabled: !!id, - refetchInterval: 1000, - }, - ) - : api.deployment.allByCompose.useQuery( - { composeId: id }, - { - enabled: !!id, - refetchInterval: 1000, - }, - ); + api.deployment.allByType.useQuery( + { + id, + type, + }, + { + enabled: !!id, + refetchInterval: 1000, + }, + ); const [url, setUrl] = React.useState(""); useEffect(() => { @@ -52,7 +51,7 @@ export const ShowDeployments = ({ id, type }: Props) => { }, []); return ( - +
Deployments @@ -60,24 +59,27 @@ export const ShowDeployments = ({ id, type }: Props) => { See all the 10 last deployments for this {type}
- + {refreshToken && }
-
- - If you want to re-deploy this application use this URL in the config - of your git provider or docker - -
- Webhook URL: -
- - {`${url}/api/deploy/${data?.refreshToken}`} - - + {refreshToken && ( +
+ + If you want to re-deploy this application use this URL in the + config of your git provider or docker + +
+ Webhook URL: +
+ + {`${url}/api/deploy/${refreshToken}`} + + +
-
+ )} + {isLoadingDeployments ? (
@@ -85,7 +87,7 @@ export const ShowDeployments = ({ id, type }: Props) => { Loading deployments...
- ) : data?.deployments?.length === 0 ? ( + ) : deployments?.length === 0 ? (
@@ -149,7 +151,7 @@ export const ShowDeployments = ({ id, type }: Props) => {
)} setActiveLog(null)} logPath={activeLog?.logPath || ""} diff --git a/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx b/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx index 19092ec9..89fa7295 100644 --- a/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx +++ b/apps/dokploy/components/dashboard/application/schedules/show-schedules.tsx @@ -18,7 +18,6 @@ import { } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { toast } from "sonner"; -import { ShowSchedulesLogs } from "./show-schedules-logs"; import { Tooltip, TooltipContent, @@ -26,6 +25,7 @@ import { TooltipTrigger, } from "@/components/ui/tooltip"; import { DialogAction } from "@/components/shared/dialog-action"; +import { ShowDeploymentsModal } from "../deployments/show-deployments-modal"; interface Props { id: string; @@ -88,7 +88,6 @@ export const ShowSchedules = ({ id, scheduleType = "application" }: Props) => { schedule.serverId || schedule.application?.serverId || schedule.compose?.serverId; - const deployments = schedule.deployments; return (
{
- - + diff --git a/apps/dokploy/components/dashboard/database/backups/show-backups.tsx b/apps/dokploy/components/dashboard/database/backups/show-backups.tsx index 81a2a299..d4aa4368 100644 --- a/apps/dokploy/components/dashboard/database/backups/show-backups.tsx +++ b/apps/dokploy/components/dashboard/database/backups/show-backups.tsx @@ -35,7 +35,7 @@ import { PostgresqlIcon, } from "@/components/icons/data-tools-icons"; import { AlertBlock } from "@/components/shared/alert-block"; -import { ShowSchedulesLogs } from "../../application/schedules/show-schedules-logs"; +import { ShowDeploymentsModal } from "../../application/deployments/show-deployments-modal"; interface Props { id: string; @@ -179,12 +179,6 @@ export const ShowBackups = ({ )}
{postgres?.backups.map((backup) => { - const orderedDeployments = backup.deployments.sort( - (a, b) => - new Date(b.createdAt).getTime() - - new Date(a.createdAt).getTime(), - ); - const serverId = "serverId" in postgres ? postgres.serverId : undefined; @@ -285,8 +279,9 @@ export const ShowBackups = ({
- - + diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx index 61f9178c..ceb7b408 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/application/[applicationId].tsx @@ -318,9 +318,14 @@ const Service = ( />
- -
- + +
+
diff --git a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx index befc7ff6..8d9639a2 100644 --- a/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx +++ b/apps/dokploy/pages/dashboard/project/[projectId]/services/compose/[composeId].tsx @@ -6,7 +6,6 @@ import { ShowEnvironment } from "@/components/dashboard/application/environment/ import { ShowSchedules } from "@/components/dashboard/application/schedules/show-schedules"; import { AddCommandCompose } from "@/components/dashboard/compose/advanced/add-command"; import { DeleteService } from "@/components/dashboard/compose/delete-service"; -import { ShowDeploymentsCompose } from "@/components/dashboard/compose/deployments/show-deployments-compose"; import { ShowGeneralCompose } from "@/components/dashboard/compose/general/show"; import { ShowDockerLogsCompose } from "@/components/dashboard/compose/logs/show"; import { ShowDockerLogsStack } from "@/components/dashboard/compose/logs/show-stack"; @@ -334,7 +333,12 @@ const Service = (
- +
diff --git a/apps/dokploy/server/api/routers/deployment.ts b/apps/dokploy/server/api/routers/deployment.ts index 8d95c121..238b3317 100644 --- a/apps/dokploy/server/api/routers/deployment.ts +++ b/apps/dokploy/server/api/routers/deployment.ts @@ -2,6 +2,8 @@ import { apiFindAllByApplication, apiFindAllByCompose, apiFindAllByServer, + apiFindAllByType, + deployments, } from "@/server/db/schema"; import { findAllDeploymentsByApplicationId, @@ -12,7 +14,9 @@ import { findServerById, } from "@dokploy/server"; import { TRPCError } from "@trpc/server"; +import { desc, eq } from "drizzle-orm"; import { createTRPCRouter, protectedProcedure } from "../trpc"; +import { db } from "@/server/db"; export const deploymentRouter = createTRPCRouter({ all: protectedProcedure @@ -54,4 +58,14 @@ export const deploymentRouter = createTRPCRouter({ } return await findAllDeploymentsByServerId(input.serverId); }), + + allByType: protectedProcedure + .input(apiFindAllByType) + .query(async ({ input }) => { + const deploymentsList = await db.query.deployments.findMany({ + where: eq(deployments[`${input.type}Id`], input.id), + orderBy: desc(deployments.createdAt), + }); + return deploymentsList; + }), }); diff --git a/packages/server/src/db/schema/deployment.ts b/packages/server/src/db/schema/deployment.ts index d019d980..8e13bf6c 100644 --- a/packages/server/src/db/schema/deployment.ts +++ b/packages/server/src/db/schema/deployment.ts @@ -195,3 +195,17 @@ export const apiFindAllByServer = schema serverId: z.string().min(1), }) .required(); + +export const apiFindAllByType = z + .object({ + id: z.string().min(1), + type: z.enum([ + "application", + "compose", + "server", + "schedule", + "previewDeployment", + "backup", + ]), + }) + .required();