diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md
index 3edd7cca6a4..6be6d3cbb4f 100644
--- a/CHANGELOG.unreleased.md
+++ b/CHANGELOG.unreleased.md
@@ -12,6 +12,7 @@
> Users must be able to say: “Nice enhancement, I'm eager to test it”
- [Proxies] Display the current proxy version (PR [#8104](https://github.com/vatesfr/xen-orchestra/pull/8104))
+- [Backup] Long-term retention
### Bug fixes
diff --git a/packages/xo-web/src/common/intl/messages.js b/packages/xo-web/src/common/intl/messages.js
index d2b8a7c4a23..663ea8bb157 100644
--- a/packages/xo-web/src/common/intl/messages.js
+++ b/packages/xo-web/src/common/intl/messages.js
@@ -623,6 +623,11 @@ const messages = {
cbtDestroySnapshotDataDisabledInformation:
'Snapshot data can be purged only when NBD is enabled and rolling snapshot is not used',
shorterBackupReports: 'Shorter backup reports',
+ longTermRetention: 'Long-term retention of backups',
+ numberOfDailyBackupsKept: 'Number of daily backups kept',
+ numberOfWeeklyBackupsKept: 'Number of weekly backups kept',
+ numberOfMonthlyBackupsKept: 'Number of monthly backups kept',
+ numberOfYearlyBackupsKept: 'Number of yearly backups kept',
// ------ New Remote -----
newRemote: 'New file system remote',
@@ -1523,8 +1528,7 @@ const messages = {
ha: 'HA',
srHaTooltip: 'SR used for High Availability',
nestedVirt: 'Nested virtualization',
- nestedVirtualizationWarning:
- 'Unstable feature, insecure for the host, usage is discouraged. Click for more details.',
+ nestedVirtualizationWarning: 'Unstable feature, insecure for the host, usage is discouraged. Click for more details.',
vmAffinityHost: 'Affinity host',
vmNeedToBeHalted: 'The VM needs to be halted',
vmVga: 'VGA',
diff --git a/packages/xo-web/src/xo-app/backup/new/index.js b/packages/xo-web/src/xo-app/backup/new/index.js
index e34c0c7c7b6..f2c5df96256 100644
--- a/packages/xo-web/src/xo-app/backup/new/index.js
+++ b/packages/xo-web/src/xo-app/backup/new/index.js
@@ -599,6 +599,18 @@ const New = decorate([
reportRecipients: (reportRecipients.splice(key, 1), reportRecipients),
})
},
+ setLongTermRetention({ setGlobalSettings }, retention, granularity) {
+ const { propSettings, settings = propSettings } = this.state
+ const longTermRetention = settings.getIn(['', 'longTermRetention']) ?? {}
+
+ if (retention > 0) {
+ longTermRetention[granularity] = { retention, settings: {} }
+ } else {
+ delete longTermRetention[granularity]
+ }
+
+ setGlobalSettings({ longTermRetention: isEmpty(longTermRetention) ? undefined : longTermRetention })
+ },
setReportWhen:
({ setGlobalSettings }, { value }) =>
() => {
@@ -679,6 +691,10 @@ const New = decorate([
inputNRetriesVmBackupFailures: generateId,
inputBackupReportTplId: generateId,
inputTimeoutId: generateId,
+ inputLongTermRetentionDaily: generateId,
+ inputLongTermRetentionWeekly: generateId,
+ inputLongTermRetentionMonthly: generateId,
+ inputLongTermRetentionYearly: generateId,
// In order to keep the user preference, the offline backup is kept in the DB
// and it's considered active only when the full mode is enabled
@@ -789,6 +805,7 @@ const New = decorate([
checkpointSnapshot,
concurrency,
fullInterval,
+ longTermRetention = {},
maxExportRate,
nbdConcurrency = 1,
nRetriesVmBackupFailures = 0,
@@ -1244,6 +1261,51 @@ const New = decorate([
+
+ {_('longTermRetention')}
+
+
+
+ effects.setLongTermRetention(value, 'daily')}
+ value={longTermRetention.daily?.retention}
+ />
+
+
+
+ effects.setLongTermRetention(value, 'weekly')}
+ value={longTermRetention.weekly?.retention}
+ />
+
+
+
+ effects.setLongTermRetention(value, 'monthly')}
+ value={longTermRetention.monthly?.retention}
+ />
+
+
+
+ effects.setLongTermRetention(value, 'yearly')}
+ value={longTermRetention.yearly?.retention}
+ />
+
+
+