From 5b87050013b6d96d1f2b381ab340e1914b6c9883 Mon Sep 17 00:00:00 2001 From: Nicolas Meienberger Date: Fri, 26 Sep 2025 22:21:37 +0200 Subject: [PATCH] refactor: coming soon backups --- .../app/modules/details/tabs/backups.tsx | 850 +++++++++--------- apps/client/app/modules/details/tabs/info.tsx | 2 +- .../modules/backends/webdav/webdav-backend.ts | 9 +- 3 files changed, 439 insertions(+), 422 deletions(-) diff --git a/apps/client/app/modules/details/tabs/backups.tsx b/apps/client/app/modules/details/tabs/backups.tsx index c387689..1720b56 100644 --- a/apps/client/app/modules/details/tabs/backups.tsx +++ b/apps/client/app/modules/details/tabs/backups.tsx @@ -134,457 +134,479 @@ export const VolumeBackupsTabContent = ({ volume }: Props) => { }; return ( -
-
- - - -
- Backup automation - - Enable scheduled snapshots and off-site replication for this volume. - -
- ( - - -
- {field.value ? "Enabled" : "Paused"} - -
-
-
- )} - /> -
- - ( - - Destination provider - - - - - Choose where backups for {volume.name} will be stored. - - - - )} - /> - - ( - - Backup frequency - - - - Define how often snapshots should be taken. - - - )} - /> - - {frequency !== "hourly" && ( +
+
+ + + + +
+ Backup automation + + Enable scheduled snapshots and off-site replication for this volume. + +
( - - Execution time + - +
+ {field.value ? "Enabled" : "Paused"} + +
- Time of day when the backup will run. -
)} /> - )} - - {frequency === "weekly" && ( +
+ ( - Execution day + Destination provider - Choose which day of the week to run the backup. - - - )} - /> - )} - - ( - - Max copies to retain - - field.onChange(event.target.value)} - /> - - Oldest backups will be pruned after this many copies. - - - )} - /> - - ( - - Retention window (days) - - field.onChange(event.target.value)} - /> - - Backups older than this window will be removed. - - - )} - /> - -
- - {destination === "s3" && ( - - - Amazon S3 bucket - - Define the bucket and path where compressed archives will be uploaded. - - - - ( - - Bucket name - - - - Ensure the bucket has versioning and lifecycle rules as needed. - - - )} - /> - - ( - - Region - - - - AWS region where the bucket resides. - - - )} - /> - - ( - - Object prefix - - - - Backups will be stored under this key prefix inside the bucket. - - - )} - /> - - - )} - - {destination === "sftp" && ( - - - SFTP target - Connect to a remote host that will receive encrypted backup archives. - - - ( - - Hostname - - - - - - )} - /> - - ( - - Port - - - - - - )} - /> - - ( - - Username - - - - - - )} - /> - - ( - - Destination path - - - - Ensure the directory exists and has write permissions. - - - )} - /> - - - )} - - {destination === "filesystem" && ( - - - Filesystem target - Persist archives to a directory on the host running Ironmount. - - - ( - - Backup directory - - - - The directory must be mounted with sufficient capacity. - - - )} - /> - - - )} - - - - Encryption & notifications - Secure backups and stay informed when something goes wrong. - - - ( - - Encryption - - - - Protect backups at rest with optional encryption. - - - )} - /> - - {encryption !== "none" && ( - ( - - Encryption secret - - - - Store this password securely. It will be required to restore backups. + Choose where backups for {volume.name} will be stored. )} /> - )} - ( - - Failure alerts -
-
-

Webhook notifications

-

Send an HTTP POST when a backup fails.

-
- - - -
- -
- )} - /> - - {notifyOnFailure && ( ( - - Webhook URL + + Backup frequency - + - Ironmount will POST a JSON payload with failure details. + Define how often snapshots should be taken. )} /> - )} -
- - - -
- - - - - Runbook summary - Validate the automation before enabling it in production. - - -
-

Volume

-

{summary.vol}

-
-
-

Schedule

-

{summary.scheduleLabel}

-
-
-

Destination

-

{summary.destinationLabel}

-
-
-

Retention

-

{summary.retentionLabel}

-
-
-

Encryption

-

{summary.encryptionLabel}

-
-
-

Notifications

-

{summary.notificationsLabel}

