From ad490dca3fc60aee4470a669d886bfd2149f462f Mon Sep 17 00:00:00 2001 From: berkay-digital <46861579+berkay-digital@users.noreply.github.com> Date: Thu, 23 Apr 2026 15:19:13 +0200 Subject: [PATCH 01/44] feat: add copy button to AI log analysis result Allows users to quickly copy the AI-generated log analysis to their clipboard from the analyze-logs popover, matching the copy UX used in the deployment and docker logs views. Made-with: Cursor --- .../dashboard/docker/logs/analyze-logs.tsx | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/apps/dokploy/components/dashboard/docker/logs/analyze-logs.tsx b/apps/dokploy/components/dashboard/docker/logs/analyze-logs.tsx index 267735eac..c343294f6 100644 --- a/apps/dokploy/components/dashboard/docker/logs/analyze-logs.tsx +++ b/apps/dokploy/components/dashboard/docker/logs/analyze-logs.tsx @@ -1,5 +1,6 @@ "use client"; -import { Bot, Loader2, RotateCcw, Settings, X } from "lucide-react"; +import copy from "copy-to-clipboard"; +import { Bot, Check, Copy, Loader2, RotateCcw, Settings, X } from "lucide-react"; import Link from "next/link"; import { useState } from "react"; import ReactMarkdown from "react-markdown"; @@ -30,6 +31,7 @@ const MAX_LOG_LINES = 200; export function AnalyzeLogs({ logs, context }: Props) { const [open, setOpen] = useState(false); const [aiId, setAiId] = useState(""); + const [copied, setCopied] = useState(false); const { data: providers } = api.ai.getEnabledProviders.useQuery(undefined, { enabled: open, }); @@ -52,6 +54,15 @@ export function AnalyzeLogs({ logs, context }: Props) { mutate({ aiId, logs: logsText, context }); }; + const handleCopy = () => { + if (!data?.analysis) return; + const success = copy(data.analysis); + if (success) { + setCopied(true); + setTimeout(() => setCopied(false), 2000); + } + }; + return ( + + +
+ ( + +
+ Repository URL + {field.value?.startsWith("https://") && ( + + + View Repository + + )} +
+ + + + +
)} -
-
+ /> + {sshKeys && sshKeys.length > 0 ? ( ( - - Branch + + + SSH Key + + - + - )} /> -
+ ) : ( + + )} + + ( + + Branch + + + + + + )} + /> ( - + Build Path @@ -223,7 +216,7 @@ export const SaveGitProvider = ({ applicationId }: Props) => { control={form.control} name="watchPaths" render={({ field }) => ( - +
Watch Paths diff --git a/apps/dokploy/components/dashboard/application/general/show.tsx b/apps/dokploy/components/dashboard/application/general/show.tsx index 01fc9e84a..faf887e3f 100644 --- a/apps/dokploy/components/dashboard/application/general/show.tsx +++ b/apps/dokploy/components/dashboard/application/general/show.tsx @@ -58,7 +58,10 @@ export const ShowGeneralApplication = ({ applicationId }: Props) => { Deploy Settings - + {canDeploy && ( { > {canUpdateService && ( -
+
Autodeploy { )} {canUpdateService && ( -
+
Clean Cache { className="h-auto px-2 py-1.5 hover:bg-accent gap-2" > - + {currentProject?.name || "Select Project"} @@ -478,7 +478,7 @@ export const AdvanceBreadcrumb = () => { aria-expanded={environmentOpen} className="h-auto px-2 py-1.5 hover:bg-accent gap-2" > - + {currentEnvironment?.name || "production"} @@ -533,7 +533,7 @@ export const AdvanceBreadcrumb = () => { )} {projectEnvironments && projectEnvironments.length === 1 && ( -

+

{currentEnvironment?.name || "production"}

)} @@ -551,7 +551,7 @@ export const AdvanceBreadcrumb = () => { className="h-auto px-2 py-1.5 hover:bg-accent gap-2" > {getServiceIcon(currentService.type)} - + {currentService.name} @@ -617,7 +617,7 @@ export const AdvanceBreadcrumb = () => {