Merge pull request #27 from Day8/feature/filter-events

Feature/filter events
This commit is contained in:
Daniel Compton 2017-08-14 20:55:53 +12:00 committed by GitHub
commit 9eae81a000
4 changed files with 275 additions and 93 deletions

View File

@ -0,0 +1,15 @@
(ns day8.re-frame.trace.components)
(defn icon-add []
[:svg.icon.icon-add
{:viewBox "0 0 32 32"}
[:title "add"]
[:path
{:d "M31 12h-11v-11c0-0.552-0.448-1-1-1h-6c-0.552 0-1 0.448-1 1v11h-11c-0.552 0-1 0.448-1 1v6c0 0.552 0.448 1 1 1h11v11c0 0.552 0.448 1 1 1h6c0.552 0 1-0.448 1-1v-11h11c0.552 0 1-0.448 1-1v-6c0-0.552-0.448-1-1-1z"}]])
(defn icon-remove []
[:svg.icon.icon-remove
{:viewBox "0 0 32 32"}
[:title "remove"]
[:path
{:d "M31.708 25.708c-0-0-0-0-0-0l-9.708-9.708 9.708-9.708c0-0 0-0 0-0 0.105-0.105 0.18-0.227 0.229-0.357 0.133-0.356 0.057-0.771-0.229-1.057l-4.586-4.586c-0.286-0.286-0.702-0.361-1.057-0.229-0.13 0.048-0.252 0.124-0.357 0.228 0 0-0 0-0 0l-9.708 9.708-9.708-9.708c-0-0-0-0-0-0-0.105-0.104-0.227-0.18-0.357-0.228-0.356-0.133-0.771-0.057-1.057 0.229l-4.586 4.586c-0.286 0.286-0.361 0.702-0.229 1.057 0.049 0.13 0.124 0.252 0.229 0.357 0 0 0 0 0 0l9.708 9.708-9.708 9.708c-0 0-0 0-0 0-0.104 0.105-0.18 0.227-0.229 0.357-0.133 0.355-0.057 0.771 0.229 1.057l4.586 4.586c0.286 0.286 0.702 0.361 1.057 0.229 0.13-0.049 0.252-0.124 0.357-0.229 0-0 0-0 0-0l9.708-9.708 9.708 9.708c0 0 0 0 0 0 0.105 0.105 0.227 0.18 0.357 0.229 0.356 0.133 0.771 0.057 1.057-0.229l4.586-4.586c0.286-0.286 0.362-0.702 0.229-1.057-0.049-0.13-0.124-0.252-0.229-0.357z"}]])

View File

@ -0,0 +1,97 @@
(ns day8.re-frame.trace.styles)
(defonce panel-styles "
#--re-frame-trace-- {
background: white;
color: black;
font-family: 'courier new', monospace;
}
#--re-frame-trace-- tbody {
color: #aaa;
}
#--re-frame-trace-- tr:nth-child(even) {
background: aliceblue;
}
#--re-frame-trace-- .button {
padding: 5px 5px 3px;
margin: 5px;
border-radius: 2px;
cursor: pointer;
}
#--re-frame-trace-- .text-button {
border-bottom: 1px dotted #888;
font-weight: normal;
}
#--re-frame-trace-- .button:focus, .text-button:focus {
border-radius: 2px 2px 0 0;
-webkit-box-shadow: inset 0px -5px 0px 0px rgba(0,0,0,0.3);
-moz-box-shadow: inset 0px -5px 0px 0px rgba(0,0,0,0.3);
box-shadow: inset 0px -5px 0px 0px rgba(0,0,0,0.3);
}
#--re-frame-trace-- .icon-button {
font-size: 10px;
}
#--re-frame-trace-- button.tab {
}
#--re-frame-trace-- .tab {
background: transparent;
border-radius: 0;
text-transform: uppercase;
font-family: monospace;
letter-spacing: 2px;
margin-bottom: 0;
padding-bottom: 4px;
vertical-align: bottom;
}
#--re-frame-trace-- .tab.active {
background: transparent;
border-bottom: 3px solid lightblue;
border-radius: 0;
padding-bottom: 1px;
}
#--re-frame-trace-- ul.filter-items {
list-style-type: none;
padding: 0;
margin: 0 -5px;
}
#--re-frame-trace-- .filter-items li {
color: #333;
background: #efefef;
display: inline-block;
font-size: 0.9em;
margin: 5px;
}
#--re-frame-trace-- .filter-items li .filter-item-string {
color: #616cdb;
}
#--re-frame-trace-- .icon {
display: inline-block;
width: 1em;
height: 1em;
stroke-width: 0;
stroke: currentColor;
fill: currentColor;
}
#--re-frame-trace-- .icon-remove {
margin-left: 10px;
}
#--re-frame-trace-- select {
background: white;
font-family: 'courier new', monospace;
font-size: 1em;
}
#--re-frame-trace-- .nav {
background: #efeef1;
color: #222;
}
#--re-frame-trace-- .panel-content-top {
flex: 1;
}
#--re-frame-trace-- .panel-content-scrollable {
padding: 10px;
flex: 1 0 auto;
height: 100%;
overflow: auto;
}
")

