mirror of
https://github.com/gotson/komga.git
synced 2025-12-06 08:32:25 +01:00
perf(webui): readlist/collection expansion panels load data by page
Refs: #817
This commit is contained in:
parent
ff70fea71a
commit
0b57dc9c96
3 changed files with 63 additions and 28 deletions
|
|
@ -5,14 +5,18 @@
|
|||
>
|
||||
<v-expansion-panel-header>{{ $t('collections_expansion_panel.title', {name: c.name}) }}</v-expansion-panel-header>
|
||||
<v-expansion-panel-content>
|
||||
<horizontal-scroller>
|
||||
<horizontal-scroller
|
||||
:tick="collectionsLoaders[index].tick"
|
||||
@scroll-changed="(percent) => scrollChanged(collectionsLoaders[index], percent)"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<router-link class="text-overline"
|
||||
:to="{name: 'browse-collection', params: {collectionId: c.id}}"
|
||||
>{{ $t('collections_expansion_panel.manage_collection') }}</router-link>
|
||||
>{{ $t('collections_expansion_panel.manage_collection') }}
|
||||
</router-link>
|
||||
</template>
|
||||
<template v-slot:content>
|
||||
<item-browser :items="collectionsContent[index]"
|
||||
<item-browser :items="collectionsLoaders[index].items"
|
||||
nowrap
|
||||
:selectable="false"
|
||||
:action-menu="false"
|
||||
|
|
@ -31,6 +35,7 @@ import ItemBrowser from '@/components/ItemBrowser.vue'
|
|||
import Vue from 'vue'
|
||||
import {ContextOrigin} from '@/types/context'
|
||||
import {SeriesDto} from '@/types/komga-series'
|
||||
import {PageLoader} from '@/types/pageLoader'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'CollectionsExpansionPanels',
|
||||
|
|
@ -47,27 +52,36 @@ export default Vue.extend({
|
|||
data: () => {
|
||||
return {
|
||||
collectionPanel: undefined as number | undefined,
|
||||
collectionsContent: [[]] as any[],
|
||||
collectionsLoaders: [] as PageLoader<SeriesDto>[],
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
collections: {
|
||||
handler (val) {
|
||||
handler(val: CollectionDto[]) {
|
||||
this.collectionPanel = undefined
|
||||
this.collectionsContent = [...Array(val.length)].map(elem => new Array(0))
|
||||
this.collectionsLoaders = val.map(coll => new PageLoader<SeriesDto>(
|
||||
{},
|
||||
(pageable: PageRequest) => this.$komgaCollections.getSeries(coll.id, pageable),
|
||||
(x: SeriesDto) => {
|
||||
x.context = {origin: ContextOrigin.COLLECTION, id: coll.id}
|
||||
return x
|
||||
},
|
||||
))
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
async collectionPanel (val) {
|
||||
async collectionPanel(val) {
|
||||
if (val !== undefined) {
|
||||
const collId = this.collections[val].id
|
||||
if (this.$_.isEmpty(this.collectionsContent[val])) {
|
||||
const content = (await this.$komgaCollections.getSeries(collId, { unpaged: true } as PageRequest)).content
|
||||
content.forEach((x: SeriesDto) => x.context = { origin: ContextOrigin.COLLECTION, id: collId })
|
||||
this.collectionsContent.splice(val, 1, content)
|
||||
if (!this.collectionsLoaders[val].hasLoadedAny) {
|
||||
this.collectionsLoaders[val].loadNext()
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async scrollChanged(loader: PageLoader<any>, percent: number) {
|
||||
if (percent > 0.95) await loader.loadNext()
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -5,14 +5,18 @@
|
|||
>
|
||||
<v-expansion-panel-header>{{ $t('readlists_expansion_panel.title', {name: r.name}) }}</v-expansion-panel-header>
|
||||
<v-expansion-panel-content>
|
||||
<horizontal-scroller>
|
||||
<horizontal-scroller
|
||||
:tick="readListsLoaders[index].tick"
|
||||
@scroll-changed="(percent) => scrollChanged(readListsLoaders[index], percent)"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<router-link class="text-overline"
|
||||
:to="{name: 'browse-readlist', params: {readListId: r.id}}"
|
||||
>{{ $t('readlists_expansion_panel.manage_readlist') }}</router-link>
|
||||
>{{ $t('readlists_expansion_panel.manage_readlist') }}
|
||||
</router-link>
|
||||
</template>
|
||||
<template v-slot:content>
|
||||
<item-browser :items="readListsContent[index]"
|
||||
<item-browser :items="readListsLoaders[index].items"
|
||||
:item-context="[ItemContext.SHOW_SERIES]"
|
||||
nowrap
|
||||
:selectable="false"
|
||||
|
|
@ -33,6 +37,7 @@ import Vue from 'vue'
|
|||
import {BookDto} from '@/types/komga-books'
|
||||
import {ContextOrigin} from '@/types/context'
|
||||
import {ItemContext} from '@/types/items'
|
||||
import {PageLoader} from '@/types/pageLoader'
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'ReadListsExpansionPanels',
|
||||
|
|
@ -50,27 +55,36 @@ export default Vue.extend({
|
|||
return {
|
||||
ItemContext,
|
||||
readListPanel: undefined as number | undefined,
|
||||
readListsContent: [[]] as any[],
|
||||
readListsLoaders: [] as PageLoader<BookDto>[],
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
readLists: {
|
||||
handler (val) {
|
||||
handler(val: ReadListDto[]) {
|
||||
this.readListPanel = undefined
|
||||
this.readListsContent = [...Array(val.length)].map(elem => new Array(0))
|
||||
this.readListsLoaders = val.map(rl => new PageLoader<BookDto>(
|
||||
{},
|
||||
(pageable: PageRequest) => this.$komgaReadLists.getBooks(rl.id, pageable),
|
||||
(x: BookDto) => {
|
||||
x.context = {origin: ContextOrigin.READLIST, id: rl.id}
|
||||
return x
|
||||
},
|
||||
))
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
async readListPanel (val) {
|
||||
async readListPanel(val) {
|
||||
if (val !== undefined) {
|
||||
const rlId = this.readLists[val].id
|
||||
if (this.$_.isEmpty(this.readListsContent[val])) {
|
||||
const content = (await this.$komgaReadLists.getBooks(rlId, { unpaged: true } as PageRequest)).content
|
||||
content.forEach((x: BookDto) => x.context = { origin: ContextOrigin.READLIST, id: rlId })
|
||||
this.readListsContent.splice(val, 1, content)
|
||||
if (!this.readListsLoaders[val].hasLoadedAny) {
|
||||
this.readListsLoaders[val].loadNext()
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async scrollChanged(loader: PageLoader<any>, percent: number) {
|
||||
if (percent > 0.95) await loader.loadNext()
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
export class PageLoader<T> {
|
||||
private readonly pageable: PageRequest
|
||||
private readonly loader: (pageRequest: PageRequest) => Promise<Page<T>>
|
||||
private readonly postProcessor: (item: T) => T
|
||||
|
||||
private currentPage = undefined as unknown as Page<T>
|
||||
private loadedPages: number[] = []
|
||||
|
|
@ -15,9 +16,15 @@ export class PageLoader<T> {
|
|||
return this._tick
|
||||
}
|
||||
|
||||
constructor(pageable: PageRequest, loader: (pageRequest: PageRequest) => Promise<Page<T>>) {
|
||||
// whether anything has been loaded yet
|
||||
get hasLoadedAny() {
|
||||
return this.currentPage
|
||||
}
|
||||
|
||||
constructor(pageable: PageRequest, loader: (pageRequest: PageRequest) => Promise<Page<T>>, postProcessor: (item: T) => T = (item) => item) {
|
||||
this.pageable = pageable
|
||||
this.loader = loader
|
||||
this.postProcessor = postProcessor
|
||||
}
|
||||
|
||||
async reload() {
|
||||
|
|
@ -29,7 +36,7 @@ export class PageLoader<T> {
|
|||
page: 0,
|
||||
})
|
||||
const page = await this.loader(pageable)
|
||||
this.items.splice(0, this.items.length, ...page.content)
|
||||
this.items.splice(0, this.items.length, ...page.content.map(this.postProcessor))
|
||||
this._tick++
|
||||
}
|
||||
|
||||
|
|
@ -38,7 +45,7 @@ export class PageLoader<T> {
|
|||
if (!this.currentPage) {
|
||||
this.loadedPages.push(this.pageable.page || 0)
|
||||
this.currentPage = await this.loader(this.pageable)
|
||||
this.items.push(...this.currentPage.content)
|
||||
this.items.push(...this.currentPage.content.map(this.postProcessor))
|
||||
this._tick++
|
||||
return true
|
||||
}
|
||||
|
|
@ -50,7 +57,7 @@ export class PageLoader<T> {
|
|||
this.loadedPages.push(nextPage)
|
||||
const pageable = Object.assign({}, this.pageable, {page: nextPage})
|
||||
this.currentPage = await this.loader(pageable)
|
||||
this.items.push(...this.currentPage.content)
|
||||
this.items.push(...this.currentPage.content.map(this.postProcessor))
|
||||
this._tick++
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue