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--;
});
}
}