-
-
-
+ {frequency !== "hourly" && ( + ( + + Execution time + + + + Time of day when the backup will run. + + + )} + /> + )} + + {frequency === "weekly" && ( + ( + + Execution day + + + + Choose which day of the week to run the backup. + + + )} + /> + )} + + ( + + Max copies to retain + + field.onChange(event.target.value)} + /> + + Oldest backups will be pruned after this many copies. + + + )} + /> + + ( + + Retention window (days) + + field.onChange(event.target.value)} + /> + + Backups older than this window will be removed. + + + )} + /> + + + + {destination === "s3" && ( + + + Amazon S3 bucket + + Define the bucket and path where compressed archives will be uploaded. + + + + ( + + Bucket name + + + + + Ensure the bucket has versioning and lifecycle rules as needed. + + + + )} + /> + + ( + + Region + + + + AWS region where the bucket resides. + + + )} + /> + + ( + + Object prefix + + + + + Backups will be stored under this key prefix inside the bucket. + + + + )} + /> + + + )} + + {destination === "sftp" && ( + + + SFTP target + + Connect to a remote host that will receive encrypted backup archives. + + + + ( + + Hostname + + + + + + )} + /> + + ( + + Port + + + + + + )} + /> + + ( + + Username + + + + + + )} + /> + + ( + + Destination path + + + + Ensure the directory exists and has write permissions. + + + )} + /> + + + )} + + {destination === "filesystem" && ( + + + Filesystem target + Persist archives to a directory on the host running Ironmount. + + + ( + + Backup directory + + + + The directory must be mounted with sufficient capacity. + + + )} + /> + + + )} + + + + Encryption & notifications + Secure backups and stay informed when something goes wrong. + + + ( + + Encryption + + + + Protect backups at rest with optional encryption. + + + )} + /> + + {encryption !== "none" && ( + ( + + Encryption secret + + + + + Store this password securely. It will be required to restore backups. + + + + )} + /> + )} + + ( + + Failure alerts +
+
+

Webhook notifications

+

Send an HTTP POST when a backup fails.

+
+ + + +
+ +
+ )} + /> + + {notifyOnFailure && ( + ( + + Webhook URL + + + + Ironmount will POST a JSON payload with failure details. + + + )} + /> + )} +
+ + + +
+ + + + + + Runbook summary + Validate the automation before enabling it in production. + + +
+

Volume

+

{summary.vol}

+
+
+

Schedule

+

{summary.scheduleLabel}

+
+
+

Destination

+

{summary.destinationLabel}

+
+
+

Retention

+

{summary.retentionLabel}

+
+
+

Encryption

+

{summary.encryptionLabel}

+
+
+

Notifications

+

{summary.notificationsLabel}

+
+
+
+
+
+
+ Preview +
+
+

Automated backups are coming soon

+

+ We're working hard to bring robust backup and snapshot capabilities to Ironmount. +

+
+
+ Coming soon — stay tuned! +
+
); }; diff --git a/apps/client/app/modules/details/tabs/info.tsx b/apps/client/app/modules/details/tabs/info.tsx index f124551..309544d 100644 --- a/apps/client/app/modules/details/tabs/info.tsx +++ b/apps/client/app/modules/details/tabs/info.tsx @@ -19,7 +19,7 @@ export const VolumeInfoTabContent = ({ volume, statfs }: Props) => {
-
+
diff --git a/apps/server/src/modules/backends/webdav/webdav-backend.ts b/apps/server/src/modules/backends/webdav/webdav-backend.ts index ad413c1..5f6d5fc 100644 --- a/apps/server/src/modules/backends/webdav/webdav-backend.ts +++ b/apps/server/src/modules/backends/webdav/webdav-backend.ts @@ -80,13 +80,8 @@ const mount = async (config: BackendConfig, path: string) => { } logger.error("Error mounting WebDAV volume", { error: errorMsg }); - if (errorMsg.includes("No such device")) { - return { - status: BACKEND_STATUS.error, - error: - "WebDAV filesystem not supported. Please ensure davfs2 is properly installed and the kernel module is loaded.", - }; - } else if (errorMsg.includes("option") && errorMsg.includes("requires argument")) { + + if (errorMsg.includes("option") && errorMsg.includes("requires argument")) { return { status: BACKEND_STATUS.error, error: "Invalid mount options. Please check your WebDAV server configuration.",