🐛 Fix race conditions on profile and teams loading.

This commit is contained in:
Andrey Antukh 2021-04-13 11:57:52 +02:00
parent 464a686c04
commit 99bcf0484a
8 changed files with 51 additions and 49 deletions

View file

@ -14,7 +14,7 @@
[app.config :as cfg] [app.config :as cfg]
[app.main.data.auth :as da] [app.main.data.auth :as da]
[app.main.data.messages :as dm] [app.main.data.messages :as dm]
[app.main.data.users :as udu] [app.main.data.users :as du]
[app.main.repo :as rp] [app.main.repo :as rp]
[app.main.store :as st] [app.main.store :as st]
[app.main.ui :as ui] [app.main.ui :as ui]
@ -91,8 +91,7 @@
(st/emit! (rt/initialize-router ui/routes) (st/emit! (rt/initialize-router ui/routes)
(rt/initialize-history on-navigate) (rt/initialize-history on-navigate)
(udu/fetch-profile) (du/fetch-profile-and-teams)))
(udu/fetch-user-teams)))
(defn reinit (defn reinit
[] []

View file

@ -47,10 +47,10 @@
(watch [this state stream] (watch [this state stream]
(let [team-id (current-team-id profile) (let [team-id (current-team-id profile)
props (:props profile)] props (:props profile)]
(rx/merge (rx/concat
(rx/of (du/profile-fetched profile) (rx/of (du/profile-fetched profile))
(rt/nav' :dashboard-projects {:team-id team-id})) (rx/of (du/fetch-teams))
(rx/of (rt/nav' :dashboard-projects {:team-id team-id}))
(when-not (:onboarding-viewed props) (when-not (:onboarding-viewed props)
(->> (rx/of (modal/show {:type :onboarding})) (->> (rx/of (modal/show {:type :onboarding}))
(rx/delay 1000)))))))) (rx/delay 1000))))))))

View file

@ -65,8 +65,6 @@
;; Data Fetching ;; Data Fetching
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; --- Fetch Team
(defn fetch-team (defn fetch-team
[{:keys [id] :as params}] [{:keys [id] :as params}]
(letfn [(fetched [team state] (letfn [(fetched [team state]
@ -117,7 +115,7 @@
(defn fetch-bundle (defn fetch-bundle
[{:keys [id] :as params}] [{:keys [id] :as params}]
(us/assert ::us/uuid id) (us/assert ::us/uuid id)
(ptk/reify ::fetch-team (ptk/reify ::fetch-bundle
ptk/WatchEvent ptk/WatchEvent
(watch [_ state stream] (watch [_ state stream]
(let [profile (:profile state)] (let [profile (:profile state)]

View file

@ -12,6 +12,7 @@
[app.config :as cf] [app.config :as cf]
[app.common.data :as d] [app.common.data :as d]
[app.common.spec :as us] [app.common.spec :as us]
[app.common.uuid :as uuid]
[app.main.data.media :as di] [app.main.data.media :as di]
[app.main.data.messages :as dm] [app.main.data.messages :as dm]
[app.main.repo :as rp] [app.main.repo :as rp]
@ -47,19 +48,29 @@
::lang ::lang
::theme])) ::theme]))
;; --- Profile Fetched (defn fetch-teams
[]
(letfn [(on-fetched [state data]
(let [teams (d/index-by :id data)]
(assoc state :teams teams)))]
(ptk/reify ::fetch-teams
ptk/WatchEvent
(watch [_ state s]
(->> (rp/query! :teams)
(rx/map (fn [data] #(on-fetched % data))))))))
(defn profile-fetched (defn profile-fetched
[{:keys [fullname id] :as data}] [{:keys [fullname id] :as data}]
(us/verify ::profile data) (us/verify ::profile data)
(ptk/reify ::profile-fetched (ptk/reify ::profile-fetched
IDeref
(-deref [_] data)
ptk/UpdateEvent ptk/UpdateEvent
(update [_ state] (update [_ state]
(-> state (-> state
(assoc :profile-id id) (assoc :profile-id id)
(assoc :profile data) (assoc :profile data)))
;; Safeguard if the profile is loaded after teams
(assoc-in [:profile :teams] (get-in state [:profile :teams]))))
ptk/EffectEvent ptk/EffectEvent
(effect [_ state stream] (effect [_ state stream]
@ -73,12 +84,31 @@
(defn fetch-profile (defn fetch-profile
[] []
(reify (ptk/reify ::fetch-profile
ptk/WatchEvent ptk/WatchEvent
(watch [_ state s] (watch [_ state stream]
(->> (rp/query! :profile) (->> (rp/query! :profile)
(rx/map profile-fetched))))) (rx/map profile-fetched)))))
(defn fetch-profile-and-teams
"Event used mainly on application bootstrap; it fetches the profile
and if and only if the fetched profile corresponds to an
authenticated user; proceed to fetch teams."
[]
(ptk/reify ::fetch-profile-and-teams
ptk/WatchEvent
(watch [_ state stream]
(rx/merge
(rx/of (fetch-profile))
(->> stream
(rx/filter (ptk/type? ::profile-fetched))
(rx/take 1)
(rx/map deref)
(rx/mapcat (fn [profile]
(if (= uuid/zero (:id profile))
(rx/empty)
(rx/of (fetch-teams))))))))))
;; --- Update Profile ;; --- Update Profile
(defn update-profile (defn update-profile
@ -204,24 +234,3 @@
(watch [_ state stream] (watch [_ state stream]
(->> (rp/query :team-users {:team-id team-id}) (->> (rp/query :team-users {:team-id team-id})
(rx/map #(partial fetched %))))))) (rx/map #(partial fetched %)))))))
(defn user-teams-fetched [data]
(ptk/reify ::user-teams-fetched
ptk/UpdateEvent
(update [_ state]
(let [teams (->> data
(group-by :id)
(d/mapm #(first %2)))]
(assoc-in state [:profile :teams] teams)))))
(defn fetch-user-teams []
(ptk/reify ::fetch-user-teams
ptk/WatchEvent
(watch [_ state s]
(->> (rp/query! :teams)
(rx/map user-teams-fetched)
(rx/catch (fn [error]
(if (= (:type error) :not-found)
(rx/of (rt/nav :auth-login))
(rx/empty))))))))

View file

@ -32,6 +32,9 @@
(def profile (def profile
(l/derived :profile st/state)) (l/derived :profile st/state))
(def teams
(l/derived :teams st/state))
(def exception (def exception
(l/derived :exception st/state)) (l/derived :exception st/state))

View file

@ -205,7 +205,7 @@
(mf/defc teams-selector-dropdown (mf/defc teams-selector-dropdown
[{:keys [team profile locale] :as props}] [{:keys [team profile locale] :as props}]
(let [show-dropdown? (mf/use-state false) (let [show-dropdown? (mf/use-state false)
teams (mf/use-state []) teams (mf/deref refs/teams)
on-create-clicked on-create-clicked
(mf/use-callback (mf/use-callback
@ -217,12 +217,6 @@
(da/set-current-team! team-id) (da/set-current-team! team-id)
(st/emit! (rt/nav :dashboard-projects {:team-id team-id}))))] (st/emit! (rt/nav :dashboard-projects {:team-id team-id}))))]
(mf/use-layout-effect
(mf/deps (:id team))
(fn []
(->> (rp/query! :teams)
(rx/subs #(reset! teams %)))))
[:ul.dropdown.teams-dropdown [:ul.dropdown.teams-dropdown
[:li.title (t locale "dashboard.switch-team")] [:li.title (t locale "dashboard.switch-team")]
[:hr] [:hr]
@ -230,7 +224,7 @@
[:span.team-icon i/logo-icon] [:span.team-icon i/logo-icon]
[:span.team-text (t locale "dashboard.your-penpot")]] [:span.team-text (t locale "dashboard.your-penpot")]]
(for [team (remove :is-default @teams)] (for [team (remove :is-default (vals teams))]
[:* {:key (:id team)} [:* {:key (:id team)}
[:li.team-name {:on-click (partial team-selected (:id team))} [:li.team-name {:on-click (partial team-selected (:id team))}
[:span.team-icon [:span.team-icon

View file

@ -271,7 +271,6 @@
(mf/use-effect (mf/use-effect
(mf/deps file-id page-id token) (mf/deps file-id page-id token)
(fn [] (fn []
(prn "viewer-page$use-effect")
(st/emit! (dv/initialize props)))) (st/emit! (dv/initialize props))))
(mf/use-effect (mf/use-effect

View file

@ -188,12 +188,12 @@
total (count frames) total (count frames)
locale (mf/deref i18n/locale) locale (mf/deref i18n/locale)
profile (mf/deref refs/profile) profile (mf/deref refs/profile)
anonymous? (= uuid/zero (:id profile)) teams (mf/deref refs/teams)
team-id (get-in data [:project :team-id]) team-id (get-in data [:project :team-id])
has-permission? (and (not anonymous?) has-permission? (and (not= uuid/zero (:id profile))
(contains? (:teams profile) team-id)) (contains? teams team-id))
project-id (get-in data [:project :id]) project-id (get-in data [:project :id])
file-id (get-in data [:file :id]) file-id (get-in data [:file :id])