From b9e128683a2a96b804adc00294410d45586fac49 Mon Sep 17 00:00:00 2001 From: Sebastien DUMETZ Date: Tue, 27 Feb 2024 12:13:31 +0100 Subject: [PATCH] basic pagination in scenes list --- source/ui/screens/List.ts | 16 +++++++++++--- source/ui/state/withScenes.ts | 41 ++++++++++++++++++++++++++++++----- 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/source/ui/screens/List.ts b/source/ui/screens/List.ts index 2a514487..5d7b97c0 100644 --- a/source/ui/screens/List.ts +++ b/source/ui/screens/List.ts @@ -146,7 +146,6 @@ interface Upload{ ...(this.list ??[]), ],(i)=>(i as any).key ?? i.name , (scene)=>this.renderScene(mode, scene)) } - ${this.list? null: html`
`} `; @@ -183,12 +182,23 @@ interface Upload{ ${this.t("ui.sortBy")} +
+ ${this.error? html`
+

Error

+ ${this.error} +
+ +
+
`:null} ${listContent} - ${this.dragover ?html`
Drop item here
`:""} + ${this.loading?html`
`:null} + ${this.dragover ?html`
Drop item here
`:""} + ${this.loading?null: html`
+ +
`}
`; diff --git a/source/ui/state/withScenes.ts b/source/ui/state/withScenes.ts index c0e7cf7d..a2d5109f 100644 --- a/source/ui/state/withScenes.ts +++ b/source/ui/state/withScenes.ts @@ -42,17 +42,32 @@ export type OrderDirection = typeof directions[number]; export declare class SceneView{ list : Scene[]; + error : string; + loading : number; access ?:Array; match ?:string; orderBy :OrderBy; orderDirection :OrderDirection; - fetchScenes():Promise; + fetchScenes(append?:Boolean):Promise; } export function withScenes>(baseClass:T) : T & Constructor { class SceneView extends baseClass{ @property() list : Scene[]; + + /** + * Error related to the last fetch attempt. Cleared on success. + */ + @property({type: String, reflect: false}) + error :string = ""; + + /** + * Loadign is a number to prevent race condition when a download is aborted. + * It is set to 0 when not loading, and to a positive number when loading. + */ + @property({type: Number}) + loading :number = 0; #loading = new AbortController(); @@ -83,10 +98,10 @@ export function withScenes>(baseClass:T) : T & } super.update(changedProperties); - } + } - async fetchScenes(){ + async fetchScenes(append=false){ this.#loading.abort(); this.#loading = new AbortController(); @@ -97,13 +112,27 @@ export function withScenes>(baseClass:T) : T & if(this.match) url.searchParams.set("match", this.match); if(this.access?.length) this.access.forEach(a=>url.searchParams.append("access", a)); - url.searchParams.set("limit", "100"); + url.searchParams.set("limit", "20"); + if(append && this.list?.length){ + url.searchParams.set("offset", this.list.length.toString()); + } + + this.loading++; fetch(url, {signal: this.#loading.signal}).then(async (r)=>{ if(!r.ok) throw new Error(`[${r.status}]: ${r.statusText}`); - this.list = ((await r.json()) as ApiResult).scenes; + const {scenes} = await r.json() as ApiResult; + if(append && this.list?.length){ + this.list = [...this.list, ...scenes]; + }else{ + this.list = scenes; + } + this.error = null; }).catch((e)=> { if(e.name == "AbortError") return; - Notification.show(`Failed to fetch scenes list : ${e.message}`, "error"); + Notification.show(`Failed to fetch scenes list : ${e.message}`, "error", 4000); + this.error = `Failed to fetch scenes list : ${e.message}`; + }).finally(()=>{ + this.loading--; }); } }