mirror of
https://github.com/gotson/komga.git
synced 2025-12-21 16:03:03 +01:00
feat(webui): metadata import settings per library
ability to edit libraries move library add dialog to global instance closes #199
This commit is contained in:
parent
6824212514
commit
521cc42858
16 changed files with 434 additions and 195 deletions
|
|
@ -19,6 +19,11 @@
|
|||
@deleted="collectionDeleted"
|
||||
/>
|
||||
|
||||
<library-edit-dialog
|
||||
v-model="editLibraryDialog"
|
||||
:library="editLibrary"
|
||||
/>
|
||||
|
||||
<library-delete-dialog
|
||||
v-model="deleteLibraryDialog"
|
||||
:library="deleteLibrary"
|
||||
|
|
@ -43,7 +48,11 @@
|
|||
<script lang="ts">
|
||||
import CollectionAddToDialog from '@/components/dialogs/CollectionAddToDialog.vue'
|
||||
import CollectionDeleteDialog from '@/components/dialogs/CollectionDeleteDialog.vue'
|
||||
import CollectionEditDialog from '@/components/dialogs/CollectionEditDialog.vue'
|
||||
import EditBooksDialog from '@/components/dialogs/EditBooksDialog.vue'
|
||||
import EditSeriesDialog from '@/components/dialogs/EditSeriesDialog.vue'
|
||||
import LibraryDeleteDialog from '@/components/dialogs/LibraryDeleteDialog.vue'
|
||||
import LibraryEditDialog from '@/components/dialogs/LibraryEditDialog.vue'
|
||||
import {
|
||||
BOOK_CHANGED,
|
||||
bookToEventBookChanged,
|
||||
|
|
@ -57,9 +66,6 @@ import {
|
|||
seriesToEventSeriesChanged,
|
||||
} from '@/types/events'
|
||||
import Vue from 'vue'
|
||||
import EditBooksDialog from '@/components/dialogs/EditBooksDialog.vue'
|
||||
import EditSeriesDialog from '@/components/dialogs/EditSeriesDialog.vue'
|
||||
import CollectionEditDialog from '@/components/dialogs/CollectionEditDialog.vue'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'Dialogs',
|
||||
|
|
@ -67,6 +73,7 @@ export default Vue.extend({
|
|||
CollectionAddToDialog,
|
||||
CollectionEditDialog,
|
||||
CollectionDeleteDialog,
|
||||
LibraryEditDialog,
|
||||
LibraryDeleteDialog,
|
||||
EditBooksDialog,
|
||||
EditSeriesDialog,
|
||||
|
|
@ -105,6 +112,17 @@ export default Vue.extend({
|
|||
deleteCollection (): CollectionDto {
|
||||
return this.$store.state.deleteCollection
|
||||
},
|
||||
editLibraryDialog: {
|
||||
get (): boolean {
|
||||
return this.$store.state.editLibraryDialog
|
||||
},
|
||||
set (val) {
|
||||
this.$store.dispatch('dialogEditLibraryDisplay', val)
|
||||
},
|
||||
},
|
||||
editLibrary (): LibraryDto | undefined {
|
||||
return this.$store.state.editLibrary
|
||||
},
|
||||
deleteLibraryDialog: {
|
||||
get (): boolean {
|
||||
return this.$store.state.deleteLibraryDialog
|
||||
|
|
|
|||
|
|
@ -1,170 +0,0 @@
|
|||
<template>
|
||||
<div>
|
||||
<v-dialog v-model="modalAddLibrary"
|
||||
:fullscreen="this.$vuetify.breakpoint.xsOnly"
|
||||
:hide-overlay="this.$vuetify.breakpoint.xsOnly"
|
||||
max-width="450"
|
||||
>
|
||||
<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">{{ confirmText }}</v-btn>
|
||||
</v-toolbar-items>
|
||||
</v-toolbar>
|
||||
|
||||
<v-card-title class="hidden-xs-only">{{ dialogTitle }}</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
|
||||
<form novalidate>
|
||||
<v-container fluid>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-text-field v-model="form.name"
|
||||
label="Name"
|
||||
:error-messages="getErrors('name')"
|
||||
@input="$v.form.name.$touch()"
|
||||
@blur="$v.form.name.$touch()"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="8">
|
||||
<file-browser-dialog
|
||||
v-model="modalFileBrowser"
|
||||
:path.sync="form.path"
|
||||
confirm-text="Choose"
|
||||
dialog-title="Library's root folder"
|
||||
/>
|
||||
|
||||
<v-text-field v-model="form.path"
|
||||
label="Root folder"
|
||||
:error-messages="getErrors('path')"
|
||||
@input="$v.form.path.$touch()"
|
||||
@blur="$v.form.path.$touch()"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="4">
|
||||
<v-btn @click="modalFileBrowser = true">Browse</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</form>
|
||||
|
||||
</v-card-text>
|
||||
|
||||
<v-card-actions class="hidden-xs-only">
|
||||
<v-spacer/>
|
||||
<v-btn text @click="dialogCancel">Cancel</v-btn>
|
||||
<v-btn text class="primary--text" @click="dialogConfirm">{{ confirmText }}</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<v-snackbar
|
||||
v-model="snackbar"
|
||||
bottom
|
||||
color="error"
|
||||
>
|
||||
{{ snackText }}
|
||||
<v-btn
|
||||
text
|
||||
@click="snackbar = false"
|
||||
>
|
||||
Close
|
||||
</v-btn>
|
||||
</v-snackbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import FileBrowserDialog from '@/components/dialogs/FileBrowserDialog.vue'
|
||||
import Vue from 'vue'
|
||||
import { required } from 'vuelidate/lib/validators'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'LibraryAddDialog',
|
||||
components: { FileBrowserDialog },
|
||||
data: () => {
|
||||
return {
|
||||
modalAddLibrary: true,
|
||||
modalFileBrowser: false,
|
||||
snackbar: false,
|
||||
snackText: '',
|
||||
dialogTitle: 'Add Library',
|
||||
confirmText: 'Add',
|
||||
form: {
|
||||
name: '',
|
||||
path: '',
|
||||
},
|
||||
validationFieldNames: new Map([]),
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
modalAddLibrary (val) {
|
||||
!val && this.dialogCancel()
|
||||
},
|
||||
},
|
||||
validations: {
|
||||
form: {
|
||||
name: { required },
|
||||
path: { required },
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getErrors (fieldName: string) {
|
||||
const errors = []
|
||||
|
||||
const field = this.$v.form!![fieldName] as any
|
||||
if (field && field.$invalid && field.$dirty) {
|
||||
const properName = this.validationFieldNames.has(fieldName)
|
||||
? this.validationFieldNames.get(fieldName) : fieldName.charAt(0).toUpperCase() + fieldName.substring(1)
|
||||
errors.push(`${properName} is required.`)
|
||||
}
|
||||
return errors
|
||||
},
|
||||
showSnack (message: string) {
|
||||
this.snackText = message
|
||||
this.snackbar = true
|
||||
},
|
||||
dialogCancel () {
|
||||
this.$router.back()
|
||||
},
|
||||
dialogConfirm () {
|
||||
this.addLibrary()
|
||||
},
|
||||
validateLibrary () {
|
||||
this.$v.$touch()
|
||||
|
||||
if (!this.$v.$invalid) {
|
||||
return {
|
||||
name: this.form.name,
|
||||
root: this.form.path,
|
||||
}
|
||||
}
|
||||
return null
|
||||
},
|
||||
async addLibrary () {
|
||||
const library = this.validateLibrary()
|
||||
if (library) {
|
||||
try {
|
||||
await this.$store.dispatch('postLibrary', library)
|
||||
this.$router.push({ name: 'home' })
|
||||
} catch (e) {
|
||||
this.showSnack(e.message)
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
276
komga-webui/src/components/dialogs/LibraryEditDialog.vue
Normal file
276
komga-webui/src/components/dialogs/LibraryEditDialog.vue
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
<template>
|
||||
<div>
|
||||
<v-dialog v-model="modal"
|
||||
:fullscreen="this.$vuetify.breakpoint.xsOnly"
|
||||
:hide-overlay="this.$vuetify.breakpoint.xsOnly"
|
||||
max-width="600"
|
||||
>
|
||||
<form novalidate>
|
||||
<v-card>
|
||||
<v-toolbar class="hidden-sm-and-up">
|
||||
<v-btn icon @click="dialogClose">
|
||||
<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">{{ confirmText }}</v-btn>
|
||||
</v-toolbar-items>
|
||||
</v-toolbar>
|
||||
|
||||
<v-card-title class="hidden-xs-only">{{ dialogTitle }}</v-card-title>
|
||||
|
||||
<v-tabs :vertical="$vuetify.breakpoint.smAndUp" v-model="tab">
|
||||
<v-tab class="justify-start">
|
||||
<v-icon left class="hidden-xs-only">mdi-bookshelf</v-icon>
|
||||
General
|
||||
</v-tab>
|
||||
<v-tab class="justify-start">
|
||||
<v-icon left class="hidden-xs-only">mdi-tune</v-icon>
|
||||
Options
|
||||
</v-tab>
|
||||
|
||||
<!-- Tab: General -->
|
||||
<v-tab-item>
|
||||
<v-card flat>
|
||||
<v-container fluid>
|
||||
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-text-field v-model="form.name"
|
||||
label="Name"
|
||||
:error-messages="getErrors('name')"
|
||||
@input="$v.form.name.$touch()"
|
||||
@blur="$v.form.name.$touch()"
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
|
||||
<v-row>
|
||||
<v-col cols="8">
|
||||
<file-browser-dialog
|
||||
v-model="modalFileBrowser"
|
||||
:path.sync="form.path"
|
||||
confirm-text="Choose"
|
||||
dialog-title="Library's root folder"
|
||||
/>
|
||||
|
||||
<v-text-field v-model="form.path"
|
||||
label="Root folder"
|
||||
:error-messages="getErrors('path')"
|
||||
@input="$v.form.path.$touch()"
|
||||
@blur="$v.form.path.$touch()"
|
||||
/>
|
||||
</v-col>
|
||||
<v-col cols="4">
|
||||
<v-btn @click="modalFileBrowser = true">Browse</v-btn>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card>
|
||||
</v-tab-item>
|
||||
|
||||
<!-- Tab: Options -->
|
||||
<v-tab-item>
|
||||
<v-card flat>
|
||||
<v-container fluid>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<span class="subtitle-2">Import metadata for CBR/CBZ containing a ComicInfo.xml file</span>
|
||||
<v-checkbox
|
||||
v-model="form.importComicInfoBook"
|
||||
label="Book metadata"
|
||||
hide-details
|
||||
/>
|
||||
<v-checkbox
|
||||
v-model="form.importComicInfoSeries"
|
||||
label="Series title"
|
||||
hide-details
|
||||
/>
|
||||
<!-- <v-checkbox-->
|
||||
<!-- v-model="form.importComicInfoCollection"-->
|
||||
<!-- label="Collections"-->
|
||||
<!-- hide-details-->
|
||||
<!-- />-->
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<span class="subtitle-2">Import metadata from EPUB files</span>
|
||||
<v-checkbox
|
||||
v-model="form.importEpubBook"
|
||||
label="Book metadata"
|
||||
hide-details
|
||||
/>
|
||||
<v-checkbox
|
||||
v-model="form.importEpubSeries"
|
||||
label="Series title"
|
||||
hide-details
|
||||
/>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</v-card>
|
||||
</v-tab-item>
|
||||
</v-tabs>
|
||||
|
||||
<v-card-actions class="hidden-xs-only">
|
||||
<v-spacer/>
|
||||
<v-btn text @click="dialogClose">Cancel</v-btn>
|
||||
<v-btn text class="primary--text" @click="dialogConfirm">{{ confirmText }}</v-btn>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</form>
|
||||
</v-dialog>
|
||||
|
||||
<v-snackbar
|
||||
v-model="snackbar"
|
||||
bottom
|
||||
color="error"
|
||||
>
|
||||
{{ snackText }}
|
||||
<v-btn
|
||||
text
|
||||
@click="snackbar = false"
|
||||
>
|
||||
Close
|
||||
</v-btn>
|
||||
</v-snackbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import FileBrowserDialog from '@/components/dialogs/FileBrowserDialog.vue'
|
||||
import { LIBRARY_ADDED, LIBRARY_CHANGED, libraryToEventLibraryChanged } from '@/types/events'
|
||||
import Vue from 'vue'
|
||||
import { required } from 'vuelidate/lib/validators'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'LibraryEditDialog',
|
||||
components: { FileBrowserDialog },
|
||||
data: () => {
|
||||
return {
|
||||
modal: false,
|
||||
modalFileBrowser: false,
|
||||
snackbar: false,
|
||||
snackText: '',
|
||||
tab: 0,
|
||||
form: {
|
||||
name: '',
|
||||
path: '',
|
||||
importComicInfoBook: true,
|
||||
importComicInfoSeries: true,
|
||||
importComicInfoCollection: true,
|
||||
importEpubBook: true,
|
||||
importEpubSeries: true,
|
||||
},
|
||||
validationFieldNames: new Map([]),
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
dialogTitle (): string {
|
||||
return this.library ? 'Edit Library' : 'Add Library'
|
||||
},
|
||||
confirmText (): string {
|
||||
return this.library ? 'Edit' : 'Add'
|
||||
},
|
||||
},
|
||||
props: {
|
||||
value: Boolean,
|
||||
library: {
|
||||
type: Object as () => LibraryDto,
|
||||
required: false,
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
value (val) {
|
||||
this.modal = val
|
||||
},
|
||||
modal (val) {
|
||||
if (val) this.dialogReset(this.library)
|
||||
else this.dialogClose()
|
||||
},
|
||||
},
|
||||
validations: {
|
||||
form: {
|
||||
name: { required },
|
||||
path: { required },
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getErrors (fieldName: string) {
|
||||
const errors = []
|
||||
|
||||
const field = this.$v.form!![fieldName] as any
|
||||
if (field && field.$invalid && field.$dirty) {
|
||||
const properName = this.validationFieldNames.has(fieldName)
|
||||
? this.validationFieldNames.get(fieldName) : fieldName.charAt(0).toUpperCase() + fieldName.substring(1)
|
||||
errors.push(`${properName} is required.`)
|
||||
}
|
||||
return errors
|
||||
},
|
||||
showSnack (message: string) {
|
||||
this.snackText = message
|
||||
this.snackbar = true
|
||||
},
|
||||
dialogClose () {
|
||||
this.$emit('input', false)
|
||||
this.tab = 0
|
||||
},
|
||||
dialogConfirm () {
|
||||
this.addLibrary()
|
||||
},
|
||||
dialogReset (library?: LibraryDto) {
|
||||
this.form.name = library ? library.name : ''
|
||||
this.form.path = library ? library.root : ''
|
||||
this.form.importComicInfoBook = library ? library.importComicInfoBook : true
|
||||
this.form.importComicInfoSeries = library ? library.importComicInfoSeries : true
|
||||
this.form.importComicInfoCollection = library ? library.importComicInfoCollection : true
|
||||
this.form.importEpubBook = library ? library.importEpubBook : true
|
||||
this.form.importEpubSeries = library ? library.importEpubSeries : true
|
||||
this.$v.$reset()
|
||||
},
|
||||
validateLibrary () {
|
||||
this.$v.$touch()
|
||||
|
||||
console.log(this.form)
|
||||
if (!this.$v.$invalid) {
|
||||
return {
|
||||
name: this.form.name,
|
||||
root: this.form.path,
|
||||
importComicInfoBook: this.form.importComicInfoBook,
|
||||
importComicInfoSeries: this.form.importComicInfoSeries,
|
||||
importComicInfoCollection: this.form.importComicInfoCollection,
|
||||
importEpubBook: this.form.importEpubBook,
|
||||
importEpubSeries: this.form.importEpubSeries,
|
||||
}
|
||||
}
|
||||
return null
|
||||
},
|
||||
async addLibrary () {
|
||||
const library = this.validateLibrary()
|
||||
if (library) {
|
||||
console.log(library)
|
||||
try {
|
||||
if (this.library) {
|
||||
await this.$store.dispatch('updateLibrary', { libraryId: this.library.id, library: library })
|
||||
this.$eventHub.$emit(LIBRARY_CHANGED, libraryToEventLibraryChanged(this.library))
|
||||
} else {
|
||||
await this.$store.dispatch('postLibrary', library)
|
||||
this.$eventHub.$emit(LIBRARY_ADDED)
|
||||
}
|
||||
this.dialogClose()
|
||||
} catch (e) {
|
||||
this.showSnack(e.message)
|
||||
}
|
||||
} else {
|
||||
this.tab = 0
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
|
|
@ -16,6 +16,9 @@
|
|||
<v-list-item @click="refreshMetadata">
|
||||
<v-list-item-title>Refresh metadata</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-list-item @click="edit">
|
||||
<v-list-item-title>Edit</v-list-item-title>
|
||||
</v-list-item>
|
||||
<v-list-item @click="promptDeleteLibrary"
|
||||
class="list-warning">
|
||||
<v-list-item-title>Delete</v-list-item-title>
|
||||
|
|
@ -50,6 +53,9 @@ export default Vue.extend({
|
|||
refreshMetadata () {
|
||||
this.$komgaLibraries.refreshMetadata(this.library)
|
||||
},
|
||||
edit () {
|
||||
this.$store.dispatch('dialogEditLibrary', this.library)
|
||||
},
|
||||
promptDeleteLibrary () {
|
||||
this.$store.dispatch('dialogDeleteLibrary', this.library)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -25,11 +25,15 @@ const vuexModule: Module<any, any> = {
|
|||
},
|
||||
async postLibrary ({ dispatch }, library) {
|
||||
await service.postLibrary(library)
|
||||
dispatch('getLibraries')
|
||||
await dispatch('getLibraries')
|
||||
},
|
||||
async updateLibrary ({ dispatch }, { libraryId, library }) {
|
||||
await service.updateLibrary(libraryId, library)
|
||||
await dispatch('getLibraries')
|
||||
},
|
||||
async deleteLibrary ({ dispatch }, library) {
|
||||
await service.deleteLibrary(library)
|
||||
dispatch('getLibraries')
|
||||
await dispatch('getLibraries')
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,12 +28,6 @@ const router = new Router({
|
|||
redirect: { name: 'dashboard' },
|
||||
component: () => import(/* webpackChunkName: "home" */ './views/Home.vue'),
|
||||
children: [
|
||||
{
|
||||
path: '/libraries/add',
|
||||
name: 'addlibrary',
|
||||
beforeEnter: adminGuard,
|
||||
component: () => import(/* webpackChunkName: "addlibrary" */ './components/dialogs/LibraryAddDialog.vue'),
|
||||
},
|
||||
{
|
||||
path: '/welcome',
|
||||
name: 'welcome',
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { AxiosInstance } from 'axios'
|
|||
const API_LIBRARIES = '/api/v1/libraries'
|
||||
|
||||
export default class KomgaLibrariesService {
|
||||
private http: AxiosInstance;
|
||||
private http: AxiosInstance
|
||||
|
||||
constructor (http: AxiosInstance) {
|
||||
this.http = http
|
||||
|
|
@ -45,6 +45,18 @@ export default class KomgaLibrariesService {
|
|||
}
|
||||
}
|
||||
|
||||
async updateLibrary (libraryId: number, library: LibraryUpdateDto) {
|
||||
try {
|
||||
await this.http.put(`${API_LIBRARIES}/${libraryId}`, library)
|
||||
} catch (e) {
|
||||
let msg = `An error occurred while trying to update library '${libraryId}'`
|
||||
if (e.response.data.message) {
|
||||
msg += `: ${e.response.data.message}`
|
||||
}
|
||||
throw new Error(msg)
|
||||
}
|
||||
}
|
||||
|
||||
async deleteLibrary (library: LibraryDto) {
|
||||
try {
|
||||
await this.http.delete(`${API_LIBRARIES}/${library.id}`)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ export default new Vuex.Store({
|
|||
editCollectionDialog: false,
|
||||
deleteCollection: {} as CollectionDto,
|
||||
deleteCollectionDialog: false,
|
||||
editLibrary: {} as LibraryDto | undefined,
|
||||
editLibraryDialog: false,
|
||||
deleteLibrary: {} as LibraryDto,
|
||||
deleteLibraryDialog: false,
|
||||
updateBooks: {} as BookDto | BookDto[],
|
||||
|
|
@ -34,6 +36,12 @@ export default new Vuex.Store({
|
|||
setDeleteCollection (state, collection) {
|
||||
state.deleteCollection = collection
|
||||
},
|
||||
setEditLibrary (state, library) {
|
||||
state.editLibrary = library
|
||||
},
|
||||
setEditLibraryDialog (state, dialog) {
|
||||
state.editLibraryDialog = dialog
|
||||
},
|
||||
setDeleteCollectionDialog (state, dialog) {
|
||||
state.deleteCollectionDialog = dialog
|
||||
},
|
||||
|
|
@ -78,6 +86,17 @@ export default new Vuex.Store({
|
|||
dialogDeleteCollectionDisplay ({ commit }, value) {
|
||||
commit('setDeleteCollectionDialog', value)
|
||||
},
|
||||
dialogAddLibrary ({ commit }) {
|
||||
commit('setEditLibrary', undefined)
|
||||
commit('setEditLibraryDialog', true)
|
||||
},
|
||||
dialogEditLibrary ({ commit }, value) {
|
||||
commit('setEditLibrary', value)
|
||||
commit('setEditLibraryDialog', true)
|
||||
},
|
||||
dialogEditLibraryDisplay ({ commit }, value) {
|
||||
commit('setEditLibraryDialog', value)
|
||||
},
|
||||
dialogDeleteLibrary ({ commit }, library) {
|
||||
commit('setDeleteLibrary', library)
|
||||
commit('setDeleteLibraryDialog', true)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,14 @@ interface EventCollectionDeleted {
|
|||
id: number
|
||||
}
|
||||
|
||||
interface EventLibraryAdded {
|
||||
id: number
|
||||
}
|
||||
|
||||
interface EventLibraryChanged {
|
||||
id: number
|
||||
}
|
||||
|
||||
interface EventLibraryDeleted {
|
||||
id: number
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ export const BOOK_CHANGED = 'book-changed'
|
|||
export const SERIES_CHANGED = 'series-changed'
|
||||
export const COLLECTION_DELETED = 'collection-deleted'
|
||||
export const COLLECTION_CHANGED = 'collection-changed'
|
||||
export const LIBRARY_ADDED = 'library-added'
|
||||
export const LIBRARY_CHANGED = 'library-changed'
|
||||
export const LIBRARY_DELETED = 'library-deleted'
|
||||
|
||||
export function bookToEventBookChanged (book: BookDto): EventBookChanged {
|
||||
|
|
@ -30,6 +32,18 @@ export function collectionToEventCollectionDeleted (collection: CollectionDto):
|
|||
} as EventCollectionDeleted
|
||||
}
|
||||
|
||||
export function libraryToEventLibraryAdded (library: LibraryDto): EventLibraryAdded {
|
||||
return {
|
||||
id: library.id,
|
||||
} as EventLibraryAdded
|
||||
}
|
||||
|
||||
export function libraryToEventLibraryChanged (library: LibraryDto): EventLibraryChanged {
|
||||
return {
|
||||
id: library.id,
|
||||
} as EventLibraryChanged
|
||||
}
|
||||
|
||||
export function libraryToEventLibraryDeleted (library: LibraryDto): EventLibraryDeleted {
|
||||
return {
|
||||
id: library.id,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,30 @@
|
|||
interface LibraryCreationDto {
|
||||
name: string,
|
||||
root: string
|
||||
root: string,
|
||||
importComicInfoBook: boolean,
|
||||
importComicInfoSeries: boolean,
|
||||
importComicInfoCollection: boolean,
|
||||
importEpubBook: boolean,
|
||||
importEpubSeries: boolean
|
||||
}
|
||||
|
||||
interface LibraryUpdateDto {
|
||||
name: string,
|
||||
root: string,
|
||||
importComicInfoBook: boolean,
|
||||
importComicInfoSeries: boolean,
|
||||
importComicInfoCollection: boolean,
|
||||
importEpubBook: boolean,
|
||||
importEpubSeries: boolean
|
||||
}
|
||||
|
||||
interface LibraryDto {
|
||||
id: number,
|
||||
name: string,
|
||||
root: string
|
||||
root: string,
|
||||
importComicInfoBook: boolean,
|
||||
importComicInfoSeries: boolean,
|
||||
importComicInfoCollection: boolean,
|
||||
importEpubBook: boolean,
|
||||
importEpubSeries: boolean
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,12 +38,12 @@
|
|||
|
||||
<script lang="ts">
|
||||
import Badge from '@/components/Badge.vue'
|
||||
import ItemBrowser from '@/components/ItemBrowser.vue'
|
||||
import LibraryActionsMenu from '@/components/menus/LibraryActionsMenu.vue'
|
||||
import LibraryNavigation from '@/components/LibraryNavigation.vue'
|
||||
import PageSizeSelect from '@/components/PageSizeSelect.vue'
|
||||
import ToolbarSticky from '@/components/bars/ToolbarSticky.vue'
|
||||
import { COLLECTION_CHANGED } from '@/types/events'
|
||||
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 { COLLECTION_CHANGED, LIBRARY_CHANGED } from '@/types/events'
|
||||
import Vue from 'vue'
|
||||
|
||||
const cookiePageSize = 'pagesize'
|
||||
|
|
@ -78,9 +78,11 @@ export default Vue.extend({
|
|||
},
|
||||
created () {
|
||||
this.$eventHub.$on(COLLECTION_CHANGED, this.reloadCollections)
|
||||
this.$eventHub.$on(LIBRARY_CHANGED, this.reloadLibrary)
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$eventHub.$off(COLLECTION_CHANGED, this.reloadCollections)
|
||||
this.$eventHub.$off(LIBRARY_CHANGED, this.reloadLibrary)
|
||||
},
|
||||
mounted () {
|
||||
if (this.$cookies.isKey(cookiePageSize)) {
|
||||
|
|
@ -166,6 +168,11 @@ export default Vue.extend({
|
|||
reloadCollections () {
|
||||
this.loadLibrary(this.libraryId)
|
||||
},
|
||||
reloadLibrary (event: EventLibraryChanged) {
|
||||
if (event.id === this.libraryId) {
|
||||
this.loadLibrary(this.libraryId)
|
||||
}
|
||||
},
|
||||
async loadLibrary (libraryId: number) {
|
||||
this.library = this.getLibraryLazy(libraryId)
|
||||
await this.loadPage(libraryId, this.page)
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ import SortMenuButton from '@/components/SortMenuButton.vue'
|
|||
import { parseQueryFilter, parseQuerySort } from '@/functions/query-params'
|
||||
import { ReadStatus } from '@/types/enum-books'
|
||||
import { SeriesStatus } from '@/types/enum-series'
|
||||
import { COLLECTION_CHANGED, LIBRARY_DELETED, SERIES_CHANGED } from '@/types/events'
|
||||
import { COLLECTION_CHANGED, LIBRARY_CHANGED, LIBRARY_DELETED, SERIES_CHANGED } from '@/types/events'
|
||||
import Vue from 'vue'
|
||||
|
||||
const cookiePageSize = 'pagesize'
|
||||
|
|
@ -154,11 +154,13 @@ export default Vue.extend({
|
|||
this.$eventHub.$on(COLLECTION_CHANGED, this.reloadCollections)
|
||||
this.$eventHub.$on(SERIES_CHANGED, this.reloadSeries)
|
||||
this.$eventHub.$on(LIBRARY_DELETED, this.libraryDeleted)
|
||||
this.$eventHub.$on(LIBRARY_CHANGED, this.reloadLibrary)
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$eventHub.$off(COLLECTION_CHANGED, this.reloadCollections)
|
||||
this.$eventHub.$off(SERIES_CHANGED, this.reloadSeries)
|
||||
this.$eventHub.$off(LIBRARY_DELETED, this.libraryDeleted)
|
||||
this.$eventHub.$off(LIBRARY_CHANGED, this.reloadLibrary)
|
||||
},
|
||||
mounted () {
|
||||
if (this.$cookies.isKey(cookiePageSize)) {
|
||||
|
|
@ -282,6 +284,11 @@ export default Vue.extend({
|
|||
this.loadPage(this.libraryId, this.page, this.sortActive)
|
||||
}
|
||||
},
|
||||
reloadLibrary (event: EventLibraryChanged) {
|
||||
if (this.libraryId === 0 || event.id === this.libraryId) {
|
||||
this.loadLibrary(this.libraryId)
|
||||
}
|
||||
},
|
||||
async loadLibrary (libraryId: number) {
|
||||
this.library = this.getLibraryLazy(libraryId)
|
||||
|
||||
|
|
|
|||
|
|
@ -134,12 +134,12 @@ export default Vue.extend({
|
|||
}
|
||||
},
|
||||
created () {
|
||||
this.$eventHub.$on(LIBRARY_DELETED, this.loadAll)
|
||||
this.$eventHub.$on(LIBRARY_DELETED, this.libraryDeleted)
|
||||
this.$eventHub.$on(SERIES_CHANGED, this.loadAll)
|
||||
this.$eventHub.$on(BOOK_CHANGED, this.loadAll)
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$eventHub.$off(LIBRARY_DELETED, this.loadAll)
|
||||
this.$eventHub.$off(LIBRARY_DELETED, this.libraryDeleted)
|
||||
this.$eventHub.$off(SERIES_CHANGED, this.loadAll)
|
||||
this.$eventHub.$off(BOOK_CHANGED, this.loadAll)
|
||||
},
|
||||
|
|
@ -167,6 +167,13 @@ export default Vue.extend({
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
libraryDeleted () {
|
||||
if (this.$store.state.komgaLibraries.libraries.length === 0) {
|
||||
this.$router.push({ name: 'welcome' })
|
||||
} else {
|
||||
this.loadAll()
|
||||
}
|
||||
},
|
||||
loadAll () {
|
||||
this.loadNewSeries()
|
||||
this.loadUpdatedSeries()
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
<v-list-item-title>Libraries</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
<v-list-item-action v-if="isAdmin">
|
||||
<v-btn icon :to="{name: 'addlibrary'}" exact>
|
||||
<v-btn icon @click.stop.capture.prevent="addLibrary">
|
||||
<v-icon>mdi-plus</v-icon>
|
||||
</v-btn>
|
||||
</v-list-item-action>
|
||||
|
|
@ -127,7 +127,6 @@ export default Vue.extend({
|
|||
data: function () {
|
||||
return {
|
||||
drawerVisible: this.$vuetify.breakpoint.lgAndUp,
|
||||
modalAddLibrary: false,
|
||||
info: {} as ActuatorInfo,
|
||||
}
|
||||
},
|
||||
|
|
@ -152,6 +151,9 @@ export default Vue.extend({
|
|||
this.$store.dispatch('logout')
|
||||
this.$router.push({ name: 'login' })
|
||||
},
|
||||
addLibrary () {
|
||||
this.$store.dispatch('dialogAddLibrary')
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -9,13 +9,14 @@
|
|||
<div class="text-center">
|
||||
<h1 class="headline mt-4">Welcome to Komga</h1>
|
||||
<p class="body-1">No libraries have been added yet!</p>
|
||||
<v-btn color="primary" :to="{name: 'addlibrary'}" v-if="isAdmin">Add library</v-btn>
|
||||
<v-btn color="primary" @click="addLibrary" v-if="isAdmin">Add library</v-btn>
|
||||
</div>
|
||||
</v-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { LIBRARY_ADDED } from '@/types/events'
|
||||
import Vue from 'vue'
|
||||
|
||||
export default Vue.extend({
|
||||
|
|
@ -25,11 +26,25 @@ export default Vue.extend({
|
|||
return this.$store.getters.meAdmin
|
||||
},
|
||||
},
|
||||
created () {
|
||||
this.$eventHub.$on(LIBRARY_ADDED, this.libraryAdded)
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$eventHub.$off(LIBRARY_ADDED, this.libraryAdded)
|
||||
},
|
||||
mounted () {
|
||||
if (this.$store.state.komgaLibraries.libraries.length !== 0) {
|
||||
this.$router.push({ name: 'dashboard' })
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
libraryAdded () {
|
||||
this.$router.push({ name: 'dashboard' })
|
||||
},
|
||||
addLibrary () {
|
||||
this.$store.dispatch('dialogAddLibrary')
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue