mirror of
https://github.com/gotson/komga.git
synced 2025-12-20 07:23:34 +01:00
parent
ae9a19af62
commit
4bab0c61c7
11 changed files with 475 additions and 1 deletions
|
|
@ -60,6 +60,11 @@
|
|||
:books="updateBooks"
|
||||
/>
|
||||
|
||||
<bulk-edit-books-dialog
|
||||
v-model="updateBulkBooksDialog"
|
||||
:books="updateBulkBooks"
|
||||
/>
|
||||
|
||||
<edit-series-dialog
|
||||
v-model="updateSeriesDialog"
|
||||
:series="updateSeries"
|
||||
|
|
@ -82,10 +87,12 @@ import {SeriesDto} from '@/types/komga-series'
|
|||
import {ERROR} from '@/types/events'
|
||||
import ConfirmationDialog from '@/components/dialogs/ConfirmationDialog.vue'
|
||||
import {LibraryDto} from '@/types/komga-libraries'
|
||||
import BulkEditBooksDialog from '@/components/dialogs/BulkEditBooksDialog.vue'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'Dialogs',
|
||||
components: {
|
||||
BulkEditBooksDialog,
|
||||
ConfirmationDialog,
|
||||
CollectionAddToDialog,
|
||||
CollectionEditDialog,
|
||||
|
|
@ -205,6 +212,18 @@ export default Vue.extend({
|
|||
updateBooks(): BookDto | BookDto[] {
|
||||
return this.$store.state.updateBooks
|
||||
},
|
||||
// books bulk
|
||||
updateBulkBooksDialog: {
|
||||
get(): boolean {
|
||||
return this.$store.state.updateBulkBooksDialog
|
||||
},
|
||||
set(val) {
|
||||
this.$store.dispatch('dialogUpdateBulkBooksDisplay', val)
|
||||
},
|
||||
},
|
||||
updateBulkBooks(): BookDto[] {
|
||||
return this.$store.state.updateBulkBooks
|
||||
},
|
||||
// series
|
||||
updateSeriesDialog: {
|
||||
get(): boolean {
|
||||
|
|
|
|||
|
|
@ -61,6 +61,15 @@
|
|||
</v-tooltip>
|
||||
</v-btn>
|
||||
|
||||
<v-btn icon @click="bulkEdit" v-if="isAdmin && kind === 'books'">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-icon v-on="on">mdi-table-edit</v-icon>
|
||||
</template>
|
||||
<span>{{ $t('menu.bulk_edit_metadata') }}</span>
|
||||
</v-tooltip>
|
||||
</v-btn>
|
||||
|
||||
<v-btn icon @click="edit" v-if="isAdmin && (kind === 'books' || kind === 'series')">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
|
|
@ -137,6 +146,9 @@ export default Vue.extend({
|
|||
edit () {
|
||||
this.$emit('edit')
|
||||
},
|
||||
bulkEdit () {
|
||||
this.$emit('bulk-edit')
|
||||
},
|
||||
doDelete () {
|
||||
this.$emit('delete')
|
||||
},
|
||||
|
|
|
|||
382
komga-webui/src/components/dialogs/BulkEditBooksDialog.vue
Normal file
382
komga-webui/src/components/dialogs/BulkEditBooksDialog.vue
Normal file
|
|
@ -0,0 +1,382 @@
|
|||
<template>
|
||||
<v-dialog v-model="modal"
|
||||
:fullscreen="$vuetify.breakpoint.xsOnly"
|
||||
scrollable
|
||||
@keydown.esc="dialogCancel"
|
||||
>
|
||||
<v-form ref="form">
|
||||
<v-card>
|
||||
<v-toolbar class="hidden-sm-and-up">
|
||||
<v-btn icon @click="dialogCancel">
|
||||
<v-icon>mdi-close</v-icon>
|
||||
</v-btn>
|
||||
<v-toolbar-title>{{ dialogTitle }}</v-toolbar-title>
|
||||
<v-spacer/>
|
||||
<v-toolbar-items>
|
||||
<v-btn text color="primary" @click="dialogConfirm">{{ $t('dialog.edit_books.button_confirm') }}</v-btn>
|
||||
</v-toolbar-items>
|
||||
</v-toolbar>
|
||||
|
||||
<v-card-title class="hidden-xs-only">
|
||||
<v-icon class="mx-4">mdi-pencil</v-icon>
|
||||
{{ dialogTitle }}
|
||||
</v-card-title>
|
||||
|
||||
<v-card-subtitle>
|
||||
<v-container fluid>
|
||||
|
||||
<v-row>
|
||||
<v-col
|
||||
v-for="(prop, i) in headerRow"
|
||||
:key="i"
|
||||
:cols="prop.cols ? prop.cols : undefined"
|
||||
>
|
||||
<v-btn icon @click="changeAllLock(prop.prop, lockStatus(prop.prop) !== 2)">
|
||||
<v-tooltip bottom>
|
||||
<template v-slot:activator="{ on }">
|
||||
<v-icon v-on="on" :color="lockStatus(prop.prop) === 2 ? 'secondary' : ''">
|
||||
{{ lockStatus(prop.prop) !== 0 ? 'mdi-lock' : 'mdi-lock-open' }}
|
||||
</v-icon>
|
||||
</template>
|
||||
<span>{{ lockStatus(prop.prop) !== 2 ? $t('common.lock_all') : $t('common.unlock_all') }}</span>
|
||||
</v-tooltip>
|
||||
</v-btn>
|
||||
|
||||
<span class="subtitle-1">{{ prop.label }}</span>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card-subtitle>
|
||||
|
||||
<v-card-text>
|
||||
<v-container fluid>
|
||||
|
||||
<div v-for="(book, i) in books"
|
||||
:key="book.id"
|
||||
class="pa-2"
|
||||
>
|
||||
<div class="subtitle-2 mb-2">{{ bookDisplayName(book) }}</div>
|
||||
|
||||
<!-- Title -->
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-text-field v-model="form[book.id].title"
|
||||
dense
|
||||
validate-on-blur
|
||||
:rules="[validateRequired]"
|
||||
@change="form[book.id].titleLock = true"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<v-icon :color="form[book.id].titleLock ? 'secondary' : ''"
|
||||
@click="form[book.id].titleLock = !form[book.id].titleLock"
|
||||
>
|
||||
{{ form[book.id].titleLock ? 'mdi-lock' : 'mdi-lock-open' }}
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
|
||||
<!-- Number -->
|
||||
<v-col cols="2">
|
||||
<v-text-field v-model="form[book.id].number"
|
||||
dense
|
||||
validate-on-blur
|
||||
:rules="[validateRequired]"
|
||||
@change="form[book.id].numberLock = true"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<v-icon :color="form[book.id].numberLock ? 'secondary' : ''"
|
||||
@click="form[book.id].numberLock = !form[book.id].numberLock"
|
||||
>
|
||||
{{ form[book.id].numberLock ? 'mdi-lock' : 'mdi-lock-open' }}
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
|
||||
<!-- Sort Number -->
|
||||
<v-col cols="2">
|
||||
<v-text-field v-model="form[book.id].numberSort"
|
||||
type="number"
|
||||
step="0.1"
|
||||
dense
|
||||
validate-on-blur
|
||||
:rules="[validateRequired]"
|
||||
@change="form[book.id].numberSortLock = true"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<v-icon :color="form[book.id].numberSortLock ? 'secondary' : ''"
|
||||
@click="form[book.id].numberSortLock = !form[book.id].numberSortLock"
|
||||
>
|
||||
{{ form[book.id].numberSortLock ? 'mdi-lock' : 'mdi-lock-open' }}
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
|
||||
<!-- Release Date -->
|
||||
<v-col cols="2">
|
||||
<v-text-field v-model="form[book.id].releaseDate"
|
||||
dense
|
||||
placeholder="YYYY-MM-DD"
|
||||
clearable
|
||||
validate-on-blur
|
||||
:rules="[validateReleaseDate]"
|
||||
@change="form[book.id].releaseDateLock = true"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<v-icon :color="form[book.id].releaseDateLock ? 'secondary' : ''"
|
||||
@click="form[book.id].releaseDateLock = !form[book.id].releaseDateLock"
|
||||
>
|
||||
{{ form[book.id].releaseDateLock ? 'mdi-lock' : 'mdi-lock-open' }}
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
|
||||
<!-- ISBN -->
|
||||
<v-col cols="2">
|
||||
<v-text-field v-model.trim="form[book.id].isbn"
|
||||
dense
|
||||
placeholder="978-2-20-504375-4"
|
||||
clearable
|
||||
validate-on-blur
|
||||
:rules="[validateIsbn]"
|
||||
@change="form[book.id].isbnLock = true"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<v-icon :color="form[book.id].isbnLock ? 'secondary' : ''"
|
||||
@click="form[book.id].isbnLock = !form[book.id].isbnLock"
|
||||
>
|
||||
{{ form[book.id].isbnLock ? 'mdi-lock' : 'mdi-lock-open' }}
|
||||
</v-icon>
|
||||
</template>
|
||||
</v-text-field>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-divider v-if="i !== (books.length - 1)"/>
|
||||
</div>
|
||||
|
||||
</v-container>
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions class="hidden-xs-only">
|
||||
<v-spacer/>
|
||||
<v-btn text @click="dialogCancel">{{ $t('dialog.edit_books.button_cancel') }}</v-btn>
|
||||
<v-btn color="primary" @click="dialogConfirm">{{ $t('dialog.edit_books.button_confirm') }}</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-form>
|
||||
</v-dialog>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import {BookDto} from '@/types/komga-books'
|
||||
import IsbnVerify from '@saekitominaga/isbn-verify'
|
||||
import {isMatch} from 'date-fns'
|
||||
import {ERROR} from '@/types/events'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'BulkEditBooksDialog',
|
||||
data: () => {
|
||||
return {
|
||||
modal: false,
|
||||
form: {
|
||||
'sampleId': {
|
||||
title: '',
|
||||
titleLock: false,
|
||||
number: '',
|
||||
numberLock: false,
|
||||
numberSort: 0,
|
||||
numberSortLock: false,
|
||||
releaseDate: '',
|
||||
releaseDateLock: false,
|
||||
isbn: '',
|
||||
isbnLock: false,
|
||||
},
|
||||
} as any,
|
||||
}
|
||||
},
|
||||
props: {
|
||||
value: Boolean,
|
||||
books: {
|
||||
type: Array as () => BookDto[],
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
value(val) {
|
||||
this.modal = val
|
||||
},
|
||||
modal(val) {
|
||||
!val && this.dialogCancel()
|
||||
},
|
||||
books: {
|
||||
immediate: true,
|
||||
handler(val) {
|
||||
this.dialogReset(val)
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
dialogTitle(): string {
|
||||
return this.$tc('dialog.edit_books.dialog_title_multiple', this.books.length)
|
||||
},
|
||||
headerRow(): object[] {
|
||||
return [
|
||||
{
|
||||
prop: 'title',
|
||||
label: this.$t('dialog.edit_books.field_title'),
|
||||
},
|
||||
{
|
||||
prop: 'number',
|
||||
label: this.$t('dialog.edit_books.field_number'),
|
||||
cols: 2,
|
||||
}, {
|
||||
prop: 'numberSort',
|
||||
label: this.$t('dialog.edit_books.field_number_sort'),
|
||||
cols: 2,
|
||||
}, {
|
||||
prop: 'releaseDate',
|
||||
label: this.$t('dialog.edit_books.field_release_date'),
|
||||
cols: 2,
|
||||
}, {
|
||||
prop: 'isbn',
|
||||
label: this.$t('dialog.edit_books.field_isbn'),
|
||||
cols: 2,
|
||||
}]
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
validateIsbn(isbn: string): string | boolean {
|
||||
return isbn && !new IsbnVerify(isbn).isIsbn13({check_digit: true}) ? this.$t('dialog.edit_books.field_isbn_error').toString() : true
|
||||
},
|
||||
validateRequired(value: string): string | boolean {
|
||||
return !value ? this.$t('common.required').toString() : true
|
||||
},
|
||||
validateReleaseDate(date: string): string | boolean {
|
||||
return date && !isMatch(date, 'yyyy-MM-dd') ? this.$t('dialog.edit_books.field_release_date_error').toString() : true
|
||||
},
|
||||
bookDisplayName(book: BookDto):string {
|
||||
const parts = book.url.split('/')
|
||||
return parts[parts.length - 2] + '/' + parts[parts.length - 1]
|
||||
},
|
||||
lockStatus(prop: string): number {
|
||||
const propLock = `${prop}Lock`
|
||||
let count = 0
|
||||
for (const book of this.books) {
|
||||
if (this.form[book.id][propLock]) count++
|
||||
}
|
||||
if (count === 0) return 0
|
||||
if (count === this.books.length) return 2
|
||||
return 1
|
||||
},
|
||||
changeAllLock(prop: string, lock: boolean) {
|
||||
const propLock = `${prop}Lock`
|
||||
for (const book of this.books) {
|
||||
this.form[book.id][propLock] = lock
|
||||
}
|
||||
},
|
||||
dialogReset(books: BookDto[]) {
|
||||
(this.$refs.form as any)?.resetValidation()
|
||||
this.form = books.reduce((accum, current) => {
|
||||
accum[current.id] = {
|
||||
title: current.metadata.title,
|
||||
titleLock: current.metadata.titleLock,
|
||||
number: current.metadata.number,
|
||||
numberLock: current.metadata.numberLock,
|
||||
numberSort: current.metadata.numberSort,
|
||||
numberSortLock: current.metadata.numberSortLock,
|
||||
releaseDate: current.metadata.releaseDate,
|
||||
releaseDateLock: current.metadata.releaseDateLock,
|
||||
isbn: current.metadata.isbn,
|
||||
isbnLock: current.metadata.isbnLock,
|
||||
}
|
||||
return accum
|
||||
}, {} as any)
|
||||
},
|
||||
dialogCancel() {
|
||||
this.$emit('input', false)
|
||||
this.dialogReset(this.books)
|
||||
},
|
||||
async dialogConfirm() {
|
||||
if (await this.editBooks()) {
|
||||
this.$emit('input', false)
|
||||
}
|
||||
},
|
||||
validateForm(): any {
|
||||
if ((this.$refs.form as any).validate()) {
|
||||
// const metadata = {
|
||||
// authorsLock: this.form.authorsLock,
|
||||
// tagsLock: this.form.tagsLock,
|
||||
// }
|
||||
//
|
||||
// if (this.$v.form?.authors?.$dirty) {
|
||||
// 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})),
|
||||
// ),
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// if (this.$v.form?.tags?.$dirty) {
|
||||
// this.$_.merge(metadata, {tags: this.form.tags})
|
||||
// }
|
||||
//
|
||||
// this.$_.merge(metadata, {
|
||||
// titleLock: this.form.titleLock,
|
||||
// numberLock: this.form.numberLock,
|
||||
// numberSortLock: this.form.numberSortLock,
|
||||
// summaryLock: this.form.summaryLock,
|
||||
// releaseDateLock: this.form.releaseDateLock,
|
||||
// isbnLock: this.form.isbnLock,
|
||||
// })
|
||||
//
|
||||
// if (this.$v.form?.title?.$dirty) {
|
||||
// this.$_.merge(metadata, {title: this.form.title})
|
||||
// }
|
||||
//
|
||||
// if (this.$v.form?.number?.$dirty) {
|
||||
// this.$_.merge(metadata, {number: this.form.number})
|
||||
// }
|
||||
//
|
||||
// if (this.$v.form?.numberSort?.$dirty) {
|
||||
// this.$_.merge(metadata, {numberSort: this.form.numberSort})
|
||||
// }
|
||||
//
|
||||
// if (this.$v.form?.summary?.$dirty) {
|
||||
// this.$_.merge(metadata, {summary: this.form.summary})
|
||||
// }
|
||||
//
|
||||
// if (this.$v.form?.releaseDate?.$dirty) {
|
||||
// this.$_.merge(metadata, {releaseDate: this.form.releaseDate ? this.form.releaseDate : null})
|
||||
// }
|
||||
//
|
||||
// if (this.$v.form?.isbn?.$dirty) {
|
||||
// this.$_.merge(metadata, {isbn: this.form.isbn})
|
||||
// }
|
||||
|
||||
return this.form
|
||||
}
|
||||
return null
|
||||
},
|
||||
async editBooks(): Promise<boolean> {
|
||||
const metadata = this.validateForm()
|
||||
if (metadata) {
|
||||
try {
|
||||
await this.$komgaBooks.updateMetadataBatch(metadata)
|
||||
} catch (e) {
|
||||
this.$eventHub.$emit(ERROR, {message: e.message} as ErrorEvent)
|
||||
}
|
||||
return true
|
||||
} else return false
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="sass" scoped>
|
||||
@import '../../styles/tabbed-dialog'
|
||||
</style>
|
||||
|
|
@ -191,6 +191,7 @@
|
|||
"go_to_series": "Go to series",
|
||||
"locale_name": "English",
|
||||
"locale_rtl": "false",
|
||||
"lock_all": "Lock all",
|
||||
"n_selected": "{count} selected",
|
||||
"nothing_to_show": "Nothing to show",
|
||||
"outdated": "Outdated",
|
||||
|
|
@ -207,6 +208,7 @@
|
|||
"series": "Series",
|
||||
"tags": "Tags",
|
||||
"unavailable": "Unavailable",
|
||||
"unlock_all": "Unlock all",
|
||||
"use_filter_panel_to_change_filter": "Use the filter panel to change the active filter",
|
||||
"year": "year"
|
||||
},
|
||||
|
|
@ -581,6 +583,7 @@
|
|||
"add_to_collection": "Add to collection",
|
||||
"add_to_readlist": "Add to read list",
|
||||
"analyze": "Analyze",
|
||||
"bulk_edit_metadata": "Bulk edit metadata",
|
||||
"delete": "Delete",
|
||||
"deselect_all": "Deselect all",
|
||||
"download_series": "Download series",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,12 @@
|
|||
import {AxiosInstance} from 'axios'
|
||||
import {BookDto, BookImportBatchDto, BookMetadataUpdateDto, PageDto, ReadProgressUpdateDto} from '@/types/komga-books'
|
||||
import {
|
||||
BookDto,
|
||||
BookImportBatchDto,
|
||||
BookMetadataUpdateBatchDto,
|
||||
BookMetadataUpdateDto,
|
||||
PageDto,
|
||||
ReadProgressUpdateDto,
|
||||
} from '@/types/komga-books'
|
||||
import {formatISO} from 'date-fns'
|
||||
|
||||
const qs = require('qs')
|
||||
|
|
@ -158,6 +165,18 @@ export default class KomgaBooksService {
|
|||
}
|
||||
}
|
||||
|
||||
async updateMetadataBatch(batch: BookMetadataUpdateBatchDto) {
|
||||
try {
|
||||
await this.http.patch(`${API_BOOKS}/metadata`, batch)
|
||||
} catch (e) {
|
||||
let msg = 'An error occurred while trying to update book metadata in batch'
|
||||
if (e.response.data.message) {
|
||||
msg += `: ${e.response.data.message}`
|
||||
}
|
||||
throw new Error(msg)
|
||||
}
|
||||
}
|
||||
|
||||
async updateReadProgress(bookId: string, readProgress: ReadProgressUpdateDto) {
|
||||
try {
|
||||
await this.http.patch(`${API_BOOKS}/${bookId}/read-progress`, readProgress)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,10 @@ export default new Vuex.Store({
|
|||
// books
|
||||
updateBooks: {} as BookDto | BookDto[],
|
||||
updateBooksDialog: false,
|
||||
// books bulk
|
||||
updateBulkBooks: [] as BookDto[],
|
||||
updateBulkBooksDialog: false,
|
||||
|
||||
// series
|
||||
updateSeries: {} as SeriesDto | SeriesDto[],
|
||||
updateSeriesDialog: false,
|
||||
|
|
@ -101,6 +105,13 @@ export default new Vuex.Store({
|
|||
setUpdateBooksDialog(state, dialog) {
|
||||
state.updateBooksDialog = dialog
|
||||
},
|
||||
// Books bulk
|
||||
setUpdateBulkBooks(state, books) {
|
||||
state.updateBulkBooks = books
|
||||
},
|
||||
setUpdateBulkBooksDialog(state, dialog) {
|
||||
state.updateBulkBooksDialog = dialog
|
||||
},
|
||||
// Series
|
||||
setUpdateSeries(state, series) {
|
||||
state.updateSeries = series
|
||||
|
|
@ -184,6 +195,14 @@ export default new Vuex.Store({
|
|||
dialogUpdateBooksDisplay({commit}, value) {
|
||||
commit('setUpdateBooksDialog', value)
|
||||
},
|
||||
// books bulk
|
||||
dialogUpdateBulkBooks({commit}, books) {
|
||||
commit('setUpdateBulkBooks', books)
|
||||
commit('setUpdateBulkBooksDialog', true)
|
||||
},
|
||||
dialogUpdateBulkBooksDisplay({commit}, value) {
|
||||
commit('setUpdateBulkBooksDialog', value)
|
||||
},
|
||||
// series
|
||||
dialogUpdateSeries({commit}, series) {
|
||||
commit('setUpdateSeries', series)
|
||||
|
|
|
|||
|
|
@ -91,6 +91,10 @@ export interface BookMetadataUpdateDto {
|
|||
isbnLock?: boolean
|
||||
}
|
||||
|
||||
export interface BookMetadataUpdateBatchDto {
|
||||
[bookId: string]: BookMetadataUpdateBatchDto
|
||||
}
|
||||
|
||||
export interface AuthorDto {
|
||||
name: string,
|
||||
role: string
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@
|
|||
@mark-unread="markSelectedUnread"
|
||||
@add-to-readlist="addToReadList"
|
||||
@edit="editMultipleBooks"
|
||||
@bulk-edit="bulkEditMultipleBooks"
|
||||
/>
|
||||
|
||||
<!-- Edit elements sticky bar -->
|
||||
|
|
@ -356,6 +357,9 @@ export default Vue.extend({
|
|||
editMultipleBooks() {
|
||||
this.$store.dispatch('dialogUpdateBooks', this.selectedBooks)
|
||||
},
|
||||
bulkEditMultipleBooks() {
|
||||
this.$store.dispatch('dialogUpdateBulkBooks', this.selectedBooks)
|
||||
},
|
||||
async markSelectedRead() {
|
||||
await Promise.all(this.selectedBooks.map(b =>
|
||||
this.$komgaBooks.updateReadProgress(b.id, {completed: true} as ReadProgressUpdateDto),
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
@mark-read="markSelectedRead"
|
||||
@mark-unread="markSelectedUnread"
|
||||
@add-to-readlist="addToReadList"
|
||||
@bulk-edit="bulkEditMultipleBooks"
|
||||
@edit="editMultipleBooks"
|
||||
/>
|
||||
|
||||
|
|
@ -804,6 +805,9 @@ export default Vue.extend({
|
|||
editMultipleBooks() {
|
||||
this.$store.dispatch('dialogUpdateBooks', this.selectedBooks)
|
||||
},
|
||||
bulkEditMultipleBooks() {
|
||||
this.$store.dispatch('dialogUpdateBulkBooks', this.$_.sortBy(this.selectedBooks, ['metadata.numberSort']))
|
||||
},
|
||||
addToReadList() {
|
||||
this.$store.dispatch('dialogAddBooksToReadList', this.selectedBooks)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
@mark-unread="markSelectedBooksUnread"
|
||||
@add-to-readlist="addToReadList"
|
||||
@edit="editMultipleBooks"
|
||||
@bulk-edit="bulkEditMultipleBooks"
|
||||
/>
|
||||
|
||||
<v-container fluid>
|
||||
|
|
@ -375,6 +376,9 @@ export default Vue.extend({
|
|||
editMultipleBooks() {
|
||||
this.$store.dispatch('dialogUpdateBooks', this.selectedBooks)
|
||||
},
|
||||
bulkEditMultipleBooks() {
|
||||
this.$store.dispatch('dialogUpdateBulkBooks', this.selectedBooks)
|
||||
},
|
||||
addToReadList() {
|
||||
this.$store.dispatch('dialogAddBooksToReadList', this.selectedBooks)
|
||||
this.selectedBooks = []
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
@mark-unread="markSelectedBooksUnread"
|
||||
@add-to-readlist="addToReadList"
|
||||
@edit="editMultipleBooks"
|
||||
@bulk-edit="bulkEditMultipleBooks"
|
||||
/>
|
||||
|
||||
<multi-select-bar
|
||||
|
|
@ -303,6 +304,9 @@ export default Vue.extend({
|
|||
editMultipleBooks () {
|
||||
this.$store.dispatch('dialogUpdateBooks', this.selectedBooks)
|
||||
},
|
||||
bulkEditMultipleBooks() {
|
||||
this.$store.dispatch('dialogUpdateBulkBooks', this.selectedBooks)
|
||||
},
|
||||
deleteCollections () {
|
||||
this.$store.dispatch('dialogDeleteCollection', this.selectedCollections)
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue