Skip to content

Instantly share code, notes, and snippets.

@realgenekim
Created August 10, 2021 18:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save realgenekim/0330b067ff756321d1ba63a3b4008001 to your computer and use it in GitHub Desktop.
Save realgenekim/0330b067ff756321d1ba63a3b4008001 to your computer and use it in GitHub Desktop.
; @tony.kay Good talking yesterday — and you’ve turned me into a believer on UI State Machines.
; You had suggested that instead of replacing each state, one by one, to just copy the entirety into my
; namespace, to make it easier.
;
; Got all the needed changes to lazily load all the Trello card comments very quickly. Eventually, I’ll post the diffs vs. the default RAD report state machine, which will make it more obvious what my changes were. But, just in case, to anyone who might find it helpful, here’s what I did.
;
; change any :: to ::report
; wrote a my-load-report! my-goto-page* and a load-comments-for-page
;
; Surprisingly straightforward to do, as @holyjak and @tony.kay predicted!
(defn load-comments-for-page
" based on populate-current-page"
[uism-env]
(let [current-rows (uism/alias-value uism-env :current-rows)
;(uism/alias-value uism-env :filtered-rows)
_ (println "load-comments-for-page: current-rows: " current-rows)]
;_ (println "load-comments-for-page: uism-env: " uism-env)]
(if (not= current-rows [:trello-card/id nil])
(doseq [c current-rows]
(println "load-comments-for-page: card-id: " c)
;[env key-or-ident component-class-or-actor-name options]
#_(uism/load uism-env c card/Card {:parallel true
:focus [:trello-card/comments]})
(df/load! (resolve 'com.example.client/app) c card/Card
{:parallel true
:focus [:trello-card/comments]})))
uism-env))
(defn my-goto-page*
"Internal state machine implementation. May be used by extensions to the stock state machine."
[env page]
(print "*** my-goto-page* ")
(let [pg (uism/alias-value env :current-page)]
(if (not= pg page)
(-> env
(uism/assoc-aliased :current-page (max 1 page) :selected-row -1)
(report/populate-current-page)
(report/page-number-changed)
(load-comments-for-page))
env)))
(defn my-load-report! [env]
(let [Report (uism/actor-class env :actor/report)
report-ident (uism/actor->ident env :actor/report)
{::report/keys [BodyItem source-attribute]} (comp/component-options Report)
current-params (report/current-control-parameters env)
path (conj report-ident :ui/loaded-data)]
(println "*** my-report-load! ")
(println " path: " path)
(println " current-params: " current-params)
(println " BodyItem: " BodyItem)
(println " source-attribute: " source-attribute)
;(println " env: " env)
(log/warn "Loading report" source-attribute (comp/component-name Report) (comp/component-name BodyItem))
(-> env
(uism/load source-attribute BodyItem {:params current-params
::uism/ok-event :event/loaded
::uism/error-event :event/failed
:without #{:trello-card/comments}
:marker report-ident
:target path})
(uism/activate :state/loading))))
(uism/defstatemachine custom-machine
{::uism/actors
#{:actor/report}
::uism/aliases
{:parameters [:actor/report :ui/parameters]
:sort-params [:actor/report :ui/parameters ::report/sort]
:sort-by [:actor/report :ui/parameters ::report/sort :sort-by]
:ascending? [:actor/report :ui/parameters ::report/sort :ascending?]
:filtered-rows [:actor/report :ui/cache :filtered-rows]
:sorted-rows [:actor/report :ui/cache :sorted-rows]
:raw-rows [:actor/report :ui/loaded-data]
:current-rows [:actor/report :ui/current-rows]
:current-page [:actor/report :ui/parameters ::report/current-page]
:selected-row [:actor/report :ui/parameters ::report/selected-row]
:page-count [:actor/report :ui/page-count]
:busy? [:actor/report :ui/busy?]}
::uism/states
{:initial
{::uism/handler (fn [env]
(let [{::uism/keys [fulcro-app event-data]} env
{::report/keys [run-on-mount?]} (report/report-options env)
page-path (report/route-params-path env ::report/current-page)
desired-page (-> (history/current-route fulcro-app)
:params
(get-in page-path))
run-now? (or desired-page run-on-mount?)]
(-> env
(uism/store :route-params (:route-params event-data))
(cond->
(nil? desired-page) (uism/assoc-aliased :current-page 1))
(report/initialize-parameters)
(cond->
run-now? (my-load-report!)
(not run-now?) (uism/activate :state/gathering-parameters)))))}
:state/loading
(merge report/global-events
{::uism/events
{:event/loaded {::uism/handler (fn [{::uism/keys [state-map] :as env}]
(let [table-name (comp/component-options (uism/actor-class env :actor/report) ::report/row-pk ::attr/qualified-key)]
(-> env
(report/preprocess-raw-result)
(report/filter-rows)
(report/sort-rows)
(report/populate-current-page)
(load-comments-for-page)
(uism/store :last-load-time (inst-ms (dt/now)))
(uism/store :raw-items-in-table (count (keys (get state-map table-name))))
(uism/activate :state/gathering-parameters))))}
:event/failed {::uism/handler (fn [env] (log/error "Report failed to load.")
(uism/activate env :state/gathering-parameters))}}})
:state/gathering-parameters
(merge report/global-events
{::uism/events
{:event/goto-page {::uism/handler (fn [{::uism/keys [event-data] :as env}]
(let [{:keys [page]} event-data]
(my-goto-page* env page)))}
:event/next-page {::uism/handler (fn [env]
(let [page (uism/alias-value env :current-page)]
(my-goto-page* env (inc (max 1 page)))))}
:event/prior-page {::uism/handler (fn [env]
(let [page (uism/alias-value env :current-page)]
(my-goto-page* env (dec (max 2 page)))))}
:event/do-sort {::uism/handler (fn [{::uism/keys [event-data app] :as env}]
(if-let [{::attr/keys [qualified-key]} (get event-data ::attr/attribute)]
(let [sort-by (uism/alias-value env :sort-by)
sort-path (report/route-params-path env ::report/sort)
ascending? (uism/alias-value env :ascending?)
ascending? (if (= qualified-key sort-by)
(not ascending?)
true)]
(rad-routing/update-route-params! app update-in sort-path merge
{:ascending? ascending?
:sort-by qualified-key})
(-> env
(uism/assoc-aliased
:busy? false
:sort-by qualified-key
:ascending? ascending?)
(report/sort-rows)
(report/populate-current-page)))
env))}
:event/select-row {::uism/handler (fn [{::uism/keys [app event-data] :as env}]
(let [row (:row event-data)
selected-row-path (report/route-params-path env ::report/selected-row)]
(when (nat-int? row)
(rad-routing/update-route-params! app assoc-in selected-row-path row))
(uism/assoc-aliased env :selected-row row)))}
:event/sort {::uism/handler (fn [{::uism/keys [app event-data] :as env}]
;; this ensures that the do sort doesn't get the CPU until the busy state is rendered
(uism/trigger! app (uism/asm-id env) :event/do-sort event-data)
(uism/assoc-aliased env :busy? true))}
:event/do-filter {::uism/handler (fn [{::uism/keys [event-data] :as env}]
(-> env
(uism/assoc-aliased :current-page 1 :busy? false)
(report/filter-rows)
(report/sort-rows)
;; TODO: Why isn't this goto-page* 1???
(report/populate-current-page)))}
:event/repaginate {::uism/handler (fn [{::uism/keys [event-data] :as env}]
(-> env
;(uism/assoc-aliased :current-page 1 :busy? false)
(report/filter-rows)
(report/sort-rows)
;; TODO: Why isn't this goto-page* 1???
(report/populate-current-page)))}
:event/filter {::uism/handler (fn [{::uism/keys [app] :as env}]
;; this ensures that the do sort doesn't get the CPU until the busy state is rendered
(uism/trigger! app (uism/asm-id env) :event/do-filter)
(uism/assoc-aliased env :busy? true))}
:event/set-ui-parameters {::uism/handler (fn [env]
(-> env
(report/initialize-parameters)))}
:event/run {::uism/handler my-load-report!}}})}})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment