From 0690f0726230031d5c88dbda510202f6b2ef92f5 Mon Sep 17 00:00:00 2001
From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>
Date: Sat, 3 May 2025 12:59:22 -0600
Subject: [PATCH] Enhance backup validation and improve backup display
- Added validation to require a service name for compose backups in the backup handling logic, improving user feedback.
- Refactored the ShowBackups component to sort deployments by creation date and enhance the display of backup information, including service names and statuses, for better user experience.
- Updated logging in the compose backup utility to include command execution details, aiding in debugging and monitoring.
---
.../database/backups/handle-backup.tsx | 9 +
.../database/backups/show-backups.tsx | 350 +++++++++---------
packages/server/src/utils/backups/compose.ts | 4 +-
3 files changed, 196 insertions(+), 167 deletions(-)
diff --git a/apps/dokploy/components/dashboard/database/backups/handle-backup.tsx b/apps/dokploy/components/dashboard/database/backups/handle-backup.tsx
index 032616b1..de5f2d3a 100644
--- a/apps/dokploy/components/dashboard/database/backups/handle-backup.tsx
+++ b/apps/dokploy/components/dashboard/database/backups/handle-backup.tsx
@@ -108,6 +108,15 @@ const Schema = z
path: ["databaseType"],
});
}
+
+ if (data.backupType === "compose" && !data.serviceName) {
+ ctx.addIssue({
+ code: z.ZodIssueCode.custom,
+ message: "Service name is required for compose backups",
+ path: ["serviceName"],
+ });
+ }
+
if (data.backupType === "compose" && data.databaseType) {
if (data.databaseType === "postgres") {
if (!data.metadata?.postgres?.databaseUser) {
diff --git a/apps/dokploy/components/dashboard/database/backups/show-backups.tsx b/apps/dokploy/components/dashboard/database/backups/show-backups.tsx
index e71bc0bb..81a2a299 100644
--- a/apps/dokploy/components/dashboard/database/backups/show-backups.tsx
+++ b/apps/dokploy/components/dashboard/database/backups/show-backups.tsx
@@ -178,184 +178,202 @@ export const ShowBackups = ({
)}
- {postgres?.backups.map((backup) => (
-
-
-
-
- {backup.backupType === "compose" && (
-
- {backup.databaseType === "postgres" && (
-
- )}
- {backup.databaseType === "mysql" && (
-
- )}
- {backup.databaseType === "mariadb" && (
-
- )}
- {backup.databaseType === "mongo" && (
-
- )}
-
- )}
-
+ {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;
+
+ return (
+
+
+
+
{backup.backupType === "compose" && (
-
-
- {backup.serviceName}
-
-
- {backup.databaseType}
-
+
+ {backup.databaseType === "postgres" && (
+
+ )}
+ {backup.databaseType === "mysql" && (
+
+ )}
+ {backup.databaseType === "mariadb" && (
+
+ )}
+ {backup.databaseType === "mongo" && (
+
+ )}
)}
-
-
-
- {backup.enabled ? "Active" : "Inactive"}
+
+ {backup.backupType === "compose" && (
+
+
+ {backup.serviceName}
+
+
+ {backup.databaseType}
+
+
+ )}
+
+
+
+ {backup.enabled ? "Active" : "Inactive"}
+
+
+
+
+
+
+
+
+ Destination
+
+ {backup.destination.name}
+
+
+
+
+
+ Database
+
+
+ {backup.database}
+
+
+
+
+
+ Schedule
+
+
+ {backup.schedule}
+
+
+
+
+
+ Prefix Storage
+
+
+ {backup.prefix}
+
+
+
+
+
+ Keep Latest
+
+
+ {backup.keepLatestCount || "All"}
+
-
-
-
- Destination
-
-
- {backup.destination.name}
-
-
+
+
+
+
+
+
+
+
+
+
+ Run Manual Backup
+
+
+
-
-
- Database
-
-
- {backup.database}
-
-
-
-
-
- Schedule
-
-
- {backup.schedule}
-
-
-
-
-
- Prefix Storage
-
-
- {backup.prefix}
-
-
-
-
-
- Keep Latest
-
-
- {backup.keepLatestCount || "All"}
-
-
+
+
{
+ await deleteBackup({
+ backupId: backup.backupId,
+ })
+ .then(() => {
+ refetch();
+ toast.success(
+ "Backup deleted successfully",
+ );
+ })
+ .catch(() => {
+ toast.error("Error deleting backup");
+ });
+ }}
+ >
+
+
-
-
-
-
-
-
-
-
-
-
- Run Manual Backup
-
-
-
-
-
{
- await deleteBackup({
- backupId: backup.backupId,
- })
- .then(() => {
- refetch();
- toast.success("Backup deleted successfully");
- })
- .catch(() => {
- toast.error("Error deleting backup");
- });
- }}
- >
-
-
-
-
- ))}
+ );
+ })}
)}
diff --git a/packages/server/src/utils/backups/compose.ts b/packages/server/src/utils/backups/compose.ts
index 6131f2a4..76fd43a6 100644
--- a/packages/server/src/utils/backups/compose.ts
+++ b/packages/server/src/utils/backups/compose.ts
@@ -33,6 +33,7 @@ export const runComposeBackup = async (
title: "Compose Backup",
description: "Compose Backup",
});
+
try {
const rcloneFlags = getS3Credentials(destination);
const rcloneDestination = `:s3:${destination.bucket}/${bucketDestination}`;
@@ -77,7 +78,8 @@ export const runComposeBackup = async (
compose.serverId,
`
set -e;
- Running command.
+ echo "Running command." >> ${deployment.logPath};
+ export RCLONE_LOG_LEVEL=DEBUG;
${backupCommand} | ${rcloneCommand} >> ${deployment.logPath} 2>> ${deployment.logPath} || {
echo "❌ Command failed" >> ${deployment.logPath};
exit 1;