diff --git a/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx b/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx index 1045856c2..1885ffc3a 100644 --- a/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx +++ b/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx @@ -1,4 +1,12 @@ -import { Clock, Loader2, RefreshCcw, RocketIcon, Settings } from "lucide-react"; +import { + ChevronDown, + ChevronUp, + Clock, + Loader2, + RefreshCcw, + RocketIcon, + Settings, +} from "lucide-react"; import React, { useEffect, useMemo, useState } from "react"; import { toast } from "sonner"; import { AlertBlock } from "@/components/shared/alert-block"; @@ -80,6 +88,23 @@ export const ShowDeployments = ({ } = api.compose.cancelDeployment.useMutation(); const [url, setUrl] = React.useState(""); + const [expandedDescriptions, setExpandedDescriptions] = useState>( + new Set(), + ); + + const MAX_DESCRIPTION_LENGTH = 200; + + const truncateDescription = (description: string): string => { + if (description.length <= MAX_DESCRIPTION_LENGTH) { + return description; + } + const truncated = description.slice(0, MAX_DESCRIPTION_LENGTH); + const lastSpace = truncated.lastIndexOf(" "); + if (lastSpace > MAX_DESCRIPTION_LENGTH - 20 && lastSpace > 0) { + return `${truncated.slice(0, lastSpace)}...`; + } + return `${truncated}...`; + }; // Check for stuck deployment (more than 9 minutes) - only for the most recent deployment const stuckDeployment = useMemo(() => { @@ -217,118 +242,164 @@ export const ShowDeployments = ({ ) : (
- {deployments?.map((deployment, index) => ( -
-
- - {index + 1}. {deployment.status} - - - - {deployment.title} - - {deployment.description && ( - - {deployment.description} + {deployments?.map((deployment, index) => { + const titleText = deployment?.title?.trim() || ""; + const needsTruncation = titleText.length > MAX_DESCRIPTION_LENGTH; + const isExpanded = expandedDescriptions.has( + deployment.deploymentId, + ); + + return ( +
+
+ + {index + 1}. {deployment.status} + - )} -
-
-
- - {deployment.startedAt && deployment.finishedAt && ( - - - {formatDuration( - Math.floor( - (new Date(deployment.finishedAt).getTime() - - new Date(deployment.startedAt).getTime()) / - 1000, - ), - )} - - )} -
-
- {deployment.pid && deployment.status === "running" && ( - { - await killProcess({ - deploymentId: deployment.deploymentId, - }) - .then(() => { - toast.success("Process killed successfully"); - }) - .catch(() => { - toast.error("Error killing process"); - }); - }} - > - - - )} - + {isExpanded ? ( + <> + + Show less + + ) : ( + <> + + Show more + + )} + + )} + {/* Hash (from description) - shown in compact form */} + {deployment.description?.trim() && ( + + {deployment.description} + + )} +
+
+
+
+ + {deployment.startedAt && deployment.finishedAt && ( + + + {formatDuration( + Math.floor( + (new Date(deployment.finishedAt).getTime() - + new Date(deployment.startedAt).getTime()) / + 1000, + ), + )} + + )} +
- {deployment?.rollback && - deployment.status === "done" && - type === "application" && ( +
+ {deployment.pid && deployment.status === "running" && ( { - await rollback({ - rollbackId: deployment.rollback.rollbackId, + await killProcess({ + deploymentId: deployment.deploymentId, }) .then(() => { - toast.success( - "Rollback initiated successfully", - ); + toast.success("Process killed successfully"); }) .catch(() => { - toast.error("Error initiating rollback"); + toast.error("Error killing process"); }); }} > )} + + + {deployment?.rollback && + deployment.status === "done" && + type === "application" && ( + { + await rollback({ + rollbackId: deployment.rollback.rollbackId, + }) + .then(() => { + toast.success( + "Rollback initiated successfully", + ); + }) + .catch(() => { + toast.error("Error initiating rollback"); + }); + }} + > + + + )} +
-
- ))} + ); + })}
)}