refactor(webui): use confirmation-dialog for deletions

This commit is contained in:
Gauthier Roebroeck 2021-07-02 16:01:49 +08:00
parent 5e9cb9a7f7
commit 363eac5ec6
8 changed files with 137 additions and 443 deletions

View file

@ -10,9 +10,14 @@
:collection="editCollection"
/>
<collection-delete-dialog
<confirmation-dialog
v-model="deleteCollectionDialog"
:collections="deleteCollections"
:title="collectionsToDeleteSingle ? $t('dialog.delete_collection.dialog_title') : $t('dialog.delete_collection.dialog_title_multiple')"
:body-html="collectionsToDeleteSingle ? $t('dialog.delete_collection.warning_html', { name: collectionsToDelete.name}) : $t('dialog.delete_collection.warning_multiple_html', { count: collectionsToDelete.length})"
:confirm-text="collectionsToDeleteSingle ? $t('dialog.delete_collection.confirm_delete', {name: collectionsToDelete.name}) : $t('dialog.delete_collection.confirm_delete_multiple', {count: collectionsToDelete.length})"
:button-confirm="$t('dialog.delete_collection.button_confirm')"
button-confirm-color="error"
@confirm="deleteCollections"
/>
<read-list-add-to-dialog
@ -25,9 +30,14 @@
:read-list="editReadList"
/>
<read-list-delete-dialog
<confirmation-dialog
v-model="deleteReadListDialog"
:read-lists="deleteReadLists"
:title="readListsToDeleteSingle ? $t('dialog.delete_readlist.dialog_title') : $t('dialog.delete_readlist.dialog_title_multiple')"
:body-html="readListsToDeleteSingle ? $t('dialog.delete_readlist.warning_html', {name: readListsToDelete.name}) : $t('dialog.delete_readlist.warning_multiple_html', {count: readListsToDelete.length})"
:confirm-text="readListsToDeleteSingle ? $t('dialog.delete_readlist.confirm_delete', {name: readListsToDelete.name}) : $t('dialog.delete_readlist.confirm_delete_multiple', {count: readListsToDelete.length})"
:button-confirm="$t('dialog.delete_readlist.button_confirm')"
button-confirm-color="error"
@confirm="deleteReadLists"
/>
<library-edit-dialog
@ -35,9 +45,14 @@
:library="editLibrary"
/>
<library-delete-dialog
<confirmation-dialog
v-model="deleteLibraryDialog"
:library="deleteLibrary"
:title="$t('dialog.delete_library.title')"
:body-html="$t('dialog.delete_library.warning_html', {name: libraryToDelete.name})"
:confirm-text="$t('dialog.delete_library.confirm_delete', {name: libraryToDelete.name})"
:button-confirm="$t('dialog.delete_library.button_confirm')"
button-confirm-color="error"
@confirm="deleteLibrary"
/>
<edit-books-dialog
@ -55,150 +70,182 @@
<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 Vue from 'vue'
import ReadListAddToDialog from '@/components/dialogs/ReadListAddToDialog.vue'
import ReadListDeleteDialog from '@/components/dialogs/ReadListDeleteDialog.vue'
import ReadListEditDialog from '@/components/dialogs/ReadListEditDialog.vue'
import {BookDto} from '@/types/komga-books'
import {SeriesDto} from "@/types/komga-series";
import {ERROR} from "@/types/events";
import ConfirmationDialog from "@/components/dialogs/ConfirmationDialog.vue";
export default Vue.extend({
name: 'Dialogs',
components: {
ConfirmationDialog,
CollectionAddToDialog,
CollectionEditDialog,
CollectionDeleteDialog,
ReadListAddToDialog,
ReadListEditDialog,
ReadListDeleteDialog,
LibraryEditDialog,
LibraryDeleteDialog,
EditBooksDialog,
EditSeriesDialog,
},
computed: {
// collections
addToCollectionDialog: {
get (): boolean {
get(): boolean {
return this.$store.state.addToCollectionDialog
},
set (val) {
set(val) {
this.$store.dispatch('dialogAddSeriesToCollectionDisplay', val)
},
},
addToCollectionSeries (): SeriesDto | SeriesDto[] {
addToCollectionSeries(): SeriesDto | SeriesDto[] {
return this.$store.state.addToCollectionSeries
},
editCollectionDialog: {
get (): boolean {
get(): boolean {
return this.$store.state.editCollectionDialog
},
set (val) {
set(val) {
this.$store.dispatch('dialogEditCollectionDisplay', val)
},
},
editCollection (): CollectionDto {
editCollection(): CollectionDto {
return this.$store.state.editCollection
},
deleteCollectionDialog: {
get (): boolean {
get(): boolean {
return this.$store.state.deleteCollectionDialog
},
set (val) {
set(val) {
this.$store.dispatch('dialogDeleteCollectionDisplay', val)
},
},
deleteCollections (): CollectionDto | CollectionDto[] {
collectionsToDelete(): CollectionDto | CollectionDto[] {
return this.$store.state.deleteCollections
},
collectionsToDeleteSingle(): boolean {
return !Array.isArray(this.collectionsToDelete)
},
// read lists
addToReadListDialog: {
get (): boolean {
get(): boolean {
return this.$store.state.addToReadListDialog
},
set (val) {
set(val) {
this.$store.dispatch('dialogAddBooksToReadListDisplay', val)
},
},
addToReadListBooks (): BookDto | BookDto[] {
addToReadListBooks(): BookDto | BookDto[] {
return this.$store.state.addToReadListBooks
},
editReadListDialog: {
get (): boolean {
get(): boolean {
return this.$store.state.editReadListDialog
},
set (val) {
set(val) {
this.$store.dispatch('dialogEditReadListDisplay', val)
},
},
editReadList (): ReadListDto {
editReadList(): ReadListDto {
return this.$store.state.editReadList
},
deleteReadListDialog: {
get (): boolean {
get(): boolean {
return this.$store.state.deleteReadListDialog
},
set (val) {
set(val) {
this.$store.dispatch('dialogDeleteReadListDisplay', val)
},
},
deleteReadLists (): ReadListDto | ReadListDto[] {
readListsToDelete(): ReadListDto | ReadListDto[] {
return this.$store.state.deleteReadLists
},
readListsToDeleteSingle(): boolean {
return !Array.isArray(this.readListsToDelete)
},
// libraries
editLibraryDialog: {
get (): boolean {
get(): boolean {
return this.$store.state.editLibraryDialog
},
set (val) {
set(val) {
this.$store.dispatch('dialogEditLibraryDisplay', val)
},
},
editLibrary (): LibraryDto | undefined {
editLibrary(): LibraryDto | undefined {
return this.$store.state.editLibrary
},
deleteLibraryDialog: {
get (): boolean {
get(): boolean {
return this.$store.state.deleteLibraryDialog
},
set (val) {
set(val) {
this.$store.dispatch('dialogDeleteLibraryDisplay', val)
},
},
deleteLibrary (): LibraryDto {
libraryToDelete(): LibraryDto {
return this.$store.state.deleteLibrary
},
// books
updateBooksDialog: {
get (): boolean {
get(): boolean {
return this.$store.state.updateBooksDialog
},
set (val) {
set(val) {
this.$store.dispatch('dialogUpdateBooksDisplay', val)
},
},
updateBooks (): BookDto | BookDto[] {
updateBooks(): BookDto | BookDto[] {
return this.$store.state.updateBooks
},
// series
updateSeriesDialog: {
get (): boolean {
get(): boolean {
return this.$store.state.updateSeriesDialog
},
set (val) {
set(val) {
this.$store.dispatch('dialogUpdateSeriesDisplay', val)
},
},
updateSeries (): SeriesDto | SeriesDto[] {
updateSeries(): SeriesDto | SeriesDto[] {
return this.$store.state.updateSeries
},
},
methods: {
async deleteLibrary() {
try {
await this.$store.dispatch('deleteLibrary', this.libraryToDelete)
} catch (e) {
this.$eventHub.$emit(ERROR, {message: e.message} as ErrorEvent)
}
},
async deleteReadLists() {
const toUpdate = (this.readListsToDeleteSingle ? [this.readListsToDelete] : this.readListsToDelete) as ReadListDto[]
for (const b of toUpdate) {
try {
await this.$komgaReadLists.deleteReadList(b.id)
} catch (e) {
this.$eventHub.$emit(ERROR, {message: e.message} as ErrorEvent)
}
}
},
async deleteCollections() {
const toUpdate = (this.collectionsToDeleteSingle ? [this.collectionsToDelete] : this.collectionsToDelete) as CollectionDto[]
for (const b of toUpdate) {
try {
await this.$komgaCollections.deleteCollection(b.id)
} catch (e) {
this.$eventHub.$emit(ERROR, {message: e.message} as ErrorEvent)
}
}
},
},
})
</script>

View file

@ -105,25 +105,37 @@
:user="userToEdit"
/>
<user-delete-dialog v-model="modalDeleteUser"
:user="userToDelete">
</user-delete-dialog>
<confirmation-dialog
v-model="modalDeleteUser"
:title="$t('dialog.delete_user.dialog_title')"
:body-html="$t('dialog.delete_user.warning_html', {name: userToDelete.email})"
:confirm-text=" $t('dialog.delete_user.confirm_delete', {name: userToDelete.email})"
:button-confirm="$t('dialog.delete_user.button_confirm')"
button-confirm-color="error"
@confirm="deleteUser"
/>
<router-view/>
</div>
</template>
<script lang="ts">
import UserDeleteDialog from '@/components/dialogs/UserDeleteDialog.vue'
import UserEditDialog from '@/components/dialogs/UserEditDialog.vue'
import UserSharedLibrariesEditDialog from '@/components/dialogs/UserSharedLibrariesEditDialog.vue'
import {UserRoles} from '@/types/enum-users'
import Vue from 'vue'
import PasswordChangeDialog from "@/components/dialogs/PasswordChangeDialog.vue"
import {ERROR} from "@/types/events";
import ConfirmationDialog from "@/components/dialogs/ConfirmationDialog.vue";
export default Vue.extend({
name: 'UsersList',
components: {UserSharedLibrariesEditDialog, UserDeleteDialog, UserEditDialog, PasswordChangeDialog},
components: {
ConfirmationDialog,
UserSharedLibrariesEditDialog,
UserEditDialog,
PasswordChangeDialog,
},
data: () => ({
UserRoles,
modalAddUser: false,
@ -175,6 +187,13 @@ export default Vue.extend({
this.userToChangePassword = user
this.modalChangePassword = true
},
async deleteUser() {
try {
await this.$store.dispatch('deleteUser', this.userToDelete)
} catch (e) {
this.$eventHub.$emit(ERROR, {message: e.message} as ErrorEvent)
}
},
},
})
</script>

View file

@ -1,110 +0,0 @@
<template>
<div>
<v-dialog v-model="modal"
max-width="450"
>
<v-card>
<v-card-title v-if="single">{{ $t('dialog.delete_collection.dialog_title') }}</v-card-title>
<v-card-title v-else>{{ $t('dialog.delete_collection.dialog_title_multiple') }}</v-card-title>
<v-card-text>
<v-container fluid>
<v-row>
<v-col
v-if="single"
v-html="$t('dialog.delete_collection.warning_html', { name: collections.name})"
/>
<v-col
v-else
v-html="$t('dialog.delete_collection.warning_multiple_html', { count: collections.length})"
/>
</v-row>
<v-row>
<v-col>
<v-checkbox v-model="confirmDelete" color="red">
<template v-slot:label v-if="single">
{{ $t('dialog.delete_collection.confirm_delete', {name: collections.name}) }}
</template>
<template v-slot:label v-else>
{{ $t('dialog.delete_collection.confirm_delete_multiple', {count: collections.length}) }}
</template>
</v-checkbox>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer/>
<v-btn text @click="dialogCancel">{{ $t('dialog.delete_collection.button_cancel') }}</v-btn>
<v-btn color="error"
@click="dialogConfirm"
:disabled="!confirmDelete"
>{{ $t('dialog.delete_collection.button_confirm') }}
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
import {ERROR} from "@/types/events";
export default Vue.extend({
name: 'CollectionDeleteDialog',
data: () => {
return {
confirmDelete: false,
modal: false,
}
},
props: {
value: Boolean,
collections: {
type: [Object as () => CollectionDto, Array as () => CollectionDto[]],
required: true,
},
},
watch: {
value(val) {
this.modal = val
},
modal(val) {
!val && this.dialogCancel()
},
},
computed: {
single(): boolean {
return !Array.isArray(this.collections)
},
},
methods: {
dialogCancel() {
this.$emit('input', false)
this.confirmDelete = false
},
dialogConfirm() {
this.deleteCollections()
this.$emit('input', false)
},
async deleteCollections() {
const toUpdate = (this.single ? [this.collections] : this.collections) as CollectionDto[]
for (const b of toUpdate) {
try {
await this.$komgaCollections.deleteCollection(b.id)
} catch (e) {
this.$eventHub.$emit(ERROR, {message: e.message} as ErrorEvent)
}
}
},
},
})
</script>
<style scoped>
</style>

View file

@ -8,7 +8,18 @@
<v-card-text>
<v-container fluid>
<v-row>
<v-col>{{ body }}</v-col>
<v-col v-if="body && !bodyHtml">{{ body }}</v-col>
<v-col v-if="bodyHtml" v-html="bodyHtml"/>
</v-row>
<v-row v-if="confirmText">
<v-col>
<v-checkbox v-model="confirmation" :color="buttonConfirmColor">
<template v-slot:label>
{{ confirmText }}
</template>
</v-checkbox>
</v-col>
</v-row>
</v-container>
</v-card-text>
@ -18,6 +29,7 @@
<v-btn text @click="dialogCancel">{{ buttonCancel || $t('common.cancel') }}</v-btn>
<v-btn :color="buttonConfirmColor"
@click="dialogConfirm"
:disabled="confirmText && !confirmation"
>{{ buttonConfirm }}
</v-btn>
</v-card-actions>
@ -33,6 +45,7 @@ export default Vue.extend({
data: () => {
return {
modal: false,
confirmation: false,
}
},
props: {
@ -43,7 +56,15 @@ export default Vue.extend({
},
body: {
type: String,
required: true,
required: false,
},
bodyHtml: {
type: String,
required: false,
},
confirmText: {
type: String,
required: false,
},
buttonCancel: {
type: String,
@ -68,6 +89,7 @@ export default Vue.extend({
},
methods: {
dialogCancel() {
this.confirmation = false
this.$emit('input', false)
},
dialogConfirm() {

View file

@ -1,86 +0,0 @@
<template>
<v-dialog v-model="modal"
max-width="450"
>
<v-card>
<v-card-title>{{ $t('dialog.delete_library.title') }}</v-card-title>
<v-card-text>
<v-container fluid>
<v-row>
<v-col v-html="$t('dialog.delete_library.warning_html', {name: library.name})"></v-col>
</v-row>
<v-row>
<v-col>
<v-checkbox v-model="confirmDelete" color="red">
<template v-slot:label>{{ $t('dialog.delete_library.confirm_delete', {name: library.name}) }}</template>
</v-checkbox>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer/>
<v-btn text @click="dialogCancel">{{ $t('dialog.delete_library.button_cancel') }}</v-btn>
<v-btn color="error"
@click="dialogConfirm"
:disabled="!confirmDelete"
>{{ $t('dialog.delete_library.button_confirm') }}
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script lang="ts">
import Vue from 'vue'
import {ERROR} from "@/types/events";
export default Vue.extend({
name: 'LibraryDeleteDialog',
data: () => {
return {
confirmDelete: false,
modal: false,
}
},
props: {
value: Boolean,
library: {
type: Object,
required: true,
},
},
watch: {
value(val) {
this.modal = val
},
modal(val) {
!val && this.dialogCancel()
},
},
methods: {
dialogCancel() {
this.$emit('input', false)
this.confirmDelete = false
},
dialogConfirm() {
this.deleteLibrary()
this.$emit('input', false)
},
async deleteLibrary() {
try {
await this.$store.dispatch('deleteLibrary', this.library)
} catch (e) {
this.$eventHub.$emit(ERROR, {message: e.message} as ErrorEvent)
}
},
},
})
</script>
<style scoped>
</style>

View file

@ -1,107 +0,0 @@
<template>
<v-dialog v-model="modal"
max-width="450"
>
<v-card>
<v-card-title v-if="single">{{ $t('dialog.delete_readlist.dialog_title') }}</v-card-title>
<v-card-title v-else>{{ $t('dialog.delete_readlist.dialog_title_multiple') }}</v-card-title>
<v-card-text>
<v-container fluid>
<v-row>
<v-col
v-if="single"
v-html="$t('dialog.delete_readlist.warning_html', {name: readLists.name})"
/>
<v-col
v-else
v-html="$t('dialog.delete_readlist.warning_multiple_html', {count: readLists.length})"
/>
</v-row>
<v-row>
<v-col>
<v-checkbox v-model="confirmDelete" color="red">
<template v-slot:label v-if="single">
{{ $t('dialog.delete_readlist.confirm_delete', {name: readLists.name}) }}
</template>
<template v-slot:label v-else>
{{ $t('dialog.delete_readlist.confirm_delete_multiple', {count: readLists.length}) }}
</template>
</v-checkbox>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer/>
<v-btn text @click="dialogCancel">{{ $t('dialog.delete_readlist.button_cancel') }}</v-btn>
<v-btn color="error"
@click="dialogConfirm"
:disabled="!confirmDelete"
>{{ $t('dialog.delete_readlist.button_confirm') }}
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script lang="ts">
import Vue from 'vue'
import {ERROR} from "@/types/events";
export default Vue.extend({
name: 'ReadListDeleteDialog',
data: () => {
return {
confirmDelete: false,
modal: false,
}
},
props: {
value: Boolean,
readLists: {
type: [Object as () => ReadListDto, Array as () => ReadListDto[]],
required: true,
},
},
watch: {
value(val) {
this.modal = val
},
modal(val) {
!val && this.dialogCancel()
},
},
computed: {
single(): boolean {
return !Array.isArray(this.readLists)
},
},
methods: {
dialogCancel() {
this.$emit('input', false)
this.confirmDelete = false
},
dialogConfirm() {
this.delete()
this.$emit('input', false)
},
async delete() {
const toUpdate = (this.single ? [this.readLists] : this.readLists) as ReadListDto[]
for (const b of toUpdate) {
try {
await this.$komgaReadLists.deleteReadList(b.id)
} catch (e) {
this.$eventHub.$emit(ERROR, {message: e.message} as ErrorEvent)
}
}
},
},
})
</script>
<style scoped>
</style>

View file

@ -1,86 +0,0 @@
<template>
<v-dialog v-model="modal"
max-width="450"
>
<v-card>
<v-card-title>{{ $t('dialog.delete_user.dialog_title') }}</v-card-title>
<v-card-text>
<v-container fluid>
<v-row>
<v-col v-html="$t('dialog.delete_user.warning_html', {name: user.email})"></v-col>
</v-row>
<v-row>
<v-col>
<v-checkbox v-model="confirmDelete" color="red">
<template v-slot:label>{{ $t('dialog.delete_user.confirm_delete', {name: user.email}) }}</template>
</v-checkbox>
</v-col>
</v-row>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer/>
<v-btn text @click="dialogCancel">{{ $t('dialog.delete_user.button_cancel') }}</v-btn>
<v-btn color="error"
@click="dialogConfirm"
:disabled="!confirmDelete"
>{{ $t('dialog.delete_user.button_confirm') }}
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script lang="ts">
import Vue from 'vue'
import {ERROR} from "@/types/events";
export default Vue.extend({
name: 'UserDeleteDialog',
data: () => {
return {
confirmDelete: false,
modal: false,
}
},
props: {
value: Boolean,
user: {
type: Object,
required: true,
},
},
watch: {
value(val) {
this.modal = val
},
modal(val) {
!val && this.dialogCancel()
},
},
methods: {
dialogCancel() {
this.$emit('input', false)
this.confirmDelete = false
},
dialogConfirm() {
this.deleteUser()
this.$emit('input', false)
},
async deleteUser() {
try {
await this.$store.dispatch('deleteUser', this.user)
} catch (e) {
this.$eventHub.$emit(ERROR, {message: e.message} as ErrorEvent)
}
},
},
})
</script>
<style scoped>
</style>

View file

@ -252,7 +252,6 @@
"label_roles": "Roles"
},
"delete_collection": {
"button_cancel": "Cancel",
"button_confirm": "Delete",
"confirm_delete": "Yes, delete the collection \"{name}\"",
"confirm_delete_multiple": "Yes, delete {count} collections",
@ -262,14 +261,12 @@
"warning_multiple_html": "{count} collections will be removed from this server. Your media files will not be affected. This <b>cannot</b> be undone. Continue?"
},
"delete_library": {
"button_cancel": "Cancel",
"button_confirm": "Delete",
"confirm_delete": "Yes, delete the library \"{name}\"",
"title": "Delete Library",
"warning_html": "The library <b>{name}</b> will be removed from this server. Your media files will not be affected. This <b>cannot</b> be undone. Continue?"
},
"delete_readlist": {
"button_cancel": "Cancel",
"button_confirm": "Delete",
"confirm_delete": "Yes, delete the read list \"{name}\"",
"confirm_delete_multiple": "Yes, delete {count} read lists",
@ -279,7 +276,6 @@
"warning_multiple_html": "{count} read lists will be removed from this server. Your media files will not be affected. This <b>cannot</b> be undone. Continue?"
},
"delete_user": {
"button_cancel": "Cancel",
"button_confirm": "Delete",
"confirm_delete": "Yes, delete the user \"{name}\"",
"dialog_title": "Delete User",
@ -415,7 +411,6 @@
"title": "Select Series"
},
"server_stop": {
"button_cancel": "Cancel",
"button_confirm": "Stop",
"confirmation_message": "Are you sure you want to stop Komga?",
"dialog_title": "Shut down server"