mirror of
https://github.com/gotson/komga.git
synced 2026-05-09 05:10:19 +02:00
295 lines
9 KiB
Vue
295 lines
9 KiB
Vue
<template>
|
|
<tr v-if="book">
|
|
<td>
|
|
<slot></slot>
|
|
</td>
|
|
|
|
<td>{{ book.name }}</td>
|
|
|
|
<!-- Status icon -->
|
|
<td>
|
|
<template v-if="bookAnalyzed">
|
|
<v-tooltip bottom :disabled="!status.message">
|
|
<template v-slot:activator="{ on }">
|
|
<v-icon :color="status.color" v-on="on">{{ status.icon }}</v-icon>
|
|
</template>
|
|
{{ convertErrorCodes(status.message) }}
|
|
</v-tooltip>
|
|
</template>
|
|
<v-progress-circular
|
|
v-else
|
|
indeterminate
|
|
color="primary"
|
|
:size="20"
|
|
:width="2"
|
|
/>
|
|
</td>
|
|
|
|
<!-- Series picker -->
|
|
<td @click="modalSeriesPicker = true" style="cursor: pointer">
|
|
<template v-if="selectedSeries">{{ selectedSeries.title }}</template>
|
|
<template v-else>
|
|
<div style="height: 2em" class="missing"></div>
|
|
</template>
|
|
<series-picker-dialog v-model="modalSeriesPicker" @update:series="pickedSeries" :include-oneshots="true"/>
|
|
</td>
|
|
|
|
<!-- Book number chooser -->
|
|
<td>
|
|
<v-text-field v-if="!selectedSeries?.oneshot"
|
|
v-model.number="bookNumber"
|
|
type="number"
|
|
step="0.1"
|
|
dense
|
|
:disabled="!selectedSeries"
|
|
/>
|
|
<span v-else>{{ $t('common.oneshot') }}</span>
|
|
</td>
|
|
|
|
<!-- Book details -->
|
|
<td class="px-1">
|
|
<v-btn icon elevation="1" :disabled="!bookAnalyzed" @click="modalBookDetails = true">
|
|
<v-icon v-if="bookToUpgrade">mdi-file-compare</v-icon>
|
|
<v-icon v-else>mdi-book-information-variant</v-icon>
|
|
</v-btn>
|
|
<transient-book-details-dialog
|
|
v-model="modalBookDetails"
|
|
:left-book="bookAnalyzed"
|
|
:right-book="bookToUpgrade"
|
|
:right-pages="bookToUpgradePages"
|
|
/>
|
|
</td>
|
|
|
|
<!-- Book viewer -->
|
|
<td class="px-1">
|
|
<v-btn icon
|
|
elevation="1"
|
|
@click="modalViewer = true"
|
|
:disabled="!bookAnalyzed || bookAnalyzed.status !== MediaStatus.READY"
|
|
>
|
|
<v-icon v-if="bookToUpgrade">mdi-compare</v-icon>
|
|
<v-icon v-else>mdi-image</v-icon>
|
|
</v-btn>
|
|
<transient-book-viewer-dialog
|
|
v-model="modalViewer"
|
|
:left-pages="leftPagesWithUrl"
|
|
:right-pages="rightPagesWithUrl"
|
|
/>
|
|
</td>
|
|
|
|
<!-- Destination name chooser -->
|
|
<td class="px-1">
|
|
<v-btn icon
|
|
elevation="1"
|
|
@click="modalNameChooser = true"
|
|
:disabled="!bookAnalyzed || bookAnalyzed.status !== MediaStatus.READY"
|
|
>
|
|
<v-icon>mdi-format-color-text</v-icon>
|
|
</v-btn>
|
|
<file-name-chooser-dialog
|
|
v-model="modalNameChooser"
|
|
:books="seriesBooks"
|
|
:name.sync="destinationName"
|
|
:existing="book.name"
|
|
/>
|
|
</td>
|
|
|
|
<td>
|
|
{{ destinationName }}
|
|
</td>
|
|
|
|
<td>
|
|
<template v-if="error">
|
|
<v-tooltip bottom>
|
|
<template v-slot:activator="{ on }">
|
|
<v-icon color="error" v-on="on">mdi-alert-circle</v-icon>
|
|
</template>
|
|
{{ error }}
|
|
</v-tooltip>
|
|
</template>
|
|
<template v-if="!error && bookToUpgrade">
|
|
<v-tooltip bottom>
|
|
<template v-slot:activator="{ on }">
|
|
<v-icon color="warning" v-on="on">mdi-comment-alert</v-icon>
|
|
</template>
|
|
{{ $t('book_import.row.warning_upgrade') }}
|
|
</v-tooltip>
|
|
</template>
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import Vue, {PropType} from 'vue'
|
|
import {MediaStatus} from '@/types/enum-books'
|
|
import {SeriesDto} from '@/types/komga-series'
|
|
import {TransientBookDto} from '@/types/komga-transientbooks'
|
|
import {BookDto, BookImportDto, PageDto, PageDtoWithUrl} from '@/types/komga-books'
|
|
import SeriesPickerDialog from '@/components/dialogs/SeriesPickerDialog.vue'
|
|
import TransientBookDetailsDialog from '@/components/dialogs/TransientBookDetailsDialog.vue'
|
|
import TransientBookViewerDialog from '@/components/dialogs/TransientBookViewerDialog.vue'
|
|
import {bookPageUrl, transientBookPageUrl} from '@/functions/urls'
|
|
import {convertErrorCodes} from '@/functions/error-codes'
|
|
import FileNameChooserDialog from '@/components/dialogs/FileNameChooserDialog.vue'
|
|
import {SeriesSelected} from '@/types/series-slim'
|
|
import {BookSearch, SearchConditionSeriesId, SearchOperatorIs} from '@/types/komga-search'
|
|
|
|
export default Vue.extend({
|
|
name: 'FileImportRow',
|
|
components: {SeriesPickerDialog, TransientBookDetailsDialog, TransientBookViewerDialog, FileNameChooserDialog},
|
|
props: {
|
|
book: {
|
|
type: Object as PropType<TransientBookDto>,
|
|
required: true,
|
|
},
|
|
series: {
|
|
type: Object as PropType<SeriesDto>,
|
|
required: false,
|
|
},
|
|
payload: {
|
|
type: Object,
|
|
required: false,
|
|
},
|
|
},
|
|
watch: {
|
|
book: {
|
|
handler(val) {
|
|
this.analyze(val)
|
|
this.destinationName = val.name
|
|
},
|
|
immediate: true,
|
|
},
|
|
selectedSeries: {
|
|
handler(val) {
|
|
this.getSeriesBooks(val)
|
|
},
|
|
immediate: true,
|
|
},
|
|
series: {
|
|
handler(val) {
|
|
if (val) this.selectedSeries = {
|
|
seriesId: val.id,
|
|
title: val.metadata.title,
|
|
oneshot: val.oneshot,
|
|
}
|
|
},
|
|
immediate: true,
|
|
},
|
|
bookNumber: {
|
|
handler(val) {
|
|
this.checkForUpgrade(val)
|
|
},
|
|
immediate: true,
|
|
},
|
|
importPayload: {
|
|
handler(val) {
|
|
this.$emit('update:payload', val)
|
|
},
|
|
immediate: true,
|
|
},
|
|
},
|
|
data: () => ({
|
|
MediaStatus,
|
|
convertErrorCodes,
|
|
innerSelect: false,
|
|
bookAnalyzed: undefined as unknown as TransientBookDto,
|
|
selectedSeries: undefined as SeriesSelected | undefined,
|
|
seriesBooks: [] as BookDto[],
|
|
bookToUpgrade: undefined as BookDto | undefined,
|
|
bookToUpgradePages: [] as PageDto[],
|
|
modalSeriesPicker: false,
|
|
modalBookDetails: false,
|
|
modalViewer: false,
|
|
modalNameChooser: false,
|
|
bookNumber: undefined as number | undefined,
|
|
destinationName: '',
|
|
}),
|
|
computed: {
|
|
leftPagesWithUrl(): PageDtoWithUrl[] {
|
|
return this.bookAnalyzed ? this.bookAnalyzed.pages.map(p => ({
|
|
...p,
|
|
url: transientBookPageUrl(this.bookAnalyzed.id, p.number),
|
|
})) : []
|
|
},
|
|
rightPagesWithUrl(): PageDtoWithUrl[] {
|
|
return this.bookToUpgrade ? this.bookToUpgradePages.map(p => ({
|
|
...p,
|
|
url: bookPageUrl(this.bookToUpgrade!!.id, p.number),
|
|
})) : []
|
|
},
|
|
status(): object {
|
|
if (!this.bookAnalyzed) return {}
|
|
switch (this.bookAnalyzed.status) {
|
|
case MediaStatus.READY:
|
|
return {icon: 'mdi-check-circle', color: 'success', message: ''}
|
|
default:
|
|
return {icon: 'mdi-alert-circle', color: 'error', message: this.bookAnalyzed.comment}
|
|
}
|
|
},
|
|
existingFileNames(): string[] {
|
|
return this.seriesBooks.map(x => x.name)
|
|
},
|
|
error(): string {
|
|
if (!this.bookAnalyzed) return this.$t('book_import.row.error_analyze_first').toString()
|
|
if (this.bookAnalyzed.status != MediaStatus.READY) return this.$t('book_import.row.error_only_import_no_errors').toString()
|
|
if (!this.selectedSeries) return this.$t('book_import.row.error_choose_series').toString()
|
|
return ''
|
|
},
|
|
importPayload(): BookImportDto | undefined {
|
|
if (this.error || !this.selectedSeries) return undefined
|
|
return {
|
|
seriesId: this.selectedSeries?.seriesId,
|
|
sourceFile: this.book.url,
|
|
upgradeBookId: this.bookToUpgrade?.id,
|
|
destinationName: this.destinationName,
|
|
}
|
|
},
|
|
},
|
|
methods: {
|
|
async analyze(book: TransientBookDto) {
|
|
this.bookAnalyzed = await this.$komgaTransientBooks.analyze(book.id)
|
|
this.getSeries(this.bookAnalyzed.seriesId)
|
|
this.bookNumber = this.bookAnalyzed.number
|
|
},
|
|
async getSeries(seriesId?: string) {
|
|
if (seriesId) {
|
|
const seriesDto = await this.$komgaSeries.getOneSeries(seriesId)
|
|
this.selectedSeries = {
|
|
seriesId: seriesDto.id,
|
|
title: seriesDto.metadata.title,
|
|
oneshot: seriesDto.oneshot,
|
|
}
|
|
}
|
|
},
|
|
async getSeriesBooks(series: SeriesSelected) {
|
|
if (series) {
|
|
this.seriesBooks = (await this.$komgaBooks.getBooksList({
|
|
condition: new SearchConditionSeriesId(new SearchOperatorIs(series.seriesId)),
|
|
} as BookSearch, {unpaged: true, sort: 'metadata.numberSort'})).content
|
|
if (series.oneshot) {
|
|
this.bookNumber = this.seriesBooks[0].metadata.numberSort
|
|
}
|
|
this.checkForUpgrade(this.bookNumber)
|
|
}
|
|
},
|
|
async checkForUpgrade(number: number | undefined) {
|
|
this.bookToUpgrade = this.seriesBooks.find(b => b.metadata.numberSort === number)
|
|
if (this.bookToUpgrade) this.bookToUpgradePages = await this.$komgaBooks.getBookPages(this.bookToUpgrade.id)
|
|
else this.bookToUpgradePages = []
|
|
},
|
|
pickedSeries(series: SeriesDto) {
|
|
this.selectedSeries = {
|
|
seriesId: series.id,
|
|
title: series.metadata.title,
|
|
oneshot: series.oneshot,
|
|
}
|
|
},
|
|
},
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.missing {
|
|
border: 2px dashed red;
|
|
}
|
|
</style>
|