Skip to content

Commit a2a689f

Browse files
committed
feat(webui): add ability to reorder libraries
1 parent 8c64639 commit a2a689f

10 files changed

+413
-249
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
<template>
2+
<div>
3+
<v-list>
4+
<v-list-item class="contrast-1">
5+
<v-list-item-content>
6+
<v-list-item-title class="text-uppercase">{{ $t('common.reorder') }}</v-list-item-title>
7+
</v-list-item-content>
8+
<v-list-item-action class="ma-0">
9+
<v-btn icon @click.stop.capture.prevent="dismiss">
10+
<v-icon>mdi-close</v-icon>
11+
</v-btn>
12+
</v-list-item-action>
13+
</v-list-item>
14+
15+
<v-list-item class="text--disabled">
16+
<v-list-item-icon>
17+
<v-icon>mdi-home</v-icon>
18+
</v-list-item-icon>
19+
<v-list-item-content>
20+
<v-list-item-title>{{ $t('navigation.home') }}</v-list-item-title>
21+
</v-list-item-content>
22+
</v-list-item>
23+
24+
<draggable
25+
v-model="localItems"
26+
v-bind="dragOptions"
27+
handle=".handle"
28+
>
29+
<template v-for="(l, index) in localItems">
30+
<v-hover :key="index"
31+
v-slot="{ hover }"
32+
:disabled="!l.unpinned"
33+
>
34+
<v-list-item>
35+
<v-list-item-icon>
36+
<v-icon class="handle">mdi-drag-horizontal-variant</v-icon>
37+
</v-list-item-icon>
38+
<v-list-item-content>
39+
<v-list-item-title class="handle">{{ l.name }}</v-list-item-title>
40+
</v-list-item-content>
41+
<v-list-item-icon>
42+
<v-btn icon v-if="!l.unpinned" @click.stop.capture.prevent="unpin(l.id)" x-small>
43+
<v-icon>mdi-pin</v-icon>
44+
</v-btn>
45+
<v-btn icon v-if="hover && l.unpinned" @click.stop.capture.prevent="pin(l.id)" x-small>
46+
<v-icon>mdi-pin-off</v-icon>
47+
</v-btn>
48+
</v-list-item-icon>
49+
</v-list-item>
50+
</v-hover>
51+
</template>
52+
</draggable>
53+
</v-list>
54+
</div>
55+
</template>
56+
57+
<script lang="ts">
58+
import Vue from 'vue'
59+
import draggable from 'vuedraggable'
60+
import {LibraryDto} from '@/types/komga-libraries'
61+
import {ClientSettingLibraryUpdate} from '@/types/komga-clientsettings'
62+
63+
export default Vue.extend({
64+
name: 'ReorderLibraries',
65+
components: {draggable},
66+
data: () => {
67+
return {
68+
localItems: [] as LibraryDto[],
69+
unwatch: false,
70+
}
71+
},
72+
computed: {
73+
dragOptions(): any {
74+
return {
75+
animation: 200,
76+
// group: 'item-cards',
77+
ghostClass: 'ghost',
78+
}
79+
},
80+
},
81+
mounted() {
82+
this.localItems = this.$store.getters.getLibraries
83+
},
84+
watch: {
85+
localItems: {
86+
handler(val: LibraryDto[]) {
87+
const newSettings = val.map((it, index) => ({
88+
libraryId: it.id,
89+
patch: {
90+
order: index,
91+
},
92+
} as ClientSettingLibraryUpdate))
93+
94+
this.$store.dispatch('updateLibrariesSettings', newSettings)
95+
},
96+
immediate: true,
97+
},
98+
},
99+
methods: {
100+
dismiss() {
101+
this.$emit('dismiss')
102+
},
103+
unpin(libraryId: string) {
104+
this.$store.dispatch('updateLibrarySetting', {
105+
libraryId: libraryId,
106+
patch: {
107+
unpinned: true,
108+
},
109+
} as ClientSettingLibraryUpdate)
110+
this.localItems.find(it => it.id == libraryId).unpinned = true
111+
},
112+
pin(libraryId: string) {
113+
this.$store.dispatch('updateLibrarySetting', {
114+
libraryId: libraryId,
115+
patch: {
116+
unpinned: false,
117+
},
118+
} as ClientSettingLibraryUpdate)
119+
this.localItems.find(it => it.id == libraryId).unpinned = false
120+
},
121+
},
122+
})
123+
</script>
124+
125+
<style scoped>
126+
.handle {
127+
cursor: grab !important;
128+
}
129+
130+
.ghost {
131+
opacity: 0.5;
132+
background: #c8ebfb;
133+
}
134+
</style>

