Sub inter-epoch handling

This commit is contained in:
Daniel Compton 2018-02-07 17:38:38 +13:00
parent c427974800
commit 9d90992470
6 changed files with 157 additions and 44 deletions

View File

@ -9,6 +9,7 @@
[binaryage/devtools "0.9.4"] [binaryage/devtools "0.9.4"]
[cljsjs/react-flip-move "2.9.17-0"] [cljsjs/react-flip-move "2.9.17-0"]
[com.yahoo.platform.yui/yuicompressor "2.4.8" :exclusions [rhino/js]] [com.yahoo.platform.yui/yuicompressor "2.4.8" :exclusions [rhino/js]]
[expound "0.4.0"]
] ]
:plugins [[thomasa/mranderson "0.4.7"] :plugins [[thomasa/mranderson "0.4.7"]
[lein-less "RELEASE"]] [lein-less "RELEASE"]]

View File

@ -536,7 +536,7 @@
;; like its reagent id, when it was created, run, disposed, what values it returned, e.t.c. ;; like its reagent id, when it was created, run, disposed, what values it returned, e.t.c.
subscription-info (metam/subscription-info (get-in db [:epochs :subscription-info] {}) filtered-traces (get-in db [:app-db :reagent-id])) subscription-info (metam/subscription-info (get-in db [:epochs :subscription-info] {}) filtered-traces (get-in db [:app-db :reagent-id]))
sub-state (get-in db [:epochs :sub-state] metam/initial-sub-state) sub-state (get-in db [:epochs :sub-state] metam/initial-sub-state)
subscription-match-state (metam/subscription-match-state sub-state filtered-traces new-matches) subscription-match-state (utils/spy "SUB" (metam/subscription-match-state sub-state filtered-traces new-matches))
subscription-matches (rest subscription-match-state) subscription-matches (rest subscription-match-state)
new-sub-state (last subscription-match-state) new-sub-state (last subscription-match-state)
timing (mapv (fn [match] timing (mapv (fn [match]

View File

@ -2,7 +2,7 @@
(defn id-between-xf (defn id-between-xf
;; Copied here because I got undeclared Var warnings from figwheel when requiring a CLJC utils ns. ;; Copied here because I got undeclared Var warnings from figwheel when requiring a CLJC utils ns.
"Returns a transducer that filters for :id between beginning and ending." "Returns a transducer that filters for :id between beginning and ending. Inclusive on both ends."
[beginning ending] [beginning ending]
(filter #(<= beginning (:id %) ending))) (filter #(<= beginning (:id %) ending)))
@ -208,7 +208,7 @@
(def initial-sub-state (def initial-sub-state
{:last-matched-id 0 {:last-matched-id 0
:reaction-state {}}) :reaction-state {}})
(defn parse-traces [parse-state traces] (defn parse-traces [parse-state traces]
(reduce (reduce
@ -278,42 +278,96 @@
3))) 3)))
initial-state))) initial-state)))
(defn reset-sub-state
"Remove information about the subscription that is transient and specific to a single
phase."
[state]
(into {}
(comp
(filter (fn [me] (when-not (:disposed? (val me)) me)))
(map (fn [[k v]]
[k (dissoc v :order :created? :run? :disposed? :previous-value)])))
state))
(defn process-sub-traces
[initial-state traces]
(reduce (fn [state trace]
(let [tags (get trace :tags)
reaction-id (:reaction tags)]
(case (:op-type trace)
:sub/create (assoc state reaction-id {:created? true
:subscription (:query-v tags)
:order [:sub/create]})
:sub/run (update state reaction-id (fn [sub-state]
(-> (if (contains? sub-state :value)
(assoc sub-state :previous-value (:value sub-state))
sub-state)
(assoc :run? true
:value (:value tags))
(update :order (fnil conj []) :sub/run))))
:sub/dispose (-> (assoc-in state [reaction-id :disposed?] true)
(update-in [reaction-id :order] (fnil conj []) :sub/dispose))
(do #?(:cljs (js/console.warn "Unhandled sub trace, this is a bug, report to re-frame-trace please" trace))
state))))
initial-state
traces))
(defn subscription-match-state (defn subscription-match-state
"Build up the state of re-frame's running subscriptions over each matched epoch. "Build up the state of re-frame's running subscriptions over each matched epoch.
Returns initial state as first item in list" Returns initial state as first item in list"
[sub-state filtered-traces new-matches] [sub-state filtered-traces new-matches]
;; For each match that we process there are two phases:
;; - Phase 1: Update and collect the state of the subscriptions that have trace between the last epoch
;; and the new epoch. These traces can be from hover state, local ratom events, figwheel re-renders
;; or rft resetting app-db. Most of the time these traces are noisy and not interesting, but we do
;; need to use them to maintain our subscription state. We also want to show them down below the main
;; subs, in case someone is wondering where they went. If there are no sub traces to process then
;; this phase doesn't run.
;; - Phase 2: Update and collect the state of the subscription traces within an epoch. These subscription
;; traces are going to be changing because of app-db changes.
;; We collect and present the state for both phases for consumption in the subs panel
;#?(:cljs (js/console.log "New matches?" (not (empty? new-matches))))
(reductions (fn [state match] (reductions (fn [state match]
(let [epoch-traces (into [] (let [previous-id (:last-matched-id state)
(comp first-match-id (:id (first match))
(id-between-xf (:id (first match)) (:id (last match))) last-match-id (:id (last match))
(filter subscription?)) pre-epoch-traces (into []
filtered-traces) (comp
reset-state (into {} (id-between-xf (inc previous-id)
(comp (dec first-match-id))
(filter (fn [me] (when-not (:disposed? (val me)) me))) (filter subscription?))
(map (fn [[k v]] filtered-traces)
[k (dissoc v :order :created? :run? :disposed? :previous-value)]))) epoch-traces (into []
(:reaction-state state))] (comp
(->> epoch-traces (id-between-xf first-match-id last-match-id)
(reduce (fn [state trace] (filter subscription?))
(let [tags (get trace :tags) filtered-traces)
reaction-id (:reaction tags)] reset-rx-state (reset-sub-state (:reaction-state state))]
(case (:op-type trace) (-> (->> epoch-traces
:sub/create (assoc state reaction-id {:created? true (reduce (fn [state trace]
:subscription (:query-v tags) (let [tags (get trace :tags)
:order [:sub/create]}) reaction-id (:reaction tags)]
:sub/run (update state reaction-id (fn [sub-state] (case (:op-type trace)
(-> (if (contains? sub-state :value) :sub/create (assoc state reaction-id {:created? true
(assoc sub-state :previous-value (:value sub-state)) :subscription (:query-v tags)
sub-state) :order [:sub/create]})
(assoc :run? true :sub/run (update state reaction-id (fn [sub-state]
:value (:value tags)) (-> (if (contains? sub-state :value)
(update :order (fnil conj []) :sub/run)))) (assoc sub-state :previous-value (:value sub-state))
:sub/dispose (-> (assoc-in state [reaction-id :disposed?] true) sub-state)
(update-in [reaction-id :order] (fnil conj []) :sub/dispose)) (assoc :run? true
(do #?(:cljs (js/console.warn "Unhandled sub trace, this is a bug, report to re-frame-trace please" trace)) :value (:value tags))
state)))) (update :order (fnil conj []) :sub/run))))
reset-state) :sub/dispose (-> (assoc-in state [reaction-id :disposed?] true)
(assoc state :reaction-state)))) (update-in [reaction-id :order] (fnil conj []) :sub/dispose))
(do #?(:cljs (js/console.warn "Unhandled sub trace, this is a bug, report to re-frame-trace please" trace))
state))))
reset-rx-state)
(assoc state :reaction-state))
(assoc :first-matched-id first-match-id
:last-matched-id last-match-id
:previous-matched-id previous-id))))
sub-state sub-state
new-matches)) new-matches))

View File

@ -2,7 +2,9 @@
(:require [mranderson047.re-frame.v0v10v2.re-frame.core :as rf] (:require [mranderson047.re-frame.v0v10v2.re-frame.core :as rf]
[day8.re-frame.trace.metamorphic :as metam] [day8.re-frame.trace.metamorphic :as metam]
[day8.re-frame.trace.utils.utils :as utils] [day8.re-frame.trace.utils.utils :as utils]
[clojure.string :as str])) [clojure.string :as str]
[cljs.spec.alpha :as s]
[expound.alpha :as expound]))
(rf/reg-sub (rf/reg-sub
:settings/root :settings/root
@ -390,6 +392,38 @@
(fn [match-state] (fn [match-state]
(:sub-state match-state))) (:sub-state match-state)))
(def string! (s/and string? #(not (empty? %))))
(s/def :sub/id string!)
(s/def :sub/reagent-id string!)
(s/def :sub/type #{:created :re-run :destroyed :not-run})
(s/def :sub/layer pos-int?)
(s/def :sub/path-data any?)
(s/def :sub/path string!)
(s/def :sub/value any?)
(s/def :sub/previous-value any?)
(s/def :subs/view-panel-sub
(s/keys :req-un [:sub/id :sub/reagent-id :sub/type :sub/layer :sub/path-data :sub/path]
:opt-un [:sub/value :sub/previous-value]))
(s/def :subs/view-subs (s/coll-of :subs/view-panel-sub))
(rf/reg-sub
:subs/inter-epoch-subs
(fn [db]
(let [sub
[{:id ":test1"
:reagent-id "ra87"
:type :created
:layer 3
:path-data [:test/sub]
:path (pr-str [:test/sub])
:value 5
:previous-value 3}]]
(when-not (s/valid? :subs/view-subs sub)
(js/console.error (expound/expound-str :subs/view-subs sub)))
sub)))
(defn sub-sort-val (defn sub-sort-val
[sub] [sub]
(case (:type sub) (case (:type sub)
@ -464,8 +498,12 @@
(filter (fn [[k v]] (< 1 v))) (filter (fn [[k v]] (< 1 v)))
(frequencies (map :id raw))) (frequencies (map :id raw)))
output (map (fn [sub] (assoc sub :run-times (get run-multiple? (:id sub)))) raw)] output (map (fn [sub] (assoc sub :run-times (get run-multiple? (:id sub)))) raw)
(sort-by identity subscription-comparator output)))) subs (sort-by identity subscription-comparator output)]
(when-not (s/valid? :subs/view-subs subs)
(js/console.error (expound/expound-str :subs/view-subs subs)))
subs
)))
(rf/reg-sub (rf/reg-sub
:subs/visible-subs :subs/visible-subs

View File

@ -149,7 +149,7 @@
[rc/v-box [rc/v-box
:size "auto" :size "auto"
:style {:margin-left common/gs-19s :style {:margin-left common/gs-19s
:overflow-y (if (contains? #{:timing :debug :event} @selected-tab) :overflow-y (if (contains? #{:timing :debug :event :subs} @selected-tab)
"auto" "initial") "auto" "initial")
;:overflow "auto" ;; TODO: Might have to put this back or add scrolling within the panels ;:overflow "auto" ;; TODO: Might have to put this back or add scrolling within the panels
} }

View File

@ -236,12 +236,13 @@
(defn pod-section [] (defn pod-section []
(let [visible-subs @(rf/subscribe [:subs/visible-subs]) (let [visible-subs @(rf/subscribe [:subs/visible-subs])
inter-epoch-subs @(rf/subscribe [:subs/inter-epoch-subs])
sub-expansions @(rf/subscribe [:subs/sub-expansions]) sub-expansions @(rf/subscribe [:subs/sub-expansions])
all-subs (if @(rf/subscribe [:settings/debug?]) all-subs (if @(rf/subscribe [:settings/debug?])
(cons {:path [:subs/current-epoch-sub-state] :id "debug" :value @(rf/subscribe [:subs/current-epoch-sub-state])} visible-subs) (cons {:path [:subs/current-epoch-sub-state] :id "debug" :value @(rf/subscribe [:subs/current-epoch-sub-state])} visible-subs)
visible-subs)] visible-subs)]
[rc/v-box [rc/v-box
:size "1" ;:size "1"
;:gap pod-gap ;:gap pod-gap
;:children (if (empty? all-subs) ;:children (if (empty? all-subs)
@ -253,16 +254,35 @@
:children [(if (and (empty? all-subs) @*finished-animation?) :children [(if (and (empty? all-subs) @*finished-animation?)
[no-pods] [no-pods]
[rc/box :width "0px" :height "0px"]) [rc/box :width "0px" :height "0px"])
[animated/component
(for [p all-subs]
^{:key (:id p)}
[pod (merge p (get sub-expansions (:id p)))])
#_[animated/component
(animated/v-box-options {:on-finish #(reset! *finished-animation? true) (animated/v-box-options {:on-finish #(reset! *finished-animation? true)
:duration animation-duration :duration animation-duration
:style {:flex "1 1 0px" :style {:flex "1 1 0px"
:overflow-x "hidden" :overflow-x "hidden"
:overflow-y "auto"}}) :overflow-y "auto"}})
(for [p all-subs] ]
^{:key (:id p)} [rc/line :size "5px"
[pod (merge p (get sub-expansions (:id p)))])]] :style {:margin "19px 0px"}]
[:h2 {:class "bm-heading-text"
:style {:margin "19px 0px"}} "Inter-epoch subscriptions"]
(for [p inter-epoch-subs]
^{:key (:id p)}
[pod (merge p (get sub-expansions (:id p)))])
#_[animated/component
(animated/v-box-options {:on-finish #(reset! *finished-animation? true)
:duration animation-duration
:style {:flex "1 1 0px"
:overflow-x "hidden"
:overflow-y "auto"}})
]
]
])) ]))