Handle loading state of parallel long-running updates correctly

This commit is contained in:
arne 2025-11-18 16:42:36 +01:00
commit cb974cb498

View file

@ -1,7 +1,6 @@
(ns computersandblues.lodestone.app (ns computersandblues.lodestone.app
(:require [reagent.core :as r] (:require [reagent.core :as r]
[reagent.dom.client :as rd] [reagent.dom.client :as rd]
[applied-science.js-interop :as j]
[clojure.string :as str] [clojure.string :as str]
[clojure.pprint :as pprint] [clojure.pprint :as pprint]
[computersandblues.lodestone.database :as db] [computersandblues.lodestone.database :as db]
@ -16,6 +15,7 @@
; TODO: Handle other lists ; TODO: Handle other lists
:section/posts {:query nil :section/posts {:query nil
:per-page 50 :per-page 50
:loading #{}
; TODO: pagination ; TODO: pagination
; :page 0 ; :page 0
; :max-displayed-id nil ; :max-displayed-id nil
@ -23,9 +23,7 @@
:total 0 :total 0
:displayed-posts []}})) :displayed-posts []}}))
; TODO Ensure that cached data is up to date
; TODO Ensure that user's handles are up to date
; TODO Manually fetch older / newer favorites ; TODO Manually fetch older / newer favorites
; TODO Handle 429 ; TODO Handle 429
; TODO Search for tags (`#foo`) and handles (`@bar`) ; TODO Search for tags (`#foo`) and handles (`@bar`)
@ -239,17 +237,15 @@
((fn fetch-favorites' [url] ((fn fetch-favorites' [url]
(let [req-id (js/Date.now)] (let [req-id (js/Date.now)]
(println :calling url) (println :calling url)
(swap! state assoc-in [:section/posts :loading] req-id) (swap! state update-in [:section/posts :loading] conj req-id)
(-> (mastodon-request! {:url url :bearer-token bearer-token}) (-> (mastodon-request! {:url url :bearer-token bearer-token})
(.then (fn [response] (.then (fn [response]
(on-response response) (on-response response)
(if (continue? response) (if (continue? response)
(js/setTimeout #(fetch-favorites' (link-header "next" (:raw response))) 500) (js/setTimeout #(fetch-favorites' (link-header "next" (:raw response))) 500)
(when (= req-id (-> @state :section/posts :loading)) (swap! state update-in [:section/posts :loading] disj req-id))))
(swap! state update :section/posts dissoc :loading)))))
(.catch (fn [response] (.catch (fn [response]
(when (= req-id (-> @state :section/posts :loading)) (swap! state update-in [:section/posts :loading] disj req-id)
(swap! state update :section/posts dissoc :loading))
(on-error response)))))) (on-error response))))))
(favorites-url {:instance-url instance-url :max-id max-id}))) (favorites-url {:instance-url instance-url :max-id max-id})))
@ -347,14 +343,14 @@
(take per-page) (take per-page)
(map #(js->clj % :keywordize-keys true))) (map #(js->clj % :keywordize-keys true)))
refresh-id (js/Date.now)] refresh-id (js/Date.now)]
(swap! state assoc-in [:section/posts :loading] refresh-id) (swap! state update-in [:section/posts :loading] conj refresh-id)
(-> (js/Promise.all #js [(db/count! ::db/posts) (-> (js/Promise.all #js [(db/count! ::db/posts)
(-> (db/open-cursor! ::db/posts db/all "prev") (-> (db/open-cursor! ::db/posts db/all "prev")
(db/transduce-cursor xform))]) (db/transduce-cursor xform))])
(.then (fn [[total displayed-posts]] (.then (fn [[total displayed-posts]]
(swap! state update :section/posts #(-> (assoc % :total total) (swap! state update :section/posts #(-> (assoc % :total total)
(assoc :displayed-posts displayed-posts) (assoc :displayed-posts displayed-posts)
(cond-> (= refresh-id (:loading %)) (dissoc :loading))))))))) (update :loading disj refresh-id))))))))
(def debounced-refresh! (debounce 20 (partial refresh-displayed-posts!))) (def debounced-refresh! (debounce 20 (partial refresh-displayed-posts!)))
@ -377,11 +373,11 @@
(str ", displaying " (count displayed-posts) (when query " matches"))))] (str ", displaying " (count displayed-posts) (when query " matches"))))]
[:div.search-form [:div.search-form
[search] [search]
(when loading " …") (when (seq loading) " …")
#_(cond (= api-state :loading) " …" #_(cond (= api-state :loading) " …"
(= api-state :error) " API Error!")]] (= api-state :error) " API Error!")]]
[:ul.results (map-indexed (fn [idx p] [:ul.results (map-indexed (fn [idx p]
^{:key idx} [:li [post {:post p}]]) displayed-posts)] ^{:key idx} [:li.result [post {:post p}]]) displayed-posts)]
#_[:div.load-buttons #_[:div.load-buttons
[:button [:button
{:on-click (fn [_] {:on-click (fn [_]