diff --git a/apps/dokploy/components/dashboard/application/deployments/show-deployment.tsx b/apps/dokploy/components/dashboard/application/deployments/show-deployment.tsx index 69c697721..0d403ecd2 100644 --- a/apps/dokploy/components/dashboard/application/deployments/show-deployment.tsx +++ b/apps/dokploy/components/dashboard/application/deployments/show-deployment.tsx @@ -1,6 +1,8 @@ -import { Loader2 } from "lucide-react"; +import copy from "copy-to-clipboard"; +import { Check, Copy, Loader2 } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; import { Checkbox } from "@/components/ui/checkbox"; import { Dialog, @@ -29,9 +31,10 @@ export const ShowDeployment = ({ const [data, setData] = useState(""); const [showExtraLogs, setShowExtraLogs] = useState(false); const [filteredLogs, setFilteredLogs] = useState([]); - const wsRef = useRef(null); // Ref to hold WebSocket instance + const wsRef = useRef(null); const [autoScroll, setAutoScroll] = useState(true); const scrollRef = useRef(null); + const [copied, setCopied] = useState(false); const scrollToBottom = () => { if (autoScroll && scrollRef.current) { @@ -106,6 +109,20 @@ export const ShowDeployment = ({ } }, [filteredLogs, autoScroll]); + const handleCopy = () => { + const logContent = filteredLogs + .map(({ timestamp, message }: LogLine) => + `${timestamp?.toISOString() || ""} ${message}`.trim(), + ) + .join("\n"); + + const success = copy(logContent); + if (success) { + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } + }; + const optionalErrors = parseLogs(errorMessage || ""); return ( @@ -128,13 +145,27 @@ export const ShowDeployment = ({ Deployment - + See all the details of this deployment |{" "} {filteredLogs.length} lines + + {serverId && (
= ({ const isPausedRef = useRef(false); const scrollRef = useRef(null); const [isLoading, setIsLoading] = React.useState(false); + const [copied, setCopied] = React.useState(false); const scrollToBottom = () => { if (autoScroll && scrollRef.current) { @@ -237,6 +246,29 @@ export const DockerLogsId: React.FC = ({ URL.revokeObjectURL(url); }; + const handleCopy = async () => { + const logContent = filteredLogs + .map( + ({ + timestamp, + message, + }: { + timestamp: Date | null; + message: string; + }) => + showTimestamp + ? `${timestamp?.toISOString() || "No timestamp"} ${message}` + : message, + ) + .join("\n"); + + const success = copy(logContent); + if (success) { + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } + }; + const handleFilter = (logs: LogLine[]) => { return logs.filter((log) => { const logType = getLogType(log.message).type; @@ -320,6 +352,21 @@ export const DockerLogsId: React.FC = ({ )} {isPaused ? "Resume" : "Pause"} +