komga/komga-webui/src/views/BookImport.vue
2021-05-20 18:09:26 +08:00

205 lines
6 KiB
Vue

<template>
<v-container fluid class="pa-6">
<v-alert type="warning" text>{{ $t('book_import.warning_early_feature') }}</v-alert>
<v-alert type="info" text class="body-2">
<div>{{ $t('book_import.info_part1') }}</div>
<div class="mt-2">{{ $t('book_import.info_part2') }}</div>
</v-alert>
<v-row align="center">
<v-col>
<v-text-field
v-model="importPath"
clearable
:label="$t('book_import.field_import_path')"
/>
</v-col>
<v-col cols="auto">
<file-browser-dialog
v-model="modalFileBrowser"
:path.sync="importPath"
/>
<v-btn @click="modalFileBrowser = true">{{ $t('book_import.button_browse') }}</v-btn>
</v-col>
<v-col cols="auto">
<v-btn
color="primary"
:disabled="!importPath"
@click="scanBooks"
>{{ $t('book_import.button_scan') }}
</v-btn>
</v-col>
</v-row>
<template v-if="transientBooks.length > 0">
<v-divider/>
<v-simple-table>
<thead class="font-weight-medium">
<tr>
<td>
<v-checkbox v-model="globalSelect" :indeterminate="globalSelect === 1"></v-checkbox>
</td>
<td>{{ $t('book_import.table.file_name') }}</td>
<td></td>
<td>{{ $t('book_import.table.series') }}</td>
<td>{{ $t('book_import.table.number') }}</td>
<td></td>
<td></td>
<td></td>
<td>{{ $t('book_import.table.destination_name') }}</td>
<td>
<v-icon>mdi-alert-circle-outline</v-icon>
</td>
</tr>
</thead>
<tbody
v-for="(book, i) in transientBooks"
:key="i"
>
<file-import-row :book="book" :series="selected.includes(i) ? selectedSeries : undefined"
:payload.sync="payloads[i]">
<v-checkbox v-model="selected" :value="i"/>
</file-import-row>
</tbody>
</v-simple-table>
<v-row align="center">
<v-col cols="3">
<v-select v-model="copyMode" :items="copyModes"></v-select>
</v-col>
<v-col cols="auto">
<v-btn @click="modalSeriesPicker = true" :disabled="globalSelect === 0">
{{ $t('book_import.button_select_series') }}
</v-btn>
<series-picker-dialog v-model="modalSeriesPicker" :series.sync="selectedSeries"></series-picker-dialog>
</v-col>
<v-spacer/>
<v-col cols="auto">
<v-btn :color="importFinished ? 'success': 'primary'"
:disabled="payloadBatch.books.length === 0"
@click="performImport"
>
<v-icon left v-if="importFinished">mdi-check</v-icon>
{{ $t('book_import.button_import') }}
</v-btn>
</v-col>
</v-row>
</template>
<v-snackbar
v-model="snackbar"
bottom
color="error"
>
{{ snackText }}
<v-btn
text
@click="snackbar = false"
>{{ $t('common.close') }}
</v-btn>
</v-snackbar>
</v-container>
</template>
<script lang="ts">
import Vue from 'vue'
import FileBrowserDialog from "@/components/dialogs/FileBrowserDialog.vue";
import FileImportRow from "@/components/FileImportRow.vue";
import {TransientBookDto} from "@/types/komga-transientbooks";
import SeriesPickerDialog from "@/components/dialogs/SeriesPickerDialog.vue";
import {SeriesDto} from "@/types/komga-series";
import {BookImportBatchDto, BookImportDto} from "@/types/komga-books";
import {CopyMode} from "@/types/enum-books";
import {convertErrorCodes} from "@/functions/error-codes";
export default Vue.extend({
name: 'BookImport',
components: {FileBrowserDialog, FileImportRow, SeriesPickerDialog},
data: () => ({
modalFileBrowser: false,
modalSeriesPicker: false,
selected: [] as number[],
selectedSeries: undefined as SeriesDto | undefined,
payloads: [] as BookImportDto[],
transientBooks: [] as TransientBookDto[],
copyMode: CopyMode.HARDLINK,
importFinished: false,
snackbar: false,
snackText: '',
}),
computed: {
globalSelect: {
get: function (): number {
if (this.selected.length === 0) return 0
if (this.selected.length === this.transientBooks.length) return 2
return 1
},
set: function (val: boolean): void {
if (val) this.selected = this.$_.range(this.transientBooks.length)
else this.selected = []
},
},
importPath: {
get: function (): string {
return this.$store.state.persistedState.importPath
},
set: function (val: string): void {
this.$store.commit('setImportPath', val)
},
},
copyModes(): object[] {
return [
{text: this.$t('enums.copy_mode.HARDLINK').toString(), value: CopyMode.HARDLINK},
{text: this.$t('enums.copy_mode.MOVE').toString(), value: CopyMode.MOVE},
]
},
payloadBatch(): BookImportBatchDto {
return {
books: this.selected.map(x => this.payloads[x]).filter(Boolean),
copyMode: this.copyMode,
}
},
},
watch: {
selectedSeries(val) {
if (val) setTimeout(() => {
this.selectedSeries = undefined
}, 100)
},
},
methods: {
async scanBooks() {
this.transientBooks = []
try {
this.transientBooks = await this.$komgaTransientBooks.scanForTransientBooks(this.importPath)
} catch (e) {
this.showSnack(convertErrorCodes(e.message))
}
this.selected = this.$_.range(this.transientBooks.length)
this.payloads = this.payloads.splice(this.transientBooks.length, this.payloads.length)
this.importFinished = false
},
performImport() {
if (!this.importFinished) {
this.$komgaBooks.importBooks(this.payloadBatch)
this.importFinished = true
}
},
showSnack(message: string) {
this.snackText = message
this.snackbar = true
},
},
})
</script>
<style scoped>
</style>