mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			214 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			214 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | |
|   <div>
 | |
|     <app-settings-content :header-text="$strings.HeaderBackups" :description="$strings.MessageBackupsDescription">
 | |
|       <div v-if="backupLocation" class="mb-4 max-w-full overflow-hidden">
 | |
|         <div class="flex items-center mb-0.5">
 | |
|           <span class="material-symbols text-2xl text-black-50 mr-2">folder</span>
 | |
|           <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">
 | |
|               <span class="material-symbols text-lg">edit</span>
 | |
|             </button>
 | |
|           </div>
 | |
|         </div>
 | |
|         <div v-else>
 | |
|           <form class="flex items-center w-full space-x-1" @submit.prevent="saveBackupPath">
 | |
|             <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>
 | |
|             <ui-btn small :disabled="savingBackupPath" type="button" class="h-8" @click="cancelEditBackupPath">{{ $strings.ButtonCancel }}</ui-btn>
 | |
|           </form>
 | |
|           <p class="text-sm text-warning/80 pt-1">{{ canEditBackup ? $strings.MessageBackupsLocationEditNote : $strings.MessageBackupsLocationNoEditNote }}</p>
 | |
|         </div>
 | |
|       </div>
 | |
| 
 | |
|       <div class="flex items-center py-2">
 | |
|         <ui-toggle-switch v-model="enableBackups" small :disabled="updatingServerSettings" @input="updateBackupsSettings" />
 | |
|         <ui-tooltip :text="$strings.LabelBackupsEnableAutomaticBackupsHelp">
 | |
|           <p class="pl-4 text-lg">{{ $strings.LabelBackupsEnableAutomaticBackups }} <span class="material-symbols icon-text">info</span></p>
 | |
|         </ui-tooltip>
 | |
|       </div>
 | |
| 
 | |
|       <div v-if="enableBackups" class="mb-6">
 | |
|         <div class="flex items-center pl-0 sm:pl-6 mb-2">
 | |
|           <span class="material-symbols text-xl sm:text-2xl text-black-50 mr-2">schedule</span>
 | |
|           <div class="w-32 min-w-32 sm:w-40 sm:min-w-40">
 | |
|             <span class="text-white text-opacity-60 uppercase text-sm">{{ $strings.HeaderSchedule }}:</span>
 | |
|           </div>
 | |
|           <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">
 | |
|             <span class="material-symbols text-lg">edit</span>
 | |
|           </button>
 | |
|         </div>
 | |
| 
 | |
|         <div v-if="nextBackupDate" class="flex items-center pl-0 sm:pl-6 py-0.5">
 | |
|           <span class="material-symbols text-xl sm:text-2xl text-black-50 mr-2">event</span>
 | |
|           <div class="w-32 min-w-32 sm:w-40 sm:min-w-40">
 | |
|             <span class="text-white text-opacity-60 uppercase text-sm">{{ $strings.LabelNextBackupDate }}:</span>
 | |
|           </div>
 | |
|           <div class="text-gray-100 text-sm sm:text-base">{{ nextBackupDate }}</div>
 | |
|         </div>
 | |
|       </div>
 | |
| 
 | |
|       <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" />
 | |
| 
 | |
|         <ui-tooltip :text="$strings.LabelBackupsNumberToKeepHelp">
 | |
|           <p class="pl-4 text-lg">{{ $strings.LabelBackupsNumberToKeep }} <span class="material-symbols icon-text">info</span></p>
 | |
|         </ui-tooltip>
 | |
|       </div>
 | |
| 
 | |
|       <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" />
 | |
| 
 | |
|         <ui-tooltip :text="$strings.LabelBackupsMaxBackupSizeHelp">
 | |
|           <p class="pl-4 text-lg">{{ $strings.LabelBackupsMaxBackupSize }} <span class="material-symbols icon-text">info</span></p>
 | |
|         </ui-tooltip>
 | |
|       </div>
 | |
| 
 | |
|       <tables-backups-table ref="backupsTable" @loaded="backupsLoaded" />
 | |
| 
 | |
|       <modals-backup-schedule-modal v-model="showCronBuilder" :cron-expression.sync="cronExpression" />
 | |
|     </app-settings-content>
 | |
|   </div>
 | |
| </template>
 | |
| 
 | |
| <script>
 | |