View File

@ -1,5 +1,7 @@
(ns day8.re-frame.trace (ns day8.re-frame.trace
(:require [day8.re-frame.trace.subvis :as subvis] (:require [day8.re-frame.trace.subvis :as subvis]
[day8.re-frame.trace.styles :as styles]
[day8.re-frame.trace.components :as components]
[re-frame.trace :as trace :include-macros true] [re-frame.trace :as trace :include-macros true]
[cljs.pprint :as pprint] [cljs.pprint :as pprint]
[clojure.string :as str] [clojure.string :as str]
@ -12,8 +14,8 @@
[goog.object :as gob] [goog.object :as gob]
[re-frame.interop :as interop] [re-frame.interop :as interop]
[devtools.formatters.core :as devtools] [devtools.formatters.core :as devtools]))
))
(defn comp-name [c] (defn comp-name [c]
(let [n (or (component/component-path c) (let [n (or (component/component-path c)
@ -61,9 +63,9 @@
(trace/with-trace {:op-type :render (trace/with-trace {:op-type :render
:tags {:component-path (reagent.impl.component/component-path c)} :tags {:component-path (reagent.impl.component/component-path c)}
:operation (last (str/split name #" > "))} :operation (last (str/split name #" > "))}
(real-renderer c) (real-renderer c)))))
))))
(set! reagent.impl.component/static-fns static-fns) (set! reagent.impl.component/static-fns static-fns)
@ -88,8 +90,8 @@
#_(set! reagent.impl.batching/schedule schedule #_(set! reagent.impl.batching/schedule schedule
#_(fn [] #_(fn []
(reagent.impl.batching/do-after-render (fn [] (trace/with-trace {:op-type :raf-end}))) (reagent.impl.batching/do-after-render (fn [] (trace/with-trace {:op-type :raf-end})))
(real-schedule))) (real-schedule)))))
))
(def traces (interop/ratom [])) (def traces (interop/ratom []))
(defn log-trace? [trace] (defn log-trace? [trace]
@ -113,80 +115,124 @@
(defn init-tracing! (defn init-tracing!
"Sets up any intial state that needs to be there for tracing. Does not enable tracing." "Sets up any intial state that needs to be there for tracing. Does not enable tracing."
[] []
(monkey-patch-reagent) (monkey-patch-reagent))
)
(defn search-input [{:keys [title on-save on-stop]}]
(defn search-input [{:keys [title on-save on-change on-stop]}]
(let [val (r/atom title) (let [val (r/atom title)
save #(let [v (-> @val str clojure.string/trim)] save #(let [v (-> @val str str/trim)]
(on-save v))] (when (pos? (count v))
(on-save v)))]
(fn [] (fn []
[:input {:type "text" [:input {:style {:margin-left 7}
:type "text"
:value @val :value @val
:auto-focus true :auto-focus true
:on-blur save :on-change #(do (reset! val (-> % .-target .-value))
:on-change #(reset! val (-> % .-target .-value)) (on-change %))
:on-key-down #(case (.-which %) :on-key-down #(case (.-which %)
13 (save) 13 (do
(save)
(reset! val ""))
nil)}]))) nil)}])))
(defn query->fn [query]
(if (= :contains (:filter-type query))
(fn [trace]
(str/includes? (str/lower-case (str (:operation trace) " " (:op-type trace)))
(:query query)))
(fn [trace]
(< (:query query) (:duration trace)))))
(defn render-traces [] (defn render-traces [showing-traces]
(let [search (r/atom "") (doall
slower-than-ms (r/atom "") (for [{:keys [op-type id operation tags duration] :as trace} showing-traces]
slower-than-bold (r/atom "")] (let [padding {:padding "0px 5px 0px 5px"}
row-style (merge padding {:border-top (case op-type :event "1px solid lightgrey" nil)})
#_#__ (js/console.log (devtools/header-api-call tags))]
(list [:tr {:key id
:style {:color (case op-type
:sub/create "green"
:sub/run "#fd701e"
:event "blue"
:render "purple"
:re-frame.router/fsm-trigger "#fd701e"
nil)}}
[:td {:style row-style} (str op-type)]
[:td {:style row-style} operation]
[:td
{:style (merge row-style {
; :font-weight (if (< slower-than-bold-int duration)
; "bold"
; "")
:white-space "nowrap"})}
(.toFixed duration 1) " ms"]]
(when true
[:tr {:key (str id "-details")}
[:td {:col-span 3} (with-out-str (pprint/pprint (dissoc tags :query-v :event :duration)))]]))))))
(defn render-trace-panel []
(let [filter-input (r/atom "")
filter-items (r/atom [])
filter-type (r/atom :contains)
input-error (r/atom false)]
(fn [] (fn []
(let [slower-than-ms-int (js/parseInt @slower-than-ms) (let [showing-traces (if (= @filter-items [])
slower-than-bold-int (js/parseInt @slower-than-bold) @traces
op-filter (when-not (str/blank? @search) (filter (apply every-pred (map query->fn @filter-items)) @traces))
(filter #(str/includes? (str (:operation %) " " (:op-type %)) @search))) save-query (fn [_]
ms-filter (when-not (str/blank? @slower-than-ms) (if (and (= @filter-type :slower-than)
(filter #(< slower-than-ms-int (:duration %)))) (js/isNaN (js/parseFloat @filter-input)))
transducers (apply comp (remove nil? [ms-filter op-filter])) (reset! input-error true)
showing-traces (sequence transducers @traces) (do
(reset! input-error false)
filter-msg (if (and (str/blank? @search) (str/blank? @slower-than-ms)) (swap! filter-items conj {:id (random-uuid)
(str "Filter " (count @traces) " events: ") :query (if (= @filter-type :contains)
(str "Filtering " (count showing-traces) " of " (count @traces) " events:")) (str/lower-case @filter-input)
padding {:padding "0px 5px 0px 5px"}] (js/parseFloat @filter-input))
:filter-type @filter-type}))))]
[:div [:div
{:style {:padding "10px"}} [:div.filter-control {:style {:margin-bottom 20}}
[:h1 "TRACES"] [:div.filter-control-input
[:span filter-msg [:button {:on-click #(do (trace/reset-tracing!) (reset! traces []))} " Clear traces"]] [:br] {:style {:margin-bottom 10}}
[:span "Filter events " [search-input {:on-save #(reset! search %)}]] [:br] [:select {:value @filter-type
[:span "Filter slower than " [search-input {:on-save #(reset! slower-than-ms %)}] "ms "] [:br] :on-change #(reset! filter-type (keyword (.. % -target -value)))}
[:span "Bold slower than " [search-input {:on-save #(reset! slower-than-bold %)}] "ms "] [:option {:value "contains"} "contains"]
[:option {:value "slower-than"} "slower than"]]
[search-input {:on-save save-query
:on-change #(reset! filter-input (.. % -target -value))}]
[:button.button.icon-button {:on-click save-query
:style {:margin 0}}
[components/icon-add]]
(if @input-error
[:div.input-error {:style {:color "red" :margin-top 5}}
"Please enter a valid number."])
[:br]]
[:ul.filter-items
(map (fn [item]
^{:key (:id item)}
[:li.filter-item
[:button.button
{:style {:margin 0}
:on-click (fn [event] (swap! filter-items #(remove (comp (partial = (:query item)) :query) %)))}
(:filter-type item) ": " [:span.filter-item-string (:query item)]
[:span.icon-button [components/icon-remove]]]])
@filter-items)]]
[:table [:table
{:cell-spacing "0" :width "100%"} {:cell-spacing "0" :width "100%"}
[:thead>tr [:thead>tr
[:th "op"] [:th "operations"]
[:th "event"] [:th
(when (pos? (count @filter-items))
(str (count showing-traces) " of "))
(when (pos? (count @traces))
(str (count @traces)))
" events "
(when (pos? (count @traces))
[:span "(" [:button.text-button {:on-click #(do (trace/reset-tracing!) (reset! traces []))} "clear"] ")"])]
[:th "meta"]] [:th "meta"]]
[:tbody [:tbody (render-traces showing-traces)]]]))))
(doall
(for [{:keys [op-type id operation tags duration] :as trace} showing-traces]
(let [row-style (merge padding {:border-top (case op-type :event "1px solid lightgrey" nil)})
#_#__ (js/console.log (devtools/header-api-call tags))
]
(list [:tr {:key id
:style {:color (case op-type
:sub/create "green"
:sub/run "red"
:event "blue"
:render "purple"
:re-frame.router/fsm-trigger "red"
nil)}}
[:td {:style row-style} (str op-type)]
[:td {:style row-style} operation]
[:td
{:style (merge row-style {:font-weight (if (< slower-than-bold-int duration)
"bold"
"")})}
(.toFixed duration 1) " ms"]]
(when true
[:tr {:key (str id "-details")}
[:td {:col-span 3} (with-out-str (pprint/pprint (dissoc tags :query-v :event :duration)))]])
))))]]]))))
(defn resizer-style [draggable-area] (defn resizer-style [draggable-area]
{:position "absolute" :z-index 2 :opacity 0 {:position "absolute" :z-index 2 :opacity 0
@ -198,7 +244,7 @@
;; 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)
size (r/atom 0.3) size (r/atom 0.35)
showing? (r/atom false) showing? (r/atom false)
dragging? (r/atom false) dragging? (r/atom false)
pin-to-bottom? (r/atom true) pin-to-bottom? (r/atom true)
@ -229,27 +275,35 @@
transition (if @showing? transition (if @showing?
ease-transition ease-transition
(str ease-transition ", opacity 0.01s linear 0.2s"))] (str ease-transition ", opacity 0.01s linear 0.2s"))]
[:div {:style {:position "fixed" :width "0px" :height "0px" :top "0px" :left "0px" :z-index 99999999}} [:div.panel-wrapper
[:div {:style {:position "fixed" :z-index 1 :box-shadow "rgba(0, 0, 0, 0.298039) 0px 0px 4px" :background "white" {:style {:position "fixed" :width "0px" :height "0px" :top "0px" :left "0px" :z-index 99999999}}
:left left :top "0px" :width (str (* 100 @size) "%") :height "100%" [:div.panel
:transition transition}} {:style {:position "fixed" :z-index 1 :box-shadow "rgba(0, 0, 0, 0.298039) 0px 0px 4px" :background "white"
[:div.resizer {:style (resizer-style draggable-area) :left left :top "0px" :width (str (* 100 @size) "%") :height "100%"
:on-mouse-down #(reset! dragging? true) :transition transition}}
:on-mouse-up #(reset! dragging? false) [:div.panel-resizer {:style (resizer-style draggable-area)
:on-mouse-move (fn [e] :on-mouse-down #(reset! dragging? true)
(when @dragging? :on-mouse-up #(reset! dragging? false)
(let [x (.-clientX e) :on-mouse-move (fn [e]
y (.-clientY e)] (when @dragging?
(.preventDefault e) (let [x (.-clientX e)
(reset! size (/ (- full-width x) y (.-clientY e)]
full-width)))))}] (.preventDefault e)
[:div {:style {:width "100%" :height "100%" :overflow "auto"}} (reset! size (/ (- full-width x)
[:button {:on-click #(reset! selected-tab :traces)} "Traces"] full-width)))))}]
[:button {:on-click #(reset! selected-tab :subvis)} "SubVis"] [:div.panel-content
(case @selected-tab {:style {:width "100%" :height "100%" :display "flex" :flex-direction "column"}}
:traces [render-traces] [:div.panel-content-top
:subvis [subvis/render-subvis traces] [:div.nav
[render-traces])]]]))}))) [:button {:class (str "tab button " (when (= @selected-tab :traces) "active"))
:on-click #(reset! selected-tab :traces)} "Traces"]
[:button {:class (str "tab button " (when (= @selected-tab :subvis) "active"))
:on-click #(reset! selected-tab :subvis)} "SubVis"]]]
[:div.panel-content-scrollable
(case @selected-tab
:traces [render-trace-panel]
:subvis [subvis/render-subvis traces]
[render-trace-panel])]]]]))})))
(defn panel-div [] (defn panel-div []
(let [id "--re-frame-trace--" (let [id "--re-frame-trace--"
@ -259,7 +313,26 @@
(let [new-panel (.createElement js/document "div")] (let [new-panel (.createElement js/document "div")]
(.setAttribute new-panel "id" id) (.setAttribute new-panel "id" id)
(.appendChild (.-body js/document) new-panel) (.appendChild (.-body js/document) 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)
(r/render [devtools] (panel-div))) (r/render [devtools] (panel-div)))

View File

@ -43,8 +43,6 @@
simulation-a (atom nil)] simulation-a (atom nil)]
(fn [] (fn []
[:div [:div
{:style {:padding "10px"}}
[:h1 "SUBVIS"]
[d3t/create-d3 [d3t/create-d3
{:render-component (fn [ratom] {:render-component (fn [ratom]
[:svg#d3cmp {:width width :height height}]) [:svg#d3cmp {:width width :height height}])
@ -184,9 +182,8 @@
(.. simulation (.. simulation
(restart) (restart)
(alpha 0.3))))) (alpha 0.3)))))]))))}
]
))))}
traces-ratom] traces-ratom]
[:hr]]))) [:hr]])))