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 {
font-size: 10px;
}
#--re-frame-trace-- .popout-icon {
max-width: 15px;
cursor: pointer;
}
#--re-frame-trace-- .tab {
background: transparent;
border-radius: 0;

View File

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

View File

@ -3,6 +3,7 @@
[day8.re-frame.trace.panels.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.utils.localstorage :as localstorage]
[day8.re-frame.trace.panels.traces :as traces]
[day8.re-frame.trace.events]
@ -23,7 +24,8 @@
[re-frame.interop :as interop]
[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
@ -119,13 +121,14 @@
(real-schedule)))))
(defonce total-traces (interop/ratom 0))
(defonce traces (interop/ratom []))
;(defonce traces (interop/ratom []))
(defn log-trace? [trace]
(let [rendering? (= (:op-type trace) :render)]
(if-not rendering?
(let [render-operation? (= (:op-type trace) :render)
component-path (get-in trace [:tags :component-path] "")]
(if-not render-operation?
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])]
@ -138,15 +141,16 @@
(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))))))))
(swap! utils.traces/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 init-tracing!
"Sets up any initial state that needs to be there for tracing. Does not enable tracing."
@ -165,7 +169,7 @@
(enable-tracing!)
(disable-tracing!)))
(defn devtools []
(defn devtools-outer [traces opts]
;; Add clear button
;; Filter out different trace types
(let [position (r/atom :right)
@ -226,21 +230,8 @@
:transition transition}}
[:div.panel-resizer {:style (resizer-style draggable-area)
:on-mouse-down #(reset! dragging? true)}]
[: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"]]]
(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])]]]))})))
[container/devtools-inner traces opts]]]))})))
(defn panel-div []
(let [id "--re-frame-trace--"
@ -253,26 +244,9 @@
(js/window.focus 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! []
(inject-styles)
(r/render [devtools] (panel-div)))
(styles/inject-styles js/document)
(r/render [devtools-outer utils.traces/traces {:panel-type :inline}] (panel-div)))
(defn 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
(: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]))
[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
:settings/panel-width%
@ -29,6 +33,46 @@
(localstorage/save! "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
(defn save-filter-items [filter-items]

View File

@ -155,4 +155,5 @@
(when (pos? (count @traces))
[:span "(" [:button.text-button {:on-click #(do (trace/reset-tracing!) (reset! traces []))} "clear"] ")"])]
[: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]))
(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 []))