| export default {
 | |
|   asyncData({ store, redirect }) {
 | |
|     if (!store.getters['user/getIsAdminOrUp']) {
 | |
|       redirect('/')
 | |
|     }
 | |
|   },
 | |
|   data() {
 | |
|     return {
 | |
|       updatingServerSettings: false,
 | |
|       enableBackups: true,
 | |
|       backupsToKeep: 2,
 | |
|       maxBackupSize: 1,
 | |
|       cronExpression: '',
 | |
|       newServerSettings: {},
 | |
|       showCronBuilder: false,
 | |
|       showEditBackupPath: false,
 | |
|       backupPathEnvSet: false,
 | |
|       backupLocation: '',
 | |
|       newBackupLocation: '',
 | |
|       savingBackupPath: false
 | |
|     }
 | |
|   },
 | |
|   watch: {
 | |
|     serverSettings(newVal, oldVal) {
 | |
|       if (newVal && !oldVal) {
 | |
|         this.newServerSettings = { ...this.serverSettings }
 | |
|         this.initServerSettings()
 | |
|       }
 | |
|     }
 | |
|   },
 | |
|   computed: {
 | |
|     serverSettings() {
 | |
|       return this.$store.state.serverSettings
 | |
|     },
 | |
|     dateFormat() {
 | |
|       return this.serverSettings.dateFormat
 | |
|     },
 | |
|     timeFormat() {
 | |
|       return this.serverSettings.timeFormat
 | |
|     },
 | |
|     canEditBackup() {
 | |
|       // Prevent editing of backup path if an environment variable is set
 | |
|       return !this.backupPathEnvSet
 | |
|     },
 | |
|     scheduleDescription() {
 | |
|       if (!this.cronExpression) return ''
 | |
|       const parsed = this.$parseCronExpression(this.cronExpression, this)
 | |
|       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) || ''
 | |
|     }
 | |
|   },
 | |
|   methods: {
 | |
|     backupsLoaded(data) {
 | |
|       this.backupLocation = data.backupLocation
 | |
|       this.newBackupLocation = data.backupLocation
 | |
|       this.backupPathEnvSet = data.backupPathEnvSet
 | |
|     },
 | |
|     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)
 | |
|           const errorMsg = error.response?.data || this.$strings.ToastFailedToUpdate
 | |
|           this.$toast.error(errorMsg)
 | |
|         })
 | |
|         .finally(() => {
 | |
|           this.savingBackupPath = false
 | |
|         })
 | |
|     },
 | |
|     updateBackupsSettings() {
 | |
|       if (isNaN(this.maxBackupSize) || this.maxBackupSize < 0) {
 | |
|         this.$toast.error(this.$strings.ToastBackupInvalidMaxSize)
 | |
|         return
 | |
|       }
 | |
|       if (isNaN(this.backupsToKeep) || this.backupsToKeep <= 0 || this.backupsToKeep > 99) {
 | |
|         this.$toast.error(this.$strings.ToastBackupInvalidMaxKeep)
 | |
|         return
 | |
|       }
 | |
|       const updatePayload = {
 | |
|         backupSchedule: this.enableBackups ? this.cronExpression : false,
 | |
|         backupsToKeep: Number(this.backupsToKeep),
 | |
|         maxBackupSize: Number(this.maxBackupSize)
 | |
|       }
 | |
|       this.updateServerSettings(updatePayload)
 | |
|     },
 | |
|     updateServerSettings(payload) {
 | |
|       this.updatingServerSettings = true
 | |
|       this.$store
 | |
|         .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
 | |
|         })
 | |
|     },
 | |
|     initServerSettings() {
 | |
|       this.newServerSettings = this.serverSettings ? { ...this.serverSettings } : {}
 | |
|       this.backupsToKeep = this.newServerSettings.backupsToKeep || 2
 | |
|       this.enableBackups = !!this.newServerSettings.backupSchedule
 | |
|       this.maxBackupSize = this.newServerSettings.maxBackupSize === 0 ? 0 : this.newServerSettings.maxBackupSize || 1
 | |
|       this.cronExpression = this.newServerSettings.backupSchedule || '30 1 * * *'
 | |
|     }
 | |
|   },
 | |
|   mounted() {
 | |
|     this.initServerSettings()
 | |
|   }
 | |
| }
 | |
| </script>
 |