diff --git a/CHANGELOG.md b/CHANGELOG.md index cb2bc81..cd9844a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file. This change * Switched from LESS to Garden styles. Now interactive development and debugging of re-frame-trace is even faster. * Reopen/reattach external popup windows when reloading host application +* Reorganise namespace layout and remove (hidden) subviz panel and D3 dependency. This may return in the future though. ### Fixed diff --git a/project.clj b/project.clj index 6df5016..62bd858 100644 --- a/project.clj +++ b/project.clj @@ -6,7 +6,6 @@ [org.clojure/clojurescript "1.9.671"] [reagent "0.6.0" :scope "provided"] [re-frame "0.10.2" :scope "provided"] - [cljsjs/d3 "4.3.0-5"] [binaryage/devtools "0.9.4"] [garden "1.3.3"]] :plugins [[thomasa/mranderson "0.4.7"] diff --git a/src/day8/re_frame/trace.cljs b/src/day8/re_frame/trace.cljs index ba7e8b6..4c3d788 100644 --- a/src/day8/re_frame/trace.cljs +++ b/src/day8/re_frame/trace.cljs @@ -1,12 +1,10 @@ (ns day8.re-frame.trace - (:require [day8.re-frame.trace.panels.subvis :as subvis] - [day8.re-frame.trace.panels.app-db :as app-db] + (:require [day8.re-frame.trace.view.app-db :as app-db] [day8.re-frame.trace.styles :as styles] - [day8.re-frame.trace.components.components :as components] - [day8.re-frame.trace.components.container :as container] + [day8.re-frame.trace.view.components :as components] + [day8.re-frame.trace.view.container :as container] [day8.re-frame.trace.utils.localstorage :as localstorage] - [day8.re-frame.trace.panels.traces :as traces] - [day8.re-frame.trace.events] + [day8.re-frame.trace.events :as events] [day8.re-frame.trace.subs] [day8.re-frame.trace.db :as trace.db] [re-frame.trace :as trace :include-macros true] @@ -22,10 +20,8 @@ [reagent.ratom :as ratom] [goog.object :as gob] [re-frame.interop :as interop] - [devtools.formatters.core :as devtools] - [mranderson047.re-frame.v0v10v2.re-frame.core :as rf] - [day8.re-frame.trace.utils.traces :as utils.traces])) + [mranderson047.re-frame.v0v10v2.re-frame.core :as rf])) ;; from https://github.com/reagent-project/reagent/blob/3fd0f1b1d8f43dbf169d136f0f905030d7e093bd/src/reagent/impl/component.cljs#L274 @@ -209,7 +205,7 @@ (defn inject-devtools! [] (styles/inject-trace-styles js/document) - (r/render [devtools-outer utils.traces/traces {:panel-type :inline}] (panel-div))) + (r/render [devtools-outer events/traces {:panel-type :inline}] (panel-div))) (defn init-db! [] (trace.db/init-db)) diff --git a/src/day8/re_frame/trace/components/components.cljs b/src/day8/re_frame/trace/components/components.cljs deleted file mode 100644 index 2e8cb0b..0000000 --- a/src/day8/re_frame/trace/components/components.cljs +++ /dev/null @@ -1,58 +0,0 @@ -(ns day8.re-frame.trace.components.components - (:require [reagent.core :as r] - [clojure.string :as str] - [goog.fx.dom :as fx])) - -(defn search-input [{:keys [title placeholder on-save on-change on-stop]}] - (let [val (r/atom title) - save #(let [v (-> @val str str/trim)] - (when (pos? (count v)) - (on-save v)))] - (fn [] - [:input {:type "text" - :value @val - :auto-focus true - :placeholder placeholder - :size (if (> 20 (count (str @val))) - 25 - (count (str @val))) - :on-change #(do (reset! val (-> % .-target .-value)) - (on-change %)) - :on-key-down #(case (.-which %) - 13 (do - (save) - (reset! val "")) - nil)}]))) - -(defn scroll! [el start end time] - (.play (fx/Scroll. el (clj->js start) (clj->js end) time))) - -(defn scrolled-to-end? [el tolerance] - ;; at-end?: element.scrollHeight - element.scrollTop === element.clientHeight - (> tolerance (- (.-scrollHeight el) (.-scrollTop el) (.-clientHeight el)))) - -(defn autoscroll-list [{:keys [class scroll?]} child] - "Reagent component that enables scrolling for the elements of its child dom-node. - Scrolling is only enabled if the list is scrolled to the end. - Scrolling can be set as option for debugging purposes. - Thanks to Martin Klepsch! Original code can be found here: - https://gist.github.com/martinklepsch/440e6fd96714fac8c66d892e0be2aaa0" - (let [node (r/atom nil) - should-scroll (r/atom true)] - (r/create-class - {:display-name "autoscroll-list" - :component-did-mount - (fn [_] - (scroll! @node [0 (.-scrollTop @node)] [0 (.-scrollHeight @node)] 0)) - :component-will-update - (fn [_] - (reset! should-scroll (scrolled-to-end? @node 100))) - :component-did-update - (fn [_] - (when (and scroll? @should-scroll) - (scroll! @node [0 (.-scrollTop @node)] [0 (.-scrollHeight @node)] 500))) - :reagent-render - (fn [{:keys [class]} child] - [:div {:class class :ref (fn [dom-node] - (reset! node dom-node))} - child])}))) diff --git a/src/day8/re_frame/trace/components/d3.cljs b/src/day8/re_frame/trace/components/d3.cljs deleted file mode 100644 index 65a6ed8..0000000 --- a/src/day8/re_frame/trace/components/d3.cljs +++ /dev/null @@ -1,37 +0,0 @@ -(ns day8.re-frame.trace.components.d3 - (:require [reagent.core :as r])) - -(defn no-op [desc] - (fn [& args] nil)) - -(defn component-did-update [{:keys [d3-update]} ratoms] - (apply d3-update ratoms)) - -(defn component-did-mount [{:keys [d3-once] :as lifecycle-fns} ratoms] - (apply d3-once ratoms) - (component-did-update lifecycle-fns ratoms)) - -(defn create-d3 - "Creates a bridging component from Reagent to D3. Takes a map of - lifecycle functions, and reactive data sources. - - :render-component - Render the outer Reagent component, and a place for your D3 component to mount to (probably an SVG element) - :d3-once - Function called after the component has been rendered, for you to setup anything you need in D3 (e.g. adding or classes) - :d3-update - Run the D3 general update pattern: https://bl.ocks.org/mbostock/3808218 - " - [{:keys [render-component d3-once d3-update] - :or {render-component (no-op :render) - d3-once (no-op :d3-did-mount) - d3-update (no-op :d3-update)}} - & ratoms] - (let [lifecycle-fns {:render-component render-component - :d3-once d3-once - :d3-update d3-update}] - (r/create-class - {:reagent-render (fn [] - (doseq [r ratoms] (deref r)) - (apply render-component ratoms)) - :component-did-mount (fn [this] - (component-did-mount lifecycle-fns ratoms)) - :component-did-update (fn [this old-argv] - (component-did-update lifecycle-fns ratoms))}))) diff --git a/src/day8/re_frame/trace/events.cljs b/src/day8/re_frame/trace/events.cljs index aeedefe..914e77f 100644 --- a/src/day8/re_frame/trace/events.cljs +++ b/src/day8/re_frame/trace/events.cljs @@ -1,15 +1,57 @@ (ns day8.re-frame.trace.events (:require [mranderson047.re-frame.v0v10v2.re-frame.core :as rf] [day8.re-frame.trace.utils.utils :as utils] - [day8.re-frame.trace.utils.traces :as utils.traces] [day8.re-frame.trace.utils.localstorage :as localstorage] [clojure.string :as str] [reagent.core :as r] [goog.object] [re-frame.db] - [day8.re-frame.trace.components.container :as container] + [day8.re-frame.trace.view.container :as container] [day8.re-frame.trace.styles :as styles])) +(defonce traces (r/atom [])) +(defonce total-traces (r/atom 0)) + +(defn log-trace? [trace] + (let [render-operation? (= (:op-type trace) :render) + component-path (get-in trace [:tags :component-path] "")] + (if-not render-operation? + true + (not (str/includes? component-path "devtools outer"))))) + +(defn disable-tracing! [] + (re-frame.trace/remove-trace-cb ::cb)) + +(defn enable-tracing! [] + (re-frame.trace/register-trace-cb ::cb (fn [new-traces] + (when-let [new-traces (filter log-trace? new-traces)] + (swap! total-traces + (count new-traces)) + (swap! traces + (fn [existing] + (let [new (reduce conj existing new-traces) + size (count new)] + (if (< 4000 size) + (let [new2 (subvec new (- size 2000))] + (if (< @total-traces 20000) ;; Create a new vector to avoid structurally sharing all traces forever + (do (reset! total-traces 0) + (into [] new2)))) + new)))))))) + +(defn dissoc-in + "Dissociates an entry from a nested associative structure returning a new + nested structure. keys is a sequence of keys. Any empty maps that result + will not be present in the new structure." + [m [k & ks :as keys]] + (if ks + (if-let [nextmap (clojure.core/get m k)] + (let [newmap (dissoc-in nextmap ks)] + (if (seq newmap) + (assoc m k newmap) + (dissoc m k))) + m) + (dissoc m k))) + + (rf/reg-event-db :settings/panel-width% (fn [db [_ width%]] @@ -35,9 +77,9 @@ external-panel? (get-in db [:settings :external-window?]) using-trace? (or external-panel? now-showing?)] (if now-showing? - (utils.traces/enable-tracing!) + (enable-tracing!) (when-not external-panel? - (utils.traces/disable-tracing!))) + (disable-tracing!))) (localstorage/save! "using-trace?" using-trace?) (localstorage/save! "show-panel" now-showing?) (-> db @@ -55,7 +97,7 @@ [(r/create-class {:display-name "devtools outer external" :reagent-render (fn [] - [container/devtools-inner utils.traces/traces {:panel-type :popup} + [container/devtools-inner traces {:panel-type :popup} ])})] app))) @@ -90,13 +132,13 @@ (rf/reg-event-fx :global/enable-tracing (fn [ctx _] - (utils.traces/enable-tracing!) + (enable-tracing!) nil)) (rf/reg-event-fx :global/disable-tracing (fn [ctx _] - (utils.traces/disable-tracing!) + (disable-tracing!) nil)) (rf/reg-event-fx @@ -151,7 +193,7 @@ (rf/reg-event-db :traces/reset-filter-items (fn [db _] - (let [new-db (utils/dissoc-in db [:traces :filter-items])] + (let [new-db (dissoc-in db [:traces :filter-items])] (save-filter-items (get-in new-db [:traces :filter-items])) new-db))) diff --git a/src/day8/re_frame/trace/panels/subvis.cljs b/src/day8/re_frame/trace/panels/subvis.cljs deleted file mode 100644 index 74eef71..0000000 --- a/src/day8/re_frame/trace/panels/subvis.cljs +++ /dev/null @@ -1,189 +0,0 @@ -(ns day8.re-frame.trace.panels.subvis - (:require cljsjs.d3 - [day8.re-frame.trace.components.d3 :as d3t] - [day8.re-frame.trace.utils.graph :as graph] - [reagent.core :as r] - [re-frame.interop :as interop] - [re-frame.db :as db] - [goog.object :as gob] - [clojure.set :as set])) - -(def width 400) -(def height 400) - -(def prev-graph (atom nil)) -(def mygraph (r/atom {:nodes [{:id 1 :group 1} - {:id 2 :group 1} - {:id 3 :group 2}] - :links [{:source 1 :target 2 :value 1}]})) - -(def app-db-node {:id (interop/reagent-id db/app-db) - :title "app-db" - :group 1 - :r 20 - :fx 15 - :fy (/ height 2)}) - -(defn render-node? [d] - (= "render" (gob/getValueByKeys d "data" "type"))) - -(defn min-max - "Returns x if it is within min-val and max-val - otherwise returns min-val if x is less than min-val - and max-val if x is greater than max-val. - - Essentially this provides a bounding box/clamp around x." - [min-val x max-val] - (assert (<= min-val max-val)) - (cljs.core/max min-val (cljs.core/min x max-val))) - -(defn render-subvis [traces-ratom] - (let [color-a (atom nil) - svg-a (atom nil) - simulation-a (atom nil)] - (fn [] - [:div - [d3t/create-d3 - {:render-component (fn [ratom] - [:svg#d3cmp {:width width :height height}]) - :d3-once (fn [ratom] - (let [svg (reset! svg-a (. js/d3 select "#d3cmp"))] - (reset! color-a (.scaleOrdinal js/d3 (.-schemeCategory20 js/d3))) - (reset! simulation-a - (.. js/d3 - (forceSimulation) - (force "link" (.. js/d3 (forceLink) - (id #(.-id %)) - (distance (constantly 100)))) - (force "charge" (.. js/d3 (forceManyBody) - (strength (constantly -100)))) - (force "center" (. js/d3 forceCenter (/ width 2) (/ height 2))))) - (.. (. svg append "g") - (attr "class" "links")) - (.. (. svg append "g") - (attr "class" "nodes")))) - :d3-update (fn [ratom] - (let [old-g @prev-graph ;; TODO: is this working? - graph (reset! prev-graph (graph/trace->sub-graph @ratom [app-db-node]))] - (when (not= old-g graph) - (let [simulation @simulation-a - color @color-a - svg @svg-a - graph (graph/trace->sub-graph @ratom [app-db-node]) - nodes (clj->js (:nodes graph)) - links (clj->js (:links graph)) - drag-started (fn [d] - (when (zero? (.. js/d3 -event -active)) - (.. simulation - (alphaTarget 0.3) - (restart)))) - dragged (fn [d] - (set! (.-fx d) (.. js/d3 -event -x)) - (set! (.-fy d) (.. js/d3 -event -y))) - drag-ended (fn [d] - (when (zero? (.. js/d3 -event -active)) - (.. simulation - (alphaTarget 0.0))) - (set! (.-fx d) nil) - (set! (.-fy d) nil)) - - ;; Links - link (.. svg - (select "g.links") - (selectAll "line") - (data links #(.-id %))) - enter-link (.. link - (enter) - (append "line") - (attr "stroke-width" (fn [d] (Math/sqrt (.-value d))))) - merged-link (.. enter-link (merge link)) - _ (.. link - (exit) - (remove "line")) - - ;; Nodes - node (.. svg - (select "g.nodes") - (selectAll ".node") - (data nodes #(.-id %))) - enter-node (.. node - (enter) - (append "g") - (attr "class" "node") - (call (.. js/d3 (drag) - (on "start" drag-started) - (on "drag" dragged) - (on "end" drag-ended)))) - circle (.. enter-node - (append "circle") - (attr "r" (fn [d] (.-r d))) - (attr "fill" (fn [d] (color (.-group d))))) - text (.. enter-node - (append "text") - (attr "dx" (fn [d] (if (render-node? d) - -12 - 12))) - (attr "dy" "0.35em") - (attr "text-anchor" (fn [d] - (if (render-node? d) - "end" - "start"))) - (attr "opacity" 1) - (text (fn [d] (.-title d)))) - - merged-node (.. enter-node (merge node)) - - ticked (fn [] - (.. merged-node - (attr "transform" - (fn [d] - (let [r (.-r d) - x (min-max r (.-x d) (- width r)) - y (min-max r (.-y d) (- height r))] - (set! (.-x d) x) - (set! (.-y d) y) - (str "translate(" x "," y ")"))))) - - (.. merged-link - (attr "x1" (fn [d] (.. d -source -x))) - (attr "y1" (fn [d] (.. d -source -y))) - (attr "x2" (fn [d] (.. d -target -x))) - (attr "y2" (fn [d] (.. d -target -y))))) - - node-exit-t (.. node - (exit) - (transition) - (delay (fn [d i] (* i 30))) - (duration 500)) - - - _ (.. node-exit-t - (select "circle") - (attr "transform" "scale(0,0)") - (attr "fill" "#000000")) - _ (.. node-exit-t - (select "text") - (attr "opacity" 0)) - _ (.. node-exit-t - (on "end" (fn [] (this-as this - (.. js/d3 - (select this) - (remove)))))) - _ (.. node-exit-t - (transition) - (call (fn [] - (.. simulation - (nodes nodes) - (on "tick" ticked)) - - (.. simulation - (force "link") - (links links)) - - (.. simulation - (restart) - (alpha 0.3)))))]))))} - - - traces-ratom] - [:hr]]))) diff --git a/src/day8/re_frame/trace/utils/graph.cljc b/src/day8/re_frame/trace/utils/graph.cljc deleted file mode 100644 index 8c5788b..0000000 --- a/src/day8/re_frame/trace/utils/graph.cljc +++ /dev/null @@ -1,85 +0,0 @@ -(ns day8.re-frame.trace.utils.graph - (:require [clojure.set :as set])) - -(defn select-type [type traces] - (filter #(= type (:op-type %)) traces)) - -(defn get-reaction [trace] - (get-in trace [:tags :reaction])) - -(defn distinct-k - "Returns a lazy sequence of the elements of coll with duplicates removed." - ([key-fn coll] - (let [step (fn step [xs seen] - (lazy-seq - ((fn [[f :as xs] seen] - (when-let [s (seq xs)] - (let [f-fn (key-fn f)] - (if (contains? seen f-fn) - (recur (rest s) seen) - (cons f (step (rest s) (conj seen f-fn))))))) - xs seen)))] - (step coll #{})))) - -(defn select-links [traces type disposed-ids link-val] - (->> traces - (select-type type) - (remove #(contains? disposed-ids (get-reaction %))) - (mapcat (fn [trace] - (for [input-signal (get-in trace [:tags :input-signals]) - :let [reaction (get-reaction trace)] - :when (every? some? [input-signal reaction])] - {:source input-signal :target reaction :value link-val - :id (str input-signal "|" reaction)}))) - (distinct-k :id))) - -(defn select-sub-nodes [traces type disposed-ids r] - (->> traces - (select-type type) - (remove #(contains? disposed-ids (get-reaction %))) - (remove #(get-in % [:tags :cached?])) - (map (fn [trace] - {:id (get-reaction trace) - :title (str (:operation trace)) - :group 2 - :r r - :data trace})) - (distinct-k :id))) - -(defn select-view-nodes [traces type unmounted-components r] - (->> traces - (select-type type) - (remove #(contains? unmounted-components (get-reaction %))) - (map (fn [trace] - {:id (get-reaction trace) - :title (str (:operation trace)) - :group 3 - :r r - :data trace - :fx 350})) - (remove #(nil? (:id %))) ;; remove reactions that are null (mostly from input fields???) - (distinct-k :id))) - -;; Use http://bl.ocks.org/GerHobbelt/3683278 to constrain nodes - -(defn trace->sub-graph [traces extra-nodes] - (let [disposed-ids (->> (select-type :sub/dispose traces) - (map get-reaction) - set) - unmounted-components (->> (select-type :componentWillUnmount traces) - (map get-reaction) - set) - - sub-nodes (select-sub-nodes traces :sub/create disposed-ids 10) - view-nodes nil #_(select-view-nodes traces :render unmounted-components 5) - sub-links (select-links traces :sub/run disposed-ids 1) - view-links nil #_(select-links traces :render unmounted-components 0.5) - all-nodes (concat extra-nodes sub-nodes view-nodes) - node-ids (set (map :id all-nodes)) - nodes-links (->> (mapcat (fn [{:keys [source target]}] [source target]) view-links) set) - missing-nodes (set/difference nodes-links node-ids) ;; These are local ratoms - view-links (->> view-links - (remove #(get missing-nodes (:source %)))) - all-links (concat sub-links view-links)] - {:nodes all-nodes - :links all-links})) diff --git a/src/day8/re_frame/trace/utils/log.cljs b/src/day8/re_frame/trace/utils/log.cljs deleted file mode 100644 index 3b6ff5c..0000000 --- a/src/day8/re_frame/trace/utils/log.cljs +++ /dev/null @@ -1 +0,0 @@ -(ns day8.re-frame.trace.utils.log) diff --git a/src/day8/re_frame/trace/utils/traces.cljs b/src/day8/re_frame/trace/utils/traces.cljs deleted file mode 100644 index 9eb828b..0000000 --- a/src/day8/re_frame/trace/utils/traces.cljs +++ /dev/null @@ -1,32 +0,0 @@ -(ns day8.re-frame.trace.utils.traces - (:require [reagent.core :as r] - [clojure.string :as str])) - -;; Put here to avoid cyclic dependencies -(defonce traces (r/atom [])) -(defonce total-traces (r/atom 0)) - -(defn log-trace? [trace] - (let [render-operation? (= (:op-type trace) :render) - component-path (get-in trace [:tags :component-path] "")] - (if-not render-operation? - true - (not (str/includes? component-path "devtools outer"))))) - -(defn disable-tracing! [] - (re-frame.trace/remove-trace-cb ::cb)) - -(defn enable-tracing! [] - (re-frame.trace/register-trace-cb ::cb (fn [new-traces] - (when-let [new-traces (filter log-trace? new-traces)] - (swap! total-traces + (count new-traces)) - (swap! traces - (fn [existing] - (let [new (reduce conj existing new-traces) - size (count new)] - (if (< 4000 size) - (let [new2 (subvec new (- size 2000))] - (if (< @total-traces 20000) ;; Create a new vector to avoid structurally sharing all traces forever - (do (reset! total-traces 0) - (into [] new2)))) - new)))))))) diff --git a/src/day8/re_frame/trace/utils/utils.cljs b/src/day8/re_frame/trace/utils/utils.cljs index c14df06..dfbf190 100644 --- a/src/day8/re_frame/trace/utils/utils.cljs +++ b/src/day8/re_frame/trace/utils/utils.cljs @@ -1,15 +1,2 @@ (ns day8.re-frame.trace.utils.utils) -(defn dissoc-in - "Dissociates an entry from a nested associative structure returning a new - nested structure. keys is a sequence of keys. Any empty maps that result - will not be present in the new structure." - [m [k & ks :as keys]] - (if ks - (if-let [nextmap (clojure.core/get m k)] - (let [newmap (dissoc-in nextmap ks)] - (if (seq newmap) - (assoc m k newmap) - (dissoc m k))) - m) - (dissoc m k))) diff --git a/src/day8/re_frame/trace/panels/app_db.cljs b/src/day8/re_frame/trace/view/app_db.cljs similarity index 87% rename from src/day8/re_frame/trace/panels/app_db.cljs rename to src/day8/re_frame/trace/view/app_db.cljs index ff5a843..0dc703c 100644 --- a/src/day8/re_frame/trace/panels/app_db.cljs +++ b/src/day8/re_frame/trace/view/app_db.cljs @@ -1,9 +1,9 @@ -(ns day8.re-frame.trace.panels.app-db +(ns day8.re-frame.trace.view.app-db (:require [reagent.core :as r] [clojure.string :as str] [devtools.prefs] [devtools.formatters.core] - [day8.re-frame.trace.components.data-browser :as data-browser] + [day8.re-frame.trace.view.components :as components] [day8.re-frame.trace.utils.re-com :as re-com] [mranderson047.re-frame.v0v10v2.re-frame.core :as rf])) @@ -33,7 +33,7 @@ ^{:key path} [:div.subtree-wrapper {:style {:margin "10px 0"}} [:div.subtree - [data-browser/subtree + [components/subtree (get-in @data path) [:button.subtree-button {:on-click #(rf/dispatch [:app-db/remove-path path])} [:span.subtree-button-string @@ -41,4 +41,4 @@ [path]]]]) @subtree-paths))] [:div {:style {:margin-bottom "20px"}} - [data-browser/subtree @data [:span.label "app-db"] [:app-db]]]]]))) + [components/subtree @data [:span.label "app-db"] [:app-db]]]]]))) diff --git a/src/day8/re_frame/trace/components/data_browser.cljs b/src/day8/re_frame/trace/view/components.cljs similarity index 70% rename from src/day8/re_frame/trace/components/data_browser.cljs rename to src/day8/re_frame/trace/view/components.cljs index 10696ad..16ed4b9 100644 --- a/src/day8/re_frame/trace/components/data_browser.cljs +++ b/src/day8/re_frame/trace/view/components.cljs @@ -1,10 +1,67 @@ -(ns day8.re-frame.trace.components.data-browser - (:require-macros [day8.re-frame.trace.utils.macros :refer [with-cljs-devtools-prefs]]) - (:require [mranderson047.re-frame.v0v10v2.re-frame.core :as rf] - [day8.re-frame.trace.utils.localstorage :as localstorage] - [day8.re-frame.trace.components.components :as components] +(ns day8.re-frame.trace.view.components + (:require [reagent.core :as r] [clojure.string :as str] - [reagent.core :as r])) + [goog.fx.dom :as fx] + [mranderson047.re-frame.v0v10v2.re-frame.core :as rf] + [day8.re-frame.trace.utils.localstorage :as localstorage] + [clojure.string :as str]) + (:require-macros [day8.re-frame.trace.utils.macros :refer [with-cljs-devtools-prefs]])) + +(defn search-input [{:keys [title placeholder on-save on-change on-stop]}] + (let [val (r/atom title) + save #(let [v (-> @val str str/trim)] + (when (pos? (count v)) + (on-save v)))] + (fn [] + [:input {:type "text" + :value @val + :auto-focus true + :placeholder placeholder + :size (if (> 20 (count (str @val))) + 25 + (count (str @val))) + :on-change #(do (reset! val (-> % .-target .-value)) + (on-change %)) + :on-key-down #(case (.-which %) + 13 (do + (save) + (reset! val "")) + nil)}]))) + +(defn scroll! [el start end time] + (.play (fx/Scroll. el (clj->js start) (clj->js end) time))) + +(defn scrolled-to-end? [el tolerance] + ;; at-end?: element.scrollHeight - element.scrollTop === element.clientHeight + (> tolerance (- (.-scrollHeight el) (.-scrollTop el) (.-clientHeight el)))) + +(defn autoscroll-list [{:keys [class scroll?]} child] + "Reagent component that enables scrolling for the elements of its child dom-node. + Scrolling is only enabled if the list is scrolled to the end. + Scrolling can be set as option for debugging purposes. + Thanks to Martin Klepsch! Original code can be found here: + https://gist.github.com/martinklepsch/440e6fd96714fac8c66d892e0be2aaa0" + (let [node (r/atom nil) + should-scroll (r/atom true)] + (r/create-class + {:display-name "autoscroll-list" + :component-did-mount + (fn [_] + (scroll! @node [0 (.-scrollTop @node)] [0 (.-scrollHeight @node)] 0)) + :component-will-update + (fn [_] + (reset! should-scroll (scrolled-to-end? @node 100))) + :component-did-update + (fn [_] + (when (and scroll? @should-scroll) + (scroll! @node [0 (.-scrollTop @node)] [0 (.-scrollHeight @node)] 500))) + :reagent-render + (fn [{:keys [class]} child] + [:div {:class class :ref (fn [dom-node] + (reset! node dom-node))} + child])}))) + +;; Data browser (defn string->css [css-string] "This function converts jsonml css-strings to valid css maps for hiccup. @@ -46,7 +103,7 @@ (defn make-devtools-api-call [api-fn & args] (with-cljs-devtools-prefs effective-cljs-devtools-prefs - (apply api-fn args))) + (apply api-fn args))) (defn cljs-devtools-header [& args] (apply make-devtools-api-call devtools.formatters.core/header-api-call args)) @@ -132,8 +189,8 @@ {:class (str/join " " ["re-frame-trace--object" (when @expanded? "expanded")])} #_[:span {:class "toggle" - :on-click #(rf/dispatch [:app-db/toggle-expansion path])} - [:button.expansion-button (if @expanded? "▼ " "▶ ")]] + :on-click #(rf/dispatch [:app-db/toggle-expansion path])} + [:button.expansion-button (if @expanded? "▼ " "▶ ")]] (or title "data") [:div {:style {:margin-left 20}} (cond diff --git a/src/day8/re_frame/trace/components/container.cljs b/src/day8/re_frame/trace/view/container.cljs similarity index 88% rename from src/day8/re_frame/trace/components/container.cljs rename to src/day8/re_frame/trace/view/container.cljs index 4cf1163..ef4714d 100644 --- a/src/day8/re_frame/trace/components/container.cljs +++ b/src/day8/re_frame/trace/view/container.cljs @@ -1,11 +1,10 @@ -(ns day8.re-frame.trace.components.container +(ns day8.re-frame.trace.view.container (:require-macros [day8.re-frame.trace.utils.macros :as macros]) (:require [mranderson047.re-frame.v0v10v2.re-frame.core :as rf] [re-frame.db :as db] - [day8.re-frame.trace.panels.app-db :as app-db] - [day8.re-frame.trace.panels.subvis :as subvis] - [day8.re-frame.trace.panels.traces :as traces] - [day8.re-frame.trace.panels.subs :as subs] + [day8.re-frame.trace.view.app-db :as app-db] + [day8.re-frame.trace.view.traces :as traces] + [day8.re-frame.trace.view.subs :as subs] [re-frame.trace] [reagent.core :as r] [day8.re-frame.trace.utils.re-com :as rc])) @@ -37,9 +36,7 @@ :children [(tab-button :traces "Traces") (tab-button :app-db "App DB") - (tab-button :subs "Subs") - #_(tab-button :subvis "SubVis") - ]] + (tab-button :subs "Subs")]] [rc/h-box :align :center :children @@ -71,6 +68,5 @@ (case @selected-tab :traces [traces/render-trace-panel traces] :app-db [app-db/render-state db/app-db] - :subvis [subvis/render-subvis traces] :subs [subs/subs-panel] [app-db/render-state db/app-db])])) diff --git a/src/day8/re_frame/trace/panels/subs.cljs b/src/day8/re_frame/trace/view/subs.cljs similarity index 89% rename from src/day8/re_frame/trace/panels/subs.cljs rename to src/day8/re_frame/trace/view/subs.cljs index 4ebb266..524e3f2 100644 --- a/src/day8/re_frame/trace/panels/subs.cljs +++ b/src/day8/re_frame/trace/view/subs.cljs @@ -1,8 +1,8 @@ -(ns day8.re-frame.trace.panels.subs +(ns day8.re-frame.trace.view.subs (:require [re-frame.subs :as subs] [day8.re-frame.trace.utils.re-com :as rc] ;[cljs.spec.alpha :as s] - [day8.re-frame.trace.components.data-browser :as data-browser] + [day8.re-frame.trace.view.components :as components] [mranderson047.re-frame.v0v10v2.re-frame.core :as rf])) ;(s/def ::query-v any?) @@ -28,7 +28,7 @@ ^{:key query-v} [:div.subtree-wrapper {:style {:margin "10px 0"}} [:div.subtree - [data-browser/subscription-render + [components/subscription-render (rc/deref-or-value-peek (val me)) [:button.subtree-button {:on-click #(rf/dispatch [:app-db/remove-path (key me)])} [:span.subtree-button-string diff --git a/src/day8/re_frame/trace/panels/traces.cljs b/src/day8/re_frame/trace/view/traces.cljs similarity index 98% rename from src/day8/re_frame/trace/panels/traces.cljs rename to src/day8/re_frame/trace/view/traces.cljs index e7ef231..889cb9b 100644 --- a/src/day8/re_frame/trace/panels/traces.cljs +++ b/src/day8/re_frame/trace/view/traces.cljs @@ -1,5 +1,5 @@ -(ns day8.re-frame.trace.panels.traces - (:require [day8.re-frame.trace.components.components :as components] +(ns day8.re-frame.trace.view.traces + (:require [day8.re-frame.trace.view.components :as components] [day8.re-frame.trace.utils.pretty-print-condensed :as pp] [re-frame.trace :as trace] [clojure.string :as str]