komga-webui/src/components/dialogs/UserRestrictionsEditDialog.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ export default Vue.extend({
188188
},
189189
computed: {
190190
libraries(): LibraryDto[] {
191-
return this.$store.getters.getLibraries
191+
return this.$store.state.komgaLibraries.libraries
192192
},
193193
ageRestrictionsAvailable(): any[] {
194194
return [

komga-webui/src/components/menus/LibrariesActionsMenu.vue

+10-5
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
<template>
22
<div>
3-
<v-menu offset-y v-if="isAdmin">
3+
<v-menu offset-y>
44
<template v-slot:activator="{ on }">
55
<v-btn icon v-on="on" @click.prevent="">
66
<v-icon>mdi-dots-vertical</v-icon>
77
</v-btn>
88
</template>
99
<v-list dense>
10-
<v-list-item @click="scan(false)">
10+
<v-list-item @click="reorder">
11+
<v-list-item-title>{{ $t('common.reorder') }}</v-list-item-title>
12+
</v-list-item>
13+
<v-list-item @click="scan(false)" v-if="isAdmin">
1114
<v-list-item-title>{{ $t('server.server_management.button_scan_libraries') }}</v-list-item-title>
1215
</v-list-item>
13-
<v-list-item @click="scan(true)" class="list-warning">
16+
<v-list-item @click="scan(true)" class="list-warning" v-if="isAdmin">
1417
<v-list-item-title>{{ $t('server.server_management.button_scan_libraries_deep') }}</v-list-item-title>
1518
</v-list-item>
16-
<v-list-item @click="confirmEmptyTrash = true">
19+
<v-list-item @click="confirmEmptyTrash = true" v-if="isAdmin">
1720
<v-list-item-title>{{ $t('server.server_management.button_empty_trash') }}</v-list-item-title>
1821
</v-list-item>
1922
</v-list>
@@ -31,7 +34,6 @@
3134
<script lang="ts">
3235
import Vue from 'vue'
3336
import ConfirmationDialog from '@/components/dialogs/ConfirmationDialog.vue'
34-
import {LibraryDto} from '@/types/komga-libraries'
3537
3638
export default Vue.extend({
3739
name: 'LibrariesActionsMenu',
@@ -47,6 +49,9 @@ export default Vue.extend({
4749
},
4850
},
4951
methods: {
52+
reorder() {
53+
this.$emit('reorder')
54+
},
5055
scan(scanDeep: boolean) {
5156
this.$store.state.komgaLibraries.libraries.forEach(library => {
5257
this.$komgaLibraries.scanLibrary(library, scanDeep)

komga-webui/src/locales/en.json

+1
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@
269269
"readlist": "Read List",
270270
"readlists": "Read Lists",
271271
"remember-me": "Remember me",
272+
"reorder": "Reorder",
272273
"required": "Required",
273274
"reset_filters": "Reset filters",
274275
"roles": "Roles",

komga-webui/src/plugins/komga-libraries.plugin.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const vuexModule: Module<any, any> = {
1515
const settings = getters.getClientSettingsLibraries
1616
return state.libraries
1717
.map((it: LibraryDto) => Object.assign({}, it, settings[it.id]))
18-
.sort((a: LibraryDto, b: LibraryDto) => a.name.toLowerCase() > b.name.toLowerCase())
18+
.sort((a: LibraryDto, b: LibraryDto) => a.order > b.order)
1919
},
2020
getLibraryById: (state, getters) => (id: number) => {
2121
return getters.getLibraries.find((l: any) => l.id === id)

komga-webui/src/plugins/komga-settings.plugin.ts

+11
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,17 @@ const vuexModule: Module<any, any> = {
5555
await service.updateClientSettingUser(newSettings)
5656
dispatch('getClientSettingsUser')
5757
},
58+
async updateLibrariesSettings({dispatch, getters}, updates: ClientSettingLibraryUpdate[]) {
59+
const all = getters.getClientSettingsLibraries
60+
updates.forEach(u => all[u.libraryId] = Object.assign({}, all[u.libraryId], u.patch))
61+
62+
const newSettings = {} as Record<string, ClientSettingUserUpdateDto>
63+
newSettings[CLIENT_SETTING.WEBUI_LIBRARIES] = {
64+
value: JSON.stringify(all),
65+
}
66+
await service.updateClientSettingUser(newSettings)
67+
dispatch('getClientSettingsUser')
68+
},
5869
},
5970
}
6071

komga-webui/src/views/BrowseCollection.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ export default Vue.extend({
341341
},
342342
async resetParams(route: any, collectionId: string) {
343343
// load dynamic filters
344-
this.$set(this.filterOptions, 'library', this.$store.getters.getLibraries.map((x: LibraryDto) => ({
344+
this.$set(this.filterOptions, 'library', this.$store.state.komgaLibraries.libraries.map((x: LibraryDto) => ({
345345
name: x.name,
346346
value: x.id,
347347
})))

komga-webui/src/views/BrowseReadList.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ export default Vue.extend({
355355
},
356356
async resetParams(route: any, readListId: string) {
357357
// load dynamic filters
358-
this.$set(this.filterOptions, 'library', this.$store.getters.getLibraries.map((x: LibraryDto) => ({
358+
this.$set(this.filterOptions, 'library', this.$store.state.komgaLibraries.libraries.map((x: LibraryDto) => ({
359359
name: x.name,
360360
value: x.id,
361361
})))

0 commit comments

Comments
 (0)