2021-10-23 03:08:02 +02:00
|
|
|
<template>
|
2022-11-26 06:12:23 +01:00
|
|
|
<div>
|
|
|
|
<app-settings-content :header-text="$strings.HeaderBackups" :description="$strings.MessageBackupsDescription">
|
2024-06-20 00:14:37 +02:00
|
|
|
<div v-if="backupLocation" class="mb-4 max-w-full overflow-hidden">
|
|
|
|
<div class="flex items-center mb-0.5">
|
2024-08-16 23:57:17 +02:00
|
|
|
<span class="material-symbols text-2xl text-black-50 mr-2">folder</span>
|
2024-06-20 00:14:37 +02:00
|
|
|
<span class="text-white text-opacity-60 uppercase text-sm whitespace-nowrap">{{ $strings.LabelBackupLocation }}:</span>
|
|
|
|
</div>
|
|
|
|
<div v-if="!showEditBackupPath" class="inline-flex items-center w-full overflow-hidden">
|
|
|
|
<p class="text-gray-100 max-w-[calc(100%-40px)] text-sm sm:text-base break-words">{{ backupLocation }}</p>
|
|
|
|
<div class="w-10 min-w-10 flex items-center justify-center">
|
|
|
|
<button class="text-black-50 hover:text-yellow-500 inline-flex" type="button" @click="showEditBackupPath = !showEditBackupPath">
|
2024-07-08 18:36:37 +02:00
|
|
|
<span class="material-symbols text-lg">edit</span>
|
2024-06-20 00:14:37 +02:00
|
|
|
</button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div v-else>
|
|
|
|
<form class="flex items-center w-full space-x-1" @submit.prevent="saveBackupPath">
|
2024-07-05 19:44:49 +02:00
|
|
|
<ui-text-input v-model="newBackupLocation" :disabled="savingBackupPath || !canEditBackup" class="w-full max-w-[calc(100%-50px)] text-sm h-8" />
|
|
|
|
<ui-btn v-if="canEditBackup" small :loading="savingBackupPath" color="success" type="submit" class="h-8">{{ $strings.ButtonSave }}</ui-btn>
|
2024-06-20 00:14:37 +02:00
|
|
|
<ui-btn small :disabled="savingBackupPath" type="button" class="h-8" @click="cancelEditBackupPath">{{ $strings.ButtonCancel }}</ui-btn>
|
|
|
|
</form>
|
2024-07-05 19:44:49 +02:00
|
|
|
<p class="text-sm text-warning/80 pt-1">{{ canEditBackup ? $strings.MessageBackupsLocationEditNote : $strings.MessageBackupsLocationNoEditNote }}</p>
|
2024-06-20 00:14:37 +02:00
|
|
|
</div>
|
2023-09-22 23:49:01 +02:00
|
|
|
</div>
|
|
|
|
|
2021-10-23 03:08:02 +02:00
|
|
|
<div class="flex items-center py-2">
|
2022-08-19 01:46:42 +02:00
|
|
|
<ui-toggle-switch v-model="enableBackups" small :disabled="updatingServerSettings" @input="updateBackupsSettings" />
|
2022-11-08 01:27:17 +01:00
|
|
|
<ui-tooltip :text="$strings.LabelBackupsEnableAutomaticBackupsHelp">
|
2024-07-08 18:36:37 +02:00
|
|
|
<p class="pl-4 text-lg">{{ $strings.LabelBackupsEnableAutomaticBackups }} <span class="material-symbols icon-text">info</span></p>
|
2021-10-23 03:08:02 +02:00
|
|
|
</ui-tooltip>
|
|
|
|
</div>
|
|
|
|
|
2022-08-19 01:46:42 +02:00
|
|
|
<div v-if="enableBackups" class="mb-6">
|
2024-06-20 00:14:37 +02:00
|
|
|
<div class="flex items-center pl-0 sm:pl-6 mb-2">
|
2024-08-16 23:57:17 +02:00
|
|
|
<span class="material-symbols text-xl sm:text-2xl text-black-50 mr-2">schedule</span>
|
2024-06-20 00:14:37 +02:00
|
|
|
<div class="w-32 min-w-32 sm:w-40 sm:min-w-40">
|
2023-06-16 00:41:27 +02:00
|
|
|
<span class="text-white text-opacity-60 uppercase text-sm">{{ $strings.HeaderSchedule }}:</span>
|
|
|
|
</div>
|
2024-06-20 00:14:37 +02:00
|
|
|
<div class="text-gray-100 text-sm sm:text-base">{{ scheduleDescription }}</div>
|
|
|
|
<button class="ml-2 text-black-50 hover:text-yellow-500 inline-flex" type="button" @click="showCronBuilder = !showCronBuilder">
|
2024-07-08 18:36:37 +02:00
|
|
|
<span class="material-symbols text-lg">edit</span>
|
2024-06-20 00:14:37 +02:00
|
|
|
</button>
|
2023-02-27 19:04:26 +01:00
|
|
|
</div>
|
|
|
|
|
2024-06-20 00:14:37 +02:00
|
|
|
<div v-if="nextBackupDate" class="flex items-center pl-0 sm:pl-6 py-0.5">
|
2024-08-16 23:57:17 +02:00
|
|
|
<span class="material-symbols text-xl sm:text-2xl text-black-50 mr-2">event</span>
|
2024-06-20 00:14:37 +02:00
|
|
|
<div class="w-32 min-w-32 sm:w-40 sm:min-w-40">
|
2023-06-16 00:41:27 +02:00
|
|
|
<span class="text-white text-opacity-60 uppercase text-sm">{{ $strings.LabelNextBackupDate }}:</span>
|
|
|
|
</div>
|
2024-06-20 00:14:37 +02:00
|
|
|
<div class="text-gray-100 text-sm sm:text-base">{{ nextBackupDate }}</div>
|
2022-08-19 01:46:42 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
2022-08-02 01:06:22 +02:00
|
|
|
|
2021-10-23 03:08:02 +02:00
|
|
|
<div class="flex items-center py-2">
|
|
|
|
<ui-text-input type="number" v-model="backupsToKeep" no-spinner :disabled="updatingServerSettings" :padding-x="1" text-center class="w-10" @change="updateBackupsSettings" />
|
|
|
|
|
2022-11-08 01:27:17 +01:00
|
|
|
<ui-tooltip :text="$strings.LabelBackupsNumberToKeepHelp">
|
2024-07-08 18:36:37 +02:00
|
|
|
<p class="pl-4 text-lg">{{ $strings.LabelBackupsNumberToKeep }} <span class="material-symbols icon-text">info</span></p>
|
2022-10-08 23:30:21 +02:00
|
|
|
</ui-tooltip>
|
2021-10-23 03:08:02 +02:00
|
|
|
</div>
|
|
|
|
|
2022-04-23 19:19:31 +02:00
|
|
|
<div class="flex items-center py-2">
|
|
|
|
<ui-text-input type="number" v-model="maxBackupSize" no-spinner :disabled="updatingServerSettings" :padding-x="1" text-center class="w-10" @change="updateBackupsSettings" />
|
|
|
|
|
2022-11-08 01:27:17 +01:00
|
|
|
<ui-tooltip :text="$strings.LabelBackupsMaxBackupSizeHelp">
|
2024-07-16 07:11:20 +02:00
|
|
|
<p class="pl-4 text-lg">{{ $strings.LabelBackupsMaxBackupSize }} <span class="material-symbols icon-text">info</span></p>
|
2022-04-23 19:23:01 +02:00
|
|
|
</ui-tooltip>
|
2022-04-23 19:19:31 +02:00
|
|
|
</div>
|
|
|
|
|
2024-06-20 00:14:37 +02:00
|
|
|
<tables-backups-table ref="backupsTable" @loaded="backupsLoaded" />
|
2022-12-20 19:35:31 +01:00
|
|
|
|
|
|
|
<modals-backup-schedule-modal v-model="showCronBuilder" :cron-expression.sync="cronExpression" />
|
2022-11-26 06:12:23 +01:00
|
|
|
</app-settings-content>
|
2021-10-23 03:08:02 +02:00
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
export default {
|
2023-06-16 00:41:27 +02:00
|
|
|
asyncData({ store, redirect }) {
|
|
|
|
if (!store.getters['user/getIsAdminOrUp']) {
|
|
|
|
redirect('/')
|
|
|
|
}
|
|
|
|
},
|
2021-10-23 03:08:02 +02:00
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
updatingServerSettings: false,
|
2022-08-19 01:46:42 +02:00
|
|
|
enableBackups: true,
|
2021-10-27 01:29:04 +02:00
|
|
|
backupsToKeep: 2,
|
2022-04-23 19:19:31 +02:00
|
|
|
maxBackupSize: 1,
|
2022-08-19 01:46:42 +02:00
|
|
|
cronExpression: '',
|
|
|
|
newServerSettings: {},
|
2023-09-20 23:36:30 +02:00
|
|
|
showCronBuilder: false,
|
2024-06-20 00:14:37 +02:00
|
|
|
showEditBackupPath: false,
|
2024-07-05 23:10:07 +02:00
|
|
|
backupPathEnvSet: false,
|
2024-06-20 00:14:37 +02:00
|
|
|
backupLocation: '',
|
|
|
|
newBackupLocation: '',
|
|
|
|
savingBackupPath: false
|
2021-10-27 01:29:04 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
watch: {
|
|
|
|
serverSettings(newVal, oldVal) {
|
|
|
|
if (newVal && !oldVal) {
|
|
|
|
this.newServerSettings = { ...this.serverSettings }
|
|
|
|
this.initServerSettings()
|
|
|
|
}
|
2021-10-23 03:08:02 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
computed: {
|
2021-10-27 01:29:04 +02:00
|
|
|
serverSettings() {
|
|
|
|
return this.$store.state.serverSettings
|
2022-08-19 01:46:42 +02:00
|
|
|
},
|
2023-02-27 19:04:26 +01:00
|
|
|
dateFormat() {
|
|
|
|
return this.serverSettings.dateFormat
|
|
|
|
},
|
|
|
|
timeFormat() {
|
|
|
|
return this.serverSettings.timeFormat
|
|
|
|
},
|
2024-07-05 19:44:49 +02:00
|
|
|
canEditBackup() {
|
2024-07-05 23:10:07 +02:00
|
|
|
// Prevent editing of backup path if an environment variable is set
|
|
|
|
return !this.backupPathEnvSet
|
2024-07-05 19:44:49 +02:00
|
|
|
},
|
2022-08-19 01:46:42 +02:00
|
|
|
scheduleDescription() {
|
|
|
|
if (!this.cronExpression) return ''
|
|
|
|
const parsed = this.$parseCronExpression(this.cronExpression)
|
2023-02-27 19:04:26 +01:00
|
|
|
return parsed ? parsed.description : `${this.$strings.LabelCustomCronExpression} ${this.cronExpression}`
|
|
|
|
},
|
|
|
|
nextBackupDate() {
|
|
|
|
if (!this.cronExpression) return ''
|
|
|
|
const parsed = this.$getNextScheduledDate(this.cronExpression)
|
|
|
|
return this.$formatJsDatetime(parsed, this.dateFormat, this.timeFormat) || ''
|
2021-10-23 03:08:02 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
2024-07-05 23:10:07 +02:00
|
|
|
backupsLoaded(data) {
|
|
|
|
this.backupLocation = data.backupLocation
|
|
|
|
this.newBackupLocation = data.backupLocation
|
|
|
|
this.backupPathEnvSet = data.backupPathEnvSet
|
2024-06-20 00:14:37 +02:00
|
|
|
},
|
|
|
|
cancelEditBackupPath() {
|
|
|
|
this.newBackupLocation = this.backupLocation
|
|
|
|
this.showEditBackupPath = false
|
|
|
|
},
|
|
|
|
saveBackupPath() {
|
|
|
|
if (!this.newBackupLocation?.trim()) {
|
|
|
|
this.$toast.error(this.$strings.MessageBackupsLocationPathEmpty)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
this.newBackupLocation = this.newBackupLocation.trim()
|
|
|
|
if (this.newBackupLocation === this.backupLocation) {
|
|
|
|
this.showEditBackupPath = false
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
this.savingBackupPath = true
|
|
|
|
this.$axios
|
|
|
|
.patch('/api/backups/path', { path: this.newBackupLocation })
|
|
|
|
.then(() => {
|
|
|
|
this.backupLocation = this.newBackupLocation
|
|
|
|
this.showEditBackupPath = false
|
|
|
|
this.$refs.backupsTable.loadBackups()
|
|
|
|
})
|
|
|
|
.catch((error) => {
|
|
|
|
console.error('Failed to save backup path', error)
|
2024-09-30 00:53:52 +02:00
|
|
|
const errorMsg = error.response?.data || this.$strings.ToastFailedToUpdate
|
2024-06-20 00:14:37 +02:00
|
|
|
this.$toast.error(errorMsg)
|
|
|
|
})
|
|
|
|
.finally(() => {
|
|
|
|
this.savingBackupPath = false
|
|
|
|
})
|
2023-09-22 23:49:01 +02:00
|
|
|
},
|
2021-10-23 03:08:02 +02:00
|
|
|
updateBackupsSettings() {
|
2024-07-16 05:58:05 +02:00
|
|
|
if (isNaN(this.maxBackupSize) || this.maxBackupSize < 0) {
|
2024-08-31 00:47:49 +02:00
|
|
|
this.$toast.error(this.$strings.ToastBackupInvalidMaxSize)
|
2022-04-23 19:19:31 +02:00
|
|
|
return
|
|
|
|
}
|
2021-10-23 03:08:02 +02:00
|
|
|
if (isNaN(this.backupsToKeep) || this.backupsToKeep <= 0 || this.backupsToKeep > 99) {
|
2024-08-31 00:47:49 +02:00
|
|
|
this.$toast.error(this.$strings.ToastBackupInvalidMaxKeep)
|
2021-10-23 03:08:02 +02:00
|
|
|
return
|
|
|
|
}
|
2023-07-14 21:04:28 +02:00
|
|
|
const updatePayload = {
|
2022-08-19 01:46:42 +02:00
|
|
|
backupSchedule: this.enableBackups ? this.cronExpression : false,
|
2022-04-23 19:19:31 +02:00
|
|
|
backupsToKeep: Number(this.backupsToKeep),
|
|
|
|
maxBackupSize: Number(this.maxBackupSize)
|
2021-10-23 03:08:02 +02:00
|
|
|
}
|
|
|
|
this.updateServerSettings(updatePayload)
|
|
|
|
},
|
|
|
|
updateServerSettings(payload) {
|
|
|
|
this.updatingServerSettings = true
|
|
|
|
this.$store
|
2023-06-16 00:41:27 +02:00
|
|
|
.dispatch('updateServerSettings', payload)
|
|
|
|
.then((success) => {
|
|
|
|
console.log('Updated Server Settings', success)
|
|
|
|
this.updatingServerSettings = false
|
|
|
|
})
|
|
|
|
.catch((error) => {
|
|
|
|
console.error('Failed to update server settings', error)
|
|
|
|
this.updatingServerSettings = false
|
|
|
|
})
|
2021-10-27 01:29:04 +02:00
|
|
|
},
|
|
|
|
initServerSettings() {
|
|
|
|
this.newServerSettings = this.serverSettings ? { ...this.serverSettings } : {}
|
|
|
|
this.backupsToKeep = this.newServerSettings.backupsToKeep || 2
|
2022-08-19 01:46:42 +02:00
|
|
|
this.enableBackups = !!this.newServerSettings.backupSchedule
|
2024-07-16 07:31:12 +02:00
|
|
|
this.maxBackupSize = this.newServerSettings.maxBackupSize === 0 ? 0 : this.newServerSettings.maxBackupSize || 1
|
2022-08-19 01:46:42 +02:00
|
|
|
this.cronExpression = this.newServerSettings.backupSchedule || '30 1 * * *'
|
2021-10-23 03:08:02 +02:00
|
|
|
}
|
|
|
|
},
|
2021-10-27 01:29:04 +02:00
|
|
|
mounted() {
|
|
|
|
this.initServerSettings()
|
|
|
|
}
|
2021-10-23 03:08:02 +02:00
|
|
|
}
|
2023-02-27 19:04:26 +01:00
|
|
|
</script>
|