Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(webui): make custom author roles consistent when editing book #1051

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions komga-webui/src/components/ReusableDialogs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
<edit-books-dialog
v-model="updateBooksDialog"
:books="updateBooks"
:additional-roles="updateBooksAdditionalRoles"
/>

<bulk-edit-books-dialog
Expand All @@ -68,6 +69,7 @@
<edit-oneshot-dialog
v-model="updateOneshotsDialog"
:oneshots="updateOneshots"
:additional-roles="updateOneshotsAdditionalRoles"
/>

<edit-series-dialog
Expand Down Expand Up @@ -240,6 +242,9 @@ export default Vue.extend({
updateBooks(): BookDto | BookDto[] {
return this.$store.state.updateBooks
},
updateBooksAdditionalRoles(): string[] {
return this.$store.state.updateBooksAdditionalRoles
},
// books bulk
updateBulkBooksDialog: {
get(): boolean {
Expand Down Expand Up @@ -278,6 +283,9 @@ export default Vue.extend({
updateOneshots(): Oneshot | Oneshot[] {
return this.$store.state.updateOneshots
},
updateOneshotsAdditionalRoles(): string[] {
return this.$store.state.updateOneshotsAdditionalRoles
},
// series
updateSeriesDialog: {
get(): boolean {
Expand Down
7 changes: 6 additions & 1 deletion komga-webui/src/components/dialogs/EditBooksDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,11 @@ export default Vue.extend({
type: [Object as () => BookDto, Array as () => BookDto[]],
required: true,
},
additionalRoles: {
type: Array as () => string[],
required: false,
default: () => [],
},
},
watch: {
value(val) {
Expand Down Expand Up @@ -548,7 +553,7 @@ export default Vue.extend({
remoteRoles = this.books.flatMap(b => b.metadata.authors).map(a => a.role)
else if (this.books?.metadata?.authors)
remoteRoles = this.books.metadata.authors.map(a => a.role)
const allRoles = this.$_.uniq([...authorRoles, ...remoteRoles, ...this.customRoles])
const allRoles = this.$_.uniq([...authorRoles, ...remoteRoles, ...this.customRoles, ...this.additionalRoles])
return allRoles.map((role: string) => ({
name: this.$te(`author_roles.${role}`) ? this.$t(`author_roles.${role}`).toString() : role,
value: role,
Expand Down
8 changes: 7 additions & 1 deletion komga-webui/src/components/dialogs/EditOneshotDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand All @@ -652,6 +653,11 @@ export default Vue.extend({
type: [Object as () => Oneshot, Array as () => Oneshot[]],
required: true,
},
additionalRoles: {
type: Array as () => string[],
required: false,
default: () => [],
},
},
watch: {
value(val) {
Expand Down Expand Up @@ -729,7 +735,7 @@ export default Vue.extend({
remoteRoles = this.books.flatMap(b => b.metadata.authors).map(a => a.role)
else if (this.books?.metadata?.authors)
remoteRoles = this.books.metadata.authors.map(a => a.role)
const allRoles = this.$_.uniq([...authorRoles, ...remoteRoles, ...this.customRoles])
const allRoles = this.$_.uniq([...authorRoles, ...remoteRoles, ...this.customRoles, ...this.additionalRoles])
return allRoles.map((role: string) => ({
name: this.$te(`author_roles.${role}`) ? this.$t(`author_roles.${role}`).toString() : role,
value: role,
Expand Down
14 changes: 14 additions & 0 deletions komga-webui/src/functions/author-roles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {authorRoles} from '@/types/author-roles'
import {BookDto} from '@/types/komga-books'

export function getCustomRoles(books: BookDto[]): string[] {
return books.flatMap((b) => b.metadata.authors.map((a) => a.role)).filter((ra) => !authorRoles.includes(ra))
}

export function getCustomRolesForSeries(books: BookDto[], seriesId: string): string[] {
return getCustomRoles(books.filter((b) => b.seriesId === seriesId))
}

export function isAllSelectedSameSeries(books: BookDto[]): boolean {
return books.every((b) => b.seriesId === books[0].seriesId)
}
14 changes: 12 additions & 2 deletions komga-webui/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@ export default new Vuex.Store({
updateBooksDialog: false,
deleteBooks: {} as BookDto | BookDto[],
deleteBookDialog: false,
updateBooksAdditionalRoles: [] as string[],
// books bulk
updateBulkBooks: [] as BookDto[],
updateBulkBooksDialog: false,

// oneshots
updateOneshots: {} as Oneshot | Oneshot[],
updateOneshotsDialog: false,
updateOneshotsAdditionalRoles: [] as string[],

// series
updateSeries: {} as SeriesDto | SeriesDto[],
Expand Down Expand Up @@ -145,6 +147,9 @@ export default new Vuex.Store({
setUpdateBulkBooks(state, books) {
state.updateBulkBooks = books
},
setUpdateBooksAdditionalRoles(state, roles) {
state.updateBooksAdditionalRoles = roles
},
setUpdateBulkBooksDialog(state, dialog) {
state.updateBulkBooksDialog = dialog
},
Expand All @@ -155,6 +160,9 @@ export default new Vuex.Store({
setUpdateOneshotsDialog(state, dialog) {
state.updateOneshotsDialog = dialog
},
setUpdateOneshotsAdditionalRoles(state, roles) {
state.updateOneshotsAdditionalRoles = roles
},
// Series
setUpdateSeries(state, series) {
state.updateSeries = series
Expand Down Expand Up @@ -246,8 +254,9 @@ export default new Vuex.Store({
commit('setDeleteLibraryDialog', value)
},
// books
dialogUpdateBooks({commit}, books) {
dialogUpdateBooks({commit}, {books, roles}) {
commit('setUpdateBooks', books)
commit('setUpdateBooksAdditionalRoles', roles || [])
commit('setUpdateBooksDialog', true)
},
dialogUpdateBooksDisplay({commit}, value) {
Expand All @@ -269,8 +278,9 @@ export default new Vuex.Store({
commit('setUpdateBulkBooksDialog', value)
},
// oneshots
dialogUpdateOneshots({commit}, oneshots) {
dialogUpdateOneshots({commit}, {oneshots, roles}) {
commit('setUpdateOneshots', oneshots)
commit('setUpdateOneshotsAdditionalRoles', roles || [])
commit('setUpdateOneshotsDialog', true)
},
dialogUpdateOneshotsDisplay({commit}, value) {
Expand Down
4 changes: 3 additions & 1 deletion komga-webui/src/views/BrowseBook.vue
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@
import BookActionsMenu from '@/components/menus/BookActionsMenu.vue'
import ItemCard from '@/components/ItemCard.vue'
import ToolbarSticky from '@/components/bars/ToolbarSticky.vue'
import {getCustomRoles} from '@/functions/author-roles'
import {groupAuthorsByRole} from '@/functions/authors'
import {getBookFormatFromMedia, getBookReadRouteFromMedia} from '@/functions/book-format'
import {getPagesLeft, getReadProgress, getReadProgressPercentage} from '@/functions/book-progress'
Expand Down Expand Up @@ -648,7 +649,8 @@ export default Vue.extend({
this.$komgaBooks.refreshMetadata(this.book)
},
editBook() {
this.$store.dispatch('dialogUpdateBooks', this.book)
const customRole = getCustomRoles(this.siblings)
this.$store.dispatch('dialogUpdateBooks', {books: this.book, roles: customRole})
},
},
})
Expand Down
6 changes: 4 additions & 2 deletions komga-webui/src/views/BrowseCollection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ import MultiSelectBar from '@/components/bars/MultiSelectBar.vue'
import {LIBRARIES_ALL} from '@/types/library'
import {ReadStatus} from '@/types/enum-books'
import {SeriesStatus, SeriesStatusKeyValue} from '@/types/enum-series'
import {getCustomRoles} from '@/functions/author-roles'
import {mergeFilterParams, toNameValue} from '@/functions/filter'
import FilterDrawer from '@/components/FilterDrawer.vue'
import FilterPanels from '@/components/FilterPanels.vue'
Expand Down Expand Up @@ -493,15 +494,16 @@ export default Vue.extend({
async editSingleSeries(series: SeriesDto) {
if (series.oneshot) {
const book = (await this.$komgaSeries.getBooks(series.id)).content[0]
this.$store.dispatch('dialogUpdateOneshots', {series: series, book: book})
this.$store.dispatch('dialogUpdateOneshots', {oneshots: {series: series, book: book}})
} else
this.$store.dispatch('dialogUpdateSeries', series)
},
async editMultipleSeries() {
if (this.selectedSeries.every(s => s.oneshot)) {
const books = await Promise.all(this.selectedSeries.map(s => this.$komgaSeries.getBooks(s.id)))
const oneshots = this.selectedSeries.map((s, index) => ({series: s, book: books[index].content[0]} as Oneshot))
this.$store.dispatch('dialogUpdateOneshots', oneshots)
const customRole = getCustomRoles(oneshots.map(o => o.book))
this.$store.dispatch('dialogUpdateOneshots', {oneshots, roles: customRole})
} else
this.$store.dispatch('dialogUpdateSeries', this.selectedSeries)
},
Expand Down
8 changes: 5 additions & 3 deletions komga-webui/src/views/BrowseLibraries.vue
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ import ItemBrowser from '@/components/ItemBrowser.vue'
import LibraryNavigation from '@/components/LibraryNavigation.vue'
import LibraryActionsMenu from '@/components/menus/LibraryActionsMenu.vue'
import PageSizeSelect from '@/components/PageSizeSelect.vue'
import {parseQuerySort} from '@/functions/query-params'
import {getCustomRoles} from '@/functions/author-roles'
import {parseBooleanFilter, parseQuerySort} from '@/functions/query-params'
import {ReadStatus} from '@/types/enum-books'
import {SeriesStatus} from '@/types/enum-series'
import {
Expand Down Expand Up @@ -725,15 +726,16 @@ export default Vue.extend({
async editSingleSeries(series: SeriesDto) {
if (series.oneshot) {
const book = (await this.$komgaSeries.getBooks(series.id)).content[0]
this.$store.dispatch('dialogUpdateOneshots', {series: series, book: book})
this.$store.dispatch('dialogUpdateOneshots', {oneshots: {series: series, book: book}})
} else
this.$store.dispatch('dialogUpdateSeries', series)
},
async editMultipleSeries() {
if (this.selectedOneshots) {
const books = await Promise.all(this.selectedSeries.map(s => this.$komgaSeries.getBooks(s.id)))
const oneshots = this.selectedSeries.map((s, index) => ({series: s, book: books[index].content[0]} as Oneshot))
this.$store.dispatch('dialogUpdateOneshots', oneshots)
const customRole = getCustomRoles(oneshots.map(o => o.book))
this.$store.dispatch('dialogUpdateOneshots', {oneshots, roles: customRole})
} else
this.$store.dispatch('dialogUpdateSeries', this.selectedSeries)
},
Expand Down
3 changes: 2 additions & 1 deletion komga-webui/src/views/BrowseOneshot.vue
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,8 @@ export default Vue.extend({
this.$komgaBooks.refreshMetadata(this.book)
},
editBook() {
this.$store.dispatch('dialogUpdateOneshots', {series: this.series, book: this.book} as Oneshot)
const oneshots = {series: this.series, book: this.book} as Oneshot
this.$store.dispatch('dialogUpdateOneshots', {oneshots})
},
},
})
Expand Down
9 changes: 5 additions & 4 deletions komga-webui/src/views/BrowseReadList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ import FilterList from '@/components/FilterList.vue'
import {ReadStatus} from '@/types/enum-books'
import {authorRoles} from '@/types/author-roles'
import {LibraryDto} from '@/types/komga-libraries'
import {isAllSelectedSameSeries, getCustomRolesForSeries} from '@/functions/author-roles'
import {mergeFilterParams, toNameValue} from '@/functions/filter'
import {Location} from 'vue-router'
import {readListFileUrl} from '@/functions/urls'
Expand Down Expand Up @@ -481,17 +482,17 @@ export default Vue.extend({
async editSingleBook(book: BookDto) {
if (book.oneshot) {
const series = (await this.$komgaSeries.getOneSeries(book.seriesId))
this.$store.dispatch('dialogUpdateOneshots', {series: series, book: book})
this.$store.dispatch('dialogUpdateOneshots', {oneshots: {series: series, book: book}})
} else
this.$store.dispatch('dialogUpdateBooks', book)
this.$store.dispatch('dialogUpdateBooks', {books: book})
},
async editMultipleBooks() {
if (this.selectedBooks.every(b => b.oneshot)) {
const series = await Promise.all(this.selectedBooks.map(b => this.$komgaSeries.getOneSeries(b.seriesId)))
const oneshots = this.selectedBooks.map((b, index) => ({series: series[index], book: b} as Oneshot))
this.$store.dispatch('dialogUpdateOneshots', oneshots)
this.$store.dispatch('dialogUpdateOneshots', {oneshots})
} else
this.$store.dispatch('dialogUpdateBooks', this.selectedBooks)
this.$store.dispatch('dialogUpdateBooks', {books: this.selectedBooks})
},
bulkEditMultipleBooks() {
this.$store.dispatch('dialogUpdateBulkBooks', this.selectedBooks)
Expand Down
7 changes: 5 additions & 2 deletions komga-webui/src/views/BrowseSeries.vue
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,7 @@ import ItemBrowser from '@/components/ItemBrowser.vue'
import ItemCard from '@/components/ItemCard.vue'
import SeriesActionsMenu from '@/components/menus/SeriesActionsMenu.vue'
import PageSizeSelect from '@/components/PageSizeSelect.vue'
import {getCustomRoles} from '@/functions/author-roles'
import {parseQuerySort} from '@/functions/query-params'
import {seriesFileUrl, seriesThumbnailUrl} from '@/functions/urls'
import {ReadStatus} from '@/types/enum-books'
Expand Down Expand Up @@ -928,10 +929,12 @@ export default Vue.extend({
this.$store.dispatch('dialogUpdateSeries', this.series)
},
editSingleBook(book: BookDto) {
this.$store.dispatch('dialogUpdateBooks', book)
const customRoles = getCustomRoles(this.books)
this.$store.dispatch('dialogUpdateBooks', {books: book, roles: customRoles})
},
editMultipleBooks() {
this.$store.dispatch('dialogUpdateBooks', this.selectedBooks)
const customRoles = getCustomRoles(this.books)
this.$store.dispatch('dialogUpdateBooks', {books: this.selectedBooks, roles: customRoles})
},
bulkEditMultipleBooks() {
this.$store.dispatch('dialogUpdateBulkBooks', this.$_.sortBy(this.selectedBooks, ['metadata.numberSort']))
Expand Down
38 changes: 29 additions & 9 deletions komga-webui/src/views/DashboardView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,7 @@ import {BookSseDto, ReadProgressSeriesSseDto, ReadProgressSseDto, SeriesSseDto}
import {LibraryDto} from '@/types/komga-libraries'
import {PageLoader} from '@/types/pageLoader'
import {ItemContext} from '@/types/items'
import {getCustomRoles, getCustomRolesForSeries, isAllSelectedSameSeries} from '@/functions/author-roles'

export default Vue.extend({
name: 'DashboardView',
Expand Down Expand Up @@ -430,16 +431,19 @@ export default Vue.extend({
async singleEditSeries(series: SeriesDto) {
if (series.oneshot) {
let book = (await this.$komgaSeries.getBooks(series.id)).content[0]
this.$store.dispatch('dialogUpdateOneshots', {series: series, book: book})
} else
this.$store.dispatch('dialogUpdateOneshots', {oneshots: {series: series, book: book}})
} else {
this.$store.dispatch('dialogUpdateSeries', series)
}
},
async singleEditBook(book: BookDto) {
if (book.oneshot) {
const series = (await this.$komgaSeries.getOneSeries(book.seriesId))
this.$store.dispatch('dialogUpdateOneshots', {series: series, book: book})
} else
this.$store.dispatch('dialogUpdateBooks', book)
this.$store.dispatch('dialogUpdateOneshots', {oneshots: {series: series, book: book}})
} else {
const customRoles = getCustomRolesForSeries(this.getAllBooksFromLoader(), book.seriesId)
this.$store.dispatch('dialogUpdateBooks', {books: book, roles: customRoles})
}
},
async markSelectedSeriesRead() {
await Promise.all(this.selectedSeries.map(s =>
Expand All @@ -465,17 +469,24 @@ export default Vue.extend({
if (this.selectedSeries.every(s => s.oneshot)) {
const books = await Promise.all(this.selectedSeries.map(s => this.$komgaSeries.getBooks(s.id)))
const oneshots = this.selectedSeries.map((s, index) => ({series: s, book: books[index].content[0]} as Oneshot))
this.$store.dispatch('dialogUpdateOneshots', oneshots)
const customRole = getCustomRoles(oneshots.map(o => o.book))
this.$store.dispatch('dialogUpdateOneshots', {oneshots, roles: customRole})
} else
this.$store.dispatch('dialogUpdateSeries', this.selectedSeries)
},
async editMultipleBooks() {
if (this.selectedBooks.every(b => b.oneshot)) {
const series = await Promise.all(this.selectedBooks.map(b => this.$komgaSeries.getOneSeries(b.seriesId)))
const oneshots = this.selectedBooks.map((b, index) => ({series: series[index], book: b} as Oneshot))
this.$store.dispatch('dialogUpdateOneshots', oneshots)
} else
this.$store.dispatch('dialogUpdateBooks', this.selectedBooks)
const customRole = getCustomRoles(oneshots.map(o => o.book))
this.$store.dispatch('dialogUpdateOneshots', {oneshots, roles: customRole})
} else {
let customRoles = [] as string[]
if (isAllSelectedSameSeries(this.selectedBooks)) {
customRoles = getCustomRolesForSeries(this.getAllBooksFromLoader(), this.selectedBooks[0].seriesId)
}
this.$store.dispatch('dialogUpdateBooks', {books: this.selectedBooks, roles: customRoles})
}
},
deleteSeries() {
this.$store.dispatch('dialogDeleteSeries', this.selectedSeries)
Expand Down Expand Up @@ -509,6 +520,15 @@ export default Vue.extend({
return undefined
}
},
getAllBooksFromLoader(): BookDto[] {
return [
...(this.loaderInProgressBooks?.items || []),
...(this.loaderOnDeckBooks?.items || []),
...(this.loaderRecentlyReleasedBooks?.items || []),
...(this.loaderLatestBooks?.items || []),
...(this.loaderRecentlyReadBooks?.items || []),
]
},
},
})
</script>
Expand Down
Loading
Loading