diff --git a/komga-webui/src/locales/en.json b/komga-webui/src/locales/en.json
index 673a64a7c..a8f1dc094 100644
--- a/komga-webui/src/locales/en.json
+++ b/komga-webui/src/locales/en.json
@@ -283,6 +283,7 @@
"comicrack_preambule_html": "You can import existing ComicRack Reading Lists in .cbl format.
Komga will try to match the provided series and book number with series and books in your libraries.",
"dialog_confirmation": {
"body": "{unmatched} / {total} books are unmatched",
+ "body2": "{duplicates} / {total} books are duplicated",
"create": "Create anyway",
"title": "Some books are not matched"
},
diff --git a/komga-webui/src/views/ImportReadList.vue b/komga-webui/src/views/ImportReadList.vue
index bf868613e..d92bd6b57 100644
--- a/komga-webui/src/views/ImportReadList.vue
+++ b/komga-webui/src/views/ImportReadList.vue
@@ -105,7 +105,7 @@
@@ -128,11 +128,6 @@ import {ERROR, NOTIFICATION, NotificationEvent} from '@/types/events'
import {helpers, required} from 'vuelidate/lib/validators'
import ConfirmationDialog from '@/components/dialogs/ConfirmationDialog.vue'
-function duplicateBooks(this: any, value: any[]) {
- const ids = value.filter(Boolean).map(b => b.bookId)
- return ids.length === [...new Set(ids)].length
-}
-
function validName(this: any, value: string) {
return !helpers.req(value) || !this.readLists.some((e: ReadListDto) => e.name.toLowerCase() === value.toLowerCase())
}
@@ -163,15 +158,37 @@ export default Vue.extend({
name: {required, validName},
ordered: {},
summary: {},
- books: {duplicateBooks},
+ books: {},
},
},
computed: {
+ totalCount(): number {
+ return this.result!!.requests.length
+ },
+ matchedCount(): number {
+ return this.form.books.filter(Boolean).length
+ },
+ unmatchedCount(): number {
+ return this.totalCount - this.matchedCount
+ },
+ duplicatesCount(): number {
+ return this.form.books.filter(this.isDuplicateBook).length
+ },
missingDialogText(): string {
- const total = this.result!!.requests.length
- const matched = this.form.books.filter(Boolean).length
- const unmatched = total - matched
- return this.$t('data_import.dialog_confirmation.body', {unmatched: unmatched, total: total}).toString()
+ let s = ''
+ if (this.unmatchedCount > 0)
+ s += this.$t('data_import.dialog_confirmation.body', {
+ unmatched: this.unmatchedCount,
+ total: this.totalCount,
+ }).toString()
+ if (this.duplicatesCount > 0) {
+ if (s !== '') s += '
'
+ s += this.$t('data_import.dialog_confirmation.body2', {
+ duplicates: this.duplicatesCount,
+ total: this.totalCount,
+ }).toString()
+ }
+ return s
},
importRules(): any {
return [
@@ -193,6 +210,7 @@ export default Vue.extend({
},
methods: {
isDuplicateBook(book?: ReadListRequestBookMatchBookDto): boolean {
+ if (book == undefined) return false
return this.form.books.filter((b) => b?.bookId === book?.bookId).length > 1
},
isErrorBook(series?: ReadListRequestBookMatchSeriesDto, book?: ReadListRequestBookMatchBookDto): string {
@@ -234,14 +252,14 @@ export default Vue.extend({
if (this.$v.$invalid) return undefined
return {
name: this.form.name,
- bookIds: this.form.books.map(b => b?.bookId).filter(Boolean) as string[],
+ bookIds: [...new Set(this.form.books.map(b => b?.bookId).filter(Boolean))] as string[],
ordered: this.form.ordered,
summary: this.form.summary,
}
},
async create(bypassMissing: boolean) {
if (!this.creationFinished) {
- if (!bypassMissing && this.form.books.filter(Boolean).length !== this.result?.requests.length) {
+ if (!bypassMissing && (this.duplicatesCount > 0 || this.unmatchedCount > 0)) {
this.modalConfirmation = true
return
}