Skip to content

Commit

Permalink
perf(webui): readlist/collection expansion panels load data by page
Browse files Browse the repository at this point in the history
Refs: #817
  • Loading branch information
gotson committed Jan 18, 2023
1 parent ff70fea commit 0b57dc9
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 28 deletions.
38 changes: 26 additions & 12 deletions komga-webui/src/components/CollectionsExpansionPanels.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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',
Expand All @@ -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>
38 changes: 26 additions & 12 deletions komga-webui/src/components/ReadListsExpansionPanels.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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',
Expand All @@ -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>
15 changes: 11 additions & 4 deletions komga-webui/src/types/pageLoader.ts
Original file line number Diff line number Diff line change
@@ -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[] = []
Expand All @@ -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() {
Expand All @@ -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++
}

Expand All @@ -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
}
Expand All @@ -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
}
Expand Down

0 comments on commit 0b57dc9

Please sign in to comment.