mirror of
https://github.com/gotson/komga.git
synced 2025-12-06 08:32:25 +01:00
feat(webui): prefill author selection when bulk editing books
This commit is contained in:
parent
d1475864af
commit
5b56f20185
3 changed files with 57 additions and 11 deletions
|
|
@ -425,7 +425,7 @@
|
|||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import {groupAuthorsByRole} from '@/functions/authors'
|
||||
import {buildManyAuthorsByRole, groupAuthorsByRole} from '@/functions/authors'
|
||||
import {authorRoles} from '@/types/author-roles'
|
||||
import Vue from 'vue'
|
||||
import {helpers, requiredIf} from 'vuelidate/lib/validators'
|
||||
|
|
@ -482,6 +482,7 @@ export default Vue.extend({
|
|||
authorSearch: [],
|
||||
authorSearchResults: [] as string[],
|
||||
tagsAvailable: [] as string[],
|
||||
isMultiBookAuthorDirty: false, // workaround for author consistency in bulk mode
|
||||
}
|
||||
},
|
||||
props: {
|
||||
|
|
@ -627,11 +628,27 @@ export default Vue.extend({
|
|||
if (Array.isArray(books) && books.length === 0) return
|
||||
else if (this.$_.isEmpty(books)) return
|
||||
if (Array.isArray(books) && books.length > 0) {
|
||||
this.form.authors = {}
|
||||
this.form.authors = buildManyAuthorsByRole(books)
|
||||
this.form.links = []
|
||||
const currentRoles = this.$_.keys(this.form.authors)
|
||||
// Use authorRoles from computed value, so we can extend if needed
|
||||
const ignoreRoles = this.authorRoles.map(r => r.value)
|
||||
.filter((r) => !this.customRoles.includes(r)) // remove old custom roles
|
||||
.filter((r) => !authorRoles.includes(r)) // remove native roles
|
||||
this.customRoles = currentRoles.filter((r) => !ignoreRoles.includes(r)) // add new custom roles
|
||||
|
||||
let forceAuthorLock = false
|
||||
for (const book of books) {
|
||||
const bookAuthor = groupAuthorsByRole(book.metadata.authors)
|
||||
if (!this.$_.isEqual(bookAuthor, this.form.authors)) {
|
||||
this.isMultiBookAuthorDirty = true
|
||||
forceAuthorLock = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const authorsLock = this.$_.uniq(books.map(x => x.metadata.authorsLock))
|
||||
this.form.authorsLock = authorsLock.length > 1 ? false : authorsLock[0]
|
||||
this.form.authorsLock = authorsLock.length > 1 ? false : authorsLock[0] || forceAuthorLock
|
||||
|
||||
this.form.tags = []
|
||||
|
||||
|
|
@ -665,7 +682,7 @@ export default Vue.extend({
|
|||
tagsLock: this.form.tagsLock,
|
||||
}
|
||||
|
||||
if (this.$v.form?.authors?.$dirty) {
|
||||
if (this.$v.form?.authors?.$dirty || this.isMultiBookAuthorDirty) {
|
||||
this.$_.merge(metadata, {
|
||||
authors: this.$_.keys(this.form.authors).flatMap((role: string) =>
|
||||
this.$_.get(this.form.authors, role).map((name: string) => ({name: name, role: role})),
|
||||
|
|
|
|||
|
|
@ -573,7 +573,7 @@ import {isMatch} from 'date-fns'
|
|||
import IsbnVerify from '@saekitominaga/isbn-verify'
|
||||
import {debounce} from 'lodash'
|
||||
import {authorRoles} from '@/types/author-roles'
|
||||
import {groupAuthorsByRole} from '@/functions/authors'
|
||||
import {buildManyAuthorsByRole, groupAuthorsByRole} from '@/functions/authors'
|
||||
|
||||
const tags = require('language-tags')
|
||||
|
||||
|
|
@ -644,6 +644,7 @@ export default Vue.extend({
|
|||
genresAvailable: [] as string[],
|
||||
tagsAvailable: [] as string[],
|
||||
sharingLabelsAvailable: [] as string[],
|
||||
isMultiBookAuthorDirty: false, // workaround for author consistency in bulk mode
|
||||
}
|
||||
},
|
||||
props: {
|
||||
|
|
@ -880,10 +881,20 @@ export default Vue.extend({
|
|||
this.form.series.sharingLabelsLock = sharingLabelsLock.length > 1 ? false : sharingLabelsLock[0]
|
||||
|
||||
this.form.book.links = []
|
||||
this.form.book.authors = {}
|
||||
this.form.book.authors = buildManyAuthorsByRole(oneshots.map(x => x.book))
|
||||
|
||||
let forceAuthorLock = false
|
||||
for (const oneshot of oneshots) {
|
||||
const bookAuthor = groupAuthorsByRole(oneshot.book.metadata.authors)
|
||||
if (!this.$_.isEqual(bookAuthor, this.form.book.authors)) {
|
||||
this.isMultiBookAuthorDirty = true
|
||||
forceAuthorLock = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const authorsLock = this.$_.uniq(oneshots.map(x => x.book.metadata.authorsLock))
|
||||
this.form.book.authorsLock = authorsLock.length > 1 ? false : authorsLock[0]
|
||||
this.form.book.authorsLock = authorsLock.length > 1 ? false : authorsLock[0] || forceAuthorLock
|
||||
} else {
|
||||
this.form.series.genres = []
|
||||
this.form.series.sharingLabels = []
|
||||
|
|
@ -925,7 +936,7 @@ export default Vue.extend({
|
|||
tagsLock: this.form.book.tagsLock,
|
||||
}
|
||||
|
||||
if (this.$v.form?.book?.authors?.$dirty) {
|
||||
if (this.$v.form?.book?.authors?.$dirty || this.isMultiBookAuthorDirty) {
|
||||
this.$_.merge(metadataBook, {
|
||||
authors: this.$_.keys(this.form.book.authors).flatMap((role: string) =>
|
||||
this.$_.get(this.form.book.authors, role).map((name: string) => ({name: name, role: role})),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,26 @@
|
|||
import {groupBy, mapValues} from 'lodash'
|
||||
import {AuthorDto} from '@/types/komga-books'
|
||||
import {flatMap, groupBy, intersection, mapValues, reduce, uniq} from 'lodash'
|
||||
import {AuthorDto, BookDto} from '@/types/komga-books'
|
||||
|
||||
type AuthorsByRole = {[role: string]: string[]}
|
||||
|
||||
// return an object where keys are roles, and values are string[]
|
||||
export function groupAuthorsByRole (authors: AuthorDto[]): any {
|
||||
export function groupAuthorsByRole (authors: AuthorDto[]): AuthorsByRole {
|
||||
return mapValues(groupBy(authors, 'role'),
|
||||
authors => authors.map((author: AuthorDto) => author.name))
|
||||
}
|
||||
|
||||
// create an object where keys are roles and values are arrays of authors
|
||||
// we're using intersection to only include authors that are present on all books of each roles
|
||||
export function buildManyAuthorsByRole(books: BookDto[]): AuthorsByRole {
|
||||
const allAuthorsByRoles = books.map(book => groupAuthorsByRole(book.metadata.authors))
|
||||
const roleKeys = uniq(flatMap(allAuthorsByRoles, Object.keys))
|
||||
return reduce(roleKeys, (acc: {[key: string]: string[]}, key) => {
|
||||
const values = allAuthorsByRoles.map(authorsByRole => authorsByRole[key] || [])
|
||||
const intersect = intersection(...values.filter(arr => arr.length > 0))
|
||||
|
||||
if (intersect.length > 0) {
|
||||
acc[key] = intersect
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue