From 982f4d70f70c7ec1db54c3be52263da7b1fc3e47 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Wed, 22 Jul 2026 00:12:53 -0600 Subject: [PATCH 01/22] Merge pull request #4890 from SteadEXE/canary fix(ui): add cursor pointer style for buttons (cherry picked from commit 0fc75840d22c459e7cb7ff65d55bbb647d8d2154) --- apps/dokploy/styles/globals.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/dokploy/styles/globals.css b/apps/dokploy/styles/globals.css index 50c516bd17..d212474c75 100644 --- a/apps/dokploy/styles/globals.css +++ b/apps/dokploy/styles/globals.css @@ -269,6 +269,12 @@ @apply bg-background text-foreground; } + /* Cursor pointer on buttons */ + button:not([disabled]), + [role="button"]:not([disabled]) { + cursor: pointer; + } + /* Custom scrollbar styling */ ::-webkit-scrollbar { width: 0.3125rem; From b024c9c2fd6ec363e321dd8c4b39d7ca418b5936 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Wed, 22 Jul 2026 14:33:42 -0600 Subject: [PATCH 02/22] Merge pull request #4626 from veksen/veksen/textarea-resets-while-editing fix: prevent environment form from resetting while editing (cherry picked from commit 73e4fdd757da90fb1fe347a92b92237e6712f98d) --- .../components/dashboard/application/environment/show.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/environment/show.tsx b/apps/dokploy/components/dashboard/application/environment/show.tsx index 909cf5287c..378a871ada 100644 --- a/apps/dokploy/components/dashboard/application/environment/show.tsx +++ b/apps/dokploy/components/dashboard/application/environment/show.tsx @@ -60,14 +60,16 @@ export const ShowEnvironment = ({ applicationId }: Props) => { const currentBuildArgs = form.watch("buildArgs"); const currentBuildSecrets = form.watch("buildSecrets"); const currentCreateEnvFile = form.watch("createEnvFile"); + const { isDirty } = form.formState; const hasChanges = currentEnv !== (data?.env || "") || currentBuildArgs !== (data?.buildArgs || "") || currentBuildSecrets !== (data?.buildSecrets || "") || currentCreateEnvFile !== (data?.createEnvFile ?? true); + // Skip reset while editing so background refetches don't wipe edits useEffect(() => { - if (data) { + if (data && !isDirty) { form.reset({ env: data.env || "", buildArgs: data.buildArgs || "", @@ -75,7 +77,7 @@ export const ShowEnvironment = ({ applicationId }: Props) => { createEnvFile: data.createEnvFile ?? true, }); } - }, [data, form]); + }, [data, isDirty, form]); const onSubmit = async (formData: EnvironmentSchema) => { mutateAsync({ @@ -87,6 +89,7 @@ export const ShowEnvironment = ({ applicationId }: Props) => { }) .then(async () => { toast.success("Environments Added"); + form.reset(formData); await refetch(); }) .catch(() => { From 6e84f39a9f4603e0949eb38662121a70afabc8df Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Tue, 28 Jul 2026 14:09:42 -0600 Subject: [PATCH 03/22] Merge pull request #4929 from Dokploy/fix/remove-buttons-not-persisting fix(ui): make interactive icons inside badges clickable again (cherry picked from commit 425d478a0b8d8201098b3f8404f9e9c340c767b6) --- apps/dokploy/components/ui/badge.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dokploy/components/ui/badge.tsx b/apps/dokploy/components/ui/badge.tsx index bcd0ffe05e..ef7e697dd4 100644 --- a/apps/dokploy/components/ui/badge.tsx +++ b/apps/dokploy/components/ui/badge.tsx @@ -5,7 +5,7 @@ import type * as React from "react"; import { cn } from "@/lib/utils"; const badgeVariants = cva( - "group/badge inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2.5 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!", + "group/badge inline-flex w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2.5 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg:not(.cursor-pointer)]:pointer-events-none [&>svg]:size-3!", { variants: { variant: { From c6607f3a198b393576f1892ba222297c62d54a2c Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Tue, 28 Jul 2026 15:13:42 -0600 Subject: [PATCH 04/22] Merge pull request #4924 from dmtrTm/fix/rollback-query-arg-limit fix: avoid postgres 100-argument limit in findRollbackById (cherry picked from commit 069939e8f99a33b0a10b1e8cd2236756acea0568) --- packages/server/src/services/rollbacks.ts | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/packages/server/src/services/rollbacks.ts b/packages/server/src/services/rollbacks.ts index 97fa4b1c5f..cc93d3354d 100644 --- a/packages/server/src/services/rollbacks.ts +++ b/packages/server/src/services/rollbacks.ts @@ -105,19 +105,7 @@ export const findRollbackById = async (rollbackId: string) => { const result = await db.query.rollbacks.findFirst({ where: eq(rollbacks.rollbackId, rollbackId), with: { - deployment: { - with: { - application: { - with: { - environment: { - with: { - project: true, - }, - }, - }, - }, - }, - }, + deployment: true, }, }); From 43229c89da14e962adf7a0c165791088ce24dbaf Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Tue, 28 Jul 2026 15:22:18 -0600 Subject: [PATCH 05/22] Merge pull request #4931 from Dokploy/fix/postgres-100-arg-limit-finders fix: avoid postgres 100-argument limit in schedule, volume backup and port queries (cherry picked from commit deebf0f1078c2954fe3c29793799c7a0211fc25a) --- apps/schedules/src/utils.ts | 6 ++++++ packages/server/src/services/port.ts | 8 ++------ packages/server/src/services/schedule.ts | 5 +++++ packages/server/src/services/volume-backups.ts | 5 +++++ 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/apps/schedules/src/utils.ts b/apps/schedules/src/utils.ts index 7caa106afc..85de85f9a9 100644 --- a/apps/schedules/src/utils.ts +++ b/apps/schedules/src/utils.ts @@ -180,6 +180,9 @@ export const initializeJobs = async () => { where: eq(schedules.enabled, true), with: { application: { + columns: { + applicationId: true, + }, with: { server: true, }, @@ -227,6 +230,9 @@ export const initializeJobs = async () => { where: eq(volumeBackups.enabled, true), with: { application: { + columns: { + applicationId: true, + }, with: { server: true, }, diff --git a/packages/server/src/services/port.ts b/packages/server/src/services/port.ts index 3ba1b73766..bcc5831a3a 100644 --- a/packages/server/src/services/port.ts +++ b/packages/server/src/services/port.ts @@ -30,12 +30,8 @@ export const finPortById = async (portId: string) => { where: eq(ports.portId, portId), with: { application: { - with: { - environment: { - with: { - project: true, - }, - }, + columns: { + applicationId: true, }, }, }, diff --git a/packages/server/src/services/schedule.ts b/packages/server/src/services/schedule.ts index c94973e024..59b75cc0da 100644 --- a/packages/server/src/services/schedule.ts +++ b/packages/server/src/services/schedule.ts @@ -81,6 +81,11 @@ export const findScheduleById = async (scheduleId: string) => { where: eq(schedules.scheduleId, scheduleId), with: { application: { + columns: { + applicationId: true, + appName: true, + serverId: true, + }, with: { environment: { with: { diff --git a/packages/server/src/services/volume-backups.ts b/packages/server/src/services/volume-backups.ts index abd29df1f4..359ccf5f0d 100644 --- a/packages/server/src/services/volume-backups.ts +++ b/packages/server/src/services/volume-backups.ts @@ -13,6 +13,11 @@ export const findVolumeBackupById = async (volumeBackupId: string) => { where: eq(volumeBackups.volumeBackupId, volumeBackupId), with: { application: { + columns: { + applicationId: true, + appName: true, + serverId: true, + }, with: { environment: { with: { From 7f41b098f9f6e0781f5b9087700d49202e309d80 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Tue, 28 Jul 2026 16:35:53 -0600 Subject: [PATCH 06/22] Merge pull request #4911 from AbiRaditya/fix/cloudflare-badge-tooltip-error-title fix(domains): don't render CDN info message as an error in DNS tooltip (cherry picked from commit 5df820a74074cf587aee8e321f692345825e7ea3) --- .../components/dashboard/application/domains/columns.tsx | 4 +++- .../dashboard/application/domains/show-domains.tsx | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/domains/columns.tsx b/apps/dokploy/components/dashboard/application/domains/columns.tsx index b88443dcc7..816fbbb8de 100644 --- a/apps/dokploy/components/dashboard/application/domains/columns.tsx +++ b/apps/dokploy/components/dashboard/application/domains/columns.tsx @@ -209,7 +209,9 @@ export const createColumns = ({ - {validationState?.error ? ( + {validationState?.isValid && validationState?.message ? ( +

