Pop out traces into an external window

Fixes #92
This commit is contained in:
Daniel Compton 2017-11-08 12:53:21 +13:00
parent 74a0b26a6a
commit 94d0b38b04
8 changed files with 134 additions and 51 deletions

View File

@ -314,6 +314,10 @@
#--re-frame-trace-- .icon-button { #--re-frame-trace-- .icon-button {
font-size: 10px; font-size: 10px;
} }
#--re-frame-trace-- .popout-icon {
max-width: 15px;
cursor: pointer;
}
#--re-frame-trace-- .tab { #--re-frame-trace-- .tab {
background: transparent; background: transparent;
border-radius: 0; border-radius: 0;

View File

@ -407,6 +407,12 @@
button.tab { button.tab {
} }
.popout-icon {
max-width: 15px;
cursor: pointer;
}
.tab { .tab {
background: transparent; background: transparent;
border-radius: 0; border-radius: 0;

View File

@ -3,6 +3,7 @@
[day8.re-frame.trace.panels.app-db :as app-db] [day8.re-frame.trace.panels.app-db :as app-db]
[day8.re-frame.trace.styles :as styles] [day8.re-frame.trace.styles :as styles]
[day8.re-frame.trace.components.components :as components] [day8.re-frame.trace.components.components :as components]
[day8.re-frame.trace.components.container :as container]
[day8.re-frame.trace.utils.localstorage :as localstorage] [day8.re-frame.trace.utils.localstorage :as localstorage]
[day8.re-frame.trace.panels.traces :as traces] [day8.re-frame.trace.panels.traces :as traces]
[day8.re-frame.trace.events] [day8.re-frame.trace.events]
@ -23,7 +24,8 @@
[re-frame.interop :as interop] [re-frame.interop :as interop]
[devtools.formatters.core :as devtools] [devtools.formatters.core :as devtools]
[mranderson047.re-frame.v0v10v2.re-frame.core :as rf])) [mranderson047.re-frame.v0v10v2.re-frame.core :as rf]
[day8.re-frame.trace.utils.traces :as utils.traces]))
;; from https://github.com/reagent-project/reagent/blob/3fd0f1b1d8f43dbf169d136f0f905030d7e093bd/src/reagent/impl/component.cljs#L274 ;; from https://github.com/reagent-project/reagent/blob/3fd0f1b1d8f43dbf169d136f0f905030d7e093bd/src/reagent/impl/component.cljs#L274
@ -119,13 +121,14 @@
(real-schedule))))) (real-schedule)))))
(defonce total-traces (interop/ratom 0)) (defonce total-traces (interop/ratom 0))
(defonce traces (interop/ratom [])) ;(defonce traces (interop/ratom []))
(defn log-trace? [trace] (defn log-trace? [trace]
(let [rendering? (= (:op-type trace) :render)] (let [render-operation? (= (:op-type trace) :render)
(if-not rendering? component-path (get-in trace [:tags :component-path] "")]
(if-not render-operation?
true true
(not (str/includes? (get-in trace [:tags :component-path] "") "devtools outer"))) (not (str/includes? component-path "devtools outer")))
#_(if-let [comp-p (get-in trace [:tags :component-path])] #_(if-let [comp-p (get-in trace [:tags :component-path])]
@ -138,15 +141,16 @@
(re-frame.trace/register-trace-cb ::cb (fn [new-traces] (re-frame.trace/register-trace-cb ::cb (fn [new-traces]
(when-let [new-traces (filter log-trace? new-traces)] (when-let [new-traces (filter log-trace? new-traces)]
(swap! total-traces + (count new-traces)) (swap! total-traces + (count new-traces))
(swap! traces (fn [existing] (swap! utils.traces/traces
(let [new (reduce conj existing new-traces) (fn [existing]
size (count new)] (let [new (reduce conj existing new-traces)
(if (< 4000 size) size (count new)]
(let [new2 (subvec new (- size 2000))] (if (< 4000 size)
(if (< @total-traces 20000) ;; Create a new vector to avoid structurally sharing all traces forever (let [new2 (subvec new (- size 2000))]
(do (reset! total-traces 0) (if (< @total-traces 20000) ;; Create a new vector to avoid structurally sharing all traces forever
(into [] new2)))) (do (reset! total-traces 0)
new)))))))) (into [] new2))))
new))))))))
(defn init-tracing! (defn init-tracing!
"Sets up any initial state that needs to be there for tracing. Does not enable tracing." "Sets up any initial state that needs to be there for tracing. Does not enable tracing."
@ -165,7 +169,7 @@
(enable-tracing!) (enable-tracing!)
(disable-tracing!))) (disable-tracing!)))
(defn devtools [] (defn devtools-outer [traces opts]
;; Add clear button ;; Add clear button
;; Filter out different trace types ;; Filter out different trace types
(let [position (r/atom :right) (let [position (r/atom :right)
@ -226,21 +230,8 @@
:transition transition}} :transition transition}}
[:div.panel-resizer {:style (resizer-style draggable-area) [:div.panel-resizer {:style (resizer-style draggable-area)
:on-mouse-down #(reset! dragging? true)}] :on-mouse-down #(reset! dragging? true)}]
[:div.panel-content [container/devtools-inner traces opts]]]))})))
{:style {:width "100%" :height "100%" :display "flex" :flex-direction "column"}}
[:div.panel-content-top
[:div.nav
[:button {:class (str "tab button " (when (= @selected-tab :traces) "active"))
:on-click #(rf/dispatch [:settings/selected-tab :traces])} "Traces"]
[:button {:class (str "tab button " (when (= @selected-tab :app-db) "active"))
:on-click #(rf/dispatch [:settings/selected-tab :app-db])} "App DB"]
#_[:button {:class (str "tab button " (when (= @selected-tab :subvis) "active"))
:on-click #(reset! selected-tab :subvis)} "SubVis"]]]
(case @selected-tab
:traces [traces/render-trace-panel traces]
:app-db [app-db/render-state db/app-db]
:subvis [subvis/render-subvis traces]
[app-db/render-state db/app-db])]]]))})))
(defn panel-div [] (defn panel-div []
(let [id "--re-frame-trace--" (let [id "--re-frame-trace--"
@ -253,26 +244,9 @@
(js/window.focus new-panel) (js/window.focus new-panel)
new-panel)))) new-panel))))
(defn inject-styles []
(let [id "--re-frame-trace-styles--"
styles-el (.getElementById js/document id)
new-styles-el (.createElement js/document "style")
new-styles styles/panel-styles]
(.setAttribute new-styles-el "id" id)
(-> new-styles-el
(.-innerHTML)
(set! new-styles))
(if styles-el
(-> styles-el
(.-parentNode)
(.replaceChild new-styles-el styles-el))
(let []
(.appendChild (.-head js/document) new-styles-el)
new-styles-el))))
(defn inject-devtools! [] (defn inject-devtools! []
(inject-styles) (styles/inject-styles js/document)
(r/render [devtools] (panel-div))) (r/render [devtools-outer utils.traces/traces {:panel-type :inline}] (panel-div)))
(defn init-db! [] (defn init-db! []
(trace.db/init-db)) (trace.db/init-db))

