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"]
[cljsjs/react-flip-move "2.9.17-0"]
[com.yahoo.platform.yui/yuicompressor "2.4.8" :exclusions [rhino/js]]
[expound "0.4.0"]
]
:plugins [[thomasa/mranderson "0.4.7"]
[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.
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)
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)
new-sub-state (last subscription-match-state)
timing (mapv (fn [match]

View File

@ -2,7 +2,7 @@
(defn id-between-xf
;; 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]
(filter #(<= beginning (:id %) ending)))
@ -208,7 +208,7 @@
(def initial-sub-state
{:last-matched-id 0
:reaction-state {}})
:reaction-state {}})
(defn parse-traces [parse-state traces]
(reduce
@ -278,42 +278,96 @@
3)))
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
"Build up the state of re-frame's running subscriptions over each matched epoch.
Returns initial state as first item in list"
[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]
(let [epoch-traces (into []
(comp
(id-between-xf (:id (first match)) (:id (last match)))
(filter subscription?))
filtered-traces)
reset-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)])))
(:reaction-state state))]
(->> epoch-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))))
reset-state)
(assoc state :reaction-state))))
(let [previous-id (:last-matched-id state)
first-match-id (:id (first match))
last-match-id (:id (last match))
pre-epoch-traces (into []
(comp
(id-between-xf (inc previous-id)
(dec first-match-id))
(filter subscription?))
filtered-traces)
epoch-traces (into []
(comp
(id-between-xf first-match-id last-match-id)
(filter subscription?))
filtered-traces)
reset-rx-state (reset-sub-state (:reaction-state state))]
(-> (->> epoch-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))))
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
new-matches))

View File

@ -2,7 +2,9 @@
(:require [mranderson047.re-frame.v0v10v2.re-frame.core :as rf]
[day8.re-frame.trace.metamorphic :as metam]
[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
:settings/root
@ -390,6 +392,38 @@
(fn [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
[sub]
(case (:type sub)
@ -464,8 +498,12 @@
(filter (fn [[k v]] (< 1 v)))
(frequencies (map :id raw)))
output (map (fn [sub] (assoc sub :run-times (get run-multiple? (:id sub)))) raw)]
(sort-by identity subscription-comparator output))))
output (map (fn [sub] (assoc sub :run-times (get run-multiple? (:id sub)))) raw)
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
:subs/visible-subs

View File

@ -149,7 +149,7 @@
[rc/v-box
:size "auto"
: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")
;:overflow "auto" ;; TODO: Might have to put this back or add scrolling within the panels
}

View File

@ -236,12 +236,13 @@
(defn pod-section []
(let [visible-subs @(rf/subscribe [:subs/visible-subs])
inter-epoch-subs @(rf/subscribe [:subs/inter-epoch-subs])
sub-expansions @(rf/subscribe [:subs/sub-expansions])
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)
visible-subs)]
[rc/v-box
:size "1"
;:size "1"
;:gap pod-gap
;:children (if (empty? all-subs)
@ -253,16 +254,35 @@
:children [(if (and (empty? all-subs) @*finished-animation?)
[no-pods]
[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)
:duration animation-duration
:style {:flex "1 1 0px"
:overflow-x "hidden"
:overflow-y "auto"}})
(for [p all-subs]
^{:key (:id p)}
[pod (merge p (get sub-expansions (:id p)))])]]
]
[rc/line :size "5px"
: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"}})
]
]
]))