{validationState.message}

+ ) : validationState?.error ? (

Error:

{validationState.error}

diff --git a/apps/dokploy/components/dashboard/application/domains/show-domains.tsx b/apps/dokploy/components/dashboard/application/domains/show-domains.tsx index daed0e2516..23d9e46bb6 100644 --- a/apps/dokploy/components/dashboard/application/domains/show-domains.tsx +++ b/apps/dokploy/components/dashboard/application/domains/show-domains.tsx @@ -626,7 +626,10 @@ export const ShowDomains = ({ id, type }: Props) => { - {validationState?.error ? ( + {validationState?.isValid && + validationState?.message ? ( +

{validationState.message}

+ ) : validationState?.error ? (

Error: From d4e087e12854a1722b718c574f4e253e75a37415 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Thu, 30 Jul 2026 11:23:32 -0600 Subject: [PATCH 07/22] Merge pull request #4937 from Dokploy/fix/persist-trigger-type-provider-forms fix(ui): persist trigger type selection in GitHub provider forms (cherry picked from commit bb73c6e6dd37f735b41de4452550c3e67bee93c0) --- .../application/general/generic/save-github-provider.tsx | 8 ++++++-- .../general/generic/save-github-provider-compose.tsx | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/general/generic/save-github-provider.tsx b/apps/dokploy/components/dashboard/application/general/generic/save-github-provider.tsx index 29df617b1d..3904bfc6ec 100644 --- a/apps/dokploy/components/dashboard/application/general/generic/save-github-provider.tsx +++ b/apps/dokploy/components/dashboard/application/general/generic/save-github-provider.tsx @@ -438,8 +438,12 @@ export const SaveGithubProvider = ({ applicationId }: Props) => {

{ + if (!value) { + return; + } + field.onChange(value); + }} value={field.value} > From c7a96ed82cba3bc1f93938297422a093a3b41c41 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Fri, 31 Jul 2026 15:15:12 -0600 Subject: [PATCH 08/22] Merge pull request #4782 from imrja8/fix/watchpath-badge-removal fix(ui): resolve unclickable watch path removal button (cherry picked from commit 018e56a7b41f74b99e87351f462e7d5744c01156) --- .../general/generic/save-bitbucket-provider.tsx | 14 +++++++++----- .../general/generic/save-git-provider.tsx | 14 +++++++++----- .../general/generic/save-gitea-provider.tsx | 14 +++++++++----- .../general/generic/save-github-provider.tsx | 14 +++++++++----- .../general/generic/save-gitlab-provider.tsx | 14 +++++++++----- .../generic/save-bitbucket-provider-compose.tsx | 14 +++++++++----- .../general/generic/save-git-provider-compose.tsx | 14 +++++++++----- .../generic/save-gitea-provider-compose.tsx | 14 +++++++++----- .../generic/save-github-provider-compose.tsx | 14 +++++++++----- .../generic/save-gitlab-provider-compose.tsx | 14 +++++++++----- 10 files changed, 90 insertions(+), 50 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/general/generic/save-bitbucket-provider.tsx b/apps/dokploy/components/dashboard/application/general/generic/save-bitbucket-provider.tsx index bc3bd5efc2..07ee5b0e49 100644 --- a/apps/dokploy/components/dashboard/application/general/generic/save-bitbucket-provider.tsx +++ b/apps/dokploy/components/dashboard/application/general/generic/save-bitbucket-provider.tsx @@ -447,14 +447,18 @@ export const SaveBitbucketProvider = ({ applicationId }: Props) => { {field.value?.map((path, index) => ( {path} - { const newPaths = [...(field.value || [])]; newPaths.splice(index, 1); form.setValue("watchPaths", newPaths); }} - /> + > + + ))}
@@ -502,14 +506,14 @@ export const SaveBitbucketProvider = ({ applicationId }: Props) => { control={form.control} name="enableSubmodules" render={({ field }) => ( - + - Enable Submodules + Enable Submodules )} /> diff --git a/apps/dokploy/components/dashboard/application/general/generic/save-git-provider.tsx b/apps/dokploy/components/dashboard/application/general/generic/save-git-provider.tsx index 3fd0592890..99b997d503 100644 --- a/apps/dokploy/components/dashboard/application/general/generic/save-git-provider.tsx +++ b/apps/dokploy/components/dashboard/application/general/generic/save-git-provider.tsx @@ -242,14 +242,18 @@ export const SaveGitProvider = ({ applicationId }: Props) => { {field.value?.map((path, index) => ( {path} - { const newPaths = [...(field.value || [])]; newPaths.splice(index, 1); form.setValue("watchPaths", newPaths); }} - /> + > + + ))} @@ -298,14 +302,14 @@ export const SaveGitProvider = ({ applicationId }: Props) => { control={form.control} name="enableSubmodules" render={({ field }) => ( - + - Enable Submodules + Enable Submodules )} /> diff --git a/apps/dokploy/components/dashboard/application/general/generic/save-gitea-provider.tsx b/apps/dokploy/components/dashboard/application/general/generic/save-gitea-provider.tsx index a43b257b80..8da817c804 100644 --- a/apps/dokploy/components/dashboard/application/general/generic/save-gitea-provider.tsx +++ b/apps/dokploy/components/dashboard/application/general/generic/save-gitea-provider.tsx @@ -477,14 +477,18 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => { className="flex items-center gap-1" > {path} - { const newPaths = [...(field.value || [])]; newPaths.splice(index, 1); field.onChange(newPaths); }} - /> + > + + ))} @@ -531,14 +535,14 @@ export const SaveGiteaProvider = ({ applicationId }: Props) => { control={form.control} name="enableSubmodules" render={({ field }) => ( - + - Enable Submodules + Enable Submodules )} /> diff --git a/apps/dokploy/components/dashboard/application/general/generic/save-github-provider.tsx b/apps/dokploy/components/dashboard/application/general/generic/save-github-provider.tsx index 3904bfc6ec..c842655953 100644 --- a/apps/dokploy/components/dashboard/application/general/generic/save-github-provider.tsx +++ b/apps/dokploy/components/dashboard/application/general/generic/save-github-provider.tsx @@ -491,14 +491,18 @@ export const SaveGithubProvider = ({ applicationId }: Props) => { className="flex items-center gap-1" > {path} - { const newPaths = [...(field.value || [])]; newPaths.splice(index, 1); field.onChange(newPaths); }} - /> + > + + ))} @@ -547,14 +551,14 @@ export const SaveGithubProvider = ({ applicationId }: Props) => { control={form.control} name="enableSubmodules" render={({ field }) => ( - + - Enable Submodules + Enable Submodules )} /> diff --git a/apps/dokploy/components/dashboard/application/general/generic/save-gitlab-provider.tsx b/apps/dokploy/components/dashboard/application/general/generic/save-gitlab-provider.tsx index cda3677a03..1711aa63cd 100644 --- a/apps/dokploy/components/dashboard/application/general/generic/save-gitlab-provider.tsx +++ b/apps/dokploy/components/dashboard/application/general/generic/save-gitlab-provider.tsx @@ -467,14 +467,18 @@ export const SaveGitlabProvider = ({ applicationId }: Props) => { className="flex items-center gap-1" > {path} - { const newPaths = [...(field.value || [])]; newPaths.splice(index, 1); field.onChange(newPaths); }} - /> + > + + ))} @@ -521,14 +525,14 @@ export const SaveGitlabProvider = ({ applicationId }: Props) => { control={form.control} name="enableSubmodules" render={({ field }) => ( - + - Enable Submodules + Enable Submodules )} /> diff --git a/apps/dokploy/components/dashboard/compose/general/generic/save-bitbucket-provider-compose.tsx b/apps/dokploy/components/dashboard/compose/general/generic/save-bitbucket-provider-compose.tsx index 7d9325e6e4..5d95aafcea 100644 --- a/apps/dokploy/components/dashboard/compose/general/generic/save-bitbucket-provider-compose.tsx +++ b/apps/dokploy/components/dashboard/compose/general/generic/save-bitbucket-provider-compose.tsx @@ -451,14 +451,18 @@ export const SaveBitbucketProviderCompose = ({ composeId }: Props) => { {field.value?.map((path, index) => ( {path} - { const newPaths = [...(field.value || [])]; newPaths.splice(index, 1); form.setValue("watchPaths", newPaths); }} - /> + > + + ))} @@ -506,14 +510,14 @@ export const SaveBitbucketProviderCompose = ({ composeId }: Props) => { control={form.control} name="enableSubmodules" render={({ field }) => ( - + - Enable Submodules + Enable Submodules )} /> diff --git a/apps/dokploy/components/dashboard/compose/general/generic/save-git-provider-compose.tsx b/apps/dokploy/components/dashboard/compose/general/generic/save-git-provider-compose.tsx index 1c0c67ef26..a454ff6101 100644 --- a/apps/dokploy/components/dashboard/compose/general/generic/save-git-provider-compose.tsx +++ b/apps/dokploy/components/dashboard/compose/general/generic/save-git-provider-compose.tsx @@ -251,14 +251,18 @@ export const SaveGitProviderCompose = ({ composeId }: Props) => { {field.value?.map((path, index) => ( {path} - { const newPaths = [...(field.value || [])]; newPaths.splice(index, 1); form.setValue("watchPaths", newPaths); }} - /> + > + + ))} @@ -306,14 +310,14 @@ export const SaveGitProviderCompose = ({ composeId }: Props) => { control={form.control} name="enableSubmodules" render={({ field }) => ( - + - Enable Submodules + Enable Submodules )} /> diff --git a/apps/dokploy/components/dashboard/compose/general/generic/save-gitea-provider-compose.tsx b/apps/dokploy/components/dashboard/compose/general/generic/save-gitea-provider-compose.tsx index 5a3016a28e..24ed16117f 100644 --- a/apps/dokploy/components/dashboard/compose/general/generic/save-gitea-provider-compose.tsx +++ b/apps/dokploy/components/dashboard/compose/general/generic/save-gitea-provider-compose.tsx @@ -442,14 +442,18 @@ export const SaveGiteaProviderCompose = ({ composeId }: Props) => { {field.value?.map((path, index) => ( {path} - { const newPaths = [...(field.value || [])]; newPaths.splice(index, 1); form.setValue("watchPaths", newPaths); }} - /> + > + + ))} @@ -497,14 +501,14 @@ export const SaveGiteaProviderCompose = ({ composeId }: Props) => { control={form.control} name="enableSubmodules" render={({ field }) => ( - + - Enable Submodules + Enable Submodules )} /> diff --git a/apps/dokploy/components/dashboard/compose/general/generic/save-github-provider-compose.tsx b/apps/dokploy/components/dashboard/compose/general/generic/save-github-provider-compose.tsx index 1f5c1ce590..10a5f64d59 100644 --- a/apps/dokploy/components/dashboard/compose/general/generic/save-github-provider-compose.tsx +++ b/apps/dokploy/components/dashboard/compose/general/generic/save-github-provider-compose.tsx @@ -483,14 +483,18 @@ export const SaveGithubProviderCompose = ({ composeId }: Props) => { {field.value?.map((path, index) => ( {path} - { const newPaths = [...(field.value || [])]; newPaths.splice(index, 1); form.setValue("watchPaths", newPaths); }} - /> + > + + ))} @@ -542,14 +546,14 @@ export const SaveGithubProviderCompose = ({ composeId }: Props) => { control={form.control} name="enableSubmodules" render={({ field }) => ( - + - Enable Submodules + Enable Submodules )} /> diff --git a/apps/dokploy/components/dashboard/compose/general/generic/save-gitlab-provider-compose.tsx b/apps/dokploy/components/dashboard/compose/general/generic/save-gitlab-provider-compose.tsx index 13a1cafc8e..c101d091b0 100644 --- a/apps/dokploy/components/dashboard/compose/general/generic/save-gitlab-provider-compose.tsx +++ b/apps/dokploy/components/dashboard/compose/general/generic/save-gitlab-provider-compose.tsx @@ -468,14 +468,18 @@ export const SaveGitlabProviderCompose = ({ composeId }: Props) => { {field.value?.map((path, index) => ( {path} - { const newPaths = [...(field.value || [])]; newPaths.splice(index, 1); form.setValue("watchPaths", newPaths); }} - /> + > + + ))} @@ -523,14 +527,14 @@ export const SaveGitlabProviderCompose = ({ composeId }: Props) => { control={form.control} name="enableSubmodules" render={({ field }) => ( - + - Enable Submodules + Enable Submodules )} /> From 2f89981597ca5fbfe1f77f3178eebd198342bb4a Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 2 Aug 2026 13:59:56 -0600 Subject: [PATCH 09/22] Merge pull request #4948 from azizbecha/fix/collapsed-sidebar-avatar fix(ui): prevent collapsed avatar clipping (cherry picked from commit 3b0bdd8f742b9bb742e7329778e1dfafdabfd84a) --- apps/dokploy/components/ui/sidebar.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/dokploy/components/ui/sidebar.tsx b/apps/dokploy/components/ui/sidebar.tsx index 6c9ca131a8..0972949e35 100644 --- a/apps/dokploy/components/ui/sidebar.tsx +++ b/apps/dokploy/components/ui/sidebar.tsx @@ -464,7 +464,7 @@ function SidebarMenuItem({ className, ...props }: React.ComponentProps<"li">) { } const sidebarMenuButtonVariants = cva( - "peer/menu-button group/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:font-medium data-active:text-sidebar-accent-foreground [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate", + "peer/menu-button group/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm ring-sidebar-ring outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pr-8 group-data-[collapsible=icon]:size-8! hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-open:hover:bg-sidebar-accent data-open:hover:text-sidebar-accent-foreground data-active:bg-sidebar-accent data-active:font-medium data-active:text-sidebar-accent-foreground [&_svg]:size-4 [&_svg]:shrink-0 [&>span:last-child]:truncate", { variants: { variant: { @@ -473,8 +473,8 @@ const sidebarMenuButtonVariants = cva( "bg-background shadow-[0_0_0_1px_var(--sidebar-border)] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_var(--sidebar-accent)]", }, size: { - default: "h-8 text-sm", - sm: "h-7 text-xs", + default: "h-8 text-sm group-data-[collapsible=icon]:p-2!", + sm: "h-7 text-xs group-data-[collapsible=icon]:p-2!", lg: "h-12 text-sm group-data-[collapsible=icon]:p-0!", }, }, From e88d13f67b650e6b02af546dcead9abe9b7376cc Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sun, 2 Aug 2026 14:06:01 -0600 Subject: [PATCH 10/22] Merge pull request #4947 from azizbecha/fix/4945-deployment-delete-loading fix(ui): scope deployment delete loading (cherry picked from commit 2be9e1e3df606bcbe09c41b1d8aae056298c365a) --- .../deployments/show-deployments.tsx | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx b/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx index 48c8ec981e..1a531e24cf 100644 --- a/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx +++ b/apps/dokploy/components/dashboard/application/deployments/show-deployments.tsx @@ -63,6 +63,9 @@ export const ShowDeployments = ({ const [activeLog, setActiveLog] = useState< RouterOutputs["deployment"]["all"][number] | null >(null); + const [removingDeploymentIds, setRemovingDeploymentIds] = useState< + Set + >(new Set()); const { data: deployments, isPending: isLoadingDeployments } = api.deployment.allByType.useQuery( { @@ -81,7 +84,7 @@ export const ShowDeployments = ({ api.rollback.rollback.useMutation(); const { mutateAsync: killProcess, isPending: isKillingProcess } = api.deployment.killProcess.useMutation(); - const { mutateAsync: removeDeployment, isPending: isRemovingDeployment } = + const { mutateAsync: removeDeployment } = api.deployment.removeDeployment.useMutation(); // Cancel deployment mutations @@ -408,6 +411,11 @@ export const ShowDeployments = ({ description="Are you sure you want to delete this deployment? This action cannot be undone." type="default" onClick={async () => { + setRemovingDeploymentIds((deploymentIds) => { + const nextDeploymentIds = new Set(deploymentIds); + nextDeploymentIds.add(deployment.deploymentId); + return nextDeploymentIds; + }); try { await removeDeployment({ deploymentId: deployment.deploymentId, @@ -415,13 +423,25 @@ export const ShowDeployments = ({ toast.success("Deployment deleted successfully"); } catch (error) { toast.error("Error deleting deployment"); + } finally { + setRemovingDeploymentIds((deploymentIds) => { + const nextDeploymentIds = new Set( + deploymentIds, + ); + nextDeploymentIds.delete( + deployment.deploymentId, + ); + return nextDeploymentIds; + }); } }} > - + From bcf97f92aba99406b5c4471962ce23b82fba18ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Narciso=20E=2E=20N=C3=BA=C3=B1ez=20Arias?= Date: Wed, 5 Aug 2026 22:21:12 -0400 Subject: [PATCH 20/22] Merge pull request #4772 from rifatdinc/fix-watch-paths-added-removed-files fix(webhook): include added and removed files in watchPaths validation (cherry picked from commit 3f98208f03072bf076a36b0c495c386142aab31b) --- .../pages/api/deploy/[refreshToken].ts | 56 ++++++++++++------- .../api/deploy/compose/[refreshToken].ts | 48 ++++++++++------ apps/dokploy/pages/api/deploy/github.ts | 8 ++- 3 files changed, 70 insertions(+), 42 deletions(-) diff --git a/apps/dokploy/pages/api/deploy/[refreshToken].ts b/apps/dokploy/pages/api/deploy/[refreshToken].ts index bb6eb06d37..9cf6142d25 100644 --- a/apps/dokploy/pages/api/deploy/[refreshToken].ts +++ b/apps/dokploy/pages/api/deploy/[refreshToken].ts @@ -119,9 +119,11 @@ export default async function handler( } // If webhook doesn't provide image info, we'll use the configured image (old behavior) } else if (sourceType === "github") { - const normalizedCommits = req.body?.commits?.flatMap( - (commit: any) => commit.modified, - ); + const normalizedCommits = req.body?.commits?.flatMap((commit: any) => [ + ...(commit.added || []), + ...(commit.modified || []), + ...(commit.removed || []), + ]); const shouldDeployPaths = shouldDeploy( application.watchPaths, @@ -150,21 +152,29 @@ export default async function handler( let normalizedCommits: string[] = []; if (provider === "github") { - normalizedCommits = req.body?.commits?.flatMap( - (commit: any) => commit.modified, - ); + normalizedCommits = req.body?.commits?.flatMap((commit: any) => [ + ...(commit.added || []), + ...(commit.modified || []), + ...(commit.removed || []), + ]); } else if (provider === "gitlab") { - normalizedCommits = req.body?.commits?.flatMap( - (commit: any) => commit.modified, - ); + normalizedCommits = req.body?.commits?.flatMap((commit: any) => [ + ...(commit.added || []), + ...(commit.modified || []), + ...(commit.removed || []), + ]); } else if (provider === "gitea") { - normalizedCommits = req.body?.commits?.flatMap( - (commit: any) => commit.modified, - ); + normalizedCommits = req.body?.commits?.flatMap((commit: any) => [ + ...(commit.added || []), + ...(commit.modified || []), + ...(commit.removed || []), + ]); } else if (provider === "soft-serve") { - normalizedCommits = req.body?.commits?.flatMap( - (commit: any) => commit.modified, - ); + normalizedCommits = req.body?.commits?.flatMap((commit: any) => [ + ...(commit.added || []), + ...(commit.modified || []), + ...(commit.removed || []), + ]); } const shouldDeployPaths = shouldDeploy( @@ -179,9 +189,11 @@ export default async function handler( } else if (sourceType === "gitlab") { const branchName = extractBranchName(req.headers, req.body); - const normalizedCommits = req.body?.commits?.flatMap( - (commit: any) => commit.modified, - ); + const normalizedCommits = req.body?.commits?.flatMap((commit: any) => [ + ...(commit.added || []), + ...(commit.modified || []), + ...(commit.removed || []), + ]); const shouldDeployPaths = shouldDeploy( application.watchPaths, @@ -225,9 +237,11 @@ export default async function handler( } else if (sourceType === "gitea") { const branchName = extractBranchName(req.headers, req.body); - const normalizedCommits = req.body?.commits?.flatMap( - (commit: any) => commit.modified, - ); + const normalizedCommits = req.body?.commits?.flatMap((commit: any) => [ + ...(commit.added || []), + ...(commit.modified || []), + ...(commit.removed || []), + ]); const shouldDeployPaths = shouldDeploy( application.watchPaths, diff --git a/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts b/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts index 85a379eb3e..0d83c10174 100644 --- a/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts +++ b/apps/dokploy/pages/api/deploy/compose/[refreshToken].ts @@ -54,9 +54,11 @@ export default async function handler( if (sourceType === "github") { const branchName = extractBranchName(req.headers, req.body); - const normalizedCommits = req.body?.commits?.flatMap( - (commit: any) => commit.modified, - ); + const normalizedCommits = req.body?.commits?.flatMap((commit: any) => [ + ...(commit.added || []), + ...(commit.modified || []), + ...(commit.removed || []), + ]); const shouldDeployPaths = shouldDeploy( composeResult.watchPaths, @@ -74,9 +76,11 @@ export default async function handler( } } else if (sourceType === "gitlab") { const branchName = extractBranchName(req.headers, req.body); - const normalizedCommits = req.body?.commits?.flatMap( - (commit: any) => commit.modified, - ); + const normalizedCommits = req.body?.commits?.flatMap((commit: any) => [ + ...(commit.added || []), + ...(commit.modified || []), + ...(commit.removed || []), + ]); const shouldDeployPaths = shouldDeploy( composeResult.watchPaths, @@ -125,17 +129,23 @@ export default async function handler( let normalizedCommits: string[] = []; if (provider === "github") { - normalizedCommits = req.body?.commits?.flatMap( - (commit: any) => commit.modified, - ); + normalizedCommits = req.body?.commits?.flatMap((commit: any) => [ + ...(commit.added || []), + ...(commit.modified || []), + ...(commit.removed || []), + ]); } else if (provider === "gitlab") { - normalizedCommits = req.body?.commits?.flatMap( - (commit: any) => commit.modified, - ); + normalizedCommits = req.body?.commits?.flatMap((commit: any) => [ + ...(commit.added || []), + ...(commit.modified || []), + ...(commit.removed || []), + ]); } else if (provider === "gitea") { - normalizedCommits = req.body?.commits?.flatMap( - (commit: any) => commit.modified, - ); + normalizedCommits = req.body?.commits?.flatMap((commit: any) => [ + ...(commit.added || []), + ...(commit.modified || []), + ...(commit.removed || []), + ]); } const shouldDeployPaths = shouldDeploy( @@ -150,9 +160,11 @@ export default async function handler( } else if (sourceType === "gitea") { const branchName = extractBranchName(req.headers, req.body); - const normalizedCommits = req.body?.commits?.flatMap( - (commit: any) => commit.modified, - ); + const normalizedCommits = req.body?.commits?.flatMap((commit: any) => [ + ...(commit.added || []), + ...(commit.modified || []), + ...(commit.removed || []), + ]); const shouldDeployPaths = shouldDeploy( composeResult.watchPaths, diff --git a/apps/dokploy/pages/api/deploy/github.ts b/apps/dokploy/pages/api/deploy/github.ts index f03bf786ec..4fc75fc50c 100644 --- a/apps/dokploy/pages/api/deploy/github.ts +++ b/apps/dokploy/pages/api/deploy/github.ts @@ -223,9 +223,11 @@ export default async function handler( const deploymentTitle = extractCommitMessage(req.headers, req.body); const deploymentHash = extractHash(req.headers, req.body); const owner = getGithubRepositoryOwner(githubBody); - const normalizedCommits = githubBody?.commits?.flatMap( - (commit: any) => commit.modified, - ); + const normalizedCommits = githubBody?.commits?.flatMap((commit: any) => [ + ...(commit.added || []), + ...(commit.modified || []), + ...(commit.removed || []), + ]); const apps = await db.query.applications.findMany({ where: and( From dd542994a4ecb15f20fa765728be1d7c96df9ec3 Mon Sep 17 00:00:00 2001 From: Mauricio Siu Date: Wed, 5 Aug 2026 23:49:59 -0600 Subject: [PATCH 21/22] chore: release v0.29.14 --- apps/dokploy/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/dokploy/package.json b/apps/dokploy/package.json index f6b4aeb2d5..cca13dea74 100644 --- a/apps/dokploy/package.json +++ b/apps/dokploy/package.json @@ -1,6 +1,6 @@ { "name": "dokploy", - "version": "v0.29.13", + "version": "v0.29.14", "private": true, "license": "Apache-2.0", "type": "module", From 57fae7385389351ba0791d3fea928159ef7dd2c8 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Wed, 5 Aug 2026 23:54:32 -0600 Subject: [PATCH 22/22] Update packages/server/src/utils/schedules/utils.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> --- packages/server/src/utils/schedules/utils.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/server/src/utils/schedules/utils.ts b/packages/server/src/utils/schedules/utils.ts index 40bc0816c5..e81f9a5823 100644 --- a/packages/server/src/utils/schedules/utils.ts +++ b/packages/server/src/utils/schedules/utils.ts @@ -118,7 +118,8 @@ export const runCommand = async (scheduleId: string) => { "This feature is not available in the cloud version.", ); writeStream.end(); - return { ...deployment, status: "running" as const }; + await updateDeploymentStatus(deployment.deploymentId, "error"); + return { ...deployment, status: "error" as const }; } writeStream.write( `docker exec ${containerId} ${shellType} -c ${command}\n`,