mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2026-02-28 21:19:42 +00:00
- Remove disabled state from series name input in edit modal - Add duplicate name validation in SeriesController (resolves TODO) - Update nameIgnorePrefix when series name changes - Add frontend validation for duplicate series names - Add updateSeriesName method to PATCH series immediately on rename - Show backend error message in toast on failure - Add i18n string for duplicate name error message This enables users to rename existing series while preventing duplicate series names within the same library.
140 lines
4.7 KiB
Vue
140 lines
4.7 KiB
Vue
<template>
|
|
<div>
|
|
<ui-multi-select-query-input v-model="seriesItems" text-key="displayName" :label="$strings.LabelSeries" :disabled="disabled" readonly show-edit @edit="editSeriesItem" @add="addNewSeries" />
|
|
|
|
<modals-edit-series-input-inner-modal v-model="showSeriesForm" :selected-series="selectedSeries" :existing-series-names="existingSeriesNames" :original-series-sequence="originalSeriesSequence" @submit="submitSeriesForm" />
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
props: {
|
|
value: {
|
|
type: Array,
|
|
default: () => []
|
|
},
|
|
disabled: Boolean
|
|
},
|
|
data() {
|
|
return {
|
|
selectedSeries: null,
|
|
originalSeriesSequence: null,
|
|
originalSeriesName: null,
|
|
showSeriesForm: false
|
|
}
|
|
},
|
|
computed: {
|
|
seriesItems: {
|
|
get() {
|
|
return (this.value || []).map((se) => {
|
|
return {
|
|
displayName: se.sequence ? `${se.name} #${se.sequence}` : se.name,
|
|
...se
|
|
}
|
|
})
|
|
},
|
|
set(val) {
|
|
this.$emit('input', val)
|
|
}
|
|
},
|
|
series() {
|
|
return this.filterData.series || []
|
|
},
|
|
filterData() {
|
|
return this.$store.state.libraries.filterData || {}
|
|
},
|
|
existingSeriesNames() {
|
|
// Only show series names not already selected
|
|
var alreadySelectedSeriesIds = (this.value || []).map((se) => se.id)
|
|
return this.series.filter((se) => !alreadySelectedSeriesIds.includes(se.id)).map((se) => se.name)
|
|
}
|
|
},
|
|
methods: {
|
|
cancelSeriesForm() {
|
|
this.showSeriesForm = false
|
|
},
|
|
editSeriesItem(series) {
|
|
var _series = this.seriesItems.find((se) => se.id === series.id)
|
|
if (!_series) return
|
|
|
|
this.selectedSeries = {
|
|
..._series
|
|
}
|
|
|
|
this.originalSeriesSequence = _series.sequence
|
|
this.originalSeriesName = _series.name
|
|
this.showSeriesForm = true
|
|
},
|
|
addNewSeries() {
|
|
this.selectedSeries = {
|
|
id: `new-${Date.now()}`,
|
|
name: '',
|
|
sequence: ''
|
|
}
|
|
|
|
this.originalSeriesSequence = null
|
|
this.originalSeriesName = null
|
|
this.showSeriesForm = true
|
|
},
|
|
submitSeriesForm() {
|
|
if (!this.selectedSeries.name) {
|
|
this.$toast.error('Must enter a series')
|
|
return
|
|
}
|
|
|
|
var existingSeriesIndex = this.seriesItems.findIndex((se) => se.id === this.selectedSeries.id)
|
|
|
|
// Check if renaming to a name that already exists in the library (different series)
|
|
var seriesSameName = this.series.find((se) => se.name.toLowerCase() === this.selectedSeries.name.toLowerCase())
|
|
if (seriesSameName && seriesSameName.id !== this.selectedSeries.id) {
|
|
// If editing an existing series and trying to rename to an existing name, block it
|
|
if (!this.selectedSeries.id.startsWith('new-')) {
|
|
this.$toast.error(this.$strings.ToastSeriesDuplicateName)
|
|
return
|
|
}
|
|
// For new series, use the existing series id instead
|
|
this.selectedSeries.id = seriesSameName.id
|
|
}
|
|
|
|
var existingSeriesSameName = this.seriesItems.findIndex((se) => se.name.toLowerCase() === this.selectedSeries.name.toLowerCase())
|
|
if (existingSeriesSameName >= 0 && existingSeriesIndex < 0) {
|
|
console.error('Attempt to add duplicate series')
|
|
this.$toast.error(this.$strings.ToastSeriesSubmitFailedSameName)
|
|
return
|
|
}
|
|
|
|
var selectedSeriesCopy = { ...this.selectedSeries }
|
|
selectedSeriesCopy.displayName = selectedSeriesCopy.sequence ? `${selectedSeriesCopy.name} #${selectedSeriesCopy.sequence}` : selectedSeriesCopy.name
|
|
|
|
var seriesCopy = this.seriesItems.map((v) => ({ ...v }))
|
|
if (existingSeriesIndex >= 0) {
|
|
seriesCopy.splice(existingSeriesIndex, 1, selectedSeriesCopy)
|
|
this.seriesItems = seriesCopy
|
|
} else {
|
|
seriesCopy.push(selectedSeriesCopy)
|
|
this.seriesItems = seriesCopy
|
|
}
|
|
|
|
// If this is an existing series (not new), update the series name immediately
|
|
if (!this.selectedSeries.id.startsWith('new-')) {
|
|
const hasNameChanged = this.originalSeriesName && this.selectedSeries.name !== this.originalSeriesName
|
|
if (hasNameChanged) {
|
|
this.updateSeriesName(this.selectedSeries.id, this.selectedSeries.name)
|
|
}
|
|
}
|
|
|
|
this.showSeriesForm = false
|
|
},
|
|
async updateSeriesName(seriesId, name) {
|
|
try {
|
|
await this.$axios.$patch(`/api/series/${seriesId}`, { name })
|
|
this.$toast.success(this.$strings.ToastSeriesUpdateSuccess)
|
|
} catch (error) {
|
|
console.error('Failed to update series name:', error)
|
|
const errorMsg = error.response?.data || this.$strings.ToastSeriesUpdateFailed
|
|
this.$toast.error(errorMsg)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|