View File

@ -0,0 +1,32 @@
(ns day8.re-frame.trace.components.container
(: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]
[reagent.core :as r]))
(defn devtools-inner [traces opts]
(let [selected-tab (rf/subscribe [:settings/selected-tab])
panel-type (:panel-type opts)]
[:div.panel-content
{:style {:width "100%" :height "100%" :display "flex" :flex-direction "column"}}
[:div.panel-content-top
[:div.nav
[:button {:class (str "tab button " (when (= @selected-tab :traces) "active"))
:on-click #(rf/dispatch [:settings/selected-tab :traces])} "Traces"]
[:button {:class (str "tab button " (when (= @selected-tab :app-db) "active"))
:on-click #(rf/dispatch [:settings/selected-tab :app-db])} "App DB"]
#_[:button {:class (str "tab button " (when (= @selected-tab :subvis) "active"))
:on-click #(reset! selected-tab :subvis)} "SubVis"]
(when-not (= panel-type :popup)
[:img.popout-icon
{:src (str "data:image/svg+xml;utf8,"
"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 8 8\" x=\"0px\" y=\"0px\">\n <path fill=\"#444444\" d=\"M0 0v8h8v-2h-1v1h-6v-6h1v-1h-2zm4 0l1.5 1.5-2.5 2.5 1 1 2.5-2.5 1.5 1.5v-4h-4z\"/>\n</svg>\n")
:on-click #(rf/dispatch-sync [:global/launch-external])}])]]
(case @selected-tab
:traces [traces/render-trace-panel traces]
:app-db [app-db/render-state db/app-db]
:subvis [subvis/render-subvis traces]
[app-db/render-state db/app-db])]))

View File

@ -1,8 +1,12 @@
(ns day8.re-frame.trace.events (ns day8.re-frame.trace.events
(:require [mranderson047.re-frame.v0v10v2.re-frame.core :as rf] (:require [mranderson047.re-frame.v0v10v2.re-frame.core :as rf]
[day8.re-frame.trace.utils.utils :as utils] [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] [day8.re-frame.trace.utils.localstorage :as localstorage]
[clojure.string :as str])) [clojure.string :as str]
[reagent.core :as r]
[day8.re-frame.trace.components.container :as container]
[day8.re-frame.trace.styles :as styles]))
(rf/reg-event-db (rf/reg-event-db
:settings/panel-width% :settings/panel-width%
@ -29,6 +33,46 @@
(localstorage/save! "show-panel" show-panel?) (localstorage/save! "show-panel" show-panel?)
(assoc-in db [:settings :show-panel?] show-panel?)))) (assoc-in db [:settings :show-panel?] show-panel?))))
;; Global
(defn mount [popup-window popup-document]
(let [app (.getElementById popup-document "--re-frame-trace--")
doc js/document]
(styles/inject-styles popup-document)
(aset popup-window "onunload" #(rf/dispatch [:global/external-closed]))
(r/render
[(r/create-class
{:display-name "devtools outer external"
:reagent-render (fn []
[container/devtools-inner utils.traces/traces {:panel-type :popup}
])})]
app)))
(defn open-debugger-window
"Copied from re-frisk.devtool/open-debugger-window"
[]
(let [{:keys [ext_height ext_width]} (:prefs {})
w (js/window.open "" "Debugger" (str "width=" (or ext_width 800) ",height=" (or ext_height 800)
",resizable=yes,scrollbars=yes,status=no,directories=no,toolbar=no,menubar=no"))
d (.-document w)]
(.open d)
(.write d "<head></head><body><div id=\"--re-frame-trace--\"></div></body>" #_html-doc)
(aset w "onload" #(mount w d))
(.close d)))
(rf/reg-event-fx
:global/launch-external
(fn [{:keys [db]} _]
(open-debugger-window)
{:db db
;; TODO: capture the intent that the user is still interacting with devtools, to persist between reloads.
:dispatch-later [{:ms 200 :dispatch [:settings/show-panel? false]}]}))
(rf/reg-event-fx
:global/external-closed
(fn [ctx _]
{:dispatch-later [{:ms 400 :dispatch [:settings/show-panel? true]}]}))
;; Traces ;; Traces
(defn save-filter-items [filter-items] (defn save-filter-items [filter-items]

View File

@ -155,4 +155,5 @@
(when (pos? (count @traces)) (when (pos? (count @traces))
[:span "(" [:button.text-button {:on-click #(do (trace/reset-tracing!) (reset! traces []))} "clear"] ")"])] [:span "(" [:button.text-button {:on-click #(do (trace/reset-tracing!) (reset! traces []))} "clear"] ")"])]
[:th {:style {:text-align "right"}} "meta"]] [:th {:style {:text-align "right"}} "meta"]]
[:tbody (render-traces visible-traces filter-items filter-input trace-detail-expansions)]]]])))) [:tbody (render-traces visible-traces filter-items filter-input trace-detail-expansions)]]]
]))))

View File

@ -2,3 +2,20 @@
(:require-macros [day8.re-frame.trace.utils.macros :as macros])) (:require-macros [day8.re-frame.trace.utils.macros :as macros]))
(def panel-styles (macros/slurp-macro "day8/re_frame/trace/main.css")) (def panel-styles (macros/slurp-macro "day8/re_frame/trace/main.css"))
(defn inject-styles [document]
(let [id "--re-frame-trace-styles--"
styles-el (.getElementById document id)
new-styles-el (.createElement document "style")
new-styles panel-styles]
(.setAttribute new-styles-el "id" id)
(-> new-styles-el
(.-innerHTML)
(set! new-styles))
(if styles-el
(-> styles-el
(.-parentNode)
(.replaceChild new-styles-el styles-el))
(let []
(.appendChild (.-head document) new-styles-el)
new-styles-el))))

View File

@ -0,0 +1,5 @@
(ns day8.re-frame.trace.utils.traces
(:require [reagent.core :as r]))
;; Put here to avoid cyclic dependencies
(defonce traces (r/atom []))