Merge branch 'master' of github.com:advplyr/audiobookshelf

# Conflicts:
#	client/components/app/BookShelfCategorized.vue
#	client/components/cards/LazySeriesCard.vue
This commit is contained in:
Toni Barth 2024-07-09 15:06:08 +02:00
commit 2896e32f4e
147 changed files with 8627 additions and 5171 deletions

View file

@ -1,10 +1,27 @@
<template>
<div>
<app-settings-content :header-text="$strings.HeaderBackups" :description="$strings.MessageBackupsDescription">
<div v-if="backupLocation" class="flex items-center mb-4">
<span class="material-icons-outlined text-2xl text-black-50 mr-2">folder</span>
<span class="text-white text-opacity-60 uppercase text-sm">{{ $strings.LabelBackupLocation }}:</span>
<div class="text-gray-100 pl-4">{{ backupLocation }}</div>
<div v-if="backupLocation" class="mb-4 max-w-full overflow-hidden">
<div class="flex items-center mb-0.5">
<span class="material-icons-outlined 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-icons 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">
@ -15,21 +32,23 @@
</div>
<div v-if="enableBackups" class="mb-6">
<div class="flex items-center pl-6 mb-2">
<span class="material-icons-outlined text-2xl text-black-50 mr-2">schedule</span>
<div class="w-40">
<div class="flex items-center pl-0 sm:pl-6 mb-2">
<span class="material-icons-outlined 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">{{ scheduleDescription }}</div>
<span class="material-icons text-lg text-black-50 hover:text-yellow-500 cursor-pointer ml-2" @click="showCronBuilder = !showCronBuilder">edit</span>
<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-icons text-lg">edit</span>
</button>
</div>
<div v-if="nextBackupDate" class="flex items-center pl-6 py-0.5 px-2">
<span class="material-icons-outlined text-2xl text-black-50 mr-2">event</span>
<div class="w-40">
<div v-if="nextBackupDate" class="flex items-center pl-0 sm:pl-6 py-0.5">
<span class="material-icons-outlined 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">{{ nextBackupDate }}</div>
<div class="text-gray-100 text-sm sm:text-base">{{ nextBackupDate }}</div>
</div>
</div>
@ -49,7 +68,7 @@
</ui-tooltip>
</div>
<tables-backups-table @loaded="backupsLoaded" />
<tables-backups-table ref="backupsTable" @loaded="backupsLoaded" />
<modals-backup-schedule-modal v-model="showCronBuilder" :cron-expression.sync="cronExpression" />
</app-settings-content>
@ -72,7 +91,11 @@ export default {
cronExpression: '',
newServerSettings: {},
showCronBuilder: false,
backupLocation: ''
showEditBackupPath: false,
backupPathEnvSet: false,
backupLocation: '',
newBackupLocation: '',
savingBackupPath: false
}
},
watch: {
@ -93,6 +116,10 @@ export default {
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)
@ -105,8 +132,42 @@ export default {
}
},
methods: {
backupsLoaded(backupLocation) {
this.backupLocation = backupLocation
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 || 'Failed to save backup path'
this.$toast.error(errorMsg)
})
.finally(() => {
this.savingBackupPath = false
})
},
updateBackupsSettings() {
if (isNaN(this.maxBackupSize) || this.maxBackupSize <= 0) {

View file

@ -100,7 +100,7 @@
</div>
<p v-else class="text-white text-opacity-50">{{ $strings.MessageNoListeningSessions }}</p>
<div class="w-full my-8 h-px bg-white/10" />
<div v-if="openListeningSessions.length" class="w-full my-8 h-px bg-white/10" />
<!-- open listening sessions table -->
<p v-if="openListeningSessions.length" class="text-lg my-4">Open Listening Sessions</p>
@ -144,6 +144,45 @@
</tr>
</table>
</div>
<div v-if="openShareListeningSessions.length" class="w-full my-8 h-px bg-white/10" />
<!-- open share listening sessions table -->
<p v-if="openShareListeningSessions.length" class="text-lg my-4">Open Share Listening Sessions</p>
<div v-if="openShareListeningSessions.length" class="block max-w-full">
<table class="userSessionsTable">
<tr class="bg-primary bg-opacity-40">
<th class="w-48 min-w-48 text-left">{{ $strings.LabelItem }}</th>
<th class="w-20 min-w-20 text-left hidden md:table-cell">{{ $strings.LabelUser }}</th>
<th class="w-32 min-w-32 text-left hidden md:table-cell">{{ $strings.LabelPlayMethod }}</th>
<th class="w-32 min-w-32 text-left hidden sm:table-cell">{{ $strings.LabelDeviceInfo }}</th>
<th class="w-16 min-w-16">{{ $strings.LabelLastTime }}</th>
<th class="flex-grow hidden sm:table-cell">{{ $strings.LabelLastUpdate }}</th>
</tr>
<tr v-for="session in openShareListeningSessions" :key="`open-${session.id}`" class="cursor-pointer" @click="showSession(session)">
<td class="py-1 max-w-48">
<p class="text-xs text-gray-200 truncate">{{ session.displayTitle }}</p>
<p class="text-xs text-gray-400 truncate">{{ session.displayAuthor }}</p>
</td>
<td class="hidden md:table-cell"></td>
<td class="hidden md:table-cell">
<p class="text-xs">{{ getPlayMethodName(session.playMethod) }}</p>
</td>
<td class="hidden sm:table-cell max-w-32 min-w-32">
<p class="text-xs truncate" v-html="getDeviceInfoString(session.deviceInfo)" />
</td>
<td class="text-center hover:underline" @click.stop="clickCurrentTime(session)">
<p class="text-xs font-mono">{{ $secondsToTimestamp(session.currentTime) }}</p>
</td>
<td class="text-center hidden sm:table-cell">
<ui-tooltip v-if="session.updatedAt" direction="top" :text="$formatDatetime(session.updatedAt, dateFormat, timeFormat)">
<p class="text-xs text-gray-200">{{ $dateDistanceFromNow(session.updatedAt) }}</p>
</ui-tooltip>
</td>
</tr>
</table>
</div>
</app-settings-content>
<modals-listening-session-modal v-model="showSessionModal" :session="selectedSession" @removedSession="removedSession" @closedSession="closedSession" />
@ -180,6 +219,7 @@ export default {
selectedSession: null,
listeningSessions: [],
openListeningSessions: [],
openShareListeningSessions: [],
numPages: 0,
total: 0,
currentPage: 0,
@ -455,6 +495,7 @@ export default {
s.open = true
return s
})
this.openShareListeningSessions = data.shareSessions || []
},
init() {
this.loadSessions(0)